from typing import Literal
from services.configuration import get_settings
import concurrent.futures

from langchain.chat_models import ChatOpenAI
from langchain.llms import HuggingFaceHub
from langchain.chains.summarize import load_summarize_chain
from langchain.prompts import PromptTemplate
from langchain.schema import Document
from langchain.schema.language_model import BaseLanguageModel
from langchain.chains.combine_documents.base import BaseCombineDocumentsChain

def create_llm(task: Literal["summarize"] | Literal["synthesis"], temperature: float = 0, max_tokens: int = 1024,):
    """
    Creates a language model for the given task. If the OPENAI_API_KEY is set, it will use the OpenAI API, otherwise it will use the HuggingFace Hub.

    Parameters
    - ``task``: The task to create the language model for. Can be either ``summarize`` or ``synthesis``.

    Returns
    ``llm``: The language model.

    Raises
    - ``ValueError``: If the task is not ``summarize`` or ``synthesis`` or the OPENAI_API_KEY or the HUGGINGFACEHUB_API_TOKEN are not set.
    """
    try:
        settings = get_settings()
        if settings.OPENAI_API_KEY != None:
            llm = ChatOpenAI(temperature=temperature,
                             openai_api_key=settings.OPENAI_API_KEY,
                             max_tokens=max_tokens,
                             model='gpt-3.5-turbo'
                             ) if task == "summarize" else ChatOpenAI(temperature=temperature,
                                                                      openai_api_key=settings.OPENAI_API_KEY,
                                                                      max_tokens=max_tokens,
                                                                      model='gpt-4',
                                                                      )
        else:
            llm = HuggingFaceHub(repo_id="tiiuae/falcon-7b-instruct",
                                 huggingfacehub_api_token=settings.HUGGINGFACEHUB_API_TOKEN)
        return llm
    except ValueError as e:
        print(e)
        raise ValueError(
            "The task must be either 'summarize' or 'synthesis' and the OPENAI_API_KEY or the HUGGINGFACEHUB_API_TOKEN must be set.")

def create_map_summarization_chain(llm: BaseLanguageModel, prompt: str, input_variables: list[str]):
    """
    Creates a summarization chain for the given language model, prompt and input variables.

    Parameters

    - ``llm``: The language model to use.
    - ``prompt``: The prompt string representation to use.
    - ``input_variables``: The input variables for the prompt to use.

    Returns

    ``map_chain``: The summarization chain.

    Raises

    - ``Exception``: If the chain could not be created.
    """
    try:
        prompt_template = PromptTemplate(
            template=prompt, input_variables=input_variables)
        map_chain = load_summarize_chain(llm=llm,
                                         chain_type="stuff",
                                         prompt=prompt_template)
        return map_chain
    except Exception as e:
        raise Exception("Could not create summarization chain.")

async def summarize_docs(llm: BaseLanguageModel, prompt: str, input_variables: list[str], documents: list[Document]):
    """
    Summarizes the given documents independently using the given language model, prompt and input variables.

    Parameters
    - ``llm``: The language model to use.
    - ``prompt``: The prompt string representation to use must be aimed to summarize.
    - ``input_variables``: The input variables for the prompt to use.
    - ``documents``: The documents to summarize.

    Returns
    ``summary_list``: The list of summaries.

    Raises
    - ``Exception``: If any of the chain instances fail.
    """
    try:
        summary_list = []
        map_chain = create_map_summarization_chain(
            llm=llm, prompt=prompt, input_variables=input_variables)

        with concurrent.futures.ThreadPoolExecutor() as executor:
            future_to_doc = {executor.submit(
                run_summarization, map_chain, doc): doc for doc in documents}

            for future in concurrent.futures.as_completed(future_to_doc):
                doc = future_to_doc[future]
                try:
                    chunk_summary = future.result()
                    summary_list.append(chunk_summary)
                except Exception as e:
                    print(
                        f"Error processing document: {doc.page_content}, error: {e}")

        return summary_list
    except Exception as e:
        raise Exception("Could not summarize documents.")

def run_summarization(map_chain: BaseCombineDocumentsChain, doc: Document):
    """
    Runs the summarization chain for the given document.

    Parameters

    - ``map_chain``: The summarization chain to use.
    - ``doc``: The document to summarize."""
    return map_chain.run([doc])

async def synthesis(llm: BaseLanguageModel, prompt: str, input_variables: list[str], summary_list: list[str]):
    """
    Synthesizes the given summaries using the given language model, prompt and input variables.

    Parameters
    - ``llm``: The language model to use.
    - ``prompt``: The prompt string representation to use must be aimed to synthesize.Must be aimed to synthesize.
    - ``input_variables``: The input variables for the prompt to use.
    - ``summary_list``: The summaries to synthesize.

    Returns
    ``output``: The output of the synthesis in plain text.

    Raises
    - ``Exception``: If the chain instance fails."""
    try:
        summaries = "\n".join(summary_list)
        summaries_doc = Document(page_content=summaries)
        reduce_chain = create_map_summarization_chain(llm=llm,
                                                      prompt=prompt,
                                                      input_variables=input_variables)

        output = await reduce_chain.arun([summaries_doc])
        return output
    except Exception as e:
        raise Exception("Could not synthesize summaries.")


import multiprocessing as mp
from collections import defaultdict
from typing import Callable, Dict, List, Optional, Tuple, Union

import numpy as np
import torch as th
from stable_baselines3.common.evaluation import evaluate_policy
from stable_baselines3.common.policies import BasePolicy
from stable_baselines3.common.running_mean_std import RunningMeanStd
from stable_baselines3.common.vec_env import VecEnv, unwrap_vec_normalize
from stable_baselines3.common.vec_env.base_vec_env import CloudpickleWrapper

def _worker(
    remote: mp.connection.Connection,
    parent_remote: mp.connection.Connection,
    worker_env_wrapper: CloudpickleWrapper,
    train_policy_wrapper: CloudpickleWrapper,
    n_eval_episodes: int = 1,
) -> None:
    """
    Function that will be run in each process.
    It is in charge of creating environments, evaluating candidates
    and communicating with the main process.

    :param remote: Pipe to communicate with the parent process.
    :param parent_remote:
    :param worker_env_wrapper: Callable used to create the environment inside the process.
    :param train_policy_wrapper: Callable used to create the policy inside the process.
    :param n_eval_episodes: Number of evaluation episodes per candidate.
    """
    parent_remote.close()
    vec_env: VecEnv = worker_env_wrapper.var()
    train_policy = train_policy_wrapper.var
    vec_normalize = unwrap_vec_normalize(vec_env)
    if vec_normalize is not None:
        obs_rms = vec_normalize.obs_rms
    else:
        obs_rms = None
    while True:
        try:
            cmd, data = remote.recv()
            if cmd == "eval":
                results = []
                # Evaluate each candidate and save results
                for weights_idx, candidate_weights in data:
                    train_policy.load_from_vector(candidate_weights.cpu())
                    episode_rewards, episode_lengths = evaluate_policy(
                        train_policy,
                        vec_env,
                        n_eval_episodes=n_eval_episodes,
                        return_episode_rewards=True,
                        warn=False,
                    )
                    results.append((weights_idx, (episode_rewards, episode_lengths)))
                remote.send(results)
            elif cmd == "seed":
                # Note: the seed will only be effective at the next reset
                remote.send(vec_env.seed(seed=data))
            elif cmd == "set_options":
                # Note: the options will only be effective at the next reset
                remote.send(vec_env.set_options(data))
            elif cmd == "get_obs_rms":
                remote.send(obs_rms)
            elif cmd == "sync_obs_rms":
                vec_normalize.obs_rms = data
                obs_rms = data
            elif cmd == "close":
                vec_env.close()
                remote.close()
                break
            else:
                raise NotImplementedError(f"`{cmd}` is not implemented in the worker")
        except EOFError:
            break

class AsyncEval:
    """
    Helper class to do asynchronous evaluation of different policies with multiple processes.
    It is useful when implementing population based methods like Evolution Strategies (ES),
    Cross Entropy Method (CEM) or Augmented Random Search (ARS).

    .. warning::

        Only 'forkserver' and 'spawn' start methods are thread-safe,
        which is important to avoid race conditions.
        However, compared to
        'fork' they incur a small start-up cost and have restrictions on
        global variables. With those methods, users must wrap the code in an
        ``if __name__ == "__main__":`` block.
        For more information, see the multiprocessing documentation.

    :param envs_fn: Vectorized environments to run in subprocesses (callable)
    :param train_policy: The policy object that will load the different candidate
        weights.
    :param start_method: method used to start the subprocesses.
           Must be one of the methods returned by ``multiprocessing.get_all_start_methods()``.
           Defaults to 'forkserver' on available platforms, and 'spawn' otherwise.
    :param n_eval_episodes: The number of episodes to test each agent
    """

    def __init__(
        self,
        envs_fn: List[Callable[[], VecEnv]],
        train_policy: BasePolicy,
        start_method: Optional[str] = None,
        n_eval_episodes: int = 1,
    ):
        self.waiting = False
        self.closed = False
        n_envs = len(envs_fn)

        if start_method is None:
            # Fork is not a thread safe method (see issue #217)
            # but is more user friendly (does not require to wrap the code in
            # a `if __name__ == "__main__":`)
            forkserver_available = "forkserver" in mp.get_all_start_methods()
            start_method = "forkserver" if forkserver_available else "spawn"
        ctx = mp.get_context(start_method)

        self.remotes, self.work_remotes = zip(*[ctx.Pipe() for _ in range(n_envs)])
        self.processes = []
        for work_remote, remote, worker_env in zip(self.work_remotes, self.remotes, envs_fn):
            args = (
                work_remote,
                remote,
                CloudpickleWrapper(worker_env),
                CloudpickleWrapper(train_policy),
                n_eval_episodes,
            )
            # daemon=True: if the main process crashes, we should not cause things to hang
            process = ctx.Process(target=_worker, args=args, daemon=True)  # pytype:disable=attribute-error
            process.start()
            self.processes.append(process)
            work_remote.close()

    def send_jobs(self, candidate_weights: th.Tensor, pop_size: int) -> None:
        """
        Send jobs to the workers to evaluate new candidates.

        :param candidate_weights: The weights to be evaluated.
        :pop_size: The number of candidate (size of the population)
        """
        jobs_per_worker = defaultdict(list)
        for weights_idx in range(pop_size):
            jobs_per_worker[weights_idx % len(self.remotes)].append((weights_idx, candidate_weights[weights_idx]))

        for remote_idx, remote in enumerate(self.remotes):
            remote.send(("eval", jobs_per_worker[remote_idx]))
        self.waiting = True

    def seed(self, seed: Optional[int] = None) -> List[Union[None, int]]:
        """
        Seed the environments.

        :param seed: The seed for the pseudo-random generators.
        :return:
        """
        for idx, remote in enumerate(self.remotes):
            remote.send(("seed", seed + idx))
        return [remote.recv() for remote in self.remotes]

    def set_options(self, options: Optional[Union[List[Dict], Dict]] = None) -> List[Union[None, int]]:
        """
        Set environment options for all environments.
        If a dict is passed instead of a list, the same options will be used for all environments.
        WARNING: Those options will only be passed to the environment at the next reset.

        :param options: A dictionary of environment options to pass to each environment at the next reset.
        :return:
        """
        for remote in self.remotes:
            remote.send(("set_options", options))
        return [remote.recv() for remote in self.remotes]

    def get_results(self) -> List[Tuple[int, Tuple[np.ndarray, np.ndarray]]]:
        """
        Retreive episode rewards and lengths from each worker
        for all candidates (there might be multiple candidates per worker)

        :return: A list of tuples containing each candidate index and its
            result (episodic reward and episode length)
        """
        results = [remote.recv() for remote in self.remotes]
        flat_results = [result for worker_results in results for result in worker_results]
        self.waiting = False
        return flat_results

    def get_obs_rms(self) -> List[RunningMeanStd]:
        """
        Retrieve the observation filters (observation running mean std)
        of each process, they will be combined in the main process.
        Synchronisation is done afterward using ``sync_obs_rms()``.
        :return: A list of ``RunningMeanStd`` objects (one per process)
        """
        for remote in self.remotes:
            remote.send(("get_obs_rms", None))
        return [remote.recv() for remote in self.remotes]

    def sync_obs_rms(self, obs_rms: RunningMeanStd) -> None:
        """
        Synchronise (and update) the observation filters
        (observation running mean std)
        :param obs_rms: The updated ``RunningMeanStd`` to be used
            by workers for normalizing observations.
        """
        for remote in self.remotes:
            remote.send(("sync_obs_rms", obs_rms))

    def close(self) -> None:
        """
        Close the processes.
        """
        if self.closed:
            return
        if self.waiting:
            for remote in self.remotes:
                remote.recv()
        for remote in self.remotes:
            remote.send(("close", None))
        for process in self.processes:
            process.join()
        self.closed = True


from PyQt5.QtWidgets import QWidget, QMessageBox
from PyQt5 import QtWidgets

class Example(QWidget):

    def __init__(self):
        super().__init__()
        self.initUI()

    def click(self):
        global map_name
        map_name = self.textbox.text()

    def initUI(self):

        self.setGeometry(400,400,400,300)
        self.setWindowTitle('Message box')
        self.setFixedSize(400, 300)
        self.textbox = QtWidgets.QLineEdit(self)
        self.textbox.move(100, 100)
        self.textbox.resize(180, 40)
        button = QtWidgets.QPushButton(self)
        button.setText("MAP name")
        button.move(150, 200)
        button.clicked.connect(self.click)
        self.show()

    def closeEvent(self, event1):
        global dop_window

        reply = QMessageBox.question(self, 'Message',
                                     "Are you sure to quit?", QMessageBox.Yes |
                                     QMessageBox.No, QMessageBox.No)

        if reply == QMessageBox.Yes:
            dop_window = True
            self.close()
        else:
            event1.ignore()


# Extract elements with Frequency greater than K

from collections import Counter
# brute force

test_list = [4, 6, 4, 3, 3, 4, 3, 4, 3, 8, 3]
k = 3

def find_elements(lis, freq):
    res_list = list(set(lis))
    out_list = []

    for i in res_list:
        if lis.count(i) > freq:
            out_list.append(i)

    return out_list

print(find_elements(test_list, k))

# using Counter

count_list = Counter(test_list)
final_list = [key for key in count_list.keys() if count_list[key] > k]
print(final_list)


import json

displayName = "Settlement Generator"

inputs = [
    (
        ('Settlement Generator', 'title'),

        ('By William, Selina, Ho Kiu, Rhys', 'label'),
        ('', 'label'),
    )
]

def perform(level, box, options):
    print('Starting Generation...')

    try:
        path_to_file = "C:\\Users\\selin\\OneDrive\\Documents\\MCEdit\\Filters"
        file_name = "platform"
        file_path = "{}\\templates\\house1\\{}.json".format(path_to_file, file_name)
        print('Loading JSON template from {}...'.format(file_path))
        template = loadFile(file_path)
        print('Template loaded')

    except Exception as e:
        print(e)

    print('Placing blocks in template...')
    for block in template:
        block_id = block['id']
        block_data = block['data']
        block_x = block['x'] + box.minx
        block_y = block['y'] + box.miny
        block_z = block['z'] + box.minz

        level.setBlockAt(block_x, block_y, block_z, block_id)
        level.setBlockDataAt(block_x, block_y, block_z, block_data)

def loadFile(file_path):
    with open(file_path) as f:
        return json.load(f)


# -*- coding: utf-8 -*-
"""
Code implementing the functionality for a replay buffer in the DDPG algorithm in
order to solve a continuous control RL problem.

Implementation largely re-used and slightly modified from my implementation in
my DQN algorithm for the navigation project.

Author: Chris Cadonic

For Deep Reinforcement Learning Nanodegree offered by Udacity.
"""

import os
import argparse

import numpy as np
import torch
from torch.utils.data import DataLoader, TensorDataset

from control.datasets import TrajectoryDataset

class ReplayBuffer:
    """
    This class implements the functionality for storing experience tuples in a
    replay buffer to sample during learning steps in the DQN algorithm.
    """

    def __init__(self, buffer_size=1E6, batch_size=32, seed=13):
        self.buffer_size = buffer_size
        self.batch_size = batch_size
        self.seed = seed
        np.random.seed(seed)  # seed for reproducibility

        # initalize device; use GPU if available
        self.device = torch.device(
            "cuda:0" if torch.cuda.is_available() else "cpu")

        self.memory = []

    def __len__(self):
        """
        Return the size of items in the replay buffer.
        """
        return len(self.memory)

    def empty(self):
        """
        Remove all tuples stored in the replay buffer. This is useful for PPO to
        use the replay buffer as storage for trajectories.
        """
        self.memory = []

    def store_tuple(self, state, action, next_state, reward, done):
        """
        Add the experience tuple to memory.

        Parameters
        ----------
        state: np.array/torch.Tensor
            Tensor singleton containing state information
        action: np.array/torch.Tensor
            Tensor singleton containing the action taken from state
        next_state: np.array/torch.Tensor
            Tensor singleton containing information about what state followed
            the action taken from the state provided by 'state'
        reward: np.array/torch.Tensor
            Tensor singleton containing reward information
        done: np.array/torch.Tensor
            Tensor singleton representing whether or not the episode ended after
            action was taken
        """
        # only keep the most recent tuples if memory size has been reached
        if len(self.memory) == self.buffer_size:
            num_agents = state.shape[0]
            self.memory = self.memory[num_agents:]
        for s, a, next_s, r, d in zip(state, action, next_state, reward, done):
            self.memory.append((s, a, next_s, r, d))

    def sample(self):
        """
        Extract a random sample of tuples from memory.
        """
        random_ints = np.random.choice(len(self.memory), self.batch_size,
                                       replace=False)

        raw_sample = [self.memory[i] for i in random_ints]
        exp_batch_lists = list(zip(*raw_sample))

        exp_batch = tuple(torch.from_numpy(
            np.array(exp_batch_lists[i])).float().to(self.device)
                          for i in range(len(exp_batch_lists)))

        return exp_batch

    def get_dataset(self, batch_size=32):
        """
        Extract a dataset of T timesteps over N learners stored in the buffer as
        a storage for trajectories. This is mainly used for PPO.
        """
        zipped_batch = list(zip(*self.memory))

        full_batch = list(torch.tensor(np.array(data_batch),
                          requires_grad=True).float().to(self.device)
                          for data_batch in zipped_batch)
        trajectory_dataset = TrajectoryDataset(*full_batch)

        dataset = DataLoader(trajectory_dataset, batch_size=batch_size,
                             shuffle=False)

        return dataset


import os
import requests as req
from bs4 import BeautifulSoup

def moje_delo():
    targeted_elements = ['div', 'a']

    if "moje_delo.html" in os.listdir("html"):
        os.remove("html/moje_delo.html")

    html = open("html/moje_delo.html", "w", encoding="utf-8")

    head = open("html/head.html", "r")
    lines = head.readlines()
    for line in lines:
        html.write(line)

    url = "https://www.mojedelo.com/prosta-delovna-mesta/vsa-podrocja/gorenjska?p=1&rid=7"
    page = req.get(url)
    soup = BeautifulSoup(page.content.decode('utf-8-sig'), 'html.parser')
    last_page = soup.find("li", class_="PagedList-skipToLast")
    last_page = last_page.find("a")
    last_page = int(last_page.text)

    for i in range(1, last_page+1):
        print(i)
        if i != 1:
            url = f"https://www.mojedelo.com/prosta-delovna-mesta/vsa-podrocja/gorenjska?p={i}&rid=7"
            page = req.get(url)
            soup = BeautifulSoup(page.content.decode('utf-8-sig'), 'html.parser')
        jobs = soup.find_all(lambda tag: tag.name in targeted_elements and 'job-ad' in tag.get('class', []))

        for job in jobs:
            details = job.find_all("div", class_="detail")
            for detail in details:
                if detail.text == "Kranj":
                    name = job.find("h2", class_="title")
                    description = job.find("p", class_="premiumDescription")
                    links = job.find_all("a")
                    date = details[0].text
                    for link in links:
                        link = link["href"]
                        if link != "#":
                            try:
                                description = description.text
                                html.write(f"\t
{name.text}
\n")
                                html.write(f"\t
{date}
\n")
                                html.write(f"\t
{description}

\n\n")
                            except Exception as e:
                                print(e)
                                html.write(f"\t
{name.text}
\n")
                                html.write(f"\t
{date}

\n\n")
    html.write("")
    html.close()
    print("Moje Delo is completed!")

if __name__ == "__main__":
    moje_delo()


import logging

from odoo.tests import Form, tagged

from odoo.addons.l10n_ro_stock_account.tests.common import TestStockCommon

_logger = logging.getLogger(__name__)

@tagged("post_install", "-at_install")
class TestStockPurchaseReturn(TestStockCommon):
    def test_return_in_notice_picking(self):
        self.create_po(vals={"l10n_ro_notice": True})
        _logger.info("Start generare retur")
        # Create return picking
        pick = self.po.picking_ids

        stock_return_picking_form = Form(
            self.env["stock.return.picking"].with_context(
                active_ids=pick.ids, active_id=pick.ids[0], active_model="stock.picking"
            )
        )
        return_wiz = stock_return_picking_form.save()
        return_wiz.product_return_moves.write(
            {"quantity": 2.0, "to_refund": True}
        )  # Return only 2
        res = return_wiz.create_returns()
        return_pick = self.env["stock.picking"].browse(res["res_id"])

        # Validate picking
        return_pick.move_line_ids.write({"qty_done": 2})
        return_pick.l10n_ro_notice = True  # asta trebuia sa fie setat in mod automat
        return_pick.button_validate()


# -*- coding: utf-8 -*-

import sys
import os

from google.appengine.dist import use_library
use_library('django', '1.2')

import re
import urllib
import datetime
import base64

import logging

from google.appengine.ext.webapp import template
from google.appengine.api import users
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext import db
from google.appengine.api import memcache
from google.appengine.api import urlfetch
from google.appengine.api.labs import taskqueue
from google.appengine.api import mail

class Entry(db.Model):
    title = db.StringProperty()
    url = db.StringProperty()
    alive = db.BooleanProperty(default=True)
    started = db.BooleanProperty(default=False)
    error_reason = db.StringProperty()
    error_hour = db.IntegerProperty(default=0)
    keyword = db.StringProperty()
    date = db.DateTimeProperty(auto_now_add=True)
    update = db.DateTimeProperty(auto_now=True)

class MainPage(webapp.RequestHandler):
    def get(self):
        entries = Entry.all().order("title").fetch(100)

        lastchecked = memcache.get("lastcheckedtime")
        diffsec = 0
        if lastchecked:
            diff = datetime.datetime.now() - lastchecked
            diffsec =  diff.seconds
            if diffsec == 0:
                diffsec = 1

        template_values = {
            "entries" : entries,
            "diffsec" : diffsec,
        }
        path = os.path.join(os.path.dirname(__file__), 'views/home.html')
        self.response.out.write(template.render(path, template_values))

class EditPage(webapp.RequestHandler):

    def need_admin(self):
        user = users.get_current_user()
        if not user:
            self.redirect(users.create_login_url(self.request.uri))
            return False
        if not users.is_current_user_admin():
            self.response.out.write("Sorry, but only admin can edit. Log out" % users.create_logout_url("/"))
            return False

        return True

    def get(self):
        if not self.need_admin():
            return

        id = self.request.get('id')
        if id:
            entry = Entry.get_by_id(int(id))
        else:
            entry = None

        template_values = {
            "id" : id,
            "entry" : entry
        }
        path = os.path.join(os.path.dirname(__file__), 'views/edit.html')
        self.response.out.write(template.render(path, template_values))

    def post(self):
        if not self.need_admin():
            return

        id = self.request.get('id')
        url = self.request.get('url')
        title = self.request.get('title')
        keyword = self.request.get('keyword')
        delete = int(self.request.get('delete',0))

        if not url or not title:
            self.response.out.write("please input url and title")
            return

        if not id:
            entry = Entry()
        else:
            entry = Entry.get_by_id(int(id))
            if not entry:
                self.response.out.write("entry not found")
                return
            if delete:
                entry.delete()
                self.redirect("/")
                return

        entry.title = title
        if entry.url != url or entry.keyword != keyword:
            entry.started = False
        entry.url = url
        entry.keyword = keyword
        entry.put()

        self.redirect("/")

def email_notification(entry,additional_message = "",body=""):
    subject = ''
    body = ''
    if entry.alive:
        subject = entry.title + " is alive"
    else:
        subject = entry.title + " is down (" + entry.error_reason + ")"
    if additional_message:
        subject += " (" + additional_message + ")"

    body = subject + "\n--\n"  + body  + "\n--\n"  + "http://alive-monitor.appspot.com/"

    mail.send_mail(sender="Alive Monitor <server@nota.jp>",
                  to="server@nota.jp",
                  subject=subject,
                  body=body)
    logging.info("Sent Email:" + subject)

class Check(webapp.RequestHandler):
    def get(self):
        entries = Entry.all().fetch(100)

        for entry in entries:
            alive = True
            error_reason = ''
            error_body = ''
            try:
                result = urlfetch.fetch(entry.url,deadline=30)
                if result.status_code != 200:
                    #try again
                    alive = False
                    error_reason = str(result.status_code) + " Error"
                elif entry.keyword:
                    if not re.search(entry.keyword, result.content):
                        alive = False
                        error_reason = "Missing Keyword Error"
                for h in result.headers:
                    error_body += h + ": " + result.headers.get(h) + "\n"
                error_body += result.content
            except urlfetch.DownloadError:
                alive = False
                error_reason = "Download Error"
            except urlfetch.InvalidURLError:
                alive = False
                error_reason = "Invalid URL Error"
            except:
                alive = False
                error_reason = "Enexpected Error"

            admsg = ''
            sendmail = False
            if entry.alive != alive or not entry.started:
                if not entry.started:
                    admsg = "Monitor Start"
                    entry.started = True
                    sendmail = True
                if alive and entry.error_hour >= 1:
                    sendmail = True
                entry.error_reason = error_reason
                entry.alive = alive
                entry.error_hour = 0
                entry.put()
            elif not alive:
                entry.error_reason = error_reason
                diff = datetime.datetime.now() - entry.update
                if entry.error_hour == 0:
                    entry.error_hour = 1
                    entry.put()
                    sendmail = True
                elif diff.seconds > 60*60:
                    sendmail = True
                    admsg = "More than %d hour!" % entry.error_hour
                    entry.error_hour += 1
                    entry.put()

            if sendmail:
                email_notification(entry,admsg,error_body)

        now = datetime.datetime.now()
        memcache.set("lastcheckedtime",now)

        self.response.out.write("Done")

application = webapp.WSGIApplication(
                                     [('/', MainPage),
                                     ('/edit', EditPage),
                                     ('/check', Check)],
                                     debug=True)

def main():
  run_wsgi_app(application)

if __name__ == "__main__":
  main()


import logging
import pandas as pd
import numpy as np
import scipy.stats as st
from .features_fourier import get_fourier_features
from .features_wavelet import get_wavelet_features

__all__ = ["build_dataset"]

logger = logging.getLogger()

def get_features(
    X_scaled: pd.DataFrame,
    X_past_scaled: pd.DataFrame,
    clusters: pd.DataFrame,
) -> np.array:
    """
    Builds dataset for LSTM model
    """

    logging.info("Building dataset for LSTM model...")

    time_seq = X_scaled.shape[0] - 1

    a = X_scaled.values
    b = X_past_scaled.values

    n = 6
    c = np.empty((X_scaled.shape[0], X_scaled.shape[1]))
    c[n:, :] = X_scaled.iloc[:-n, :]

    n = 30
    d = np.empty((X_scaled.shape[0], X_scaled.shape[1]))
    d[n:, :] = X_scaled.iloc[:-n, :]

    X1 = np.vstack([a, b, a - b, c, a - c, d, a - d]).reshape(7, -1, X_scaled.shape[1])
    X1 = np.moveaxis(X1, 0, -1)[-time_seq:, :, :]

    X2 = get_1st_differences(X_scaled)
    X3 = get_2nd_differences(X_scaled)
    X4 = get_moments(X_scaled)
    X5 = get_rolling_means(X_scaled)

    X6 = clusters.values.repeat(time_seq, axis=0).reshape(
        clusters.shape[0], -1, clusters.shape[1]
    )
    X6 = np.moveaxis(X6, 1, 0)
    X7 = get_fourier_features(X_scaled, clusters)[-time_seq:, :, :]
    X8 = get_wavelet_features(X_scaled)[-time_seq:, :, :]

    return np.concatenate([X1, X2, X3, X4, X5, X6, X7, X8], axis=-1)

def get_1st_differences(X_scaled: pd.DataFrame, periods=["D", "W", "M"]) -> np.array:
    df = pd.DataFrame(index=X_scaled.index[1:])
    for t in periods:
        a1 = X_scaled.resample(t).median()
        X1 = a1.values[1:, :] - a1.values[:-1, :]
        X2 = (a1.values[1:, :] - a1.values[:-1, :]) / a1.values[:-1, :]
        X = pd.DataFrame(np.hstack([X1, X2]), index=a1.index[1:])
        df = df.merge(X, on="dt", how="left").bfill().ffill()

        X = df.values.reshape(len(df), -1, X_scaled.shape[1])

    return np.moveaxis(X, 1, -1)

def get_2nd_differences(X_scaled: pd.DataFrame, periods=["W", "M"]) -> np.array:
    df = pd.DataFrame(index=X_scaled.index[1:])
    for t in periods:
        a1 = X_scaled.resample(t).median()
        X = a1.values[1:, :] - a1.values[:-1, :]
        X = pd.DataFrame(X[1:, :] - X[:-1, :], index=a1.index[2:])
        df = df.merge(X, on="dt", how="left").bfill().ffill()

        X = df.values.reshape(len(df), -1, X_scaled.shape[1])

    return np.moveaxis(X, 1, -1)

def get_moments(X_scaled: pd.DataFrame, periods=["W", "M"]) -> np.array:
    df = pd.DataFrame(index=X_scaled.index)
    for t in periods:
        f = X_scaled.resample(t)
        df = pd.concat(
            [
                df,
                f.median(),
                f.mean(),
                f.std(),
                f.mean() / f.std(),
                f.agg(st.skew),
                f.agg(st.kurtosis),
            ],
            axis=1,
        ).bfill()
    df = pd.DataFrame(index=X_scaled.index[1:]).merge(df, on="dt", how="left")

    X = df.values.reshape(len(df), -1, X_scaled.shape[1])

    return np.moveaxis(X, 1, -1)

def get_rolling_means(X_scaled: pd.DataFrame, windows=[6, 24]) -> np.array:
    df = pd.DataFrame(index=X_scaled.index)
    for w in windows:
        f = X_scaled.rolling(w)
        df = pd.concat([df, X_scaled.rolling(w).mean()], axis=1).bfill()
    df = pd.DataFrame(index=X_scaled.index[1:]).merge(df, on="dt", how="left")

    X = df.values.reshape(len(df), -1, X_scaled.shape[1])

    return np.moveaxis(X, 1, -1)


from typing import Dict, List, Tuple

import torch
import torch.nn as nn
from torch.cuda import nvtx
from ..utils import original_requires_grad, cholesky_inv, smw_inv
from ..matrices import *
from ..symmatrix import *
from ..vector import ParamVector

# compute no-centered covariance
OP_FULL_COV = 'full_cov'  # full covariance
OP_FULL_CVP = 'full_cvp'  # full covariance-vector product
OP_COV = 'cov'  # layer-wise covariance
OP_COV_INV = 'cov_inv'  # layer-wise covariance inverse
OP_CVP = 'cvp'  # layer-wise covariance-vector product
OP_COV_KRON = 'cov_kron'  # Kronecker-factored covariance
OP_COV_KRON_INV = 'cov_kron_inv'  # Kronecker-factored covariance inverse
OP_COV_SWIFT_KRON = 'cov_swift_kron'  # swift Kronecker-factored covariance
OP_COV_SWIFT_KRON_INV = 'cov_swift_kron_inv'  # swift Kronecker-factored covariance inverse
OP_COV_KFE = 'cov_kfe'  # Kronecker-factored covariance eigenbasis
OP_COV_UNIT_WISE = 'cov_unit_wise'  # unit-wise covariance
OP_COV_UNIT_WISE_INV = 'cov_unit_wise_inv'  # unit-wise covariance inverse
OP_COV_DIAG = 'cov_diag'  # diagonal covariance
OP_COV_DIAG_INV = 'cov_diag_inv'  # diagonal covariance inverse
OP_RFIM_RELU = 'rfim_relu'  # relative FIM for ReLU
OP_RFIM_SOFTMAX = 'rfim_softmax'  # relative FIM for softmax

# compute Gram matrix
OP_GRAM_DIRECT = 'gram_direct'  # direct
OP_GRAM_HADAMARD = 'gram_hada'  # Hadamard-factored
OP_SKETCHED_GRAM = 'sketched_gram'  # apply sketching matrix to gram

OP_BATCH_GRADS = 'batch_grads'  # compute batched gradients (per-example gradients)
OP_SAVE_INPUTS = 'save_inputs'  # save inputs during a forward-pass
OP_SAVE_OUTPUTS = 'save_outputs'  # save outputs during a forward-pass
OP_SAVE_OUTGRADS = 'save_outgrads'  # save outgrads during a backward-pass
OP_MEAN_INPUTS = 'mean_inputs'  # compute the mean of inputs
OP_MEAN_OUTPUTS = 'mean_outputs'  # compute the mean of outputs
OP_SPATIAL_MEAN_OUTPUTS = 'spatial_mean_outputs'  # compute the spatial mean of outputs (only for Conv2d)
OP_OUT_SPATIAL_SIZE = 'out_spatial_size'  # get the spatial size of outputs
OP_MEAN_OUTGRADS = 'mean_outgrads'  # compute the mean outgrads
OP_SPATIAL_MEAN_OUTGRADS = 'spatial_mean_outgrads'  # compute the spatial mean of outgrads (only for Conv2d)
OP_BFGS_KRON_S_AS = 'bfgs_kron_s_As'  # compute s ans As for K-BFGS

ALL_OPS = [OP_FULL_COV, OP_FULL_CVP,
           OP_COV, OP_COV_INV, OP_CVP,
           OP_COV_KRON, OP_COV_KRON_INV,
           OP_COV_SWIFT_KRON, OP_COV_SWIFT_KRON_INV,
           OP_COV_UNIT_WISE, OP_COV_UNIT_WISE_INV,
           OP_COV_DIAG, OP_COV_DIAG_INV,
           OP_RFIM_RELU, OP_RFIM_SOFTMAX,
           OP_GRAM_DIRECT, OP_GRAM_HADAMARD, OP_BATCH_GRADS,
           OP_SAVE_INPUTS, OP_SAVE_OUTPUTS, OP_SAVE_OUTGRADS,
           OP_SKETCHED_GRAM,
           OP_MEAN_INPUTS, OP_MEAN_OUTPUTS, OP_MEAN_OUTGRADS,
           OP_SPATIAL_MEAN_OUTPUTS, OP_SPATIAL_MEAN_OUTGRADS,
           OP_OUT_SPATIAL_SIZE, OP_BFGS_KRON_S_AS,
           OP_COV_KFE]

FWD_OPS = [OP_SAVE_INPUTS, OP_SAVE_OUTPUTS,
           OP_COV_KRON, OP_COV_SWIFT_KRON,
           OP_RFIM_RELU, OP_RFIM_SOFTMAX,
           OP_MEAN_INPUTS, OP_MEAN_OUTPUTS,
           OP_SPATIAL_MEAN_OUTPUTS, OP_OUT_SPATIAL_SIZE, OP_BFGS_KRON_S_AS]

BWD_OPS_WITH_INPUTS = [OP_COV, OP_COV_INV, OP_CVP,
                       OP_COV_KRON_INV, OP_COV_SWIFT_KRON_INV,
                       OP_COV_UNIT_WISE, OP_COV_UNIT_WISE_INV,
                       OP_COV_DIAG, OP_COV_DIAG_INV,
                       OP_GRAM_HADAMARD, OP_GRAM_DIRECT,
                       OP_BATCH_GRADS, OP_COV_KFE,
                       OP_SKETCHED_GRAM]

BWD_OPS = [OP_SAVE_OUTGRADS,
           OP_COV_KRON, OP_COV_SWIFT_KRON,
           OP_RFIM_RELU, OP_RFIM_SOFTMAX,
           OP_MEAN_OUTGRADS, OP_SPATIAL_MEAN_OUTGRADS] \
          + BWD_OPS_WITH_INPUTS

BASIC_OPS = [OP_FULL_COV, OP_FULL_CVP,
             OP_SAVE_INPUTS, OP_SAVE_OUTPUTS,
             OP_SAVE_OUTGRADS, OP_COV, OP_COV_INV,
             OP_CVP, OP_GRAM_DIRECT]

class Operation:
    supported_operations = set(ALL_OPS)

    def __init__(self, module, op_names, model_for_kernel=None):
        if hasattr(module, 'weight'):
            requires_grad = module.weight.requires_grad
            if hasattr(module, 'bias') and module.bias is not None:
                requires_grad = requires_grad or module.bias.requires_grad
            if not requires_grad:
                raise ValueError(f'One of weight or bias has to require grad (module: {module}).')
        self._module = module
        self._model_for_kernel = model_for_kernel
        if isinstance(op_names, str):
            op_names = [op_names]
        if not isinstance(op_names, list):
            raise TypeError(f'op_names has to be a list. Got {type(op_names)}.')
        # remove duplicates
        op_names = set(op_names)
        for name in op_names:
            if name not in ALL_OPS:
                raise ValueError(f'Invalid operation name: {name}. {ALL_OPS} are supported.')
        if any(op_name in BWD_OPS_WITH_INPUTS for op_name in op_names):
            op_names.add(OP_SAVE_INPUTS)
            op_names.add(OP_SAVE_OUTPUTS)
        self._op_names = op_names
        self._op_results = {}
        self._damping = 1.e-7
        self._cov_scale = 1.
        self._sketching_size = 256
        self._truncated_rank = None

    def accumulate_result(self, value, *keys, extend=False):
        """
        Examples:
             accumulate_result(data, OP_COV_UNIT_WISE)
             accumulate_result(data, OP_BATCH_GRADS, 'weight')
             accumulate_result(A, OP_COV_KRON, 'A')
        """
        results = self._op_results
        if len(keys) > 1:
            for key in keys[:-1]:
                if results.get(key, None) is None:
                    results[key] = {}
                results = results[key]
        key = keys[-1]
        if results.get(key, None) is None:
            results[key] = value
        elif extend:
            results[key].extend(value)
        else:
            results[key] += value

    def get_result(self, *keys, pop=False, default=None):
        results = self._op_results
        if len(keys) > 1:
            for key in keys[:-1]:
                try:
                    results = results[key]
                except KeyError:
                    return None
        key = keys[-1]
        if pop:
            return results.pop(key, default)
        return results.get(key, default)

    def clear_result(self, *keys):
        results = self._op_results
        if len(keys) > 1:
            for key in keys[:-1]:
                results = results[key]
        key = keys[-1]
        results.pop(key, None)

    def clear_results(self):
        self._op_results = {}

    def add_op_name(self, op_name):
        if op_name not in self._op_names:
            self._op_names.add(op_name)

    def remove_op_name(self, op_name):
        while op_name in self._op_names:
            self._op_names.remove(op_name)

    def set_damping(self, value):
        self._damping = value

    def set_cov_scale(self, value):
        self._cov_scale = value

    def set_sketching_size(self, value):
        self._sketching_size = value

    def set_truncated_rank(self, value):
        self._truncated_rank = value

    def forward_post_process(self, in_data: torch.Tensor, out_data: torch.Tensor):
        module = self._module
        op_names = self._op_names
        cov_scale = self._cov_scale

        if OP_SAVE_INPUTS in op_names:
            self.accumulate_result([in_data], OP_SAVE_INPUTS, extend=True)
        if OP_SAVE_OUTPUTS in op_names:
            self.accumulate_result([out_data], OP_SAVE_OUTPUTS, extend=True)

        if any(op_name in FWD_OPS for op_name in op_names):
            in_data = self.preprocess_in_data(module, in_data, out_data)

        for op_name in op_names:
            if op_name not in FWD_OPS:
                continue
            if op_name == OP_COV_KRON:
                A = self.cov_kron_A(module, in_data).mul_(cov_scale)
                self.accumulate_result(A, OP_COV_KRON, 'A')
            elif op_name == OP_COV_SWIFT_KRON:
                A = self.cov_swift_kron_A(module, in_data).mul_(cov_scale)
                self.accumulate_result(A, OP_COV_KRON, 'A')  # not OP_COV_SWIFT_KRON
            elif op_name == OP_RFIM_RELU:
                self.accumulate_result(self.rfim_relu(module, in_data, out_data), OP_RFIM_RELU)
            elif op_name == OP_RFIM_SOFTMAX:
                self.accumulate_result(self.rfim_softmax(module, in_data, out_data), OP_RFIM_SOFTMAX)
            elif op_name == OP_MEAN_INPUTS:
                self.accumulate_result(self.in_data_mean(module, in_data), OP_MEAN_INPUTS)
            elif op_name == OP_MEAN_OUTPUTS:
                self.accumulate_result(self.out_data_mean(module, out_data), OP_MEAN_OUTPUTS)
            elif op_name == OP_SPATIAL_MEAN_OUTPUTS:
                self.accumulate_result(self.out_data_spatial_mean(module, out_data), OP_SPATIAL_MEAN_OUTPUTS)
            elif op_name == OP_OUT_SPATIAL_SIZE:
                self.accumulate_result(self.out_spatial_size(module, out_data), OP_OUT_SPATIAL_SIZE)
            elif op_name == OP_BFGS_KRON_S_AS:
                self.accumulate_result(self.bfgs_kron_s_As(module, in_data), OP_BFGS_KRON_S_AS)

    def backward_pre_process(self, out_grads, vector: torch.Tensor = None):
        module = self._module
        op_names = self._op_names
        cov_scale = self._cov_scale
        damping = self._damping

        if any(op_name in BWD_OPS for op_name in op_names):
            out_grads = self.preprocess_out_grads(module, out_grads)
            if OP_SAVE_OUTGRADS in op_names:
                self.accumulate_result([out_grads], OP_SAVE_OUTGRADS, extend=True)
        in_data = None
        if any(op_name in BWD_OPS_WITH_INPUTS for op_name in op_names):
            in_data = self.get_result(OP_SAVE_INPUTS)[-1]
            out_data = self.get_result(OP_SAVE_OUTPUTS)[-1]
            in_data = self.preprocess_in_data(module, in_data, out_data)
            del out_data

        for op_name in op_names:
            if op_name not in BWD_OPS:
                continue
            if op_name in [OP_COV, OP_COV_INV]:
                _, _, batch_g = self.collect_batch_grads(in_data, out_grads)
                cov = torch.matmul(batch_g.T, batch_g).mul_(cov_scale)
                if op_name == OP_COV:
                    self.accumulate_result(cov, OP_COV, 'data')
                else:
                    self.accumulate_result(cholesky_inv(cov, damping), OP_COV, 'inv')
            elif op_name == OP_CVP:
                _, _, batch_g = self.collect_batch_grads(in_data, out_grads)
                if vector is None:
                    raise ValueError('vector is not set.')
                if vector.ndim != 1:
                    raise ValueError(f'vector.ndim has to be 1. Got {vector.ndim}.')
                batch_gtv = batch_g.mul(vector.unsqueeze(0)).sum(dim=1)
                cvp = torch.einsum('ni,n->i', batch_g, batch_gtv).mul_(cov_scale)
                if original_requires_grad(module, 'weight'):
                    if original_requires_grad(module, 'bias'):
                        w_numel = module.weight.numel()
                        self.accumulate_result(cvp[:w_numel].view_as(module.weight), OP_CVP, 'weight')
                        self.accumulate_result(cvp[w_numel:].view_as(module.bias), OP_CVP, 'bias')
                    else:
                        self.accumulate_result(cvp.view_as(module.weight), OP_CVP, 'weight')
                else:
                    self.accumulate_result(cvp.view_as(module.bias), OP_CVP, 'bias')
            elif op_name == OP_COV_KRON:
                B = self.cov_kron_B(module, out_grads).mul_(cov_scale)
                self.accumulate_result(B, OP_COV_KRON, 'B')
            elif op_name == OP_COV_KRON_INV:
                A = self.cov_kron_A(module, in_data).mul_(cov_scale)
                del in_data
                B = self.cov_kron_B(module, out_grads).mul_(cov_scale)

                damping_A, damping_B = self.cov_kron_damping(A, B)
                A_inv = cholesky_inv(A, damping_A)
                del A
                B_inv = cholesky_inv(B, damping_B)
                del B
                self.accumulate_result(A_inv, OP_COV_KRON, 'A_inv')
                self.accumulate_result(B_inv, OP_COV_KRON, 'B_inv')
            elif op_name == OP_COV_SWIFT_KRON:
                B = self.cov_swift_kron_B(module, out_grads).mul_(cov_scale)
                self.accumulate_result(B, OP_COV_KRON, 'B')  # not OP_COV_SWIFT_KRON
            elif op_name == OP_COV_SWIFT_KRON_INV:
                A = self.cov_swift_kron_A(module, in_data)
                del in_data
                B = self.cov_swift_kron_B(module, out_grads)
                damping_A, damping_B = self.cov_kron_damping(A, B)

                if A.shape[0] == A.shape[1]:
                    A_inv = cholesky_inv(A.mul_(cov_scale), damping_A)
                else:
                    A_inv = smw_inv(A, damping_A)
                del A
                if B.shape[0] == B.shape[1]:
                    B_inv = cholesky_inv(B.mul_(cov_scale), damping_B)
                else:
                    B_inv = smw_inv(B, damping_B)
                del B
                self.accumulate_result(A_inv, OP_COV_KRON, 'A_inv')  # not OP_COV_SWIFT_KRON
                self.accumulate_result(B_inv, OP_COV_KRON, 'B_inv')  # not OP_COV_SWIFT_KRON
            elif op_name == OP_COV_KFE:
                Ua = self.cov_kfe_A(module, in_data)
                Ub = self.cov_kfe_B(module, out_grads)
                bias = original_requires_grad(module, 'bias')
                self.accumulate_result(Ua, OP_COV_KFE, 'A')
                self.accumulate_result(Ub, OP_COV_KFE, 'B')
                self.accumulate_result(self.cov_kfe_scale(module, in_data, out_grads, Ua, Ub, bias=bias),
                                       OP_COV_KFE, 'scale')
            elif op_name in [OP_COV_UNIT_WISE, OP_COV_UNIT_WISE_INV]:
                if isinstance(module, (nn.BatchNorm1d, nn.BatchNorm2d, nn.BatchNorm3d, nn.LayerNorm)):
                    if not (original_requires_grad(module, 'weight') and original_requires_grad(module, 'bias')):
                        raise ValueError(f'Both weight and bias have to require grad for {OP_COV_UNIT_WISE} (module: {module}).')
                elif original_requires_grad(module, 'bias'):
                    in_data = self.extend_in_data(in_data)
                cov = self.cov_unit_wise(module, in_data, out_grads).mul_(cov_scale)
                if op_name == OP_COV_UNIT_WISE:
                    self.accumulate_result(cov, OP_COV_UNIT_WISE, 'data')
                else:
                    diag = torch.diagonal(cov, dim1=1, dim2=2)
                    diag += damping
                    inv = torch.inverse(cov)
                    self.accumulate_result(inv, OP_COV_UNIT_WISE, 'inv')
            elif op_name in [OP_COV_DIAG, OP_COV_DIAG_INV]:
                if original_requires_grad(module, 'weight'):
                    cov = self.cov_diag_weight(module, in_data, out_grads).mul_(cov_scale)
                    if op_name == OP_COV_DIAG:
                        self.accumulate_result(cov, OP_COV_DIAG, 'weight')
                    else:
                        self.accumulate_result(1/(cov+damping), OP_COV_DIAG, 'weight_inv')
                if original_requires_grad(module, 'bias'):
                    cov = self.cov_diag_bias(module, out_grads).mul_(cov_scale)
                    if op_name == OP_COV_DIAG:
                        self.accumulate_result(cov, OP_COV_DIAG, 'bias')
                    else:
                        self.accumulate_result(1/(cov+damping), OP_COV_DIAG, 'bias_inv')
            elif op_name == OP_GRAM_HADAMARD:
                if self._model_for_kernel is None:
                    raise ValueError(f'model_for_kernel needs to be set for {OP_GRAM_HADAMARD}.')
                n_data = out_grads.shape[0]
                n1 = self._model_for_kernel.kernel.shape[0]
                if n_data == n1:
                    A = self.gram_A(module, in_data)
                else:
                    A = self.gram_A(module, in_data[:n1], in_data[n1:])
                del in_data
                if original_requires_grad(module, 'bias'):
                    A += 1.
                if n_data == n1:
                    B = self.gram_B(module, out_grads)
                else:
                    B = self.gram_B(module, out_grads[:n1], out_grads[n1:])
                self._model_for_kernel.kernel += B.mul(A)
            elif op_name == OP_GRAM_DIRECT:
                if self._model_for_kernel is None:
                    raise ValueError(f'model_for_kernel needs to be set for {OP_GRAM_DIRECT}.')
                n_data = in_data.shape[0]
                n1 = self._model_for_kernel.kernel.shape[0]

                batch_grads_w, batch_grads_b, batch_g = self.collect_batch_grads(in_data, out_grads)

                precond = getattr(module, 'gram_precond', None)
                if precond is not None:
                    precond.precondition_module(module, vec_weight=batch_grads_w, vec_bias=batch_grads_b)
                    grads = [g.flatten(start_dim=1) for g in [batch_grads_w, batch_grads_b] if g is not None]
                    batch_g2 = torch.cat(grads, dim=1)
                else:
                    batch_g2 = batch_g

                if n_data == n1:
                    self._model_for_kernel.kernel += torch.matmul(batch_g, batch_g2.T)
                else:
                    self._model_for_kernel.kernel += torch.matmul(batch_g[:n1], batch_g2[n1:].T)
            elif op_name == OP_BATCH_GRADS:
                if original_requires_grad(module, 'weight'):
                    rst = self.batch_grads_weight(module, in_data, out_grads)
                    self.accumulate_result(rst, OP_BATCH_GRADS, 'weight')
                if original_requires_grad(module, 'bias'):
                    rst = self.batch_grads_bias(module, out_grads)
                    self.accumulate_result(rst, OP_BATCH_GRADS, 'bias')
            elif op_name == OP_MEAN_OUTGRADS:
                self.accumulate_result(self.out_grads_mean(module, out_grads), OP_MEAN_OUTGRADS)
            elif op_name == OP_SPATIAL_MEAN_OUTGRADS:
                self.accumulate_result(self.out_grads_spatial_mean(module, out_grads), OP_SPATIAL_MEAN_OUTGRADS)
            elif op_name == OP_SKETCHED_GRAM:
                self.accumulate_result(self.random_sketch_and_gram(module, in_data, out_grads), OP_SKETCHED_GRAM)

    @staticmethod
    def preprocess_in_data(module, in_data, out_data):
        # no preprocess by default
        return in_data

    @staticmethod
    def preprocess_out_grads(module, out_grads):
        # no preprocess by default
        return out_grads

    @torch.no_grad()
    def collect_batch_grads(self, in_data, out_grads):
        module = self._module
        batch_grads_w = None
        batch_grads_b = None
        if original_requires_grad(module, 'weight'):
            batch_grads_w = self.batch_grads_weight(module, in_data, out_grads)
        if original_requires_grad(module, 'bias'):
            batch_grads_b = self.batch_grads_bias(module, out_grads)
        if batch_grads_w is None and batch_grads_b is None:
            raise ValueError(f'At least one of weight or bias has to require grad (module: {module}).')

        grads = [batch_grads_w, batch_grads_b]
        batch_g = torch.cat([g.flatten(start_dim=1) for g in grads if g is not None], dim=1)
        return batch_grads_w, batch_grads_b, batch_g

    @staticmethod
    def extend_in_data(in_data):
        # no extension by default
        return in_data

    @staticmethod
    def batch_grads_weight(module, in_data, out_grads):
        raise NotImplementedError

    @staticmethod
    def batch_grads_bias(module, out_grads):
        raise NotImplementedError

    @staticmethod
    def grad_weight(module, in_data, out_grads):
        raise NotImplementedError

    @staticmethod
    def grad_bias(module, out_grads):
        raise NotImplementedError

    @staticmethod
    def cov_diag_weight(module, in_data, out_grads):
        raise NotImplementedError

    @staticmethod
    def cov_diag_bias(module, out_grads):
        raise NotImplementedError

    @staticmethod
    def cov_kron_A(module, in_data):
        raise NotImplementedError

    @staticmethod
    def cov_swift_kron_A(module, in_data):
        raise NotImplementedError

    @staticmethod
    def cov_kron_B(module, out_grads):
        raise NotImplementedError

    @staticmethod
    def cov_swift_kron_B(module, out_grads):
        raise NotImplementedError

    def cov_kron_damping(self, A, B, eps=1.e-7):
        damping_A = damping_B = damping = self._damping
        A_eig_mean = (A.trace() if A.shape[0] == A.shape[1] else (A ** 2).sum()) / A.shape[-1]
        B_eig_mean = (B.trace() if B.shape[0] == B.shape[1] else (B ** 2).sum()) / B.shape[-1]
        pi = torch.sqrt(A_eig_mean / B_eig_mean)
        if pi != 0 and pi != float('inf'):
            r = damping**0.5
            damping_A = max(r * pi, eps)
            damping_B = max(r / pi, eps)
        return damping_A, damping_B

    @staticmethod
    def cov_kfe_A(module, in_data):
        raise NotImplementedError

    @staticmethod
    def cov_kfe_B(module, out_grads):
        raise NotImplementedError

    @staticmethod
    def cov_kfe_scale(module, in_data, out_grads, Ua, Ub, bias=True):
        raise NotImplementedError

    @staticmethod
    def cov_unit_wise(module, in_data, out_grads):
        raise NotImplementedError

    @staticmethod
    def gram_A(module, in_data1, in_data2=None):
        raise NotImplementedError

    @staticmethod
    def gram_B(module, out_grads1, out_grads2=None):
        raise NotImplementedError

    @staticmethod
    def rfim_relu(module, in_data, out_data):
        raise NotImplementedError

    @staticmethod
    def rfim_softmax(module, in_data, out_data):
        raise NotImplementedError

    @staticmethod
    def in_data_mean(module, in_data):
        raise NotImplementedError

    @staticmethod
    def out_data_mean(module, out_data):
        raise NotImplementedError

    def out_data_spatial_mean(self, module, out_data):
        return self.out_data_mean(module, out_data)

    @staticmethod
    def out_spatial_size(module, out_data):
        raise NotImplementedError

    @staticmethod
    def out_grads_mean(module, out_grads):
        raise NotImplementedError

    def out_grads_spatial_mean(self, module, out_grads):
        return self.out_grads_mean(module, out_grads)

    @staticmethod
    def bfgs_kron_s_As(module, in_data):
        raise NotImplementedError

    def random_sketch_and_gram(self, module, in_data, out_grads):
        """
        in_data: n x d_in (x r)
        out_grads: n x d_out (x r)
        """
        sketching_size = self._sketching_size

        def sketch(tensor):
            dim = tensor.shape[1]
            if sketching_size < dim:
                device = 'cuda' if torch.cuda.is_available() else 'cpu'
                indices = torch.randperm(dim, device=device)[:sketching_size]
                ratio = dim / sketching_size
                return torch.index_select(tensor, dim=1, index=indices).mul(ratio), indices
            else:
                return tensor, None

        sub_in_data, in_indices = sketch(in_data)  # n x d_in_sub (x r)
        sub_out_grads, out_indices = sketch(out_grads)  # n x d_out_sub (x r)
        gram_A = self.gram_A(module, sub_in_data)  # n x n
        gram_B = self.gram_B(module, sub_out_grads)  # n x n
        gram = gram_A.mul(gram_B)  # n x n
        return (in_data, out_grads), (sub_in_data, sub_out_grads), (in_indices, out_indices), gram

class OperationContext:
    def __init__(self, vectors: ParamVector = None):
        self._operations: Dict[nn.Module, Operation] = {}
        self._vectors: ParamVector = vectors
        self._input_scale = 1.
        self._output_scale = 1.

    def is_operation_registered(self, module: nn.Module):
        return module in self._operations

    def register_operation(self, module: nn.Module, operation: Operation):
        self._operations[module] = operation

    def get_vectors_by_module(self, module: nn.Module, flatten=False):
        if self._vectors is None:
            return None
        vectors = self._vectors.get_vectors_by_module(module)
        if vectors is None:
            return None
        if flatten:
            return vectors.get_flatten_vector()
        return vectors

    def get_operation(self, module: nn.Module) -> Operation:
        try:
            return self._operations[module]
        except KeyError:
            raise KeyError(f'No operation is registered to {module}.')

    def clear_operation(self, module: nn.Module):
        try:
            self._operations.pop(module)
        except KeyError:
            raise KeyError(f'No operation is registered to {module}.')

    def clear_operations(self):
        keys = list(self._operations.keys())
        for key in keys:
            del self._operations[key]

    def call_operations_in_forward(self, module, in_data, out_data):
        self.get_operation(module).forward_post_process(in_data, out_data)

    def call_operations_in_backward(self, module, out_grads):
        vector = self.get_vectors_by_module(module, flatten=True)
        self.get_operation(module).backward_pre_process(out_grads, vector)

    def get_result(self, module, *keys, pop=False, default=None):
        try:
            return self.get_operation(module).get_result(*keys, pop=pop, default=default)
        except KeyError:
            return default

    def accumulate_result(self, module, value, *keys):
        return self.get_operation(module).accumulate_result(value, *keys)

    def clear_result(self, module, *keys):
        return self.get_operation(module).clear_result(*keys)

    def turn_on_op(self, op_name):
        for operation in self._operations.values():
            operation.add_op_name(op_name)

    def turn_off_op(self, op_name):
        for operation in self._operations.values():
            operation.remove_op_name(op_name)

    def turn_on_save_inputs_outgrads(self):
        self.turn_on_op(OP_SAVE_INPUTS)
        self.turn_on_op(OP_SAVE_OUTGRADS)

    def turn_off_save_inputs_outgrads(self):
        self.turn_off_op(OP_SAVE_INPUTS)
        self.turn_off_op(OP_SAVE_OUTGRADS)

    def calc_grads(self, scale=None):
        for module in self._operations.keys():
            if original_requires_grad(module, 'weight') \
                    or original_requires_grad(module, 'bias'):
                self.calc_grad(module, scale)

    def calc_grad(self, module, scale=None):
        operation, in_data, out_grads = self.load_op_in_out(module)
        if scale is not None:
            if scale.shape[0] != out_grads.shape[0]:
                raise ValueError(f'scale and out_grads have to have the same first dimension. '
                                 f'Got {scale.shape[0]} and {out_grads.shape[0]}')
            out_grads.mul_(scale.unsqueeze(-1))
        if original_requires_grad(module, 'weight'):
            grad = operation.grad_weight(module, in_data, out_grads)
            if module.weight.grad is None:
                module.weight.grad = grad
            else:
                module.weight.grad.data.copy_(grad)
        if original_requires_grad(module, 'bias'):
            grad = operation.grad_bias(module, out_grads)
            if module.bias.grad is None:
                module.bias.grad = grad
            else:
                module.bias.grad.data.copy_(grad)

    def calc_kernel(self):
        kernel = None
        for module in self._operations.keys():
            if original_requires_grad(module, 'weight'):
                operation, in_data, out_grads = self.load_op_in_out(module)
                A = operation.gram_A(module, in_data, in_data)
                B = operation.gram_B(module, out_grads, out_grads)
                if kernel is None:
                    kernel = torch.zeros_like(A)
                kernel += A.mul(B)
                if original_requires_grad(module, 'bias'):
                    kernel += B
        return kernel

    def batch_grads(self, module, flatten=False):
        grads = self.get_result(module, OP_BATCH_GRADS)
        if grads is not None and flatten:
            return torch.cat([g.flatten(start_dim=1) for g in grads.values()], dim=1)
        else:
            return grads

    def clear_batch_grads(self):
        for operation in self._operations.values():
            if operation.get_result(OP_BATCH_GRADS, default=None) is not None:
                operation.clear_result(OP_BATCH_GRADS)

    def full_batch_grads(self, module):
        bg = [self.batch_grads(m, flatten=True) for m in module.modules()]
        bg = [_bg for _bg in bg if _bg is not None]
        if len(bg) == 0:
            return None
        return torch.cat(bg, dim=1)  # n x p

    def full_cov(self, module):
        return self.get_result(module, OP_FULL_COV)

    def calc_full_cov(self, module, scale=1., calc_inv=False, damping=1.e-7):
        """
        g: (p,)
        cov = sum[gg^t]: (p, p)
        """
        bg = self.full_batch_grads(module)
        if bg is None:
            return
        cov = torch.matmul(bg.T, bg).mul_(scale)  # p x p
        if calc_inv:
            self.accumulate_result(module, cholesky_inv(cov, damping), OP_FULL_COV, 'inv')
        else:
            self.accumulate_result(module, cov, OP_FULL_COV, 'data')

    def full_cvp(self, module):
        return self.get_result(module, OP_FULL_CVP)

    def calc_full_cvp(self, module, scale=1.):
        """
        g: (p,)
        c = sum[gg^t]: (p, p)
        v: (p,)
        cvp = sum[gg^t]v = sum[g(g^t)v]: (p,)
        """
        vector = self.get_vectors_by_module(module, flatten=True)
        bg = self.full_batch_grads(module)
        if bg is None:
            return
        if bg.shape[1] != vector.shape[0]:
            raise ValueError(f'bg.shape[1] ({bg.shape[1]}) does not mathc vector.shape[0] ({vector.shape[0]}).')
        bgtv = bg.mul(vector.unsqueeze(0)).sum(dim=1)
        cvp = torch.einsum('ni,n->i', bg, bgtv).mul_(scale)
        self.accumulate_result(module, cvp, OP_FULL_CVP)

    def load_op_in_out(self, module) -> Tuple[Operation, List[torch.Tensor], List[torch.Tensor]]:
        operation = self.get_operation(module)
        in_data = self.in_data(module)
        out_grads = self.out_grads(module)
        return operation, in_data, out_grads

    def cov(self, module):
        return self.get_result(module, OP_COV)

    def cvp(self, module):
        return self.get_result(module, OP_CVP)

    def cov_kron(self, module):
        return self.get_result(module, OP_COV_KRON)

    def cov_unit_wise(self, module):
        return self.get_result(module, OP_COV_UNIT_WISE)

    def cov_diag(self, module):
        return self.get_result(module, OP_COV_DIAG)

    def calc_cov(self, module, shape=SHAPE_LAYER_WISE, kron=None, clear_in_out=False, num_batches=None, swift=False, tag=''):
        operation, in_data, out_grads = self.load_op_in_out(module)
        if shape == SHAPE_KRON:
            if kron is None:
                kron = ['A', 'B']
            if 'A' in kron and in_data is not None:
                max_len = len(in_data) if num_batches is None else min(len(in_data), num_batches)
                with nvtx.range('cov_kron_A' + tag):
                    for i in range(max_len):
                        if clear_in_out:
                            tensor = in_data.pop(0)
                        else:
                            tensor = in_data[i]
                        if self._input_scale != 1:
                            tensor = tensor * self._input_scale
                        if swift:
                            A = operation.cov_swift_kron_A(module, tensor)
                        else:
                            A = operation.cov_kron_A(module, tensor)
                        self.accumulate_result(module, A, OP_COV_KRON, 'A')
            if 'B' in kron and out_grads is not None:
                max_len = len(out_grads) if num_batches is None else min(len(out_grads), num_batches)
                with nvtx.range('cov_kron_B' + tag):
                    for i in range(max_len):
                        if clear_in_out:
                            tensor = out_grads.pop(0)
                        else:
                            tensor = out_grads[i]
                        if self._output_scale != 1:
                            tensor = tensor * self._output_scale
                        if swift:
                            B = operation.cov_swift_kron_B(module, tensor)
                        else:
                            B = operation.cov_kron_B(module, tensor)
                        self.accumulate_result(module, B, OP_COV_KRON, 'B')
        else:
            if in_data is None or out_grads is None:
                return
            max_len = min(len(in_data), len(out_grads))
            if num_batches is not None:
                max_len = min(max_len, num_batches)
            with nvtx.range(f'cov_{shape}' + tag):
                for i in range(max_len):
                    if clear_in_out:
                        tensor1 = in_data.pop(0)
                        tensor2 = out_grads.pop(0)
                    else:
                        tensor1 = in_data[i]
                        tensor2 = out_grads[i]
                    if shape == SHAPE_LAYER_WISE:
                        _, _, batch_g = operation.collect_batch_grads(tensor1, tensor2)
                        cov = torch.matmul(batch_g.T, batch_g)
                        self.accumulate_result(module, cov, OP_COV)
                    elif shape == SHAPE_UNIT_WISE:
                        unit = operation.cov_unit_wise(module, tensor1, tensor2)
                        self.accumulate_result(module, unit, OP_COV_UNIT_WISE)
                    elif shape == SHAPE_DIAG:
                        diag_w = operation.cov_diag_weight(module, tensor1, tensor2)
                        self.accumulate_result(module, diag_w, OP_COV_DIAG, 'weight')
                        if original_requires_grad(module, 'bias'):
                            diag_b = operation.cov_diag_bias(module, tensor2)
                            self.accumulate_result(module, diag_b, OP_COV_DIAG, 'bias')

    def calc_cov_kron(self, module, clear_in_out=False):
        self.calc_cov(module, shape=SHAPE_KRON, clear_in_out=clear_in_out)

    def calc_cov_unit_wise(self, module, clear_in_out=False):
        self.calc_cov(module, shape=SHAPE_UNIT_WISE, clear_in_out=clear_in_out)

    def calc_cov_diag(self, module, clear_in_out=False):
        self.calc_cov(module, shape=SHAPE_DIAG, clear_in_out=clear_in_out)

    def cov_symmatrix(self, module, pop=False):
        kwargs = dict()
        cov = self.get_result(module, OP_COV, pop=pop)
        if cov is not None:
            kwargs['data'] = cov.pop('data', None)
            kwargs['inv'] = cov.pop('inv', None)
        cov_kron = self.get_result(module, OP_COV_KRON, pop=pop)
        if cov_kron is not None:
            kwargs['kron_A'] = cov_kron.pop('A', None)
            kwargs['kron_B'] = cov_kron.pop('B', None)
            kwargs['kron_A_inv'] = cov_kron.pop('A_inv', None)
            kwargs['kron_B_inv'] = cov_kron.pop('B_inv', None)
        cov_kfe = self.get_result(module, OP_COV_KFE, pop=pop)
        if cov_kfe is not None:
            kwargs['kfe_A'] = cov_kfe.pop('A', None)
            kwargs['kfe_B'] = cov_kfe.pop('B', None)
            kwargs['kfe_scale'] = cov_kfe.pop('scale', None)
        cov_unit = self.get_result(module, OP_COV_UNIT_WISE, pop=pop)
        if cov_unit is not None:
            kwargs['unit_data'] = cov_unit.pop('data', None)
            kwargs['unit_inv'] = cov_unit.pop('inv', None)
        cov_diag = self.get_result(module, OP_COV_DIAG, pop=pop)
        if cov_diag is not None:
            if original_requires_grad(module, 'weight'):
                kwargs['diag_weight'] = cov_diag.pop('weight', None)
                kwargs['diag_weight_inv'] = cov_diag.pop('weight_inv', None)
            if original_requires_grad(module, 'bias'):
                kwargs['diag_bias'] = cov_diag.pop('bias', None)
                kwargs['diag_bias_inv'] = cov_diag.pop('bias_inv', None)
        if all(v is None for v in kwargs.values()):
            return None
        return SymMatrix(**kwargs)

    def full_cov_symmatrix(self, module, pop=False):
        cov = self.get_result(module, OP_FULL_COV, pop=pop)
        if cov is None:
            return
        return SymMatrix(data=cov.pop('data', None), inv=cov.pop('inv', None))

    def register_symmatrix(self, module, matrix: SymMatrix):
        operation = self.get_operation(module)
        if matrix.has_data:
            operation.accumulate_result(matrix.data, OP_COV, 'data')
        if matrix.has_kron:
            if matrix.kron.has_A:
                operation.accumulate_result(matrix.kron.A, OP_COV_KRON, 'A')
            if matrix.kron.has_B:
                operation.accumulate_result(matrix.kron.B, OP_COV_KRON, 'B')
        if matrix.has_kfe:
            if matrix.kfe.has_Ua:
                operation.accumulate_result(matrix.kfe.Ua, OP_COV_KFE, 'A')
            if matrix.kfe.has_Ub:
                operation.accumulate_result(matrix.kfe.Ub, OP_COV_KFE, 'B')
            if matrix.kfe.has_scale:
                operation.accumulate_result(matrix.kfe.scale, OP_COV_KFE, 'scale')
        if matrix.has_unit and matrix.unit.has_data:
            operation.accumulate_result(matrix.unit.data, OP_COV_UNIT_WISE, 'data')
        if matrix.has_diag:
            if matrix.diag.has_weight:
                operation.accumulate_result(matrix.diag.weight, OP_COV_DIAG, 'weight')
            if matrix.diag.has_bias:
                operation.accumulate_result(matrix.diag.bias, OP_COV_DIAG, 'bias')

    def register_full_symmatrix(self, module, matrix: SymMatrix):
        if not matrix.has_data:
            raise ValueError('data do not exist')
        operation = self.get_operation(module)
        operation.accumulate_result(matrix.data, OP_FULL_COV, 'data')

    def cvp_paramvector(self, module, pop=False):
        cvp = self.get_result(module, OP_CVP, pop=pop)
        if cvp is None:
            return None
        params = []
        vectors = []
        if original_requires_grad(module, 'weight'):
            params.append(module.weight)
            vectors.append(cvp['weight'])
        if original_requires_grad(module, 'bias'):
            params.append(module.bias)
            vectors.append(cvp['bias'])
        return ParamVector(params, vectors)

    def full_cvp_paramvector(self, module, pop=False):
        cvp = self.get_result(module, OP_FULL_CVP, pop=pop)
        if cvp is None:
            return None
        params = [p for p in module.parameters() if original_requires_grad(param=p)]
        return ParamVector(params, cvp)

    def rfim_relu(self, module):
        return self.get_result(module, OP_RFIM_RELU)

    def rfim_softmax(self, module):
        return self.get_result(module, OP_RFIM_SOFTMAX)

    def set_input_scale(self, scale):
        self._input_scale = scale

    def set_output_scale(self, scale):
        self._output_scale = scale

    def in_data(self, module, pop=False):
        return self.get_result(module, OP_SAVE_INPUTS, pop=pop)

    def out_data(self, module, pop=False):
        return self.get_result(module, OP_SAVE_OUTPUTS, pop=pop)

    def out_grads(self, module, pop=False):
        return self.get_result(module, OP_SAVE_OUTGRADS, pop=pop)

    def mean_in_data(self, module):
        return self.get_result(module, OP_MEAN_INPUTS)

    def mean_out_data(self, module):
        return self.get_result(module, OP_MEAN_OUTPUTS)

    def spatial_mean_out_data(self, module):
        return self.get_result(module, OP_SPATIAL_MEAN_OUTPUTS)

    def out_spatial_size(self, module):
        return self.get_result(module, OP_OUT_SPATIAL_SIZE)

    def mean_out_grads(self, module):
        return self.get_result(module, OP_MEAN_OUTGRADS)

    def spatial_mean_out_grads(self, module):
        return self.get_result(module, OP_SPATIAL_MEAN_OUTGRADS)

    def bfgs_kron_s_As(self, module):
        return self.get_result(module, OP_BFGS_KRON_S_AS)

    def sketched_inputs_outgrads_gram(self, module):
        return self.get_result(module, OP_SKETCHED_GRAM)

    def set_damping(self, value):
        for operation in self._operations.values():
            operation.set_damping(value)

    def set_cov_scale(self, value):
        for operation in self._operations.values():
            operation.set_cov_scale(value)

    def set_sketching_size(self, value):
        for operation in self._operations.values():
            operation.set_sketching_size(value)

    def set_truncated_rank(self, value):
        for operation in self._operations.values():
            operation.set_truncated_rank(value)


import urllib.request, urllib.parse, urllib.error
import json

def solve(board):
    """
    solves sudoku board using backtracking
    board: 2d list of ints
    return: solution
    """

    find = find_empty(board)
    if find:
        row, col = find
    else:
        return True

    for i in range(1,10):
        if valid(board, (row, col), i):
            board[row][col] = i

            if solve(board):
                return True

            board[row][col] = 0

    return False

def valid(board, pos, num):
    """
    returns if the attempted move is valid
    board: 2d list of ints
    pos: (row, col)
    num: int
    return: bool
    """

    #check row
    for i in range(0, len(board)):
        if board[pos[0]][i] == num and pos[1] != i:
            return False

    #check column
    for i in range(0, len(board)):
        if board[i][pos[1]] == num and pos[0] != i:
            return False

    #checks box
    box_x = pos[1]//3
    box_y = pos[0]//3

    for i in range(box_y*3, box_y*3+3):
        for j in range(box_x*3, box_x*3 + 3):
            if board[i][j] == num and (i,j) != pos:
                return False

    return True

def find_empty(board):
    """
    finds empty space in the board
    board: partially complete board
    return: (int, row) row col
    """

    for i in range(len(board)):
        for j in range(len(board[0])):
            if board[i][j] == 0:
                return (i,j)

    return None

def print_board(board):
    '''
    prints the board
    board: 2d list of ints
    return: none
    '''
    for i in range(len(board)):
        if i % 3 == 0 and i != 0:
            print("- - - - - - - - - - - - - ")

        for j in range(len(board[0])):
            if j % 3 == 0 and j != 0:
                print(" | ", end="")

            if j == 8:
                print(board[i][j])
            else:
                print(str(board[i][j]) + " ", end="")

while True:
    serviceurl = 'http://www.cs.utep.edu/cheon/ws/sudoku/new/'
    board = [[0 for i in range(1,10)] for j in range(1,10)]
    level = input("Enter level (1,2,3):")
    if len(level) < 1: break

    url = serviceurl + '?size=9?level=' + level

    uh = urllib.request.urlopen(url)
    data = uh.read().decode()

    try:
        js = json.loads(data)
    except:
        js = None

    if not js or 'response' not in js or js['response'] != True:
        print('==== Failure to Retrieve ====')
        print(data)
        continue

    for square in js['squares']:
        i = square["x"]
        j = square["y"]
        board[i][j] = square["value"]

    print_board(board)
    print()
    solve(board)
    print_board(board)


# -*- coding: utf-8 -*-
"""
Editor de Spyder

Este es un archivo temporal.
"""

import os, re
import datetime as dt
import os.path as op

basedir = r'C:\Users\gonzalo\Projects\data\Espectros'

audits = [op.join(d[0], 'audita.txt') for d in os.walk(basedir)
            if 'audita.txt' in d[2]]

total_time = 0
records = []

for audit in audits:
    with open(audit) as au:
        path_list = op.normpath(audit).split('\\') # ('/') # for linux
        user_name, sample_name, expno = path_list[-4:-1]

        contents = au.read()

        # find starting time
        start_str = re.findall(r'started at (\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}.\d{3} \+\d{4})',
                           contents)
        # check for starting time matching
        if len(start_str) == 1:
            start_time = dt.datetime.strptime(start_str[0], '%Y-%m-%d %H:%M:%S.%f %z')
        else:
            print('Starting time not found for: %s' % op.dirname(audit))
            continue
        # find starting time
        finish_str = re.findall(r'finished successfully at (\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}.\d{3} \+\d{4})',
                           contents)
        if len(finish_str) == 1:
            finish_time = dt.datetime.strptime(finish_str[0], '%Y-%m-%d %H:%M:%S.%f %z')
        else:
            print('Finish time not found for: %s' % op.dirname(audit))
            continue

        duration = finish_time - start_time

        print(audit, user_name, sample_name, expno, start_time.ctime(), finish_time.ctime(), duration)


# -*- coding: utf-8 -*-
"""Common Actions for Domestic Page Objects"""
import logging

from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.remote.webdriver import WebDriver

from directory_tests_shared.constants import MD5_CHECKSUM_DIT_FAVICON
from pages.common_actions import (
    check_hash_of_remote_file,
    find_element,
    find_selector_by_name,
    wait_for_page_load_after_action,
)
from pages.common_selectors import DOMESTIC_HEADER, EXOPPS_FAVICON, FAVICON, LOGOS

def search(driver: WebDriver, phrase: str):
    search_input = find_element(
        driver, find_selector_by_name(DOMESTIC_HEADER, "search box")
    )
    search_button = find_element(
        driver, find_selector_by_name(DOMESTIC_HEADER, "search button")
    )
    search_input.clear()
    search_input.send_keys(phrase)
    search_button.click()

def go_to_sign_out(driver: WebDriver):
    sign_out_link = find_element(
        driver, find_selector_by_name(DOMESTIC_HEADER, "sign out")
    )
    with wait_for_page_load_after_action(driver):
        sign_out_link.click()

def check_logo(driver: WebDriver, logo_name: str):
    logo = LOGOS[logo_name.lower()]
    logo_element = find_element(driver, logo["selector"], wait_for_it=False)
    src = logo_element.get_attribute("src")
    if not src:
        logging.debug(f"IMG SRC is empty will try to use 'data-src' for {logo}")
        src = logo_element.get_attribute("data-src")
    check_hash_of_remote_file(logo["md5"], src)
    logging.debug(f"{src} has correct MD5sum {logo['md5']}")

def check_dit_favicon(driver: WebDriver):
    try:
        favicon = find_element(
            driver, FAVICON, element_name="Favicon", wait_for_it=False
        )
    except NoSuchElementException:
        try:
            favicon = find_element(
                driver, EXOPPS_FAVICON, element_name="Favicon", wait_for_it=False
            )
        except NoSuchElementException:
            raise
    src = favicon.get_attribute("href")
    check_hash_of_remote_file(MD5_CHECKSUM_DIT_FAVICON, src)
    logging.debug("Favicon %s has correct MD5sum %s", src, MD5_CHECKSUM_DIT_FAVICON)


# -*- coding: utf-8 -*-
import os
import sys
import random
from typing import Any, Union

import cv2
import torch
import numpy as np
from scipy import misc
from tqdm import tqdm

def calc_tv_loss(inp, mask=None, eps=1e-8):
    """ 提供inp平滑性约束 """
    x_diff = inp[:, :, 1:, 1:] - inp[:, :, :-1, 1:]
    y_diff = inp[:, :, 1:, 1:] - inp[:, :, 1:, :-1]
    if mask is not None:
        x_diff *= mask[:, :, 1:, 1:]
        y_diff *= mask[:, :, 1:, 1:]

    # loss = torch.mean(torch.abs(x_diff) + torch.abs(y_diff))
    loss = torch.mean(torch.sqrt(torch.square(inp) + torch.square(inp) + eps))
    return loss

def load_test_data(image_path, size=256):
    img = misc.imread(image_path, mode='RGB')
    img = misc.imresize(img, [size, size])
    img = np.expand_dims(img, axis=0)
    img = preprocessing(img)

    return img

def preprocessing(x):
    x = x / 127.5 - 1  # -1 ~ 1
    return x

def save_images(images, size, image_path):
    return imsave(inverse_transform(images), size, image_path)

def inverse_transform(images):
    return (images + 1.) / 2

def imsave(images, size, path):
    return misc.imsave(path, merge(images, size))

def merge(images, size):
    h, w = images.shape[1], images.shape[2]
    img = np.zeros((h * size[0], w * size[1], 3))
    for idx, image in enumerate(images):
        i = idx % size[1]
        j = idx // size[1]
        img[h * j:h * (j + 1), w * i:w * (i + 1), :] = image

    return img

def check_folder(log_dir):
    if not os.path.exists(log_dir):
        os.makedirs(log_dir)
    return log_dir

def cam(x, size=256):
    x = x - np.min(x)
    cam_img = x / np.max(x)
    cam_img = np.uint8(255 * cam_img)
    cam_img = cv2.resize(cam_img, (size, size))
    cam_img = cv2.applyColorMap(cam_img, cv2.COLORMAP_JET)
    return cam_img / 255.0

def attention_mask(x, size=256):
    attention_img = cv2.resize(np.uint8(255 * x), (size, size))
    attention_img = cv2.applyColorMap(attention_img, cv2.COLORMAP_JET)
    return attention_img / 255.0

def imagenet_norm(x):
    mean = [0.485, 0.456, 0.406]
    std = [0.299, 0.224, 0.225]
    mean = torch.FloatTensor(mean).unsqueeze(0).unsqueeze(2).unsqueeze(3).to(x.device)
    std = torch.FloatTensor(std).unsqueeze(0).unsqueeze(2).unsqueeze(3).to(x.device)
    return (x - mean) / std

def denorm(x):
    return x * 0.5 + 0.5

def tensor2numpy(x):
    return x.detach().cpu().numpy().transpose(1, 2, 0)

def RGB2BGR(x):
    return cv2.cvtColor(x, cv2.COLOR_RGB2BGR)

def setup_seed(seed):
    torch.manual_seed(seed)
    torch.cuda.manual_seed_all(seed)
    np.random.seed(seed)
    random.seed(seed)
    torch.backends.cudnn.deterministic = True

"""
评估量：记录，打印
"""

class AverageMeter:
    """ 计算并存储 评估量的均值和当前值 """

    def __init__(self, name, fmt=':f'):
        self.name = name  # 评估量名称
        self.fmt = fmt  # 评估量打印格式
        self.val = 0  # 评估量当前值
        self.avg = 0  # 评估量均值
        self.sum = 0  # 历史评估量的和
        self.count = 0  # 历史评估量的数量

    def reset(self):
        self.val = 0
        self.avg = 0
        self.sum = 0
        self.count = 0

    def update(self, val, n=1):
        self.val = val
        self.sum += val * n
        self.count += n
        self.avg = self.sum / self.count

    def __str__(self):
        fmtstr = f'{{name}} {{val{self.fmt}}} ({{avg{self.fmt}}})'
        return fmtstr.format(**self.__dict__)

class ProgressMeter:
    """ 评估量的进度条打印 """

    def __init__(self, num_batches, *meters, prefix=""):
        self.batch_fmtstr = self._get_batch_fmtstr(num_batches)
        self.meters = meters
        self.prefix = prefix

    def print(self, batch):
        entries = [self.prefix + self.batch_fmtstr.format(batch)]
        entries += [str(meter) for meter in self.meters]
        print('\t'.join(entries))

    @staticmethod
    def _get_batch_fmtstr(num_batches):
        num_digits = len(str(num_batches // 1))
        fmt = f'{{:{str(num_digits)}d}}'
        return f'[{fmt}/{fmt.format(num_batches)}]'

class Logger(object):
    """
    Redirect stderr to stdout, optionally print stdout to a file,
    and optionally force flushing on both stdout and the file.
    """

    def __init__(self, file_name: str = None, file_mode: str = "w", should_flush: bool = True):
        self.file = None

        if file_name is not None:
            self.file = open(file_name, file_mode)

        self.should_flush = should_flush
        self.stdout = sys.stdout
        self.stderr = sys.stderr

        sys.stdout = self
        sys.stderr = self

    def __enter__(self) -> "Logger":
        return self

    def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None:
        self.close()

    def write(self, text: Union[str, bytes]) -> None:
        """Write text to stdout (and a file) and optionally flush."""
        if isinstance(text, bytes):
            text = text.decode()
        if len(text) == 0:  # workaround for a bug in VSCode debugger: sys.stdout.write(''); sys.stdout.flush() => crash
            return

        if self.file is not None:
            self.file.write(text)

        self.stdout.write(text)

        if self.should_flush:
            self.flush()

    def flush(self) -> None:
        """Flush written text to both stdout and a file, if open."""
        if self.file is not None:
            self.file.flush()

        self.stdout.flush()

    def close(self) -> None:
        """Flush, close possible files, and remove stdout/stderr mirroring."""
        self.flush()

        # if using multiple loggers, prevent closing in wrong order
        if sys.stdout is self:
            sys.stdout = self.stdout
        if sys.stderr is self:
            sys.stderr = self.stderr

        if self.file is not None:
            self.file.close()
            self.file = None

"""
制作模糊图像
"""

def generate_blur_images(root, save):
    """ 根据清晰图像制作模糊的图像
    :param root: 清晰图像所在的根目录
    :param save: 模糊图像存放的根目录
    """
    print(f'generating blur images: {root} to {save}...')
    file_list = os.listdir(root)
    if not os.path.isdir(save):
        os.makedirs(save)
    kernel_size = 5
    kernel = np.ones((kernel_size, kernel_size), np.uint8)
    gauss = cv2.getGaussianKernel(kernel_size, 0)
    gauss = gauss * gauss.transpose(1, 0)
    for f in tqdm(file_list):
        try:
            rgb_img = cv2.imread(os.path.join(root, f))
            gray_img = cv2.imread(os.path.join(root, f), 0)
            pad_img = np.pad(rgb_img, ((2, 2), (2, 2), (0, 0)), mode='reflect')
            edges = cv2.Canny(gray_img, 100, 200)
            dilation = cv2.dilate(edges, kernel)

            gauss_img = np.copy(rgb_img)
            idx = np.where(dilation != 0)
            for i in range(np.sum(dilation != 0)):
                gauss_img[idx[0][i], idx[1][i], 0] = np.sum(
                    np.multiply(pad_img[idx[0][i]:idx[0][i] + kernel_size, idx[1][i]:idx[1][i] + kernel_size, 0],
                                gauss))
                gauss_img[idx[0][i], idx[1][i], 1] = np.sum(
                    np.multiply(pad_img[idx[0][i]:idx[0][i] + kernel_size, idx[1][i]:idx[1][i] + kernel_size, 1],
                                gauss))
                gauss_img[idx[0][i], idx[1][i], 2] = np.sum(
                    np.multiply(pad_img[idx[0][i]:idx[0][i] + kernel_size, idx[1][i]:idx[1][i] + kernel_size, 2],
                                gauss))

            cv2.imwrite(os.path.join(save, f), gauss_img)
        except Exception as e:
            print(f'{f} failed!\n{e}')

    print(f'finish: blur images over! ')


#!/usr/bin/env python
# activity.py
#
# Activity functions with keras.py
# DSDE Deep Learning
# June 2018
# Sam Friedman
# sam@broadinstitute.org

from __future__ import print_function

import os
import sys
import math
import h5py
import gzip
import pickle
import argparse
import matplotlib
import numpy as np
matplotlib.use('Agg')
from scipy import interp
from keras import metrics
import keras.backend as K
from random import shuffle
from Bio import Seq, SeqIO
from itertools import cycle
import matplotlib.pyplot as plt
from collections import Counter

from keras.optimizers import SGD, Adam
from keras.models import Sequential, Model
from sklearn.metrics import roc_curve, auc, roc_auc_score
from keras.callbacks import ModelCheckpoint, EarlyStopping
from keras.layers.convolutional import Convolution1D, MaxPooling1D, Conv1D
from keras.layers import Input, Dense, Dropout, BatchNormalization, SpatialDropout1D, Activation, Flatten

data_path = '/dsde/data/deep/'
reference_fasta = data_path + 'Homo_sapiens_assembly19.fasta'
chrom_hmm_bed_file = data_path + 'wgEncodeAwgSegmentationCombinedGm12878.bed'
breakpoint_bed_file =  '/dsde/data/deep/vqsr/beds/icgc_bkp_sorted.bed'

amiguity_codes = {'K':[0,0,0.5,0.5], 'M':[0.5,0.5,0,0], 'R':[0.5,0,0,0.5], 'Y':[0,0.5,0.5,0], 'S':[0,0.5,0,0.5],
				  'W':[0.5,0,0.5,0], 'B':[0,0.333,0.333,0.334], 'V':[0.333,0.333,0,0.334],'H':[0.333,0.333,0.334,0],
				  'D':[0.333,0,0.333,0.334], 'N':[0.25,0.25,0.25,0.25]}

label_sets = {
	'chrom_hmm'  : {'TSS':0, 'PF':1, 'E':2, 'WE':3, 'CTCF':4, 'T':5, 'R':6 },
	'breakpoint' : {'WT':0, 'BREAKPOINT':1}
}

def run():
	args = parse_args()
	multilayer_perceptron_on_mnist(args)

def parse_args():
	parser = argparse.ArgumentParser()

	parser.add_argument('--mode', default='bp')
	parser.add_argument('--activation', default='relu',
		help="The neuronal activation type (keras string like 'relu' of make your own...")
	parser.add_argument('--window_size', default=64, type=int)
	parser.add_argument('--samples', default=1000, type=int)
	parser.add_argument('--activity', default=0, type=int)
	parser.add_argument('--reference_fasta', default=reference_fasta)
	parser.add_argument('--bed_file',default=breakpoint_bed_file)
	parser.add_argument('--inputs', default={'A':0, 'C':1, 'T':2, 'G':3})
	parser.add_argument('--epochs', default=15, type=int, help='Training epochs.')
	parser.add_argument('--batch_size', default=32, type=int, help='Training mini batch size.')
	parser.add_argument('--label_set', default='breakpoint', choices=label_sets.keys())
	parser.add_argument('--labels', default={})
	parser.add_argument('--conv_width', default=5, type=int, help='Width of 1D convolutional kernels.')
	parser.add_argument('--conv_dropout', default=0.0, type=float,
		help='Dropout rate in convolutional layers.')
	parser.add_argument('--conv_batch_normalize', default=False, action='store_true',
		help='Batch normalize convolutional layers.')
	parser.add_argument('--conv_layers', nargs='+', default=[128, 96, 64, 48], type=int,
		help='List of sizes for each convolutional filter layer')
	parser.add_argument('--kernel_initializer', default='he_normal',
		help='convolution kernel initializer.')
	parser.add_argument('--same_padding', default=False, action='store_true',
		help='Valid or same border padding on the convolutional layers.')
	parser.add_argument('--spatial_dropout', default=False, action='store_true',
		help='Spatial dropout on the convolutional layers.')
	parser.add_argument('--max_pools', nargs='+', default=[], type=int,
		help='List of maxpooling layers.')
	parser.add_argument('--fc_layers', nargs='+', default=[32], type=int,
		help='List of sizes for each fully connected layer')
	parser.add_argument('--fc_dropout', default=0.0, type=float,
		help='Dropout rate in fully connected  layers.')
	parser.add_argument('--fc_batch_normalize', default=False, action='store_true',
		help='Batch normalize fully connected layers.')
	parser.add_argument('--fc_initializer', default='he_normal',
		help='fully connected layer initializer')

	args = parser.parse_args()
	args.labels = label_sets[args.label_set]
	print('Arguments are', args)
	return args

def activity_1d_model_from_args(args):
	'''Build Reference 1d CNN model for classification.

	Architecture specified by parameters.
	Dynamically sets input channels based on args via defines.total_input_channels_from_args(args)
	Uses the functional API.
	Prints out model summary.

	Arguments
		args.labels: The output labels (e.g. BREAKPOINT, WT)

	Returns
		The keras model
	'''
	concat_axis = -1
	x = reference = Input(shape=(args.window_size, len(args.inputs)), name='reference')

	max_pool_diff = len(args.conv_layers)-len(args.max_pools)
	for  i,c in enumerate(args.conv_layers):

		x = Conv1D(filters=c, kernel_size=args.conv_width, activation='linear', padding=args.padding, kernel_initializer=args.kernel_initializer)(x)
		if args.conv_batch_normalize:
			x = BatchNormalization(axis=concat_axis)(x)
		x = Activation(args.activation)(x)

		if args.conv_dropout > 0 and args.spatial_dropout:
			x = SpatialDropout1D(args.conv_dropout)(x)
		elif conv_dropout > 0:
			x = Dropout(args.conv_dropout)(x)

		if i >= max_pool_diff:
			x = MaxPooling1D(args.max_pools[i-max_pool_diff])(x)

	x = Flatten()(x)

	for fc in args.fc_layers:
		if args.fc_batch_normalize:
			x = Dense(units=fc, activation='linear', kernel_initializer=args.fc_initializer)(x)
			x = BatchNormalization(axis=1)(x)
			x = Activation('relu')(x)
		else:
			x = Dense(units=fc, activation=args.activation)(x)

		if fc_dropout > 0:
			x = Dropout(fc_dropout)(x)

	prob_output = Dense(units=len(args.labels), activation='softmax')(x)

	model = Model(inputs=[reference], outputs=[prob_output])

	adam = Adam(lr=0.0001, beta_1=0.9, beta_2=0.999, epsilon=1e-08)
	my_metrics = [metrics.binary_accuracy]

	model.compile(optimizer=adam, loss='binary_crossentropy', metrics=my_metrics)
	model.summary()

	return model

def multilayer_perceptron_on_mnist(args):
	train, test, valid = load_data('mnist.pkl.gz')

	num_labels = 10
	train_y = make_one_hot(train[1], num_labels)
	valid_y = make_one_hot(valid[1], num_labels)
	test_y = make_one_hot(test[1], num_labels)

	mlp_model = Sequential()
	for fc in args.fc_layers:
		mlp_model.add(Dense(fc, activation=args.activation, input_dim=784))

	mlp_model.add(Dense(num_labels, activation='softmax'))
	mlp_model.compile(loss='categorical_crossentropy', optimizer='sgd', metrics=['accuracy'])
	mlp_model.summary()

	print('Train multilayer perceptron on MNIST. Test set loss and accuracy:', mlp_model.evaluate(test[0], test_y))
	mlp_model.fit(train[0], train_y, validation_data=(valid[0],valid_y), batch_size=32, epochs=args.epochs)
	print('Multilayer Perceptron trained. Test set loss and accuracy:', mlp_model.evaluate(test[0], test_y))

def make_one_hot(y, num_labels):
	ohy = np.zeros((len(y), num_labels))
	for i in range(0, len(y)):
		ohy[i][y[i]] = 1.0
	return ohy

def load_data(dataset):
	''' Loads the dataset
	:type dataset: string
	:param dataset: the path to the dataset (here MNIST)
	'''

	#############
	# LOAD DATA #
	#############

	# Download the MNIST dataset if it is not present
	data_dir, data_file = os.path.split(dataset)
	if data_dir == "" and not os.path.isfile(dataset):
		# Check if dataset is in the data directory.
		new_path = os.path.join(
			os.path.split(__file__)[0],
			"data",
			dataset
		)
		if os.path.isfile(new_path) or data_file == 'mnist.pkl.gz':
			dataset = new_path

	if (not os.path.isfile(dataset)) and data_file == 'mnist.pkl.gz':
		origin = ('http://www.iro.umontreal.ca/~lisa/deep/data/mnist/mnist.pkl.gz')
		print('Downloading data from %s' % origin)
		if not os.path.exists(os.path.dirname(dataset)):
			os.makedirs(os.path.dirname(dataset))
		if (sys.version_info > (3, 0)):
			from urllib.request import urlretrieve
			urlretrieve(origin, dataset)
		else:
			import urllib
			urllib.urlretrieve(origin, dataset)

	print('loading data...')

	# Load the dataset
	f = gzip.open(dataset, 'rb')
	if sys.version_info[0] == 3:
		u = pickle._Unpickler(f)
		u.encoding = 'latin1'
		train_set, valid_set, test_set = u.load()
	else:
		train_set, valid_set, test_set = pickle.load(f)

	f.close()
	#train_set, valid_set, test_set format: tuple(input, target)
	#input is an numpy.ndarray of 2 dimensions (a matrix)
	#which row's correspond to an example. target is a
	#numpy.ndarray of 1 dimensions (vector)) that have the same length as
	#the number of rows in the input. It should give the target
	#target to the example with the same index in the input.

	return train_set, valid_set, test_set

if '__main__'==__name__:
	run()