import array
import struct
from contextlib import contextmanager
from typing import List, Tuple

from cuda import cudart
from cuda.cudart import cudaError_t

from .mapping import Mapping

def _raise_if_error(error: cudaError_t):
    if error != cudaError_t.cudaSuccess:
        raise RuntimeError(error)

@contextmanager
def peer_access(mapping: Mapping):
    set_peer_access(mapping, True)
    try:
        yield
    finally:
        set_peer_access(mapping, False)

def set_peer_access(mapping: Mapping, enabled: bool = True):
    src_node = mapping.rank
    for dest_node in mapping.tp_group:
        if dest_node == src_node:
            continue

        error, result = cudart.cudaDeviceCanAccessPeer(src_node, dest_node)
        _raise_if_error(error)

        if result == 0:
            raise RuntimeError(
                f"Can't enable access between nodes {src_node} and {dest_node}")

        if enabled:
            cudart.cudaDeviceEnablePeerAccess(dest_node, 0)
        else:
            cudart.cudaDeviceDisablePeerAccess(dest_node)
        error = cudart.cudaGetLastError()[0]
        if error not in [
                cudaError_t.cudaSuccess,
                cudaError_t.cudaErrorPeerAccessAlreadyEnabled,
                cudaError_t.cudaErrorPeerAccessNotEnabled
        ]:
            raise RuntimeError(error)

class IpcMemory():

    IPC_BUFFERS_SIZE = 50331648
    IPC_BARRIERS_SIZE_PER_GPU = 25 * 4  # Max all reduce blocks * sizeof(float)

    def __init__(self, mapping, size):
        self.mapping = mapping
        self.peer_ptrs, self.local_ptr = IpcMemory.open_ipc_memory(
            self.mapping, size, True)

    def __del__(self):
        IpcMemory.close_ipc_memory(self.mapping, self.peer_ptrs)

    def serialize(self) -> List[int]:
        buffer = bytes(0)
        for ptr in self.peer_ptrs:
            buffer += struct.pack("P", ptr)

        return array.array("Q", buffer).tolist()

    @staticmethod
    def open_ipc_memory(mapping: Mapping,
                        size: int,
                        set_to_zero: bool = False) -> Tuple[List[int], int]:
        """ Allocates a buffer with the given *size* on each GPU. Then, enables IPC communication between TP groups.
        Returns a list of buffer pointers, buffers[i] is a handle to the corresponding buffer residing on GPU #i.
        Call close_ipc_handle with the *buffer*.
        """
        from mpi4py import MPI
        comm = MPI.COMM_WORLD.Split(mapping.pp_rank, mapping.tp_rank)

        error, local_ptr = cudart.cudaMalloc(size)
        _raise_if_error(error)
        if set_to_zero:
            _raise_if_error(cudart.cudaMemset(local_ptr, 0, size)[0])
        error, local_handle = cudart.cudaIpcGetMemHandle(local_ptr)
        _raise_if_error(error)

        handles_reserved = comm.allgather(local_handle.reserved)
        handles = []
        for reserved in handles_reserved:
            handle = cudart.cudaIpcMemHandle_t()
            handle.reserved = reserved
            handles.append(handle)

        peer_ptrs = []
        for node, handle in enumerate(handles):
            if node == mapping.tp_rank:
                peer_ptrs.append(local_ptr)
            else:
                error, ptr = cudart.cudaIpcOpenMemHandle(
                    handle, cudart.cudaIpcMemLazyEnablePeerAccess)
                _raise_if_error(error)
                peer_ptrs.append(ptr)

        return peer_ptrs, local_ptr

    @staticmethod
    def close_ipc_memory(mapping: Mapping, peer_ptrs: List[int]):
        for node, ptr in enumerate(peer_ptrs):
            if node == mapping.tp_rank:
                _raise_if_error(cudart.cudaFree(ptr)[0])
            else:
                _raise_if_error(cudart.cudaIpcCloseMemHandle(ptr)[0])


import setuptools

with open("README.md") as fh:
    long_description = fh.read()

setuptools.setup(
    name="pysqueezebox",
    version="0.7.1",
    license="apache-2.0",
    author="Raj Laud",
    author_email="raj.laud@gmail.com",
    description="Asynchronous library to control Logitech Media Server",
    long_description=long_description,
    long_description_content_type="text/markdown",
    url="https://github.com/rajlaud/pysqueezebox",
    packages=setuptools.find_packages(),
    python_requires=">=3.6",
    install_requires=["aiohttp", "async-timeout"],
)


import functools
import pandas as pd
import numpy as np
import periodictable as pt
from pathlib import Path
from tinydb import TinyDB, Query
from .transform import formula_to_elemental
from ..util.meta import pyrolite_datafolder
from ..util.database import _list_tindyb_unique_values
import logging

logging.getLogger(__name__).addHandler(logging.NullHandler())
logger = logging.getLogger(__name__)

__dbpath__ = pyrolite_datafolder(subfolder="mineral") / "mindb.json"

@functools.lru_cache(maxsize=None)  # cache outputs for speed
def list_groups():
    """
    List the mineral groups present in the mineral database.

    Returns
    ----------
    :class:`list`
    """
    return _list_tindyb_unique_values("group", dbpath=__dbpath__)

@functools.lru_cache(maxsize=None)  # cache outputs for speed
def list_minerals():
    """
    List the minerals present in the mineral database.

    Returns
    ----------
    :class:`list`
    """
    return _list_tindyb_unique_values("name", dbpath=__dbpath__)

@functools.lru_cache(maxsize=None)  # cache outputs for speed
def list_formulae():
    """
    List the mineral formulae present in the mineral database.

    Returns
    ----------
    :class:`list`
    """
    return _list_tindyb_unique_values("formula", dbpath=__dbpath__)

def get_mineral(name="", dbpath=None):
    """
    Get a specific mineral from the database.

    Parameters
    ------------
    name : :class:`str`
        Name of the desired mineral.
    dbpath : :class:`pathlib.Path`, :class:`str`
        Optional overriding of the default database path.

    Returns
    --------
    :class:`pd.Series`
    """
    if dbpath is None:
        dbpath = __dbpath__

    assert name in list_minerals()
    with TinyDB(str(dbpath)) as db:
        out = db.get(Query().name == name)

    return pd.Series(out)

def parse_composition(composition, drop_zeros=True):
    """
    Parse a composition reference and return the composiiton as a :class:`~pandas.Series`

    Parameters
    -----------
    composition : :class:`str` | :class:`periodictable.formulas.Formula`
    """
    mnrl = None
    if composition in list_minerals():
        mnrl = get_mineral(composition)

    try:  # formulae
        form = pt.formula(composition)
        mnrl = pd.Series(formula_to_elemental(form))
        # could also check for formulae in the database, using f.atoms
    except:
        pass

    assert mnrl is not None
    if drop_zeros:
        mnrl = mnrl[mnrl != 0]
    return mnrl

def get_mineral_group(group=""):
    """
    Extract a mineral group from the database.

    Parameters
    -----------
    group : :class:`str`
        Group to extract from the mineral database.

    Returns
    ---------
    :class:`pandas.DataFrame`
        Dataframe of group members and compositions.
    """
    assert group in list_groups()
    with TinyDB(str(__dbpath__)) as db:
        grp = db.search(Query().group == group)

    df = pd.DataFrame(grp)
    meta, chem = (
        ["name", "formula"],
        [i for i in df.columns if i not in ["name", "formula", "group"]],
    )
    df = df.reindex(columns=meta + chem)
    df.loc[:, chem] = df.loc[:, chem].apply(pd.to_numeric)
    df = df.loc[:, (df != 0).any(axis=0)]  # remove zero-only columns
    return df

def update_database(path=None, **kwargs):
    """
    Update the mineral composition database.

    Parameters
    -----------
    path : :class:`str` | :class:`pathlib.Path`
        The desired filepath for the JSON database.

    Notes
    ------
    This will take the 'mins.csv' file from the mineral pyrolite data folder
    and construct a document-based JSON database.
    """
    mindf = pd.read_csv(pyrolite_datafolder(subfolder="mineral") / "mins.csv")
    mindf = mindf.reindex(
        columns=mindf.columns.tolist()
        + [str(a) for a in pt.formula(" ".join(mindf.formula.to_list())).atoms]
    )
    for ix in mindf.index:  # add elemental compositions
        el = parse_composition(pt.formula(mindf.loc[ix, "formula"]))
        mindf.loc[ix, el.index] = el

    mindf = mindf.fillna(0.0)

    if path is None:
        path = __dbpath__

    path = Path(path).with_suffix(".json")

    # name group formula composition
    with TinyDB(str(path)) as db:
        db.purge()
        for k, v in mindf.T.to_dict().items():
            db.insert(v)
        db.close()


from configs import ssd300 as cfg

import torch
import torchvision.transforms as transforms

def base_transform(size):
    transform = transforms.Compose([
        transforms.Resize(size),
        transforms.ToTensor()
    ])
    return transform

class BaseTransform:
    def __init__(self, size, mean):
        self.size = size

    def __call__(self, image, boxes=None, labels=None):
        return base_transform(self.size), boxes, labels

class VOCAnnotationTransform(object):
    """Transforms a VOC annotation into a Tensor of bbox coords and label index
    Initilized with a dictionary lookup of classnames to indexes
    Arguments:
        class_to_ind (dict, optional): dictionary lookup of classnames -> indexes
            (default: alphabetic indexing of VOC's 20 classes)
        keep_difficult (bool, optional): keep difficult instances or not
            (default: False)
        height (int): height
        width (int): width
    """

    def __init__(self, class_to_ind=None, keep_difficult=False):
        self.class_to_ind = class_to_ind or dict(
            zip(cfg.VOC_CLASSES, range(len(cfg.VOC_CLASSES))))
        self.keep_difficult = keep_difficult

    def __call__(self, target, width, height):
        """
        Arguments:
            target (annotation) : the target annotation to be made usable
                will be an ET.Element
        Returns:
            a list containing lists of bounding boxes  [bbox coords, class name]
        """
        res = []
        for obj in target.iter('object'):
            difficult = int(obj.find('difficult').text) == 1
            if not self.keep_difficult and difficult:
                continue
            name = obj.find('name').text.lower().strip()
            bbox = obj.find('bndbox')

            pts = ['xmin', 'ymin', 'xmax', 'ymax']
            bndbox = []
            for i, pt in enumerate(pts):
                cur_pt = int(bbox.find(pt).text) - 1
                # scale height or width
                cur_pt = cur_pt / width if i % 2 == 0 else cur_pt / height
                bndbox.append(cur_pt)
            label_idx = self.class_to_ind[name]
            bndbox.append(label_idx)
            res += [bndbox]  # [xmin, ymin, xmax, ymax, label_ind]
            # img_id = target.find('filename').text[:-4]

        return res  # [[xmin, ymin, xmax, ymax, label_ind], ... ]


from __future__ import absolute_import, division, print_function, unicode_literals

import uuid
from contextlib import contextmanager

from pants.backend.codegen.thrift.java.java_thrift_library import JavaThriftLibrary
from pants.backend.codegen.thrift.java.thrift_defaults import ThriftDefaults
from pants.build_graph.target import Target
from pants_test.test_base import TestBase

class TestThriftDefaults(TestBase):
  def create_thrift_defaults(self, **options):
    self.context(for_subsystems=[ThriftDefaults], options={
      ThriftDefaults.options_scope: options
    })
    return ThriftDefaults.global_instance()

  @contextmanager
  def invalid_fixtures(self):
    target = self.make_target(spec='not_java_thift_library_{}'.format(uuid.uuid4()),
                              target_type=Target)
    thrift_defaults = self.create_thrift_defaults()
    with self.assertRaises(ValueError):
      yield thrift_defaults, target

  def test_compiler_invalid(self):
    with self.invalid_fixtures() as (thrift_defaults, target):
      thrift_defaults.compiler(target)

  def test_language_invalid(self):
    with self.invalid_fixtures() as (thrift_defaults, target):
      thrift_defaults.language(target)

  def create_thrift_library(self, **kwargs):
    return self.make_target(spec='java_thift_library_{}'.format(uuid.uuid4()),
                            target_type=JavaThriftLibrary,
                            **kwargs)

  def test_compiler(self):
    thrift_defaults = self.create_thrift_defaults(compiler='thrift')
    self.assertEqual('thrift', thrift_defaults.compiler(self.create_thrift_library()))
    self.assertEqual('scrooge',
                     thrift_defaults.compiler(self.create_thrift_library(compiler='scrooge')))

  def test_language(self):
    thrift_defaults = self.create_thrift_defaults(language='java')
    self.assertEqual('java', thrift_defaults.language(self.create_thrift_library()))
    self.assertEqual('scala',
                     thrift_defaults.language(self.create_thrift_library(language='scala')))


from django.http import HttpResponse
from django.shortcuts import render
from config import settings
#from email.message import EmailMessage

from django.core.mail import EmailMessage
# Create your views here.

def home(request):
    return render(request,"index.html")

def send_email(request):
    if request.method=='POST':
        name=request.POST['name']
        sender_email=request.POST['email']
        msg=request.POST['msg']
        phone=request.POST['phone']

        email=EmailMessage(
            f'Xabar qoldiruvchi: {sender_email}',
            f'Ismi: {name}\nXabari: {msg}\nTel raqami: {phone}',
            settings.EMAIL_HOST_USER,
            [sender_email]
        )
        email.fail_silently=True
        email.send()
        return HttpResponse("Muvaffaqiyatli jo'natildi")
    else:
        return HttpResponse("Jo'natilmadi")


import os, glob, math
import numpy as np
import tensorflow as tf
from PIL import Image

from myutils_tf import bwutils

def save_4ch_to_3ch(path_pixel_shift):
    print(path_pixel_shift)

    files = glob.glob(os.path.join(path_pixel_shift, '*.npy'))
    # print(files)
    for idx, file in enumerate(files):
        if '3ch' not in file:
            arr = np.load(file)
            arr_3ch = arr[:,:,(0,1,3)]
            file_new = file[:-4] + '_3ch.npy'
            np.save(file_new, arr_3ch)

def get_model(model_name, model_sig):
    base_path = os.path.join('model_dir', 'checkpoint')
    structure_path = os.path.join(base_path, model_name + '_model_structure.h5')
    ckpt_path = os.path.join(base_path, model_name + '_' + model_sig)
    print(structure_path, '\n', ckpt_path)

    # load model structure
    model = tf.keras.models.load_model(structure_path)

    # find latest weights and load
    ckpts = glob.glob(os.path.join(ckpt_path, '*.h5'))
    ckpts.sort()
    ckpt = ckpts[-1]

    model.load_weights(ckpt)

    # print(ckpt)
    # model.summary()
    return model

def normalize1_and_gamma(arr, bits=16, beta=1/2.2):
    arr = arr / (2**bits -1) # (0, 1)
    arr = arr ** beta   # (0, 1)
    return arr

def main():
    # model name
    model_name = 'unetv2'
    model_name = 'unet'

    # model sig
    model_sig = 'noise3'

    # get model
    model = get_model(model_name, model_sig)

    # test data
    PATH_PIXELSHIFT = 'C:/Users/AI38/datasets/pixelshfit/PixelShift200_test'
    files = glob.glob(os.path.join(PATH_PIXELSHIFT, '*_3ch.npy'))

    pad_size = 32
    patch_size = 128
    # shape = np.load(files[0]).shape
    # height, width, channels = np.load(files[0]).shape
    # npatches_y, npatches_x = math.ceil(shape[0]/patch_size), math.ceil(shape[1]/patch_size)
    # print(arr_pred.shape)
    for idx, file in enumerate(files):
        arr = np.load(file)    # (0, 65535)
        # arr = arr / (2**16 -1) # (0, 1)
        # arr = arr ** (1/2.2)   # (0, 1)
        arr = normalize1_and_gamma(arr)
        img_arr = Image.fromarray(  (arr*255).astype(np.uint8) )
        img_arr.save(os.path.join(PATH_PIXELSHIFT, f'inf_ref_%02d.png'%(idx+1)))

        print('arr.shape', arr.shape)
        arr = np.pad(arr, ((pad_size, pad_size), (pad_size, pad_size),(0, 0)), 'symmetric')
        print('arr.shape', arr.shape)

        height, width, channels = arr.shape
        npatches_y = math.ceil((height+2*pad_size) / (patch_size-2*pad_size))
        npatches_x = math.ceil((width +2*pad_size) / (patch_size-2*pad_size))

        arr_pred = np.zeros_like(arr)
        print(idx, file, arr.shape, arr_pred.shape)
        # exit()
        cnt=0
        tcnt= npatches_x*npatches_y
        for idx_y in range(npatches_y):
            for idx_x  in range(npatches_x):
                if(cnt%10==0):
                    print(f'{cnt} / {tcnt}')
                cnt+=1
                sy = idx_y * (patch_size-2*pad_size)
                ey = sy + patch_size
                sx = idx_x * (patch_size-2*pad_size)
                ex = sx + patch_size

                if ey >= height:
                    ey = height-1
                    sy = height-patch_size-1

                if ex >= width:
                    ex = width-1
                    sx = width-patch_size-1

                arr_patch = arr[sy:ey, sx:ex,:]

                print(np.amin(arr_patch), np.amax(arr_patch) )

                # pre-process
                arr_patch = arr_patch**(1/2.2)
                arr_patch = (arr_patch*2) -1  # (0, 1) -> (-1, 1)

                # prediction
                pred = model.predict(arr_patch[np.newaxis,...])
                print(pred.shape)

                # post-process
                arr_pred[sy+pad_size:ey-pad_size, sx+pad_size:ex-pad_size, :] = \
                             (pred[0, pad_size:-pad_size, pad_size:-pad_size, :]+1)/2 #  (-1, 1) -> (0, 1)
                # print(np.amin(arr_patch), np.amax(arr_patch), np.amin(arr_pred), np.amax(arr_pred))
                # exit()

        # arr_pred.astype(np.uint8)
        arr_pred = arr_pred[pad_size:-pad_size, pad_size:-pad_size, :]
        img_pred = Image.fromarray((arr_pred*255).astype(np.uint8))
        # name = os.path.join(PATH_PIXELSHIFT, f'inf_{model_name}_{model_sig}_%02d.png'%(idx+1))
        name = os.path.join(PATH_PIXELSHIFT, f'inf_{model_name}_{model_sig}_%02d_gamma.png'%(idx+1))
        img_pred.save(name)
        print(np.amin(img_pred), np.amax(img_pred), np.amin(arr_pred.astype(np.uint8)), np.amax(arr_pred.astype(np.uint8)))

        exit()

if __name__ == '__main__':
    main()


import os
import helper, wiredtiger, wttest
from wtscenario import make_scenarios

# test_prefetch01.py
#    Test basic functionality of the prefetch configuration.

class test_prefetch01(wttest.WiredTigerTestCase):
    new_dir = 'new.dir'

    conn_avail = [
        ('available', dict(available=True)),
        ('not-available', dict(available=False))
    ]

    conn_default = [
        ('default-off', dict(default=True)),
        ('default-on', dict(default=False)),
    ]

    session_cfg = [
        ('no-config', dict(scenario='no-config', enabled=False, has_config=False)),
        ('enabled', dict(scenario='enabled', enabled=True, has_config=True)),
        ('not-enabled', dict(scenario='not-enabled', enabled=False, has_config=True)),
    ]

    scenarios = make_scenarios(conn_avail, conn_default, session_cfg)

    def test_prefetch_config(self):
        conn_cfg = 'prefetch=(available=%s,default=%s)' % (str(self.available).lower(), str(self.default).lower())
        session_cfg = ''
        msg = '/pre-fetching cannot be enabled/'

        if self.has_config:
            session_cfg = 'prefetch=(enabled=%s)' % (str(self.enabled).lower())

        os.mkdir(self.new_dir)
        helper.copy_wiredtiger_home(self, '.', self.new_dir)

        if not self.available and self.default:
            # Test that we can't enable a connection's sessions to have pre-fetching when
            # pre-fetching is configured as unavailable.
            self.assertRaisesWithMessage(wiredtiger.WiredTigerError,
                lambda: self.wiredtiger_open(self.new_dir, conn_cfg), msg)
        elif not self.available and self.enabled:
            # Test that we can't enable a specific session to have pre-fetching turned on
            # if pre-fetching is configured as unavailable.
            new_conn = self.wiredtiger_open(self.new_dir, conn_cfg)
            self.assertRaisesWithMessage(wiredtiger.WiredTigerError,
                lambda: new_conn.open_session(session_cfg), msg)
        else:
            new_conn = self.wiredtiger_open(self.new_dir, conn_cfg)
            new_session = new_conn.open_session(session_cfg)
            self.assertEqual(new_session.close(), 0)

if __name__ == '__main__':
    wttest.run()


import argparse
import os
from glob import glob
import json
import jellyfish
from text_extraction import Rectangle, AUTHOR_LABEL, DESCRIPTION_LABEL
import re
import pandas as pd
from tqdm import tqdm

ap = argparse.ArgumentParser()
ap.add_argument("-i", "--input-folder", required=True, help="Folder with the json file")
ap.add_argument("-o", "--output-folder", required=True, help="Folder with the saved corrected json files")
args = ap.parse_args()

INPUT_FOLDER = args.input_folder
OUTPUT_FOLDER = args.output_folder

input_elements = sorted([os.path.basename(f) for f in glob(os.path.join(OUTPUT_FOLDER, '*.json'))])

def get_transcription(basename, groundtruth: bool):
    saved_file = os.path.join(OUTPUT_FOLDER, basename)
    if groundtruth:
        with open(saved_file, 'r') as f:
            return json.load(f)
    else:
        input_file = os.path.join(INPUT_FOLDER, basename)
        rects = Rectangle.load_from_json(input_file)
        return {
            AUTHOR_LABEL: next((r.text for r in rects if r.label == AUTHOR_LABEL), ''),
            DESCRIPTION_LABEL: next((r.text for r in rects if r.label == DESCRIPTION_LABEL), '')
        }

def normalized_str(s):
    s = s.lower()
    s = re.sub(r"[,;\-\.\n\(\)']", ' ', s)
    s = re.sub(' +', ' ', s)
    return s.strip()

results = []
for basename in tqdm(input_elements):
    gt_transcription = get_transcription(basename, groundtruth=True)
    input_transcription = get_transcription(basename, groundtruth=False)
    gt_author, gt_description = gt_transcription[AUTHOR_LABEL], gt_transcription[DESCRIPTION_LABEL]
    extracted_author, extracted_description = input_transcription[AUTHOR_LABEL], input_transcription[DESCRIPTION_LABEL]
    # print(gt_author, gt_description, extracted_author, extracted_description)
    try:
        results.append({
            'basename': basename,
            'author_error': jellyfish.damerau_levenshtein_distance(gt_author, extracted_author),
            'description_error': jellyfish.damerau_levenshtein_distance(gt_description, extracted_description),
            'author_len': len(gt_author),
            'description_len': len(gt_description),
            'author_error_normalized': jellyfish.damerau_levenshtein_distance(normalized_str(gt_author),
                                                                              normalized_str(extracted_author)),
            'description_error_normalized': jellyfish.damerau_levenshtein_distance(normalized_str(gt_description),
                                                                                normalized_str(
                                                                                extracted_description))
        })
        if jellyfish.damerau_levenshtein_distance(normalized_str(gt_author), normalized_str(extracted_author))>0:
            print(gt_author, extracted_author)
    except Exception:
        print(basename)

df = pd.DataFrame.from_records(results)

print('CER (author) : {:.2f}'.format(100 * df.author_error.sum() / df.author_len.sum()))
print('CER (description) : {:.2f}'.format(100 * df.description_error.sum() / df.description_len.sum()))
print('CER (author, normalized) : {:.2f}'.format(100 * df.author_error_normalized.sum() / df.author_len.sum()))
print('CER (description, normalized) : {:.2f}'.format(
    100 * df.description_error_normalized.sum() / df.description_len.sum()))

print('Perfect transcription (author) : {:.2f}'.format(100 * (df.author_error == 0).sum() / len(df)))
print('Perfect transcription (description) : {:.2f}'.format(100 * (df.description_error == 0).sum() / len(df)))
print('Perfect transcription (author, normalized) : {:.2f}'.format(
    100 * (df.author_error_normalized == 0).sum() / len(df)))
print('Perfect transcription (description, normalized) : {:.2f}'.format(
    100 * (df.description_error_normalized == 0).sum() / len(df)))

print('1-away transcription (author) : {:.2f}'.format(100 * (df.author_error <= 1).sum() / len(df)))
print('1-away  transcription (description) : {:.2f}'.format(100 * (df.description_error <= 1).sum() / len(df)))
print('1-away  transcription (author, normalized) : {:.2f}'.format(
    100 * (df.author_error_normalized <= 1).sum() / len(df)))
print('1-away  transcription (description, normalized) : {:.2f}'.format(
    100 * (df.description_error_normalized <= 1).sum() / len(df)))


from django.urls import path
from . import views

app_name = 'base'

urlpatterns = [
    path('home/', views.landing_page, name='home'),
    path('school_registered/', views.school_list_page, name='school_registered'),
    path('contact_us/', views.contact_us_page, name='contact_us'),

]


import firebase_admin
from firebase_admin import credentials, firestore
import os
from gcloud import storage
from pprint import pprint
from datetime import datetime
import ast

from django import template

INDEX = 1
INDEX_historic = 1
INDEX_cv = 1
# Setup the connexion to the project
cred = credentials.Certificate("./website/serviceAccountKey.json")
#cred = credentials.Certificate("serviceAccountKey.json")
firebase_admin.initialize_app(cred)

db = firestore.client()

os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = r'./website/serviceAccountKey.json'
#os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = r'serviceAccountKey.json'

storage_client = storage.Client()

def increment_index_historic():
    """Fonction qui incrémente la variable globale INDEX_historic
        nécessaire pour l'unicité de notre historique dans la base de donnée"""

    global INDEX_historic
    INDEX_historic += 1
    return INDEX_historic

def increment_index():
    """Fonction qui incrémente la variable globale INDEX
        nécessaire pour l'unicité de notre fiche de poste dans la base de donnée"""
    global INDEX
    INDEX += 1
    return INDEX

def increment_index_cv():
    """Fonction qui incrémente la variable globale INDEX_historic
        nécessaire pour l'unicité de notre historique dans la base de donnée"""

    global INDEX_cv
    INDEX_cv += 1
    return INDEX_cv

def add_CV(name_hr,url_desc,file,name,date,lieu, dict_infos):
    global INDEX_historic
    #date = datetime.today().strftime('%Y-%m-%d')
    #name_file = "gs://snipehr_historic/"

    #dict_infos={"email":"norayda.nsiemo@gmail.com","phone":"+33768373205","skills":["Python","R","DevOps","MongoDB","documentation","flux","Python","R","Java","Jenkins","Airflow","Docker","Google","MySQL","MongoDB","Firebase","Tableau","documentation","flux"]}
    index_job =url_desc.split("/")[-1].split('.')[0]
    name_file = name_hr + "_" + index_job + "_" + str(INDEX_cv)
    increment_index_cv()

    #my_bucket = storage_client.get_bucket("snipehr_cvs")
    #pprint(vars(my_bucket))
    #blob = my_bucket.blob(name_file)
    #blob.upload_from_filename(file)
    #blob.upload_from_filename(file)

    db = firestore.client()
    new_cv={
        'name': name,
        'lieu' :lieu,
        'email': dict_infos['email'],
        'phone': dict_infos['phone'],
        'date' : date,
        'status': False,
        'url_resume': "gs://snipehr_cvs/" + name_file,
        'skills':dict_infos['skills']
    }
    #print(name_hr)
    db.collection('hrs').document(read_hr(name_hr).id).collection('resumes').add(new_cv)

def read_file_as_file(uri,name,date,poste):
    """Fonction qui lit la fiche de poste stocker dans le cloud storage à partir de l'URI """
    destination = "resumes/"+name+"_"+poste+"_"+date+'.pdf'
    blob=""
    if(uri != None):
        bucket = storage_client.get_bucket(uri.split("/")[-2])
        blob = bucket.blob(uri.split("/")[-1])
        blob = blob.download_to_filename(destination)
        #blob = blob.decode('utf-8')
    return blob

def read_file(uri):
    """Fonction qui lit la fiche de poste stocker dans le cloud storage à partir de l'URI """
    blob=""
    if(uri != None):
        bucket = storage_client.get_bucket(uri.split("/")[-2])

        blob = bucket.blob(uri.split("/")[-1])
        blob = blob.download_as_string()
        blob = blob.decode('utf-8')
    return blob

def liste_historic(name_hr,url_desc):
    """Fonction qui retourne la liste des historic pour une fiche de poste donnée"""
    liste =[]
    index_job =url_desc.split("/")[-1].split('.')[0]
    name_file = name_hr + "_" + index_job
    my_bucket = storage_client.get_bucket("snipehr_historic")

    blobs_all = list(my_bucket.list_blobs(prefix=name_file)) #récupère les fiches dont le nom du RH =name_hr et le job concerné à l'index du job en paramètre
    print(blobs_all)
    for blob in blobs_all:
        blob = blob.download_as_string()
        blob = blob.decode('utf-8')
        liste.append(ast.literal_eval(blob))
    return liste

def add_historic(name_hr, commentaire, url_desc):
    """Fonction qui ajoute un historique à une fiche de poste donnée"""
    global INDEX_historic
    date = datetime.today().strftime('%Y-%m-%d')
    #name_file = "gs://snipehr_historic/"
    index_job =url_desc.split("/")[-1].split('.')[0] #exemple dans l'URI gs://snipehr_job_desc/1.txt ça récupèrera 1
    my_bucket = storage_client.get_bucket("snipehr_historic")
    #pprint(vars(my_bucket))
    print(index_job)
    name = name_hr + "_" + index_job + "_" + str(INDEX_historic)+".txt"
    increment_index_historic()
    #text_file = open(name, "w")
    #n = text_file.write(commentaire)
    #text_file.close()

    historic =str({"date":date,"commentaire":commentaire})
    blob = my_bucket.blob(name)
    blob.upload_from_string(historic)

    print(blob)

def get_nb_missions_affectees(liste_jobs):
    """Fonction qui renvoie le nombre exacte de missions affecté à partir de la liste des jobs lié au profil"""
    nb=0
    for job in liste_jobs:
        if(job["status"]):
            nb+=1
    return nb

def set_status(name_hr,job_to_set):
    """Fonction qui met à jour le status d'une mission"""
    job =get_job(name_hr,job_to_set)
    print(job)
    print(job.to_dict()["status"])
    hr=read_hr(name_hr)
    status = job.to_dict()["status"]
    db.collection('hrs').document(hr.id).collection('job_description').document(job.id).update({"status": not status})

def read_company(name_hr):
    """Fonction qui retourne le nom de la compagnie du RH connecté"""
    hr=read_hr(name_hr)
    return hr.to_dict()["company"]

def chiffrement_message(message,clef):
    return None

def dechiffrement_message(message,clef):
    return None

def create_message(name_hr,message,nom,post):
    """Fonction qui crée et chiffre le message dans la base de donnée"""
    db = firestore.client()
    date = datetime.today().strftime('%Y-%m-%d')
    new_message={
        'date': f'{date}',
        'message': f'{message}',
        'candidat':f'{nom}',
        'post':f'{post}'
    }
    db.collection('hrs').document(read_hr(name_hr).id).collection('messages').add(new_message)

    return None

def create_job_desc(titre,lieu, date, competences, fiche, name_hr):
    global INDEX
    """Fonction qui ajoute une fiche de poste dans la base de donée"""
    url_desc="gs://snipehr_job_desc/"
    url_historic="gs://snipehr_historic/"
    lieu =lieu
    my_bucket = storage_client.get_bucket("snipehr_job_desc")
    #pprint(vars(my_bucket))
    name = str(INDEX)+".txt"
    increment_index()
    #text_file = open(name, "w")
    #n = text_file.write(fiche)
    #text_file.close()
    blob = my_bucket.blob(name)
    blob.upload_from_string(fiche)

    url_desc+=name
    db = firestore.client()
    new_job_desc={
        'titre': f'{titre}',
        'lieu' :f'{lieu}',
        'date': f'{date}',
        'status': False,
        'url_desc': f'{url_desc}',
        'url_historic': f'{url_historic}',
        'skills':f'{competences}'
    }
    #print(name_hr)
    db.collection('hrs').document(read_hr(name_hr).id).collection('job_description').add(new_job_desc)

def create_hr(name_hr, email_hr, mdp_hr, company_hr):
    """Fonction qui ajoute un RH à notre base de donée """
    db = firestore.client()
    # A voir pour ajouter le doc avec un id auto généré
    new_hr = {
        'name': f'{name_hr}',
        'email': f'{email_hr}',
        'mdp': f'{mdp_hr}',
        'company': f'{company_hr}'
    }

    db.collection('hrs').add(new_hr)
    db.collection('hrs').document(read_hr(name_hr).id).collections('job_description')

def set_hr(past_name,name_hr, email_hr, company_hr):
    db = firestore.client()
    new_hr = {
        'name': f'{name_hr}',
        'email': f'{email_hr}',
        'company': f'{company_hr}'
    }
    hr=read_hr(past_name)
    db.collection('hrs').document(hr.id).update(new_hr)

def get_job(name_hr,job_to_set):
    """Fonction qui nous permet d'avoir l'ID d'une jfiche de description"""
    col_jobs = db.collection('hrs').document(read_hr(name_hr).id).collection('job_description')
    jobs = col_jobs.stream()
    dictfilt = lambda x, y: dict([(i, x[i]) for i in x if i in set(y)])

    for job in jobs:
        print(dictfilt(job.to_dict(),("url_desc","date")))
        print(dictfilt(job_to_set,("url_desc","date")))
        #print(dictfilt(job.to_dict(),("date","titre","url_desc","url_historic")))
        if dictfilt(job_to_set,("url_desc","date")) == dictfilt(job.to_dict(),("url_desc","date")):
            return job

def read_hr(name_hr):
    """fonction qui nous perme d'avoir l'ID du RH à partir du nom"""
    # Only get 1 document or hrs
    col_hrs = db.collection('hrs').where("name", '==', f'{name_hr}')
    hrs = col_hrs.stream()

    for hr in hrs:
        #print(f'{hr.id} => {hr.to_dict()}')
        return hr

def read_hrs():
    """Fonction qui nous permet d'avoir la liste des RHs"""
    # Get the hole hrs collection
    col_hrs = db.collection('hrs')
    hrs = col_hrs.stream()
    for hr in hrs:
        print(f'{hr.id} => {hr.to_dict()}')

def test(email_hr, mdp_hr):
    hr = db.collection('hrs').where("email", '==', f'{email_hr}').where("mdp", '==', f'{mdp_hr}').get()
    print(hr)
    for h in hr:
        print(f'{h.id} => {h.to_dict()}')

def read_jobs(name_hr):
    """Fonction qui retourne la liste des fiches de poste associé à un RH"""
    collections = db.collection('hrs').document(read_hr(name_hr).id).collection("job_description").stream()
    list_jobs = []
    for collection in collections:
        list_jobs.append(collection.to_dict())
    return list_jobs

def read_resumes(name_hr):
    """Fonction qui retourne la liste des fiches de poste associé à un RH"""
    collections = db.collection('hrs').document(read_hr(name_hr).id).collection("resumes").stream()
    list_resumes = []
    for collection in collections:
        list_resumes.append(collection.to_dict())
    return list_resumes

def read_messages(name_hr):
    """Fonction qui retourne la liste des fiches de poste associé à un RH"""
    messages = db.collection('hrs').document(read_hr(name_hr).id).collection('messages').stream()
    list_messages = []
    i=1
    message_dict ={}
    for message in messages:
        message_dict=message.to_dict()
        message_dict['index']=i
        i+=1
        list_messages.append(message_dict)
    return list_messages

def get_job_title(name_hr,url_resume):
    titre =""
    url_desc = "gs://snipehr_job_desc/" + url_resume.split("/")[-1].split("_")[-2] +'.txt'
    jobs = read_jobs(name_hr)
    for job in jobs:
        if (job["url_desc"]==url_desc):
            titre=job["titre"]
    return titre

if __name__ == '__main__':
    #create_hr('Khalida', 'test@gmail.fr', 'azerty', 'ESGI')
    #read_hr('Test')
    #test('test@test.fr', 'test')
    #jobs = read_job(read_hr("Test"))
    #print(jobs)

    #titre=""
    #date=""
    #status= True
    #url_desc=""
    #url_historic =""
    #create_job_desc(titre, date, status, url_desc, url_historic, read_hr("Khalida"))
    name_hr ="Test"
    #job_to_set = {'date': '2022-08-25', 'titre': 'Data Analyst', 'url_desc': '', 'url_historic': ''}
    #print(get_job(name_hr,{'titre': 'Data', 'date': '2022-11-10', 'url_desc': 'gs://snipehr_job_desc/1.txt', 'url_historic': 'gs://snipehr_job_desc/'}).to_dict()["status"])
    #set_status(name_hr, job_to_set)
    #print(get_job(name_hr,job_to_set).to_dict()["status"])

    #print(read_job(read_hr("Test"))["jobs"])
    #set_status("Test",{'status': False, 'date': '2022-08-25', 'titre': 'Data Analyst', 'url_desc': '', 'url_historic': ''})

    #read_file("gs://snipehr_job_desc/1.txt")
    commentaire ="Test des commentaires"
    url_desc = "gs://snipehr_job_desc/1.txt"
    #add_historic(name_hr, commentaire, url_desc)
    #add_historic(name_hr, commentaire, url_desc)
    #print(liste_historic(name_hr, url_desc))

    #print(get_nb_missions_affectees(read_jobs(name_hr)))
    #add_CV(name_hr,url_desc,"CVNorayda_NSIEMO.pdf","Norayda NSIEMO","2022-09-23","Paris", dict())

    #read_file_as_file("gs://snipehr_cvs/Test_1_1","Norayda NSIEMO","2022-09-23","Data Engineer")


"""
Support for random optimizers, including the random-greedy path.
"""

import functools
import heapq
import math
import numbers
import time
from collections import deque
from random import choices as random_choices
from random import seed as random_seed
from typing import Any, Dict, Generator, Iterable, List, Optional, Tuple

from . import helpers, paths
from .typing import ArrayIndexType, ArrayType, PathType

__all__ = ["RandomGreedy", "random_greedy", "random_greedy_128"]

class RandomOptimizer(paths.PathOptimizer):
    """Base class for running any random path finder that benefits
    from repeated calling, possibly in a parallel fashion. Custom random
    optimizers should subclass this, and the `setup` method should be
    implemented with the following signature:

    ```python
    def setup(self, inputs, output, size_dict):
        # custom preparation here ...
        return trial_fn, trial_args
    ```

    Where `trial_fn` itself should have the signature::

    ```python
    def trial_fn(r, *trial_args):
        # custom computation of path here
        return ssa_path, cost, size
    ```

    Where `r` is the run number and could for example be used to seed a
    random number generator. See `RandomGreedy` for an example.

    **Parameters:**

    - **max_repeats** - *(int, optional)* The maximum number of repeat trials to have.
    - **max_time** - *(float, optional)* The maximum amount of time to run the algorithm for.
    - **minimize** - *({'flops', 'size'}, optional)* Whether to favour paths that minimize the total estimated flop-count or
        the size of the largest intermediate created.
    - **parallel** - *({bool, int, or executor-pool like}, optional)* Whether to parallelize the random trials, by default `False`. If
        `True`, use a `concurrent.futures.ProcessPoolExecutor` with the same
        number of processes as cores. If an integer is specified, use that many
        processes instead. Finally, you can supply a custom executor-pool which
        should have an API matching that of the python 3 standard library
        module `concurrent.futures`. Namely, a `submit` method that returns
        `Future` objects, themselves with `result` and `cancel` methods.
    - **pre_dispatch** - *(int, optional)* If running in parallel, how many jobs to pre-dispatch so as to avoid
        submitting all jobs at once. Should also be more than twice the number
        of workers to avoid under-subscription. Default: 128.

    **Attributes:**

    - **path** - *(list[tuple[int]])* The best path found so far.
    - **costs** - *(list[int])* The list of each trial's costs found so far.
    - **sizes** - *(list[int])* The list of each trial's largest intermediate size so far.
    """

    def __init__(
        self,
        max_repeats: int = 32,
        max_time: Optional[float] = None,
        minimize: str = "flops",
        parallel: bool = False,
        pre_dispatch: int = 128,
    ):

        if minimize not in ("flops", "size"):
            raise ValueError("`minimize` should be one of {'flops', 'size'}.")

        self.max_repeats = max_repeats
        self.max_time = max_time
        self.minimize = minimize
        self.better = paths.get_better_fn(minimize)
        self._parallel = False
        self.parallel = parallel
        self.pre_dispatch = pre_dispatch

        self.costs: List[int] = []
        self.sizes: List[int] = []
        self.best: Dict[str, Any] = {"flops": float("inf"), "size": float("inf")}

        self._repeats_start = 0
        self._executor: Any
        self._futures: Any

    @property
    def path(self) -> PathType:
        """The best path found so far."""
        return paths.ssa_to_linear(self.best["ssa_path"])

    @property
    def parallel(self) -> bool:
        return self._parallel

    @parallel.setter
    def parallel(self, parallel: bool) -> None:
        # shutdown any previous executor if we are managing it
        if getattr(self, "_managing_executor", False):
            self._executor.shutdown()

        self._parallel = parallel
        self._managing_executor = False

        if parallel is False:
            self._executor = None
            return

        if parallel is True:
            from concurrent.futures import ProcessPoolExecutor

            self._executor = ProcessPoolExecutor()
            self._managing_executor = True
            return

        if isinstance(parallel, numbers.Number):
            from concurrent.futures import ProcessPoolExecutor

            self._executor = ProcessPoolExecutor(parallel)
            self._managing_executor = True
            return

        # assume a pool-executor has been supplied
        self._executor = parallel

    def _gen_results_parallel(self, repeats: Iterable[int], trial_fn: Any, args: Any) -> Generator[Any, None, None]:
        """Lazily generate results from an executor without submitting all jobs at once."""
        self._futures = deque()

        # the idea here is to submit at least ``pre_dispatch`` jobs *before* we
        # yield any results, then do both in tandem, before draining the queue
        for r in repeats:
            if len(self._futures) < self.pre_dispatch:
                self._futures.append(self._executor.submit(trial_fn, r, *args))
                continue
            yield self._futures.popleft().result()

        while self._futures:
            yield self._futures.popleft().result()

    def _cancel_futures(self) -> None:
        if self._executor is not None:
            for f in self._futures:
                f.cancel()

    def setup(
        self,
        inputs: List[ArrayIndexType],
        output: ArrayIndexType,
        size_dict: Dict[str, int],
    ) -> Tuple[Any, Any]:
        raise NotImplementedError

    def __call__(
        self,
        inputs: List[ArrayIndexType],
        output: ArrayIndexType,
        size_dict: Dict[str, int],
        memory_limit: Optional[int] = None,
    ) -> PathType:
        self._check_args_against_first_call(inputs, output, size_dict)

        # start a timer?
        if self.max_time is not None:
            t0 = time.time()

        trial_fn, trial_args = self.setup(inputs, output, size_dict)

        r_start = self._repeats_start + len(self.costs)
        r_stop = r_start + self.max_repeats
        repeats = range(r_start, r_stop)

        # create the trials lazily
        if self._executor is not None:
            trials = self._gen_results_parallel(repeats, trial_fn, trial_args)
        else:
            trials = (trial_fn(r, *trial_args) for r in repeats)

        # assess the trials
        for ssa_path, cost, size in trials:

            # keep track of all costs and sizes
            self.costs.append(cost)
            self.sizes.append(size)

            # check if we have found a new best
            found_new_best = self.better(cost, size, self.best["flops"], self.best["size"])

            if found_new_best:
                self.best["flops"] = cost
                self.best["size"] = size
                self.best["ssa_path"] = ssa_path

            # check if we have run out of time
            if (self.max_time is not None) and (time.time() > t0 + self.max_time):
                break

        self._cancel_futures()
        return self.path

    def __del__(self):
        # if we created the parallel pool-executor, shut it down
        if getattr(self, "_managing_executor", False):
            self._executor.shutdown()

def thermal_chooser(queue, remaining, nbranch=8, temperature=1, rel_temperature=True):
    """A contraction 'chooser' that weights possible contractions using a
    Boltzmann distribution. Explicitly, given costs `c_i` (with `c_0` the
    smallest), the relative weights, `w_i`, are computed as:

        $$w_i = exp( -(c_i - c_0) / temperature)$$

    Additionally, if `rel_temperature` is set, scale `temperature` by
    `abs(c_0)` to account for likely fluctuating cost magnitudes during the
    course of a contraction.

    **Parameters:**

    - **queue** - *(list)* The heapified list of candidate contractions.
    - **remaining** - *(dict[str, int])* Mapping of remaining inputs' indices to the ssa id.
    - **temperature** - *(float, optional)* When choosing a possible contraction, its relative probability will be
        proportional to `exp(-cost / temperature)`. Thus the larger
        `temperature` is, the further random paths will stray from the normal
        'greedy' path. Conversely, if set to zero, only paths with exactly the
        same cost as the best at each step will be explored.
    - **rel_temperature** - *(bool, optional)* Whether to normalize the `temperature` at each step to the scale of
        the best cost. This is generally beneficial as the magnitude of costs
        can vary significantly throughout a contraction.
    - **nbranch** - *(int, optional)* How many potential paths to calculate probability for and choose from at each step.

    **Returns:**

    - **cost**
    - **k1**
    - **k2**
    - **k3**
    """
    n = 0
    choices = []
    while queue and n < nbranch:
        cost, k1, k2, k12 = heapq.heappop(queue)
        if k1 not in remaining or k2 not in remaining:
            continue  # candidate is obsolete
        choices.append((cost, k1, k2, k12))
        n += 1

    if n == 0:
        return None
    if n == 1:
        return choices[0]

    costs = [choice[0][0] for choice in choices]
    cmin = costs[0]

    # adjust by the overall scale to account for fluctuating absolute costs
    if rel_temperature:
        temperature *= max(1, abs(cmin))

    # compute relative probability for each potential contraction
    if temperature == 0.0:
        energies = [1 if c == cmin else 0 for c in costs]
    else:
        # shift by cmin for numerical reasons
        energies = [math.exp(-(c - cmin) / temperature) for c in costs]

    # randomly choose a contraction based on energies
    (chosen,) = random_choices(range(n), weights=energies)
    cost, k1, k2, k12 = choices.pop(chosen)

    # put the other choice back in the heap
    for other in choices:
        heapq.heappush(queue, other)

    return cost, k1, k2, k12

def ssa_path_compute_cost(
    ssa_path: PathType,
    inputs: List[ArrayIndexType],
    output: ArrayIndexType,
    size_dict: Dict[str, int],
) -> Tuple[int, int]:
    """Compute the flops and max size of an ssa path."""
    inputs = list(map(frozenset, inputs))  # type: ignore
    output = frozenset(output)
    remaining = set(range(len(inputs)))
    total_cost = 0
    max_size = 0

    for i, j in ssa_path:
        k12, flops12 = paths.calc_k12_flops(inputs, output, remaining, i, j, size_dict)  # type: ignore
        remaining.discard(i)
        remaining.discard(j)
        remaining.add(len(inputs))
        inputs.append(k12)
        total_cost += flops12
        max_size = max(max_size, helpers.compute_size_by_dict(k12, size_dict))

    return total_cost, max_size

def _trial_greedy_ssa_path_and_cost(
    r: int,
    inputs: List[ArrayIndexType],
    output: ArrayIndexType,
    size_dict: Dict[str, int],
    choose_fn: Any,
    cost_fn: Any,
) -> Tuple[PathType, int, int]:
    """A single, repeatable, greedy trial run. **Returns:** ``ssa_path`` and cost."""
    if r == 0:
        # always start with the standard greedy approach
        choose_fn = None

    random_seed(r)

    ssa_path = paths.ssa_greedy_optimize(inputs, output, size_dict, choose_fn, cost_fn)
    cost, size = ssa_path_compute_cost(ssa_path, inputs, output, size_dict)

    return ssa_path, cost, size

class RandomGreedy(RandomOptimizer):
    """

    **Parameters:**

    - **cost_fn** - *(callable, optional)* A function that returns a heuristic 'cost' of a potential contraction
        with which to sort candidates. Should have signature
        `cost_fn(size12, size1, size2, k12, k1, k2)`.
    - **temperature** - *(float, optional)* When choosing a possible contraction, its relative probability will be
        proportional to `exp(-cost / temperature)`. Thus the larger
        `temperature` is, the further random paths will stray from the normal
        'greedy' path. Conversely, if set to zero, only paths with exactly the
        same cost as the best at each step will be explored.
    - **rel_temperature** - *(bool, optional)* Whether to normalize the ``temperature`` at each step to the scale of
        the best cost. This is generally beneficial as the magnitude of costs
        can vary significantly throughout a contraction. If False, the
        algorithm will end up branching when the absolute cost is low, but
        stick to the 'greedy' path when the cost is high - this can also be
        beneficial.
    - **nbranch** - *(int, optional)* How many potential paths to calculate probability for and choose from at each step.
    - **kwargs** - Supplied to RandomOptimizer.
    """

    def __init__(
        self,
        cost_fn: str = "memory-removed-jitter",
        temperature: float = 1.0,
        rel_temperature: bool = True,
        nbranch: int = 8,
        **kwargs: Any,
    ):
        self.cost_fn = cost_fn
        self.temperature = temperature
        self.rel_temperature = rel_temperature
        self.nbranch = nbranch
        super().__init__(**kwargs)

    @property
    def choose_fn(self) -> Any:
        """The function that chooses which contraction to take - make this a
        property so that ``temperature`` and ``nbranch`` etc. can be updated
        between runs.
        """
        if self.nbranch == 1:
            return None

        return functools.partial(
            thermal_chooser,
            temperature=self.temperature,
            nbranch=self.nbranch,
            rel_temperature=self.rel_temperature,
        )

    def setup(
        self,
        inputs: List[ArrayIndexType],
        output: ArrayIndexType,
        size_dict: Dict[str, int],
    ) -> Tuple[Any, Any]:
        fn = _trial_greedy_ssa_path_and_cost
        args = (inputs, output, size_dict, self.choose_fn, self.cost_fn)
        return fn, args

def random_greedy(
    inputs: List[ArrayIndexType],
    output: ArrayIndexType,
    idx_dict: Dict[str, int],
    memory_limit: Optional[int] = None,
    **optimizer_kwargs: Any,
) -> ArrayType:
    """ """
    optimizer = RandomGreedy(**optimizer_kwargs)
    return optimizer(inputs, output, idx_dict, memory_limit)

random_greedy_128 = functools.partial(random_greedy, max_repeats=128)


import pyriemann
import mne
from mne.io import read_raw_gdf
import scipy
from scipy import signal
from scipy.signal import butter, filtfilt, sosfiltfilt
import os

import pickle
import sklearn
import seaborn as sns
import matplotlib
import matplotlib as mpl
mpl.use('Qt5Agg') # for using pyplot (pip install pyqt5)

import matplotlib.pyplot as plt
import numpy as np

# Bandpass filtering
def butter_lowpass_filter(data, lowcut, fs, order):
    nyq = fs/2
    low = lowcut/nyq
    b, a = butter(order, low, btype='low')
    # demean before filtering
    meandat = np.mean(data, axis=1)
    data = data - meandat[:, np.newaxis]
    y = filtfilt(b, a, data) # zero-phase filter # data: [ch x time]
    return y

def butter_highpass_filter(data, highcut, fs, order):
    nyq = fs/2
    high = highcut/nyq
    b, a = butter(order, high, btype='high')
    # demean before filtering
    meandat = np.mean(data, axis=1)
    data = data - meandat[:, np.newaxis]
    y = filtfilt(b, a, data) # zero-phase filter # data: [ch x time]
    return y

def butter_bandpass_filter(data, lowcut, highcut, fs, order):
    nyq = fs/2
    low = lowcut/nyq
    high = highcut/nyq
    sos = butter(order, [low, high], btype='band', output='sos')
    # demean before filtering
    meandat = np.mean(data, axis=1)
    data = data - meandat[:, np.newaxis]
    y = sosfiltfilt(sos, data) # zero-phase filter # data: [ch x time]
    # specify pandlen to make the result the same as Matlab filtfilt()
    return y

# User parameters
# 769, 770, 774, 780 - left, right, up (tongue), down (feet)
#markers = [769, 770, 780, 774]
#markers_arr = {769:0, 770:1, 780:2, 774:3}
markers = [769, 770] # left, right
markers_arr = {769:1, 770:2}

# for g.tec EEG
nCh = 16
fs = 512
frame = [0.5, 3]
nTime = int((frame[1]-frame[0]) * 512)
#nTrial = 20
nClass = len(markers)
bp = [8, 30]

ch_names = ['FP1', 'FP2', 'F4', 'Fz', 'F3', 'T7', 'C3', 'Cz', 'C4', 'T8', 'P4', 'Pz', 'P3', 'O1', 'Oz', 'O2']
roi = ['F4', 'Fz', 'F3', 'C3', 'Cz', 'C4', 'P4', 'Pz', 'P3']
roi_id = np.zeros((len(roi)), dtype=np.int64)

for i in range(len(roi)):
  roi_id[i] = ch_names.index(roi[i]) # use roi_id

nSub = 3
train_EEG = np.array([]).reshape(0, nCh, nTime)
train_labels = []

for i in range(4):
    fname = './data/s%02d/MI_run%02d.gdf' % (nSub, (i+1))
    print(fname)

    eeg = read_raw_gdf(fname)
    ano_types = eeg.annotations.description.astype(int) # markers
    ano_latency = np.round(eeg.annotations.onset, 4)
    eeg_times = np.round(eeg.times, 4)
    dat = eeg.get_data() * 1000000
    ch_names = eeg.ch_names

    merge_EEG = np.array([]).reshape(nCh, nTime, 0)
    for cur_markers in markers:
        event_indicies = np.argwhere(ano_types == cur_markers)
        event_latencies = ano_latency[event_indicies]
        print('current marker is '+str(cur_markers))
        n_trial = 0
        epoched_EEG = np.array([]).reshape(nCh, nTime, 0)
        tmp_labels = markers_arr[cur_markers] * np.ones((len(event_latencies)))
        train_labels = np.append(train_labels, tmp_labels)

        for cur_latency in event_latencies:
            m_onset = np.where(eeg_times == cur_latency)[0][0]
            tmp_epoch = dat[:, m_onset + int(frame[0]*fs):m_onset + int(frame[1]*fs)]

            # epoch-level bandpass filtering
            tmp_epoch = butter_bandpass_filter(tmp_epoch, bp[0], bp[1], fs, 4)
            epoched_EEG = np.dstack((epoched_EEG, tmp_epoch))
            n_trial = n_trial + 1
        merge_EEG = np.dstack((merge_EEG, epoched_EEG))

    merge_EEG = np.transpose(merge_EEG, (2, 0, 1)) # now [trial x ch x time]
    train_EEG = np.vstack((train_EEG, merge_EEG))

cov_train = pyriemann.estimation.Covariances().fit_transform(train_EEG[:, roi_id, :])
print(cov_train.shape)
print(train_labels.shape)

mdm = pyriemann.classification.MDM()
mdm.metric = 'Riemann'
mdm.fit(cov_train, train_labels) # training

mdm_train_acc = np.sum(mdm.predict(cov_train) == train_labels) / len(train_labels) # train - meaningless
print('training accuracy is', np.round(mdm_train_acc,4))

trained = {'COV':cov_train, 'Labels':train_labels}
fname_user = input('Enter model name: ')
fname_model = './data/s%02d/%s.pkl' % (nSub, fname_user)
print(fname_model, 'saved.')
out_file = open(fname_model, 'wb')
pickle.dump(trained, out_file)
out_file.close()


import matplotlib
matplotlib.use('TKAgg')

import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from dateutil import parser

import numpy as np
import pandas as pd
import datetime

df_ferrara = pd.read_csv('WeatherData/ferrara_270615.csv')
df_milano = pd.read_csv('WeatherData/milano_270615.csv')
df_mantova = pd.read_csv('WeatherData/mantova_270615.csv')
df_ravenna = pd.read_csv('WeatherData/ravenna_270615.csv')
df_torino = pd.read_csv('WeatherData/torino_270615.csv')
df_asti = pd.read_csv('WeatherData/asti_270615.csv')
df_bologna = pd.read_csv('WeatherData/bologna_270615.csv')
df_piacenza = pd.read_csv('WeatherData/piacenza_270615.csv')
df_cesena = pd.read_csv('WeatherData/cesena_270615.csv')
df_faenza = pd.read_csv('WeatherData/faenza_270615.csv')

# dist 是一个装城市距离海边距离的列表
dist = [df_ravenna['dist'][0],
    df_cesena['dist'][0],
    df_faenza['dist'][0],
    df_ferrara['dist'][0],
    df_bologna['dist'][0],
    df_mantova['dist'][0],
    df_piacenza['dist'][0],
    df_milano['dist'][0],
    df_asti['dist'][0],
    df_torino['dist'][0]
]

# temp_max 是一个存放每个城市最高温度的列表
temp_max = [df_ravenna['temp'].max(),
    df_cesena['temp'].max(),
    df_faenza['temp'].max(),
    df_ferrara['temp'].max(),
    df_bologna['temp'].max(),
    df_mantova['temp'].max(),
    df_piacenza['temp'].max(),
    df_milano['temp'].max(),
    df_asti['temp'].max(),
    df_torino['temp'].max()
]

# temp_min 是一个存放每个城市最低温度的列表
temp_min = [df_ravenna['temp'].min(),
    df_cesena['temp'].min(),
    df_faenza['temp'].min(),
    df_ferrara['temp'].min(),
    df_bologna['temp'].min(),
    df_mantova['temp'].min(),
    df_piacenza['temp'].min(),
    df_milano['temp'].min(),
    df_asti['temp'].min(),
    df_torino['temp'].min()
]

# 调用 subplots() 函数，重新定义 fig, ax 变量
fig, ax = plt.subplots()
plt.xticks(rotation=70)

hours = mdates.DateFormatter('%H:%M')
ax.xaxis.set_major_formatter(hours)

# 先把最高温画出来。
fig, ax = plt.subplots()
ax.plot(dist,temp_max,'ro')

# 用线性回归算法得到两条直线，分别表示两种不同的气温趋势，这样做很有趣。我们可以使用scikit-learn库的SVR方法。

from sklearn.svm import SVR

# dist1是靠近海的城市集合，dist2是远离海洋的城市集合
dist1 = dist[0:5]
dist2 = dist[5:10]

# 改变列表的结构，dist1现在是5个列表的集合
# 之后我们会看到 numpy 中 reshape() 函数也有同样的作用
dist1 = [[x] for x in dist1]
dist2 = [[x] for x in dist2]

# temp_max1 是 dist1 中城市的对应最高温度
temp_max1 = temp_max[0:5]
# temp_max2 是 dist2 中城市的对应最高温度
temp_max2 = temp_max[5:10]

# 我们调用SVR函数，在参数中规定了使用线性的拟合函数
# 并且把 C 设为1000来尽量拟合数据（因为不需要精确预测不用担心过拟合）
svr_lin1 = SVR(kernel='linear', C=1e3)
svr_lin2 = SVR(kernel='linear', C=1e3)

# 加入数据，进行拟合（这一步可能会跑很久，大概10多分钟，休息一下:) ）
svr_lin1.fit(dist1, temp_max1)
svr_lin2.fit(dist2, temp_max2)

# 关于 reshape 函数请看代码后面的详细讨论
xp1 = np.arange(10,100,10).reshape((9,1))
xp2 = np.arange(50,400,50).reshape((7,1))
yp1 = svr_lin1.predict(xp1)
yp2 = svr_lin2.predict(xp2)

# ax = fig.add_subplot(122)

# 限制了 x 轴的取值范围
ax.set_xlim(0,400)

# 画出图像
ax.plot(xp1, yp1, c='b', label='Strong sea effect')
ax.plot(xp2, yp2, c='g', label='Light sea effect')

print(svr_lin1.coef_)  #斜率
print(svr_lin1.intercept_)  # 截距
print(svr_lin2.coef_)
print(svr_lin2.intercept_)

# 你可能会考虑将这两条直线的交点作为受海洋影响和不受海洋影响的区域的分界点，或者至少是海洋影响较弱的分界点。
from scipy.optimize import fsolve

# 定义了第一条拟合直线
def line1(x):
    a1 = svr_lin1.coef_[0][0]
    b1 = svr_lin1.intercept_[0]
    return a1*x + b1

# 定义了第二条拟合直线
def line2(x):
    a2 = svr_lin2.coef_[0][0]
    b2 = svr_lin2.intercept_[0]
    return a2*x + b2

# 定义了找到两条直线的交点的 x 坐标的函数
def findIntersection(fun1,fun2,x0):
    return fsolve(lambda x : fun1(x) - fun2(x),x0)

result = findIntersection(line1,line2,0.0)
print("[x,y] = [ %d , %d ]" % (result,line1(result)))

ax.plot(result, line1(result), 'ys')

fig.show()

气象数据分析/气象线性分析.py


"""
Sandbox URL Configuration
"""
from django.conf import settings
from django.conf.urls import url

from django.views.generic.base import TemplateView

from sandbox.views import BasicSampleFormView, ModesSampleFormView

urlpatterns = [
    # Dummy homepage to list demo views
    url(r'^$', TemplateView.as_view(
        template_name="homepage.html"
    ), name='home'),

    # Sample with codemirror in the raw way
    url(r'^raw/$', TemplateView.as_view(
        template_name="raw.html"
    ), name='raw'),

    # Basic form sample
    url(r'^form/$', BasicSampleFormView.as_view(
        template_name="form.html"
    ), name='form'),

    # Mode index list
    url(r'^modes/$', ModesSampleFormView.as_view(
        template_name="modes.html"
    ), name='mode-index'),

    # Basic form sample with specific mode
    url(r'^modes/(?P<mode>[-\w]+)/$', ModesSampleFormView.as_view(
        template_name="modes.html"
    ), name='basic'),
]


import json
from typing import Any, Dict, List, Optional, Set

from clairvoyance.entities import GraphQLPrimitive
from clairvoyance.entities.context import log
from clairvoyance.entities.primitives import GraphQLKind

class Schema:
    """Host of the introspection data."""

    def __init__(
        self,
        query_type: str = None,
        mutation_type: str = None,
        subscription_type: str = None,
        schema: Dict[str, Any] = None,
    ):
        if schema:
            self._schema = {
                'directives': schema['data']['__schema']['directives'],
                'mutationType': schema['data']['__schema']['mutationType'],
                'queryType': schema['data']['__schema']['queryType'],
                'subscriptionType': schema['data']['__schema']['subscriptionType'],
                'types': [],
            }
            self.types = {}
            for t in schema['data']['__schema']['types']:
                typ = Type.from_json(t)
                self.types[typ.name] = typ
        else:
            self.query_type = {'name': query_type} if query_type else None
            self.mutation_type = {'name': mutation_type} if mutation_type else None
            self.subscription_type = ({'name': subscription_type} if subscription_type else None)
            self._schema = {
                'directives': [],
                'queryType': self.query_type,
                'mutationType': self.mutation_type,
                'subscriptionType': self.subscription_type,
                'types': [],
            }
            self.types = {
                GraphQLPrimitive.STRING: Type(
                    name=GraphQLPrimitive.STRING,
                    kind=GraphQLKind.SCALAR,
                ),
                GraphQLPrimitive.ID: Type(
                    name=GraphQLPrimitive.ID,
                    kind=GraphQLKind.SCALAR,
                ),
            }
            if query_type:
                self.add_type(query_type, 'OBJECT')
            if mutation_type:
                self.add_type(mutation_type, 'OBJECT')
            if subscription_type:
                self.add_type(subscription_type, 'OBJECT')

    # Adds type to schema if it's not exists already
    def add_type(
        self,
        name: str,
        kind: str,
    ) -> None:
        """Adds type to schema if it's not exists already."""

        if name not in self.types:
            typ = Type(name=name, kind=kind)
            self.types[name] = typ

    def __repr__(self) -> str:
        """String representation of the schema."""

        schema = {'data': {'__schema': self._schema}}

        for t in self.types.values():
            schema['data']['__schema']['types'].append(t.to_json())

        output = json.dumps(schema, indent=4, sort_keys=True)
        return output

    def get_path_from_root(
        self,
        name: str,
    ) -> List[str]:
        """Getting path starting from root.

        The algorigthm explores the schema in a DFS manner. It uses a set to keep track of visited nodes, and a list to keep track of the path. Keeping track of
        the visited nodes is necessary to avoid infinite loops (ie. recursions in the schema). If a full iteration over the types is made without finding a
        match, it means that the schema is not connected, and the path cannot be found.
        """

        log().debug(f'Entered get_path_from_root({name})')
        path_from_root: List[str] = []

        if name not in self.types:
            raise Exception(f'Type \'{name}\' not in schema!')

        roots = [
            self._schema['queryType']['name'] if self._schema['queryType'] else '',
            self._schema['mutationType']['name'] if self._schema['mutationType'] else '',
            self._schema['subscriptionType']['name'] if self._schema['subscriptionType'] else '',
        ]
        roots = [r for r in roots if r]

        visited = set()
        initial_name = name
        while name not in roots:
            found = False
            for t in self.types.values():
                for f in t.fields:
                    key = f'{t.name}.{f.name}'
                    if key in visited:
                        continue
                    if f.type.name == name:
                        path_from_root.insert(0, f.name)
                        visited.add(key)
                        name = t.name
                        found = True
            if not found:
                log().debug('get_path_from_root: Ran an iteration with no matches found')
                raise Exception(f'Could not find path from root to \'{initial_name}\' \nCurrent path: {path_from_root}')

        # Prepend queryType or mutationType
        path_from_root.insert(0, name)

        return path_from_root

    def get_type_without_fields(
        self,
        ignored: Set[str] = None,
    ) -> str:
        """Gets the type without a field."""
        ignored = ignored or set()

        for t in self.types.values():
            if not t.fields and t.name not in ignored and t.kind != GraphQLKind.INPUT_OBJECT:
                return t.name

        return ''

    def convert_path_to_document(
        self,
        path: List[str],
    ) -> str:
        """Converts a path to document."""

        log().debug(f'Entered convert_path_to_document({path})')
        doc = 'FUZZ'

        while len(path) > 1:
            doc = f'{path.pop()} {{ {doc} }}'

        if self._schema['queryType'] and path[0] == self._schema['queryType']['name']:
            doc = f'query {{ {doc} }}'
        elif self._schema['mutationType'] and path[0] == self._schema['mutationType']['name']:
            doc = f'mutation {{ {doc} }}'
        elif self._schema['subscriptionType'] and path[0] == self._schema['subscriptionType']['name']:
            doc = f'subscription {{ {doc} }}'
        else:
            raise Exception('Unknown operation type')

        return doc

class TypeRef:
    def __init__(
        self,
        name: str,
        kind: str,
        is_list: bool = False,
        non_null_item: bool = False,
        non_null: bool = False,
    ) -> None:
        if not is_list and non_null_item:
            raise Exception('elements can\'t be NON_NULL if TypeRef is not LIST')

        self.name = name
        self.kind = kind
        self.is_list = is_list
        self.non_null = non_null
        self.list = self.is_list
        self.non_null_item = non_null_item

    def __eq__(self, other: Any) -> bool:
        if isinstance(other, TypeRef):
            for key, attr in self.__dict__.items():
                if attr != other.__dict__[key]:
                    return False
            return True
        return False

    def __str__(self) -> str:
        return str(self.__dict__)

    def to_json(self) -> Dict[str, Any]:
        j: Dict[str, Any] = {'kind': self.kind, 'name': self.name, 'ofType': None}

        if self.non_null_item:
            j = {'kind': GraphQLKind.NON_NULL, 'name': None, 'ofType': j}

        if self.list:
            j = {'kind': GraphQLKind.LIST, 'name': None, 'ofType': j}

        if self.non_null:
            j = {'kind': GraphQLKind.NON_NULL, 'name': None, 'ofType': j}

        return j

class InputValue:
    def __init__(
        self,
        name: str,
        typ: TypeRef,
    ) -> None:
        self.name = name
        self.type = typ

    def __str__(self) -> str:
        return f'{{ \'name\': {self.name}, \'type\': {str(self.type)} }}'

    def to_json(self) -> dict:
        return {
            'defaultValue': None,
            'description': None,
            'name': self.name,
            'type': self.type.to_json(),
        }

    @classmethod
    def from_json(
        cls,
        _json: Dict[str, Any],
    ) -> 'InputValue':
        name = _json['name']
        typ = field_or_arg_type_from_json(_json['type'])

        return cls(
            name=name,
            typ=typ,
        )

def field_or_arg_type_from_json(_json: Dict[str, Any]) -> 'TypeRef':
    typ = None

    if _json['kind'] not in [GraphQLKind.NON_NULL, GraphQLKind.LIST]:
        typ = TypeRef(
            name=_json['name'],
            kind=_json['kind'],
        )
    elif not _json['ofType']['ofType']:
        actual_type = _json['ofType']

        if _json['kind'] == GraphQLKind.NON_NULL:
            typ = TypeRef(
                name=actual_type['name'],
                kind=actual_type['kind'],
                non_null=True,
            )
        elif _json['kind'] == GraphQLKind.LIST:
            typ = TypeRef(
                name=actual_type['name'],
                kind=actual_type['kind'],
                is_list=True,
            )
        else:
            raise Exception(f'Unexpected type.kind: {_json["kind"]}')
    elif not _json['ofType']['ofType']['ofType']:
        actual_type = _json['ofType']['ofType']

        if _json['kind'] == GraphQLKind.NON_NULL:
            typ = TypeRef(
                actual_type['name'],
                actual_type['kind'],
                True,
                False,
                True,
            )
        elif _json['kind'] == GraphQLKind.LIST:
            typ = TypeRef(
                name=actual_type['name'],
                kind=actual_type['kind'],
                is_list=True,
                non_null_item=True,
            )
        else:
            raise Exception(f'Unexpected type.kind: {_json["kind"]}')
    elif not _json['ofType']['ofType']['ofType']['ofType']:
        actual_type = _json['ofType']['ofType']['ofType']
        typ = TypeRef(
            name=actual_type['name'],
            kind=actual_type['kind'],
            is_list=True,
            non_null_item=True,
            non_null=True,
        )
    else:
        raise Exception('Invalid field or arg (too many \'ofType\')')

    return typ

class Field:
    def __init__(
        self,
        name: str,
        typeref: Optional[TypeRef],
        args: List[InputValue] = None,
    ):
        if not typeref:
            raise Exception(f'Can\'t create {name} Field from {typeref} TypeRef.')

        self.name = name
        self.type = typeref
        self.args = args or []

    def to_json(self) -> dict:
        return {
            'args': [a.to_json() for a in self.args],
            'deprecationReason': None,
            'description': None,
            'isDeprecated': False,
            'name': self.name,
            'type': self.type.to_json(),
        }

    @classmethod
    def from_json(cls, _json: Dict[str, Any]) -> 'Field':
        name = _json['name']
        typ = field_or_arg_type_from_json(_json['type'])

        args = []
        for a in _json['args']:
            args.append(InputValue.from_json(a))

        return cls(name, typ, args)

class Type:
    def __init__(
        self,
        name: str = '',
        kind: str = '',
        fields: List[Field] = None,
    ):
        self.name = name
        self.kind = kind
        self.fields: List[Field] = fields or []

    def to_json(self) -> Dict[str, Any]:
        # dirty hack

        if not self.fields:
            field_typeref = TypeRef(
                name=GraphQLPrimitive.STRING,
                kind=GraphQLKind.SCALAR,
            )
            dummy = Field('dummy', field_typeref)
            self.fields.append(dummy)

        output: Dict[str, Any] = {
            'description': None,
            'enumValues': None,
            'interfaces': [],
            'kind': self.kind,
            'name': self.name,
            'possibleTypes': None,
        }

        if self.kind in [GraphQLKind.OBJECT, GraphQLKind.INTERFACE]:
            output['fields'] = [f.to_json() for f in self.fields]
            output['inputFields'] = None
        elif self.kind == GraphQLKind.INPUT_OBJECT:
            output['fields'] = None
            output['inputFields'] = [f.to_json() for f in self.fields]

        return output

    @classmethod
    def from_json(
        cls,
        _json: Dict[str, Any],
    ) -> 'Type':
        name = _json['name']
        kind = _json['kind']
        fields = []

        if kind in [GraphQLKind.OBJECT, GraphQLKind.INTERFACE, GraphQLKind.INPUT_OBJECT]:
            fields_field = ''
            if kind in [GraphQLKind.OBJECT, GraphQLKind.INTERFACE]:
                fields_field = 'fields'
            elif kind == GraphQLKind.INPUT_OBJECT:
                fields_field = 'inputFields'

            for f in _json[fields_field]:
                # Don't add dummy fields!
                if f['name'] == 'dummy':
                    continue
                fields.append(Field.from_json(f))

        return cls(
            name=name,
            kind=kind,
            fields=fields,
        )


from rodi import RoDI
import time

robot = RoDI()

def reubicar():
    robot.move_stop()
    robot.pixel(20,0,0)
    robot.move_backward()
    time.sleep(0.1)
    robot.move_left()
    time.sleep(0.5)
    robot.move_forward()
    time.sleep(0.5)

def ataque():
    robot.move(100,100)

while True:
    try:
        distancia = robot.see()
        linea = robot.sense()
        robot.pixel(20,20,20)
        robot.move(30,30)
        time.sleep(0.1)
        inicio_de_ataque = None

        print("Distancia: " + str(distancia))
        print("Linea 1: " + str(linea[0]))
        print("Linea 2: " + str(linea[1]))

        if (linea[0] >= 100 or linea[1] >= 100):
            reubicar()
        if distancia < 15:
            ataque()
            inicio_de_ataque = time.time()
        if time.time() - inicio_de_ataque > 2:
            reubicar()

    except KeyboardInterrupt:
        robot.move_stop()
        break


from datetime import datetime
from sqlalchemy import Column, String, Integer, Float, DateTime, select, delete
from sqlalchemy.exc import IntegrityError, NoResultFound
from sqlalchemy.ext.asyncio import AsyncSession

from app.services.database import Base

class TokenInfo(Base):
    __tablename__ = "TokenInfo"
    created_at = Column(DateTime, primary_key=True)
    symbol = Column(String, primary_key=True)
    rank = Column(Integer, nullable=False)
    price = Column(Float, nullable=True)

    @classmethod
    async def create(cls, db: AsyncSession, **kwargs):
        transaction = cls(**kwargs)
        db.add(transaction)
        await db.commit()
        await db.refresh(transaction)
        return transaction

    @classmethod
    async def delete_timestamp(cls, db: AsyncSession, created_at: datetime):
        transaction = delete(cls).where(
            cls.created_at==created_at
        ).returning(cls.symbol, cls.created_at)
        await db.execute(transaction)
        await db.commit()
        return transaction

    @classmethod
    async def get_tokens_by_date(cls, db: AsyncSession, dt: datetime):
        return (await db.execute(
            select(cls).filter_by(created_at=dt)
        )).scalars().all()


import cv2, time, pandas
from datetime import datetime

firstFrame = None
statusList = [None, None]
times = []
contourCount = []
frameCount = []
avgContour = []
contCStart = 0 #indicator to start recording contour area

video = cv2.VideoCapture(0, cv2.CAP_DSHOW)
df = pandas.DataFrame(columns=["Start","End"])

while True:
    check, frame = video.read()
    status = 0
    # turning gray
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    gray = cv2.GaussianBlur(gray, (21,21), 0)

    #catch first frame for later comparisons
    if firstFrame is None:
        firstFrame = gray
        continue

    delta = cv2.absdiff(firstFrame, gray)

    #finding areas of movement and turning them to black/white
    # then finding contours for the movement
    threshFrame = cv2.threshold(delta, 30, 255, cv2.THRESH_BINARY)[1]
    threshFrame = cv2.dilate(threshFrame, None, iterations=2)
    (cnts,_) = cv2.findContours(threshFrame.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

    #if contour area >5000 put a rectangle around it and excecute rest
    for contour in cnts:
        if cv2.contourArea(contour) < 5000:
            if contCStart == 1: #if first movement already detected
                contourCount.append(0)
            continue

        status = 1
        contCStart = 1
        contourCount.append(cv2.contourArea(contour))
        (x, y, w, h) = cv2.boundingRect(contour)
        cv2.rectangle(frame, (x,y), (x+w, y+h), (0,255,0), 3)

    statusList.append(status)
    statusList = statusList[-2:] #only keep track of part of list we need

    #record time something exits/enters frame, and size on exit
    if statusList[-1] == 1 and statusList[-2] == 0:
        times.append(datetime.now())
    if statusList[-1] == 0 and statusList[-2] == 1:
        times.append(datetime.now())
        times.append(cv2.contourArea(contour))

    #showing gray, delta, black/white, and rectangle on orig
    cv2.imshow("Capturing", gray)
    cv2.imshow("Delta", delta)
    cv2.imshow("Threshold", threshFrame)
    cv2.imshow("Color Frame", frame)

    key = cv2.waitKey(100)

    if key == ord('q'):
        if status == 1:
            times.append(datetime.now())
            times.append(cv2.contourArea(contour))
        break
################# end while loop ###############

#add times to data frame
for i in range(0, len(times), 3):
    df = df.append({"Start":times[i], "End":times[i+1], "ExitArea":times[i+2]}, ignore_index=True)

df.to_csv("Times.csv")

z = 0
x = 0
y = 0
count = 1
# averaging contours together to smooth graph
while x < len(contourCount):
    while z < x+10:
        if z < len(contourCount):
            y = contourCount[z] + y
            z = z + 1
            count = count + 1
        else:
            z = x + 50

    avgContour.append(float(int(y/count)^2)) #squared to accentuate changes
    #avgContour.append((y/count))
    y = 0
    x = x + 10
    z = z + 1
    count = 1

i = 0
# count for x-axis on plot
while i < len(avgContour):
    frameCount.append(i)
    i = i + 1

video.release()
cv2.destroyAllWindows()


from .range_borders import Date, FromInfinity, ToInfinity
from datetime import timedelta

class DateRange:
    """
    This class implements date ranges that support open borders,
    so it is possible to create date ranges that contain all dates up to
    a specific date or all dates from a specific date on. Strict ranges with
    specific dates as borders are supported as well.
    The implementation does not support any kind of daytime measurement.
    """

    # DateRange supports all formats that are supported by the datetime module
    # '%Y-%m-%d' is the predefined format
    DATE_FORMAT: str = '%Y-%m-%d'

    #######################################################################################
    # the following methods can be called on every DateRange instance (infinite and finite)
    def __init__(self, date_from: str or None, date_to: str or None):
        """
        Creates a new Daterange. date_to must be greater or equal to date_form
        :param date_from: None value represents an open border
        :param date_to: None value represents an open border
        """
        if date_from is None:
            self._date_from = FromInfinity()
        else:
            self._date_from = Date(date_from, DateRange.DATE_FORMAT)

        if date_to is None:
            self._date_to = ToInfinity()
        else:
            self._date_to = Date(date_to, DateRange.DATE_FORMAT)

        # is set in the first call of the __len__ function
        self._length = None

        self._is_infinite = date_from is None or date_to is None

        if not self._is_infinite:
            if date_to < date_from:
                raise ValueError(f"date_to must be equal or greater than date_form. "
                                 f"{self.__repr__()}")

    def __repr__(self):
        return f"DateRange({self._date_from.to_string(DateRange.DATE_FORMAT)}, " \
               f"{self._date_to.to_string(DateRange.DATE_FORMAT)})"

    def __contains__(self, item: str):
        date = Date(item, DateRange.DATE_FORMAT)
        return self._date_from <= date <= self._date_to

    def intersects(self, date_from: str or None, date_to: str or None) -> bool:
        # returns true if at least one date is contained in both ranges
        date_range = DateRange(date_from=date_from, date_to=date_to)
        return not (self._date_to < date_range._date_from or date_range._date_to < self._date_from)

    def is_infinite(self) -> bool:
        return self._is_infinite

    ##########################################################################
    # the following methods raise exceptions if called on infinite DateRanges
    def __iter__(self):
        if self._is_infinite:
            raise ValueError(f"infinite date ranges are not iterable. date_range: {self.__repr__()}")
        else:
            self._current = self._date_from.date
        return self

    def __next__(self):
        if self._current > self._date_to.date:
            raise StopIteration
        else:
            ret = self._current.strftime(DateRange.DATE_FORMAT)
            self._current += timedelta(1)
            return ret

    def __len__(self):
        if self._is_infinite:
            raise ValueError(f"length infinite date ranges is not defined. date_range: {self.__repr__()}")

        # length has to be calculated and set only once because the
        # length of a date range can not change
        # !!!---if you want to implement the borders of date ranges to be changeable
        # this method must be reimplemented---!!!
        if self._length is None:
            counter = 0
            # __iter__ can safely be used because __len__ requires a finite date range as well
            for _ in self.__iter__():
                counter += 1
            self._length = counter

        return self._length


from django.db import models
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericRelation

from model_utils.models import TimeStampedModel

from files.mixins import UploadedFileMixin
from permissions.models import PermissionManagerMixin

from utils.models import CreatedByMixin
from utils.models.slug_field import AutoSlugCustomManagerField
from utils.descriptors import ChoicesDescriptorMixin

from ..managers.post import PostManager, AllPostManager
from ..conf import settings
from .mails.mails import PostEmailMixin
from .mixins import PostStatsMixin, PostPermissionsMixin, PostMetricMixin

class Post(
        PostPermissionsMixin,
        PostMetricMixin,
        PostStatsMixin,
        UploadedFileMixin,
        PermissionManagerMixin,
        CreatedByMixin,
        ChoicesDescriptorMixin,
        PostEmailMixin,
        TimeStampedModel):

    # Define here because of AutoSlugField
    objects = PostManager()
    all_objects = AllPostManager()

    title = models.CharField(max_length=255)
    description = models.TextField()

    content_type = models.ForeignKey(
        ContentType,
        on_delete=models.CASCADE,
        null=True,
    )
    object_id = models.PositiveIntegerField(null=True)
    content_object = GenericForeignKey('content_type', 'object_id')

    slug = AutoSlugCustomManagerField(
        populate_from='title',
        unique=True,
        null=True,
        blank=False,
    )
    tags = models.ManyToManyField('keywords.Keyword')
    _type = models.CharField(
        max_length=1,
        choices=settings.FORUM_POST_CH_TYPE)
    status = models.CharField(
        max_length=1,
        choices=settings.FORUM_CH_POST_STATUS,
        default=settings.FORUM_CH_POST_STATUS_DEFAULT)

    CHOICES_DESCRIPTOR_FIELDS = [
        '_type',
        'status',
    ]
    CHOICES_DESCRIPTOR_FIELDS_CHOICES = [
        settings.FORUM_POST_CH_TYPE,
        settings.FORUM_CH_POST_STATUS,
    ]

    logs = GenericRelation('PostAnswerStatus')
    files = GenericRelation('files.UploadedFile')

    objects = PostManager()
    all_objects = AllPostManager()
    slug_manager = AllPostManager()

    class Meta:
        verbose_name = 'Post'
        verbose_name_plural = 'Posts'
        ordering = ['-modified']
        base_manager_name = 'objects'
        permissions = settings.FORUM_PERMS_POST_ALL_PERMISSIONS

    def __str__(self):
        return self.title

    @property
    def category_name(self):
        category_name = ''
        if self.is_q_a_session:
            category_name = '{} - {} - {}'.format(
                self.get__type_display(),
                self.content_object.team.project,
                self.content_object.session.name,
            )
        elif self.content_object:
            category_name = self.content_object.name
        else:
            category_name = self.get__type_display()

        return category_name

    @property
    def circle(self):
        if self.is_circle:
            return self.content_object
        return None

    @property
    def qa_session(self):
        if self.is_q_a_session:
            return self.content_object.session
        return None

    @property
    def team(self):
        if self.is_project:
            return self.content_object
        elif self.is_q_a_session:
            return self.content_object.team
        return None

    @property
    def project(self):
        if self.team:
            return self.team.project
        return None

    @property
    def created_by_role(self):
        return self.created_by.user_title

    @property
    def url(self):
        if self.is_circle or self.is_project or self.is_announcement:
            if self.is_circle:
                circle = self.circle.slug
            elif self.is_project:
                circle = 'participant-questions'
            else:
                circle = 'announcements'
            return settings.FRONTEND_POST_DETAIL_PAGE.format(
                slug=self.slug,
                circle=circle)
        elif self.is_q_a_session:
            return settings.FRONTEND_JOBS_SWARM_SESSION_QUESTION_PAGE.format(
                **{
                    'pk_qa_session': self.content_object.session.pk,
                    'pk': self.pk
                })
        else:
            return ''

    @property
    def url_project(self):
        kwargs = {}
        if self.project is not None:
            kwargs = {
                'project_id': self.project.pk,
                'team_id': self.team.pk,
                'pk': self.pk,
            }
        if self.is_project:
            kwargs['section'] = 'ask-ecosystem'
        elif self.is_q_a_session:
            kwargs['section'] = 'swarm-session'
        else:
            kwargs = None
        if kwargs is not None:
            return settings.FRONTEND_PROJECT_QUESTION_PAGE.format(**kwargs)
        return ''

    def set_status(self, user_from, new_status):
        self.logs.create(
            user=user_from, status=self.status)
        self.status = new_status
        self.save(update_fields=['modified', 'status'])

    def mark_as_removed(self, user_from):
        self.can_update_or_remove(user_from)
        self.set_status(user_from, settings.FORUM_CH_REMOVED)
        self.action_removed(user_from)

    def reply(self, user_from, comment, timestamp=None, **kwargs):
        self.can_reply(user_from)
        answer = self.answers.create(
            comment=comment,
            created_by=user_from,
            reply_to=kwargs.get('reply_to'),
        )
        kwargs['target_object'] = answer
        if timestamp:
            self.answers.filter(pk=answer.pk).update(
                created=timestamp,
                modified=timestamp)
            Post.objects.filter(pk=self.pk).update(modified=timestamp)
        else:
            self.save(update_fields=['modified'])

        if kwargs.get('email_notification', True):
            self.send_email_reply(answer)

        answer.see(user_from)
        super().reply(user_from, comment, timestamp, **kwargs)
        return answer


from PIL import Image, ImageDraw

cella = 75

def rect(x1, y1, x2, y2, col):
  dib.polygon([(x1, y1), (x2, y1), (x2, y2), (x1, y2)], col)

def cercle(x, y, col):
  dib.ellipse([cella*x + 25, cella*y + 25, cella*x + 49, cella*y + 49], col)

c = int(input())
f = int(input())

img = Image.new('RGB', (cella*c, cella*f), 'Beige')
dib = ImageDraw.Draw(img)

mat = []
for j in range(f):
    fila = [0]*c
    mat += [fila]

mat[0][0] = 1
cercle(0, 0, 'Black')
mat[f-1][c-1] = 1
cercle(c - 1, f - 1, 'Black')
n = int(input())
for r in range(n):
  x = int(input()) - 1
  y = int(input()) - 1
  mat[y][x] = 1
  cercle(x, y, 'Black')

x = 0
y = 0
color = ''
while color == '':
  if x == c - 1 and y == f - 1:
    color = 'Green'
  elif x < c - 1 and mat[y][x+1]:
    x += 1
  elif y < f - 1 and mat[y+1][x]:
    y += 1
  else:
    color = 'Red'

x = 0
y = 0
fi = False
while not fi:
  cercle(x, y, color)
  if x == c - 1 and y == f - 1:
    fi = True
  elif x < c - 1 and mat[y][x+1]:
    rect(cella*x + cella//2, cella*y + 35, cella*x + 3*cella//2, cella*y + 39, color)
    x += 1
  elif y < f - 1 and mat[y+1][x]:
    rect(cella*x + 35, cella*y + cella//2, cella*x + 39, cella*y + 3*cella//2, color)
    y += 1
  else:
    fi = True

img.save("output.png")


# Student Virtual Assistant

# Libraries for accessing Google Scholar and scheduling reminders
import webbrowser
import schedule
import time

# Function to access Google Scholar
def search_scholar(query):
  webbrowser.open(f"https://scholar.google.com/scholar?q={query}")

# Function to input schedule
def input_schedule():
  schedule = {}
  while True:
    class_name = input("Enter class name (or type 'done' if finished): ")
    if class_name == "done":
      break
    class_time = input("Enter class time (e.g. 9:00 AM): ")
    schedule[class_name] = class_time
  return schedule

# Function to input assignments
def input_assignments():
  assignments = []
  while True:
    assignment = input("Enter assignment (or type 'done' if finished): ")
    if assignment == "done":
      break
    assignments.append(assignment)
  return assignments

# Function to remind student to hydrate
def remind_hydrate():
  print("Don't forget to drink water and stay hydrated!")

# Main function to run the virtual assistant
def run_assistant():
  print("Welcome to the Student Virtual Assistant")

  # Input schedule
  print("Please enter your schedule:")
  schedule = input_schedule()
  print(f"Your schedule: {schedule}")

  # Input assignments
  print("Please enter your assignments:")
  assignments = input_assignments()
  print(f"Your assignments: {assignments}")

  # Access Google Scholar
  query = input("What would you like to search on Google Scholar? ")
  search_scholar(query)

  # Schedule reminders to hydrate
  schedule.every(1).hours.do(remind_hydrate)

  # Start reminders
  while True:
    schedule.run_pending()
    time.sleep(1)

# Run the virtual assistant
if __name__ == "__main__":
  run_assistant()


#!/usr/bin/python3

"""
Run this with:

python3 -m http.server --cgi
"""

import cgitb
cgitb.enable(format="text")

from helper import get_input, json

# user_input = get_input()

test_data = {
  "firstName": "John",
  "lastName": "Smith",
  "age": 27
  }

# Will give you JSON output in the console
print(json.dumps(test_data))

'''
if user_input:
    print("User-input", user_input)
else:
    print(test_data)
'''


from setuptools import setup, find_packages

with open("requirements.txt") as f:
    content = f.readlines()
requirements = [x.strip() for x in content if "git+" not in x]

setup(name='chord-cleaning',
      description='creating a set of standardized chords from data',
      install_requires=requirements,
      packages=find_packages(),)