import argparse
import sys
from pathlib import Path
from typing import Union

from config.settings import get_config

DATA_SRC = 'data_src'
DATA_DST = 'data_dst'

ALIGNED = 'aligned'
ALIGNED_DEBUG = 'aligned_debug'
ALIGNED_CONVERT = 'aligned_convert'
MANUAL_EXTRACT = 'manual_extract'

def get_workspace_structure():
    """Create a workspace directory structure template"""
    return {
        DATA_SRC: [ALIGNED],
        DATA_DST: [ALIGNED_CONVERT, ALIGNED_DEBUG, ALIGNED, MANUAL_EXTRACT]
    }

def get_base_workspaces_path() -> Path:
    config = get_config()
    return config.WORKSPACES_BASE

def clear_directory(target: Path):
    # don't try to delete root!
    assert target != target.parent

    children = list(target.rglob("*"))
    # children

    response = input(
        f"{target} already exists, all {len(children)} files in this directory will be deleted. (Y|N)")
    if response != 'Y':
        print("Quitting")
        sys.exit()

    directories = []
    for child in children:
        if child.is_file():
            child.unlink()
        elif child.is_dir():
            directories.append(child)

    for directory in reversed(directories):
        directory.rmdir()

def create_workspace(workspace_name):
    base = get_base_workspaces_path()

    workspace_name = Path(workspace_name)
    new_workspace = base / workspace_name.name

    # ensure our target is a level below the base directory
    assert len(new_workspace.parts) > len(base.parts)

    if new_workspace.is_dir():
        clear_directory(new_workspace)
    if new_workspace.is_file():
        raise FileExistsError()

    new_workspace.mkdir(exist_ok=True)

    data_src = new_workspace / DATA_SRC
    data_dst = new_workspace / DATA_DST

    data_dst.mkdir()
    data_src.mkdir()

    project_structure = get_workspace_structure()

    for top_level_key in project_structure:
        sub_folders = project_structure[top_level_key]
        for folder in sub_folders:
            (new_workspace / top_level_key / folder).mkdir()

def makedir_iterable_structure(structure: Union[dict, list], current_base):
    """Take an iterable structure and produce directories from it"""
    if structure:
        for top_level_key in structure:
            recur_mkdir(structure, top_level_key, current_base)

def recur_mkdir(structure: Union[dict, list, str], current_entry, current_base: Path):
    """Recursively traverse the template structure and create directories"""

    if current_entry and isinstance(current_entry, str):
        current_base /= current_entry
        current_base.mkdir()
    else:
        return makedir_iterable_structure(current_entry, current_base)

    if isinstance(structure, dict):
        next_structure = structure.get(current_entry)
        if isinstance(next_structure, (list, dict)):
            return makedir_iterable_structure(next_structure, current_base)
        else:
            return recur_mkdir([], next_structure, current_base)

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('workspace_name')
    create_workspace(parser.parse_args().workspace_name)


"""
This small stub executes a command to get list of top 5
programs currently running with the longest time .

"""

import os
import sys
import subprocess
import logging

logging.basicConfig(level=logging.INFO, format='%(process)d-%(levelname)s-%(message)s')

try:
    if sys.platform.startswith("win"):
        logging.info("Windows Operating System found..")
        POWERSHELL_PROCESS = subprocess.Popen(["powershell", "Get-Process | select starttime,ProcessName,CPU,PM | Sort starttime -Desc"], stdout=subprocess.PIPE)
        RESULT = POWERSHELL_PROCESS.communicate()[0]
        print(RESULT)

    elif sys.platform.startswith("lin"):
        logging.info("Linux Operating System found..")
        COMMAND = "ps -o pid=,user=,vsz=,command=,%cpu=,%mem,time -e | sort -nrk 3,3 | head -n 7"
        RESULT = os.system(COMMAND)

except Exception as exception:
    logging.error("Error!", exc_info=True)


import flask
from flask import request, jsonify
import subprocess
from flask_cors import CORS, cross_origin
import json
import os

app = flask.Flask(__name__)
app.config["DEBUG"] = True
cors = CORS(app)
app.config['CORS_HEADERS'] = 'Content-Type'

chapel_frontend_executable = "/root/chapel_frontend/ChapelParseJson"
chapel_frontend_param = "/tmp/program_to_be_parsed.txt"

@app.route('/', methods=['GET'])
def home():
    return "
Home

Here you cant see nothing..
"

@app.route('/api/v1/resources/haskell/chapel_parser/', methods=['POST'])
@cross_origin()
def api_all():
    post_content = request.get_json()
    program = post_content["program"]

    if os.path.exists(chapel_frontend_param):
        os.remove(chapel_frontend_param)

    file = open(chapel_frontend_param,"w+")

    file.write(program)

    file.close()

    temp = subprocess.Popen([chapel_frontend_executable, chapel_frontend_param], stdout = subprocess.PIPE, universal_newlines=True)
    # get the output as a string
    output = str(temp.communicate()[0])

    print (output)

    # response = "asdad"
    # response.headers.add("Access-Control-Allow-Origin", "*")

    # response.headers.add('Access-Control-Allow-Origin', '*')
    # print (output)
    return output

app.run(host='0.0.0.0', port=8080)


from pylab import *
from scipy.optimize import curve_fit

c=3e8
h=6.626e-34
k=1.38e-23

data=loadtxt('firas.txt')
x=data[:,0]*c*100
y=data[:,1]*1e-20
er=data[:,3]*1e-23*1000

def I(f,T):
    return 2*h/c**2*f**3/(exp(h*f/(k*T))-1)

temp,_=curve_fit(I,x,y)
print('Temperature =',temp[0],'K')
errorbar(x,y,yerr=er,label='Data')
plot(x,y,'.')
plot(x,I(x,temp[0]),label='Fitted Plot')
xlabel("$\\nu$ [Hz]")
ylabel("$I(\\nu)$ [W/$m^2$/Hz/sr]")
title('CMB')
legend()
grid()
show()


import abc

import torch

class AttackInstance:
    """This class is subclassed by each AttackInstance, abstracing away the underlying attack.

    Parameters
    ----

    model: nn.Module
       The model for which the adversarial examples are optimised

    args: argparse.Namespace
        The arguments passed to the program, which are used to determine the attack parameters
    """

    def __init__(self, model, args):
        self.model = model
        self.args = args

    @abc.abstractmethod
    def generate_attack(self, batch):
        """An abstract function, which when implemented takes in a batch, and applies an adversarial perturbation to the datapoints

        Parameters
        ----
        batch: (Tensor,Tensor)
           Takes in a typical tuple (xs,ys) of datapoints and their labels

        Returns
        ---
        perturbed batch: (Tensor,Tensor)
           This returns (adv(xs),ys) where adv denotes our adversarial examples"""
        return None

def tensor_clamp(x, a_min, a_max):
    """
    like torch.clamp, except with bounds defined as tensors
    """
    out = torch.clamp(x - a_max, max=0) + a_max
    out = torch.clamp(out - a_min, min=0) + a_min
    return out

def normalize_l2(x):
    """
    Expects x.shape == [N, C, H, W]
    """
    norm = torch.norm(x.view(x.size(0), -1), p=2, dim=1)

    for i in range(1, len(x.shape)):
        norm = norm.unsqueeze(-1)

    return x / (norm + 1e-8)

def tensor_clamp_l2(x, center, radius):
    """batched clamp of x into l2 ball around center of given radius"""
    x = x.data
    diff = x - center
    diff_norm = torch.norm(diff.view(diff.size(0), -1), p=2, dim=1)
    project_select = diff_norm > radius
    if project_select.any():
        for _ in range(0, len(x.shape) - 1):
            diff_norm = diff_norm.unsqueeze(-1)

        new_x = x
        new_x[project_select] = (center + (diff / diff_norm) * radius)[project_select]
        return new_x
    else:
        return x

def cwloss(outputs, targets, k=None):
    # This is the CW loss function, which is a maximisation of the margin between the correct class and the incorrect class
    # This is the loss function used in the paper
    # https://arxiv.org/abs/1608.04644
    #

    outputs_sorted = torch.argsort(outputs, dim=1)
    predictions = outputs_sorted[:, -1]
    correct_predictions = targets == predictions
    margin_targets = predictions.clone()
    margin_targets[correct_predictions] = outputs_sorted[:, -2][correct_predictions]

    loss = outputs[:, targets] - outputs[:, margin_targets]

    if k is not None:
        loss = torch.max(loss, -k)

    return torch.mean(loss)


from django.urls import path
from core import views

urlpatterns = [
    path('contests/', views.contests, name='all_contests'),
    path('contests/<int:contest_id>', views.contests, name='contest'),
    path('contests/<str:contests_type>', views.contests, name='contests'),
    path('attempts/', views.attempts, name='all_attempts'),
    path('attempts/<int:contest_id>', views.attempts, name='attempts'),
    path('teams/', views.teams, name='all_teams'),
    path('teams/<int:team_id>', views.teams, name='team'),
    path('teams/contest-<int:contest_id>', views.teams, name='teams'),
    path('get_permissions/<int:contest_id>', views.get_permissions, name='permissions'),
    path('users/', views.register_user, name='register_user')
]


from rdkit import Chem
from rdkit.Chem import Draw
from rdkit import RDLogger
import numpy as np
import copy
import random
from collections import OrderedDict
from rdkit.Chem import rdMolDescriptors as rdDesc
from .molecular_graph import *
from .molecule_state import MolState
import torch
import warnings
from rdkit.Chem.QED import qed
from rdkit.Chem import AllChem
from rdkit import DataStructs
from scipy.stats import wasserstein_distance
import pickle
from .chemprop_IR.smiles_predict import get_IR_prediction, Forward_IR
import ipdb

lg = RDLogger.logger()
lg.setLevel(RDLogger.CRITICAL)
rdBase.DisableLog('rdApp.error')
warnings.filterwarnings("ignore")

REWARD_THRESHOLD = 0.95

class Env:
    def __init__(self, molForm, targetIRSpectra, targetNMRSpectra):
        self.molForm = molForm # CNOF Molecular Formula
        self.targetSpectra = targetIRSpectra
        self.targetNMR = targetNMRSpectra
        self.state = MolState(molForm, targetNMRSpectra) # Molecular State that has all the loose atoms

    def __str__(self):
        return "Current Env State: " + str(self.state) + " MolForm: " + str(self.molForm)

    def convertStrToList(self, string):
        return [int(i) for i in string.strip('][').split(', ')]

    def reset(self, ir_train_dat, idx=74753):
        try:
            self.targetmol = ir_train_dat[idx][0]
            self.molForm = ir_train_dat[idx][1]
            self.targetSpectra = ir_train_dat[idx][2] # ir-spectra
            self.targetNMR = ir_train_dat[idx][3] # nmr-spectra
        except Exception as e:
            print('Reset error', e)
            time.sleep(20)
        self.state = MolState(self.molForm, self.targetNMR)
        #print('Finished env reset')

    def reward(self, episode_actor, state = None, target = None):
        # Need to change for the testing code
        # Would be same as terminal_reward for our usecase in IR
        try:
            if state is None:
                state = self.state
            if target is None:
                target = self.targetSpectra
            state_mol = Chem.MolToSmiles(self.state.rdmol)
            state_mol = Chem.MolFromSmiles(Chem.MolToSmiles(Chem.MolFromSmiles(state_mol, sanitize=False), kekuleSmiles=True), sanitize=False)
            target_mol = Chem.MolFromSmiles(Chem.MolToSmiles(Chem.MolFromSmiles(self.targetmol, sanitize=False), kekuleSmiles=True), sanitize=False)
            substructmatch = int(target_mol.HasSubstructMatch(state_mol))
            if state.numInRdmol < state.totalNumOfAtoms:
                return substructmatch
            return substructmatch
        except:
            return 0

    def terminal_reward(self, episode_actor, state = None, target = None):
        try:
            if state is None:
                state = self.state
            if target is None:
                target = self.targetSpectra
            mol = self.state.rdmol
            Chem.SanitizeMol(mol,Chem.SanitizeFlags.SANITIZE_FINDRADICALS|Chem.SanitizeFlags.SANITIZE_KEKULIZE|Chem.SanitizeFlags.SANITIZE_SETAROMATICITY|Chem.SanitizeFlags.SANITIZE_SETCONJUGATION|Chem.SanitizeFlags.SANITIZE_SETHYBRIDIZATION|Chem.SanitizeFlags.SANITIZE_SYMMRINGS,catchErrors=True)

            if state.numInRdmol < state.totalNumOfAtoms:
                return 0

            self.forward_model.predict_smiles(Chem.MolToSmiles(mol))
            predicted_IR = np.abs(np.array(predicted_IR))

            reward = 1 - wasserstein_distance(predicted_IR, target)

            return 2*(reward-0.5)

        except Exception as e:
            print('Terminal reward error', e)
            return 0

    def invalidAction(self):
        raise Exception("Invalid Action has been chosen :(")

    def isTerminal(self, episode_actor, state: MolState = None):

        if state is None:
            state = self.state

        if sum(state.valid_actions()) == 0:
            return True

        if state.numInRdmol < state.totalNumOfAtoms:
            return False

        # target_ir = self.targetSpectra

        # mol = deepcopy(self.state.rdmol)
        # Chem.SanitizeMol(mol)

        state_mol = self.state.rdmol
        target_mol = Chem.MolFromSmiles(self.targetmol,sanitize=False)
        substructmatch = int(target_mol.HasSubstructMatch(state_mol))

        # if the present state is the target molecule
        if Chem.MolToSmiles(state_mol, canonical=True) == Chem.MolToSmiles(target_mol, canonical=True):
            return True

        # if the present state is a substructure of the target
        if substructmatch > 0:
            return False
        else:
            return True

        if self.terminal_reward(episode_actor) > REWARD_THRESHOLD:
            return True
        else:
            return False

    def step(self,  actionInt: int, episode_actor, state: MolState = None):
        if state is None:
            state = self.state

        valid_actions = state.action_mask
        if valid_actions[actionInt] == 0:
            action = state._actionIntToList(actionInt)
            #print(state._actionIntToList(actionInt))
            #print(state)

            return self.invalidAction()

        state.doStep(state._actionIntToList(actionInt))
        terminal = self.isTerminal(episode_actor, state)
        _ = state.valid_actions()
        reward = self.reward(episode_actor, state)
        if terminal:
            return state, reward,terminal
        else:
            return state, reward,terminal


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

from openfisca_core.parameters import Parameter, ParameterNode, Scale

def build_api_values_history(values_history):
    api_values_history = {}
    for value_at_instant in values_history.values_list:
        api_values_history[value_at_instant.instant_str] = value_at_instant.value

    return api_values_history

def get_value(date, values):
    candidates = sorted(
        [
            (start_date, value)
            for start_date, value in values.items()
            if start_date
            <= date  # dates are lexicographically ordered and can be sorted
        ],
        reverse=True,
    )

    if candidates:
        return candidates[0][1]
    else:
        return None

def build_api_scale(scale, value_key_name):
    # preprocess brackets for a scale with 'rates' or 'amounts'
    brackets = [
        {
            "thresholds": build_api_values_history(bracket.threshold),
            "values": build_api_values_history(getattr(bracket, value_key_name)),
        }
        for bracket in scale.brackets
    ]

    dates = set(
        sum(
            [
                list(bracket["thresholds"].keys()) + list(bracket["values"].keys())
                for bracket in brackets
            ],
            [],
        )
    )  # flatten the dates and remove duplicates

    # We iterate on all dates as we need to build the whole scale for each of them
    api_scale = {}
    for date in dates:
        for bracket in brackets:
            threshold_value = get_value(date, bracket["thresholds"])
            if threshold_value is not None:
                rate_or_amount_value = get_value(date, bracket["values"])
                api_scale[date] = api_scale.get(date) or {}
                api_scale[date][threshold_value] = rate_or_amount_value

    # Handle stopped parameters: a parameter is stopped if its first bracket is stopped
    latest_date_first_threshold = max(brackets[0]["thresholds"].keys())
    latest_value_first_threshold = brackets[0]["thresholds"][
        latest_date_first_threshold
    ]

    if latest_value_first_threshold is None:
        api_scale[latest_date_first_threshold] = None

    return api_scale

def build_source_url(absolute_file_path, country_package_metadata):
    relative_path = absolute_file_path.replace(country_package_metadata["location"], "")
    return "{}/blob/{}{}".format(
        country_package_metadata["repository_url"],
        country_package_metadata["version"],
        relative_path,
    )

def build_api_parameter(parameter, country_package_metadata):
    api_parameter = {
        "description": getattr(parameter, "description", None),
        "id": parameter.name,
        "metadata": parameter.metadata,
    }
    if parameter.file_path:
        api_parameter["source"] = build_source_url(
            parameter.file_path, country_package_metadata
        )
    if isinstance(parameter, Parameter):
        if parameter.documentation:
            api_parameter["documentation"] = parameter.documentation.strip()
        api_parameter["values"] = build_api_values_history(parameter)
    elif isinstance(parameter, Scale):
        if "rate" in parameter.brackets[0].children:
            api_parameter["brackets"] = build_api_scale(parameter, "rate")
        elif "amount" in parameter.brackets[0].children:
            api_parameter["brackets"] = build_api_scale(parameter, "amount")
    elif isinstance(parameter, ParameterNode):
        if parameter.documentation:
            api_parameter["documentation"] = parameter.documentation.strip()
        api_parameter["subparams"] = {
            child_name: {
                "description": child.description,
            }
            for child_name, child in parameter.children.items()
        }
    return api_parameter

def build_parameters(tax_benefit_system, country_package_metadata):
    return {
        parameter.name.replace(".", "/"): build_api_parameter(
            parameter, country_package_metadata
        )
        for parameter in tax_benefit_system.parameters.get_descendants()
    }


# loading cash amount from the database
import datetime
import os
import sys
import pandas as pd

# *********** импортируем данные для подключения к базам
scriptpath = r"d:\Prestige\Python\Config"
sys.path.append(os.path.abspath(scriptpath))
from authorize import con_postgres_psycopg2

conpg = con_postgres_psycopg2()

def sql_rest_of_cash():
    return '''
        SELECT currency, kasa, (sum(amount_receipt) + sum(amount_expense)) AS amount
        FROM v_one_cach
        WHERE bank_account_cashier_key IN
            (SELECT DISTINCT
                bank_account_cashier_key
            FROM v_one_cach
            WHERE (doc_date >= '2022-01-01')
                AND (type_of_cash = 'Наличные')
            GROUP BY bank_account_cashier_key)
        GROUP BY currency, kasa
        ORDER BY currency, kasa;
    '''

def create_sql_universal(field, table_name, parameter):
    return '''
        SELECT DISTINCT %s
        FROM %s
        WHERE (type_of_cash = 'Наличные') AND %s
        ORDER BY %s
    ''' % (field, table_name, parameter, field)

def get_currencies(prm):
    # create sql of type currency
    field = "currency"
    parameter = "doc_date = '%s'" % prm
    table_name = 'v_one_cach'
    sql = create_sql_universal(field, table_name, parameter)
    return sql

def get_cash_expenses(date):
    sms = ''
    field = "currency"
    parameter_currency = "doc_date = '%s'" % date
    table_name = 'v_one_cach'
    try:
        conpg = con_postgres_psycopg2()
        sql = create_sql_universal(field, table_name, parameter_currency)
        currencies = pd.read_sql(sql, conpg)
        for idcurrency, currency in currencies.itertuples():
            field = "kasa"
            parameter_kasa = "%s AND currency = '%s'" % (parameter_currency, currency)
            sql = create_sql_universal(field, table_name, parameter_kasa)
            cash_boxs = pd.read_sql(sql, conpg)
            for id_cash_box, cash_box in cash_boxs.itertuples():
                field = "concat(client,': ', a_comment)" \
                        ", sum(amount_receipt + amount_expense) OVER (PARTITION BY currency, concat(client,': ', a_comment))"
                parameter_description = "%s AND kasa = '%s'" % (parameter_kasa, cash_box)
                sql = create_sql_universal(field, table_name, parameter_description)
                df = pd.read_sql(sql, conpg)
                sms_current = create_sms_movement(df)
                sms += '\n\n***** %s *****%s' % (cash_box, sms_current)

    except Exception as e:
        print("ERROR: OneC. %s" % e)

    finally:
        return sms

def create_sms_movement(df, sms=''):
    for row in df.itertuples():
        firm_name = row[1]
        amount = str("{:.2f}".format(row[2]))
        sms += "\n%s\n%s\n" % (firm_name, amount)

    return sms

def create_sms_rest(df):
    sms = ''
    for row in df.itertuples():
        firm_name = row.kasa
        currency = row.currency
        amount = str("{:.2f}".format(row.amount))
        if row.amount < 0:
            amount += ' (EKSI)'

        sms += "\n%s\n%s\n%s\n" % (firm_name, currency, amount)

    return sms

def main_one_c_cash_rest():
    # 1С - rest cash in 1C
    conpg = con_postgres_psycopg2()
    sql = sql_rest_of_cash()
    df = pd.read_sql(sql, conpg)
    sms = create_sms_rest(df)
    return sms

if __name__ == '__main__':
    # main_one_c_cash_rest()
    get_cash_expenses('01.02.2023')


# import the necessary packages
from threading import Thread
from multiprocessing import Process
import cv2
import YoloModel
import ArucoDetect

class WebcamVideoStream:
	def __init__(self, src=0, name="WebcamVideoStream",UseModel = False, UseAruco = False):
		# initialize the video camera stream and read the first frame
		# from the stream
		self.stream = cv2.VideoCapture(0)

		#self.stream = cv2.VideoCapture('1664152920.7081351basicvideo2.avi')
		self.stream.set(cv2.CAP_PROP_FRAME_WIDTH, 320)
		self.stream.set(cv2.CAP_PROP_FRAME_HEIGHT, 320)

		(self.grabbed, self.frame) = self.stream.read()

		# initialize the thread name
		self.name = name

		# initialize the variable used to indicate if the thread should
		# be stopped
		self.stopped = False
		self.UseModel = UseModel
		self.UseAruco = UseAruco
		self.Model = YoloModel.Yolo()
		self.Aruco = ArucoDetect.Aruco()

	def start(self):
		# start the thread to read frames from the video stream
		t = Thread(target=self.update, name=self.name, args=())
		t.daemon = True
		t.start()
		#t = Process(target=self.update, args=())
		#t.start()
		#t.join()
		#self.update()

		return self

	def update(self):
		# keep looping infinitely until the thread is stopped

		while True:
			# if the thread indicator variable is set, stop the thread
			if self.stopped:
				print("stop 4")
				cv2.destroyAllWindows()
				self.stream.release()
				return

			# otherwise, read the next frame from the stream
			(self.grabbed, frame) = self.stream.read()
			self.frame = frame

			#if(self.UseAruco):
			#	self.Aruco.update(frame)

			#if(self.UseModel):
			#	self.frame = self.Model.update(frame)

			#if(self.UseAruco):
			#	self.Aruco.draw(frame)

			#Display image
			#cv2.imshow('WebcamVideo',frame)
			#cv2.waitKey(1)

	def read(self):
		# return the frame most recently read
		return self.frame, self.grabbed

	def stop(self):
		# indicate that the thread should be stopped
		print("stop 3")
		self.stopped = True
		self.close()

Drone Payload Project/Pi Code/WebcamVideoStreamOverride.py


"""Rebuilding broken crowdsale contracts."""
import csv
import datetime
from io import StringIO

import pytest
from eth_utils import to_wei
from ethereum.tester import TransactionFailed
from web3.contract import Contract

from ico.tests.utils import time_travel
from ico.state import CrowdsaleState

@pytest.fixture
def token(empty_token):
    """Get a token with 0 initial issuance."""
    return empty_token

@pytest.fixture
def new_token(chain, team_multisig, token_name, token_symbol) -> Contract:
    """Get another token contract with 0 initial issuance."""

    args = [token_name, token_symbol, 0, 0, True]  # Owner set

    tx = {
        "from": team_multisig
    }

    contract, hash = chain.provider.deploy_contract('CrowdsaleToken', deploy_args=args, deploy_transaction=tx)
    return contract

@pytest.fixture
def start_time() -> int:
    """Start Apr 15th"""
    return int((datetime.datetime(2017, 4, 15, 16, 00) - datetime.datetime(1970, 1, 1)).total_seconds())

@pytest.fixture
def end_time(start_time) -> int:
    """Run 4 weeks."""
    return start_time + 4 * 7 * 24 * 3600

@pytest.fixture
def minimum_funding_goal() -> int:
    """What is our minimum funding goal."""
    return to_wei(7500, "ether")

@pytest.fixture
def cap() -> int:
    """What is our maximum tokens sold capacity."""
    return 4000000

@pytest.fixture
def sample_data(customer, customer_2):
    data = """
Address,Payment at,Tx hash,Tx index,Invested ETH,Received tokens
{},2017-04-13T16:01:46+00:00,0xf88780859cfde239e5898d036b685f5358d4b0a0f82e8cce26403c782f8a2e52,1,0.505,561
{},2017-04-13T16:02:38+00:00,0x1385320b9d693afad1dce05cb0f9c8c3c1bc017668d32ee2b69d4039fdaf5983,3,0.1,111
    """.strip().format(customer, customer_2)
    return list(csv.DictReader(StringIO(data)))

@pytest.fixture
def success_sample_data(customer, customer_2):
    """Enough to break the minimum funding goal"""
    data = """
Address,Payment at,Tx hash,Tx index,Invested ETH,Received tokens
{},2017-04-13T16:01:46+00:00,0xf88780859cfde239e5898d036b685f5358d4b0a0f82e8cce26403c782f8a2e52,1,0.505,561
{},2017-04-13T16:02:38+00:00,0x1385320b9d693afad1dce05cb0f9c8c3c1bc017668d32ee2b69d4039fdaf5983,3,0.1,111
{},2017-04-13T16:02:38+00:00,0x1385320b9d693afad1dce05cb0f9c8c3c1bc017668d32ee2b69d4039fdaf5984,4,7500,1111
    """.strip().format(customer, customer_2, customer_2)
    return list(csv.DictReader(StringIO(data)))

@pytest.fixture
def founder_allocation() -> float:
    """How much tokens are allocated to founders, etc."""
    return 0.2

def set_finalizer(chain, token, crowdsale, team_multisig, founder_allocation) -> Contract:
    # Create finalizer contract
    args = [
        token.address,
        crowdsale.address,
        int(founder_allocation * 10000),  # 20% for founders, bounties, etc.
        team_multisig,  # Who gets extra tokens
    ]
    contract, hash = chain.provider.deploy_contract('BonusFinalizeAgent', deploy_args=args)

    # Allow finalzier to do mint()
    token.transact({"from": team_multisig}).setMintAgent(contract.address, True)
    assert token.call().mintAgents(contract.address) == True

    token.transact({"from": team_multisig}).setReleaseAgent(contract.address)
    crowdsale.transact({"from": team_multisig}).setFinalizeAgent(contract.address)
    return contract

@pytest.fixture
def milestone_pricing(chain, start_time, end_time):
    """Milestone pricing, do not set presale collection contract."""

    week = 24*3600 * 7

    args = [
        [
            start_time + 0, to_wei("0.0009", "ether"),
            start_time + week*1, to_wei("0.0009", "ether"),
            end_time, 0,
        ],
    ]

    tx = {
        "gas": 4000000
    }
    contract, hash = chain.provider.deploy_contract('MilestonePricing', deploy_args=args, deploy_transaction=tx)
    return contract

@pytest.fixture
def original_crowdsale(chain, team_multisig, start_time, end_time, milestone_pricing, preico_cap, minimum_funding_goal, cap, token, founder_allocation) -> Contract:
    """Crowdsale that we are going to relaunch.

    This will reserve the release agent for the original crowdsale.
    """

    args = [
        token.address,
        milestone_pricing.address,
        team_multisig,
        start_time,
        end_time,
        minimum_funding_goal,
        cap
    ]

    tx = {
        "from": team_multisig,
    }

    contract, hash = chain.provider.deploy_contract('MintedTokenCappedCrowdsale', deploy_args=args, deploy_transaction=tx)

    assert contract.call().owner() == team_multisig
    assert not token.call().released()
    assert contract.call().maximumSellableTokens() == cap

    # Allow crowdsale contract to do mint()
    token.transact({"from": team_multisig}).setMintAgent(contract.address, True)
    assert token.call().mintAgents(contract.address) == True

    set_finalizer(chain, token, contract, team_multisig, founder_allocation)

    return contract

@pytest.fixture
def relaunched_crowdsale(chain, team_multisig, start_time, end_time, milestone_pricing, preico_cap, minimum_funding_goal, cap, original_crowdsale, new_token, founder_allocation) -> Contract:
    """Create a crowdsale with fixed contracts."""

    args = [
        new_token.address,
        milestone_pricing.address,
        team_multisig,
        start_time,
        end_time,
        minimum_funding_goal,
        cap
    ]

    tx = {
        "from": team_multisig,
    }

    contract, hash = chain.provider.deploy_contract('RelaunchedCrowdsale', deploy_args=args, deploy_transaction=tx)

    assert contract.call().owner() == team_multisig
    assert not new_token.call().released()
    assert contract.call().maximumSellableTokens() == cap

    # Allow crowdsale contract to do mint()
    new_token.transact({"from": team_multisig}).setMintAgent(contract.address, True)
    assert new_token.call().mintAgents(contract.address) == True
    set_finalizer(chain, new_token, contract, team_multisig, founder_allocation)

    return contract

def test_rebuild_failed_crowdsale_with_new_token(chain, original_crowdsale, token, new_token, relaunched_crowdsale, sample_data, team_multisig, customer, customer_2):
    """Rebuild a crowdsale that is not going to reach its minimum goal."""

    time_travel(chain, original_crowdsale.call().startsAt() + 1)
    assert original_crowdsale.call().getState() == CrowdsaleState.Funding
    assert relaunched_crowdsale.call().getState() == CrowdsaleState.Funding

    for data in sample_data:
        addr = data["Address"]
        wei = to_wei(data["Invested ETH"], "ether")
        original_crowdsale.transact({"from": addr, "value": wei}).buy()

    # We have a confirmation hash
    events = original_crowdsale.pastEvents("Invested").get()
    assert len(events) == 2
    e = events[-1]

    # Import old transactions from the multisig contract
    for data in sample_data:
        addr = data["Address"]
        wei = to_wei(data["Invested ETH"], "ether")
        tokens = int(data["Received tokens"])
        orig_txid = int(data["Tx hash"], 16)
        orig_tx_index = int(data["Tx index"])
        relaunched_crowdsale.transact({"from": team_multisig}).setInvestorDataAndIssueNewToken(addr, wei, tokens, orig_txid)

    # No double issuance for the same tx
    data = sample_data[0]
    addr = data["Address"]
    wei = to_wei(data["Invested ETH"], "ether")
    tokens = int(data["Received tokens"])
    orig_txid = int(data["Tx hash"], 16)
    orig_tx_index = int(data["Tx index"])
    with pytest.raises(TransactionFailed):
        relaunched_crowdsale.transact({"from": team_multisig}).setInvestorDataAndIssueNewToken(addr, wei, tokens, orig_txid)

    # Compare that both crowdsales and tokens look the same
    assert original_crowdsale.call().tokensSold() == relaunched_crowdsale.call().tokensSold()
    assert original_crowdsale.call().investedAmountOf(customer) == relaunched_crowdsale.call().investedAmountOf(customer)
    assert original_crowdsale.call().investedAmountOf(customer_2) == relaunched_crowdsale.call().investedAmountOf(customer_2)

    assert token.call().balanceOf(customer) == relaunched_crowdsale.call().tokenAmountOf(customer)
    assert token.call().balanceOf(customer_2) == relaunched_crowdsale.call().tokenAmountOf(customer_2)
    assert token.call().balanceOf(customer) == new_token.call().balanceOf(customer)
    assert token.call().balanceOf(customer_2) == new_token.call().balanceOf(customer_2)

    assert token.call().totalSupply() == new_token.call().totalSupply()

    time_travel(chain, original_crowdsale.call().endsAt() + 1)

    assert original_crowdsale.call().getState() == CrowdsaleState.Failure
    assert relaunched_crowdsale.call().getState() == CrowdsaleState.Failure
    relaunched_crowdsale.transact({"from": team_multisig, "value": to_wei(30, "ether")}).loadRefund()
    assert relaunched_crowdsale.call().getState() == CrowdsaleState.Refunding

    relaunched_crowdsale.transact({"from": customer}).refund()
    relaunched_crowdsale.transact({"from": customer_2}).refund()

    # No double refund
    with pytest.raises(TransactionFailed):
        relaunched_crowdsale.transact({"from": customer}).refund()

    with pytest.raises(TransactionFailed):
        original_crowdsale.transact({"from": customer}).refund()

def test_rebuild_success_crowdsale_with_new_token(chain, new_token, relaunched_crowdsale, success_sample_data, team_multisig, customer, customer_2):
    """Rebuild a crowdsale that reaches its minimum goal."""

    time_travel(chain, relaunched_crowdsale.call().startsAt() + 1)
    assert relaunched_crowdsale.call().getState() == CrowdsaleState.Funding

    # Import old transactions from the multisig contract
    for data in success_sample_data:
        addr = data["Address"]
        wei = to_wei(data["Invested ETH"], "ether")
        tokens = int(data["Received tokens"])
        orig_txid = int(data["Tx hash"], 16)
        # orig_tx_index = int(data["Tx index"])
        relaunched_crowdsale.transact({"from": team_multisig}).setInvestorDataAndIssueNewToken(addr, wei, tokens, orig_txid)

        assert relaunched_crowdsale.call().getRestoredTransactionStatus(orig_txid)

    # Compare that both crowdsales and tokens look the same
    assert relaunched_crowdsale.call().investorCount() == 2

    # We restored 3 events
    events = relaunched_crowdsale.pastEvents("RestoredInvestment").get()
    assert len(events) == 3

    assert new_token.call().balanceOf(customer_2) == 1222
    assert new_token.call().balanceOf(customer) == relaunched_crowdsale.call().tokenAmountOf(customer)
    assert new_token.call().balanceOf(customer_2) == relaunched_crowdsale.call().tokenAmountOf(customer_2)
    assert new_token.call().totalSupply() == relaunched_crowdsale.call().tokensSold()

    time_travel(chain, relaunched_crowdsale.call().endsAt() + 1)

    assert relaunched_crowdsale.call().getState() == CrowdsaleState.Success

    before_final = new_token.call().totalSupply()
    relaunched_crowdsale.transact({"from": team_multisig}).finalize()
    assert new_token.call().totalSupply() == int(before_final * 1.20)

    assert new_token.call().released()


"""
# 推荐系统模型
"""
import os
import logging
import math
import paddle
import paddle.nn as nn
import paddle.nn.functional as F

logger = logging.getLogger(__name__)

class MovieRecommendModel(nn.Layer):
    def __init__(self, use_poster, use_mov_title, use_mov_cat, use_age_job,
                 vocab_sizes={}, fc_sizes=[]):
        super(MovieRecommendModel, self).__init__()

        # 将传入的name信息和bool型参数添加到模型类中
        self.use_mov_poster = use_poster  # 计算电影信息特征时是否使用海报, 现模型不使用
        self.use_mov_title = use_mov_title
        self.use_usr_age_job = use_age_job
        self.use_mov_cat = use_mov_cat
        self.fc_sizes = fc_sizes

        usr_embedding_dim = 32
        gender_embeding_dim = 16
        age_embedding_dim = 16

        job_embedding_dim = 16
        mov_embedding_dim = 16
        category_embedding_dim = 16
        title_embedding_dim = 32

        logger.info("define network layer for embedding usr info")
        USR_ID_NUM = vocab_sizes["max_usr_id"] + 1
        # 对用户ID做映射，并紧接着一个Linear层
        self.usr_emb = nn.Embedding(num_embeddings=USR_ID_NUM, embedding_dim=usr_embedding_dim, sparse=False)
        self.usr_fc = nn.Linear(in_features=usr_embedding_dim, out_features=32)

        # 对用户性别信息做映射，并紧接着一个Linear层
        USR_GENDER_DICT_SIZE = 2
        self.usr_gender_emb = nn.Embedding(num_embeddings=USR_GENDER_DICT_SIZE, embedding_dim=gender_embeding_dim)
        self.usr_gender_fc = nn.Linear(in_features=gender_embeding_dim, out_features=16)

        # 对用户年龄信息做映射，并紧接着一个Linear层
        USR_AGE_DICT_SIZE = vocab_sizes["max_usr_age"] + 1  # +1 考虑0自然数
        self.usr_age_emb = nn.Embedding(num_embeddings=USR_AGE_DICT_SIZE, embedding_dim=age_embedding_dim)
        self.usr_age_fc = nn.Linear(in_features=age_embedding_dim, out_features=16)

        # 对用户职业信息做映射，并紧接着一个Linear层
        USR_JOB_DICT_SIZE = vocab_sizes["max_usr_job"] + 1
        self.usr_job_emb = nn.Embedding(num_embeddings=USR_JOB_DICT_SIZE, embedding_dim=job_embedding_dim)
        self.usr_job_fc = nn.Linear(in_features=job_embedding_dim, out_features=16)

        # 新建一个Linear层，用于整合用户数据信息
        self.usr_combined = nn.Linear(in_features=80, out_features=200)

        logger.info("define network layer for embedding usr info")
        MOV_DICT_SIZE = vocab_sizes["max_mov_id"] + 1
        self.mov_emb = nn.Embedding(num_embeddings=MOV_DICT_SIZE, embedding_dim=mov_embedding_dim)
        self.mov_fc = nn.Linear(in_features=mov_embedding_dim, out_features=32)

        # 对电影类别做映射
        CATEGORY_DICT_SIZE = vocab_sizes["movie_category_size"] + 1  # +1 考虑添加0类别
        self.mov_cat_emb = nn.Embedding(num_embeddings=CATEGORY_DICT_SIZE,
                                        embedding_dim=category_embedding_dim,
                                        sparse=False)
        self.mov_cat_fc = nn.Linear(in_features=category_embedding_dim, out_features=32)

        # 对电影名称做映射
        MOV_TITLE_DICT_SIZE = vocab_sizes["movie_title_size"] + 1
        self.mov_title_emb = nn.Embedding(num_embeddings=MOV_TITLE_DICT_SIZE,
                                          embedding_dim=title_embedding_dim,
                                          sparse=False)
        self.mov_title_conv = nn.Conv2D(in_channels=1, out_channels=1,
                                        kernel_size=(3, 1), stride=(2, 1), padding=0)
        self.mov_title_conv2 = nn.Conv2D(in_channels=1, out_channels=1,
                                         kernel_size=(3, 1), stride=1, padding=0)

        # 新建一个Linear层，用于整合电影特征
        self.mov_concat_embed = nn.Linear(in_features=96, out_features=200)

        # 增加全连接层深度提取特征
        user_sizes = [200] + self.fc_sizes
        acts = ["relu" for _ in range(len(self.fc_sizes))]
        self._user_layers = []
        for i in range(len(self.fc_sizes)):
            linear = nn.Linear(
                in_features=user_sizes[i],
                out_features=user_sizes[i + 1],
                weight_attr=paddle.ParamAttr(
                    initializer=paddle.nn.initializer.Normal(
                        std=1.0 / math.sqrt(user_sizes[i]))))
            self.add_sublayer("linear_user_%d" % i, linear)
            self._user_layers.append(linear)
            if acts[i] == "relu":
                act = nn.ReLU()
                self.add_sublayer("user_act_%d" % i, act)
                self._user_layers.append(act)

        # 电影特征和用户特征使用了不同的全连接层，不共享参数
        movie_sizes = [200] + self.fc_sizes
        acts = ["relu" for _ in range(len(self.fc_sizes))]
        self._movie_layers = []
        for i in range(len(self.fc_sizes)):
            linear = nn.Linear(
                in_features=movie_sizes[i],
                out_features=movie_sizes[i + 1],
                weight_attr=paddle.ParamAttr(
                    initializer=paddle.nn.initializer.Normal(
                        std=1.0 / math.sqrt(movie_sizes[i]))))
            self.add_sublayer("linear_movie_%d" % i, linear)
            self._movie_layers.append(linear)
            if acts[i] == "relu":
                act = nn.ReLU()
                self.add_sublayer("movie_act_%d" % i, act)
                self._movie_layers.append(act)

    def get_usr_feature(self, usr_var):
        """定义计算用户特征的前向运算过程"""
        # 获取到用户数据
        usr_id, usr_gender, usr_age, usr_job = usr_var
        # 将用户的ID数据经过embedding和Linear计算，得到的特征保存在feats_collect中
        feats_collect = []

        usr_id_feat = F.relu(self.usr_fc(self.usr_emb(usr_id)))
        feats_collect.append(usr_id_feat)

        # 计算用户的性别特征，并保存在feats_collect中
        usr_gender_feat = F.relu(self.usr_gender_fc(self.usr_gender_emb(usr_gender)))
        feats_collect.append(usr_gender_feat)

        # 选择是否使用用户的年龄-职业特征
        if self.use_usr_age_job:
            usr_age_feat = F.relu(self.usr_age_fc(self.usr_age_emb(usr_age)))
            feats_collect.append(usr_age_feat)

            usr_job_feat = F.relu(self.usr_job_fc(self.usr_job_emb(usr_job)))
            feats_collect.append(usr_job_feat)

        # 将用户的特征级联，并通过Linear层得到最终的用户特征
        usr_feat = paddle.concat(feats_collect, axis=-1)
        user_features = F.tanh(self.usr_combined(usr_feat))

        # 通过3层全链接层，获得用于计算相似度的用户特征和电影特征
        for n_layer in self._user_layers:
            user_features = n_layer(user_features)

        return user_features

    def get_movie_feature(self, mov_var):
        """定义电影特征的前向计算过程"""
        # 获得电影数据
        mov_id, mov_cat, mov_title, mov_poster = mov_var
        feats_collect = []
        # 获得batchsize的大小
        batch_size = mov_id.shape[0]
        # 计算电影ID的特征，并存在feats_collect中
        mov_id_feat = F.relu(self.mov_fc(self.mov_emb(mov_id)))
        feats_collect.append(mov_id_feat)

        # 如果使用电影的种类数据，计算电影种类特征的映射
        if self.use_mov_cat:
            # 计算电影种类的特征映射，对多个种类的特征求和得到最终特征
            mov_cat_feat = self.mov_cat_emb(mov_cat)
            mov_cat_feat = paddle.sum(mov_cat_feat, axis=1, keepdim=False)  # shape: [btc, feature_size]
            mov_cat_feat = F.relu(self.mov_cat_fc(mov_cat_feat))
            feats_collect.append(mov_cat_feat)

        if self.use_mov_title:
            mov_title_feat = self.mov_title_emb(mov_title)
            mov_title_feat = self.mov_title_conv2(F.relu(self.mov_title_conv(mov_title_feat)))
            mov_title_feat = paddle.sum(mov_title_feat, axis=2, keepdim=False)  # shape: [bat, 1, feature_size]
            mov_title_feat = F.relu(mov_title_feat)
            mov_title_feat = paddle.reshape(mov_title_feat, [batch_size, -1])
            feats_collect.append(mov_title_feat)

        # 使用一个全连接层，整合所有电影特征，映射为一个200维的特征向量
        mov_feat = paddle.concat(feats_collect, axis=-1)
        mov_features = F.tanh(self.mov_concat_embed(mov_feat))
        # 继续使用深度网络提取特征
        for n_layer in self._movie_layers:
            mov_features = n_layer(mov_features)

        return mov_features

    def forward(self, usr_var, mov_var):
        """定义个性化推荐算法的前向计算"""
        # 计算用户特征和电影特征
        user_features = self.get_usr_feature(usr_var)
        mov_features = self.get_movie_feature(mov_var)

        # 根据计算的特征计算相似度, reshape方便loss计算
        sim = F.common.cosine_similarity(user_features, mov_features).reshape([-1, 1])
        # 使用余弦相似度算子，计算用户和电影的相似程度
        # sim = F.cosine_similarity(user_features, mov_features, axis=1).reshape([-1, 1])
        # 将相似度扩大范围到和电影评分相同数据范围
        res = paddle.scale(sim, scale=5)

        return user_features, mov_features, res


#!python

from typing import Dict
import sys
import json
import pathlib
from PyQt5.QtCore import QUrl, Qt, pyqtSignal, QTimer, QByteArray
from PyQt5.QtMultimedia import QMediaPlayer, QMediaContent, QMediaPlaylist
from PyQt5.QtMultimediaWidgets import QVideoWidget
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QLabel, QPushButton, QHBoxLayout, QSlider, QVBoxLayout, QFileDialog, QScrollArea, QComboBox, QKeySequenceEdit, QGridLayout, QMessageBox
from PyQt5.QtGui import QIcon, QPixmap, QCloseEvent

# 静态全局配置
DEFAULT_CONFIG = pathlib.Path.home() / ".wmask"
DEFAULT_FOLDER_PATH = ""
DEFAULT_VOLUME = 30
DEFAULT_OPACITY = 20
DEFAULT_PLAY = False
DEFAULT_ACTIVE = False

# 应用主界面
class WmaskMain(QMainWindow):
    def __init__(self):
        super().__init__()
        # 全局参数
        self.folder_path = DEFAULT_FOLDER_PATH
        self.default_volume = DEFAULT_VOLUME
        self.default_opacity = DEFAULT_OPACITY
        self.default_play = DEFAULT_PLAY
        self.default_active = DEFAULT_ACTIVE
        # 主界面保持的数据
        self.playlist = set() # 媒体路径
        self.positions: Dict[str, int] = dict() # 媒体路径->进度
        self.volumes: Dict[str, int] = dict() # 媒体路径->音量(max:100)
        self.opacitys: Dict[str, int] = dict() # 媒体路径->不透明度(max:80)
        self.plays: Dict[str, bool] = dict() # 媒体路径->是否正在播放
        self.actives: Dict[str, bool] = dict() # 媒体路径->是否处于激活状态
        # 读取配置文件
        self.openConfig()
        # 主界面持有的 wmask组件句柄、wmask窗口句柄
        self.components: Dict[str, WmaskComponent] = dict()
        self.wmasks: Dict[str, Wmask] = dict()
        # 主界面设置
        self.setWindowTitle("Wmask")
        self.setWindowIcon(ICON_FAVICON)
        self.setFixedWidth(400)
        self.resize(400, 200)
        ### 》 窗体布局
        # 按钮群
        self.newButton = QPushButton("New", parent=self) # 添加媒体
        self.newButton.clicked.connect(self.newButtonOnClicked)
        # 按钮群 水平布局
        self.buttonLayout = QHBoxLayout()
        self.buttonLayout.addWidget(self.newButton)
        # wmask组件群 垂直布局
        self.componentLayout = QVBoxLayout()
        self.componentLayout.setAlignment(Qt.AlignmentFlag.AlignTop)
        self.componentLayout.setContentsMargins(0, 0, 0, 0)
        # wmask组件群 垂直布局实体组件
        self.componentWidget = QWidget()
        self.componentWidget.setLayout(self.componentLayout)
        # wmask组件群 垂直布局实体组件 垂直滑动区域
        self.componentScroll = QScrollArea(self)
        self.componentScroll.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOn)
        self.componentScroll.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
        self.componentScroll.setWidgetResizable(True)
        self.componentScroll.setWidget(self.componentWidget)
        # 主界面 垂直布局
        self.centralLayout = QVBoxLayout()
        self.centralLayout.setAlignment(Qt.AlignmentFlag.AlignTop)
        self.centralLayout.addLayout(self.buttonLayout)
        self.centralLayout.addWidget(self.componentScroll)
        # 主界面 垂直布局实体组件
        self.centralWidget = QWidget()
        self.centralWidget.setLayout(self.centralLayout)
        self.setCentralWidget(self.centralWidget)
        # 依此逐个载入wmask组件
        for i in self.playlist:
            self.addComponent(i)
        ### 《 窗体布局
        # 同步wmask视频进度到wmask组件进度滑动条
        self.syncPositionTimer = QTimer(parent=self)
        self.syncPositionTimer.setInterval(1000)
        self.syncPositionTimer.timeout.connect(self.syncPositionTimerOnTimeout)
        self.syncPositionTimer.start()

    def closeEvent(self, a0: QCloseEvent) -> None:
        self.saveConfig()
        playlist = self.playlist.copy()
        for i in playlist:
            self.deleteSlot(i)
        return super().closeEvent(a0)

    # 读取配置文件
    def openConfig(self, config=DEFAULT_CONFIG):
        if not pathlib.Path(config).is_file():
            return
        try:
            with open(config, "r") as fp:
                config_dict = json.load(fp)
        except:
            return
        def check(_key:str, _type:type, _default, _dict=config_dict):
            if _key in _dict and isinstance(_dict[_key], _type):
                return _dict[_key]
            else:
                return _default
        self.folder_path = check("folder_path", str, DEFAULT_FOLDER_PATH)
        self.default_volume = check("default_volume", int, DEFAULT_VOLUME)
        self.default_opacity = check("default_opacity", int, DEFAULT_OPACITY)
        self.default_play = check("default_play", bool, DEFAULT_PLAY)
        self.default_active = check("default_active", bool, DEFAULT_ACTIVE)
        playlist = check("playlist", list, [])
        def addMedia(mediaObj:dict):
            mediaPath = check("mediaPath", str, "", mediaObj)
            if mediaPath == "":
                return
            self.playlist.add(mediaPath)
            self.positions[mediaPath] = check("position", int, 0, mediaObj)
            self.volumes[mediaPath] = check("volume", int, self.default_volume, mediaObj)
            self.opacitys[mediaPath] = check("opacity", int, self.default_opacity, mediaObj)
            self.plays[mediaPath] = check("play", bool, self.default_play, mediaObj)
            self.actives[mediaPath] = check("active", bool, self.default_active, mediaObj)
        for mediaObj in playlist:
            addMedia(mediaObj)

    # 保存配置文件
    def saveConfig(self, config=DEFAULT_CONFIG):
        configObj = {}
        configObj["folder_path"] = self.folder_path
        configObj["default_volume"] = self.default_volume
        configObj["default_opacity"] = self.default_opacity
        configObj["default_play"] = self.default_play
        configObj["default_active"] = self.default_active
        configObj["playlist"] = []
        for i in self.playlist:
            mediaObj = {}
            mediaObj["mediaPath"] = i
            mediaObj["position"] = self.components[i].positionSlider.value()
            mediaObj["volume"] = self.components[i].volumeSlider.value()
            mediaObj["opacity"] = self.components[i].opacitySlider.value()
            mediaObj["play"] = self.components[i].playOn
            mediaObj["active"] = self.components[i].activeOn
            configObj["playlist"].append(mediaObj)
        with open(config, "w") as fp:
            json.dump(configObj, fp)

    ### 》 按钮群信号槽
    def newButtonOnClicked(self):
        return_lists, _ = QFileDialog.getOpenFileNames(self, "select media", self.folder_path, "Media Files (*.mp4 *.MP4 *.avi *.AVI *.mkv *.MKV *.webm *.WebM *.mov *.MOV *.flv *.FLV *.ogg *.OGG);;All Files (*.*)")
        if return_lists:
            self.folder_path = str(pathlib.Path(return_lists[-1]).parent)
        for i in return_lists:
            if i in self.playlist:
                continue
            self.playlist.add(i)
            self.positions[i] = 0
            self.volumes[i] = self.default_volume
            self.opacitys[i] = self.default_opacity
            self.plays[i] = self.default_play
            self.actives[i] = self.default_active
            self.addComponent(i)
    ### 《 按钮群信号槽

    # 添加wmask组件
    def addComponent(self, mediaPath:str):
        self.components[mediaPath] = WmaskComponent(mediaPath, self.positions[mediaPath], self.opacitys[mediaPath], self.volumes[mediaPath], self.plays[mediaPath], self.actives[mediaPath], parent=self)
        self.components[mediaPath].rateSignal.connect(self.rateSlot)
        self.components[mediaPath].playSignal.connect(self.playSlot)
        self.components[mediaPath].activeSignal.connect(self.activeSlot)
        self.components[mediaPath].deleteSignal.connect(self.deleteSlot)
        self.components[mediaPath].positionSignal.connect(self.positionSlot)
        self.components[mediaPath].volumeSignal.connect(self.volumeSlot)
        self.components[mediaPath].opactiySignal.connect(self.opacitySlot)
        if self.actives[mediaPath]:
            self.activeSlot(mediaPath, True)
        self.componentLayout.addWidget(self.components[mediaPath])

    ### 》 Wmask组件信号槽
    def rateSlot(self, mediaPath:str, value:float):
        if mediaPath in self.wmasks:
            self.wmasks[mediaPath].player.setPlaybackRate(value)

    def playSlot(self, mediaPath:str, play:bool):
        if mediaPath not in self.wmasks:
            return
        if play:
            self.wmasks[mediaPath].player.play()
        else:
            self.wmasks[mediaPath].player.pause()

    def activeSlot(self, mediaPath:str, active:bool):
        if active:
            self.wmasks[mediaPath] = Wmask(mediaPath, self.components[mediaPath].opacitySlider.value(), self.components[mediaPath].volumeSlider.value())
            self.wmasks[mediaPath].player.durationChanged.connect(lambda x: self.components[mediaPath].positionSlider.setMaximum(x) if x > 0 else None)
            self.wmasks[mediaPath].player.setPosition(self.components[mediaPath].positionSlider.value())
            self.wmasks[mediaPath].wmaskCloseSignal.connect(self.wmaskCloseSlot)
            self.wmasks[mediaPath].show()
            if self.components[mediaPath].playOn:
                self.wmasks[mediaPath].player.play()
        else:
            if mediaPath in self.wmasks:
                self.wmasks[mediaPath].deleteLater()
                del self.wmasks[mediaPath]

    def deleteSlot(self, mediaPath:str):
        if self.components[mediaPath].activeOn:
            self.components[mediaPath].activeButton.click()
        self.components[mediaPath].deleteLater()
        del self.components[mediaPath]

        self.playlist.remove(mediaPath)
        self.positions.pop(mediaPath)
        self.opacitys.pop(mediaPath)
        self.volumes.pop(mediaPath)
        self.plays.pop(mediaPath)
        self.actives.pop(mediaPath)

    def positionSlot(self, mediaPath:str, position:int):
        if mediaPath in self.components and self.components[mediaPath].activeOn:
            self.wmasks[mediaPath].player.setPosition(position)

    def volumeSlot(self, mediaPath:str, volume:int):
        if mediaPath in self.components and self.components[mediaPath].activeOn:
            self.wmasks[mediaPath].player.setVolume(volume)

    def opacitySlot(self, mediaPath:str, opacity:int):
        if mediaPath in self.components and self.components[mediaPath].activeOn:
            self.wmasks[mediaPath].setWindowOpacity(opacity / 100)
    ### 《 wmask组件信号槽

    # wmask信号槽
    def wmaskCloseSlot(self, mediaPath:str):
        if mediaPath in self.components and self.components[mediaPath].activeOn:
            self.components[mediaPath].activeButton.click()

    # 计时器信号槽
    def syncPositionTimerOnTimeout(self):
        for i in self.playlist:
            if self.components[i].activeOn and self.components[i].playOn:
                self.components[i].positionSlider.blockSignals(True)
                self.components[i].positionSlider.setValue(self.wmasks[i].player.position())
                self.components[i].positionSlider.blockSignals(False)

# wmask组件
class WmaskComponent(QWidget):
    # 信号
    rateSignal = pyqtSignal(str, float)
    playSignal = pyqtSignal(str, bool)
    activeSignal = pyqtSignal(str, bool)
    deleteSignal = pyqtSignal(str)
    positionSignal = pyqtSignal(str, int)
    volumeSignal = pyqtSignal(str, int)
    opactiySignal = pyqtSignal(str, int)

    def __init__(self, mediaPath:str, position:int, opacity:int, volume:int, play:bool, active:bool, parent):
        super().__init__(parent)
        self.mediaPath = mediaPath
        # 名称标签
        self.nameLabel = QLabel(pathlib.Path(mediaPath).name, parent=self)
        self.nameLabel.setToolTip(self.mediaPath)
        # 播放速度下拉列表框
        self.rateComboBox = QComboBox(parent=self)
        self.rateComboBox.setFixedWidth(80)
        self.rateComboBox.addItems(["0.25", "0.5", "1.0", "1.25", "1.5"])
        self.rateComboBox.setCurrentText("1.0")
        self.rateComboBox.currentTextChanged.connect(self.rateComboBoxOnCurrentTextChanged)
        # 播放/暂停键
        self.playOn = play
        self.playButton = QPushButton(parent=self)
        self.playButton.setFixedWidth(30)
        self.playButton.setIcon(ICON_MEDIA_PLAYBACK_PAUSE if play else ICON_MEDIA_PLAYBACK_START)
        self.playButton.clicked.connect(self.playButtonOnClicked)
        # 激活/关闭键
        self.activeOn = active
        self.activeButton = QPushButton(parent=self)
        self.activeButton.setFixedWidth(30)
        self.activeButton.setIcon(ICON_SYSTEM_SHUTDOWN if active else ICON_SYSTEM_RUN)
        self.activeButton.clicked.connect(self.activeButtonOnClicked)
        # 删除键
        self.deleteButton = QPushButton(parent=self)
        self.deleteButton.setFixedWidth(30)
        self.deleteButton.setIcon(ICON_WINDOW_CLOSE)
        self.deleteButton.clicked.connect(self.deleteButtonOnClicked)
        # 上面四个组件 水平布局
        self.hlayout = QHBoxLayout()
        self.hlayout.addWidget(self.nameLabel)
        self.hlayout.addWidget(self.rateComboBox)
        self.hlayout.addWidget(self.playButton)
        self.hlayout.addWidget(self.activeButton)
        self.hlayout.addWidget(self.deleteButton)
        # 进度
        self.positionLabel = QLabel("progress", parent=self)
        self.positionLabel.setFixedWidth(80)
        self.positionSlider = QSlider(Qt.Orientation.Horizontal, parent=self)
        self.positionSlider.setMinimum(0)
        self.positionSlider.setMaximum(2 * position)
        self.positionSlider.setSingleStep(1000)
        self.positionSlider.setValue(position)
        self.positionSlider.valueChanged.connect(lambda x: self.positionSignal.emit(self.mediaPath, x))
        # 进度 水平布局
        self.h1layout = QHBoxLayout()
        self.h1layout.addWidget(self.positionLabel)
        self.h1layout.addWidget(self.positionSlider)
        # 音量
        self.volumeLabel = QLabel("volume", parent=self)
        self.volumeLabel.setFixedWidth(80)
        self.volumeSlider = QSlider(Qt.Orientation.Horizontal, parent=self)
        self.volumeSlider.setMinimum(0)
        self.volumeSlider.setMaximum(100)
        self.volumeSlider.setSingleStep(1)
        self.volumeSlider.setValue(volume)
        self.volumeSlider.valueChanged.connect(lambda x: self.volumeSignal.emit(self.mediaPath, x))
        # 音量 水平布局
        self.h2layout = QHBoxLayout()
        self.h2layout.addWidget(self.volumeLabel)
        self.h2layout.addWidget(self.volumeSlider)
        # 不透明度
        self.opacityLabel = QLabel("opacity", parent=self)
        self.opacityLabel.setFixedWidth(80)
        self.opacitySlider = QSlider(Qt.Orientation.Horizontal, parent=self)
        self.opacitySlider.setMinimum(0)
        self.opacitySlider.setMaximum(80)
        self.opacitySlider.setSingleStep(1)
        self.opacitySlider.setValue(opacity)
        self.opacitySlider.valueChanged.connect(lambda x: self.opactiySignal.emit(self.mediaPath, x))
        # 不透明度 水平布局
        self.h3layout = QHBoxLayout()
        self.h3layout.addWidget(self.opacityLabel)
        self.h3layout.addWidget(self.opacitySlider)
        # 总 垂直布局
        self.vlayout = QVBoxLayout()
        self.vlayout.addLayout(self.hlayout)
        self.vlayout.addLayout(self.h1layout)
        self.vlayout.addLayout(self.h2layout)
        self.vlayout.addLayout(self.h3layout)
        self.setLayout(self.vlayout)
        # 窗体尺寸
        self.setFixedHeight(120)
        self.setFixedWidth(parent.width()-40)

        self.rateComboBox.setEnabled(self.activeOn)
        self.playButton.setEnabled(self.activeOn)

    ### 《 转发信号
    def rateComboBoxOnCurrentTextChanged(self, value:str):
        if not self.activeOn:
            return
        self.rateSignal.emit(self.mediaPath, float(value))

    def playButtonOnClicked(self):
        if not self.activeOn:
            return
        self.playButton.setIcon(ICON_MEDIA_PLAYBACK_START if self.playOn else ICON_MEDIA_PLAYBACK_PAUSE)
        self.playOn ^= True
        self.playSignal.emit(self.mediaPath, self.playOn)

    def activeButtonOnClicked(self):
        self.activeButton.setIcon(ICON_SYSTEM_RUN if self.activeOn else ICON_SYSTEM_SHUTDOWN)
        self.activeOn ^= True
        self.rateComboBox.setEnabled(self.activeOn)
        self.playButton.setEnabled(self.activeOn)
        self.activeSignal.emit(self.mediaPath, self.activeOn)

    def deleteButtonOnClicked(self):
        self.deleteSignal.emit(self.mediaPath)
    ### 》 转发信号

# wmask窗体
class Wmask(QWidget):
    wmaskCloseSignal = pyqtSignal(str)

    def __init__(self, mediaPath:str, opacity:int, volume:int):
        super().__init__()
        self.mediaPath = mediaPath
        # 设置全屏
        desktop = QApplication.desktop()
        screen_size = desktop.screenGeometry(desktop.screenNumber(self))
        self.resize(screen_size.width(), screen_size.height())
        # 窗体属性
        self.setWindowOpacity(opacity / 100) # 不透明度
        self.setAttribute(Qt.WidgetAttribute.WA_TransparentForMouseEvents, True) # 鼠标事件穿透
        self.setAttribute(Qt.WidgetAttribute.WA_OpaquePaintEvent) # 视频循环播放时，播完到重新开始不重绘，以防止闪屏
        self.flags = Qt.WindowType.FramelessWindowHint | Qt.WindowType.BypassWindowManagerHint | Qt.WindowType.WindowStaysOnTopHint # 无边框 | 键盘鼠标事件穿透 | 置顶窗体
        self.setWindowFlags(self.flags)
        # 视频输出组件
        self.video_widget = QVideoWidget(parent=self)
        self.video_widget.resize(self.width(), self.height())
        # 播放列表（其实只有单一视频，但为了循环播放，需要设置一个播放列表）
        self.playlist = QMediaPlaylist(parent=self)
        self.playlist.addMedia(QMediaContent(QUrl.fromLocalFile(self.mediaPath)))
        self.playlist.setPlaybackMode(QMediaPlaylist.Loop)
        # 播放器
        self.player = QMediaPlayer(parent=self)
        self.player.setPlaylist(self.playlist)
        self.player.setVideoOutput(self.video_widget)
        self.player.setVolume(volume)

    def closeEvent(self, a0: QCloseEvent) -> None:
        self.wmaskCloseSignal.emit(self.mediaPath)
        return super().closeEvent(a0)

# base64字符串转QIcon
def base64ToQIcon(_base64:bytes):
    qpixmap = QPixmap()
    qpixmap.loadFromData(QByteArray.fromBase64(_base64))
    return QIcon(qpixmap)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    # favicon
    ICON_FAVICON = base64ToQIcon(b"iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAACXBIWXMAAAAAAAAAAQCEeRdzAAACKklEQVR4nO2ZvUoDQRDHJzZqSh/AwhiNirWf2PoMVtr7GgE1aPQFLPyGdFa+gIUPYGXjJyRgDIIiaDQ6w87hJrlNNuvt3UbuDz849obN7Gbmn2UDECtWrFj/UQNIFikzWR4LKt66KIEq8s1UeSyoeOsqS8l4lAOMt66uX0DXl9AkUkE+mAqP6cQ70cQbyB0yjKT4OdciPscxKfuptVcGxC5uI31MnscyLeLzHBupEsghUkJmpXF6LvK7hE98sSE+Ms2ASOYI6ZHGVYmqFhaJvFJ5QsZ83jeWSrvSCl3UgLfIJqh3U25WneYOVeQ89yCcRyU5aaedRyW5bJxyngMQzjOnEe81rjPOMw0imWOodx6VnFoAff1bIJxnXDPeqRLynIcWoePjzjXxOrR3HllO2ego8ojsgF4ZOPVDRuWyD/rO49xRwtR5nDjM0VdPxwUT53HiOD2E3ICZ86gUqiOtIQ9g5jwqheZII/DrPP0a8brlEYojUbnsgXCeec34ThrUuiNN8QecwN+cRyWrjiQ7z4RmvElJWHMkcp5rnjgo51EpMEeiJl0FcVj7Ql5AlJFK8g2zzmWWSt4R5QLZRRaRXoN5YAlE0t51Xw05BXX9B3U9uII8S/NQ2S4bzANn0Hzh+gnCSv3kd0H7ilx2SMVnnqtuWsC7zzxvJguIqoQK0LyAgsE8dU1MO0kNNdgiPqi/idLIOYgNq/Fz2mCeSJVEFphkxLnEihXLpn4AChIW6yQNMxgAAAAASUVORK5CYII=")
    # 媒体播放键
    ICON_MEDIA_PLAYBACK_START = base64ToQIcon(b"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAATdEVYdFRpdGxlAE9wdGljYWwgRHJpdmU+Z7oMAAABg0lEQVQ4jcWTS0tCURDH5+jJezNNLKpv0AOKHlK0CVwFtesjRAs3PWgTtHKhmwiCFi1amASCLSRLK2+ZFhmtSoWgWhdooPgI70O795x2YaZluGhgFgPz//GfYQZRSqGRUDWkBgBcXoQuT28pAQ6rGLvZbJb+7IAQYurp7l0BtfwcDHMzdVmglH7mWeiEyrJMRVGgD0/30vkFdxMMHvWV91TmFweSJIGiyJDJpqGzo4sxDY+Ns1pd7Jg73AoEAq2/jsDzPBBCQCyK8JpKQjqbQgP9g8zI0KhFpqUXt8c1CwDoR4BCFJCKEmCMAavVIIg86PV69dTkdGuTCu84drcnyjW4EkAIAYwxMBoGmlkt6Fr0kM/nlf2wR8hlc0uL88uRmgCBFwAhBCzDgtHQBrJMqM/vLSUSSUcBi6vWBetb5Q6+OWA0LBgN7XAduSpG49FoURTmbLa1x2oLrAqIxaPvPv9BThAFy8b6preWsCpAhdCde8/F5TIFu9PprOsS0b8/U8OAD1i6yfAlA768AAAAAElFTkSuQmCC")
    # 媒体暂停键
    ICON_MEDIA_PLAYBACK_PAUSE = base64ToQIcon(b"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAATdEVYdFRpdGxlAE9wdGljYWwgRHJpdmU+Z7oMAAAA7ElEQVQ4jdWTwUoDMRRFz3sTZvoH6beIKIOFfpsLcSfoj4hYqFj8FWlcqMvJTJO4GA2t2lEYN75N8g7kcO8iklJizOio138hMNvLYnmzTilaABV1J/V8ulher1PCAoiom9Xz6V5BStHWRzNAWN7f2p5hDw+OERFWD3d2sELXdQC4p8d870/h5fU5s70C7z0hRpq2wXufmYhQlVVmA4KWEDY0vsH7NjMVoSyrzIYThIAxZieBqlJVk28TmM8CYCduLyhQ1d9U+Og7+ZIgxvhzgrDp3OXVhQUoCuMAYgju7PzUAph3tj3y///CaMEbabKLq8akpOcAAAAASUVORK5CYII=")
    # 媒体激活建
    ICON_SYSTEM_RUN = base64ToQIcon(b"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAA3NCSVQICAjb4U/gAAAACXBIWXMAAA3XAAAN1wFCKJt4AAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAABN0RVh0VGl0bGUAT3B0aWNhbCBEcml2ZT5nugwAAABgUExURf///wAAAP///4CAgFhbV1hbVp+gnXN0ca6uq3N1ca2trK+wrcfIxlVXU0JDQVVXU1VXU1ZYVGxuaoiKhcXFxM/PzuHh4OLi4O7u7PHx8fLz8vf39/j4+Pv7+/z8+/7+/mcCE4sAAAAQdFJOUwABAQKzt/b6+vv7+/z9/v7YPlFDAAAAdUlEQVQYlXWOWQ6AIAwFAfeVQl1QVO5/SxsTAUN8f22mb8qYDyKyOJk2OotmMe5uH0Xg9dZW7ab9FRrXiMYZ/CU+HY9PAVlAeR/MK+3XGV5WLsdlr2ORoe0sh/Ksi+CzwMFOPCWSDtqQRZCl67vH4v/IeQ6K3yejC9e2pE6uAAAAAElFTkSuQmCC")
    # 媒体失活键
    ICON_SYSTEM_SHUTDOWN = base64ToQIcon(b"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAA3NCSVQICAjb4U/gAAAACXBIWXMAAA3XAAAN1wFCKJt4AAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAANhQTFRFnZ2dnp6eoKCgn5+fnZ2dnJyc0NDQ09PTAAAABQUFDxAPJicmQ0RBX2BdYGFgaGhodHR0e314iIqFiYmJjpCLj5GMm5ubsbKwsrKys7Ozu7u7vL+4vb68wMDAxMTExcfCxsjDyMjIzMzMz8/P0dHR1dXV1tbW19fX2NjY2dnZ3d3d3t7e39/f4ODg4eHh4+Pj5OTk5eXl5ubm5+fn6Ojo6enp6urq6+vr7Ozs7e3t7u7u7+/v8PDw8fHx8vLy8/Pz9PT09vb2+vr6+/v7/Pz8/f39/v7+////R6AftQAAAAh0Uk5TGqamp/n6/f1ShpYZAAAAqUlEQVQYV12Pu41CQRAEu3dm3xNIGDznQjiPECB3QsDHIQAQAsQdOx+MBQzaLJVKakLKEu+dwpWylg/wbYhuzjYCQKZf7r8HnaRNj+zC7CSTAiVt90hwWLEAChSLVguiRXbAdFZA3IPd8GAl8j+sdqM5fwDc3IZutNARgIa9GhZcKIyRvUFP2TeouHUA43gNFLEEoMeQ+WU+/AmlLSSOLHVd3t8Q28bv+09M609MRKtpUAAAAABJRU5ErkJggg==")
    # wmask组件删除键
    ICON_WINDOW_CLOSE = base64ToQIcon(b"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAA3NCSVQICAjb4U/gAAAACXBIWXMAAA3XAAAN1wFCKJt4AAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAALpQTFRF////YWRfYGNgX19dX2FdYWFdXmBcYGNcYGReYmRgYWNfYGJeYGJcYGJeYmReYmRgYWNdYmRgYGJeYGReYmReYWNfX2FdYGJeYWJfY2VgYmRgY2ZhYmReY2ZhZGZhYGRffH55enx2en13e313fH55f4F8gIJ9gIJ+g4WAhIaBio2Gi42IfH55fYB6gYN9gYR9g4WAhYeChomDio2IsLOrsbSsuby0ur21ur62wMS8wcS8wsa+w8a+x8vDi9cj2gAAADR0Uk5TAG5vdnZ2d3d4eHl6fX19fX5/gICAhIaSmdnd3eDh4uTs7e3t7e3t7e3t7e3u7u7u7u7u7ttMubAAAABxSURBVBiVY2AgC4jJc4IoZnlRqICUqa4QAwOPkokkVIBF11xPiEfJVIURpkfAwNJIzVSHA2GKoLGVmT4XkrH82jYWquwIPp+mrZaGqSJchFXd2lCEV9lUkQkqIGemIQy0VsFUBiogIcsNotikxcnzGAAVDQmLdEUqbgAAAABJRU5ErkJggg==")
    wmask_main = WmaskMain()
    wmask_main.show()
    sys.exit(app.exec_())


#coding=utf-8
#./node_modules/.bin/chromedriver --verbose --log-path=chromedriver.log
# electron .  --remote-debugging-port=9200  --nokiosk   --http

from selenium import webdriver
from selenium.webdriver.chrome.options import Options

chrome_options = Options()
chrome_options.add_experimental_option("debuggerAddress", "127.0.0.1:9200")

driver = webdriver.Chrome(options=chrome_options)

executor_url = driver.command_executor._url
session_id = driver.session_id
print(session_id)
print(executor_url)
driver.get('https://www.baidu.com')
# driver.find_element_by_id("set_button1").click()

driver2 = webdriver.Remote(command_executor=executor_url, desired_capabilities={})
driver2.session_id = session_id
print(driver2.current_url)


import scrapy
from scrapy_selenium import SeleniumRequest
from selenium import webdriver
import pandas as pd
from time import sleep

class QuotesSpider(scrapy.Spider):
  # driver = webdriver.Chrome()
  # driver.get('https://quotes.toscrape.com/page/1/')
  # sleep(10)

  name = "quotes"
  allowed_domains = ["quotes.toscrape.com"]
  # start_urls = ["https://quotes.toscrape.com"]

  def start_requests(self):
    url='https://quotes.toscrape.com/'
    yield SeleniumRequest(
      url=url,
      callback=self.parse,
      wait_time=10
    )

  def parse(self, response):
      print('===== parse(self, response) =====')
      # print(response)
      # r = response.css('h1').get()
      # t = response.css('h1 > a::text').get()
      # print(r)
      # print(t)

      for quote in response.css('div.quote'):
        d = {
            'text': quote.css('span.text::text').get(),
            'author': quote.css('small.author::text').get(),
            'tags': quote.css('div.tags a.tag::text').getall(),
        }
        # print(d)
        yield d

      next_page = response.css('li.next a::attr(href)').get()
      print(f'=========={next_page}==========')
      if next_page is not None:
        yield response.follow(next_page, callback=self.parse)

      print('===========')

  # driver.close()

      # pass


import json

import pandas as pd

df = pd.read_csv('./train_finer.csv')
df_result = pd.DataFrame(columns=['text', 'annotation'])

with open('./labels.json', 'r') as JSON:
    label_dict = json.load(JSON)

xbrl_label_dict = {v: k for k, v in label_dict.items()}

f_train = open('./train.txt', 'w')
tokens_length = []
for i, row in df.iterrows():
    tokens = eval(row['tokens'])
    tags = eval(row['ner_tags'])

    #if len(tokens) <= 50:

    for token_index in range(len(tokens)):
        f_train.write(tokens[token_index] + ' ' + xbrl_label_dict[tags[token_index]])
        f_train.write('\n')
        f_train.write('\n')

# print(set(sorted(tokens_length)))


import torch
import torch.nn as nn
import torch.nn.functional as F

class CustomModelLoc(nn.Module):
  def __init__(self, num_classes):
    super(CustomModelLoc, self).__init__()
    self.conv1 = nn.Conv2d(3, 8, 3, padding=1)
    self.conv2 = nn.Conv2d(8, 16, 3, padding=1)
    self.conv3 = nn.Conv2d(16, 32, 3, padding=1)
    self.conv4 = nn.Conv2d(32, 64, 3, padding=1)
    self.pool = nn.MaxPool2d(2, 2)
    self.norm1 = nn.BatchNorm2d(3)
    self.norm2 = nn.BatchNorm2d(8)
    self.norm3 = nn.BatchNorm2d(16)
    self.norm4 = nn.BatchNorm2d(32)
    self.fc1 = nn.Linear(64* 24* 24, 128)
    self.fc2 = nn.Linear(132, 64)
    self.fc3 = nn.Linear(64, num_classes)

  def forward(self, img, data):
    img = self.pool(self.conv1(F.relu(self.norm1(img))))
    img = self.pool(self.conv2(F.relu(self.norm2(img))))
    img = self.pool(self.conv3(F.relu(self.norm3(img))))
    img = self.pool(self.conv4(F.relu(self.norm4(img))))
    img = img.view(img.size(0), -1)
    img = F.relu(self.fc1(img))
    out = torch.cat((img, data), 1)
    out = F.relu(self.fc2(out))
    out = self.fc3(out)
    return out


import multiprocessing
from collections import OrderedDict
from typing import Dict, List, Optional

import ripyl.protocol.uart as uart
import ripyl.streaming as stream
import ripyl.util.plot as rplot

CHANNEL_COLOR: Dict[int, str] = {0: 'orange', 1: 'blue'}
BITS: int = 8
PARITY: Optional[str] = None
STOP_BITS: int = 1

class UartPlotter(object):

    def __init__(self, samples: Dict[int, List[float]], sample_period: float):
        self._processes: List[multiprocessing.Process] = []
        self._samples: Dict[int, List[float]] = samples
        self._sample_period: float = sample_period

    def __enter__(self, *args, **kwargs):
        self.__init__(*args, **kwargs)
        return self

    @staticmethod
    def decoder_process(channel, data, period):
        print(f"Decoding channel : {channel}")

        txd = stream.samples_to_sample_stream(raw_samples=data, sample_period=period)
        records = list(uart.uart_decode(stream_data=txd, bits=BITS, parity=PARITY, stop_bits=STOP_BITS))
        success = True
        for rec in records:
            if rec.nested_status() != stream.StreamStatus.Ok:
                success = False
                print(f"Failed to decode record : {rec}")
                break
        if success:
            txd = stream.samples_to_sample_stream(raw_samples=data, sample_period=period)
            channels = OrderedDict([(f'CHANNEL {channel} : {CHANNEL_COLOR[channel]} (V)', txd)])
            title = "UART debug"
            plotter = rplot.Plotter()
            plotter.plot(channels=channels, annotations=records, title=title,
                         label_format=stream.AnnotationFormat.Text)
            plotter.show()

    def plot(self):
        for name, data in self._samples.items():
            self._processes.append(multiprocessing.Process(target=self.decoder_process,
                                                           args=(name, data, self._sample_period)))
            self._processes[-1].start()

    def __del__(self):
        for process in self._processes:
            process.join()

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.__del__()


"""
If we wanted to do pages as well as just the link title, we could:

from BeautifulSoup import BeautifulSoup
from urllib import urlopen
soup = BeautifulSoup(urlopen("<<<url>>>").read())
contents = ''.join(soup.findAll(text=True))

to extract the text, then throw everything in the classifier

"""
"""
User clicks an arrow, key + direction are ajax'd to /vote. vote trains the classifier, then
calls Reload which sends info back out through ajax to the page
"""
"""
user clicks down on a link, it fades out, we request a bunch of new new articles from the db.
for each article we classify it, and if it fills the threshold we push it to the user.

"""

import os
import datetime
import simplejson as json
import urllib2
from logging import info as log
from google.appengine.ext import db
from google.appengine.ext import webapp
from google.appengine.ext.webapp import template
from google.appengine.api import users
from google.appengine.api import taskqueue

from classifier import *
from models import *

class Vote(webapp.RequestHandler):
    def __init__(self):

        # Load user
        user = users.get_current_user()
        self.user = db.GqlQuery("SELECT * FROM User WHERE user_id = '%s'" % user.user_id()).get()

        # Instantiate the classifier
        self.cl = naivebayes(self.user, getwords)

        self.cl.setthreshold('bad', 2.0)

    def reload(self, user):
        '''
        pull out a bunch of entries. classify each one. take the strongest
        one corresponding with 'up' and display it.

        make sure not to pull any that have already been voted on, OR
        are already being displayed.
        '''

        count = 0
        down = True
        while down and count < 100:
            #print count
            count += 10
            posts = db.GqlQuery("SELECT * FROM Node ORDER BY created, points ASC").fetch(100)
            for p in posts:
                cat = self.cl.classify(p.title, default='unknown')
                log(cat)
                if cat == 'up':
                    log('****FOUND ONE**** %s' %p.title)
                    return p

        log('couldnt find anything')
        return db.GqlQuery("SELECT * FROM Node ORDER BY created, points ASC").get()
        #return story

    def get(self):
        user = self.user

        # Load story
        key = self.request.get("key")
        story = db.get(key)

        # Which direction was clicked?
        dir = str(self.request.get("dir"))

        log("WHOOOOOOOOOOOOOOOOOOOOOOOA %s"  %len(self.request.get("test")))

        # Save the story's key
        user_stories = user.stories.setdefault(dir, [])
        user.stories[dir].append(story.key())
        user.put()

        log('TRAINING:  "%s" | %s' %(story.title, dir))
        self.cl.train(story.title, dir)

        newstory = self.reload(user).to_dict()
        log(newstory)
        self.response.out.write(json.dumps(newstory))

        #self.response.out.write(
        # Set the Threshold

        #print cl.classify('rabbit', default='unknown')
        #print cl.classify('money', default='unknown')
        #print cl.classify('money', default='unknown')
        #print cl.classify('money', default='unknown')
        #self.redirect('/')

class MainPage(webapp.RequestHandler):
    def get(self):
        temp_user = users.get_current_user()
        if temp_user:
            user = db.GqlQuery("SELECT * FROM User WHERE user_id = '%s'" % temp_user.user_id()).get()
            if not user:
                new_user = User(user = temp_user,
                                user_id = temp_user.user_id(),
                                email = temp_user.email())
                new_user.put()
                user = new_user

            posts = db.GqlQuery("SELECT * FROM Node ORDER BY points DESC LIMIT 10")
            template_values = {'user': users.get_current_user(),
                               'logout_url': users.create_logout_url("/"),
                               'posts': posts}

            self.response.out.write(template.render('static/index.html', template_values))
        else:
            self.redirect(users.create_login_url(self.request.uri))

class ScrapeHandler(webapp.RequestHandler):
    def get(self):
        if not db.GqlQuery("SELECT * FROM StopWord").get():
            import stopwords as s
            db.put([StopWord(word = w) for w in s.words()])

        for x in range(10):
            taskqueue.add(url="/scrape_bot", params={'start': (x*100)})

class ScrapeBot(webapp.RequestHandler):
    def post(self):
            base = 'http://api.thriftdb.com/api.hnsearch.com/items/_search?'
            url = base + '%s%s%s' % ('&filter[fields][create_ts]=[NOW-48HOURS%20TO%20NOW]',
                                     '&limit=100', '&filter[fields][type]=submission')
            req = url + '&start=%s' % self.request.get("start")
            log('URL - %s' %req)
            hn_url = "http://news.ycombinator.com/"
            response = urllib2.urlopen(req)
            content = json.loads(response.read())
            for item in content['results']:
                if not db.GqlQuery("SELECT * FROM Node WHERE hn_id = %s" % item['item']['id']).get():
                    i = item['item']
                    scraped_content = Node(hn_id = i['id'], type = i['type'],
                                           url = i['url'] if i['url'] else hn_url + "item?id=%s" % id,
                                           domain = i['domain'] if i['domain'] else hn_url,
                                           title = i['title'], commentcount = i['num_comments'],
                                           username = i['username'], points = i['points'])
                    scraped_content.put()


from rest_framework import serializers
from django.urls.resolvers import RegexPattern

class URLSerializer(serializers.Serializer):
    # Define fields for pattern names and URLs
    def to_representation(self, instance):
        current_domain = self.context['request'].build_absolute_uri('/')[:-1]

        urls = {}
        for pattern in instance:
            # if isinstance(pattern, RegexPattern):  # Checking for RegexPattern to avoid errors
            if hasattr(pattern, 'name'):
                urls[pattern.name] = f'{current_domain}/{pattern.pattern}'
            else:
                urls[str(pattern)] = f'{current_domain}/{pattern.pattern}'

        return urls


from django.core.exceptions import ValidationError
from django.core.management.base import BaseCommand

from microlearning import scraper
from microlearning.models import Article

class Command(BaseCommand):
    help = 'Parse and save articles from medscape'

    def handle(self, *args, **kwargs):
        medscape_scraper = scraper.MedscapeScraper()

        for category, name in Article.ARTICLE_TYPES:
            self.stdout.write('Start parsing {} category'.format(name))

            articles = medscape_scraper.get_articles_by_category(category)

            self.stdout.write('Found {} articles'.format(len(articles)))

            added_count, not_unique_count = 0, 0
            for item in articles:
                article = scraper.create_article(item, category)

                try:
                    article.validate_unique()

                    parsed_article = medscape_scraper.get_full_article_by_url(item['url'])

                    article = scraper.create_article(parsed_article, category)
                    article.save()

                    added_count += 1
                except ValidationError:
                    not_unique_count += 1

            self.stdout.write('Added: {}. Not unique: {}'.format(added_count, not_unique_count))


import re
import time
from datetime import timedelta
from typing import Optional

import numpy as np
from pponnxcr.predict_system import BoxedResult

import module.config.server as server
from module.base.button import ButtonWrapper
from module.base.decorator import cached_property
from module.base.utils import area_pad, corner2area, crop, float2str
from module.exception import ScriptError
from module.logger import logger
from module.ocr.keyword import Keyword
from module.ocr.models import OCR_MODEL, TextSystem
from module.ocr.utils import merge_buttons

class OcrResultButton:
    def __init__(self, boxed_result: BoxedResult, matched_keyword: Optional[Keyword]):
        """
        Args:
            boxed_result: BoxedResult from ppocr-onnx
            matched_keyword: Keyword object or None
        """
        self.area = boxed_result.box
        self.search = area_pad(self.area, pad=-20)
        # self.color =
        self.button = boxed_result.box

        if matched_keyword is not None:
            self.matched_keyword = matched_keyword
            self.name = str(matched_keyword)
        else:
            self.matched_keyword = None
            self.name = boxed_result.ocr_text

        self.text = boxed_result.ocr_text
        self.score = boxed_result.score

    def __str__(self):
        return self.name

    __repr__ = __str__

    def __eq__(self, other):
        return str(self) == str(other)

    def __hash__(self):
        return hash(self.name)

    def __bool__(self):
        return True

    @property
    def is_keyword_matched(self) -> bool:
        return self.matched_keyword is not None

class Ocr:
    # Merge results with box distance <= thres
    merge_thres_x = 0
    merge_thres_y = 0

    def __init__(self, button: ButtonWrapper, lang=None, name=None):
        """
        Args:
            button:
            lang: If None, use in-game language
            name: If None, use button.name
        """
        if lang is None:
            lang = server.lang
        if name is None:
            name = button.name

        self.button: ButtonWrapper = button
        self.lang: str = lang
        self.name: str = name

    @cached_property
    def model(self) -> TextSystem:
        return OCR_MODEL.get_by_lang(self.lang)

    def pre_process(self, image):
        """
        Args:
            image (np.ndarray): Shape (height, width, channel)

        Returns:
            np.ndarray: Shape (width, height)
        """
        return image

    def after_process(self, result):
        """
        Args:
            result (str): '第二行'

        Returns:
            str:
        """
        if result.startswith('UID'):
            result = 'UID'
        return result

    def format_result(self, result):
        """
        Will be overriden.
        """
        return result

    def _log_change(self, attr, func, before):
        after = func(before)
        if after != before:
            logger.attr(f'{self.name} {attr}', f'{before} -> {after}')
        return after

    def ocr_single_line(self, image, direct_ocr=False):
        # pre process
        start_time = time.time()
        if not direct_ocr:
            image = crop(image, self.button.area)
        image = self.pre_process(image)
        # ocr
        result, _ = self.model.ocr_single_line(image)
        # after proces
        result = self._log_change('after', self.after_process, result)
        result = self._log_change('format', self.format_result, result)
        logger.attr(name='%s %ss' % (self.name, float2str(time.time() - start_time)),
                    text=str(result))
        return result

    def ocr_multi_lines(self, image_list):
        # pre process
        start_time = time.time()
        image_list = [self.pre_process(image) for image in image_list]
        # ocr
        result_list = self.model.ocr_lines(image_list)
        result_list = [(result, score) for result, score in result_list]
        # after process
        result_list = [(self.after_process(result), score) for result, score in result_list]
        result_list = [(self.format_result(result), score) for result, score in result_list]
        logger.attr(name="%s %ss" % (self.name, float2str(time.time() - start_time)),
                    text=str([result for result, _ in result_list]))
        return result_list

    def filter_detected(self, result: BoxedResult) -> bool:
        """
        Return False to drop result.
        """
        return True

    def detect_and_ocr(self, image, direct_ocr=False) -> list[BoxedResult]:
        """
        Args:
            image:
            direct_ocr: True to ignore `button` attribute and feed the image to OCR model without cropping.

        Returns:

        """
        # pre process
        start_time = time.time()
        if not direct_ocr:
            image = crop(image, self.button.area)
        image = self.pre_process(image)
        # ocr
        results: list[BoxedResult] = self.model.detect_and_ocr(image)
        # after proces
        for result in results:
            if not direct_ocr:
                result.box += self.button.area[:2]
            result.box = tuple(corner2area(result.box))

        results = [result for result in results if self.filter_detected(result)]
        results = merge_buttons(results, thres_x=self.merge_thres_x, thres_y=self.merge_thres_y)
        for result in results:
            result.ocr_text = self.after_process(result.ocr_text)

        logger.attr(name='%s %ss' % (self.name, float2str(time.time() - start_time)),
                    text=str([result.ocr_text for result in results]))
        return results

    def _match_result(
            self,
            result: str,
            keyword_classes,
            lang: str = None,
            ignore_punctuation=True,
            ignore_digit=True):
        """
        Args:
            result (str):
            keyword_classes: A list of `Keyword` class or classes inherited `Keyword`

        Returns:
            If matched, return `Keyword` object or objects inherited `Keyword`
            If not match, return None
        """
        if not isinstance(keyword_classes, list):
            keyword_classes = [keyword_classes]

        # Digits will be considered as the index of keyword
        if ignore_digit:
            if result.isdigit():
                return None

        # Try in current lang
        for keyword_class in keyword_classes:
            try:
                matched = keyword_class.find(
                    result,
                    lang=lang,
                    ignore_punctuation=ignore_punctuation
                )
                return matched
            except ScriptError:
                continue

        return None

    def matched_single_line(
            self,
            image,
            keyword_classes,
            lang: str = None,
            ignore_punctuation=True
    ) -> OcrResultButton:
        """
        Args:
            image: Image to detect
            keyword_classes: `Keyword` class or classes inherited `Keyword`, or a list of them.
            lang:
            ignore_punctuation:

        Returns:
            OcrResultButton: Or None if it didn't matched known keywords.
        """
        result = self.ocr_single_line(image)

        result = self._match_result(
            result,
            keyword_classes=keyword_classes,
            lang=lang,
            ignore_punctuation=ignore_punctuation,
        )

        logger.attr(name=f'{self.name} matched',
                    text=result)
        return result

    def matched_multi_lines(
            self,
            image_list,
            keyword_classes,
            lang: str = None,
            ignore_punctuation=True
    ) -> list[OcrResultButton]:
        """
        Args:
            image_list:
            keyword_classes: `Keyword` class or classes inherited `Keyword`, or a list of them.
            lang:
            ignore_punctuation:

        Returns:
            List of matched OcrResultButton.
            OCR result which didn't matched known keywords will be dropped.
        """
        results = self.ocr_multi_lines(image_list)

        results = [self._match_result(
            result,
            keyword_classes=keyword_classes,
            lang=lang,
            ignore_punctuation=ignore_punctuation,
        ) for result in results]
        results = [result for result in results if result.is_keyword_matched]

        logger.attr(name=f'{self.name} matched',
                    text=results)
        return results

    def _product_button(
            self,
            boxed_result: BoxedResult,
            keyword_classes,
            lang: str = None,
            ignore_punctuation=True,
            ignore_digit=True
    ) -> OcrResultButton:
        if not isinstance(keyword_classes, list):
            keyword_classes = [keyword_classes]

        matched_keyword = self._match_result(
            boxed_result.ocr_text,
            keyword_classes=keyword_classes,
            lang=lang,
            ignore_punctuation=ignore_punctuation,
            ignore_digit=ignore_digit,
        )
        button = OcrResultButton(boxed_result, matched_keyword)
        return button

    def matched_ocr(self, image, keyword_classes, direct_ocr=False) -> list[OcrResultButton]:
        """
        Args:
            image: Screenshot
            keyword_classes: `Keyword` class or classes inherited `Keyword`, or a list of them.
            direct_ocr: True to ignore `button` attribute and feed the image to OCR model without cropping.

        Returns:
            List of matched OcrResultButton.
            OCR result which didn't matched known keywords will be dropped.
        """
        results = self.detect_and_ocr(image, direct_ocr=direct_ocr)

        results = [self._product_button(result, keyword_classes) for result in results]
        results = [result for result in results if result.is_keyword_matched]

        logger.attr(name=f'{self.name} matched',
                    text=results)
        return results

class Digit(Ocr):
    def __init__(self, button: ButtonWrapper, lang='en', name=None):
        super().__init__(button, lang=lang, name=name)

    def format_result(self, result) -> int:
        """
        Returns:
            int:
        """
        result = super().after_process(result)
        logger.attr(name=self.name, text=str(result))

        res = re.search(r'(\d+)', result)
        if res:
            return int(res.group(1))
        else:
            logger.warning(f'No digit found in {result}')
            return 0

class DigitCounter(Ocr):
    def __init__(self, button: ButtonWrapper, lang='en', name=None):
        super().__init__(button, lang=lang, name=name)

    def format_result(self, result) -> tuple[int, int, int]:
        """
        Do OCR on a counter, such as `14/15`, and returns 14, 1, 15

        Returns:
            int:
        """
        result = super().after_process(result)
        logger.attr(name=self.name, text=str(result))

        res = re.search(r'(\d+)/(\d+)', result)
        if res:
            groups = [int(s) for s in res.groups()]
            current, total = int(groups[0]), int(groups[1])
            # current = min(current, total)
            return current, total - current, total
        else:
            logger.warning(f'No digit counter found in {result}')
            return 0, 0, 0

class Duration(Ocr):
    @classmethod
    def timedelta_regex(cls, lang):
        regex_str = {
            'cn': r'^(?P<prefix>.*?)'
                  r'((?P<days>\d{1,2})\s*天\s*)?'
                  r'((?P<hours>\d{1,2})\s*小时\s*)?'
                  r'((?P<minutes>\d{1,2})\s*分钟\s*)?'
                  r'((?P<seconds>\d{1,2})\s*秒)?'
                  r'(?P<suffix>[^天时钟秒]*?)$',
            'en': r'^(?P<prefix>.*?)'
                  r'((?P<days>\d{1,2})\s*d\s*)?'
                  r'((?P<hours>\d{1,2})\s*h\s*)?'
                  r'((?P<minutes>\d{1,2})\s*m\s*)?'
                  r'((?P<seconds>\d{1,2})\s*s)?'
                  r'(?P<suffix>[^dhms]*?)$'
        }[lang]
        return re.compile(regex_str)

    def after_process(self, result):
        result = super().after_process(result)
        result = result.strip('.,。，')
        result = result.replace('Oh', '0h').replace('oh', '0h')
        return result

    def format_result(self, result: str) -> timedelta:
        """
        Do OCR on a duration, such as `18d 2h 13m 30s`, `2h`, `13m 30s`, `9s`

        Returns:
            timedelta:
        """
        matched = self.timedelta_regex(self.lang).search(result)
        if not matched:
            return timedelta()
        days = self._sanitize_number(matched.group('days'))
        hours = self._sanitize_number(matched.group('hours'))
        minutes = self._sanitize_number(matched.group('minutes'))
        seconds = self._sanitize_number(matched.group('seconds'))
        return timedelta(days=days, hours=hours, minutes=minutes, seconds=seconds)

    @staticmethod
    def _sanitize_number(number) -> int:
        if number is None:
            return 0
        return int(number)


import numpy as np
import pywt
import peakutils
import matplotlib
from scipy.signal import butter, lfilter
matplotlib.use('TkAgg')
from matplotlib import pyplot as plt

def perform_fft_analysis(time_series, buffer_size, peak_treshold):
    # length of the signal and data
    n = len(time_series)

    # normalizing to discard DC component
    mean = sum(time_series) / n
    time_series = time_series - mean

    # zero padding
    pow_2 = 1 << (n-1).bit_length()
    time_series_padded = np.pad(time_series, (0, pow_2 - n), 'constant')
    n_pad = len(time_series_padded)
    fs = buffer_size  # sampling rate
    k = np.arange(n_pad)
    t = n_pad / fs
    frq = k / t  # two sides frequency range
    frq = frq[range(int(n_pad / 2))]  # one side frequency range

    # computing FFT
    fft_x = np.fft.fft(time_series_padded) / n_pad  # (normalized)
    fft_x = fft_x[range(int(n_pad / 2))]
    fft_abs = abs(fft_x)
    print(max(fft_abs))

    # finding peaks
    indexes = peakutils.indexes(fft_abs, thres=peak_treshold, min_dist=20)
    if len(indexes) > 0:
        detected_freq = max(frq[indexes])
    else:
        detected_freq = 0
    if max(fft_abs) > 7:
        return fft_abs, detected_freq
    else:
        return fft_abs, 0

def perform_wavelet_analysis(time_series, central_freq, sampling_rate, peak_tresh):
    mean = sum(time_series) / len(time_series)
    time_series = time_series - mean
    ts = 1 / sampling_rate
    central_scale = sampling_rate / central_freq
    wav = pywt.ContinuousWavelet('cmor2-1.0')
    f_bound_high = central_scale / 2
    f_bound_low = central_scale / 2
    bands = 64
    widths = np.linspace(central_scale - f_bound_high, central_scale + f_bound_low, bands)
    # (IMPORTANTE) devo trovare la formula che lega direttamente la frequenza rilevata dalla fft coi parametri da settare per le wavelets
    # in pratica ho capito che a bassissime frequenze non ho bisogno di un numero di bande superiore a 50
    # oltretutto a basse frequenze l'analisi wavelet è molto più lenta
    # un altro parametro molto importante è la larghezza della banda di analisi
    # il limite inferiore (in frequenza) deve essere aumentato
    # 6 Hz -> bands = 100, f_bound_high = central_scale / 20, f_bound_low = central_scale / 80
    # 0.15 Hz -> bands = 20, f_bound_high = central_scale / 3, f_bound_low = central_scale / 1
    cwtmatr, freqs = pywt.cwt(time_series, widths, wav, ts)
    cwt_freq_peaks = []
    times = 0;
    for time_stamp in cwtmatr.T: # [int(len(cwtmatr.T)/3):int(len(cwtmatr.T)*2/3)]:
        abs_ts = abs(time_stamp)
        max_value = max(abs_ts)
        indexes = peakutils.indexes(abs_ts, thres=peak_tresh, min_dist=20)
        for i in indexes:
            cwt_freq_peaks.append(freqs[i])
        times = times+1
    #print("Peaks: " + str(cwt_freq_peaks))
    #print("Freqs: " + str(freqs))
    freq_det_cwt = np.mean(cwt_freq_peaks)
    return cwtmatr, freq_det_cwt


import stringrnautils
import argparse
import os
import logging
logger = logging.getLogger(os.path.basename(__file__))
logging.basicConfig(level=logging.INFO)

def is_valid_path(arg):
    if not os.path.exists(arg):
        parser.error("Given master file path %s does not exist." % arg)
    return arg

def main():
    stringrnautils.combine_masterfiles(("miRTarBase_NPInter_SBexcluded.tsv", "starbase.tsv"),
                                        'experiments.tsv', args.gold_standard_file, 'experiments', 40,
                                         negative_evidence=False,rebenchmark_everything=True,
                                         ignore_fraction=0.3)

if __name__ == '__main__':
    logger.info("Integrating Experiments channel.")
    parser = argparse.ArgumentParser()
    parser.add_argument('gold_standard_file', type=is_valid_path,
                        help='The gold standard file to benchmark against.')
    args = parser.parse_args()
    main()
    logger.info('Done.' + os.linesep + os.linesep)


from os import getenv
from flask import Flask
from flask import make_response
from flask import jsonify
from models import storage
from flask_cors import CORS

from api.v1.views import app_views

if getenv("HBNB_API_HOST") is None:
    HBNB_API_HOST = '0.0.0.0'
else:
    HBNB_API_HOST = getenv("HBNB_API_HOST")
if getenv("HBNB_API_PORT") is None:
    HBNB_API_PORT = '5000'
else:
    HBNB_API_PORT = getenv("HBNB_API_PORT")

app = Flask(__name__)
app.register_blueprint(app_views)
cors = CORS(app, resources={r"/api/v1/*": {"origins": "*"}})

@app.teardown_appcontext
def teardown_db(exception):
    """method to handle teardown"""
    storage.close()

@app.errorhandler(404)
def page_not_found(e):
    """Error Handler"""
    return make_response(jsonify({'error': 'Not found'}), 404)

if __name__ == '__main__':
    app.run(host=HBNB_API_HOST, port=HBNB_API_PORT, threaded=True)