__author__ = 'Anni'

import random

from buildingControl.smartbes import SmartBes
from building.pvsystem import PVSystem
import numpy as np

class DataBase(object):
    """
    holds information and methods for creating random BES's
    """

    @staticmethod
    def createRandomBESs(number, sharesOfBESTypes, environment, stepSize, RSC, solPoolAbsGap=2, solPoolRelGap=0.2, solPoolIntensity=4, pseudorandom = True, randomSeed = 1, sqm=0, specDemandTh=0, iApartments=0, lclPV=True):
        """
        method adds given number of random members. based on statistics of german households.
        sources:    Number of apartments per building   | Zensus 2011
                    Sqm per apartment                   | Zensus 2011
                    Thermal demand (1 aptm. buildings)  | Zusatzauswertung zur Studie "Wohnungsbau in Deutschland - 2011, Modernisierung oder Bestandsersatz" (inkl. Warmwasser, bezogen auf Wohnflaeche)
                    Thermal demand (>1 aptm. buildings) | Energiekennwerte 2013, Techem
                    Specific PV Generation              | http://www.umwelt-campus.de/ucb/fileadmin/users/176_h.teheesen/dokumente/Publikationen/Ertragsstudie_2012.pdf
                    TER 1 for HPs                       | Dimplex LA 12TU (http://www.dimplex.de/pdf/de/produktattribute/produkt_1725609_extern_egd.pdf)
        :param number: number of new BES to be added to the cluster
        :param sharesOfBESTypes:    array of shares of both types of BESs
                                    1. HPs | 2. CHPs (in %)
                                    if sum != 100% -> remaining share will be GBs
        :param pseudorandom: set to True if created BES's are supposed to be the exact same each time method is run
        :return:
        """

        # if pseudorandom is true, create reproducible BES with equal properties every time this method is called
        if pseudorandom:
            random.seed(randomSeed)

        # ==============================================================================================================
        # create data arrays of statistics for different BES parameters
        # ==============================================================================================================

        # no. of apartments per BES
        noApartmentsList = [1] * 651 \
                         + [2] * 172 \
                         + [3] * 29 + [4] * 29 + [5] * 29 + [6] * 29 \
                         + [7] * 8 + [8] * 8 + [9] * 8 + [10] * 8 + [11] * 8 + [12] * 7 \
                         + [13] + [14] + [15] + [16] + [17] + [18] + [19] + [20] + [21] + [22] + [23] + [24]

        # thermal demand per sqm and year, distribution depending on number of apartments in building
        demandList1 = [random.randint(30,60) for _ in range(4)] + [random.randint(60,80) for _ in range(17)] + [random.randint(80,100) for _ in range(38)] \
                   + [random.randint(100,120) for _ in range(59)] + [random.randint(120,140) for _ in range(85)] + [random.randint(140,160) for _ in range(106)] \
                   + [random.randint(160,180) for _ in range(120)] + [random.randint(180,200) for _ in range(123)] + [random.randint(200,220) for _ in range(119)] \
                   + [random.randint(220,240) for _ in range(100)] + [random.randint(240,260) for _ in range(55)] + [random.randint(260,280) for _ in range(38)] \
                   + [random.randint(280,300) for _ in range(29)] + [random.randint(300,320) for _ in range(24)] + [random.randint(320,340) for _ in range(20)] \
                   + [random.randint(340,360) for _ in range(18)] + [random.randint(360,380) for _ in range(13)] + [random.randint(380,400) for _ in range(13)] \
                   + [random.randint(400,500) for _ in range(19)]
        demandList2 = [random.randint(40,80) for _ in range(65)] + [random.randint(80,120) for _ in range(205)] + [random.randint(120,160) for _ in range(286)] \
                   + [random.randint(160,200) for _ in range(222)] + [random.randint(200,240) for _ in range(122)] + [random.randint(240,280) for _ in range(58)] \
                   + [random.randint(280,320) for _ in range(27)] + [random.randint(320,560) for _ in range(17)]
        demandList3 = [random.randint(40,80) for _ in range(81)] + [random.randint(80,120) for _ in range(289)] + [random.randint(120,160) for _ in range(330)] \
                   + [random.randint(160,200) for _ in range(186)] + [random.randint(200,240) for _ in range(75)] + [random.randint(240,280) for _ in range(25)] \
                   + [random.randint(280,320) for _ in range(8)] + [random.randint(320,560) for _ in range(5)]
        demandList7 = [random.randint(40,80) for _ in range(95)] + [random.randint(80,120) for _ in range(368)] + [random.randint(120,160) for _ in range(350)] \
                   + [random.randint(160,200) for _ in range(137)] + [random.randint(200,240) for _ in range(35)] + [random.randint(240,280) for _ in range(10)] \
                   + [random.randint(280,320) for _ in range(3)] + [random.randint(320,560) for _ in range(3)]
        demandList13 = [random.randint(40,80) for _ in range(98)] + [random.randint(80,120) for _ in range(404)] + [random.randint(120,160) for _ in range(339)] \
                   + [random.randint(160,200) for _ in range(121)] + [random.randint(200,240) for _ in range(28)] + [random.randint(240,280) for _ in range(6)] \
                   + [random.randint(280,320) for _ in range(1)] + [random.randint(320,560) for _ in range(2)]

        # pv system sizes in kWp
        pvSystemkWpList = [1.5 for _ in range(11)] + [2.5 for _ in range(38)] + [3.5 for _ in range(83)] + [4.5 for _ in range(137)] + [5.5 for _ in range(172)] \
                       + [6.5 for _ in range(122)] + [7.5 for _ in range(145)] + [8.5 for _ in range(129)] + [9.5 for _ in range(163)]

        # ==============================================================================================================
        # setup variables etc.
        # ==============================================================================================================

        # calculate numbers of HPs, CHPs and GBs each
        noHPs  = int(round(sharesOfBESTypes[0] * number / 100))
        noCHPs = int(round(sharesOfBESTypes[1] * number / 100))
        noGBs = number - noHPs - noCHPs

        # specific PV generation per year (2012) in kWh per kWp for PV systems in Bottrop (PLZ 46*) (source in comments above)
        specificGeneration = 918

        # create parameter arrays depending on number of each HS type
        TER1_arr = [-2.32] * noHPs + [+2.3] * noCHPs + [0] * noGBs      # TER 1
        TER2_arr = [-1]    * noHPs + [0]    * noCHPs + [0] * noGBs      # TER 2
        SM_arr   = [-2]    * noHPs + [-1]   * noCHPs + [1] * noGBs      # sizing method

        noApartments_arr = np.zeros(number)
        sqmPerApartment_arr = np.zeros(number)
        demand_arr = np.zeros(number)

        for i in range(number):

            noApartments_arr[i] = int(random.choice(noApartmentsList))  # no of apartments

            # get sqm and thermal demand depending on number of apartments in BES
            if noApartments_arr[i] == 1:
                sqmPerApartment_arr[i] = 128.5     # average sqm for 1 apartment buildings: 128,5
                demand_arr[i] = random.choice(demandList1)
            elif noApartments_arr[i] == 2:
                sqmPerApartment_arr[i] = 101.1     # average sqm for 2 apartment buildings: 101,1
                demand_arr[i] = random.choice(demandList2)
            else:
                sqmPerApartment_arr[i] = 68        # average sqm for >3 apartment buildings: 68

                if 2 < noApartments_arr[i] < 7:
                    demand_arr[i] = random.choice(demandList3)
                elif 6 < noApartments_arr[i] < 13:
                    demand_arr[i] = random.choice(demandList7)
                else:
                    demand_arr[i] = random.choice(demandList13)

        # ==============================================================================================================
        # create list of random BESs
        # ==============================================================================================================

        listBes = list()

        if sqm == 0:
            for i in range(number):
                listBes.append(SmartBes(stepSize=stepSize, TER1=TER1_arr[i], TER2=TER2_arr[i], RSC=RSC, sizingMethod=SM_arr[i], iApartments=int(noApartments_arr[i]),
                                        sqm=sqmPerApartment_arr[i], specDemandTh=demand_arr[i], env=environment, solPoolAbsGap=solPoolAbsGap,
                                        solPoolRelGap=solPoolRelGap, solPoolIntensity=solPoolIntensity))
        elif sqm > 0:
            for i in range(number):
                listBes.append(SmartBes(stepSize=stepSize, TER1=TER1_arr[i], TER2=TER2_arr[i], RSC=RSC, sizingMethod=SM_arr[i], iApartments=iApartments,
                                        sqm=sqm, specDemandTh=specDemandTh, env=environment, solPoolAbsGap=solPoolAbsGap,
                                        solPoolRelGap=solPoolRelGap, solPoolIntensity=solPoolIntensity))

        # ==============================================================================================================
        # equip BESs with available PV systems
        # ==============================================================================================================

        if lclPV==True:
            annualElecDemand = np.sum([bes.getAnnualElectricalDemand() for bes in listBes])     # in kWh
            desiredAnnualLclPVGeneration = np.abs(np.sum(environment.getPVEnergyCurve(0, 86400*365, annualElecDemand)[1,:]) / 3600000)  # in kWh

            listPVSystems = list()
            _pvSystemsGen = 0

            # create pv systems
            while len(listPVSystems) < number:
                # pick a random value for annual generation
                _annGen = random.choice(pvSystemkWpList) * specificGeneration

                # if this value causes the overall local pv generation to exceed the desired value...
                if _pvSystemsGen + _annGen > desiredAnnualLclPVGeneration:
                    # ...calculate difference between desired and current overall local pv generation...
                    _diff_kWp = (desiredAnnualLclPVGeneration - _pvSystemsGen) / specificGeneration
                    # ...and break if difference is smaller than the smallest pv system possible...
                    if _diff_kWp < 1.5:         # 1.5 kWp = smallest possible system size
                        break
                    # ...or add another last pv system before breaking if difference can be decreased any further
                    else:
                        _last_kWp = round(_diff_kWp) - 0.5                      # will be a value from the kWp system size array (x.5)
                        _annGen = _last_kWp * specificGeneration                # use this value to calculate annual generation of last pv system
                        listPVSystems.append(PVSystem(environment, _annGen))    # add system to list...
                        break                                                   # ...and break from while loop

                # add system to list & update pv systems' generation variable
                listPVSystems.append(PVSystem(environment, _annGen))
                _pvSystemsGen += _annGen

            # generate random list of BESs that receive a PV system
            noPVSystems = len(listPVSystems)
            listPVequippedBESs = random.sample(listBes[:], noPVSystems)

            # add pv systems to BESs
            for p in range(noPVSystems):
                listPVequippedBESs[p].addPVSystem(listPVSystems[p])

        # ==============================================================================================================
        # return list of BESs
        # ==============================================================================================================
        random.shuffle(listBes)
        return listBes


#!/bin/python3

"""
Advent of Code 2021
Day 7 Part 2
https://adventofcode.com/2021/day/7
"""

__author__ = "Adam Karl"

INPUT_FILE = 'crabPositions.txt'

def alignCrabs():
    """Determine the position that requires the least amount of fuel for all
    crabs to reach. Return that position and the total fuel required"""

    f = open(INPUT_FILE, 'r')
    input = f.readlines()
    f.close()

    positions = list(map(int, input[0].split(',')))

    bestPos = -1
    minFuel = -1
    for x in range(min(positions), max(positions)+1):
        totalFuel = 0
        for p in positions:
            # subsequent steps take extra fuel
            for step in range(abs(p-x)):
                totalFuel += (step+1)

        if totalFuel < minFuel or minFuel == -1:
            bestPos = x
            minFuel = totalFuel
        print(f"checked position {x}", flush=True)
    return bestPos, minFuel

def main():
    pos, fuel = alignCrabs()
    print(f"Final position: {pos}")
    print(f"Total fuel required: {fuel}")

if __name__ == "__main__":
    main()


import logging
from typing import Optional

from ..effect import EffectFactory
from .effect_checker import EffectChecker, AnnotationEffect, AnnotationRequest

class UTREffectChecker(EffectChecker):
    """UTR effect checker class."""

    def __init__(self) -> None:
        self.logger = logging.getLogger(__name__)

    def create_utr_effect(
        self, request: AnnotationRequest, strand: str
    ) -> AnnotationEffect:
        """Create an UTR annotation effect."""
        if request.transcript_model.strand == strand:
            effect_name = "5'UTR"
        else:
            effect_name = "3'UTR"

        effect = EffectFactory.create_effect_with_prot_length(
            effect_name, request
        )
        self.logger.debug(
            "pos=%d cds end=%d",
            request.variant.ref_position_last - 1,
            request.transcript_model.cds[0],
        )

        if strand == "+":
            effect.dist_from_coding = request.get_exonic_distance(
                request.variant.corrected_ref_position_last,
                request.transcript_model.cds[0],
            )
        else:
            effect.dist_from_coding = request.get_exonic_distance(
                request.transcript_model.cds[1], request.variant.position
            )
        return effect

    def create_effect(
        self, request: AnnotationRequest, strand: str
    ) -> Optional[AnnotationEffect]:
        """Create UTR effect."""
        coding_regions = request.transcript_model.exons
        last_position = request.variant.corrected_ref_position_last
        prev = None

        for i, j in enumerate(coding_regions):
            if request.variant.position <= j.stop and j.start <= last_position:
                return self.create_utr_effect(request, strand)
            if (
                prev is not None
                and prev <= request.variant.position
                and last_position < j.start
            ):
                if request.transcript_model.strand == strand:
                    effect_name = "5'UTR-intron"
                else:
                    effect_name = "3'UTR-intron"
                return EffectFactory.create_intronic_non_coding_effect(
                    effect_name, request, prev, j.start, i
                )
            prev = j.stop
        return None

    def check_stop_codon(
        self, request: AnnotationRequest
    ) -> Optional[AnnotationEffect]:
        """Check for stop codon."""
        if not request.has_utr3_region():
            return None

        try:
            ref_aa, alt_aa = request.get_amino_acids()
            if "End" not in ref_aa:
                return None

            ref_index = ref_aa.index("End")
            alt_index = alt_aa.index("End")

            if ref_index == alt_index:
                effect = EffectFactory.create_effect_with_prot_length(
                    "3'UTR", request
                )
                effect.dist_from_coding = 0
                return effect
        except ValueError:
            pass
        except IndexError:
            pass
        return None

    def get_effect(
        self, request: AnnotationRequest
    ) -> Optional[AnnotationEffect]:
        if request.is_stop_codon_affected():
            return self.check_stop_codon(request)

        self.logger.debug(
            "utr check: %d<%d or %d>%d exons:%d-%d",
            request.variant.position,
            request.transcript_model.cds[0],
            request.variant.position,
            request.transcript_model.cds[1],
            request.transcript_model.exons[0].start,
            request.transcript_model.exons[-1].stop,
        )

        if request.variant.position < request.transcript_model.cds[0]:
            return self.create_effect(request, "+")

        if request.variant.position > request.transcript_model.cds[1]:
            return self.create_effect(request, "-")

        return None


from pyroll.cli.program import main
from pyroll.cli.config import RES_DIR
import click.testing
import os

def test_create_project(tmp_path):
    runner = click.testing.CliRunner()

    os.chdir(tmp_path)
    result = runner.invoke(main, ["create-project"])

    assert result.exit_code == 0
    print(result.output)

    fi = tmp_path / "input.py"
    fc = tmp_path / "config.toml"

    assert fi.exists()
    assert fc.exists()

    assert fi.read_text() == (RES_DIR / "input.py").read_text()


from datetime import datetime

from pytest import fixture

from .model import User
from .schema import UserSchema
from .interface import UserInterface

@fixture
def schema() -> UserSchema:
    return UserSchema()

def test_UserSchema_create(schema: UserSchema):
    assert schema

def test_UserSchema_works(schema: UserSchema):
    params: UserInterface = schema.load(
        {
            "id": "1",
            "auth_provider": "google",
            "username": "JohnDoe",
            "first_name": "John",
            "family_name": "Doe",
            "picture_url": "www.google.com",
            "super_admin": True,
            "created_date": str(datetime.now()),
            "last_seen": str(datetime.now()),
        }
    )
    user = User(**params)

    assert user.id == "1"
    assert user.auth_provider == "google"
    assert user.username == "JohnDoe"
    assert user.first_name == "John"
    assert user.family_name == "Doe"
    assert user.picture_url == "www.google.com"
    assert user.super_admin == True


from openpyxl import load_workbook

workbook = load_workbook(filename=r'F:\kinscloud.github.io\Python\Excel\testxls.xlsx')
#print(workbook.sheetnames)
sheet = workbook.active
for row in sheet.rows:
#for row in sheet.iter_rows(min_row=2,max_row=3,min_col=1,max_col=3):
    for cell in row:
        print(cell.value)

#sheet['A1']='ids'
cell=sheet['A1']
cell.value='ids'
workbook.save(filename=r'F:\kinscloud.github.io\Python\Excel\testxls2.xlsx')


#!/usr/bin/env python3
import asyncio
import sys
from getpass import getpass
from pathlib import Path
from typing import Dict

import httpx
import hug

IGNORED_AUTHOR_LOGINS = {"deepsource-autofix[bot]"}

REPO = "pycqa/isort"
GITHUB_API_CONTRIBUTORS = f"https://api.github.com/repos/{REPO}/contributors"
GITHUB_USER_CONTRIBUTIONS = f"https://github.com/{REPO}/commits?author="
GITHUB_USER_TYPE = "User"
USER_DELIMITER = "-" * 80
PER_PAGE = 100

_ACK_FILE = Path(__file__).parent.parent / "docs" / "contributing" / "4.-acknowledgements.md"
ACKNOWLEDGEMENTS = _ACK_FILE.read_text().lower()

def _user_info(user: Dict[str, str], verbose=False) -> str:
    login = "@" + user["login"]
    name = user.get("name")
    display_name = f"{name} ({login})" if name else login
    user_info = f"- {display_name}"
    if verbose:
        contributions = f"  {GITHUB_USER_CONTRIBUTIONS}{user['login']}"
        user_info += "\n" + contributions
    return user_info

@hug.cli()
async def main():
    auth = (input("Github Username: "), getpass())
    async with httpx.AsyncClient() as client:
        page = 0
        results = []
        contributors = []
        while not page or len(results) == PER_PAGE:
            page += 1
            response = await client.get(
                f"{GITHUB_API_CONTRIBUTORS}?per_page={PER_PAGE}&page={page}", auth=auth
            )
            results = response.json()
            contributors.extend(
                (
                    contributor
                    for contributor in results
                    if contributor["type"] == GITHUB_USER_TYPE
                    and contributor["login"] not in IGNORED_AUTHOR_LOGINS
                    and f"@{contributor['login'].lower()}" not in ACKNOWLEDGEMENTS
                )
            )

        unacknowledged_users = await asyncio.gather(
            *(client.get(contributor["url"], auth=auth) for contributor in contributors)
        )
        unacknowledged_users = [request.json() for request in unacknowledged_users]

        if not unacknowledged_users:
            sys.exit()

        print("Found unacknowledged authors:")
        print()

        for user in unacknowledged_users:
            print(_user_info(user, verbose=True))
            print(USER_DELIMITER)

        print()
        print("Printing again for easy inclusion in Markdown file:")
        print()
        for user in unacknowledged_users:
            print(_user_info(user))

        sys.exit(1)

if __name__ == "__main__":
    main.interface.cli()


#regular expressions
# import re
# match and search
# match()-find a perticular fn at the begining of a string
# search()-it can find entire line or word in the string
import re
l="python programing is fun"
m=re.search("python",l)
if m:
    print("match found")
else:
    print("no match")

# search
# sub-search and replace
import re
zipcode="1231-3245-4554"            #   syntax (pattern,replace,string name)
result=re.sub(r"\D"," ",zipcode)    #"\D" non digits "\d" digits
print(result)

# findall()
import re
l="we 23  fgfg 345 fgd 34"
print(re.findall("\D+",l))


#!/usr/bin/python3
"""Alta3 Research | By RZFeeser
   Making choices with "if" logic"""

# starship registry list
sshipreg = ["ncc-1701"]

# create our "trigger"
ans = "y"

while ans == "y":
    # prompt user for the "new starship" to be added to sshipreg
    newsship = input("What is the starship you would like to register? ")

    # force collected input data to be lower-case
    newsship = newsship.lower()

    # tests for "true" or "false" - no input is evalualted as "false"
    if (newsship) and (newsship not in sshipreg):
        sshipreg.append(newsship) # given the user didn't just press "enter", add the data to the list
    elif newsship == "":
        print("You need to provide a valid name")
    else: # in all other cases...
        print("That name already appears within the starship regsitry.")

    ans = input("Would you like to register another starship (y/n)? ")
    ans = ans.lower() # ensure user input is LOWERCASE

# do this just ONCE
print(sshipreg)


import sys
sys.path.append("/home/trung/_qhe-library")
from subprocess import call, Popen, PIPE
import numpy as np
import FQH_states as FQH
import misc
import time
from itertools import product, combinations_with_replacement

import string
import random

def read_jack(root, debug=False):
	# To adapt to the changes in convention
	# If the root starts with 0, remove the 0 e.g. 001001001 --> 01001001 --> 1001001
	# If the root is in negative Lz sector (convention left most digit = -S), reverse it. e.g 10001001 --> 10010001
	jack = FQH.fqh_state(f"jacks/J_{root}", quiet=True)
	if jack.dim()==0:
		if debug: print(f"{root} not found")
		S = (len(root)-1)/2
		if misc.findLZ(int(root,2), S) > 0:
			root_read = root[::-1]
			reverse = True
			if debug: print(f"reading root {root_read} instead")
		else:
			root_read = root
			reverse = False
			if debug: print(f"reading {root}")
		if root_read[0]=="0":
			if debug: print(f"reading root {root_read[1:]} instead")
			jack = read_jack(root_read[1:])
			jack.basis = ["0"+x for x in jack.basis] # put back the zero
		else:
			jack = FQH.fqh_state(f"jacks/J_{root_read}")
		if reverse:
			jack.basis = [x[::-1] for x in jack.basis]

	if debug:
		if jack.dim()==0:
			print(f"WARNING: reading {root} outputs a null state")
		print("-----")
	return jack

def generate_jack(root, alpha,fname=None,debug=False):
	# root must be in binary string format
	p = Popen(["./jack"], stdin = PIPE, shell = True)
	No = len(root)
	rootconfig = " ".join(root)
	# Use this to get the coefficients
	if fname==None:
		filename = "none"
	else:
		filename = fname[:4]

	p.communicate(input=bytes(f"{No} -1\n{rootconfig}\n{filename}\n1\n{alpha}\n",encoding = 'utf-8'))
	call(["mv", filename, f"jacks/J_{root}"])
	return

def get_jack_list(root_list, alpha, geom="none", placeholder=None):
	# special means special case where one quasihole is at center
	try:
		root_read = FQH.fqh_state(root_list)
	except FileNotFoundError:
		print("file not found")
		return
	jack_list = []
	if placeholder==None:
		placeholder = "".join(random.choices(string.ascii_uppercase + string.digits + string.ascii_lowercase, k=4))
	for root_bin in root_read.basis:
		jack_read = FQH.fqh_state(f"jacks/J_{root_bin}", quiet=True)
		if jack_read.dim()==0:
			generate_jack(root_bin, alpha,fname=placeholder)
			jack_read = FQH.fqh_state(f"jacks/J_{root_bin}")
		if geom=="disk":
			jack_read.disk_normalize()
		elif geom=="sphere":
			jack_read.sphere_normalize()
		jack_list.append(jack_read)
	return jack_list
"""
def gen_Jack_2qh((k,l), Ne):
	# Assume k<=l
	root = "1"*k+"0"+"1"*(l-k)+"0"
	return
"""

"""

if __name__ == "__main__":
	nqh = int(input("Generate jack list for 1 or 2 quasihole? "))
	Ne = int(input("Input N_e: "))
	ph = str(input("Placeholder name for jacks (max 4 characters): "))
	JL = get_jack_list(Ne,nqh, placeholder = ph)
	print("------")
	print(f"{Ne} electrons and {nqh} quasiholes")
	print(f"Number of jacks = {len(JL)}")
	#st = time.time()
	#a  = two_quasihole_state(4, -2.5, 2.5,JL)
	#print(f"{time.time()-st} seconds")
	#print("Plotting density")
	#a.plot_disk_density("density_4_2.pdf", ref=[-2.5,2.5])
	#print(f"Total: {time.time()-st} seconds")
	#print("------")

"""

if __name__ == "__main__":
	import os
	if not os.path.isdir("jacks"):
		call(["mkdir", "jacks"])

	print("Generate a list of Jack polynomials from a given list of root configurations")
	fname = str(input("Input file name: "))

	alpha = str(input("alpha parameter = num/den. Input num den (separated with space)"))
	jacks = get_jack_list(fname, alpha)


import sys
import os
from PyQt5 import QtWidgets, uic, QtCore
import pyqtgraph as pg
import numpy as np
from ..communication import SCPI_mannager, upload
import json

class graph_view(pg.GraphicsLayoutWidget):
    def __init__(self, top_window):
        super().__init__(show=True)
        self.top_window : Top_window = top_window # parent
        self.plt1 = self.addPlot()

        self.vals = []
        y,x = np.histogram([])
        self.hist : pg.PlotDataItem= self.plt1.plot(x, y, stepMode="center", fillLevel=0, fillOutline=True, brush=(0,0,255,150))
        self.update_hist()

        self.line_photon1 = pg.InfiniteLine(movable=True, angle=90, label='1:{value:0.0f}',
                       labelOpts={'position':0.1, 'color': (200,200,100), 'fill': (200,200,200,50), 'movable': False})
        self.line_photon2 = pg.InfiniteLine(movable=True, angle=90, label='2:{value:0.0f}',
                       labelOpts={'position':0.2, 'color': (200,200,100), 'fill': (200,200,200,50), 'movable': False})
        self.line_photon3 = pg.InfiniteLine(movable=True, angle=90, label='3:{value:0.0f}',
                       labelOpts={'position':0.3, 'color': (200,200,100), 'fill': (200,200,200,50), 'movable': False})
        self.line_photon4 = pg.InfiniteLine(movable=True, angle=90, label='4:{value:0.0f}',
                       labelOpts={'position':0.4, 'color': (200,200,100), 'fill': (200,200,200,50), 'movable': False})
        self.line_photon5 = pg.InfiniteLine(movable=True, angle=90, label='5:{value:0.0f}',
                       labelOpts={'position':0.5, 'color': (200,200,100), 'fill': (200,200,200,50), 'movable': False})
        self.line_photon6 = pg.InfiniteLine(movable=True, angle=90, label='6:{value:0.0f}',
                       labelOpts={'position':0.6, 'color': (200,200,100), 'fill': (200,200,200,50), 'movable': False})
        self.line_photon7 = pg.InfiniteLine(movable=True, angle=90, label='7:{value:0.0f}',
                       labelOpts={'position':0.7, 'color': (200,200,100), 'fill': (200,200,200,50), 'movable': False})
        self.line_photon8 = pg.InfiniteLine(movable=True, angle=90, label='8:{value:0.0f}',
                       labelOpts={'position':0.8, 'color': (200,200,100), 'fill': (200,200,200,50), 'movable': False})

        self.plt1.addItem(self.line_photon1)
        self.plt1.addItem(self.line_photon2)
        self.plt1.addItem(self.line_photon3)
        self.plt1.addItem(self.line_photon4)
        self.plt1.addItem(self.line_photon5)
        self.plt1.addItem(self.line_photon6)
        self.plt1.addItem(self.line_photon7)
        self.plt1.addItem(self.line_photon8)

        def temp_func():
            self.on_line_dragged()
            self.top_window.display_value()

        self.line_photon1.sigPositionChangeFinished.connect(temp_func)
        self.line_photon2.sigPositionChangeFinished.connect(temp_func)
        self.line_photon3.sigPositionChangeFinished.connect(temp_func)
        self.line_photon4.sigPositionChangeFinished.connect(temp_func)
        self.line_photon5.sigPositionChangeFinished.connect(temp_func)
        self.line_photon6.sigPositionChangeFinished.connect(temp_func)
        self.line_photon7.sigPositionChangeFinished.connect(temp_func)
        self.line_photon8.sigPositionChangeFinished.connect(temp_func)

    def photon_threshold_set(self, value_dict: dict):
        assert len(value_dict) == 8
        self.line_photon1.setValue(value_dict['photon1'])
        self.line_photon2.setValue(value_dict['photon2'])
        self.line_photon3.setValue(value_dict['photon3'])
        self.line_photon4.setValue(value_dict['photon4'])
        self.line_photon5.setValue(value_dict['photon5'])
        self.line_photon6.setValue(value_dict['photon6'])
        self.line_photon7.setValue(value_dict['photon7'])
        self.line_photon8.setValue(value_dict['photon8'])

    def update_hist(self):
        bins = 1 if len(self.vals) == 0 else np.linspace(min(self.vals) - 0.5, max(self.vals) + 0.5 , max(self.vals) - min(self.vals) + 2)
        y,x = np.histogram(self.vals, bins= bins )
        self.hist.setData(x,y)

    def append_data(self, array: list):
        self.vals = self.vals + array
        self.update_hist()

    def on_line_dragged(self):
        value_dict = {
            'photon1':round(self.line_photon1.value()),
            'photon2':round(self.line_photon2.value()),
            'photon3':round(self.line_photon3.value()),
            'photon4':round(self.line_photon4.value()),
            'photon5':round(self.line_photon5.value()),
            'photon6':round(self.line_photon6.value()),
            'photon7':round(self.line_photon7.value()),
            'photon8':round(self.line_photon8.value())
        }

        self.top_window.photon_threshold_set(value_dict)

    def reset_graph(self):
        self.vals = []
        self.update_hist()

class Top_window(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        dir_name = os.path.dirname(__file__)
        uic.loadUi(os.path.join(dir_name, 'top.ui'), self)
        self.setWindowTitle('Redpitaya photon number resolver controller')
        self.setFixedSize(self.size())
        self.attach_graph()
        self.toggle_config_input(False)
        self.scpi_mannager: SCPI_mannager = None

        self.pushButton_upload.clicked.connect(self.push_upload)
        self.pushButton_connect.clicked.connect(self.push_connect)
        self.pushButton_disconnect.clicked.connect(self.push_disconnect)

        self.lineEdit_port.setText('5025')

        def trigger_level_slider_change(value):
            self.spinBox_trigger_level.setValue(value)
            self.display_value()
        def trigger_level_spin_change(value):
            self.horizontalSlider_trigger_level.setValue(value)
            self.display_value()

        self.horizontalSlider_trigger_level.valueChanged.connect(trigger_level_slider_change)
        self.spinBox_trigger_level.valueChanged.connect(trigger_level_spin_change)

        self.spinBox_trigger_delay.valueChanged.connect(self.display_value)
        self.spinBox_trigger_clearance.valueChanged.connect(self.display_value)
        self.spinBox_photon1.valueChanged.connect(self.display_value)
        self.spinBox_photon2.valueChanged.connect(self.display_value)
        self.spinBox_photon3.valueChanged.connect(self.display_value)
        self.spinBox_photon4.valueChanged.connect(self.display_value)
        self.spinBox_photon5.valueChanged.connect(self.display_value)
        self.spinBox_photon6.valueChanged.connect(self.display_value)
        self.spinBox_photon7.valueChanged.connect(self.display_value)
        self.spinBox_photon8.valueChanged.connect(self.display_value)

        self.pushButton_read.clicked.connect(self.push_read)
        self.pushButton_write.clicked.connect(self.push_write)
        self.pushButton_graph_reset.clicked.connect(self.push_graph_reset)

        self.pushButton_graph_load.clicked.connect(self.push_graph_load)

    def ui_components(self):
        # just type hint
        self.graph_container                    : QtWidgets.QGridLayout = None
        self.pushButton_upload                  : QtWidgets.QGridLayout = None
        self.pushButton_connect                 : QtWidgets.QPushButton = None
        self.pushButton_disconnect              : QtWidgets.QPushButton = None
        self.pushButton_read                    : QtWidgets.QPushButton = None
        self.pushButton_write                   : QtWidgets.QPushButton = None
        self.pushButton_graph_reset             : QtWidgets.QPushButton = None
        self.pushButton_graph_load              : QtWidgets.QPushButton = None
        self.lineEdit_ip                        : QtWidgets.QLineEdit   = None
        self.lineEdit_port                      : QtWidgets.QLineEdit   = None
        self.spinBox_trigger_level              : QtWidgets.QSpinBox    = None
        self.spinBox_trigger_delay              : QtWidgets.QSpinBox    = None
        self.spinBox_trigger_clearance          : QtWidgets.QSpinBox    = None
        self.spinBox_photon1                    : QtWidgets.QSpinBox    = None
        self.spinBox_photon2                    : QtWidgets.QSpinBox    = None
        self.spinBox_photon3                    : QtWidgets.QSpinBox    = None
        self.spinBox_photon4                    : QtWidgets.QSpinBox    = None
        self.spinBox_photon5                    : QtWidgets.QSpinBox    = None
        self.spinBox_photon6                    : QtWidgets.QSpinBox    = None
        self.spinBox_photon7                    : QtWidgets.QSpinBox    = None
        self.spinBox_photon8                    : QtWidgets.QSpinBox    = None
        self.horizontalSlider_trigger_level     : QtWidgets.QSlider     = None

        self.label_trigger_level_display        : QtWidgets.QLabel      = None
        self.label_trigger_delay_display        : QtWidgets.QLabel      = None
        self.label_trigger_clearance_display    : QtWidgets.QLabel      = None
        self.label_photon1_display              : QtWidgets.QLabel      = None
        self.label_photon2_display              : QtWidgets.QLabel      = None
        self.label_photon3_display              : QtWidgets.QLabel      = None
        self.label_photon4_display              : QtWidgets.QLabel      = None
        self.label_photon5_display              : QtWidgets.QLabel      = None
        self.label_photon6_display              : QtWidgets.QLabel      = None
        self.label_photon7_display              : QtWidgets.QLabel      = None
        self.label_photon8_display              : QtWidgets.QLabel      = None
        self.label_graph_samples                : QtWidgets.QLabel      = None

        self.graph_container                    : QtWidgets.QGridLayout = None

        self.groupBox_controll                  : QtWidgets.QGroupBox   = None
        self.groupBox_trigger_level             : QtWidgets.QGroupBox   = None
        self.groupBox_timing_controll           : QtWidgets.QGroupBox   = None
        self.groupBox_misc_config               : QtWidgets.QGroupBox   = None
        self.groupBox_threshold                 : QtWidgets.QGroupBox   = None
        self.groupBox_graph_control             : QtWidgets.QGroupBox   = None

        self.checkBox_trig_pos_edge             : QtWidgets.QCheckBox   = None
        self.checkBox_trig_is_a                 : QtWidgets.QCheckBox   = None
        self.checkBox_pnr_sig_inverse           : QtWidgets.QCheckBox   = None
        self.checkBox_dac_logic_mask_photon0    : QtWidgets.QCheckBox   = None
        self.checkBox_dac_logic_mask_photon1    : QtWidgets.QCheckBox   = None
        self.checkBox_dac_logic_mask_photon2    : QtWidgets.QCheckBox   = None
        self.checkBox_dac_logic_mask_photon3    : QtWidgets.QCheckBox   = None
        self.checkBox_dac_logic_mask_photon4    : QtWidgets.QCheckBox   = None
        self.checkBox_dac_logic_mask_photon5    : QtWidgets.QCheckBox   = None
        self.checkBox_dac_logic_mask_photon6    : QtWidgets.QCheckBox   = None
        self.checkBox_dac_logic_mask_photon7    : QtWidgets.QCheckBox   = None

    def attach_graph(self):
        self.graph = graph_view(self) #pg.GraphicsLayoutWidget(show=True)
        self.graph_container.addWidget(self.graph)

    def toggle_config_input(self, bool):
        self.groupBox_controll.setEnabled(bool)
        self.groupBox_trigger_level.setEnabled(bool)
        self.groupBox_timing_controll.setEnabled(bool)
        self.groupBox_misc_config.setEnabled(bool)
        self.groupBox_threshold.setEnabled(bool)
        self.groupBox_graph_control.setEnabled(bool)

    def push_upload(self):
        host         = self.lineEdit_ip.text().strip()
        ssh_port     = 22
        user         = 'root'
        passwd       = 'root'
        upload_cfg   = json.load(open("upload_cfg.json"))
        assets       = upload_cfg["assets"]
        exec_command = upload_cfg["exec_command"]

        upload(host, ssh_port, user, passwd, assets, exec_command)

    def push_connect(self):
        try:
            self.scpi_mannager = SCPI_mannager(host=self.lineEdit_ip.text().strip(), port=int(self.lineEdit_port.text()))
            result = self.scpi_mannager.idn()
            if result == None: raise Exception('fail for IDN')
            self.pushButton_connect.setEnabled(False)
            self.pushButton_disconnect.setEnabled(True)
            self.toggle_config_input(True)
        except Exception as e:
            print(e)
            pass

    def push_disconnect(self):
        self.pushButton_disconnect.setEnabled(False)
        self.pushButton_connect.setEnabled(True)
        self.toggle_config_input(False)
        self.scpi_mannager: SCPI_mannager = None

    def display_value(self):
        gen_time = lambda x: f'= {8*x} ns'
        gen_volt = lambda x: f'= {x/8.192:.5g} mv'

        self.label_trigger_level_display.setText(gen_volt(self.spinBox_trigger_level.value()))
        self.label_trigger_delay_display.setText(gen_time(self.spinBox_trigger_delay.value()))
        self.label_trigger_clearance_display.setText(gen_time(self.spinBox_trigger_clearance.value()))
        self.label_photon1_display.setText(gen_volt(self.spinBox_photon1.value()))
        self.label_photon2_display.setText(gen_volt(self.spinBox_photon2.value()))
        self.label_photon3_display.setText(gen_volt(self.spinBox_photon3.value()))
        self.label_photon4_display.setText(gen_volt(self.spinBox_photon4.value()))
        self.label_photon5_display.setText(gen_volt(self.spinBox_photon5.value()))
        self.label_photon6_display.setText(gen_volt(self.spinBox_photon6.value()))
        self.label_photon7_display.setText(gen_volt(self.spinBox_photon7.value()))
        self.label_photon8_display.setText(gen_volt(self.spinBox_photon8.value()))

        value_dict = {
            'photon1':self.spinBox_photon1.value(),
            'photon2':self.spinBox_photon2.value(),
            'photon3':self.spinBox_photon3.value(),
            'photon4':self.spinBox_photon4.value(),
            'photon5':self.spinBox_photon5.value(),
            'photon6':self.spinBox_photon6.value(),
            'photon7':self.spinBox_photon7.value(),
            'photon8':self.spinBox_photon8.value()
        }
        self.graph.photon_threshold_set(value_dict)

    def push_read(self):
        self.spinBox_trigger_level.setValue(self.scpi_mannager.read_trigger_level())
        self.spinBox_trigger_delay.setValue(self.scpi_mannager.read_trigger_delay())
        self.spinBox_trigger_clearance.setValue(self.scpi_mannager.read_trigger_clearance())
        self.spinBox_photon1.setValue(self.scpi_mannager.read_photon_threshold(1))
        self.spinBox_photon2.setValue(self.scpi_mannager.read_photon_threshold(2))
        self.spinBox_photon3.setValue(self.scpi_mannager.read_photon_threshold(3))
        self.spinBox_photon4.setValue(self.scpi_mannager.read_photon_threshold(4))
        self.spinBox_photon5.setValue(self.scpi_mannager.read_photon_threshold(5))
        self.spinBox_photon6.setValue(self.scpi_mannager.read_photon_threshold(6))
        self.spinBox_photon7.setValue(self.scpi_mannager.read_photon_threshold(7))
        self.spinBox_photon8.setValue(self.scpi_mannager.read_photon_threshold(8))
        self.checkBox_pnr_sig_inverse.setChecked(self.scpi_mannager.read_pnr_sig_inverse())
        self.checkBox_trig_pos_edge.setChecked(self.scpi_mannager.read_trig_positive_edge())
        self.checkBox_trig_is_a.setChecked(self.scpi_mannager.read_trig_is_a())

        dac_logic_mask = self.scpi_mannager.read_dac_logic_mask()
        self.checkBox_dac_logic_mask_photon0.setChecked(bool(dac_logic_mask & (1<<0)))
        self.checkBox_dac_logic_mask_photon1.setChecked(bool(dac_logic_mask & (1<<1)))
        self.checkBox_dac_logic_mask_photon2.setChecked(bool(dac_logic_mask & (1<<2)))
        self.checkBox_dac_logic_mask_photon3.setChecked(bool(dac_logic_mask & (1<<3)))
        self.checkBox_dac_logic_mask_photon4.setChecked(bool(dac_logic_mask & (1<<4)))
        self.checkBox_dac_logic_mask_photon5.setChecked(bool(dac_logic_mask & (1<<5)))
        self.checkBox_dac_logic_mask_photon6.setChecked(bool(dac_logic_mask & (1<<6)))
        self.checkBox_dac_logic_mask_photon7.setChecked(bool(dac_logic_mask & (1<<7)))

    def push_write(self):
        self.scpi_mannager.set_trigger_level(self.spinBox_trigger_level.value())
        self.scpi_mannager.set_trigger_delay(self.spinBox_trigger_delay.value())
        self.scpi_mannager.set_trigger_clearance(self.spinBox_trigger_clearance.value())
        self.scpi_mannager.set_photon_threshold(1, self.spinBox_photon1.value())
        self.scpi_mannager.set_photon_threshold(2, self.spinBox_photon2.value())
        self.scpi_mannager.set_photon_threshold(3, self.spinBox_photon3.value())
        self.scpi_mannager.set_photon_threshold(4, self.spinBox_photon4.value())
        self.scpi_mannager.set_photon_threshold(5, self.spinBox_photon5.value())
        self.scpi_mannager.set_photon_threshold(6, self.spinBox_photon6.value())
        self.scpi_mannager.set_photon_threshold(7, self.spinBox_photon7.value())
        self.scpi_mannager.set_photon_threshold(8, self.spinBox_photon8.value())
        self.scpi_mannager.set_pnr_sig_inverse(self.checkBox_pnr_sig_inverse.isChecked())
        self.scpi_mannager.set_trig_positive_edge(self.checkBox_trig_pos_edge.isChecked())
        self.scpi_mannager.set_trig_is_a(self.checkBox_trig_is_a.isChecked())

        dac_logic_mask = 0
        dac_logic_mask += self.checkBox_dac_logic_mask_photon0.isChecked() << 0
        dac_logic_mask += self.checkBox_dac_logic_mask_photon1.isChecked() << 1
        dac_logic_mask += self.checkBox_dac_logic_mask_photon2.isChecked() << 2
        dac_logic_mask += self.checkBox_dac_logic_mask_photon3.isChecked() << 3
        dac_logic_mask += self.checkBox_dac_logic_mask_photon4.isChecked() << 4
        dac_logic_mask += self.checkBox_dac_logic_mask_photon5.isChecked() << 5
        dac_logic_mask += self.checkBox_dac_logic_mask_photon6.isChecked() << 6
        dac_logic_mask += self.checkBox_dac_logic_mask_photon7.isChecked() << 7
        self.scpi_mannager.set_dac_logic_mask(dac_logic_mask)

    def push_graph_reset(self):
        self.graph.reset_graph()
        self.scpi_mannager.reset_adc_fifo()
        self.label_graph_samples.setText(f'Samples:{len(self.graph.vals)}')

    def push_graph_load(self):
        array = self.scpi_mannager.read_pnr_adc_fifo()
        self.graph.append_data(array)
        self.label_graph_samples.setText(f'Samples:{len(self.graph.vals)}')

    def photon_threshold_set(self, value_dict: dict):
        assert len(value_dict) == 8
        self.spinBox_photon1.setValue(value_dict['photon1'])
        self.spinBox_photon2.setValue(value_dict['photon2'])
        self.spinBox_photon3.setValue(value_dict['photon3'])
        self.spinBox_photon4.setValue(value_dict['photon4'])
        self.spinBox_photon5.setValue(value_dict['photon5'])
        self.spinBox_photon6.setValue(value_dict['photon6'])
        self.spinBox_photon7.setValue(value_dict['photon7'])
        self.spinBox_photon8.setValue(value_dict['photon8'])


import sys

from loguru import logger as log
from bs4 import BeautifulSoup
from pyquery import PyQuery as pq
from selenium.common.exceptions import ElementClickInterceptedException

from my_selenium import MySelenium
from locate104 import LocateOneZeroFour

# remove default level
log.remove()
# level DEBUG|INFO
log.add(sys.stderr, level="INFO", diagnose=True, backtrace=True)

class CrawlOneZeroFour(MySelenium, LocateOneZeroFour):

    def __int__(self, set_browser, target_url, headless):
        MySelenium.__init__(self, set_browser=set_browser, target_url=target_url, headless=headless)

    def go_search(self):
        __ERROR_CALL = "CrawlOneZeroFour.go_search"
        __SEARCH_LOCATE = self.css_locate['search_keyword']
        __SUBMIT = 'submit-buttons'

        # get url
        self.driver_get()
        self.wait_element(__SEARCH_LOCATE[__SUBMIT], f"[{__ERROR_CALL}:{__SUBMIT}]")

    def search_keyword(self, keys, value):
        __ERROR_CALL = "CrawlOneZeroFour.go_search"
        __SEARCH_LOCATE = self.css_locate['search_keyword']
        __SUBMIT = 'submit-buttons'
        __KEYWORD = 'keyword'
        __SEARCH_TYPE = 'search-type'
        find_keyword = self.find_element(__SEARCH_LOCATE[__KEYWORD], f"[{__ERROR_CALL}:{__KEYWORD}]")
        find_keyword.clear()
        find_keyword.send_keys(keys)
        # find_select_type = self.find_element(__SEARCH_LOCATE[__SEARCH_TYPE], f"[{__ERROR_CALL}:{__SEARCH_TYPE}]")
        # self.select_element(find_select_type, value)

    def job_cate(self, job_list):
        __ERROR_CALL = "CrawlOneZeroFour.job_cate"
        __SEARCH_LOCATE = self.css_locate['job_cate']
        __UL_LIST = 'result-list'
        __SUBMIT = 'submit'
        js_document_job_cate = "document.getElementById('jobCateLauncher').click();"
        # show job cate
        self.execute_script(js_document_job_cate)
        self.wait_element(__SEARCH_LOCATE[__UL_LIST], f"[{__ERROR_CALL}:{__UL_LIST}]", ec_mode="visi")
        ul_list_element = self.find_element("ul.result-list", f"[{__ERROR_CALL}:{__UL_LIST}]")
        log.debug(ul_list_element)
        ul_items = ul_list_element.find_elements_by_tag_name('li')
        log.debug(ul_items)

        find_count = len(job_list)
        for item in ul_items:
            log.debug(item.text)
            if item.text in job_list:
                item.find_element_by_css_selector('.result-list [type="checkbox"]').click()
                find_count -= 1
            elif find_count == 0:
                self.find_element(__SEARCH_LOCATE[__SUBMIT], f"[{__ERROR_CALL}:{__SUBMIT}]").click()
                break

    def exclusion_condition(self, value):
        __ERROR_CALL = "CrawlOneZeroFour.exclusion_condition"
        __SEARCH_LOCATE = self.css_locate['exclusion_condition']
        __TITLE_BUTTON = 'title_button'
        __EXCLUDE_SELECT = 'exclude_select'
        __STYLED_SELECT = 'styled-select'
        self.wait_element(__SEARCH_LOCATE[__TITLE_BUTTON], f"[{__ERROR_CALL}:{__TITLE_BUTTON}]", ec_mode="visi")
        self.find_element(__SEARCH_LOCATE[__TITLE_BUTTON], f"[{__ERROR_CALL}:{__TITLE_BUTTON}]").click()
        self.wait_element(__SEARCH_LOCATE[__STYLED_SELECT], f"[{__ERROR_CALL}:{__STYLED_SELECT}]", ec_mode="visi")
        self.find_element(__SEARCH_LOCATE[__STYLED_SELECT], f"[{__ERROR_CALL}:{__STYLED_SELECT}]").click()

        find_exclude_select = self.find_element(__SEARCH_LOCATE[__EXCLUDE_SELECT], f"[{__ERROR_CALL}:{__EXCLUDE_SELECT}]")

        self.select_element(find_exclude_select, value)

    @property
    def whole_submit(self):
        __ERROR_CALL = "CrawlOneZeroFour.whole_submit"
        __SEARCH_LOCATE = self.css_locate['whole_submit']
        __WHOLE_SUBMIT = 'whole_submit'
        __xWHOLE_SUBMIT = "//body//input[@id='searchSubmit']"
        __JOB_LIST = 'job-list'
        # self.find_element(__SEARCH_LOCATE[__WHOLE_SUBMIT], f"[{__ERROR_CALL}:{__WHOLE_SUBMIT}]").click()
        btn = self.find_element(__xWHOLE_SUBMIT, f"[{__ERROR_CALL}:{__xWHOLE_SUBMIT}]", selector='xpath')
        self.driver.execute_script("arguments[0].click();", btn)
        self.wait_element(__SEARCH_LOCATE[__JOB_LIST], f"[{__ERROR_CALL}:{__JOB_LIST}]", ec_mode="visi")
        return self.page_source()

    @staticmethod
    def write_my_soup(source):
        soup = BeautifulSoup(source, 'html5lib')
        prettify_soup = soup.prettify()
        with open("soup.html", mode="w", encoding="utf8") as soup_file:
            soup_file.write(prettify_soup)

    @staticmethod
    def read_my_soup():
        soup_data = BeautifulSoup(open("soup.html", encoding="utf8"), "html5lib")
        data1 = soup_data.find('main')
        # log.debug(soup.prettify())
        log.debug(data1)

    @staticmethod
    def pq_test(page):
        doc = pq(page)

        for title in doc('.items .title').parent().parent().items():
            log.debug(title)
            log.debug('"' + title.attr['data-cno'] + '"')
            log.debug('"' + f"https://www.104.com.tw/company/{title.attr['data-cno']}?jobsource=m104_hotorder" + '"')

        # title = [re.sub(',', ' _ ', '"' + title.text() + '"') for title in doc('.items .title').items()]
        # title = ['"' + title.text() + '"' for title in doc('.items .title').items()]
        # log.debug(title)

    @staticmethod
    def pq_read_driver(page):
        doc = pq(page)

        # title = [re.sub(',', ' _ ', '"' + title.text() + '"') for title in doc('.items .title').items()]
        title = ['"' + title.text() + '"' for title in doc('.items .title').items()]
        log.debug(title)

        # company = [re.sub(',', ' _ ', '"' + company.text() + '"') for company in doc('li>a>.company').items()]
        company = ['"' + company.text() + '"' for company in doc('li>a>.company').items()]
        log.debug(company)

        # location = [re.sub(',', ' _ ', '"' + location.text() + '"') for location in doc('li>a>p:nth-child(4)').items()]
        location = ['"' + location.text() + '"' for location in doc('li>a>p:nth-child(4)').items()]
        log.debug(location)

        title_link = [f"\"https://m.104.com.tw/{link.attrib['href']}\"" for link in doc('ul.job-list > li > a')]
        log.debug(title_link)

        com_link = ['"' + f"https://www.104.com.tw/company/{title.attr['data-cno']}?jobsource=m104_hotorder" + '"' for title in
                    doc('.items .title').parent().parent().items()]
        log.debug(com_link)

        res = [[t, tl, c, cl, l] for (t, tl, c, cl, l) in zip(title, title_link, company, com_link, location)]
        log.debug(res)

        with open("104.csv", mode='a', encoding='utf8') as f:
            for sub_index in range(len(res)):
                log.info(','.join(res[sub_index]))
                f.write(','.join(res[sub_index]) + '\n')

    def next_page(self):
        __ERROR_CALL = "CrawlOneZeroFour.next_page"
        __SEARCH_LOCATE = self.css_locate['whole_submit']
        __NEXT_PAGE = 'next_page'
        __UL_LIST = 'job-list'

        self.page_scroll_bottom()
        check_next_page = self.wait_element(__SEARCH_LOCATE[__NEXT_PAGE], f"[{__ERROR_CALL}:{__NEXT_PAGE}]", ec_mode="vis", seconds=3)

        log.debug(check_next_page)
        if not check_next_page:
            exit("check_next_page fail")

        self.find_element(__SEARCH_LOCATE[__NEXT_PAGE], f"[{__ERROR_CALL}:{__NEXT_PAGE}]").click()
        return self.page_source()

    def search_area(self, area):
        __ERROR_CALL = "CrawlOneZeroFour.search_area"
        __SEARCH_LOCATE = self.css_locate['search_area']
        __MENU_LIST = 'area_menu'
        __AREA_TW = 'area_tw'
        __TW_LABEL = 'tw_label'
        __AREA_BUTTON = 'area_button'
        js_search_area = "document.getElementById('searchAreaFake').click();"
        # show job cate
        self.execute_script(js_search_area)
        menu_list = self.wait_element(__SEARCH_LOCATE[__MENU_LIST], f"[{__ERROR_CALL}:{__MENU_LIST}]", ec_mode="visi")
        if not menu_list:
            exit("Wait menu_list fail")

        self.find_element(__SEARCH_LOCATE[__AREA_TW], f"[{__ERROR_CALL}:{__AREA_TW}]").click()

        tw_area_list = self.find_element('#area-menu .scd-cate:nth-child(2) > ul:last-child', f"[{__ERROR_CALL}:'tw_area_list']")
        log.debug(tw_area_list)

        tw_label_items = tw_area_list.find_elements_by_tag_name('label')
        # tw_label_items = tw_area_list.find_elements_by_css_selector('.active > span')
        log.debug(tw_label_items)

        find_count = len(area)
        for item in tw_label_items:
            log.debug(item.text)

            if item.text in area:

                try:
                    item.find_element_by_css_selector('.scd-class [type="checkbox"]').click()
                    find_count -= 1
                except ElementClickInterceptedException:
                    wait_checkbox = 0
                    while not wait_checkbox:
                        log.debug("do scroll bottom")
                        self.page_scroll_bottom()
                        wait_checkbox = self.wait_element(f"//span[text()='{area}']", f"[{__ERROR_CALL}:{__MENU_LIST}]", ec_mode="visi",
                                                          selector='xpath')
                        log.debug(wait_checkbox)
                    item.find_element_by_css_selector('.scd-class [type="checkbox"]').click()
                    find_count -= 1

            elif find_count == 0:
                self.find_element(__SEARCH_LOCATE[__AREA_BUTTON], f"[{__ERROR_CALL}:{__AREA_BUTTON}]").click()
                break

if __name__ == "__main__":
    url = "https://m.104.com.tw/search"
    keyword_keys = "auto in test 測試 SDET 程式"
    keyword_keys2 = "auto 測試 in test 自動 SDET Quality 品質 QA SET"
    # work_area = ['台中市'] # for test
    work_area = ['台北市']  # 新北市
    option_value = "全職"
    job_cate_list = ["測試人員", "軟體設計工程師", "軟韌體測試工程師", "電腦組裝／測試"]
    exclude_value = "排除派遣"
    ts_crawlonezerofour = CrawlOneZeroFour("chrome", url, headless=1)
    ts_crawlonezerofour.go_search()
    ts_crawlonezerofour.search_area(work_area)

    ts_crawlonezerofour.exclusion_condition(exclude_value)
    ts_crawlonezerofour.search_keyword(keyword_keys, option_value)
    ts_crawlonezerofour.job_cate(job_cate_list)
    ts_crawlonezerofour.search_keyword(keyword_keys2, option_value)
    current_page = ts_crawlonezerofour.whole_submit
    ts_crawlonezerofour.pq_read_driver(current_page)

    more_page = ts_crawlonezerofour.next_page()
    while more_page:
        ts_crawlonezerofour.pq_read_driver(more_page)
        more_page = ts_crawlonezerofour.next_page()

    ts_crawlonezerofour.driver_close()

    # ts_crawlonezerofour = CrawlOneZeroFour("no_driver")
    # ts_crawlonezerofour.read_csv()


import torch
def css(outputs, labels, n_classes, m, m2):
    batch_size = outputs.size(0)
    defer = [n_classes] * batch_size
    outputs = -m2 * torch.log2(outputs[range(batch_size),labels])\
              -m * torch.log2(outputs[range(batch_size), defer])
    return torch.sum(outputs) / batch_size

def my_CrossEntropyLoss(outputs, labels):
    batch_size = outputs.size()[0]  # batch_size
    # pick the values corresponding to the labels
    outputs = - torch.log2(outputs[range(batch_size), labels])
    return torch.sum(outputs) / batch_size

def madras_loss(outputs, rej, labels, expert, eps = 10e-12):
    # MixOfExperts loss of Madras et al. 2018
    batch_size = outputs.size()[0]
    output_no_grad = outputs.detach()
    net_loss_no_grad = -torch.log2(output_no_grad[range(batch_size), labels]+eps)
    net_loss = -torch.log2(outputs[range(batch_size), labels]+eps)
    exp_loss = -torch.log2(expert[range(batch_size), labels]+eps)
    system_loss =  (rej[range(batch_size),0])  *  net_loss_no_grad + rej[range(batch_size),1]  * exp_loss
    system_loss += net_loss
    return torch.sum(system_loss)/batch_size


import sys
# add module search path
sys.path.append('/flash/res')
sys.path.reverse() #revert search direction to load custom libs first

from producer import Producer
from subscriber import subscribe

try:
    import utime as time
except ModuleNotFoundError:
    import time

def is_int_or_float(*args, **kwargs):
    for arg in args:
        if type(arg) == int or type(arg) == float:
            pass
        else:
            raise ValueError('arg is not a float or int')

message_bus = Producer(
    name="my message bus", as_threads=True, validation=is_int_or_float)

def simple_logger(func):
    def with_logger(*args, **kwargs):
        print('%s got a message!' % func.__name__)
        result = func(*args, **kwargs)
        print('%s has finished!' % func.__name__)
        return result
    return with_logger

@subscribe(message_bus)
@simple_logger
def handler_1(*args, **kwargs):
    time.sleep(3)

@subscribe(message_bus)
@simple_logger
def handler_2(*args, **kwargs):
    time.sleep(2)

message_bus(123, some="me")


# O(n+p)
# n = numCourses | p = len(prerequisites)

class Solution:
    def findOrder(self, numCourses: int, prerequisites: List[List[int]]) -> List[int]:
        prerequisitesDict = self.buildPrerequisitesDict(prerequisites, numCourses)
        visited = set()
        order = []
        for course in prerequisitesDict:
            if not self.explore(course, prerequisitesDict, visited, set(), order):
                return []
        return order

    def explore(self, course, prerequisitesDict, visited, loop, order):
        if course in visited:
            return True
        if course in loop:
            return False
        loop.add(course)
        for prerequisite in prerequisitesDict[course]:
            if not self.explore(prerequisite, prerequisitesDict, visited, loop, order):
                loop.remove(course)
                return False
        loop.remove(course)
        order.append(course)
        visited.add(course)
        return True

    def buildPrerequisitesDict(self, prerequisites, numCourses):
        prerequisitesDict = {i: [] for i in range(numCourses)}
        for prerequisite in prerequisites:
            prerequisitesDict[prerequisite[0]].append(prerequisite[1])
        return prerequisitesDict


import re

from django import template
from django.template.defaultfilters import stringfilter
from django.utils.html import escape
from django.conf import settings

from django_fortunes.models import Fortune

register = template.Library()

@register.filter
@stringfilter
def fortunize(value):
    """
    Transforms a fortune plain text into htmlized (but safe) one.
    """
    r = ""
    for i, line in enumerate(value.splitlines()):
        m = re.findall(r"^<(\w+)>\s?(.*)$", line.strip())
        className = "odd" if i % 2 == 0 else "even"
        if (len(m) > 0):
            for match in m:
                nick = match[0]
                quote = escape(match[1])
                r += "
<%s>

<q>%s</q>
\n" % (className, nick, quote)
        else:
            r += "

%s
\n" % (escape(line))
    return "
%s
" % r

@register.inclusion_tag('partials/topcontributors.html')
def top_contributors():
    """
    Displays the list of MAX_TOP_CONTRIBUTORS top contributors
    """
    max = getattr(settings, 'FORTUNES_MAX_TOP_CONTRIBUTORS', 5)
    return {'authors': Fortune.objects.top_authors()[:max]}


from tests.my_test_case import MyTestCase
from configuration import PrefixDict

class TestUtils(MyTestCase):
    def setUp(self):
        pass

    def test_prefix_dict(self):
        words = ['ban', 'banka', 'bankestr', 'banket', 'bankik', 'banks', 'blan', 'blanka', 'blankestr', 'blanket',
                 'blankik', 'blanks', 'blau', 'blaua', 'blauestr', 'blauet', 'blauik', 'blaus', 'brut', 'bruta',
                 'brutestr', 'brutet', 'brutik', 'bruts', 'dolen', 'dolenta', 'dolentestr', 'dolentet', 'dolentik',
                 'dolents', 'elefan', 'elefanta', 'elefantestr', 'elefantet', 'elefantik', 'elefants', 'fu', 'fuma',
                 'fumestr', 'fumet', 'fumik', 'fums', 'gra', 'grana', 'granestr', 'granet', 'granik', 'grans', 'gris',
                 'grisa', 'grisestr', 'griset', 'grisik', 'griss', 'kaima', 'kaimana', 'kaimanestr', 'kaimanet',
                 'kaimanik', 'kaimans', 'kalen', 'kalenta', 'kalentestr', 'kalentet', 'kalentik', 'kalents', 'kam',
                 'kampa', 'kampestr', 'kampet', 'kampik', 'kamps', 'kap', 'kapa', 'kapestr', 'kapet', 'kapik', 'kaps',
                 'kasa', 'kasaa', 'kasaestr', 'kasaet', 'kasaik', 'kasas', 'katala', 'katalana', 'katalanestr',
                 'katalanet', 'katalanik', 'katalans', 'kuzi', 'kuzina', 'kuzinestr', 'kuzinet', 'kuzinik', 'kuzins',
                 'len', 'lenta', 'lentestr', 'lentet', 'lentik', 'lents', 'leo', 'leona', 'leonestr', 'leonet',
                 'leonik', 'leons', 'mal', 'mala', 'malestr', 'malet', 'malik', 'mals', 'metal', 'metala', 'metalestr',
                 'metalet', 'metalik', 'metals', 'nebot', 'nebota', 'nebotestr', 'nebotet', 'nebotik', 'nebots',
                 'negre', 'negrea', 'negreestr', 'negreet', 'negreik', 'negres', 'pikan', 'pikanta', 'pikantestr',
                 'pikantet', 'pikantik', 'pikants', 'pla', 'plana', 'planestr', 'planet', 'planik', 'plans', 'plasa',
                 'plasaa', 'plasaestr', 'plasaet', 'plasaik', 'plasas', 'pri', 'prima', 'primestr', 'primet', 'primik',
                 'prims', 'profun', 'profunda', 'profundestr', 'profundet', 'profundik', 'profunds', 'sile', 'silena',
                 'silenestr', 'silenet', 'silenik', 'silens', 'telefo', 'telefona', 'telefonestr', 'telefonet',
                 'telefonik', 'telefons', 'tin', 'tinka', 'tinkestr', 'tinket', 'tinkik', 'tinks']
        prefix_dict = PrefixDict(words)
        print(prefix_dict.words_by_prefix)
        print(prefix_dict.prefixes_by_word)


#Лістинг 2
a = [1, 2, 3]
b = 5

def func(x, y):
    x.append(4)
    y = y + 1

func(a, b)
print("a=", a) # Вихід a=[1, 2, 3, 4]
print("b=", b) # Вихід b=5

# лістинг 5
def f(x):
    def g(y):
        return y
    return g
a = 5
b = 1
h=f(a)
h(b) # Вихід 1


# This program is in the public domain
# Author: Paul Kienzle
"""
SNS data loaders

The following instruments are defined::

    Liquids, Magnetic

These are :class:`resolution.Pulsed` classes tuned with
default instrument parameters and loaders for reduced SNS data.
See :mod:`resolution` for details.
"""

import re
import math

import numpy as np

from bumps.data import parse_file

from .rebin import rebin
from .instrument import Pulsed
from . import resolution
from .probe import make_probe

## Estimated intensity vs. wavelength for liquids reflectometer
LIQUIDS_FEATHER = np.array([
    (2.02555, 20.6369),
    (2.29927, 23.6943),
    (2.57299, 23.6943),
    (2.87409, 21.1146),
    (3.22993, 15.5732),
    (3.58577, 12.8981),
    (4.07847, 9.4586),
    (4.5438, 6.59236),
    (5.11861, 4.68153),
    (5.7208, 3.05732),
    (6.37774, 1.91083),
    (7.19891, 1.24204),
    (8.04745, 0.955414),
    (9.06022, 0.573248),
    (10.1825, 0.477707),
    (11.4142, 0.382166),
    (12.8102, 0.191083),
    (14.3431, 0.286624),
]).T

def load(filename, instrument=None, **kw):
    """
    Return a probe for SNS data.
    """
    if instrument is None:
        instrument=Pulsed()
    header, data = parse_sns_file(filename)
    header.update(**kw) # calling parameters override what's in the file.
    #print "\n".join(k+":"+str(v) for k, v in header.items())
    # Guess what kind of data we have
    if has_columns(header, ('Q', 'dQ', 'R', 'dR', 'L')):
        probe = QRL_to_data(instrument, header, data)
    elif has_columns(header, ('time_of_flight', 'data', 'Sigma')):
        probe = TOF_to_data(instrument, header, data)
    else:
        raise IOError("Unknown columns: "+", ".join(header['columns']))
    probe.title = header['title']
    probe.date = header['date']
    probe.instrument = header['instrument']
    return probe

def has_columns(header, v):
    return (len(header['columns']) == len(v)
            and all(ci == si for ci, si in zip(header['columns'], v)))

def QRL_to_data(instrument, header, data):
    """
    Convert data to T, L, R
    """
    Q, dQ, R, dR, L = data
    dL = resolution.binwidths(L)
    if 'angle' in header and 'slits_at_Tlo' in header:
        T = header.pop('angle', header.pop('T', None))
        probe = instrument.probe(L=L, dL=dL, T=T, data=(R, dR),
                                 **header)
    else:
        T = resolution.QL2T(Q[0], L[0])
        dT = resolution.dQdL2dT(Q[0], dQ[0], L[0], dL[0])
        probe = make_probe(T=T, dT=dT, L=L, dL=dL, data=(R, dR),
                           **header)
    return probe

def TOF_to_data(instrument, header, data):
    """
    Convert TOF data to neutron probe.

    Wavelength is set from the average of the times at the edges of the
    bins, not the average of the wavelengths.  Wavelength resolution is
    set assuming the wavelength at the edges of the bins defines the
    full width at half maximum.

    The correct answer is to look at the wavelength distribution within
    the bin including effects of pulse width and intensity as a function
    wavelength and use that distribution, or a gaussian approximation
    thereof, when computing the resolution effects.
    """
    TOF, R, dR = data
    Ledge = resolution.TOF2L(instrument.d_moderator, TOF)
    L = resolution.TOF2L(instrument.d_moderator, (TOF[:-1]+TOF[1:])/2)
    dL = (Ledge[1:]-Ledge[:-1])/2.35   # FWHM is 2.35 sigma
    R = R[:-1]
    dR = dR[:-1]
    min_time, max_time = header.get('TOF_range', instrument.TOF_range)
    keep = (np.isfinite(R)
            & np.isfinite(dR)
            & (TOF[:-1] >= min_time)
            & (TOF[1:] <= max_time))
    L, dL, R, dR = [v[keep] for v in (L, dL, R, dR)]
    T = np.array([header.get('angle', header.get('T', None))], 'd')
    T, dT, L, dL = instrument.resolution(L=L, dL=dL, T=T, **header)
    probe = make_probe(T=T, dT=dT, L=L, dL=dL, data=(R, dR), **header)
    return probe

def parse_sns_file(filename):
    """
    Parse SNS reduced data, returning *header* and *data*.

    *header* dictionary of fields such as 'data', 'title', 'instrument'
    *data* 2D array of data
    """
    raw_header, data = parse_file(filename)
    header = {}

    # guess instrument from file name
    original_file = raw_header.get('F', 'unknown')
    if 'REF_L' in original_file:
        instrument = 'Liquids'
    elif 'REF_M' in original_file:
        instrument = 'Magnetic'
    else:
        instrument = 'unknown'
    header['instrument'] = instrument
    header['filename'] = original_file
    header['radiation'] = 'neutron'

    # Plug in default instrument values for slits
    if 'instrument' in header and header['instrument'] in INSTRUMENTS:
        instrument = INSTRUMENTS[header['instrument']]
        header['d_s1'] = instrument.d_s1
        header['d_s2'] = instrument.d_s2

    # Date-time field for the file
    header['date'] = raw_header.get('D', '')

    # Column names and units
    columnpat = re.compile(r'(?P<name>\w+)\((?P<units>[^)]*)\)')
    columns, units = zip(*columnpat.findall(raw_header.get('L', '')))
    header['columns'] = columns
    header['units'] = units

    # extra information like title, angle, etc.
    commentpat = re.compile(r'(?P<name>.*)\s*:\s*(?P<value>.*)\s*\n')
    comments = dict(commentpat.findall(raw_header.get('C', '')))
    header['title'] = comments.get('Title', '')
    header['description'] = comments.get('Notes', '')

    # parse values of the form "Long Name: (value, 'units')" in comments
    valuepat = re.compile(r"[(]\s*(?P<value>.*)\s*, \s*'(?P<units>.*)'\s*[)]")
    def parse_value(valstr):
        d = valuepat.match(valstr).groupdict()
        return float(d['value']), d['units']
    if 'Detector Angle' in comments:
        header['angle'], _ = parse_value(comments['Detector Angle'])

    return header, data

def write_file(filename, probe, original=None, date=None,
               title=None, notes=None, run=None, charge=None):
    """
    Save probe as SNS reduced file.
    """
## Example header
#F /SNSlocal/REF_L/2007_1_4B_SCI/2895/NeXus/REF_L_2895.nxs
#E 1174593434.7
#D 2007-03-22 15:57:14
#C Run Number: 2895
#C Title: MK NR4 dry 032007_No2Rep0
#C Notes: MK NR 4 DU 53 dry from air
#C Detector Angle: (0.0, 'degree')
#C Proton Charge: 45.3205833435

#S 1 Spectrum ID ('bank1', (85, 151))
#N 3
#L time_of_flight(microsecond) data() Sigma()
    from datetime import datetime as dt

    parts = []
    if original is None: original = filename
    if date is None:
        date = dt.strftime ( dt.now(), '%Y-%m-%d %H:%M:%S')
    parts.append('#F '+original)
    parts.append('#D '+date)
    if run is not None:
        parts.append('#C Run Number: %s'%run)
    if title is not None:
        parts.append('#C Title: %s'%title)
    if notes is not None:
        parts.append('#C Notes: %s'%notes)
    parts.append("#C Detector Angle: (%g, 'degree')"%probe.T[0])
    if charge is not None:
        parts.append('#C Proton Charge: %s'%charge)
    parts.append('')
    parts.append('#N 5')
    parts.append('#L Q(1/A) dQ(1/A) R() dR() L(A)')
    parts.append('')
    header = "\n".join(parts)
    probe.write_data(filename, columns=['Q', 'dQ', 'R', 'dR', 'L'],
                     header=header)

class SNSData(object):
    def load(self, filename, **kw):
        return load(filename, instrument=self, **kw)

# TODO: print "Insert correct slit distances for Liquids and Magnetic"
class Liquids(SNSData, Pulsed):
    """
    Loader for reduced data from the SNS Liquids instrument.
    """
    instrument = "Liquids"
    radiation = "neutron"
    feather = LIQUIDS_FEATHER
    wavelength = 2., 15.
    #wavelength = 0.5, 5
    #wavelength = 5.5, 10
    #wavelength = 10.5, 15
    dLoL = 0.02
    d_s1 = 230.0 + 1856.0
    d_s2 = 230.0
    d_moderator = 14.850 # moderator to detector distance
    TOF_range = (6000, 60000)

class Magnetic(SNSData, Pulsed):
    """
    Loader for reduced data from the SNS Magnetic instrument.
    """
    instrument = "Magnetic"
    radiation = "neutron"
    wavelength = 1.8, 14
    dLoL = 0.02
    d_s1 = 75*2.54
    d_s2 = 14*2.54

# Instrument names assigned by reflpak
INSTRUMENTS = {
    'Liquids': Liquids,
    'Magnetic': Magnetic,
    }

# ===== utils ==============

def intensity_from_spline(Lrange, dLoL, feather):
    L0, L1 = Lrange
    n = math.ceil(math.log(L1/L0)/math.log(1+dLoL))
    L = L0*(1+dLoL)**np.arange(0, n)
    return (L[:-1]+L[1:])/2, rebin(feather[0], feather[1], L)

def boltzmann_feather(L, counts=100000, range=None):
    """
    Return expected intensity as a function of wavelength given the TOF
    feather range and the total number of counts.

    TOF feather is approximately a boltzmann distribution with gaussian
    convolution.  The following looks pretty enough; don't know how well it
    corresponds to the actual SNS feather.
    """
    import scipy.stats
    y = np.linspace(-4, 4, 10)
    G = np.exp(-y**2/10)
    x = np.arange(12, 85)
    B = scipy.stats.boltzmann.pmf(x, 0.05, counts, loc=16)
    BGz = np.convolve(B, G, mode='same')
    #if range is None: range = L[0], L[-1]
    #if range[0] > range[1]: range = range[::-1]
    #range = range[0]*(1-1e-15), range[1]*(1+1e-15)
    #z = np.linspace(range[0], range[1], len(BGz))
    z = np.linspace(2, 16.5, len(BGz))  # Wavelength range for liquids
    pL = np.interp(L, z, BGz, left=0, right=0)
    nL = pL/sum(pL)*counts
    return  nL


"""Stock Prediction"""

"""Requirements"""

import pandas as pd
import yfinance as yf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import LSTM, Dense
from tensorflow.keras.callbacks import ModelCheckpoint
from tensorflow.keras.callbacks import Callback
import numpy as np
import matplotlib.pyplot as plt
from tensorflow.keras.optimizers import Adam
import tensorflow as tf
import tensorflow.lite as tflite
import tensorflow_model_optimization as tfmot

"""## Metrics

SMAPE
"""

def calculate_smape(actual, predicted):

    numerator = np.abs(predicted - actual)
    denominator = (np.abs(predicted) + np.abs(actual)) / 2

    smape = np.mean(numerator / denominator) * 100

    return smape

"""MAPE"""

def calculate_mape(actual, predicted):

    actual = np.array(actual)
    predicted = np.array(predicted)

    absolute_percentage_errors = np.abs((actual - predicted) / actual)
    mape = np.mean(absolute_percentage_errors) * 100

    return mape

"""RSME"""

def calculate_rmse(actual, predicted):
    actual = np.array(actual)
    predicted = np.array(predicted)

    squared_errors = (predicted - actual) ** 2
    mean_squared_error = np.mean(squared_errors)
    rmse = np.sqrt(mean_squared_error)

    return rmse

"""### Load model"""

model = tf.keras.models.load_model('apple_model.h5')
print("Main Model is Loaded!")

"""## Quantization"""

annotated_layers = [
    tfmot.quantization.keras.quantize_annotate_layer(model.layers[0]),
    tfmot.quantization.keras.quantize_annotate_layer(model.layers[1])
]
quantize_model = tf.keras.Sequential(annotated_layers + model.layers[2:])

quantize_model.compile(optimizer='adam', loss='mean_squared_error')
converter = tf.lite.TFLiteConverter.from_keras_model(quantize_model)

converter.experimental_new_converter = True

converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS, tf.lite.OpsSet.SELECT_TF_OPS]
converter._experimental_lower_tensor_list_ops = False

"""Save quantized model to a file"""

tflite_model = converter.convert()
with open('models/apple_quantized_model.tflite', 'wb') as f:
    f.write(tflite_model)
print("Quantized Model is saved!")


'''
Input: a List of integers
Returns: a List of integers
'''
def moving_zeroes(arr):
    zeros = list(filter(lambda ii: ii == 0, arr))
    no_zeros = list(filter(lambda ii: ii != 0, arr)) + zeros
    return no_zeros

if __name__ == '__main__':
    # Use the main function here to test out your implementation
    arr = [0, 3, 1, 0, -2]

    print(f"The resulting of moving_zeroes is: {moving_zeroes(arr)}")


####################################################################################################
# Copyright 2013 John Crawford
#
# This file is part of PatchCorral.
#
# PatchCorral is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# PatchCorral is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with PatchCorral.  If not, see <http://www.gnu.org/licenses/>.
####################################################################################################

## @file
#  Initializes the GUI for SynthNav.

from PySide import QtGui, QtCore
from patchcorral.src.engine import mididevice
import traceback

##
#  Base class for voice list widgets.
class VoiceListWidget(QtGui.QWidget):

  ## Currently-assigned patchcorral.src.engine.mididevice.MIDIVoiceList object.
  voiceList = None

  class TableWidget(QtGui.QTableWidget):

    keyPressed = QtCore.Signal(QtGui.QKeyEvent)

    def keyPressEvent(self, event):
      super().keyPressEvent(event)
      self.keyPressed.emit(event)

  def __init__(self, parent, synthNav):
    super().__init__(parent)
    self.synthNav = synthNav
    assert self.voiceList is not None, '"self.voiceList" needs to be populated by the subclass.'
    self.voiceMap = {}
    if len(self.voiceList) == 0:
      self.cols = mididevice.MIDIVoice.tags
    else:
      self.cols = list(self.voiceList[0].keys())
    self.numCols = len(self.cols)
    #Create widgets.
    self.tw_currVoices = self.TableWidget(0, self.numCols, self)
    self.tw_currVoices.setHorizontalHeaderLabels(self.cols)
    #Lay it out.
    self.vbox = QtGui.QVBoxLayout(self)
    self.vbox.addWidget(self.tw_currVoices)
    #Populate voices.
    self.setVoiceList(self.voiceList)
    #Connect signals.
    self.tw_currVoices.keyPressed.connect(self.onKeypressEvent)

  def onKeypressEvent(self, event):
    pass

  def refreshCurrVoices(self):
    print("refreshCurrVoices called")
    rowCountI = self.tw_currVoices.rowCount()
    rowCountF = min(len(self.voiceList), 1000)
    self.tw_currVoices.clearContents()
    print("refreshCurrVoices setting row count")
    self.tw_currVoices.setRowCount(rowCountF)
    assert self.tw_currVoices.rowCount() == rowCountF, '{} != {}'.format(self.tw_currVoices.rowCount(), rowCountF)
    print("refreshCurrVoices entering for loops")
    for row, voice in zip(range(rowCountF), self.voiceList):
      for col, attr in enumerate(self.cols):
        item = self.tw_currVoices.item(row, col)
        if item is None or item is 0:
          item = QtGui.QTableWidgetItem(str(voice[attr]))
          isNewItem = True
        else:
          item.setText(str(voice[attr]))
          isNewItem = False
        # self.voiceMap[voice] = item
        item.setFlags(item.flags() ^ QtCore.Qt.ItemIsEditable)
        item.voice = voice
        if isNewItem:
          self.tw_currVoices.setItem(row, col, item)
    print("refreshCurrVoices returning")

  def setVoiceList(self, voiceList):
    oVoiceList = self.voiceList
    if isinstance(voiceList, str):
      voiceList = self.synthNav.getVoiceList(voiceList)
    self.voiceList = voiceList
    try:
      self.refreshCurrVoices()
    except:
      self.voiceList = oVoiceList
      self.refreshCurrVoices()
      raise
    else:
      try:
        self.voiceList.listModified.disconnect(self.refreshCurrVoices)
      except:
        traceback.print_exc()
    self.voiceList.listModified.connect(self.refreshCurrVoices)

##
#  Widget displaying voices that remain after applying the selected filters.
class FilteredVoiceListWidget(VoiceListWidget):

  voiceDoubleClicked = QtCore.Signal(mididevice.MIDIVoice)

  def __init__(self, parent, synthNav):
    self.voiceList = synthNav.getFilteredVoiceList()
    super().__init__(parent, synthNav)
    self.tw_currVoices.itemDoubleClicked.connect(self.onItemDoubleClicked)
    self.tw_currVoices.itemSelectionChanged.connect(self.onItemSelectionChanged)

  def onItemDoubleClicked(self, item):
    self.voiceDoubleClicked.emit(item.voice)

  def onItemSelectionChanged(self):
    selectedItems = self.tw_currVoices.selectedItems()
    if len(selectedItems) > 0:
      selectedItems[0].voice.pc()

  def onKeypressEvent(self, event):
    if event.key() in [QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return]:
      self.synthNav.getVoiceList('queued').adds(item.voice for item in self.tw_currVoices.selectedItems())

class VoiceListSelectWidget(QtGui.QComboBox):

  selectionChanged = QtCore.Signal(str)

  def __init__(self, parent, synthNav):
    super().__init__(parent)
    self.addItems(list(synthNav.voiceLists.keys()))
    self.currentIndexChanged.connect(self.onCurrentIndexChanged)

  def onCurrentIndexChanged(self, idx):
    self.selectionChanged.emit(self.itemText(idx))

##
#  Widget displaying voices in the currently-selected user list.
class VoiceListEditWidget(VoiceListWidget):

  def __init__(self, parent, synthNav, voiceList="queued"):
    self.voiceList = synthNav.getVoiceList(voiceList)
    super().__init__(parent, synthNav)
    self.pb_clearQueue = QtGui.QPushButton("Clear Queue")
    self.vbox.addWidget(self.pb_clearQueue)
    self.pb_clearQueue.pressed.connect(self.onClearButtonPressed)
    self.tw_currVoices.itemDoubleClicked.connect(self.onItemDoubleClicked)

  def onClearButtonPressed(self):
    self.voiceList.clear()

  def onItemDoubleClicked(self, item):
    item.voice.pc()

  def onKeypressEvent(self, event):
    if event.key() in [QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return]:
      items = self.tw_currVoices.selectedItems()
      try:
        item = items[0]
      except IndexError:
        pass
      else:
        item.voice.pc()
    elif event.key() in [QtCore.Qt.Key_Delete]:
      currCell = [self.tw_currVoices.currentRow(), self.tw_currVoices.currentColumn()]
      items = self.tw_currVoices.selectedItems()
      self.voiceList.remove(*(item.voice for item in items))
      if currCell[0] >= self.tw_currVoices.rowCount():
        currCell[0] = self.tw_currVoices.rowCount()
      self.tw_currVoices.setCurrentCell(*currCell)


from django.urls import path
from .views import *

urlpatterns = [

    path('api/', PostList.as_view()),
    path('api/<int:pk>/', PostDetail.as_view()),
    path("", sorry, name="sorry"),
    # path('location/', LocationList.as_view()),
    # path('location/<int:pk>/', LocationDetail.as_view()),
]


from typing import List

class Solution:
    def numRescueBoats(self, people: List[int], limit: int) -> int:
        people.sort()

        heavy_person = len(people) - 1
        light_person = 0

        boats = 0

        while heavy_person >= light_person:
            if heavy_person == light_person:
                boats += 1
                break

            if people[heavy_person] + people[light_person] <= limit:
                light_person += 1

            boats += 1
            heavy_person -= 1

        return boats

if __name__ == "__main__":
    solution = Solution()

    print(solution.numRescueBoats([3, 5, 3, 4], 5))


import json

with open("brassiceae3.txt", "r", encoding="utf-8") as f:
    lines = f.readlines()
data_1 = open("brassiceae3奇数行.txt", 'w', encoding='utf-8')
data_2 = open("brassiceae3偶数行.txt", 'w', encoding='utf-8')

num = 0  # 行数-1
for line in lines:
    if (num % 2) == 0:  # num为偶数说明是奇数行
        print(line.strip(), file=data_1)  # .strip用来删除空行
    else:  # # num为奇数说明是偶数行
        print(line.strip(), file=data_2)
    num += 1

data_1.close()
data_2.close()


import json
import matplotlib.pyplot as plt

print("Loading cross validation history...")

with open("imdb_histories", "r") as f:
    histories = json.load(f)

# Visualizing the data
control  = histories[0]
ctrl_val = control["val_loss"]
epochs   = range(1, len(ctrl_val) + 1)

print("Plotting comparisions...")
for idx, hist in enumerate(histories[1:]):
    hist_val = hist["val_loss"]
    title    = "Comparison " + str(idx)

    plt.title(title)
    plt.plot(epochs, ctrl_val, 'bo')
    plt.plot(epochs, hist_val, 'b+')
    plt.xlabel('Epochs')
    plt.ylabel('Loss')

    plt.savefig("comparison" + "_" + str(idx) + ".png")
    plt.clf()


import pytest

from eth2.beacon.db.chain import BeaconChainDB
from eth2.beacon.state_machines.forks.serenity.blocks import (
    SerenityBeaconBlock,
)
from eth2.beacon.tools.builder.initializer import (
    create_mock_genesis,
)
from eth2.beacon.tools.builder.proposer import (
    create_mock_block,
)
from eth2.beacon.tools.builder.validator import (
    create_mock_signed_attestations_at_slot,
)

@pytest.mark.long
@pytest.mark.parametrize(
    (
        'num_validators,'
        'slots_per_epoch,'
        'min_attestation_inclusion_delay,'
        'target_committee_size,'
        'shard_count'
    ),
    [
        (40, 8, 2, 3, 2)
    ]
)
def test_demo(base_db,
              num_validators,
              config,
              keymap,
              fixture_sm_class):
    genesis_slot = config.GENESIS_SLOT
    genesis_epoch = config.GENESIS_EPOCH
    chaindb = BeaconChainDB(base_db)

    genesis_state, genesis_block = create_mock_genesis(
        num_validators=num_validators,
        config=config,
        keymap=keymap,
        genesis_block_class=SerenityBeaconBlock,
    )
    for i in range(num_validators):
        assert genesis_state.validator_registry[i].is_active(genesis_slot)

    chaindb.persist_block(genesis_block, SerenityBeaconBlock)
    chaindb.persist_state(genesis_state)

    state = genesis_state
    block = genesis_block

    chain_length = 3 * config.SLOTS_PER_EPOCH
    blocks = (block,)

    attestations_map = {}  # Dict[Slot, Sequence[Attestation]]

    for current_slot in range(genesis_slot + 1, genesis_slot + chain_length):
        if current_slot > genesis_slot + config.MIN_ATTESTATION_INCLUSION_DELAY:
            attestations = attestations_map[current_slot - config.MIN_ATTESTATION_INCLUSION_DELAY]
        else:
            attestations = ()

        block = create_mock_block(
            state=state,
            config=config,
            state_machine=fixture_sm_class(
                chaindb,
                blocks[-1],
            ),
            block_class=SerenityBeaconBlock,
            parent_block=block,
            keymap=keymap,
            slot=current_slot,
            attestations=attestations,
        )

        # Get state machine instance
        sm = fixture_sm_class(
            chaindb,
            blocks[-1],
        )
        state, _ = sm.import_block(block)

        chaindb.persist_state(state)
        chaindb.persist_block(block, SerenityBeaconBlock)

        blocks += (block,)

        # Mock attestations
        attestation_slot = current_slot
        attestations = create_mock_signed_attestations_at_slot(
            state=state,
            config=config,
            attestation_slot=attestation_slot,
            beacon_block_root=block.root,
            keymap=keymap,
            voted_attesters_ratio=1.0,
        )
        attestations_map[attestation_slot] = attestations

    assert state.slot == chain_length - 1 + genesis_slot
    assert isinstance(sm.block, SerenityBeaconBlock)

    # Justification assertions
    assert state.justified_epoch == 2 + genesis_epoch
    assert state.finalized_epoch == 1 + genesis_epoch


def isContained(firstPair, secondPair):
    if firstPair[0] <= secondPair[0] <= firstPair[1] and firstPair[0] <= secondPair[1] <= firstPair[1]:
        return True
    if secondPair[0] <= firstPair[0] <= secondPair[1] and secondPair[0] <= firstPair[1] <= secondPair[1]:
        return True
    return False

def isOverlap(firstPair, secondPair):
    if secondPair[1] >= firstPair[1] >= secondPair[0] or firstPair[1] >= secondPair[1] >= firstPair[0]:
        return True
    if secondPair[1] >= firstPair[0] >= secondPair[0] or firstPair[1] >= secondPair[0] >= firstPair[0]:
        return True
    return isContained(firstPair, secondPair)

if __name__ == '__main__':
    f = open('./day4_input.txt', 'r')
    lines = f.readlines()

    fullyContainedPairs = 0
    overlappingPairs = 0

    for l in lines:
        firstPair = l.strip().split(',')[0].split('-')
        secondPair = l.strip().split(',')[1].split('-')

        if isContained([eval(i) for i in firstPair], [eval(i) for i in secondPair]):
            fullyContainedPairs += 1
        if isOverlap([eval(i) for i in firstPair], [eval(i) for i in secondPair]):
            overlappingPairs += 1

    print(fullyContainedPairs)
    print(overlappingPairs)


# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

from unittest import mock

from senlin.db.sqlalchemy import api as db_api
from senlin.db.sqlalchemy import utils as db_utils
from senlin.tests.unit.common import base
from senlin.tests.unit.common import utils

class DBAPIRegistryTest(base.SenlinTestCase):
    def setUp(self):
        super(DBAPIRegistryTest, self).setUp()
        self.ctx = utils.dummy_context()

        db_api.service_create('SERVICE_ID')

    def _create_registry(self, cluster_id, check_type, interval, params,
                         engine_id):
        return db_api.registry_create(self.ctx, cluster_id, check_type,
                                      interval, params, engine_id)

    def test_registry_create_get(self):
        registry = self._create_registry(cluster_id='CLUSTER_ID',
                                         check_type='NODE_STATUS_POLLING',
                                         interval=60,
                                         params={},
                                         engine_id='ENGINE_ID')
        ret_registries = db_api.registry_claim(self.ctx, registry.engine_id)
        self.assertEqual(1, len(ret_registries))
        ret_registry = ret_registries[0]
        self.assertEqual(registry.id, ret_registry.id)
        self.assertEqual(registry.cluster_id, ret_registry.cluster_id)
        self.assertEqual(registry.check_type, ret_registry.check_type)
        self.assertEqual(registry.interval, ret_registry.interval)
        self.assertEqual(registry.params, ret_registry.params)
        self.assertEqual(registry.engine_id, ret_registry.engine_id)

    def test_registry_update(self):
        self._create_registry(cluster_id='FAKE_ID',
                              check_type='NODE_STATUS_POLLING',
                              interval=60,
                              params={},
                              engine_id='DEAD_ENGINE')

        registries = db_api.registry_claim(self.ctx, engine_id='ENGINE_ID')
        self.assertTrue(registries[0].enabled)

        db_api.registry_update(self.ctx, 'FAKE_ID', {'enabled': False})
        registries = db_api.registry_claim(self.ctx, engine_id='NEW_ENGINE_ID')
        self.assertFalse(registries[0].enabled)

    def test_registry_claim(self):
        for i in range(2):
            cluster_id = 'cluster-%s' % i
            self._create_registry(cluster_id=cluster_id,
                                  check_type='NODE_STATUS_POLLING',
                                  interval=60,
                                  params={},
                                  engine_id='DEAD_ENGINE')

        registries = db_api.registry_claim(self.ctx, engine_id='ENGINE_ID')
        self.assertEqual(2, len(registries))
        self.assertEqual('DEAD_ENGINE', registries[0].engine_id)
        self.assertEqual('DEAD_ENGINE', registries[1].engine_id)

    @mock.patch.object(db_utils, 'is_service_dead')
    def test_registry_claim_with_dead_engine(self, mock_check):
        db_api.service_create('SERVICE_ID_DEAD')
        self._create_registry(
            cluster_id='CLUSTER_1', check_type='NODE_STATUS_POLLING',
            interval=60, params={}, engine_id='SERVICE_ID')
        self._create_registry(
            cluster_id='CLUSTER_1', check_type='NODE_STATUS_POLLING',
            interval=60, params={}, engine_id='SERVICE_ID_DEAD')

        mock_check.side_effect = [False, True]

        registries = db_api.registry_claim(self.ctx, engine_id='ENGINE_ID')

        self.assertEqual(1, len(registries))
        self.assertEqual('SERVICE_ID_DEAD', registries[0].engine_id)

    def test_registry_delete(self):
        registry = self._create_registry('CLUSTER_ID',
                                         check_type='NODE_STATUS_POLLING',
                                         interval=60,
                                         params={},
                                         engine_id='ENGINE_ID')
        db_api.registry_delete(self.ctx, 'CLUSTER_ID')
        self.assertEqual([], db_api.registry_claim(self.ctx,
                                                   registry.engine_id))

    def test_registry_get(self):
        obj = self._create_registry(cluster_id='FAKE_ID',
                                    check_type='NODE_STATUS_POLLING',
                                    interval=60,
                                    params={},
                                    engine_id='DEAD_ENGINE')

        registry = db_api.registry_get(self.ctx, 'FAKE_ID')

        self.assertEqual(registry.id, obj.id)
        self.assertEqual(registry.cluster_id, obj.cluster_id)
        self.assertEqual(registry.check_type, obj.check_type)
        self.assertEqual(registry.interval, obj.interval)
        self.assertEqual(registry.params, obj.params)
        self.assertEqual(registry.engine_id, obj.engine_id)

    def test_registry_get_by_engine(self):
        obj = self._create_registry(cluster_id='FAKE_ID',
                                    check_type='NODE_STATUS_POLLING',
                                    interval=60,
                                    params={},
                                    engine_id='ENGINE')

        registry = db_api.registry_get_by_param(
            self.ctx, {"cluster_id": "FAKE_ID", "engine_id": "ENGINE"})

        self.assertEqual(registry.id, obj.id)
        self.assertEqual(registry.cluster_id, obj.cluster_id)
        self.assertEqual(registry.check_type, obj.check_type)
        self.assertEqual(registry.interval, obj.interval)
        self.assertEqual(registry.params, obj.params)
        self.assertEqual(registry.engine_id, obj.engine_id)

    def test_registry_list_ids_by_service(self):
        for index in range(10):
            self._create_registry(
                cluster_id='MAIN_FAKE_ID_%d' % index,
                check_type='NODE_STATUS_POLLING',
                interval=60,
                params={},
                engine_id='ENGINE0'
            )
        for index in range(10):
            self._create_registry(
                cluster_id='FAKE_ID_%d' % (index + 1),
                check_type='NODE_STATUS_POLLING',
                interval=60,
                params={},
                engine_id='ENGINE%d'
            )

        registries = db_api.registry_list_ids_by_service(self.ctx, 'ENGINE0')
        self.assertEqual(10, len(registries))
        for registry in registries:
            self.assertIn('MAIN_FAKE_ID', registry.cluster_id)

    def test_registry_list_ids_by_service_is_empty(self):
        self._create_registry(
            cluster_id='FAKE_ID',
            check_type='NODE_STATUS_POLLING',
            interval=60,
            params={},
            engine_id='ENGINE'
        )

        registries = db_api.registry_list_ids_by_service(self.ctx, 'ENGINE1')
        self.assertEqual(0, len(registries))