from socket import SOL_SOCKET, SOCK_STREAM, SO_REUSEADDR, socket, AF_INET, SOCK_DGRAM
from contextlib import closing
from requests import packages, Session
from requests.adapters import HTTPAdapter

def getMyIpAddr():
    s = socket(AF_INET, SOCK_DGRAM)
    try:
        # google DNS should be ping-able
        s.connect(("8.8.8.8", 1))
        IP = s.getsockname()[0]
    except OSError:
        IP = "127.0.0.1"
    finally:
        s.close()
    return IP

def findFreePort():
    with closing(socket(AF_INET, SOCK_STREAM)) as s:
        s.bind(('', 0))
        s.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
        return s.getsockname()[1]

# This creates a session request that will retry with backoff timing.
def requestsRetrySession(retries=1, backoff_factor=0.3, status_forcelist=(500, 502, 504), session=None):
    session = session or Session()
    retry = packages.urllib3.util.retry.Retry(
        total=retries,
        read=retries,
        connect=retries,
        backoff_factor=backoff_factor,
        status_forcelist=status_forcelist,
    )
    adapter = HTTPAdapter(max_retries=retry)
    session.mount("http://", adapter)
    session.mount("https://", adapter)
    return session


import torch
from tqdm.auto import tqdm
import wandb
from utils import save_model

def train_step(model,
               dataloader,
               optimizer,
               device):
    model.train()
    train_loss = 0
    for batch, (images, masks) in enumerate(dataloader):
        images, masks = images.to(device), masks.to(device)
        logits, loss = model(images, masks)

        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

        train_loss += loss.item()

    train_loss = train_loss / len(dataloader)
    return train_loss

def val_step(model,
              dataloader,
              device):
    model.eval()
    val_loss = 0

    with torch.inference_mode():
        for batch, (images, masks) in enumerate(dataloader):
            images, masks = images.to(device), masks.to(device)
            logits, loss = model(images, masks)
            val_loss += loss.item()

    val_loss = val_loss / len(dataloader)
    return val_loss

def train(model,
          train_dataloader,
          test_dataloader,
          optimizer,
          epochs,
          earlystopping,
          model_name,
          device):

    results = {"train_loss": [],
               "test_loss": [],
    }

    model.to(device)

    for epoch in tqdm(range(epochs)):
        train_loss = train_step(model=model,
                                dataloader=train_dataloader,
                                optimizer=optimizer,
                                device=device)

        test_loss = val_step(model=model,
                            dataloader=test_dataloader,
                            device=device)
        wandb.log({"Epoch": epoch+1,
                   "train_loss": train_loss,
                   "test_loss": test_loss})

        print(
          f"Epoch: {epoch+1} | "
          f"train_loss: {train_loss:.4f} | "
          f"test_loss: {test_loss:.4f} | "
        )

        results["train_loss"].append(train_loss)
        results["test_loss"].append(test_loss)

        earlystopping(test_loss, model, model_name)
        if earlystopping.early_stop:
            print("Early Stopping!")
            break

def train_for_submit(model,
                    train_dataloader,
                    optimizer,
                    epochs,
                    model_name,
                    device):

    results = {"train_loss": []}

    model.to(device)

    for epoch in tqdm(range(epochs)):
        train_loss = train_step(model=model,
                                dataloader=train_dataloader,
                                optimizer=optimizer,
                                device=device)

        wandb.log({"Epoch": epoch+1,
                   "train_loss": train_loss})

        print(
          f"Epoch: {epoch+1} | "
          f"train_loss: {train_loss:.4f} | "
        )

        save_model(model=model,
                   target_dir="models",
                   model_name=model_name)

        results["train_loss"].append(train_loss)


from flask import Blueprint, render_template, request, redirect

from db_cms.db_cms_core import db
from forms.items_form import ItemsForm

items_blueprint = Blueprint('items_blueprint', __name__)

settings = {
    'title': 'Towary',
    'button_name': 'Dodaj nowy towar',
    'table_headers': ['skrócona nazwa', 'pełna nazwa', 'kategoria', 'jednostka miary']}

@items_blueprint.route('/items/list')
def items_list():
    request_params = request.args.to_dict()
    if request_params and request_params.get('mode') == 'remove':
        id_elem = request_params.get('id_elem')
        if id_elem:
            db.remove_item(int(id_elem))
            return redirect('/items/list')
    list_data = db.show_all_items()
    return render_template('custom_forms/items.html', settings=settings, page_state='list', list_data=list_data)

@items_blueprint.route('/items/edit/<item_id>')
def edit_item(item_id):
    id_elem = None
    form = ItemsForm()

    if request.method == 'POST':
        id_elem = request.form.to_dict().get('element_id')
        if form.validate():
            db.edit_unit(int(id_elem), {'name': form.name.data,
                                        'short_name': form.short_name.data,
                                        'category_id': form.category_id.data,
                                        'measurement_id': form.measurement_id.data})
            return redirect('/items/list')
    else:
        if item_id:
            element_to_edit = db.get_item(int(item_id))
            form.name.data = element_to_edit.name
            form.short_name.data = element_to_edit.short_name
            form.category_id.data = element_to_edit.category_id
            form.measurement_id.data = element_to_edit.measurement_id
            id_elem = element_to_edit.id

    return render_template('custom_forms/items.html', form=form, page_state='edit', element_id=id_elem,
                           settings=settings)

@items_blueprint.route('/items/new', methods=['POST', 'GET'])
def new_item():
    form = ItemsForm()
    if request.method == 'POST':
        if form.validate():
            db.add_item({'name': form.name.data,
                         'short_name': form.short_name.data,
                         'category_id': form.category_id.data,
                         'measurement_id': form.measurement_id.data})
            return redirect('/items/list')
    return render_template('custom_forms/items.html', form=form, page_state='new', settings=settings)


import aiohttp
import asyncio
import argparse
import requests
import itertools

from collections import namedtuple
from lxml import html
from tqdm import tqdm

from typing import Generator, Iterator, Optional

# Types
Breed = namedtuple("Breed", ["name", "group"])

# Constants
BASE_URL = "http://www.fci.be"

ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"

BREED_UL_LIST_PATH_X_PATH = '//*[@id="page"]/div[2]/div[1]/ul/li/a'

ENGLISH_NAME_X_PATH = '//*[@id="ContentPlaceHolder1_NomEnLabel"]'

GROUP_X_PATH = '//*[@id="ContentPlaceHolder1_GroupeHyperLink"]'

def _breeds_from_listing_page(page_content: str) -> list[tuple[str, str]]:
    elems = html.fromstring(page_content).xpath(BREED_UL_LIST_PATH_X_PATH)
    return [(breed.text_content(), breed.attrib["href"]) for breed in elems]

def _breed_from_page(page_content: str) -> Breed:
    tree = html.fromstring(page_content)
    eng_name = tree.xpath(ENGLISH_NAME_X_PATH)[0].text_content()

    group = tree.xpath(GROUP_X_PATH)[0].text_content()
    group = group[group.index("-") + 2 :]
    return Breed(eng_name.title(), group)

def print_results(breeds: Iterator[Breed], outfile: Optional[str]) -> None:
    # Report results
    header = "Name, Group\n"
    format_gen = (f"{b.name}, {b.group}\n" for b in sorted(breeds))

    if outfile is None:
        print(header, end="")
        for l in format_gen:
            print(l, end="")
    else:
        with open(outfile, "w") as f:
            f.write(header)
            f.writelines(format_gen)
            print(f"Results written to {outfile}")

def get_dog_listings(show_pbar: bool) -> Generator[Breed, None, None]:
    alphabet_pbar = tqdm(ALPHABET)

    for init in alphabet_pbar if show_pbar else ALPHABET:
        if args.destination is not None:
            alphabet_pbar.set_description(
                f"Getting listings for dogs beginning with {init}"
            )

        page = requests.get(f"{BASE_URL}/en/nomenclature/races.aspx?init={init}")

        breeds = _breeds_from_listing_page(page.text)

        breeds_pbar = tqdm(breeds)

        for breed_name, breed_path in breeds_pbar if show_pbar else breeds:
            if args.destination is not None:
                breeds_pbar.set_description(f"Getting English name for {breed_name}")
            subpage = requests.get(f"{BASE_URL}{breed_path}")

            yield _breed_from_page(subpage.text)

async def async_get_dog_listings() -> Iterator[Breed]:
    async def _breed_from_their_page(
        path: str, session: aiohttp.ClientSession
    ) -> Breed:
        page = session.get(f"{BASE_URL}{path}")
        return _breed_from_page(await (await page).text())

    async def _process_letter(
        letter: str, session: aiohttp.ClientSession
    ) -> Generator[Breed, None, None]:
        page = session.get(f"{BASE_URL}/en/nomenclature/races.aspx?init={letter}")
        breeds = _breeds_from_listing_page(await (await page).text())

        return iter(
            await asyncio.gather(
                *(_breed_from_their_page(path, session) for _, path in breeds)
            )
        )

    async with aiohttp.ClientSession() as session:
        return itertools.chain(
            *await asyncio.gather(*(_process_letter(l, session) for l in ALPHABET))
        )

if __name__ == "__main__":
    # Arguments
    parser = argparse.ArgumentParser()
    parser.add_argument(
        "destination",
        nargs="?",
        help="Output file to write contents to. stdout if not specified",
    )

    args = parser.parse_args()

    # print_results(get_dog_listings(args.destination is not None), args.destination)
    print_results(asyncio.run(async_get_dog_listings()), args.destination)


from django.core.management.base import BaseCommand
from django.conf import settings
from elasticsearch import Elasticsearch

es = Elasticsearch(settings.ELASTICSEARCH_URL)

MAPPINGS = {
    "document": {
        "properties": {
            "id": {"type": "string", "index": "not_analyzed"},
        }
    }
}

SETTINGS = {
    "analysis": {
        "analyzer": {
            "default": {
                "tokenizer": "standard",
                "filter": ["standard", "lowercase", "asciifolding"],
            }
        }
    }
}

class Command(BaseCommand):
    help = "Reset the elasticsearch index"

    def handle(self, **options):
        es.indices.delete(settings.ELASTICSEARCH_INDEX, ignore=[400, 404])
        es.indices.create(settings.ELASTICSEARCH_INDEX, {
            "mappings": MAPPINGS,
            "settings": SETTINGS,
        })


# -*- coding: utf-8 -*-
"""The AWS shared resources for core application stage."""
import aws_cdk as cdk
from constructs import Construct
from cdk.stacks.services.frontend_stack import FrontEndStack, FrontEndMonitoring

class ServicesStage(cdk.Stage):
    """Create CI/CD stage with shared resources."""

    def __init__(self, scope: Construct, construct_id: str, env: cdk.Environment, props: dict, **kwargs) -> None:
        """Initialize default parameters from AWS CDK and configuration file.

        :param scope:
        :param construct_id:
        :param env: Tha AWS CDK Environment class which provide AWS Account ID and AWS Region.
        :param props:
        :param kwargs:
        """
        super().__init__(scope, construct_id, env=env, **kwargs)

        service_name = "frontend"
        front_end_stack = FrontEndStack(
            self,
            construct_id=f"{service_name}-service-stack",
            env=env,
            props=props,
        )
        FrontEndMonitoring(
            self,
            name=f"{service_name}-monitoring-stack",
            env=env,
            props=front_end_stack.output_props,
        )


from setuptools import setup, find_packages
from codecs import open
from os import path

BASE_DIR = path.abspath(path.dirname(__file__))

with open(path.join(BASE_DIR, 'README.rst'), encoding='utf-8') as f:
    long_description = f.read()

setup(
    name='subst',
    version='0.4.0',
    description='`subst` is simple utility to replace one string into another in given list of files.',
    long_description=long_description,
    url='http://msztolcman.github.io/subst/',
    author='Marcin Sztolcman',
    author_email='marcin@urzenia.net',
    license='MIT',

    # See https://pypi.python.org/pypi?%3Aaction=list_classifiers
    classifiers=[
        'Development Status :: 4 - Beta',
        'Environment :: Console',
        'Intended Audience :: Developers',
        'Intended Audience :: Other Audience',
        'Intended Audience :: System Administrators',
        'License :: OSI Approved :: MIT License',
        'Topic :: Text Processing',
        'Topic :: Utilities',
        'Programming Language :: Python :: 2.7',
        'Programming Language :: Python :: 3',
        'Programming Language :: Python :: 3.3',
        'Programming Language :: Python :: 3.4',
        'Programming Language :: Python :: 3.5',
        'Programming Language :: Python :: 3.6',
    ],
    py_modules=['subst'],

    keywords='sed text processing',

    entry_points={
        'console_scripts': [
            'subst=subst:main',
        ],
    },
)


import pickle
import json
import os
import shutil
import threading
import collections

recursive_dict = lambda: collections.defaultdict(recursive_dict)

def run_crawler(crawler):
  print ("[%s] Start" % crawler.name)
  crawler.getTheaters()
  crawler.getMovies()
  print ("[%s] Finish" % crawler.name)

  print ("[%s] Writing pickle dump" % crawler.name)
  with open('./tmp/dumps/%s.dump' % crawler.name, 'wb') as f:
    pickle.dump(crawler.model, f, protocol=3)

  print ("[%s] Writing json dump" % crawler.name)
  with open('./tmp/jsons/%s.json' % crawler.name, 'w') as f:
    json.dump(crawler.model.toJSON(), f)

  return crawler.model

def merge_crawler_result(result, crawler):
  print ("[%s] Merging model with root" % crawler.name)

  chainHash = hex(hash(crawler.model))
  result['chains'][chainHash] = crawler.model.toJSON(False)

  for theater in crawler.model.theaters:
    theaterHash = hex(hash(theater))

    result['theaters'][theaterHash] = theater.toJSON(False)

    for movie in theater.movies:
      movieHash = hex(hash(movie))
      movieJSON = movie.toJSON()
      movieShowTimes = movieJSON['showtimes']
      if not result['movies'].get(movieHash):
        movieJSON['showtimes'] = recursive_dict()
        result['movies'][movieHash] = movieJSON
      damovie = result['movies'][movieHash]

      damovie['showtimes'][chainHash][theaterHash].update({
        'theater': theaterHash,
        'chain': chainHash,
        'showtime': movieShowTimes,
        'movie' : damovie['id']
      })

      if not chainHash in damovie['chains']:
        damovie['chains'].append(chainHash)

      if not theaterHash in damovie['theaters']:
        damovie['theaters'].append(theaterHash)

      result['movies'][movieHash] = damovie

def replace_hashes_by_ids(result):
  output = json.dumps(result)

  chainID = 1
  theaterID = 1
  movieID = 1

  for key, chain in result['chains'].items():
    output = output.replace(key, str(chainID))
    chainID = chainID + 1

  for key, theater in result['theaters'].items():
    output = output.replace(key, str(theaterID))
    theaterID = theaterID + 1

  for key, movie in result['movies'].items():
    output = output.replace(key, str(movieID))
    movieID = movieID + 1

  return output

def prepare_fs():
  try:
    shutil.rmtree('./tmp')
  except (FileNotFoundError, FileExistsError):
    pass

  try:
    os.mkdir('./tmp')
    os.mkdir('./tmp/responses')
    os.mkdir('./tmp/dumps')
    os.mkdir('./tmp/jsons')
  except (FileNotFoundError, FileExistsError):
    pass

class Worker (threading.Thread):
  def __init__(self, threadID, instance, mergeLock, result):
    threading.Thread.__init__(self)
    self.threadID = threadID
    self.instance = instance
    self.mergeLock = mergeLock
    self.result = result

  def run(self):
    run_crawler(self.instance)

    self.mergeLock.acquire()
    merge_crawler_result(self.result, self.instance)
    self.mergeLock.release()
    print ("[%s] End" % self.threadID)


import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from IPython.display import display
from evds import evdsAPI
import csv

#### for taking EVDS data into Python

evds = evdsAPI('Lb4qWxFtXa')
data = evds.get_data(['TP.KKHARTUT.KT1','TP.KKHARTUT.KT16'], startdate="10-03-2020", enddate="06-08-2020")
data_pandas = pd.DataFrame(data)

with open('full_data.csv') as csv_file:
    csv_reader = csv.reader(csv_file, delimiter = ',')
    line_count = -1
    data_case = []
    data_death = []
    for row in csv_reader:
            if row[1]  == 'Turkey':
                if row[6] != '':
                    line_count += 1
                    if (line_count % 7) == 0:
                        data_case.append(row[6])
                        data_death.append(row[7])
                        data_pandas2 = pd.DataFrame({"Weekly Cases": data_case})
                        data_pandas3 = pd.DataFrame({"Weekly Deaths": data_death})
data_pandas = data_pandas.join(data_pandas2)
data_pandas = data_pandas.join(data_pandas3)
display(data_pandas)


#!/usr/bin/env python3
from os import walk, getcwd, path
from pathlib import PurePath

# ignore all of directories, include root level
IGNORE_DIRS = ['.git','bin','lib','include']

# ignore all files mathes
IGNORE_FILES = ['pyvenv.cfg','.DS_Store','.gitignore']

rootDir = getcwd()

result = []
for root, dir, files in walk(rootDir):
    dir.sort()
    files.sort()
    match = path.basename(root)
    if match in IGNORE_DIRS:
        dir[:] = [] # ignore sub
        continue

    times = len(PurePath(root[len(rootDir)-1:]).parts)
    result.append('|\t' * (times-1) + '├── %s\n' %match)

    for fname in files:
        pre = '|\t' * times
        recordPos = pre
        if fname not in IGNORE_FILES:
            result.append(pre+'├── %s\n' %fname)
dirs = ''.join(result)

print(dirs)


import sentencepiece as spm
import os
import json
import warnings

warnings.filterwarnings("ignore")
import pandas as pd
import pickle
import argparse
from util import *

def get_info(DATA, USER_DEFINED_SYMBOLS):
    train_date, valid_date, test_date, end_date = get_date_info(DATA)
    STOCK_LIST = os.listdir(os.path.join(GENERAL_PATH, 'data', DATA, 'tweet'))
    for stock in STOCK_LIST:
        USER_DEFINED_SYMBOLS += ',$' + stock.lower()
    return train_date, valid_date, test_date, end_date, STOCK_LIST, USER_DEFINED_SYMBOLS

def get_text(DATA_PATH, DATA):
    texts = ''
    for stock in STOCK_LIST:
        stock_path = os.path.join(DATA_PATH, DATA, 'tweet', stock)
        date_list = sorted(os.listdir(stock_path))
        # date_list = ['2017-01-01', '2017-01-02', '2017-01-03', ... ,]
        for date in date_list:
            if date >= train_date and date < valid_date:
                with open(os.path.join(stock_path, date), 'r',
                          encoding='utf8') as f:
                    for idx_tweet, line in enumerate(f):
                        tweet = json.loads(line, strict=False)
                        texts += tweet['text'] + '\n'
    return texts

def html_decode(s):
    """
    Returns the ASCII decoded version of the given HTML string. This does
    NOT remove normal HTML tags like <p>.
    """
    htmlCodes = (
        ("'", '''),
        ('"', '"'),
        ('>', '>'),
        ('<', '<'),
        ('&', '&')
    )
    for code in htmlCodes:
        s = s.replace(code[1], code[0])
    return s

def make_input(texts):
    texts = texts[:-1]
    texts = html_decode(texts)
    with open(INPUT, 'w', encoding='utf8') as f:
        f.write(texts)
    f.close()

def make_tweet_sentencepiece(data):
    if data == 'train':
        start_date = train_date
        end_date = valid_date
    elif data == 'valid':
        start_date = valid_date
        end_date = test_date

    if DATA == 'acl18':
        max_len = 180
    elif DATA == 'cikm18':
        max_len = 129
    elif DATA == 'cikm21':
        max_len = 229
    df = pd.DataFrame(
        columns={'id_list', 'text_len', 'idx_stock_position', 'up_down_label',
                 'stock_label'})
    stock_list = ['$' + stock.lower() for stock in STOCK_LIST]
    stock_id_list = sp.piece_to_id(stock_list)
    for stock in STOCK_LIST:
        stock_label = STOCK_LIST.index(stock)
        stock_path = os.path.join(DATA_PATH, DATA, 'tweet', stock)
        date_list = sorted(os.listdir(stock_path))
        # date_list = ['2017-01-01', '2017-01-02', '2017-01-03', ... ,]
        df_stock_price = pd.read_csv(
            os.path.join(DATA_PATH, DATA, 'price', stock + '.csv'))
        for date in date_list:
            if date >= start_date and date < end_date:
                up_down_label = \
                    df_stock_price[df_stock_price['date'] > date].iloc[0][
                        'label']
                with open(os.path.join(stock_path, date), 'r',
                          encoding='utf8') as f:
                    for idx_tweet, line in enumerate(f):
                        tweet = json.loads(line, strict=False)
                        ids_list = sp.encode_as_ids(tweet['text'])

                        if sp.piece_to_id('$' + stock.lower()) not in ids_list:
                            continue

                        idx_stock_position = ids_list.index(
                            sp.piece_to_id('$' + stock.lower()))
                        text_len = len(ids_list)
                        ids_list += [3] * (max_len - len(ids_list))
                        df = df.append(pd.DataFrame([[ids_list, text_len,
                                                      idx_stock_position,
                                                      up_down_label,
                                                      stock_label]],
                                                    columns=['id_list',
                                                             'text_len',
                                                             'idx_stock_position',
                                                             'up_down_label',
                                                             'stock_label']))
    with open(os.path.join(GENERAL_PATH, 'sentence_piece',
                           '{}_{}.pkl'.format(DATA, data)), 'wb') as f:
        pickle.dump((df, stock_id_list), f)

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('-d', '--data', help='data', type=str,
                        default='acl18')
    parser.add_argument('-v', '--vocab_size', help='vocab_size', type=int,
                        default=16000)
    args = parser.parse_args()
    DATA = args.data
    GENERAL_PATH = os.path.dirname(os.getcwd())
    DATA_PATH = os.path.join(GENERAL_PATH, 'data')
    INPUT = os.path.join(GENERAL_PATH, 'sentence_piece',
                         '{}_input.txt'.format(DATA))
    VOCAB_SIZE = args.vocab_size
    USER_DEFINED_SYMBOLS = '<s>,</s>,<pad>,<mask>,rt,AT_USER,URL'
    train_date, valid_date, test_date, end_date, STOCK_LIST, \
    USER_DEFINED_SYMBOLS = get_info(DATA, USER_DEFINED_SYMBOLS)
    texts = get_text(DATA_PATH, DATA)
    make_input(texts)
    # train sentencepiece model from `input.txt` and makes `m.model` and `m.vocab`
    # `m.vocab` is just a reference. not used in the segmentation.
    spm.SentencePieceTrainer.train(
        '--input={} --model_prefix={} --vocab_size={} --user_defined_symbols={}'.format(
            INPUT,
            os.path.join(GENERAL_PATH, 'sentence_piece',
                         '{}'.format(DATA)), VOCAB_SIZE, USER_DEFINED_SYMBOLS))
    # makes segmenter instance and loads the model file (m.model)
    sp = spm.SentencePieceProcessor()
    sp.load(os.path.join(GENERAL_PATH, 'sentence_piece',
                         '{}.model'.format(DATA)))
    max_len = 0
    for stock in STOCK_LIST:
        stock_path = os.path.join(DATA_PATH, DATA, 'tweet', stock)
        date_list = sorted(os.listdir(stock_path))
        for date in date_list:
            if date >= train_date and date <= end_date:
                with open(os.path.join(stock_path, date), 'r',
                          encoding='utf8') as f:
                    for idx_tweet, line in enumerate(f):
                        tweet = json.loads(line, strict=False)
                        ids_list = sp.encode_as_ids(tweet['text'])
                        if len(ids_list) > max_len:
                            max_len = len(ids_list)
    make_tweet_sentencepiece('train')
    make_tweet_sentencepiece('valid')


import logging
import numpy as np
import os
import sys

from .base_model import BaseModelWrapper
from tempeh.constants import Tasks, DataTypes, Algorithms

logger = logging.getLogger(__name__)

# Suppress messages from tensorflow
stderr = sys.stderr
sys.stderr = open(os.devnull, 'w')
try:
    import keras
    from tensorflow.keras.layers import Activation, Dense, Dropout
    from tensorflow.keras.models import Sequential
except ImportError:
    logger.debug("No modules named 'keras' and 'tensorflow'. If you want to use keras and "
                 "tensorflow with tempeh please install keras and tensorflow separately first.")
finally:
    sys.stderr = stderr

class BaseKerasWrapper(BaseModelWrapper):
    """Base wrapper for Keras models."""

    algorithm = Algorithms.DEEP
    limit = (100000, 10000)
    keras_args = None

    def __init__(self, model):
        """Initializes the base keras model wrapper.
        :param model: the model
        :type model: model
        """
        super().__init__(model)

    @classmethod
    def compatible_with_dataset(cls, dataset):
        """Checks if the model is compatible with the dataset
        :param dataset: the dataset
        :type dataset: BaseDatasetWrapper
        :rtype: bool
        """
        return dataset.task in cls.tasks and dataset.data_type == DataTypes.TABULAR and \
            (cls.limit is None or all((cls.limit[i] is None or cls.limit[i] > dataset.size[i]
                                       for i in range(len(dataset.size)))))

class KerasMulticlassClassifierWrapper(BaseKerasWrapper):
    """Wrapper for Keras multiclass classifier."""

    tasks = [Tasks.MULTICLASS]

    def __init__(self, dataset):
        """Initializes the base model wrapper.

        :param dataset: the dataset
        :type dataset: BasePerformanceDatasetWrapper
        """
        model = create_keras_multiclass_classifier(dataset._X_train, dataset._y_train)
        super().__init__(dataset, model)

class KerasBinaryClassifierWrapper(BaseKerasWrapper):
    """Wrapper for Keras multiclass classifier."""

    tasks = [Tasks.BINARY]

    def __init__(self, dataset):
        """Initializes the base model wrapper.

        :param dataset: the dataset
        :type dataset: BasePerformanceDatasetWrapper
        """
        model = create_keras_classifier(dataset._X_train, dataset._y_train)
        super().__init__(dataset, model)

class KerasRegressionWrapper(BaseKerasWrapper):
    """Wrapper for Keras regressor."""

    tasks = [Tasks.REGRESSION]

    def __init__(self, dataset):
        """Initializes the base model wrapper.

        :param dataset: the dataset
        :type dataset: BasePerformanceDatasetWrapper
        """
        model = create_keras_regressor(dataset._X_train, dataset._y_train)
        super().__init__(dataset, model)

def create_keras_regressor(X, y):
    # create simple (dummy) Keras DNN model for regression
    batch_size = 128
    epochs = 12
    model = _common_model_generator(X.shape[1])
    model.add(Activation('linear'))
    model.compile(loss=keras.losses.mean_squared_error,
                  optimizer=keras.optimizers.Adadelta(),
                  metrics=['accuracy'])
    model.fit(X, y,
              batch_size=batch_size,
              epochs=epochs,
              verbose=1,
              validation_data=(X, y))
    return model

def create_keras_classifier(X, y):
    # create simple (dummy) Keras DNN model for binary classification
    batch_size = 128
    epochs = 12
    model = _common_model_generator(X.shape[1])
    model.add(Activation('sigmoid'))
    model.compile(loss=keras.losses.binary_crossentropy,
                  optimizer=keras.optimizers.Adadelta(),
                  metrics=['accuracy'])
    model.fit(X, y,
              batch_size=batch_size,
              epochs=epochs,
              verbose=1,
              validation_data=(X, y))
    return model

def create_keras_multiclass_classifier(X, y):
    batch_size = 128
    epochs = 12
    num_classes = len(np.unique(y))
    model = _common_model_generator(X.shape[1], num_classes)
    model.add(Dense(units=num_classes, activation=Activation('softmax')))
    model.compile(loss=keras.losses.categorical_crossentropy,
                  optimizer=keras.optimizers.Adadelta(),
                  metrics=['accuracy'])
    y_train = keras.utils.to_categorical(y, num_classes)
    model.fit(X, y_train,
              batch_size=batch_size,
              epochs=epochs,
              verbose=1,
              validation_data=(X, y_train))
    return model

def create_dnn_classifier_unfit(feature_number):
    # create simple (dummy) Keras DNN model for binary classification
    model = _common_model_generator(feature_number)
    model.add(Activation('sigmoid'))
    model.compile(loss=keras.losses.binary_crossentropy,
                  optimizer=keras.optimizers.Adadelta(),
                  metrics=['accuracy'])
    return model

def _common_model_generator(feature_number, output_length=1):
    model = Sequential()
    model.add(Dense(32, activation='relu', input_shape=(feature_number,)))
    model.add(Dropout(0.25))
    model.add(Dense(output_length, activation='relu', input_shape=(32,)))
    model.add(Dropout(0.5))
    return model


"""
This function will be triggered by Cloudwatch Custom Widget lambda function. You can also trigger resource-controller function manually with below event.
To stop ECS and EKS resources: {'Action':'disable'}
To start ECS and EKS resources: {'Action':'enable'}
"""

import os
import boto3
import time

ecs_client = boto3.client('ecs')
eks_client = boto3.client('eks')

EKS_CLUSTER_NAME = os.environ['EKS_CLUSTER_NAME']
ECS_CLUSTER_ARNS = os.environ['ECS_CLUSTER_ARNS'].split(",")

def set_ecs_desired_task_count_to_zero(cluster):
    """Function to set ECS Desired Tasks counts to 0 for all ECS Cluster Services"""
    services = ecs_client.list_services(
        cluster = cluster
        )
    for service in services['serviceArns']:
        update_response = ecs_client.update_service(
            cluster = cluster,
            service = service,
            desiredCount = 0)
    return 0

def set_ecs_desired_task_count_to_normal(cluster):
    """Function to set ECS Desired Tasks counts to 2 for all ECS Cluster Services except trafficgeneratorservice"""
    services = ecs_client.list_services(
        cluster = cluster
        )
    for service in services['serviceArns']:
        desired_count = 2
        if 'trafficgeneratorserviceecsservice' in service:
            desired_count = 1
        update_response = ecs_client.update_service(
            cluster = cluster,
            service = service,
            desiredCount = desired_count)
    return 0

def manageECSTasks(status):
    """Enable/Disable ECS Tasks"""
    clusters = ecs_client.list_clusters()
    for cluster in clusters['clusterArns']:
        if cluster in ECS_CLUSTER_ARNS:
            if status == "enable":
                set_ecs_desired_task_count_to_normal(cluster)
            elif status == "disable":
                set_ecs_desired_task_count_to_zero(cluster)
    if status == "enable":
        return "ECS Tasks Count set back to Normal"
    else:
        return "ECS Tasks Count set to Zero"

def waitTillUpdateCompletes(update_response,nodegroup_name):
    """Waiter function to wait till EKS cluster accepts the update"""
    update_in_progress = True
    while update_in_progress:
        update_status = eks_client.describe_update(
            name = EKS_CLUSTER_NAME,
            updateId = update_response['update']['id'],
            nodegroupName = nodegroup_name
        )
        if update_status['update']['status'] == 'InProgress':
            time.sleep(5)
        else:
            update_in_progress = False

def setEKSNodeGroupCountToNormal(nodegroup_name):
    """Function to set EKS nodegroup node desired count to 2"""
    update_response = eks_client.update_nodegroup_config(
        clusterName=EKS_CLUSTER_NAME,
        nodegroupName=nodegroup_name,
        scalingConfig={
            'minSize': 2,
            'desiredSize': 2
        },
    )
    waitTillUpdateCompletes(update_response,nodegroup_name)

def setEKSNodeGroupCountToZero(nodegroup_name):
    """Function to set EKS nodegroup node desired count to 0"""
    update_response = eks_client.update_nodegroup_config(
        clusterName=EKS_CLUSTER_NAME,
        nodegroupName=nodegroup_name,
        scalingConfig={
            'minSize': 0,
            'desiredSize': 0
        },
    )
    waitTillUpdateCompletes(update_response,nodegroup_name)

def manageEKSNodes(status):
    """Enable/Disable the EKS nodegroup Count"""
    nodegroups = eks_client.list_nodegroups(
        clusterName=EKS_CLUSTER_NAME)
    for group in nodegroups['nodegroups']:
        if EKS_CLUSTER_NAME.lower()+'nodegroup' in group.lower():
            nodegroup_name = group
            break
    if status == "enable":
        setEKSNodeGroupCountToNormal(nodegroup_name)
        return "EKS Nodegroup Count set back to Normal"
    elif status == "disable":
        setEKSNodeGroupCountToZero(nodegroup_name)
        return "EKS Nodegroup Count set to Zero"

def lambda_handler(event, context):
    """Main function to control ECS and EKS resources"""
    output1 = manageECSTasks(event['Action'])
    output2 = manageEKSNodes(event['Action'])
    return output1 + ', '+ output2


import numpy as np
from scipy.optimize import curve_fit

def svi_vol(k, a, b, rho, m, sigma):
    return np.sqrt(a + b * (rho * (k - m) + np.sqrt((k - m)**2 + sigma**2)))

class SVIFitter:

    def __init__(self, strikes, observed_vol, init_params=None):
        self.strikes = np.array(strikes)
        self.observed_vol = np.array(observed_vol)

        if init_params:
            self.init_params = init_params
            self.opt_params = init_params
        else:
            self.init_params = np.array([0.1, 0.1, 0.1, 100, 0.1])
            self.opt_params = None

    def fit_curve_fit(self, maxfev=20000, num_iter=2):
        log_strikes = np.log(self.strikes)
        params = self.init_params
        for _ in range(num_iter):
            result = curve_fit(svi_vol, log_strikes, self.observed_vol, p0=params, maxfev=maxfev)
            params = result[0]
        return params

    def fit(self, method='curve_fit'):
        if method == 'curve_fit':
            return self.fit_curve_fit()

    def eval(self, k):
        if self.opt_params is None:
            raise Exception("No Parameters")
        return svi_vol(k, *self.opt_params)


import math
import time
from bs4 import BeautifulSoup
from Building import Building
from Codes import Codes
from Fleet import Fleet
from Request import Request
from tasks.BuildingTask import BuildingTask
from UtilitiesFunctions import log

class Planet:
    def __init__(self, id, name, position, player):
        self.id = id        # integer
        self.name = name
        self.pos = position
        self.player = player
        self.batiments = []
        self.construction = []
        self.metal = None
        self.metalStorage = None
        self.metalProduction = None
        self.crystal = None
        self.crystalStorage = None
        self.crystalProduction = None
        self.deut = None
        self.deutStorage = None
        self.deutProduction = None
        self.energy = None
        self.energyStorage = None
        self.lastExtracedInfosDate = None
        self.upgradingEnd = 0 #when the last upgrade will finish. Either 0 or time.time() + rest
        self.upgradingBuildingsId = [] # List of (id, end) with id of the buildings being upgraded and end of the construction
        self.isMoon = "(Lune)" in name
        self.sizeUsed = None
        self.sizeMax = None
        self.ships = {}
        self.customBuildOrder = None
        self.lastKnownSystem = []

    def __repr__(self):
        return "Planet (id %i position %s)" % (self.id, self.getPosAsString())

    def buildingById(self, id):
        for b in self.batiments:
            if b.id == id:
                return b
        return None

    def buildingLevelById(self, id): #returns the level or 0 if the building isn't build yet
        for b in self.batiments:
            if b.id == id:
                return b.level
        return 0

    def buildingByType(self, type):
        for b in self.batiments:
            if b.type == type:
                return b
        return None

    def getNameWithSize(self):
        return self.name + " (" + str(self.sizeUsed) + "/" + str(self.sizeMax) + ")"

    def getSize(self):
        reqP = Request(self.player.ia.overviewPage + "&cp=" + str(self.id), {})
        self.player.ia.execRequest(reqP)
        soup = BeautifulSoup(reqP.content, "html.parser")
        #parse the size
        self.sizeUsed = int(soup.find(attrs={"title": 'Cases occupées'}).text)
        self.sizeMax = int(soup.find(attrs={"title": 'Cases max. disponibles'}).text)

    def rename(self, name): #Returns true if renaming worked
        reqP = Request(self.player.ia.renamingPage + name + "&cp=" + str(self.id), {})
        response = self.player.ia.execRequest(reqP)
        if reqP.response.status_code == 200:
            self.name = name
            return True
        return False

    def getTimeToWaitForResources(self, resourcesWanted):
        resources = [x for x in resourcesWanted] # copy to not change original list
        resources[0] = (resources[0] - self.metal) / self.metalProduction
        resources[1] = (resources[1] - self.crystal) /  self.crystalProduction
        if self.deutProduction == 0:
            resources[2] = 0 if (self.deut - resources[2]) >= 0 else math.inf
        else:
            resources[2] = (resources[2] - self.deut) /  self.deutProduction
        resources.append(0) #to ensure that the wait time is at least 0
        timeToWait = max(resources)
        return timeToWait

    def planBuilding(self):
        config = self.player.ia.config #to make lines smaller
        buildingId = None
        if config.activateCustomBuildOrders and self.customBuildOrder is not None:
            building = self.customBuildOrder.nextBuilding(self) # the building to build
            if building is None:
                if self.customBuildOrder.options.get("useDefaultBuildPlanWhenEmpty", False):
                    buildingId = self.defaultPlanBuildingWithoutHangars()
                else:
                    log(self, "No more building planned by the custom build order !")
                    return None
            else:
                buildingId = building.id
        else:
            buildingId = self.defaultPlanBuildingWithoutHangars()
        buildingId = self.planHangarsInstead(buildingId)
        building = self.buildingById(buildingId)
        #now we need to know how much to wait
        timeToWait = self.getTimeToWaitForResources(building.upgradeCost)
        task = BuildingTask(self.lastExtracedInfosDate + timeToWait, building)
        self.player.ia.addTask(task)
        return task

    def defaultPlanBuildingWithoutHangars(self):
        config = self.player.ia.config #to make lines smaller
        b = None
        if self.energy < 0:
            b = 'Centrale éléctrique Solaire'
        else:
            metalMine = self.buildingByType('Mine de Métal').level
            crystalMine = self.buildingByType('Mine de Cristal').level
            deutMine = self.buildingByType('Synthétiseur de Deutérium').level
            robotFactory = self.buildingByType('Usine de Robots').level
            if metalMine >= config.robotStartingLevel and (metalMine / config.robotRatio > robotFactory) and self.buildingByType('Usine de Robots').upgradeCost[2] <= self.deut:
                b = 'Usine de Robots'
            elif crystalMine > deutMine + 5:
                b = 'Synthétiseur de Deutérium'
            else:
                if metalMine > crystalMine + 2:
                    b = 'Mine de Cristal'
                else:
                    b = 'Mine de Métal'
        buildingId = Codes.strToId[b]
        return buildingId

    def planHangarsInstead(self, b):
        building = self.buildingById(b)
        while not building.upgradable([self.metalStorage, self.crystalStorage, self.deutStorage]):
            # on ne peut pas stocker assez de ressources pour le construire
            b = 'Hangar de Métal'
            if building.upgradeCost[1] > self.crystalStorage:
                b = 'Hangar de Cristal'
            elif building.upgradeCost[2] > self.deutStorage:
                b = 'Réservoir de Deutérium'
            building = self.buildingByType(b)
        buildingId = building.id
        return buildingId

    def upgradableBuildings(self, ressources):
        return [bat for bat in self.batimens if bat.upgradable(ressources)]

    def scan(self):
        reqB = Request(self.player.ia.buildingPage + "&cp=" + str(self.id), {})
        self.player.ia.execRequest(reqB)
        self.scanUsingRequest(reqB)

    def scanUsingRequest(self, reqB):
        soup = BeautifulSoup(reqB.content, "html.parser")
        #parse all available buildings
        bats = soup.find(id="content").find_all("div", recursive=False)
        self.batiments = []
        self.upgradingEnd = 0
        self.upgradingBuildingsId = []
        for b in bats:
            if b.attrs.get("id") == "buildlist": #if it's a building currently building
                # This b regroups all buildings in the building list
                trs = b.find_all("tr")
                for tr in trs: # This way we have one building in each tr
                    endTime = float(tr.find(class_="timer").attrs["data-time"])
                    self.upgradingEnd = endTime #at the end of the loop, it will be the end of the last building
                    input = tr.find("input", attrs={"name": "building"})
                    if input is None: # Happens when the construction list is full
                        td = tr.td
                        nameToParse = td.text # Looks like 1.: Synthétiseur de Deutérium 16
                        name = self.player.ia.buildingWaitListNameParser.findall(nameToParse)[0]
                        buildingId = Codes.strToId[name]
                    else:
                        buildingId = int(input.attrs["value"])
                    self.upgradingBuildingsId.append((buildingId, endTime))
            else:
                nameAndLevelText = b.find("a").text
                nameAndLevel = self.player.ia.buildingNameParser.findall(nameAndLevelText)
                name = nameAndLevel[0][0]
                level = 0
                if nameAndLevel[0][1] != '':
                    level = int(nameAndLevel[0][1])
                divs = b.find_all("div", recursive=False)
                upgradeTimeString = divs[1].span.text
                upgradeTimeTab = upgradeTimeString.split("d ")
                if len(upgradeTimeTab) == 1:
                    upgradeTimeTab = ['0', upgradeTimeTab[0]]
                upgradeTimeDay = int(upgradeTimeTab[0])
                upgradeTimeTab = upgradeTimeTab[1].split("h ")
                upgradeTimeHour = int(upgradeTimeTab[0])
                upgradeTimeTab = upgradeTimeTab[1].split("m ")
                upgradeTimeMin = int(upgradeTimeTab[0])
                upgradeTimeTab = upgradeTimeTab[1].split("s")
                upgradeTimeSec = int(upgradeTimeTab[0])
                upgradeTime = (((upgradeTimeDay * 24) + upgradeTimeHour) * 60 + upgradeTimeMin) * 60 + upgradeTimeSec
                m = divs[2].span.find(alt="Métal")
                if m != None:
                    m.replace_with("Metal;")
                c = divs[2].span.find(alt="Crystal")
                if c != None:
                    c.replace_with("Crystal;")
                d = divs[2].span.find(alt="Deutérium")
                if d != None:
                    d.replace_with("Deut;")
                costText = divs[2].span.text.replace(".", "")
                res = [0, 0, 0]
                for r in self.player.ia.ressourcesParser.findall(costText):
                    if r[1] == "Metal":
                        res[0] = int(r[0])
                    if r[1] == "Crystal":
                        res[1] = int(r[0])
                    if r[1] == "Deut":
                        res[2] = int(r[0])
                form = divs[4].find("input", attrs={"name": "building"})
                id = Codes.strToId.get(name)
                b = Building(name, id, self, level)
                b.upgradeCost = res
                b.upgradeTime = upgradeTime
                self.batiments.append(b)

        self.metal = float(soup.find(id="current_metal").attrs['data-real'])
        self.crystal = float(soup.find(id="current_crystal").attrs['data-real'])
        deutTd = soup.find(id="current_deuterium")
        energyText = deutTd.nextSibling.span.text.replace(".", "") #-40 / 0 for example
        e = self.player.ia.energyParser.findall(energyText)
        self.energy = int(e[0][0])
        self.energyStorage = int(e[0][1])
        self.deut = float(deutTd.attrs['data-real'])
        self.metalStorage = float(soup.find(id="max_metal").text.replace(".", ""))
        self.crystalStorage = float(soup.find(id="max_crystal").text.replace(".", ""))
        self.deutStorage = float(soup.find(id="max_deuterium").text.replace(".", ""))
        script = soup.find_all("script", attrs={"type":"text/javascript"})[-1].text
        if self.isMoon: #Moons don't produce
            self.metalProduction = 0
            self.crystalProduction = 0
            self.deutProduction = 0
        else:
            self.metalProduction = float(self.player.ia.metalProductionParser.findall(script)[0]) / 3600
            self.crystalProduction = float(self.player.ia.crystalProductionParser.findall(script)[0]) / 3600
            self.deutProduction = float(self.player.ia.deutProductionParser.findall(script)[0]) / 3600
        sizeUsed = 0
        for batiment in self.batiments:
            sizeUsed += batiment.level
        self.sizeUsed = sizeUsed
        self.lastExtracedInfosDate = time.time()

    def scanRessourcesUsingRequest(self, req):
        soup = BeautifulSoup(req.content, "html.parser")
        self.metal = float(soup.find(id="current_metal").attrs['data-real'])
        self.crystal = float(soup.find(id="current_crystal").attrs['data-real'])
        self.deut = float(soup.find(id="current_deuterium").attrs['data-real'])
        self.lastExtracedInfosDate = time.time()

    def expectedRessources(self, timeTarget=time.time(), takeStorageInAccount=True):
        t = (timeTarget - self.lastExtracedInfosDate) / 3600
        em = self.metal + self.metalProduction * t
        ec = self.crystal + self.crystalProduction * t
        ed = self.deut + self.deutProduction * t
        if (takeStorageInAccount):
            return [min(em, self.metalStorage), min(ec, self.crystalStorage), min(ed, self.deutStorage)]
        return [em, ec, ed]

    def scanShips(self):
        scanShipsRequest = Request(self.player.ia.scanShipsPage + "&cp=" + str(self.id), {})
        self.player.ia.execRequest(scanShipsRequest)
        soup = BeautifulSoup(scanShipsRequest.content, "html.parser")
        #parse all available ships
        shipsTr = soup.find("table", class_="table519").find_all("tr")[2:-2] #the first and last 2 are headers
        ships = {}
        for shipTr in shipsTr:
            shipTd = shipTr.find_all("td")[1]
            shipId = int(shipTd.attrs["id"].split("_")[0].replace("ship", ""))
            shipAmount = int(shipTd.text.replace(".", ""))
            ships[shipId] = shipAmount
        self.ships = ships

    def sendFleet(self, target, missionType, ships, ressources, speed=10, staytime=1, allRessources=False):
        firstPayload = {}
        for shipId in ships.keys():
            if shipId not in [212, 227, 228, 229, 230, 231]:
                firstPayload["ship" + str(shipId)] = ships[shipId]
        sendFleetStep1 = Request(self.player.ia.sendFleetStep1Page + "&cp=" + str(self.id), firstPayload)
        self.player.ia.execRequest(sendFleetStep1)
        soup = BeautifulSoup(sendFleetStep1.content, "html.parser")
        tokenInput = soup.find("input", attrs={"name":"token"})
        if tokenInput is not None:
            token = tokenInput.attrs["value"]
            secondPayload = {}
            secondPayload["galaxy"] = target[0]
            secondPayload["system"] = target[1]
            secondPayload["planet"] = target[2]
            secondPayload["type"  ] = target[3] #1 = planet, 2 = CDR, 3 = moon
            secondPayload["speed" ] = speed #the speed in multiples of 10%
            secondPayload["token" ] = token
            sendFleetStep2 = Request(self.player.ia.sendFleetStep2Page + "&cp=" + str(self.id), secondPayload)
            self.player.ia.execRequest(sendFleetStep2)
            thirdPayload = {}
            if allRessources:
                self.scanRessourcesUsingRequest(sendFleetStep2)
                ressources[0] = self.metal
                ressources[1] = self.crystal
                ressources[2] = self.deut
            soup = BeautifulSoup(sendFleetStep2.content, "html.parser")
            scriptRessources = soup.findAll("script")[-1].text
            fleetroom = int(scriptRessources.split(':"')[1].split('"')[0])
            consumption = int(scriptRessources.split(':"')[2].split('"')[0])
            fleetroom -= consumption
            if missionType == Fleet.colonizeCode:
                thirdPayload["metal"] = min(ressources[0], fleetroom/2)
                fleetroom -= thirdPayload["metal"]
                thirdPayload["crystal"] = min(ressources[1], fleetroom*2/3)
                fleetroom -= thirdPayload["crystal"]
                thirdPayload["deuterium"] = min(ressources[2], fleetroom)
                fleetroom -= thirdPayload["deuterium"]
                if fleetroom >= 0:
                    fleetroom += thirdPayload["metal"]
                    thirdPayload["metal"] = min(ressources[0], fleetroom)
                    fleetroom -= thirdPayload["metal"]
                    fleetroom += thirdPayload["crystal"]
                    thirdPayload["crystal"] = min(ressources[1], fleetroom)
                    fleetroom -= thirdPayload["crystal"]
                    fleetroom += thirdPayload["deuterium"]
                    thirdPayload["deuterium"] = min(ressources[2], fleetroom)
                    fleetroom -= thirdPayload["deuterium"]
            else:
                thirdPayload["deuterium"] = min(ressources[2], fleetroom)
                fleetroom -= thirdPayload["deuterium"]
                thirdPayload["crystal"] = min(ressources[1], fleetroom)
                fleetroom -= thirdPayload["crystal"]
                thirdPayload["metal"] = min(ressources[0], fleetroom)
                fleetroom -= thirdPayload["metal"]
            thirdPayload["mission"  ] = missionType
            thirdPayload["staytime" ] = staytime
            thirdPayload["token"    ]  = token
            sendFleetStep3 = Request(self.player.ia.sendFleetStep3Page + "&cp=" + str(self.id), thirdPayload)
            self.player.ia.execRequest(sendFleetStep3)
            log(self, "Fleet sent")
        else:
            log(self, "Error while sending the fleet", isError=True)

    def buildDefenses(self, defenses):
        payload = {}
        for id in defenses.keys():
            payload["fmenge[" + str(id) + "]"] = defenses[id]
        buildDefReq = Request(self.player.ia.buildDefPage + "&cp=" + str(self.id), payload)
        self.player.ia.execRequest(buildDefReq)

    def buildShips(self, ships):
        payload = {}
        for id in ships.keys():
            payload["fmenge[" + str(id) + "]"] = ships[id]
        buildShipReq = Request(self.player.ia.buildShipPage + "&cp=" + str(self.id), payload)
        self.player.ia.execRequest(buildShipReq)

    def scanSystem(self, galaxy, system): #TODO add check for not enough deut
        payload = {}
        payload["galaxy"] = galaxy
        payload["system"] = system
        scanSystemRequest = Request(self.player.ia.galaxyPage + "&cp=" + str(self.id), payload)
        self.player.ia.execRequest(scanSystemRequest)
        soup = BeautifulSoup(scanSystemRequest.content, "html.parser")
        #parse all available locations
        divContent = soup.find("div", id="content")
        systemTable = divContent.find("table", recursive=False)
        locationList = systemTable.find_all("tr")[2:-5] #the first 2 and last 5 are headers
        planets = []
        locationNumber = 0
        for location in locationList:
            locationNumber += 1
            tdList = location.find_all("td")
            if tdList[0].a is None: # if there is a planet in this location
                nameWithActivity = tdList[2].text #TODO remove activity from the name
                planet = Planet(None, nameWithActivity, [galaxy, system, locationNumber, 1], None)
                planets.append(planet)
                #TODO add moon
        for planet in self.player.planets:
            if planet.pos[0] == galaxy and planet.pos[1] == system:
                planet.lastKnownSystem = planets
        return planets

    def scanOwnSystem(self):
        return self.scanSystem(self.pos[0], self.pos[1])

    def getColonizationTarget(self, useLastKnownSystem=False):
        planetsList = self.lastKnownSystem
        if not useLastKnownSystem:
            planetsList = self.scanOwnSystem()
        planetsDict = {}
        for planet in planetsList:
            if not planet.isMoon:
                planetsDict[planet.pos[2]] = planet
        for location in self.player.getColonizableLocations():
            if planetsDict.get(location, None) is None: # No planet in this location
                return location
        return None

    def getPosAsString(self):
        return str(self.pos[0]) + ":" + str(self.pos[1]) + ":" + str(self.pos[2]) + ":" + str(self.pos[3])


import argparse
import logging
import os
import re

from bs4 import BeautifulSoup
import requests
import yaml

search_url = "https://www.admin.ch/opc/search/?text={}"
latest_update_string = r"\(Stand am ([^<]*)\)<"
is_active_string = "Dieser Text ist in Kraft"
download_dir = "downloads"
logger = logging.getLogger("root")
csv_logger = logging.getLogger("csv_logger")

def setup_logging():
    import logging.config
    with open('log_conf.yaml') as f:
        conf = yaml.load(f, Loader=yaml.SafeLoader)
        logging.config.dictConfig(conf)

class SrRecord(object):
    """A legal document from admin.ch classified collection.

    May be a federal law, directive or other regulation.
    SR is short for "Systemematische Rechtssammlung".
    """

    def __init__(self, sr_id):
        self.sr_id = sr_id
        self.url = ""
        self.title = ""
        self.is_active = ""
        self.last_update = ""
        self.pdf_url = ""

    def populate(self):
        url = search_url.format(self.sr_id)
        r = requests.get(url)

        # check if this looks like a legal record
        if not r.status_code == 200 \
                or "classified-compilation" not in r.url \
                or "index.html" not in r.url:
            logger.info(f"Could not obtain details for ID {self.sr_id}.")
            return

        soup = BeautifulSoup(r.text, 'html.parser')
        self.url = r.url
        self.title = soup.title.string
        self.is_active = self.get_is_active(soup)
        # do not expect details for inactive records
        if self.is_active:
            self.last_update = self.get_last_update_date(soup)
            self.pdf_url = self.get_pdf_url(soup)

    def get_last_update_date(self, soup):
        m = re.findall(latest_update_string, str(soup))
        if m:
            return m[0]
        else:
            return ""

    def get_is_active(self, soup):
        return is_active_string in str(soup)

    def get_pdf_url(self, soup):
        base_url = self.url[:self.url.rfind('/')]
        pdf_url = soup.find_all("a", string="PDF")[0]['href']
        return base_url + "/" + pdf_url

    def download_pdf(self, download_dir):
        if not self.pdf_url:
            logger.info(f"No PDF found for ID {self.sr_id}.")
            return
        pdf_file = requests.get(self.pdf_url)
        if pdf_file:
            file_name = f"{download_dir}/{self.title}.pdf"
            with open(file_name, "wb") as file:
                file.write(pdf_file.content)

    @staticmethod
    def get_csv_header():
        return (
            "ID; "
            "Title (German); "
            "Last update; "
            "Active status; "
            "URL"
            )

    def to_csv(self):
        return (
            f"{self.sr_id}; "
            f"{self.title}; "
            f"{self.last_update}; "
            f"{self.is_active}; "
            f"{self.url}"
            )

    def __str__(self):
        return (
            f"SR record with ID: {self.sr_id}\n"
            f"Last updated on: {self.last_update}\n"
            f"Title: {self.title}\n"
            f"Active Status: {self.is_active}\n"
        )

def clean_up_ids(id_list):
    unique_ids = list(set(id_list))
    return sorted(unique_ids)

def main(args):

    setup_logging()

    if not args.print_only:
        if not os.path.exists(args.output_dir):
            os.makedirs(args.output_dir)

    records = []
    sr_ids = clean_up_ids(args.sr_ids)
    for sr_id in sr_ids:
        record = SrRecord(sr_id)
        record.populate()
        records.append(record)
        logger.info(record)

    csv_logger.info(SrRecord.get_csv_header())
    for record in records:
        csv_logger.info(record.to_csv())

    if args.print_only:
        logger.info("Skipping downloads.")
    else:
        logger.info(f"Downloading PDFs into {args.output_dir} ...")
        for record in records:
            record.download_pdf(args.output_dir)

if __name__ == "__main__":
    parser = argparse.ArgumentParser(
        description='Fetch legal documents from admin.ch.')
    parser.add_argument('sr_ids', metavar='ID', nargs='+',
                        help='IDs of documents to fetch')
    parser.add_argument('-o', '--output_dir', default=download_dir,
                        help='where to place the PDF files')
    parser.add_argument('-p', '--print_only', action='store_true',
                        help='do not download anything, just print some info')
    args = parser.parse_args()
    main(args)


import scrapy
from ..items import QuotestutorialItem
from scrapy.http import FormRequest

class QuoteSpider(scrapy.Spider):
    name = 'quotesbackup'
    start_urls = ['http://quotes.toscrape.com/login']

    def parse(self, response):
        token = response.css("form input::attr(value)").extract_first()
        # print("TOKEN :" + token)
        return FormRequest.from_response(response, formdata={
            'csrf_token': token,
            'username': 'hero',
            'pasword' : 'password'
        }, callback=self.start_scraping)

    def start_scraping(self, response):
        items = QuotestutorialItem()
        all_div_quotes = response.css("div.quote")

        for quote in all_div_quotes:
            title = quote.css(".text::text").extract()
            author = quote.css(".author::text").extract()
            tags = quote.css(".tag::text").extract()

            items['title'] = title
            items['author'] = author
            items['tags'] = tags

            yield items


import os
import zipfile

"""
ZIP压缩包处理
zipfile 内置库
"""

# 递归删除目录
def delete_folder(folder_path: str):
    """
    folder_path: 要删除的目录名。
    """
    # check folder exist
    if not os.path.exists(folder_path):
        return

    # del items in folder
    for item in os.listdir(folder_path):
        item_path = os.path.join(folder_path, item)
        if os.path.isfile(item_path):
            # del file
            os.remove(item_path)
        else:
            # del folder
            delete_folder(item_path)

    # del empty folder
    try:
        os.rmdir(folder_path)
    except PermissionError as e:
        raise (e, "no access")

# 打包文件夹为zip压缩文件
def zip_folder(to_zip_f: str):
    # 检查
    if not os.path.exists(to_zip_f):  # check file exist
        raise FileExistsError(f"folder not exist: {to_zip_f}")
    if not os.access(to_zip_f, os.R_OK):  # check file access
        raise PermissionError(f"folder no read access: {to_zip_f}")
    if not os.access(to_zip_f, os.W_OK):  # check file access
        raise PermissionError(f"folder no write access: {to_zip_f}")

    # 取默认压缩文件名
    *_, zip_file_name = to_zip_f.split(os.sep)
    zip_file_name = f"{zip_file_name}.zip"

    # 执行压缩
    with zipfile.ZipFile(zip_file_name, 'w') as zip_file:
        for root, dirs, files in os.walk(to_zip_f):
            for file in files:
                file_path = os.path.join(root, file)
                zip_file.write(file_path)

    return os.path.abspath(zip_file_name)

# 解压缩zip包
def unzip_file(zip_path: str, unzip_path=None):
    """
    解压zip文件

    :param zip_path: 压缩文件路径
    :param unzip_path: 解压位置 默认压缩文件同目录下 同名目录
    :return: 解压后 全路径
    """

    # 检查
    if not os.path.exists(zip_path):  # check file exist
        raise FileExistsError(f"file not exist: {zip_path}")
    if not os.access(zip_path, os.R_OK):  # check file access
        raise PermissionError(f"file no read access: {zip_path}")

    # 压缩文件路径 自适应
    zip_full_path = zip_path
    if not os.path.isabs(zip_path):
        zip_full_path = os.path.abspath(zip_path)
    base_name = os.path.basename(zip_full_path)  # testcase.zip
    pre_path, extension = os.path.splitext(base_name)  # 路径(不包括扩展名) 文件类型

    # 解压路径 自适应
    unzip_full_path = unzip_path
    if not unzip_path:
        unzip_full_path = pre_path
    if os.path.exists(unzip_full_path):
        delete_folder(unzip_full_path)

    # 执行解压
    try:
        with zipfile.ZipFile(zip_path, 'r') as zip_ref:
            # 校验压缩包是否损坏 不能覆盖所有损坏情况
            # res = zip_ref.testzip()
            # if res:
            #     raise IOError(f"{zip_path} file is broken")

            for file_info in zip_ref.infolist():
                file_info.filename = file_info.filename.encode('cp437').decode('gbk')  # 修复中文乱码
                zip_ref.extract(file_info, unzip_full_path)
    except zipfile.BadZipFile as e:  # 文件损坏可能报错
        print(f"bad zip file: {zip_path} {e}")
    except OSError as e:  # 文件损坏可能报错
        print(f"os error: {e}")
        return ''

    return os.path.abspath(unzip_full_path)

if __name__ == '__main__':
    # zip_file_path = "xxx.zip"
    # print(unzip_file(zip_file_path))

    to_zip_folder = r"xxx"
    print(zip_folder(to_zip_folder))


"""Coordinates conversion functions."""
from typing import Dict

import numpy as np
from aztekasPlot.utils.miscellaneous import remove_nan

def convert_to_plot_coordinates(data_dict: Dict) -> dict:
    """Convert data to plot coordinates.

    Parameters
    ----------
        data_dict [dict]:
            Data dictionary.

    Returns:
    --------
        data_dict [dict]:
            Data dictionary with converted coordinates.
    """
    x1 = data_dict["x1"]
    x2 = data_dict["x2"]
    Nx1 = data_dict["Nx1"]
    Nx2 = data_dict["Nx2"]
    COORD = data_dict["COORD"]
    metric = data_dict["metric"]

    # Mesh grid
    nx1 = x1[::Nx2, :]
    nx2 = x2[::, ::Nx1]

    X1, X2 = np.meshgrid(nx1, nx2)

    if COORD in ["CARTESIAN", "CYLINDRICAL"] and metric == "Non-rel":
        data_dict = convert_from_cartesian_minkowski(data_dict, X1, X2)
    elif COORD in ["CARTESIAN", "CYLINDRICAL"] and metric == "Minkowski":
        data_dict = convert_from_cartesian_minkowski(data_dict, X1, X2)
    elif COORD in ["SPHERICAL"]:
        r = X1
        th = X2

        if metric == "Non-rel":
            data_dict = convert_from_spherical(data_dict, r, th)
        elif metric == "Minkowski":
            data_dict = convert_from_spherical_minkowski(data_dict, r, th)
        elif metric == "Kerr-Schild":
            data_dict = convert_from_spherical_kerr_schild(data_dict, r, th)
    elif COORD in ["POLAR"]:
        r = X1
        _ = X2  # phi
        # if metric == "Kerr-Schild":
        # data_dict = convert_from_polar_kerr_schild(data_dict, r, phi)

    return data_dict

def convert_from_cartesian(data_dict: Dict, x: np.ndarray, y: np.ndarray) -> dict:
    """Convert data from cartesian Minkowski coordinates to cartesian.

    Parameters
    ----------
        data_dict [dict]:
            Data dictionary.

        x [np.ndarray]:
            X coordinate.

        y [np.ndarray]:
            Y coordinate.

    Returns:
    --------
        data_dict [dict]:
            Data dictionary with converted coordinates.
    """
    X1 = x
    X2 = y

    vx = data_dict["vx1"]
    vy = data_dict["vx2"]

    data_dict["X1"] = X1
    data_dict["X2"] = X2
    data_dict["vX1"] = vx
    data_dict["vX2"] = vy
    data_dict["vv"] = np.sqrt(vx**2 + vy**2)

    return data_dict

def convert_from_cartesian_minkowski(
    data_dict: Dict, x: np.ndarray, y: np.ndarray
) -> dict:
    """Convert data from cartesian Minkowski coordinates to cartesian.

    Parameters
    ----------
        data_dict [dict]:
            Data dictionary.

        x [np.ndarray]:
            X coordinate.

        y [np.ndarray]:
            Y coordinate.

    Returns:
    --------
        data_dict [dict]:
            Data dictionary with converted coordinates.
    """
    X1 = x
    X2 = y

    vx = data_dict["vx1"]
    vy = data_dict["vx2"]

    data_dict["X1"] = X1
    data_dict["X2"] = X2
    data_dict["vX1"] = vx
    data_dict["vX2"] = vy
    data_dict["vv"] = np.sqrt(vx**2 + vy**2)
    data_dict["W"] = 1.0 / np.sqrt(1.0 - data_dict["vv"] ** 2)

    return data_dict

def convert_from_spherical_minkowski(
    data_dict: Dict, r: np.ndarray, th: np.ndarray
) -> dict:
    """Convert data from spherical Minkowski coordinates to cartesian.

    Parameters
    ----------
        data_dict [dict]:
            Data dictionary.

        r [np.ndarray]:
            Spherical radius.

        th [np.ndarray]:
            Longitudinal angle.

    Returns:
    --------
        data_dict [dict]:
            Data dictionary with converted coordinates.
    """
    X1 = r * np.sin(th)
    X2 = r * np.cos(th)

    vr = data_dict["vx1"]
    vth = data_dict["vx2"]

    data_dict["X1"] = X1
    data_dict["X2"] = X2
    data_dict["vX1"] = vr * X1 + vth * X2
    data_dict["vX2"] = vr * X2 / r - vth * X1
    data_dict["vv"] = np.sqrt(vr**2 + r**2 * vth**2)
    data_dict["W"] = 1.0 / np.sqrt(1.0 - data_dict["vv"] ** 2)

    return data_dict

def convert_from_spherical(data_dict: Dict, r: np.ndarray, th: np.ndarray) -> dict:
    """Convert data from spherical non-relativistic coordinates to cartesian.

    Parameters
    ----------
        data_dict [dict]:
            Data dictionary.

        r [np.ndarray]:
            Spherical radius.

        th [np.ndarray]:
            Longitudinal angle.

    Returns:
    --------
        data_dict [dict]:
            Data dictionary with converted coordinates.
    """
    X1 = r * np.sin(th)
    X2 = r * np.cos(th)

    vr = data_dict["vx1"]
    vth = data_dict["vx2"]

    data_dict["X1"] = X1
    data_dict["X2"] = X2
    data_dict["vX1"] = vr * X1 / r + vth * X2 / r
    data_dict["vX2"] = vr * X2 / r - vth * X1 / r
    data_dict["vv"] = np.sqrt(vr**2 + vth**2)

    return data_dict

def convert_from_spherical_kerr_schild(
    data_dict: Dict, r: np.ndarray, th: np.ndarray
) -> dict:
    """Convert data from spherical Kerr-Schild coordinates to cartesian.

    Parameters
    ----------
        data_dict [dict]:
            Data dictionary.

        r [np.ndarray]:
            Spherical radius.

        th [np.ndarray]:
            Longitudinal angle.

    Returns:
    --------
        data_dict [dict]:
            Data dictionary with converted coordinates.
    """
    a_spin = data_dict["a_spin"]
    metric_dict = get_metric_dict(a_spin, r, th)

    # Define X1 and X2
    X1 = np.sqrt(r**2 + a_spin**2) * np.sin(th)
    X2 = r * np.cos(th)

    # Define v_i
    v_r = data_dict["vx1"]
    v_th = data_dict["vx2"]
    if data_dict["rotation"]:
        v_phi = data_dict["vx3"]

    # Compute v^i = gamma^{ij} v_j
    vr = metric_dict["gammarr"] * v_r + metric_dict["gammarth"] * v_th
    vth = metric_dict["gammarth"] * v_r + metric_dict["gammathth"] * v_th
    if data_dict["rotation"]:
        vr += metric_dict["gammarphi"] * v_phi
        vth += metric_dict["gammathphi"] * v_phi
        vphi = (
            metric_dict["gammarphi"] * v_r
            + metric_dict["gammathphi"] * v_th
            + metric_dict["gammaphiphi"] * v_phi
        )

    # Compute Horizon Penetrating (HP) velocity magnitude square VV_HP = v^i * v_i
    vv_HP = vr * v_r + vth * v_th
    if data_dict["rotation"]:
        vv_HP += vphi * v_phi

    # Compute Lorentz factor W_HP = 1/sqrt(1 - VV_HP)
    W_HP = 1 / np.sqrt(1 - vv_HP)
    vv_HP = np.sqrt(vv_HP)

    # Compute teh four velocity vector U^\mu
    UT = W_HP / metric_dict["alpha"]
    Ur = W_HP * (vr - metric_dict["betar"] / metric_dict["alpha"])
    Uth = W_HP * (vth - metric_dict["betath"] / metric_dict["alpha"])
    if data_dict["rotation"]:
        Uphi = W_HP * (vphi - metric_dict["betaphi"] / metric_dict["alpha"])

    # Compute HP velocity vector
    vr_HP = Ur / UT
    vth_HP = Uth / UT
    vphi_HP = Uphi / UT

    # Compute stream velocities
    vX1 = Ur * X1 * r / (r**2 + a_spin**2) + Uth * X2
    vX2 = Ur * X2 / r - Uth * X1

    # Compute the Non-Horizon Penetrating (NH) velocity vector
    alpha_NH = np.sqrt(
        np.abs(metric_dict["rho2"] * metric_dict["Delta"] / metric_dict["Sigma"])
    )
    gamma_rr = metric_dict["rho2"] / metric_dict["Delta"]
    gamma_thth = metric_dict["rho2"]

    UT_NH = UT - 2 * r * Ur / metric_dict["Delta"]
    Ur_NH = Ur
    Uth_NH = Uth
    if data_dict["rotation"]:
        Uphi_NH = Uphi - a_spin * Ur / metric_dict["Delta"]

    # Compute NH velocity vector
    W_NH = alpha_NH * UT_NH
    vr_NH = Ur_NH / W_NH
    vth_NH = Uth_NH / W_NH
    vphi_NH = Uphi_NH / W_NH

    vv_NH = gamma_rr * vr_NH**2 + gamma_thth * vth_NH**2
    W_NH = 1.0 / np.sqrt(1.0 - vv_NH)

    UhatT = UT / np.sqrt(1.0 + 2.0 * r / metric_dict["rho2"])
    Uhatr = np.sqrt(1.0 + 2.0 * r / metric_dict["rho2"]) * (
        Ur
        + (2.0 * r / (metric_dict["rho2"] + 2.0 * r)) * UT
        - Uphi * a_spin * np.sin(th) ** 2.0
    )
    Uhatth = np.sqrt(metric_dict["rho2"]) * Uth
    Uhatphi = np.sqrt(metric_dict["rho2"]) * np.sin(th) * Uphi

    data_dict["metric_dict"] = metric_dict
    data_dict["X1"] = remove_nan(X1)
    data_dict["X2"] = remove_nan(X2)
    data_dict["vX1"] = remove_nan(vX1)
    data_dict["vX2"] = remove_nan(vX2)
    data_dict["vv"] = remove_nan(vv_HP)
    data_dict["W"] = remove_nan(W_HP)
    data_dict["vv_NH"] = remove_nan(vv_NH)
    data_dict["W_NH"] = remove_nan(W_NH)
    data_dict["vr_NH"] = remove_nan(vr_NH)
    data_dict["vth_NH"] = remove_nan(vth_NH)
    data_dict["vphi_NH"] = remove_nan(vphi_NH)
    data_dict["vr_HP"] = remove_nan(vr_HP)
    data_dict["vth_HP"] = remove_nan(vth_HP)
    data_dict["vphi_HP"] = remove_nan(vphi_HP)
    data_dict["UhatT"] = remove_nan(UhatT)
    data_dict["Uhatr"] = remove_nan(Uhatr)
    data_dict["Uhatth"] = remove_nan(Uhatth)
    data_dict["Uhatphi"] = remove_nan(Uhatphi)

    return data_dict

def get_metric_dict(a: float, r: np.ndarray, th: np.ndarray) -> dict:
    """Get metric dictionary.

    Parameters
    ----------
        a [float]:
            Spin parameter.

        r [np.ndarray]:
            First coordinate.

        th [np.ndarray]:
            Second coordinate.

    Returns:
    --------
        metric_dict [dict]:
            Metric dictionary.
    """
    rho2 = r**2.0 + (a**2.0) * (np.cos(th) ** 2.0)
    Delta = r**2.0 - 2.0 * r + a**2.0
    Sigma = (r**2.0 + a**2.0) ** 2.0 - (a**2.0) * Delta * (np.sin(th) ** 2.0)

    alpha = 1.0 / np.sqrt(1.0 + 2.0 * r / rho2)

    beta_r = 2.0 * r / rho2
    beta_th = 0.0
    beta_phi = 0.0

    betar = (2.0 * r / rho2) * (1.0 / (1.0 + 2.0 * r / rho2))
    betath = 0.0
    betaphi = 0.0

    gamma_rr = 1.0 + 2.0 * r / rho2
    gamma_rth = 0
    gamma_rphi = -a * (1.0 + 2.0 * r / rho2) * np.sin(th) ** 2
    gamma_thth = rho2
    gamma_thphi = 0
    gamma_phiphi = (np.sin(th) ** 2.0) * (
        (a**2.0) * (1.0 + 2.0 * r / rho2) * (np.sin(th) ** 2.0) + rho2
    )

    gammarr = ((a**2) * (rho2 + 2.0 * r) * (np.sin(th) ** 2.0) + rho2**2.0) / (
        rho2 * (rho2 + 2.0 * r)
    )
    gammarth = 0.0
    gammarphi = a / rho2
    gammathth = 1.0 / rho2
    gammathphi = 0
    gammaphiphi = 1.0 / (rho2 * np.sin(th + 0.000001) ** 2.0)

    return {
        "rho2": rho2,
        "Delta": Delta,
        "Sigma": Sigma,
        "alpha": alpha,
        "beta_r": beta_r,
        "betha_th": beta_th,
        "betha_phi": beta_phi,
        "betar": betar,
        "betath": betath,
        "betaphi": betaphi,
        "gamma_rr": gamma_rr,
        "gamma_rth": gamma_rth,
        "gamma_rphi": gamma_rphi,
        "gamma_thth": gamma_thth,
        "gamma_thphi": gamma_thphi,
        "gamma_phiphi": gamma_phiphi,
        "gammarr": gammarr,
        "gammarth": gammarth,
        "gammarphi": gammarphi,
        "gammathth": gammathth,
        "gammathphi": gammathphi,
        "gammaphiphi": gammaphiphi,
    }


import time
import os
from flask import render_template, request, redirect, send_from_directory, session, flash, url_for
from dao import JogoDao, UsuarioDao
from models import Jogo
from jogoteca import db, app
from helpers import recupera_imagem, deleta_arquivo

jogo_dao = JogoDao(db)
usuario_dao = UsuarioDao(db)

@app.route('/')
def index():
    #Lista todos os jogos que estão salvo no banco de dados.
    lista = jogo_dao.listar()
    return render_template('lista.html', titulo='Jogos', jogos=lista)

@app.route('/novo')
def novo():
    #Verifica se o usuário está logado e direciona para a URL de criação de novo jogo para inserir as informações.
    if 'usuario_logado' not in session or session['usuario_logado'] == None:
        return redirect(url_for('login', proxima=url_for('novo')))
    return render_template('novo.html', titulo='Novo Jogo')

@app.route('/criar', methods=['POST',])
def criar():
    #Pega as informações que foram inseridas pelo usuário e salva no banco de dados.
    nome = request. form['nome']
    categoria = request. form['categoria']
    console = request. form['console']
    jogo = Jogo(nome, categoria, console)
    jogo = jogo_dao.salvar(jogo)

    arquivo = request.files['arquivo']
    upload_path = app.config['UPLOAD_PATH']
    timestamp = time.time()
    arquivo.save(f'{upload_path}/capa{jogo.id}--{timestamp}.jpg')
    return redirect(url_for('index'))

@app.route('/editar/<int:id>')
def editar(id):
    #Verifica se o usuario está logado e direciona o para o URL de editar para poder alterar.
    if 'usuario_logado' not in session or session['usuario_logado'] == None:
        return redirect(url_for('login', proxima=url_for('editar', id=id)))
    jogo = jogo_dao.busca_por_id(id)
    nome_imagem = recupera_imagem(id)
    return render_template('editar.html', titulo='Editando Jogo', jogo=jogo, capa_jogo=nome_imagem)

@app.route('/atualizar', methods=['POST',])
def atualizar():
    #Pega as alterações que foram feita pelo usuário e salva no banco de dados.
    nome = request. form['nome']
    categoria = request. form['categoria']
    console = request. form['console']
    jogo = Jogo(nome, categoria, console, id=request.form['id'])
    jogo_dao.salvar(jogo)

    arquivo = request.files['arquivo']
    upload_path = app.config['UPLOAD_PATH']
    timestamp = time.time()
    deleta_arquivo(jogo.id)
    arquivo.save(f'{upload_path}/capa{jogo.id}--{timestamp}.jpg')

    return redirect(url_for('index'))

@app.route('/deletar/<int:id>')
def deletar(id):
    #Essa rota deleta as informações do banco de dados, conforme o ID informado pelo usuário.
    jogo_dao.deletar(id)
    flash('O jogo foi removido com sucesso!')
    return redirect(url_for('index'))

@app.route('/login')
def login():
    #Rota para o usuário logar.
    proxima = request.args.get('proxima')
    return render_template('login.html', proxima=proxima)

@app.route('/autenticar', methods=['POST', ])
def autenticar():
    #Essa rota autentica as informações inseridas pelo usuário.
    usuario = usuario_dao.buscar_por_id(request.form['usuario'])
    if usuario:
        if usuario.senha == request.form['senha']:
            session['usuario_logado'] = usuario.id
            flash(usuario.nome + ' logou com sucesso!')
            proxima_pagina = request.form['proxima']
            return redirect(proxima_pagina)
    else:
        flash('Não logado, tente novamente!')
        return redirect(url_for('login'))

@app.route('/logout')
def logout():
    #Rota para o usuário realizar o logout.
    session['usuario_logado'] = None
    flash('Nenhum usuário logado!')
    return redirect(url_for('index'))

@app.route('/uploads/<nome_arquivo>')
def imagem(nome_arquivo):
    return send_from_directory('uploads', nome_arquivo)


from typing import Dict

import networkx as nx
from networkx.classes.multidigraph import MultiDiGraph

from quafu.dagcircuits.instruction_node import InstructionNode

class DAGCircuit(MultiDiGraph):
    def __init__(
        self, qubits_used=None, cbits_used=None, incoming_graph_data=None, **attr
    ):
        super().__init__(incoming_graph_data, **attr)

        if qubits_used is None:
            self.qubits_used = set()
        elif isinstance(qubits_used, set):
            self.qubits_used = qubits_used
        else:
            raise ValueError("qubits_used should be a set or None")

        if cbits_used is None:
            self.cbits_used = set()
        elif isinstance(cbits_used, set):
            self.cbits_used = cbits_used
        else:
            raise ValueError("cbits_used should be a set or None")

        # num of instruction nodes
        self.num_instruction_nodes = 0

    # add new methods or override existing methods here.

    def update_qubits_used(self):
        """
        qubits_used is a set of qubits used in DAGCircuit
        based on node -1's edges' labels, the qubits is the integer part of the label

        return:
            qubits_used: set of qubits used in DAGCircuit
        """
        if -1 not in self.nodes:
            raise ValueError("-1 should be in DAGCircuit, please add it first")
        self.qubits_used = set(
            [int(edge[2]["label"][1:]) for edge in self.out_edges(-1, data=True)]
        )
        return self.qubits_used

    def update_cbits_used(self):
        """
        cbits_used is a set of cbits used in DAGCircuit
        calculated by  measurenode's cbits
        return:
            cbits_used: set of cbits used in DAGCircuit
        """
        for node in self.nodes:
            # if node.has a attribute 'name' and node.name == 'measure'
            if hasattr(node, "name") and node.name == "measure":
                self.cbits_used = set(node.pos.values())
        return self.cbits_used

    def update_num_instruction_nodes(self):
        """
        num_instruction_nodes is the number of instruction nodes in DAGCircuit
        """
        if -1 not in self.nodes:
            raise ValueError("-1 should be in DAGCircuit, please add it first")
        if float("inf") not in self.nodes:
            raise ValueError(
                'float("inf") should be in DAGCircuit, please add it first'
            )
        self.num_instruction_nodes = len(self.nodes) - 2

        for node in self.nodes:
            if hasattr(node, "name") and node.name == "measure":
                self.num_instruction_nodes -= 1
        return self.num_instruction_nodes

    def nodes_dict(self):
        """
        nodes_dict is a dictionary of nodes with the node label as key and the node as value.
        without  -1 and float('inf')
        """
        nodes_dict = {}
        for node in nx.topological_sort(self):
            if node != -1 and node != float("inf"):
                nodes_dict[node.label] = node
        return nodes_dict

    def nodes_list(self):
        """
        nodes_list is a list of nodes without  -1 and float('inf')
        """
        nodes_list = []
        for node in nx.topological_sort(self):
            if node != -1 and node != float("inf"):
                nodes_list.append(node)
        return nodes_list

    def node_qubits_predecessors(self, node: InstructionNode):
        """
        node_qubits_predecessors is a dict of {qubits -> predecessors }of node
        Args:
            node in DAGCircuit, node should not be -1
        Returns:
            node_qubits_predecessors: dict of {qubits -> predecessors }of node
        """
        # for edge in self.in_edges(node, data=True):
        #     print(edge[0], edge[1], edge[2])

        if node not in self.nodes:
            raise ValueError("node should be in DAGCircuit")
        if node in [-1]:
            raise ValueError("-1 has no predecessors")

        predecessor_nodes = [edge[0] for edge in self.in_edges(node, data=True)]
        qubits_labels = [
            int(edge[2]["label"][1:]) for edge in self.in_edges(node, data=True)
        ]
        node_qubits_predecessors = dict(zip(qubits_labels, predecessor_nodes))
        return node_qubits_predecessors

    def node_qubits_successors(self, node: InstructionNode):
        """
        node_qubits_successors is a dict of {qubits -> successors }of node
        Args:
            node in DAGCircuit, node should not be  float('inf')
        Returns:
            node_qubits_successors: dict of {qubits -> successors }of node

        """
        if node not in self.nodes:
            raise ValueError("node should be in DAGCircuit")
        if node in [float("inf")]:
            raise ValueError('float("inf") has no successors')
        successor_nodes = [edge[1] for edge in self.out_edges(node, data=True)]
        qubits_labels = [
            int(edge[2]["label"][1:]) for edge in self.out_edges(node, data=True)
        ]
        node_qubits_successors = dict(zip(qubits_labels, successor_nodes))
        return node_qubits_successors

    def node_qubits_inedges(self, node: InstructionNode):
        """
        node_qubits_inedges is a dict of {qubits -> inedges }of node
        Args:
            node in DAGCircuit, node should not be -1
        Returns:
            node_qubits_inedges: dict of {qubits -> inedges }of node
        """
        if node not in self.nodes:
            raise ValueError("node should be in DAGCircuit")
        if node in [-1]:
            raise ValueError("-1 has no predecessors")

        inedges = [edge for edge in self.in_edges(node)]
        qubits_labels = [
            int(edge[2]["label"][1:]) for edge in self.in_edges(node, data=True)
        ]
        node_qubits_inedges = dict(zip(qubits_labels, inedges))
        return node_qubits_inedges

    def node_qubits_outedges(self, node: InstructionNode):
        """
        node_qubits_outedges is a dict of {qubits -> outedges }of node
        Args:
            node in DAGCircuit, node should not be float('inf')
        Returns:
            node_qubits_outedges: dict of {qubits -> outedges }of node
        """
        if node not in self.nodes:
            raise ValueError("node should be in DAGCircuit")
        if node in [float("inf")]:
            raise ValueError('float("inf") has no successors')
        outedges = [edge for edge in self.out_edges(node)]
        qubits_labels = [
            int(edge[2]["label"][1:]) for edge in self.out_edges(node, data=True)
        ]
        node_qubits_outedges = dict(zip(qubits_labels, outedges))
        return node_qubits_outedges

    def remove_instruction_node(self, gate: InstructionNode):
        """
        remove a gate from DAGCircuit, and all edges connected to it.
        add new edges about qubits of removed gate between all predecessors and successors of removed gate.
        Args:
            gate: InstructionNode, gate should be in DAGCircuit, gate should not be -1 or float('inf')
        """

        if gate not in self.nodes:
            raise ValueError("gate should be in DAGCircuit")
        if gate in [-1, float("inf")]:
            raise ValueError('gate should not be -1 or float("inf")')

        qubits_predecessors = self.node_qubits_predecessors(gate)
        qubits_successors = self.node_qubits_successors(gate)
        for qubit in gate.pos:
            if qubits_predecessors[qubit] != -1 and qubits_successors[qubit] != float(
                "inf"
            ):
                self.add_edge(
                    qubits_predecessors[qubit],
                    qubits_successors[qubit],
                    label=f"q{qubit}",
                )
            elif qubits_predecessors[qubit] == -1 and qubits_successors[qubit] != float(
                "inf"
            ):
                self.add_edge(
                    qubits_predecessors[qubit],
                    qubits_successors[qubit],
                    label=f"q{qubit}",
                    color="green",
                )
            else:
                self.add_edge(
                    qubits_predecessors[qubit],
                    qubits_successors[qubit],
                    label=f"q{qubit}",
                    color="red",
                )

        self.remove_node(gate)

        # update qubits
        self.qubits_used = self.update_qubits_used()

    def merge_dag(self, other_dag):
        """
        merge other_dag into self
        Args:
            other_dag: DAGCircuit
        Returns:
            self: DAGCircuit
        """
        if not isinstance(other_dag, DAGCircuit):
            raise ValueError("other_dag should be a DAGCircuit")
        if other_dag == None:
            return self
        if self == None:
            return other_dag

        # for the same qubits (intersection),
        # remove the outgoing edges from the final node of the original DAG and the incoming edges from the initial node of the other DAG,
        # then connect the corresponding tail and head nodes by adding edges
        other_dag_qubits_used = other_dag.update_qubits_used()
        self_qubits_used = self.update_qubits_used()

        insect_qubits = self_qubits_used & other_dag_qubits_used
        end_edges_labels_1 = self.node_qubits_inedges(float("inf"))
        start_edges_labels_2 = other_dag.node_qubits_outedges(-1)

        if len(insect_qubits) != 0:
            for insect_qubit in insect_qubits:
                self.remove_edges_from([end_edges_labels_1[insect_qubit]])
                other_dag.remove_edges_from([start_edges_labels_2[insect_qubit]])
                self.add_edge(
                    end_edges_labels_1[insect_qubit][0],
                    start_edges_labels_2[insect_qubit][1],
                    label=f"q{insect_qubit}",
                )

        # add other_dag's nodes and edges into self
        # ！if we add edges, we don't need to add nodes again
        self.add_edges_from(other_dag.edges(data=True))

        # remove the edges between -1 and float('inf')
        self.remove_edges_from(
            [
                edge
                for edge in self.edges(data=True)
                if edge[0] == -1 and edge[1] == float("inf")
            ]
        )

        # update qubits
        self.qubits_used = self.update_qubits_used()

    def add_instruction_node(
        self,
        gate: InstructionNode,
        predecessors_dict: Dict[int, InstructionNode],
        successors_dict: Dict[int, InstructionNode],
    ):
        """
        add a gate into DAGCircuit, and all edges connected to it.
        add new edges about qubits of new gate between all predecessors and successors of new gate.
        Args:
            gate: InstructionNode, gate should not be -1 or float('inf')
            predecessors_dict: dict of {qubits -> predecessors }of gate
            successors_dict: dict of {qubits -> successors }of gate
        """
        if gate in [-1, float("inf")]:
            raise ValueError('gate should not be -1 or float("inf")')

        # remove the edges between the predessors,successors about the qubits used by the added node
        qubits_pre_out_edges = []
        qubits_suc_in_edges = []
        for qubit in gate.pos:
            pre_out_edges = self.node_qubits_outedges(predecessors_dict[qubit])
            qubits_pre_out_edges.append(pre_out_edges[qubit])

            suc_in_edges = self.node_qubits_inedges(successors_dict[qubit])
            qubits_suc_in_edges.append(suc_in_edges[qubit])

        self.remove_edges_from(qubits_pre_out_edges)
        self.remove_edges_from(qubits_suc_in_edges)

        # add the new node and edges
        for qubit in gate.pos:
            if predecessors_dict[qubit] == -1:
                self.add_edge(
                    predecessors_dict[qubit], gate, label=f"q{qubit}", color="green"
                )
            else:
                self.add_edge(predecessors_dict[qubit], gate, label=f"q{qubit}")
            if successors_dict[qubit] == float("inf"):
                self.add_edge(
                    gate, successors_dict[qubit], label=f"q{qubit}", color="red"
                )
            else:
                self.add_edge(gate, successors_dict[qubit], label=f"q{qubit}")

        # update qubits
        self.qubits_used = self.update_qubits_used()

    def is_dag(self):
        """
        is_dag is a bool value to check if DAGCircuit is a DAG
        """
        return nx.is_directed_acyclic_graph(self)


## standard imports
import argparse
import numpy as np
import pulp

## argument parser
parser = argparse.ArgumentParser()

## algorithm solver class
class planner():
    ## init
    def __init__(self, mdppath, algorithm, policy = None) :
        self.mdp = self.extractmdp(mdppath)
        if policy == None:
            if algorithm == "vi":
                self.valuefunc, self.policy = self.valueiteration()
            elif algorithm == "hpi":
                self.valuefunc, self.policy = self.howardpolicyiteration()
            else:
                self.valuefunc, self.policy = self.linearprogramming()
        else:
            self.policy = self.extractpolicy(policy)
            self.valuefunc = self.evalpolicy(self.policy, self.mdp["noofstates"])
        self.printoutput()

    ## function to extract mdp from the text file
    def extractmdp(self, mdppath):
        mdp = dict()
        lines = open(mdppath).read().strip()
        lines = lines.split("\n")
        for line in lines:
            l = line.split()
            if l[0] == "transition":
                s1 = int(l[1])
                ac = int(l[2])
                s2 = int(l[3])
                r = float(l[4])
                p = float(l[5])
                mdp["transitionfunc"][s1][ac][s2] = p
                mdp["rewardfunc"][s1][ac][s2] = r
            elif l[0] == "numStates":
                mdp["noofstates"] = int(l[1])
            elif l[0] == "numActions":
                mdp["noofactions"] = int(l[1])
                ## initialising transition and reward funtion
                mdp["transitionfunc"] = np.zeros((mdp["noofstates"], mdp["noofactions"], mdp["noofstates"]))
                mdp["rewardfunc"] = np.zeros((mdp["noofstates"], mdp["noofactions"], mdp["noofstates"]))
            elif l[0] == "mdptype":
                mdp["mdptype"] = l[1]
            elif l[0] == "discount":
                mdp["discountfactor"] = float(l[1])
            elif l[0] == "end":
                pass
        return mdp

    ## function to extract policy
    def extractpolicy(self, policypath):
        policy = []
        lines = open(policypath).read().strip()
        lines = lines.split("\n")
        for line in lines:
            policy.append(int(line))
        return np.array(policy)

    ## function for value iteration
    def valueiteration(self,):
        noofstates = int(self.mdp["noofstates"])
        v = np.zeros(noofstates)        ## initial value function
        vdash = np.zeros(noofstates)    ## value function after applying the operator
        while(True):                    ## iterating until all are within a tolerance of 1e-8 since precision is only upto 6
            vdash = np.sum(self.mdp["transitionfunc"]*(self.mdp["rewardfunc"] + self.mdp["discountfactor"]*v), axis=2)
            vdash = np.max(vdash, axis = 1)
            if(np.sum(vdash - v < 1e-8) == noofstates ):
                break
            v = vdash
        policy = np.sum(self.mdp["transitionfunc"]*(self.mdp["rewardfunc"] + self.mdp["discountfactor"]*v), axis=2)
        policy = np.argmax(policy, axis = 1)
        return vdash, policy

    ## function for linear programming
    def linearprogramming(self,):
        lpsolver = pulp.LpProblem('linearprogformdp', pulp.LpMaximize)    ## the linear program solver
        noofstates = self.mdp["noofstates"]
        noofactions = self.mdp["noofactions"]
        vars = ["v" + str(i) for i in range(0, noofstates)]              ## creating the linear programs variables's names
        v = [pulp.LpVariable(i) for i in vars]                ## converting them into pulp variables
        v = np.array(v)                                     ## putting them into numpy array to make calculation easier later
        lpsolver += (-pulp.lpSum(v))                           ## the objective function

        for s in range(0, noofstates):
            for a in range(0, noofactions):
                lpsolver += v[s] >= pulp.lpSum(self.mdp["transitionfunc"][s][a]*(self.mdp["rewardfunc"][s][a] + self.mdp["discountfactor"]*v))

        lpsolver.solve(pulp.PULP_CBC_CMD(msg=False))        ## to make pulp print nothing on the terminal

        valfunc = []
        for i in range(0, noofstates):
            valfunc.append(pulp.value(v[i]))
        valfunc = np.array(valfunc)
        policy = np.sum(self.mdp["transitionfunc"]*(self.mdp["rewardfunc"] + self.mdp["discountfactor"] * valfunc), axis=2)
        policy = np.argmax(policy, axis = 1)
        return valfunc, policy

    ## function for howard policy iteration
    def howardpolicyiteration(self,):
        noofstates = self.mdp["noofstates"]
        noofactions = self.mdp["noofactions"]
        policy = np.random.randint(low=0, high=noofactions, size=noofstates)            ## random initialisation of actions for the states
        policydash = np.random.randint(low=0, high=noofactions, size=noofstates)
        valfunc = None
        while(True):
            valfunc = self.evalpolicy(policy, noofstates)       ## doing policy evaluation
            policydash = np.sum(self.mdp["transitionfunc"]*(self.mdp["rewardfunc"] + self.mdp["discountfactor"]*valfunc), axis=2)
            policydash = np.argmax(policydash, axis = 1)
            if np.array_equal(policydash, policy):
                break
            policy = policydash
        return valfunc, policydash

    ## function for evaluating given policy
    def evalpolicy(self, policy, noofstates):
        statearray = np.arange(noofstates)
        transitionfunc = self.mdp["transitionfunc"][statearray,policy]
        rewardfunc = self.mdp["rewardfunc"][statearray,policy]
        tr = np.sum(transitionfunc*rewardfunc, axis=1)
        tr = np.reshape(tr,(tr.shape[0],1))
        invmat = np.linalg.inv(np.identity(noofstates) - self.mdp["discountfactor"]*transitionfunc)
        v = np.matmul(invmat, tr)
        v = np.reshape(v,(v.shape[0]))
        return v

    ## function to print the output
    def printoutput(self,):
        for i in range(0,self.mdp["noofstates"]):
            print('{:.6f}'.format(round(self.valuefunc[i], 6))," ",self.policy[i])

if __name__ == "__main__":

    ## parsing args
    parser.add_argument("--mdp",type=str)
    parser.add_argument("--algorithm",type=str,default="vi")
    parser.add_argument("--policy",type=str)
    args = parser.parse_args()

    ## calling planner to solve
    planner(args.mdp, args.algorithm,args.policy)