import os
import json
import time
from PySide2 import QtCore

class GetCollectionItems(QtCore.QObject):

    init_run = QtCore.Signal(str)

    start_process = QtCore.Signal(int)
    add_entry = QtCore.Signal(dict)
    end_process = QtCore.Signal()
    cancel_process = QtCore.Signal()

    def __init__(self):
        super(GetCollectionItems, self).__init__()

        self.cancel = False
        self.init_run.connect(self.run)

    @QtCore.Slot()
    def run(self, collection_folder):

        if not collection_folder or not os.path.exists(collection_folder):
            return
        self.cancel = False

        files = [f for f in os.listdir(collection_folder) if f.endswith(".json")]
        if self.cancel:
            self.cancel_process.emit()
            return

        if files:
            self.start_process.emit(len(files))

        for f in files:

            if self.cancel:
                self.cancel_process.emit()
                return

            with open(collection_folder + os.sep + f) as m:
                metadata = json.load(m)
            if self.cancel:
                self.cancel_process.emit()
                return

            self.add_entry.emit(metadata)

        self.end_process.emit()


from Scweet.scweet import scrape
from Scweet.user import get_user_information, get_users_following, get_users_followers

# data = scrape(since="2021-10-07",  to_account = "@NetflixIndia", interval=1,
# 	headless=False, display_type="Top", save_images=False,
# 	resume=False, filter_replies=False, proximity=False)

# data = scrape(since="2021-10-06", from_account = "@NetflixIndia", interval=1,
# 	headless=True, display_type="Top", save_images=False,
# 	resume=False, filter_replies=False, proximity=False)

data = scrape(hashtag="covid", since="2021-10-14", until=None, from_account = None, interval=1,
	headless=True, display_type="Top", save_images=False,
	resume=False, filter_replies=True, proximity=False)

print(data)

# data = scrape(words="covid", since="2021-10-05", until=None, from_account = None, interval=1,
# 	headless=True, display_type="Top", save_images=False,
# 	resume=False, filter_replies=True, proximity=False)

users = ['@isaurabhpawar1']

# users_info = get_user_information(users, headless=True)

# following = get_users_following(users=users, verbose=0, headless=True, wait=2, limit=50, file_path=None)

# followers = get_users_followers(users=users, verbose=0, headless=True, wait=2, limit=50, file_path=None)


from django.conf.urls import url
from . import views

urlpatterns = [
    url(r'^$', views.index, name='hd.index'),
    url(r'^login/$', views.login, name='hd.login'),
    url(r'^mwanafunzi/([0-9]+)/$', views.mwanafunzi, name='hd.mwanafunzi'),
    url(r'^changamoto/([0-9]+)/([0-9]+)$', views.changamoto, name='hd.changamoto'),
    url(r'^run_code$', views.run_code, name='hd.run_code'),
    url(r'^hongera/([0-9]+)/([0-9]+)$', views.hongera, name='hd.hongera'),
    url(r'^reset/([0-9]+)/([0-9]+)$', views.reset, name='hd.reset'),
    url(r'^save_code$', views.save_code, name='hd.save_code'),
]


import csv
import matplotlib.pyplot as plt
import pandas as pd
from scipy import stats
import numpy as np

def read_csv(filename):
    return pd.read_csv(filename)

def print_dataframe_stats(df, frequency):
    print("Statistics for " + frequency + " frequency:")
    print("---------")
    print("Mean Market Return: ", df["mktret"].mean())
    print("Var Market Return: ", df["mktret"].var())
    print("Std Dev Market Return: ", df["mktret"].std())
    print("Skewness Market Return: ", df["mktret"].skew())
    print("Kurtosis Market Return: ", df["mktret"].kurtosis())
    print("Mean Bond Return: ", df["bondret"].mean())
    print("Var Bond Return: ", df["bondret"].var())
    print("Std Dev Bond Return: ", df["bondret"].std())
    print("Skewness Bond Return: ", df["bondret"].skew())
    print("Kurtosis Bond Return: ", df["bondret"].kurtosis())
    print("Covariance Market and Bond: ", df["mktret"].cov(df["bondret"]))
    print("Correlation Market and Bond: ", df["mktret"].corr(df["bondret"]))
    print("=======================")

def histogram(df_annual, df_monthly, df_daily):
    fig, axes = plt.subplots(3,2)

    df_annual["mktret"].hist(bins=50, ax=axes[0,0])
    df_annual["bondret"].hist(bins=50, ax=axes[0, 1])
    df_monthly["mktret"].hist(bins=50, ax=axes[1, 0])
    df_monthly["bondret"].hist(bins=50, ax=axes[1, 1])
    df_daily["mktret"].hist(bins=50, ax=axes[2, 0])
    df_daily["bondret"].hist(bins=50, ax=axes[2, 1])

    axes[0,0].set_title("Mkt Ret Annual")
    axes[0, 1].set_title("Bond Ret Annual")
    axes[1, 0].set_title("Mkt Ret Monthly")
    axes[1, 1].set_title("Bond Ret Monthly")
    axes[2, 0].set_title("Mkt Ret Daily")
    axes[2, 1].set_title("Bond Ret Daily")

    fig.tight_layout()

    plt.show()

def confidence_intervals(df, frequency):
    print("Mkt Ret Conf Interval 1 period " + frequency, confidence_interval(df["mktret"]))
    print("Bond Ret Conf Interval 1 period " + frequency, confidence_interval(df["bondret"]))
    df["mktret_ma"] = df["mktret"].rolling(window=30).mean()
    df["bondret_ma"] = df["bondret"].rolling(window=30).mean()
    print("Mkt Ret Conf Interval 30 period " + frequency, confidence_interval(df["mktret_ma"]))
    print("Bond Ret Conf Interval 30 period " + frequency, confidence_interval(df["bondret_ma"]))
    print("==================")

def confidence_interval(df):
    mean = df.mean()
    std = df.std()
    return stats.norm.interval(0.95, loc=mean, scale=std)

def shortfall_plot(df):
    k = [-.2, -.1, 0, .1, .2]
    mkt_mean = df["mktret"].mean()
    mkt_std = df["mktret"].std()
    bond_mean = df["bondret"].mean()
    bond_std = df["bondret"].std()

    mkt_probs = []
    bond_probs = []

    for i in k:
        mkt_probs.append(stats.norm(mkt_mean, mkt_std).cdf(i))
        bond_probs.append(stats.norm(bond_mean, bond_std).cdf(i))

    fig, ax = plt.subplots(1,2)
    ax[0].plot(k, mkt_probs)
    ax[1].plot(k, bond_probs)

    plt.show()

def prob_stock_lower_than_bond(df, frequency):
    mkt_mean = df["mktret"].mean()
    mkt_var = df["mktret"].var()
    bond_mean = df["bondret"].mean()
    bond_var = df["bondret"].var()

    diff_mean = bond_mean - mkt_mean
    cov = df["mktret"].cov(df["bondret"])
    diff_var = bond_var + mkt_var - 2*cov

    prob = 1 - stats.norm.cdf((0 - diff_mean) / np.sqrt(diff_var))
    print("Probability Bond Ret > Stock Ret " + frequency + ": ", prob)

def simulation(df, frequency):
    mkt_mean = df["mktret"].mean()
    mkt_std = df["mktret"].std()
    bond_mean = df["bondret"].mean()
    bond_std = df["bondret"].std()

    mkt_norm = stats.norm(mkt_mean, mkt_std)
    bond_norm = stats.norm(bond_mean, bond_std)

    mkt_samples = mkt_norm.rvs(size=10000)
    bond_samples = bond_norm.rvs(size=10000)

    k = [-.2, -.1, 0, .1, .2]

    mkt_probs = []
    bond_probs = []

    for i in k:
        mkt_k = mkt_norm.ppf(i)
        bond_k = bond_norm.ppf(i)

        num_mkt_less = 0.0
        num_bond_less = 0.0
        for j in range(0,10000):

            if mkt_samples[j] < mkt_k:
                num_mkt_less += 1.0

            if bond_samples[j] < bond_k:
                num_bond_less += 1.0

        mkt_probs.append(num_mkt_less / 10000)
        bond_probs.append(num_bond_less / 10000)

    fig, ax = plt.subplots(1, 2)
    ax[0].plot(k, mkt_probs)
    ax[1].plot(k, bond_probs)
    ax[0].set_title(frequency + " Market Fraction < K")
    ax[1].set_title(frequency + " Bond Fraction < K")

    plt.show()

def simulation_empirical(df, frequency):
    mkt_samples = df["mktret"].sample(10000, replace=True).values
    bond_samples = df["bondret"].sample(10000, replace=True).values

    k = [-.2, -.1, 0, .1, .2]

    mkt_probs = []
    bond_probs = []

    for i in k:
        mkt_k = i
        bond_k = i

        num_mkt_less = 0.0
        num_bond_less = 0.0
        for j in range(0,10000):

            if mkt_samples[j] < mkt_k:
                num_mkt_less += 1.0

            if bond_samples[j] < bond_k:
                num_bond_less += 1.0

        mkt_probs.append(num_mkt_less / 10000)
        bond_probs.append(num_bond_less / 10000)

    fig, ax = plt.subplots(1, 2)
    ax[0].plot(k, mkt_probs)
    ax[1].plot(k, bond_probs)
    ax[0].set_title(frequency + " Historical Market Fraction < K")
    ax[1].set_title(frequency + " Historical Bond Fraction < K")

    plt.show()

def five_consecutive_known(df, frequency):
    mkt_mean = df["mktret"].mean()
    mkt_var = df["mktret"].var()
    bond_mean = df["bondret"].mean()
    bond_var = df["bondret"].var()

    mkt_norm = stats.norm(5*mkt_mean, np.sqrt(5*mkt_var))
    bond_norm = stats.norm(5*bond_mean, np.sqrt(5*bond_var))

    mkt_samples = mkt_norm.rvs(size=10000)
    bond_samples = bond_norm.rvs(size=10000)

    mkt_ppf = mkt_norm.ppf(.2)
    bond_ppf = bond_norm.ppf(.2)

    num_mkt_less = 0.0
    num_bond_less = 0.0
    for j in range(0,10000):

        if mkt_samples[j] > .2:
            num_mkt_less += 1.0

        if bond_samples[j] > .2:
            num_bond_less += 1.0

    mkt_prob = num_mkt_less / 10000
    bond_prob = num_bond_less / 10000

    print("============")
    print(frequency + " 5 Consecutive Periods Known Market Prob: ", mkt_prob)
    print(frequency + " 5 Consecutive Periods Known Bond Prob: ", bond_prob)

def five_consecutive_empirical(df, frequency):
    mkt_mean = df["mktret"].mean()
    mkt_var = df["mktret"].var()
    bond_mean = df["bondret"].mean()
    bond_var = df["bondret"].var()

    df["mktret_5_sum"] = df["mktret"].rolling(window=5).sum()
    df["bondret_5_sum"] = df["bondret"].rolling(window=5).sum()

    mkt_norm = stats.norm(5 * mkt_mean, np.sqrt(5 * mkt_var))
    bond_norm = stats.norm(5 * bond_mean, np.sqrt(5 * bond_var))

    mkt_samples = df["mktret_5_sum"].sample(10000, replace=True).values
    bond_samples = df["bondret_5_sum"].sample(10000, replace=True).values

    num_mkt_less = 0.0
    num_bond_less = 0.0
    mkt_ppf = mkt_norm.ppf(.2)
    bond_ppf = bond_norm.ppf(.2)
    for j in range(0,10000):

        if mkt_samples[j] > .2:
            num_mkt_less += 1.0

        if bond_samples[j] > .2:
            num_bond_less += 1.0

    mkt_prob = num_mkt_less / 10000
    bond_prob = num_bond_less / 10000

    print("============")
    print(frequency + " 5 Consecutive Periods Empirical Market Prob: ", mkt_prob)
    print(frequency + " 5 Consecutive Periods Empirical Bond Prob: ", bond_prob)

def prob_greater_than_twenty(df, frequency):
    mkt_mean = df["mktret"].mean()
    mkt_var = df["mktret"].var()
    bond_mean = df["bondret"].mean()
    bond_var = df["bondret"].var()

    print("==============")
    mkt_prob = 1 - stats.norm(5*mkt_mean, np.sqrt(5*mkt_var)).cdf(.2)
    print("Probability Market Ret > 20% " + frequency + ": ", mkt_prob)

    bond_prob = 1 - stats.norm(5 * bond_mean, np.sqrt(5 * bond_var)).cdf(.2)
    print("Probability Bond Ret > 20% " + frequency + ": ", bond_prob)

def prob_stock_lower_than_bond_30(df, frequency):
    mkt_mean = 30*df["mktret"].mean()
    mkt_var = np.sqrt(30*df["mktret"].var())
    bond_mean = 30*df["bondret"].mean()
    bond_var = np.sqrt(30*df["bondret"].var())

    df["mktret_30_sum"] = df["mktret"].rolling(window=30).sum()
    df["bondret_30_sum"] = df["bondret"].rolling(window=30).sum()

    diff_mean = bond_mean - mkt_mean
    cov = df["mktret_30_sum"].cov(df["bondret_30_sum"])
    diff_var = bond_var + mkt_var - 2*cov

    prob = 1 - stats.norm.cdf((0 - diff_mean) / np.sqrt(diff_var))
    print("========")
    print("Probability Bond Ret > Stock Ret over 30 periods " + frequency + ": ", prob)

data_annual = read_csv("returns_annual.csv")
data_monthly = read_csv("returns_monthly.csv")
data_daily = read_csv("returns_daily.csv")

print_dataframe_stats(data_annual, "Annual")
print_dataframe_stats(data_monthly, "Monthly")
print_dataframe_stats(data_daily, "Daily")

# histogram(data_annual, data_monthly, data_daily)

confidence_intervals(data_annual, "Annual")
confidence_intervals(data_monthly, "Monthly")
confidence_intervals(data_daily, "Daily")

# shortfall_plot(data_annual)
# shortfall_plot(data_monthly)
# shortfall_plot(data_daily)

prob_stock_lower_than_bond(data_annual, "Annual")
prob_stock_lower_than_bond(data_monthly, "Monthly")
prob_stock_lower_than_bond(data_daily, "Daily")

# simulation(data_annual, "Annual")
# simulation(data_monthly, "Monthly")
# simulation(data_daily, "Daily")

# simulation_empirical(data_annual, "Annual")
# simulation_empirical(data_monthly, "Monthly")
# simulation_empirical(data_daily, "Daily")

prob_greater_than_twenty(data_annual, "Annual")
prob_greater_than_twenty(data_monthly, "Monthly")
prob_greater_than_twenty(data_daily, "Daily")

five_consecutive_known(data_annual, "Annual")
five_consecutive_known(data_monthly, "Monthly")
five_consecutive_known(data_daily, "Daily")

five_consecutive_empirical(data_annual, "Annual")
five_consecutive_empirical(data_monthly, "Monthly")
five_consecutive_empirical(data_daily, "Daily")

prob_stock_lower_than_bond_30(data_annual, "Annual")
prob_stock_lower_than_bond_30(data_monthly, "Monthly")
prob_stock_lower_than_bond_30(data_daily, "Daily")


def part_one(filename: str) -> int:
    with open(filename) as f:
        nums = list(map(lambda n: [int(x) for x in list(n.strip())], f.readlines()))

    count_flashes = 0
    for _ in range(100):
        nums = next_step(nums)
        count_flashes += sum([int(num == 0) for line in nums for num in line])

    return count_flashes

def part_two(filename: str) -> int:
    with open(filename) as f:
        nums = list(map(lambda n: [int(x) for x in list(n.strip())], f.readlines()))

    synced = False
    step = 0
    while not synced:
        step += 1
        nums = next_step(nums)
        synced = all([num == nums[0][0] for line in nums for num in line])
    return step

def next_step(nums):
    for y, line in enumerate(nums):
        for x, _ in enumerate(line):
            nums[y][x] += 1

    to_flash = {
        (x, y) for y, line in enumerate(nums) for x, val in enumerate(line) if val > 9
    }

    flashed = set()

    while to_flash:
        x0, y0 = to_flash.pop()
        flashed.add((x0, y0))
        for x, y in get_adjacents(x0, y0, nums):
            if (x, y) not in flashed | to_flash:
                nums[y][x] += 1
                if nums[y][x] > 9:
                    to_flash.add((x, y))

    for y, line in enumerate(nums):
        for x, _ in enumerate(line):
            if nums[y][x] > 9:
                nums[y][x] = 0
    return nums

def get_adjacents(x, y: int, nums: list[list[int]]) -> list[tuple[int, int]]:
    return [
        (x + dx, y + dy)
        for dx, dy in [
            (-1, -1),
            (-1, 0),
            (-1, 1),
            (0, -1),
            (0, 1),
            (1, -1),
            (1, 0),
            (1, 1),
        ]
        if 0 <= x + dx < len(nums[0]) and 0 <= y + dy < len(nums)
    ]

if __name__ == "__main__":
    input_path = "./day_11/test_input.txt"
    print("---Part One---")
    print(part_one(input_path))

    print("---Part Two---")
    print(part_two(input_path))


"""Taller python practicando con clases"""

class Compuerta():
    """Clase padre"""
    def __init__(self, inx_, iny_):
        self.inx_ = inx_
        self.iny_ = iny_

class CompuertaAnd(Compuerta):
    """Clase hijo and"""
    def __init__(self, andx, andy):
        self.inx_ = andx
        self.iny_ = andy

    def __str__(self):
        resultado = '0'
        if self.inx_ == '1' and self.iny_ == '1':
            resultado = '1'
        else:
            resultado = '0'
        return 'Compuerta AND: '+resultado

class CompuertaOr(Compuerta):
    """Clase hijo or"""
    def __init__(self, andx, andy):
        self.inx_ = andx
        self.iny_ = andy

    def __str__(self):
        resultado = '0'
        if self.inx_ == '1' or self.iny_ == '1':
            resultado = '1'
        else:
            resultado = '0'
        return 'Compuerta OR: '+resultado

print("Ingresa x: ")
INPUTX_ = input()
print("Ingresa y: ")
INPUTY_ = input()

print('Compuerta AND: ', CompuertaAnd(INPUTX_, INPUTY_))
print('Compuerta OR: ', CompuertaOr(INPUTX_, INPUTY_))


# 1452. 데일리과제 6-2. 데이터 구조 복습 및 심화 예제1
# # 입력 예시
# # mass percent.py 실행 시
# 1.소금물의 농도(%)와 소금물의 양(g)을 입력하십시오: 1% 400g
# 2.소금물의 농도(%)와 소금물의 양(g)을 입력하십시오: 8% 300g
# Done

# 출력 예시
# 4.0% 700.0g
n=1
pctls=[]
gramls=[]
sogeum=[]
while(n<=5):
    #입력받기
    print(f'{n}. 소금물의 농도(%)와 소금물의 양(g)을 입력하십시오: ', end='')
    try:
        pct, gram = map(str, input().split())
        n+=1
    except ValueError:
        break

    #계산
    pctls.append(int(pct.rstrip('%')))
    gramls.append(int(gram.rstrip('g')))
for i in range(len(pctls)):
    sg = pctls[i]*gramls[i]/100
    sogeum.append(sg)

sumgram = sum(gramls)
nd = round(sum(sogeum)/sumgram*100,2)
print(f'{nd}% {sumgram}g')

Python/DAY 6/HW - day6/홈워크_python_06_hw01_P.py


# Set of simulation objects (drawable objects). Do not confuse with Battle package objects. Current ones are only used to be defined and edited, and contain just
# the required data to define them

import wx
import Battles.Utils.Geometry as Geometry
import BE_Dialogs.BE_MoatDlg
import BE_Dialogs.BE_CityEvolutionDlg
import BE_Dialogs.BE_FlankDlg

OBJECT_COUNTER = 0

class BE_Object:
    """ Base class for data objects

        Attributes:
            type: free string with the type of object
            ID: Object identifier
    """

    # Canvas object label
    CANVASOBJECT_NONE = 0
    CANVASOBJECT_RIVER = 1
    CANVASOBJECT_CASTLE = 2
    CANVASOBJECT_TOWER = 3
    CANVASOBJECT_HOUSE = 4
    CANVASOBJECT_CITYEVOLUTION = 5
    CANVASOBJECT_FLANK = 6

    def __init__(self):

        self._type = self.CANVASOBJECT_NONE

        global OBJECT_COUNTER;
        OBJECT_COUNTER += 1
        self.__ID = OBJECT_COUNTER

    def GetID(self):
        return self.__ID

    def GetType(self):
        return self._type

    def SetShape(self):
        # Sets the shape data. Each derived class must implement its own
        pass

    def Draw(self, dc, document, canvas):
        pass

    def GetBoundingBox(self):
        # Returns a BoundingBox object for current object
        return Geometry.BoundingQuad()

    def Select(self, point):
        # Returns true if given point "selects" current object
        bbox = self.GetBoundingBox()
        return bbox.IsInside(point)

    def Edit(self, parentwindow):
        # Edits the object information specified when the object was created (not default or game data)
        pass

class BE_River(BE_Object):
    """ River object

        Attributes:
            polyline: array of Point2D that define the river shape
            width: river width
    """

    def __init__(self):

        BE_Object.__init__(self)

        self._type = self.CANVASOBJECT_RIVER
        self.__polyline = []
        self.__width = 0

    def SetShape(self, pointslist, width):
        # Creates a river from an array of points

        self.__polyline = []

        i = 0
        while ( i < len(pointslist) ):
            self.__polyline.append(pointslist[i].Copy())
            i += 1

        self.__width = width

    def GetWidth(self):
        return self.__width

    def GetShape(self):
        return self.__polyline

    def Draw(self, dc, document, canvas):

        width = canvas.UserToScreenValue(self.__width)    # NOTE: This sould be changed if window/viewport are not squared

        lastpen = dc.GetPen()
        dc.SetPen(wx.Pen(wx.Colour(0, 0, 255, wx.ALPHA_OPAQUE), width))

        i = 1
        while (i < len(self.__polyline)):
            p1 = canvas.UserToScreenCoord(self.__polyline[i-1].x, self.__polyline[i-1].y)
            p2 = canvas.UserToScreenCoord(self.__polyline[i].x, self.__polyline[i].y)
            dc.DrawLine(p1.x, p1.y, p2.x, p2.y)
            i += 1

        dc.SetPen(lastpen)

    def GetBoundingBox(self):
        bbox = Geometry.BoundingQuad()

        for p in self.__polyline:
            bbox.InsertPoint(p)

        bbox.Expand(self.__width)

        return bbox

    def Select(self, point):
        # Since river is a nonclosed polyline, we need to check the selection over each polyline segment

        i = 1
        while (i < len(self.__polyline)):
            seg = Geometry.Segment2D(self.__polyline[i-1], self.__polyline[i])
            poly = seg.GetBounding(self.__width / 2.0)
            bbox = Geometry.BoundingQuad()
            for p in poly.shape:
                bbox.InsertPoint(p.p1)
            if (len(poly.shape) > 0):
                bbox.InsertPoint(poly.shape[-1].p2)
            if (bbox.IsInside(point)):
                return True

            i += 1

        return False

    def Edit(self, parentwindow):

        dlg = wx.TextEntryDialog(parentwindow,'Enter the river width','Add River', str(self.__width))
        ret = dlg.ShowModal()
        if ret == wx.ID_OK:
            try:
                self.__width = float(dlg.GetValue())
            except:
                pass

        dlg.Destroy()

class BE_Castle(BE_Object):
    """ Castle shape object

        Attributes:
            polyline: array of Point2D that define the river shape. Each point has a BE_CanvasTower associated data
            thickness: walls thickness
            isClosed: True if castle is closed. This must be ever true when polyline is ready. It is used to check at draw time if the castle is in create mode
            moat: Castle moat data. See Usage documentation to know more about it
    """

    def __init__(self):
        BE_Object.__init__(self)
        self._type = self.CANVASOBJECT_CASTLE
        self.__shape = []
        self.__isClosed = False
        self.__moat = {'Active': False, 'HasWater': False}

    def AddVertex(self, vertex = Geometry.Point2D()):
        self.__shape.append(vertex)

    def GetNVertices(self):
        return len(self.__shape)

    def SetMoat(self, active = False, width = 0, haswater = False):
        self.__moat['Active'] = active
        self.__moat['HasWater'] = haswater

    def GetMoat(self):
        return self.__moat

    def GetShape(self):
        return self.__shape

    def Close(self):
        self.__isClosed = True

    def Draw(self, dc, document, canvas):

        castledata = document.GetDefaultSettings().castle

        lastpen = dc.GetPen()

        # Draw the moat
        if (self.__moat['Active']):

            moatwidth = canvas.UserToScreenValue(castledata.moat.width)    # NOTE: This sould be changed if window/viewport are not squared

            if (self.__moat['HasWater']):
                dc.SetPen(wx.Pen(wx.Colour(162, 215, 245, wx.ALPHA_OPAQUE), moatwidth))
            else:
                dc.SetPen(wx.Pen(wx.Colour(128, 181, 72, wx.ALPHA_OPAQUE), moatwidth))

            # Expand the castle shape to cover it
            pol = Geometry.Polygon2D()
            pol.SetPointsList(self.__shape)

            gpc = Geometry.GPCWrapper()
            if (not gpc.IsCCW(self.__shape)):
                pol.SwitchOrientation()

            pol.Expand((castledata.walls.thickness / 2.0) + (castledata.moat.width / 2))
            plist = pol.GetPointsList()

            i = 1
            while (i < len(plist)):
                p1 = canvas.UserToScreenCoord(plist[i-1].x, plist[i-1].y)
                p2 = canvas.UserToScreenCoord(plist[i].x, plist[i].y)
                dc.DrawLine(p1.x, p1.y, p2.x, p2.y)
                i += 1
            if (len(plist) > 2):
                p1 = canvas.UserToScreenCoord(plist[-1].x, plist[-1].y)
                p2 = canvas.UserToScreenCoord( plist[0].x, plist[0].y)
                dc.DrawLine(p1.x, p1.y, p2.x, p2.y)

        thickness = canvas.UserToScreenValue(castledata.walls.thickness)    # NOTE: This sould be changed if window/viewport are not squared

        dc.SetPen(wx.Pen(wx.Colour(130, 130, 130, wx.ALPHA_OPAQUE), thickness))

        # Draw the walls
        i = 1
        while (i < len(self.__shape)):
            p1 = canvas.UserToScreenCoord(self.__shape[i-1].x, self.__shape[i-1].y)
            p2 = canvas.UserToScreenCoord(self.__shape[i].x, self.__shape[i].y)
            dc.DrawLine(p1.x, p1.y, p2.x, p2.y)
            i += 1
        if (self.__isClosed and (len(self.__shape) > 2)):
            p1 = canvas.UserToScreenCoord(self.__shape[-1].x, self.__shape[-1].y)
            p2 = canvas.UserToScreenCoord( self.__shape[0].x, self.__shape[0].y)
            dc.DrawLine(p1.x, p1.y, p2.x, p2.y)

        # Draw the towers
        i = 0
        while (i < len(self.__shape)):
            tower = self.__shape[i].data
            if (tower):
                tower.Draw(dc, document,canvas)
            i += 1

        dc.SetPen(lastpen)

    def GetBoundingBox(self):
        bbox = Geometry.BoundingQuad()

        for p in self.__shape:
            bbox.InsertPoint(p)

        for p in self.__shape:
            if (p.data):
                bbox.Expand(p.data.size)
                break

        return bbox

    def Edit(self, parentwindow):

        # Edit the moat castle data

        dlg = BE_Dialogs.BE_MoatDlg.BE_MoatDlg(parentwindow)

        dlg.checkActive.SetValue(self.__moat['Active'])
        dlg.checkHasWater.SetValue(self.__moat['HasWater'])

        ret = dlg.ShowModal()
        if (ret == wx.ID_OK):

            self.__moat['Active'] = dlg.checkActive.GetValue()
            self.__moat['HasWater'] = dlg.checkHasWater.GetValue()

        dlg.Destroy()

class BE_Tower(BE_Object):
    """ Tower shape object. It can be squared, rounded or bastion

        Attributes:
            center: Tower center
            towertype: Tower type. See definitions below
            side: Tower side (for squared ones)
            radius: Tower radius (for rounded ones)
            size: internal size value, related to the towers size, used only to get the bounding box
    """

    # Tower types
    TOWERTYPE_SQUARED = 0
    TOWERTYPE_ROUNDED = 1
    TOWERTYPE_RANDOM = 2

    def __init__(self, towertype, center = Geometry.Point2D()):
        BE_Object.__init__(self)
        self._type = self.CANVASOBJECT_TOWER
        self.__towertype = towertype
        self.__center = center
        self.size = 0.0

    def GetTowerType(self):
        return self.__towertype

    def Draw(self, dc, document, canvas):

        towerdata = document.GetDefaultSettings().castle.towers
        self.size = towerdata.squareSide / 2.0

        lastpen = dc.GetPen()
        dc.SetPen(wx.Pen(wx.Colour(100, 100, 100, wx.ALPHA_OPAQUE), 1))

        if (self.__towertype == self.TOWERTYPE_SQUARED):
            center = self.__center.Copy()
            center.Move(Geometry.Vector2D(-1,-1), towerdata.squareSide / 2.0)
            center = canvas.UserToScreenCoord(center.x, center.y)
            side = canvas.UserToScreenValue(towerdata.squareSide)    # NOTE: This sould be changed if window/viewport are not squared
            dc.DrawRectangle(center.x, center.y, side, side)

        if (self.__towertype == self.TOWERTYPE_ROUNDED):
            center = self.__center.Copy()
            center.Move(Geometry.Vector2D(-1,-1), towerdata.circleRadius / 2.0)
            center = canvas.UserToScreenCoord(center.x, center.y)
            radius = canvas.UserToScreenValue(towerdata.circleRadius)    # NOTE: This sould be changed if window/viewport are not squared
            dc.DrawEllipse(center.x, center.y, radius*2, radius*2)

        if (self.__towertype == self.TOWERTYPE_RANDOM):
            lastfont = dc.GetFont()
            currfont = wx.Font(pointSize = 25, family = wx.FONTFAMILY_DEFAULT, style = wx.FONTSTYLE_NORMAL, weight = wx.FONTWEIGHT_BOLD)
            dc.SetFont(currfont)
            center = canvas.UserToScreenCoord(self.__center.x, self.__center.y)
            dc.DrawText("?", center.x, center.y)
            dc.SetFont(lastfont)

        dc.SetPen(lastpen)

    def Select(self, point):
        # Towers are not selectable, only the whole castle
        return False

class BE_House(BE_Object):
    """ House shape object

        Attributes:
            center: House center Point2D object
            size: internal house size value, used only to get the bounding box (where city houses settings are not available)
    """

    def __init__(self, center):
        BE_Object.__init__(self)
        self._type = self.CANVASOBJECT_HOUSE
        self.center = center
        self.__size = 8.0

    def Draw(self, dc, document, canvas):

        citydata = document.GetDefaultSettings().city
        self.__size = citydata.housesSize

        lastpen = dc.GetPen()
        lastbrush = dc.GetBrush()
        dc.SetPen(wx.Pen(wx.Colour(141, 114, 71, wx.ALPHA_OPAQUE), 1))
        dc.SetBrush(wx.Brush(wx.Colour(234, 207, 160), wx.SOLID))

        p = self.center.Copy()
        p.Move(Geometry.Vector2D(-1,-1), citydata.housesSize / 2.0)

        p = canvas.UserToScreenCoord(p.x, p.y)
        size = canvas.UserToScreenValue(citydata.housesSize)    # NOTE: This sould be changed if window/viewport are not squared. A polygon should be calculated instead
        dc.DrawRectangle(p.x, p.y, size, size)

        dc.SetBrush(lastbrush)
        dc.SetPen(lastpen)

    def GetBoundingBox(self):
        bbox = Geometry.BoundingQuad()

        p = self.center.Copy()
        p.Move(Geometry.Vector2D(-1,-1), self.__size / 2.0)
        bbox.InsertPoint(p)
        p = self.center.Copy()
        p.Move(Geometry.Vector2D(-1,1), self.__size / 2.0)
        bbox.InsertPoint(p)
        p = self.center.Copy()
        p.Move(Geometry.Vector2D(1,-1), self.__size / 2.0)
        bbox.InsertPoint(p)
        p = self.center.Copy()
        p.Move(Geometry.Vector2D(1,1), self.__size / 2.0)
        bbox.InsertPoint(p)

        return bbox

class BE_CityEvolution(BE_Object):

    """ City evolution object

        Attributes:
            timerange: range of time (in years) to execute the evolution
            basesegment: base segment used to start the evolution
            arrow: evolution direction vector, represented as a segment, from basesegment mid point to the arrow edge
            housesperyear: number of houses per year (it can be < 1)
            groupID: ID of evolution group
    """

    # Color array. Each city evolution is drawn using the same color than other city evolutions with the same groupID
    COLOR_GROUP = ["ORANGE", "MAGENTA" , "PINK", "AQUAMARINE", "VIOLET", "MAROON", "GREEN YELLOW", "STEEL BLUE", "DARK GREEN", "FIREBRICK", "SALMON", "TURQUOISE", "GOLD", "KHAKI"]

    def __init__(self):

        BE_Object.__init__(self)
        self._type = self.CANVASOBJECT_CITYEVOLUTION
        self.timeRange = [0,0]
        self.baseSegment = Geometry.Segment2D()
        self.arrow = Geometry.Segment2D()
        self.housesPerYear = 1
        self.groupID = 0
        self.__colorDB = wx.ColourDatabase()

    def Draw(self, dc, document, canvas):

        # Get the colour from the groupID. A better approach would be to take it randomly, but there are the risk of obtaining too close colors
        # The main drawback of this method is that the number of groups is limited, so it is the number of colors. But a huge number of available colors should
        # be enough

        groupcolor = self.__colorDB.Find(self.COLOR_GROUP[self.groupID % len(self.COLOR_GROUP)])

        lastpen = dc.GetPen()
        lastbrush = dc.GetBrush()
        dc.SetPen(wx.Pen(groupcolor, 2))
        dc.SetBrush(wx.Brush(groupcolor, wx.SOLID))

        base1 = canvas.UserToScreenCoord(self.baseSegment.p1.x, self.baseSegment.p1.y)
        base2 = canvas.UserToScreenCoord(self.baseSegment.p2.x, self.baseSegment.p2.y)
        arrow1 = canvas.UserToScreenCoord(self.arrow.p1.x, self.arrow.p1.y)
        arrow2 = canvas.UserToScreenCoord(self.arrow.p2.x, self.arrow.p2.y)
        dc.DrawLine(base1.x, base1.y, base2.x, base2.y)
        dc.DrawLine(arrow1.x, arrow1.y, arrow2.x, arrow2.y)

        arrowshape = self.arrow.GetArrow(atEnd = True, size = 30, arrowangle = 20)
        plist = []
        for p in arrowshape:
            parr = canvas.UserToScreenCoord(p.x, p.y)
            plist.append([parr.x, parr.y])
        dc.DrawPolygon(plist)

        dc.SetBrush(lastbrush)
        dc.SetPen(lastpen)

    def GetBoundingBox(self):

        bbox = Geometry.BoundingQuad()

        bbox.InsertPoint(self.baseSegment.p1)
        bbox.InsertPoint(self.baseSegment.p2)
        bbox.InsertPoint(self.arrow.p2)

        return bbox

    def Edit(self, parentwindow):

        # Edits the timerange, houses per year, and groupID

        dlg = BE_Dialogs.BE_CityEvolutionDlg.BE_CityEvolutionDlg(parentwindow)

        dlg.textGroupID.SetValue(str(self.groupID))
        dlg.textTimeRangeStart.SetValue(str(self.timeRange[0]))
        dlg.textTimeRangeEnd.SetValue(str(self.timeRange[1]))
        dlg.textHousesYear.SetValue(str(self.housesPerYear))

        if (dlg.ShowModal() == wx.ID_OK):

            try:
                self.timeRange[0] = int(dlg.textTimeRangeStart.GetValue())
                self.timeRange[1] = int(dlg.textTimeRangeEnd.GetValue())
            except:
                pass

            try:
                self.housesPerYear = float(dlg.textHousesYear.GetValue())
            except:
                pass

            try:
                self.groupID = int(dlg.textGroupID.GetValue())
            except:
                pass

        dlg.Destroy()

class BE_Flank(BE_Object):

    """ Flank object. It is related to a battle on a specific year. All same year flanks are drawn with the same color

        Attributes:
            year: related battle year
            standDistance: (see Usage documentation)
            origin: flank origin
            target: flank target
            battalions: dictonary with the kind of battalions for this flank. Each one is a dictionary -> {'Number', 'BattalionSize', 'GroupSize', 'GroupDistance'}
    """

    def __init__(self):

        BE_Object.__init__(self)
        self._type = self.CANVASOBJECT_FLANK

        self.year = 0
        self.standDistance = None
        self.origin = Geometry.Point2D()
        self.target = Geometry.Point2D()

        self.battalions = {}
        self.battalions['Infantry'] = {'Number': None, 'BattalionSize': None, 'GroupSize': None, 'GroupDistance': None}
        self.battalions['Archers'] = {'Number': None, 'BattalionSize': None, 'GroupSize': None, 'GroupDistance': None}
        self.battalions['Cannons'] = {'Number': None, 'BattalionSize': None, 'GroupSize': None, 'GroupDistance': None}
        self.battalions['SiegeTowers'] = {'Number': None, 'BattalionSize': None, 'GroupSize': None, 'GroupDistance': None}

    def Draw(self, dc, document, canvas):

        battle = document.GetGameData().battles.GetBattle(self.year)
        if (not battle):
            return
        if (not battle.color):
            return

        lastpen = dc.GetPen()
        lastbrush = dc.GetBrush()
        dc.SetPen(wx.Pen(battle.color, 1))
        dc.SetBrush(wx.Brush(battle.color, wx.BDIAGONAL_HATCH))

        plist = []
        axis = Geometry.Segment2D(self.origin, self.target)
        length = axis.GetLength()
        direction = axis.GetDirection()
        normal = axis.GetNormal()

        arrowwidth = 20
        arrowcapheight = 50
        arrowcapwidth = 50

        p = self.origin.Copy()
        p.Move(normal, arrowwidth / 2.0)
        plist.append([p.x, p.y])
        p.Move(direction, length - arrowcapheight)
        plist.append([p.x, p.y])
        p.Move(normal, (arrowcapwidth / 2.0) - (arrowwidth / 2.0))
        plist.append([p.x, p.y])
        plist.append([self.target.x, self.target.y])
        p.Move(normal, -arrowcapwidth)
        plist.append([p.x, p.y])
        p.Move(normal, (arrowcapwidth / 2.0) - (arrowwidth / 2.0))
        plist.append([p.x, p.y])
        p = self.origin.Copy()
        p.Move(normal, -arrowwidth / 2.0)
        plist.append([p.x, p.y])

        plistcanvas = []
        for pl in plist:
            pc = canvas.UserToScreenCoord(pl[0], pl[1])
            plistcanvas.append([pc.x, pc.y])

        dc.DrawPolygon(plistcanvas)

        dc.SetBrush(lastbrush)
        dc.SetPen(lastpen)

    def GetBoundingBox(self):

        # TODO: Improve bounding over arrow (not box)

        bbox = Geometry.BoundingQuad()

        bbox.InsertPoint(self.origin)
        bbox.InsertPoint(self.target)
        bbox.Expand(20)

        return bbox

    def Edit(self, parentwindow):

        dlg = BE_Dialogs.BE_FlankDlg.BE_FlankDlg(parentwindow)

        if (self.standDistance):
            dlg.textStandDistance.SetValue(str(self.standDistance))

        # Populate the battalions data

        if (self.battalions['Infantry']['Number']):
            dlg.textInfantryNumber.SetValue(str(self.battalions['Infantry']['Number']))
        if (self.battalions['Infantry']['BattalionSize']):
            dlg.textInfantryBattalionSize.SetValue(str(self.battalions['Infantry']['BattalionSize']))
        if (self.battalions['Infantry']['GroupSize']):
            dlg.textInfantryGroupSize.SetValue(str(self.battalions['Infantry']['GroupSize']))
        if (self.battalions['Infantry']['GroupDistance']):
            dlg.textInfantryGroupDistance.SetValue(str(self.battalions['Infantry']['GroupDistance']))

        if (self.battalions['Archers']['Number']):
            dlg.textArchersNumber.SetValue(str(self.battalions['Archers']['Number']))
        if (self.battalions['Archers']['BattalionSize']):
            dlg.textArchersBattalionSize.SetValue(str(self.battalions['Archers']['BattalionSize']))
        if (self.battalions['Archers']['GroupSize']):
            dlg.textArchersGroupSize.SetValue(str(self.battalions['Archers']['GroupSize']))
        if (self.battalions['Archers']['GroupDistance']):
            dlg.textArchersGroupDistance.SetValue(str(self.battalions['Archers']['GroupDistance']))

        if (self.battalions['Cannons']['Number']):
            dlg.textCannonsNumber.SetValue(str(self.battalions['Cannons']['Number']))
        if (self.battalions['Cannons']['BattalionSize']):
            dlg.textCannonsBattalionSize.SetValue(str(self.battalions['Cannons']['BattalionSize']))
        if (self.battalions['Cannons']['GroupSize']):
            dlg.textCannonsGroupSize.SetValue(str(self.battalions['Cannons']['GroupSize']))
        if (self.battalions['Cannons']['GroupDistance']):
            dlg.textCannonsGroupDistance.SetValue(str(self.battalions['Cannons']['GroupDistance']))

        if (self.battalions['SiegeTowers']['Number']):
            dlg.textSiegeTowersNumber.SetValue(str(self.battalions['SiegeTowers']['Number']))
        if (self.battalions['SiegeTowers']['BattalionSize']):
            dlg.textSiegeTowersBattalionSize.SetValue(str(self.battalions['SiegeTowers']['BattalionSize']))
        if (self.battalions['SiegeTowers']['GroupSize']):
            dlg.textSiegeTowersGroupSize.SetValue(str(self.battalions['SiegeTowers']['GroupSize']))
        if (self.battalions['SiegeTowers']['GroupDistance']):
            dlg.textSiegeTowersGroupDistance.SetValue(str(self.battalions['SiegeTowers']['GroupDistance']))

        # Populate the years dialog combolist
        battleslist = parentwindow.GetDocument().GetGameData().battles.GetBattlesYears()
        i = 0
        sel = 0
        for year in battleslist:
            dlg.comboYear.Append(str(year))
            if (year == self.year):
                sel = i
            i += 1
        dlg.comboYear.SetSelection(sel)

        if (dlg.ShowModal() == wx.ID_OK):

            try:
                self.year = int(dlg.comboYear.GetStringSelection())
            except:
                return

            try:
                self.standDistance = float(dlg.textStandDistance.GetValue())
            except:
                pass

            try:
                self.battalions['Infantry']['Number'] = int(dlg.textInfantryNumber.GetValue())
            except:
                pass
            try:
                self.battalions['Infantry']['BattalionSize'] = int(dlg.textInfantryBattalionSize.GetValue())
            except:
                pass
            try:
                self.battalions['Infantry']['GroupSize'] = int(dlg.textInfantryGroupSize.GetValue())
            except:
                pass
            try:
                self.battalions['Infantry']['GroupDistance'] = int(dlg.textInfantryGroupSize.GetValue())
            except:
                pass

            try:
                self.battalions['Archers']['Number'] = int(dlg.textArchersNumber.GetValue())
            except:
                pass
            try:
                self.battalions['Archers']['BattalionSize'] = int(dlg.textArchersBattalionSize.GetValue())
            except:
                pass
            try:
                self.battalions['Archers']['GroupSize'] = int(dlg.textArchersGroupSize.GetValue())
            except:
                pass
            try:
                self.battalions['Archers']['GroupDistance'] = int(dlg.textArchersGroupSize.GetValue())
            except:
                pass

            try:
                self.battalions['Cannons']['Number'] = int(dlg.textCannonsNumber.GetValue())
            except:
                pass
            try:
                self.battalions['Cannons']['BattalionSize'] = int(dlg.textCannonsBattalionSize.GetValue())
            except:
                pass
            try:
                self.battalions['Cannons']['GroupSize'] = int(dlg.textCannonsGroupSize.GetValue())
            except:
                pass
            try:
                self.battalions['Cannons']['GroupDistance'] = int(dlg.textCannonsGroupSize.GetValue())
            except:
                pass

            try:
                self.battalions['SiegeTowers']['Number'] = int(dlg.textSiegeTowersNumber.GetValue())
            except:
                pass
            try:
                self.battalions['SiegeTowers']['BattalionSize'] = int(dlg.textSiegeTowersBattalionSize.GetValue())
            except:
                pass
            try:
                self.battalions['SiegeTowers']['GroupSize'] = int(dlg.textSiegeTowersGroupSize.GetValue())
            except:
                pass
            try:
                self.battalions['SiegeTowers']['GroupDistance'] = int(dlg.textSiegeTowersGroupSize.GetValue())
            except:
                pass

        dlg.Destroy()


import ssl
import socket
from scapy.all import *
load_layer("http")

import scapy.supersocket as supersocket
import scapy.contrib.http2 as h2
import scapy.config

HOST, PORT = 'google.com', 443

# hostname = 'www.python.org'
# context = ssl.create_default_context()

# # with socket.create_connection((hostname, 443)) as sock:
# with context.wrap_socket(sock, server_hostname=hostname) as ssock:
#     print(ssock.version())
#     # ssock.send(req)
#     # print(ssock.recv(1280))

# import socket
dn = 'www.google.com'

# Get the IP address of a Google HTTP endpoint
l = socket.getaddrinfo(dn, PORT, socket.INADDR_ANY, socket.SOCK_STREAM, socket.IPPROTO_TCP)
assert len(l) > 0, 'No address found :('

s = socket.socket(l[0][0], l[0][1], l[0][2])
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
if hasattr(socket, 'SO_REUSEPORT'):
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
ip_and_port = l[0][4]

print(ip_and_port)

context = ssl.create_default_context()
with context.wrap_socket(s, server_hostname=HOST) as ssl_sock:

    ssl_sock.connect(ip_and_port)

    # print(ssock.version())
    scapy.config.conf.debug_dissector = True
    print(h2.H2Frame.Raw)
    ss = supersocket.SSLStreamSocket(ssl_sock, basecls=h2.H2Frame)
    srv_set = ss.recv()
    srv_set.show()


import concurrent.futures
import datetime
import json
import logging
import os
import subprocess
import sys
import traceback
from asyncio import get_event_loop, sleep
from http.client import RemoteDisconnected
from http.server import BaseHTTPRequestHandler, HTTPServer
from inspect import getframeinfo, stack
from socketserver import ThreadingMixIn
from typing import (Any, Awaitable, Callable, Generic, Optional, Tuple, Type,
                    TypeVar, Union, cast)
from urllib import request
from urllib.error import URLError

from genericpath import exists

T = TypeVar("T")
R = TypeVar("R")
Fn = Callable[[T], R]

paracetamol_smiles = "CC(=O)Nc1ccc(O)cc1"
os.environ["TF_CPP_MIN_LOG_LEVEL"] = "3"  # disable tensorflow warnings
os.environ["CUDA_VISIBLE_DEVICES"] = "0"
project_dir = os.path.dirname(os.path.realpath(__file__))
logger = logging.Logger(__name__)
conda_dir = os.environ["CONDA_PREFIX"]

class Timer:
    @staticmethod
    def calc(fn: Callable[[], T]) -> Tuple[float, T]:
        timer = Timer()
        result = fn()
        return timer.done(), result

    @staticmethod
    async def acalc(awaitable: Awaitable[T]) -> Tuple[float, T]:
        timer = Timer()
        result = await awaitable
        return timer.done(), result

    def __init__(self):
        self.start = datetime.datetime.now()

    def done(self):
        self.delta = (datetime.datetime.now() - self.start).total_seconds()
        return self.delta

def _serve(port: int, callback: Fn[Any, Any]):
    class S(BaseHTTPRequestHandler):
        def log_message(self, *args: Any):
            pass

        def do_POST(self):
            content_length = int(self.headers["Content-Length"])
            post_data = self.rfile.read(content_length).decode("utf-8")
            try:
                in_data = json.loads(post_data)
                out_data = callback(in_data)
                result = (False, out_data)
            except Exception as e:
                result = (
                    True,
                    "".join(
                        traceback.format_exception(type(e), value=e, tb=e.__traceback__)
                    ),
                )
            self.send_response(200)
            self.send_header("Content-type", "application/json")
            self.end_headers()
            self.wfile.write(json.dumps(result).encode("utf-8"))

    class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
        """Handle requests in a separate thread."""

    httpd = ThreadedHTTPServer(("localhost", port), S)
    httpd.serve_forever()

def serve(callback: Fn[Any, Any]):
    _serve(int(sys.argv[1]), callback)

def disable_mf():
    if os.environ.get("DISABLE_MF"):
        caller = getframeinfo(stack()[1][0])
        print(f"DISABLE_MF: {caller.filename}:{caller.lineno}")
        return True
    else:
        return False

def disable_syba():
    if os.environ.get("DISABLE_SYBA"):
        caller = getframeinfo(stack()[1][0])
        print(f"DISABLE_SYBA: {caller.filename}:{caller.lineno}")
        return True
    else:
        return False

class AppKilled(Exception):
    pass

class AppError(Exception):
    pass

def _is_errno(e: URLError, errno: int):
    return isinstance(e.reason, OSError) and e.reason.errno == errno

def _fetch(port: int, data: Any, remaining_retries: int = 5) -> Tuple[bool, Any]:
    def f(e: Exception):
        if remaining_retries > 0:
            return _fetch(port, data, remaining_retries - 1)
        else:
            return (True, e)

    try:
        req = request.Request(
            f"http://localhost:{port}",
            method="POST",
            data=json.dumps(data).encode(),
        )
        res = request.urlopen(req)
        return (False, json.loads(res.read()))
    except URLError as e:
        if _is_errno(e, 110):
            return f(e)
        else:
            raise e
    except ConnectionResetError as e:
        return f(e)
    except Exception as e:
        return (True, e)

class CondaApp(Generic[T, R]):
    def __init__(self, port: int, module: str, env: str):
        self.port = port
        self.module = module
        self.env = env
        self.p: Optional[subprocess.Popen[Any]] = None
        self.executor: Optional[concurrent.futures.ProcessPoolExecutor] = None

    def __str__(self):
        return f'CondaApp(port={self.port}, module="{self.module}", env="{self.env}")'

    def running(self):
        return self.p and (self.p.poll() is None)

    def _process_fetch(self, x: Tuple[bool, Any]):
        is_internal_error, v = x
        if is_internal_error:
            logger.exception(v)
            raise v
        else:
            is_app_error, value = v
            if is_app_error:
                raise AppError(value)
            else:
                return value

    def fetch_sync(self, data: Optional[T]) -> R:
        if self.running():
            return self._process_fetch(_fetch(self.port, data))
        else:
            raise AppKilled()

    async def fetch(self, data: Optional[T]) -> R:
        if self.running():
            return self._process_fetch(
                await get_event_loop().run_in_executor(
                    self.executor, _fetch, self.port, data
                )
            )
        else:
            raise AppKilled()

    async def _start(self):
        assert not self.executor
        assert not self.p
        self.executor = concurrent.futures.ProcessPoolExecutor()
        self.p = subprocess.Popen(
            [
                os.path.join(conda_dir, "envs", self.env, "bin/python"),
                "-m",
                f"{self.module}.main",
                str(self.port),
            ],
            env={
                **os.environ,
                "PYTHONPATH": f"{os.environ.get('PYTHONPATH', '')}:{project_dir}/askcos-core/",
            },
        )
        while self.running():
            await sleep(1)
            try:
                await self.fetch(None)
                break
            except RemoteDisconnected:
                pass
            except URLError as e:
                if not _is_errno(e, 111):
                    raise e

    async def start(self):
        time, _ = await Timer.acalc(self._start())
        print(f"{self} starting time: {time}")

    async def __aenter__(self):
        await self.start()
        return self.fetch, self.fetch_sync

    def stop(self):
        if self.executor:
            self.executor.shutdown()
        self.executor = None
        if self.running():
            assert self.p
            self.p.kill()
            try:
                self.p.wait(timeout=3)
            except subprocess.TimeoutExpired:
                self.p.send_signal(9)
            self.p = None

    async def __aexit__(self, *_: Any):
        self.stop()

class Db:
    def __init__(self, name: str, readonly: bool):
        from sqlitedict import SqliteDict
        dirname = f"{project_dir}/results"
        if not exists(dirname):
            os.mkdir(dirname)
        self.db = SqliteDict(
            f"{dirname}/{name}.sqlite",
            outer_stack=False,
            autocommit=True,
            flag="r" if readonly else "c",
        )

    def _write(self, raw_key: str, value: T) -> T:
        self.db[raw_key] = json.dumps(value, sort_keys=True)
        return value

    async def maybe_create(self, key: Any, f: Callable[[], Awaitable[Any]]):
        raw_key = json.dumps(key, sort_keys=True)
        if raw_key not in self.db:
            self._write(raw_key, await f())

    def read_or_create_sync(self, key: Any, f: Callable[[], T]) -> T:
        raw_key = json.dumps(key, sort_keys=True)
        return (
            cast(T, self._read(raw_key, type(T)))
            if raw_key in self.db
            else self._write(raw_key, f())
        )

    async def read_or_create(
        self, key: Any, f: Callable[[], Awaitable[T]]
    ) -> Awaitable[T]:

        raw_key = json.dumps(key, sort_keys=True)
        return (
            self.db[raw_key] if raw_key in self.db else self._write(raw_key, await f())
        )

    def _read(self, raw_key: Any, type: Type[T]) -> Union[T, None]:
        return cast(type, json.loads(self.db.get(raw_key, "null")))

    def read(self, key: Any, type: Type[T]) -> Union[T, None]:
        return self._read(json.dumps(key, sort_keys=True), type)

    def write(self, key: Any, value: Any):
        self._write(json.dumps(key, sort_keys=True), value)

    def as_json(self):
        return json.dumps({k: v for k, v in self.db.iteritems()}, indent=2)

    def __enter__(self):
        self.db.__enter__()
        return self

    def __exit__(self, *exc_info):
        self.db.close()


# when: 2019/04/05 11:53 PM
# who: fanchuang
# repo: https://github.com/buxuele/
# find: baogebuxuele@163.com

import sqlite3

# if db, conn db, else, create db
conn = sqlite3.connect("my_database.db")

cur = conn.cursor()

# table can be created once
# cur.execute("""create table quotes_tb(
#     title text,
#     author text,
#     tags text
#     )""")

# insert some data
cur.execute("""insert into quotes_tb values(
            'Python is awesome!',
            'fanchuang',
            'python'
            )""")

conn.commit()
conn.close()


import numpy as np
# This is the internal name of the integration, it should also match the directory
# name for the integration.
DOMAIN = "custom_recorder"
NAME = "Custom Recorder"
VERSION = "1.2.0"

CONF_DEVICE_NAME = "device_name"
CONF_SOURCE_ENTITY = "source_entity"
CONF_SOURCE_ENTITY_ATTR = "source_entity_attr"
CONF_ENTITIES = "entities"
CONF_ADD_ANODHER = "add_another"
CONF_NAME = "name"
CONF_RECORD_PERIOD_UNIT = "record_period_unit"
CONF_RECORD_PERIOD = "record_period"
CONF_OFFSET_UNIT = "offset_unit"
CONF_OFFSET = "offset"
CONF_RECORD_LIMIT_COUNT = "record_limit_count"
CONF_DATA_DIR = "data_dir"
CONF_MOVE_SOURCE_ENTITY_DEVICE = "move_source_entity_device"

DEFAULT_LIMIT_COUNT = 0

DIR_PATH = "custom_recorder/"
DATA_PATH = "data/"

DATA_DIR = DIR_PATH + DATA_PATH

FIELD_NAME = "[name]\n"
FIELD_SOURCE_ENTITY = "[source_entity]\n"
FIELD_SOURCE_ENTITY_ATTR = "[source_entity_attr]\n"
FIELD_RECORD_PERIOD_UNIT = "[record_period_unit]\n"
FIELD_RECORD_PERIOD = "[record_period]\n"
FIELD_OFFSET_UNIT = "[offset_unit]\n"
FIELD_OFFSET = "[offset]\n"
FIELD_DATA = "[data]\n"
FIELD_RECORD_LIMIT_COUNT = "[record_limit_count]\n"
FIELD_MOVE_SOURCE_ENTITY_DEVICE = "[move_source_entity_device]\n"

DATE_UNIT = [
    'years',
    'months',
    'weeks',
    'days',
    'hours',
    'minutes',
    'seconds',
    'microseconds',
]

STATISTICS_TYPE = {
    "min": np.min,
    "max": np.max,
    "mean": np.mean,
    "median": np.median,
    "sum": np.sum,
    "std": np.std,
    "var": np.var,
    "quantile_25": np.quantile,
    "quantile_50": np.quantile,
    "quantile_75": np.quantile,
}


from domino.base_piece import BasePiece
from .models import InputModel, OutputModel
import importlib.util

class CustomPythonPiece(BasePiece):

    def piece_function(self, input_data: InputModel):
        # Log inputs
        self.logger.info(f"""
Input model:\n{input_data.input_args}\n
Output model:\n{input_data.output_args}\n
Script:\n{input_data.script}\n
""")

        # Save the script as a local Python file
        script_file = "custom_script.py"
        with open(script_file, "w") as file:
            file.write(input_data.script)

        # Import the custom function from the script file
        spec = importlib.util.spec_from_file_location("custom_script", script_file)
        module = importlib.util.module_from_spec(spec)
        spec.loader.exec_module(module)

        # Call the imported function with the input variables list
        input_kwargs = {arg.kwarg_name: arg.kwarg_value for arg in input_data.input_args}
        output_args = getattr(module, "custom_function")(**input_kwargs)

        # Log output
        self.logger.info(output_args)

        # Return output
        return OutputModel(**output_args)


#!/usr/bin/env python
"""A script to find a, b, c where a^2 + b^2 = c^2, and a + b + c = 1000"""

from math import sqrt

def main() -> None:
    """Find a, b, c where a^2 + b^2 = c^2, and a + b + c = 1000"""
    for b in range(2, 999):
        for a in range(b):
            c = sqrt(a * a + b * b)
            if c == int(c) and a + b + c == 1000:
                print(a * b * int(c))
                return

if __name__ == "__main__":
    main()


'''
list is started by a variable and the contents are enclosed in [] square brackets
'''
l=[1,2,3,4,5,6,7,8,9,10]            #l=[1,2,3,4,,6,7,8,9,10]is a list
#print(len(l))                      #prints length of the list

#l.append("11")                     #adds an element at the end of a list
#print(l)

l2=[4,5,3,2,6,8,3,9,10]             #sorts the list on ascending order
#l2.sort()
#print(l2)


"""
 * @file     lc_0088.py
 * @brief    https://leetcode-cn.com/problems/merge-sorted-array/
 * @author   YongDu
 * @date     2021-09-09
"""

class Solution:
    def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None:
        """
        Do not return anything, modify nums1 in-place instead.
        """
        p1, p2 = m - 1, n - 1
        tail = m + n - 1
        while p1 >= 0 or p2 >= 0:
            if p1 == -1:
                nums1[tail] = nums2[p2]
                p2 -= 1
            elif p2 == -1:
                nums1[tail] = nums1[p1]
                p1 -= 1
            elif nums1[p1] > nums2[p2]:
                nums1[tail] = nums1[p1]
                p1 -= 1
            else:
                nums1[tail] = nums2[p2]
                p2 -= 1
            tail -= 1


array = ["mission statement",
    "a quick bite to eat",
    "a chip off the old block",
    "chocolate bar",
    "mission impossible",
    "a man on a mission",
    "block party",
    "eat my words",
    "bar of soap"]

# output - a man on mission impossible
# a man on mission statement
# a quick bite to eat my words

# this stores the first word and sentence
firstDict = {}
# this stores the last word and sentence
lastDict = {}

# this loop creates the two dictionary
for sentence in array:

    # split by space
    wordsList = sentence.split(" ")

    # get the last word
    lastWord = wordsList[-1] #mission

    # get the first word
    firstWord = wordsList[0]

    # if not present in dictionary
    if firstWord not in firstDict:
        firstDict[firstWord] = [sentence]
    else:
        firstDict[firstWord].append(sentence)

    # if not present in dictionary
    if lastWord not in lastDict:
        lastDict[lastWord] = sentence
#print(firstDict)

for sentence in array:
    wordsList = sentence.split(" ")
    firstWord = wordsList[0]
    lastWord = wordsList[-1] #mission
    #print('----------------------')
    #print(firstDict)
    #print('----------------------')
    if firstWord in lastDict:
        if firstDict[firstWord][0] != 1:
            #print(firstDict[firstWord][0])
            print(lastDict[firstWord] + firstDict[firstWord][0][len(firstWord):])
            firstDict[firstWord][0] = 1
        else:
            index = firstDict[firstWord][0]
            print(lastDict[firstWord] + firstDict[firstWord][index][len(firstWord):])
            index = index + 1


"""HPC management functionality"""

import logging
import os
import time

from jade.enums import Status
from jade.exceptions import InvalidParameter
from jade.hpc.common import HpcType, HpcJobStatus
from jade.hpc.fake_manager import FakeManager
from jade.hpc.local_manager import LocalManager
from jade.hpc.pbs_manager import PbsManager
from jade.hpc.slurm_manager import SlurmManager
from jade.models import HpcConfig

logger = logging.getLogger(__name__)

class HpcManager:
    """Manages HPC job submission and monitoring."""

    def __init__(self, submission_groups, output):
        self._output = output
        self._configs = {}
        self._intfs = {}
        self._hpc_type = None
        assert submission_groups
        for name, group in submission_groups.items():
            self._configs[name] = group.submitter_params.hpc_config
            self._intfs[name] = self.create_hpc_interface(group.submitter_params.hpc_config)
            if self._hpc_type is None:
                self._hpc_type = group.submitter_params.hpc_config.hpc_type

        logger.debug("Constructed HpcManager with output=%s", output)

    def _get_interface(self, submission_group_name=None):
        if submission_group_name is None:
            # In many cases we don't care which interface is used.
            # We could store job IDs by group if we need to perform actions by group
            # in the future.
            # As of now we don't track IDs at all in this class.
            return next(iter(self._intfs.values()))
        return self._intfs[submission_group_name]

    def am_i_manager(self):
        """Return True if the current node is the manager node.

        Returns
        -------
        bool

        """
        intf = self._get_interface()
        return intf.am_i_manager()

    def cancel_job(self, job_id):
        """Cancel job.

        Parameters
        ----------
        job_id : str

        Returns
        -------
        int
            return code

        """
        intf = self._get_interface()
        ret = intf.cancel_job(job_id)
        if ret == 0:
            logger.info("Successfully cancelled job ID %s", job_id)
        else:
            logger.info("Failed to cancel job ID %s", job_id)

        return ret

    def check_status(self, name=None, job_id=None):
        """Return the status of a job by name or ID.

        Parameters
        ----------
        name : str
            job name
        job_id : str
            job ID

        Returns
        -------
        HpcJobStatus

        """
        if (name is None and job_id is None) or (name is not None and job_id is not None):
            raise InvalidParameter("exactly one of name / job_id must be set")

        intf = self._get_interface()
        info = intf.check_status(name=name, job_id=job_id)
        logger.debug("info=%s", info)
        return info.status

    def check_statuses(self):
        """Check the statuses of all user jobs.

        Returns
        -------
        dict
            key is job_id, value is HpcJobStatus

        """
        intf = self._get_interface()
        return intf.check_statuses()

    def get_hpc_config(self, submission_group_name):
        """Returns the HPC interface instance.

        Parameters
        ----------
        submission_group_name : str

        Returns
        -------
        HpcManagerInterface

        """
        return self._get_interface(submission_group_name=submission_group_name)

    def get_job_stats(self, job_id):
        return self._get_interface().get_job_stats(job_id)

    def get_local_scratch(self):
        """Get path to local storage space.

        Returns
        -------
        str

        """
        return self._get_interface().get_local_scratch()

    def get_manager_node(self, job_id):
        """Return the first node in the job.

        Parameters
        ----------
        job_id : str

        Returns
        -------
        list
            list of node hostnames

        """
        intf = self._get_interface()
        return intf.list_active_nodes(job_id)[0]

    @property
    def hpc_type(self):
        """Return the type of HPC management system.

        Returns
        -------
        HpcType

        """
        return self._hpc_type

    def list_active_nodes(self, job_id):
        """Return the nodes currently participating in the job. Order should be deterministic.

        Parameters
        ----------
        job_id : str

        Returns
        -------
        list
            list of node hostnames

        """
        intf = self._get_interface()
        return intf.list_active_nodes(job_id)

    def submit(
        self,
        directory,
        name,
        script,
        submission_group_name,
        wait=False,
        keep_submission_script=True,
        dry_run=False,
    ):
        """Submits scripts to the queue for execution.

        Parameters
        ----------
        directory : str
            directory to contain the submission script
        name : str
            job name
        script : str
            Script to execute.
        submission_group_name : str
        wait : bool
            Wait for execution to complete.
        keep_submission_script : bool
            Do not delete the submission script.
        dry_run : bool
            Do not actually submit jobs. Just create the files.

        Returns
        -------
        tuple
            (job_id, submission status)

        """
        intf = self._get_interface(submission_group_name)
        intf.check_storage_configuration()

        # TODO: enable this logic if batches have unique names.
        # info = intf.check_status(name=name)
        # if info.status in (HpcJobStatus.QUEUED, HpcJobStatus.RUNNING):
        #    raise JobAlreadyInProgress(
        #        "Not submitting job '{}' because it is already active: "
        #        f"{info}"
        #    )

        filename = os.path.join(directory, name + ".sh")
        intf.create_submission_script(name, script, filename, self._output)
        logger.debug("Created submission script %s", filename)

        if dry_run:
            logger.info("Dry run mode enabled. Return without submitting.")
            return 0, Status.GOOD

        result, job_id, err = intf.submit(filename)

        if result == Status.GOOD:
            logger.info("job '%s' with ID=%s submitted successfully", name, job_id)
            if not keep_submission_script:
                os.remove(filename)
        else:
            logger.error("Failed to submit job '%s': result=%s: %s", name, result, err)

        if wait:
            self._wait_for_completion(job_id)

        return job_id, result

    @staticmethod
    def create_hpc_interface(config):
        """Returns an HPC implementation instance appropriate for the current
        environment.

        """
        if config.hpc_type == HpcType.SLURM:
            intf = SlurmManager(config)
        elif config.hpc_type == HpcType.FAKE:
            intf = FakeManager(config)
        elif config.hpc_type == HpcType.LOCAL:
            intf = LocalManager(config)
        else:
            raise ValueError("Unsupported HPC type: {}".format(config.hpc_type))

        logger.debug("HPC manager type=%s", config.hpc_type)
        return intf

    def _wait_for_completion(self, job_id):
        status = HpcJobStatus.UNKNOWN
        intf = self._get_interface()

        while status not in (HpcJobStatus.COMPLETE, HpcJobStatus.NONE):
            time.sleep(5)
            job_info = intf.check_status(job_id=job_id)
            logger.debug("job_info=%s", job_info)
            if job_info.status != status:
                logger.info("Status of job ID %s changed to %s", job_id, job_info.status)
                status = job_info.status

        logger.info("Job ID %s is complete", job_id)


"""Games to Pandas DF"""

import re, time, pickle
import pandas as pd
import numpy as np
import sqlite3

from boardgame import BoardGame # pylint: disable=E0401

class Database():
    def __init__(self, path):
        self.connection = sqlite3.connect(path)
        self.db = self.connection.cursor()

def all_games_to_pd_DF(lst):
    """Moves list to Pandas DF

    Description:
        Converts object returned by list_to_boardgame_class() to a
        Pandas DataFrame.

    Input:
    lst (list): List object from list_to_boardgame_class()

    Returns:
    bg_df (pd.DataFrame): DataFrame with all information. Also saves as a CSV
    """
    all_games = lst[:]
    bg_df = pd.DataFrame()

    ## Basic Info
    bg_df['Name'] = [i.name for i in all_games]
    bg_df['ID'] = [i.id for i in all_games]
    bg_df['Year'] = [i.year_published for i in all_games]

    ## Rating
    bg_df['Num_Ratings'] = [i.users_rated for i in all_games]
    bg_df['Avg_Rating'] = [i.avg_rating for i in all_games]
    bg_df['Bayes_Avg_Rating'] = [i.bayes_avg_rating for i in all_games]
    bg_df['Avg_Weight'] = [i.avg_weight for i in all_games]
    bg_df['StDev_Rating'] = [i.stdev_rating for i in all_games]

    ## Players
    bg_df['Pub_Min_Age'] = [i.min_age for i in all_games]

    BGG_Min_Age = []
    for i in all_games:
        try:
            BGG_Min_Age.append(i.suggested_player_age)
        except:
            BGG_Min_Age.append(np.nan)

    bg_df['BGG_Min_Age'] = BGG_Min_Age
    bg_df['Pub_Min_Players'] = [i.min_players for i in all_games]
    bg_df['Pub_Max_Players'] = [i.max_players for i in all_games]

    BGG_Num_Players = []
    for i in all_games:
        try:
            BGG_Num_Players.append(i.suggested_players)
        except:
            BGG_Num_Players.append(np.nan)

    bg_df['BGG_Num_Players'] = BGG_Num_Players
    bg_df['Play_Time'] = [i.playing_time for i in all_games]

    ## Ownership & Community Engagement
    bg_df['Num_Owned'] = [i.num_owned for i in all_games]
    bg_df['Num_Comments'] = [i.num_comments for i in all_games]
    bg_df['Num_Trading'] = [i.num_trading for i in all_games]
    bg_df['Num_Wanting'] = [i.num_wanting for i in all_games]
    bg_df['Num_Wishing'] = [i.num_wishing for i in all_games]
    bg_df['Num_Weights'] = [i.num_weights for i in all_games]

    ### Ranks
    rank_categories = []
    for i in all_games:
        rank_categories.append(list(i.rank.keys()))

    unique_rank_categories = list(set([i for j in rank_categories for i in j]))
    rank_columns = ['Name', 'ID'] + unique_rank_categories
    major_rank_df = pd.DataFrame(columns = rank_columns)

    for game in all_games:
        rank_data = game.rank
        rank_data['Name'] = game.name
        rank_data['ID'] = game.id
        minor_rank_df = pd.DataFrame(rank_data, index=[0], columns = rank_columns)
        major_rank_df = major_rank_df.append(minor_rank_df)

    bg_df = bg_df.merge(major_rank_df, on = ['Name', 'ID'])

    ### Category Function
    def cast_merge_by_class(grouping, fill_term, lst, df):
        all_terms_grouping = [getattr(i, grouping) for i in lst]
        unique_terms_grouping = list(set([i for j in all_terms_grouping for i in j]))
        grouping_term_columns = ['Name', 'ID'] + [fill_term + s for s in unique_terms_grouping]
        grouping_term_columns = [re.sub(' ', '_', x) for x in grouping_term_columns]

        major_grouping_df = pd.DataFrame(columns = grouping_term_columns)

        for game in lst:
            minor_grouping_df = pd.DataFrame(columns = grouping_term_columns, index=[0])
            minor_grouping_df = minor_grouping_df.fillna(False)
            minor_grouping_df['Name'] = game.name
            minor_grouping_df['ID'] = game.id
            for entry in getattr(game, grouping):
                term = fill_term + re.sub(' ', '_', entry)
                minor_grouping_df[term] = True

            major_grouping_df = major_grouping_df.append(minor_grouping_df)

        # global bg_df
        df_out = pd.merge(df, major_grouping_df, on = ['Name', 'ID'])
        return(df_out)

    merge_pairs = {'mechanics':'Mechanic_', 'categories':'Category_'}

    for key in merge_pairs.keys():
        bg_df = cast_merge_by_class(key, merge_pairs[key], all_games, bg_df)

    return(bg_df)

# if __name__ == "__main__":
#     all_games = pickle.load(open("./data/Raw/all_games_100.pkl", "rb"))
#     games_df = all_games_to_pd_DF(all_games)

#     games_database = Database('./data/boardgames_sql.db')
#     games_df.to_sql("games", games_database.connection, if_exists='replace')

#     print("--- SQL Query - Validation ---")
#     print(pd.read_sql_query("SELECT COUNT(*) Num_Games_in_DB FROM games;",
#                             games_database.connection))
#     games_database.connection.commit()
#     games_database.connection.close()


# Carries out an autofocus algorithm from the textbook
#  Microscope Image Processing by Qiang Wu (2008)
# The implementation below is from section 16.3.3 (DWT is unstested and commented out)
# 'Multiresolution Search for In-Focus Position'

from hw.ledmotorcontrol import driver
import numpy as np
#import matplotlib.pyplot as plt
#import dwt
import requests
import ssl
import cv2
import time

score_history = []

def low_res_score(IMAGE):

    def dwt(X, h1 = np.array([-1, 2, 6, 2, -1])/8 , h2 = np.array([-1, 2 -1])/4):
        """
        From 3rd year engineering project SF2
        DWT Discrete Wavelet Transform
        Y = dwt(X, h1, h2) returns a 1-level 2-D discrete wavelet
        transform of X.

        If filters h1 and h2 are given, then they are used,
        otherwise the LeGall filter pair are used.
        """
        m = X.shape[0] # no: of rows in image X
        n = X.shape[1] # no: of columns in image X
        Y = np.zeros((m,n))
        #print('Output image is of shape ',Y.shape)

        n2 = int(n/2)
        t = np.array(range(n2))
        #print('Editing this part of Y: ',Y[:,t].shape)
        #print(X.shape, h1.shape)

        Y[:,t] = rowdec(X, h1)
        Y[:,t+n2] = rowdec2(X, h2)

        X = Y.T
        m2 = int(m/2)
        t = np.array(range(m2))
        # print(Y[t,:].shape)
        # print(X.shape)
        Y[t,:] = rowdec(X, h1).T
        Y[t+m2, :] = rowdec2(X, h2).T
        return Y

    def rowdec(X, h):
        """"
        ROWDEC Decimate rows of a matrix
        Y = ROWDEC(X, H) Filters the rows of image X using H, and
        decimates them by a factor of 2.
        If length(H) is odd, each output sample is aligned with the first of
        each pair of input samples.
        If length(H) is even, each output sample is aligned with the mid point
        of each pair of input samples.
        """
        c = X.shape[1]
        r = X.shape[0]
        m = h.size
        m2 = int(m/2)

        if np.remainder(m,2)>0:
            # Odd h: symmetrically extend indices without repeating end samples.
            xe = np.array([x for y in [range(m2, 0, -1), range(c), range(c-2,c-m2-2, -1)]  for x in y])
        else:
            # Even h: symmetrically extend with repeat of end samples.
            xe = np.array([x for y in [range(m2,-1,-1), range(c+1), range(c-1,c-m2-2,-1)] for x in y])

        t = np.array(range(0, c-1, 2))

        Y = np.zeros((r, t.size))
        # Loop for each term in h.
        for i in range(m):
            Y = Y + h[i] * X[:,xe[t+i]];

        return Y

    def rowdec2(X, h):
        """"
        ROWDEC2 Decimate rows of a matrix
        Y = ROWDEC2(X, H) Filters the rows of image X using H, and
        decimates them by a factor of 2.
        If length(H) is odd, each output sample is aligned with the first of
        each pair of input samples.
        If length(H) is even, each output sample is aligned with the mid point
        of each pair of input samples.
        """
        c = X.shape[1]
        r = X.shape[0]
        m = h.size
        m2 = int(m/2)

        if np.remainder(m,2)>0:
            # Odd h: symmetrically extend indices without repeating end samples.
            xe = np.array([x for y in [range(m2, 0, -1), range(c), range(c-2,c-m2-2, -1)]  for x in y])
        else:
            # Even h: symmetrically extend with repeat of end samples.
            xe = np.array([x for y in [range(m2,-1,-1), range(c+1), range(c-1,c-m2-2,-1)] for x in y])

        t = np.array(range(1, c, 2))

        Y = np.zeros((r, t.size))
        # Loop for each term in h.
        for i in range(m):
            Y = Y + h[i] * X[:,xe[t+i]];

        return Y

    def nleveldwt(X, N = 3):
        """ N level DWT of image
        Returns an array of the smaller resolution images
        """
        #print('N = ', N)
        Xs = [X]
        if N > 0:
            h, w = X.shape[:2]
            Xs += nleveldwt( dwt(X)[:h//2, :w//2], N-1)
        return Xs

    def focus_score(X):
        """ Focus score is the sum of the squared values of the low resolution images.
        """
        score = 0
        for i in X:
            i += 1
            score += np.var(i)
        return score

    return focus_score(nleveldwt(IMAGE))

def test_function(x):
    return (x-1)**2

def plot_score(f, points = 10):
    imgs = []
    score = []
    #f.move_motor()

    for i in range(points):
        f.move_motor(200, pause = 1)
        imgs.append(f.get_image())
        #time.sleep(2)

    for i in imgs:
        score.append(f.focus_score(i))
        #print(score)

    plt.plot(range(len(score)),score)
    plt.ylabel('Variance')
    plt.xlabel('Position')
    plt.title('Focus score varying with position')
    plt.show()

def gaussian_fitting(z , f):
    """Fit the autofocus function data according to the equation 16.5 in the
        textbook : 'Microscope Image Processing' by Q.Wu et al'
        z_max = gaussian_fitting((z1, z2, z3), (f1, f2 f3))
        where z1, z2 , z3 are points where the autofocus functions
        values f1, f2, f3 are measured """

    z1 = z[0];z2 = z[1];z3 = z[2];
    f1 = f[0];f2 = f[1];f3 = f[2];

    B = (np.log(f2) - np.log(f1))/(np.log(f3) - np.log(f2))

    if (z3 - z2)==(z2 - z1):
        return 0.5 * (B * (z3 + z2) - (z2 + z1))/(B-1)
    else:
        return 0.5 * (B * (z3**2 - z2**2) - (z2**2 - z1**2))/(B * (z3 - z2) - (z2 - z1))

def parabola_fitting(z , f):
    """Fit the autofocus function data according to the equation 16.5 in the
        textbook : 'Microscope Image Processing' by Q.Wu et al'
        parabola_fitting((z1, z2, z3), (f1, f2 f3))
        where z1, z2 , z3 are points where the autofocus functions
        values f1, f2, f3 are measured """

    z1 = z[0];z2 = z[1];z3 = z[2];
    f1 = f[0];f2 = f[1];f3 = f[2];

    E = (f2 - f1)/(f3 - f2)

    if (z3 - z2) == (z2 - z1):
        return 0.5 * (E * (z3 + z2) - (z2 + z1))/(E - 1)
    else:
        return 0.5 * (E * (z3 ** 2 - z2 ** 2) - (z2 ** 2 - z1 ** 2))/(E * (z3 - z2) - (z2 - z1))

def old_fibonacci_search(interval, f ):
    """ Carry out the fibonacci search method according* to the paper:
        'Autofocusing for tissue microscopy' by T.T.E.Yeo et al

        fibonacci_search(interval, f)
        interval = (a, b)
        f is the microscope control class

        * The paper made two mistakes, the evaluations should be if (y1 > y2) not the other way round
        """

    # ################### Functions #######################

    phi = 0.5 * (1 + 5 ** 0.5) # Golden ratio

    def fibs(n=None):
        """ A generator, (thanks to W.J.Earley) that returns the fibonacci series """
        a, b = 0, 1
        yield 0
        yield 1
        if n is not None:
            for _ in range(1,n):
                b = b + a
                a = b - a
                yield(b)
        else:
            while True:
                b = b + a
                a = b - a
                yield(b)

    def smallfib(m):
        """ Return N such that fib(N) >= m """
        n = 0
        for fib in fibs(m):
            if fib >= m:
                return n
            n = n + 1

    def fib(n):
        """ Evaluate the n'th fibonacci number """
        return (phi ** n - (-phi) ** (-n))/(5 ** 0.5)

    # ################# Fibonacci search #########################
    a = interval[0]
    b = interval[1]
    N = smallfib(b-a)
    delta = (fib(N-2)/fib(N))*(b-a)

    x1 = a + delta
    x2 = b - delta
    y1 = f(x1)
    y2 = f(x2)

    for n in range(N-1, 1, -1):
        #print ((x1,x2),(a,b))
        if y1 > y2 :
            a = x1
            x1 = x2
            y1 = y2
            x2 = b - (fib(n-2)/fib(n))*(b-a)
            y2 = f(x2)
        else:
            b = x2
            x2 = x1
            y2 = y1
            x1 = a + (fib(n-2)/fib(n))*(b-a)
            y1 = f(x1)

    if y1 < y2:
        return x1
    else:
        return x2

def fibonacci_search(interval, f ):
    """ Carry out the fibonacci search method according* to the paper:
        'Autofocusing for tissue microscopy' by T.T.E.Yeo et al

        (a,b,x) = fibonacci_search(interval, f)
        interval = (a, b)
        f is the microscope control class

        * The paper made two mistakes, the evaluations should be if (y1 > y2) not the other way round
        """

    # ################### Functions #######################

    phi = 0.5 * (1 + 5 ** 0.5) # Golden ratio

    def fibs(n=None):
        """ A generator, (thanks to W.J.Earley) that returns the fibonacci series """
        a, b = 0, 1
        yield 0
        yield 1
        if n is not None:
            for _ in range(1,n):
                b = b + a
                a = b - a
                yield(b)
        else:
            while True:
                b = b + a
                a = b - a
                yield(b)

    def smallfib(m):
        """ Return N such that fib(N) >= m """
        n = 0
        for fib in fibs(m):
            if fib >= m:
                return n
            n = n + 1

    def fib(n):
        """ Evaluate the n'th fibonacci number """
        return (phi ** n - (-phi) ** (-n))/(5 ** 0.5)

    # ################# Fibonacci search #########################
    print('Starting Fibonacci search')
    a = interval[0]
    b = interval[1]
    c = np.mean((a,b)) # current position of z is inbetween the interval
    N = smallfib(int(b-a))
    delta = (fib(N-2)/fib(N))*(b-a)

    x1 = a + delta
    x2 = b - delta
    y1 = f.move_motor(x1-c,1).eval_score()
    y2 = f.move_motor(x2-x1,1).eval_score()
    score_history.append(y1)
    score_history.append(y2)
    older_pos = 0
    old_pos = x1
    curr_pos = x2
    iterations = 1

    for n in range(N-1, 1, -1):
        #print ('Interval is (%f, %f)' % (a,b) )
        # if (abs(a-b) <=20):
            # print(a, b)
            # print('Bye')
            # return (a,b,x1)
        if iterations >5: # Only 5 iterations for speed
            break
        elif y1 < y2 :
            a = x1
            x1 = x2
            y1 = y2
            x2 = b - (fib(n-2)/fib(n))*(b-a)
            y2 = f.move_motor(x2-curr_pos,2).eval_score()
            score_history.append(y2)
            #print ('Score: ',y2)
            older_pos = old_pos
            old_pose = curr_pos
            curr_pos = x2
        else:
            b = x2
            x2 = x1
            y2 = y1
            x1 = a + (fib(n-2)/fib(n))*(b-a)
            y1 = f.move_motor(x1-curr_pos, 2).eval_score()
            score_history.append(y1)
            #print('Score: ',y1)
            older_pos = old_pos
            old_pos = curr_pos
            curr_pos = x1
        iterations += 1

    if y1 > y2:
        print('Finished Fibonacci search') #(Limited to 5 iterations) \n Max at %f' %x1)
        #f.move_motor(x1 - curr_pos, 6).eval_score()
        return (a,b,x1, older_pos, old_pos, curr_pos)
    else:
        print('Finished Fibonacci search')# (Limited to 5 iterations) \n Max at %f' %x2)
        #f.move_motor(x2 - curr_pos, 6).eval_score()
        return (a,b,x2, older_pos, old_pos, curr_pos)

class microscope_control:
    """ Microscope class to control motors and read images """

    def __init__(self, timeout=None):
        """ Set up HTTP request stuff """
        self.begin = time.time()
        self.timeout = timeout

        # Set the urls
        self.motor_url_request = 'http://127.0.0.1:9001/control/motor/%d/%d'
        self.img_url_request = 'http://127.0.0.1:9002/?action=snapshot'

        #pagehandle = urllib.request.urlopen(theurl)
        #print(pagehandle.read())

    def check_time(self):
        if self.timeout is not None:
            if time.time() - self.begin > self.timeout:
                raise Exception("timed out")

    def move_motor(self,steps,pause = None, axis = 2):
        """ Control motors
            move_motor(steps, pause = False, axis = 2)
            steps : number of steps for the motor to move
            pause : wait after moving motor?
            axis  : 0 = x, 1 = y, 2 = z
            """
        self.check_time()

        #print('Moving %d' %steps)
        if abs(steps)>=100:
            #pagehandle = urllib.request.urlopen('https://172.29.9.20:9000/_webshell/control/motor/%d/%d' %(axis, steps))
            #pagehandle = urllib.request.urlopen('https://192.168.0.1:9000/_webshell/control/motor/%d/%d' %(axis, steps))
            driver.move_motor(axis, steps)

            if (pause != None):
                time.sleep(pause)

            # pagehandle = urllib.request.urlopen('https://192.168.0.1:9000/_webshell/control/motor/%d/%d' %(axis, steps))
        elif steps != 0:
            #print('Moving up then down')
            driver.move_motor(axis, steps + 300)
            time.sleep(2)
            driver.move_motor(axis, -300)
            if (pause != None):
                time.sleep(pause)
        else :
            pass

        #print(pagehandle.read())

        #time.sleep(10)
        return self

    def get_image(self):
        """Return image captured"""
        self.check_time()

        raw = requests.get(self.img_url_request).content
        # When Pi is connected to the internet
        # uro = urllib.request.urlopen('https://192.168.0.1:9000/_stream/?action=snapshot')   # When connected to Pi
        # uro = urllib.request.urlopen('https://192.168.0.1:9000/_stream/?action=stream')

        # print (raw)
        nparr = np.fromstring(raw, np.uint8)
        img_np = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
        return cv2.cvtColor(img_np, cv2.COLOR_BGR2GRAY)

    def focus_score(self, image):
        """ Return -1*variance(image)"""
        #return -1*dwt.focus_score(self.get_image())
        #a = dwt.nleveldwt(3,self.get_image())
        #return -1*dwt.focus_score(a)
        #return -1*dwt.focus_score(self.get_image())
        self.check_time()
        return np.var(image)

    def eval_score(self):
        self.check_time()
        return self.focus_score(self.get_image())

def naiive_autofocus(f, step_size = 500):
    threshold = 0
    direction = 0
    curr = f.eval_score()
    print(curr)

    while True:
        prev = curr
        if direction == 0:
            f.move_motor(step_size, 1)
        else:
            f.move_motor(direction * step_size, 1)
        time.sleep(1)
        curr = f.eval_score()
        print(curr)

        if direction == 0:
            direction = 1 if (curr-prev) > 0 else -1
        elif threshold > 0 and curr > threshold:
               return
        else:
            curdir = 1 if (curr-prev) > 0 else -1
            if curdir != direction:
                direction = curdir * direction
                if threshold == 0:
                    threshold = prev
                step_size = step_size / 2

# moosd's simple autofocus search implementation
def naive_autofocus(f, step_size = 500, thresh = 999999):
    print("Is simple better?")
    prev = f.eval_score()

    f.move_motor(step_size, 1)
    time.sleep(1)
    curr = f.eval_score()
    print(prev)
    print(curr)

    if curr > thresh:
        print("tres focused")
        return

    # check direction to climb
    diff = curr - prev
    direction = 1 if diff > 0 else -1

    # climb in smaller increments until theshold
    step_thresh = 99

    # for sanity
    timeout = 100
    tprogress = 0

    # climb, baby, climb!
    while step_size > step_thresh:
        while tprogress < timeout:
            prev = curr
            f.move_motor(direction * step_size, 1)
            time.sleep(1)
            curr = f.eval_score()
            print(curr)
            if curr > thresh:
                print("tres focused")
                return

            diff = curr - prev
            curdir = 1 if diff > 0 else -1
            direction = curdir * direction
            if curdir == -1:
                print("back back back")
                f.move_motor(direction * step_size, 1)
                if thresh == 999999:
                    thresh = prev#naive_autofocus(f, step_size, prev - 100)
                    #return
                break
            tprogress = tprogress + 1
        tprogress = 0
        step_size = step_size / 2

    print("Done naive hill climb")

def hill_climbing(f, step_size = 500):
    """ Climb to a higher place, find a smaller interval containing focus position
    (z1, z2, z3),(f1, f2, f3) = hill_climbing(f)

    """
    global scan_direction
    print('Starting hill climbing')
    f1 = f.eval_score()
    z1 = 0
    f2 = f.move_motor(step_size, 1).eval_score()
    z2 = step_size
    score_history.append(f1)
    score_history.append(f2)
    iterations = 0

    while(1):
        #print(f1,f2)
        if(f2 > f1):
            f0 = f1
            f1 = f2
            f2 = f.move_motor(step_size,1).eval_score()
            score_history.append(f2)
            z2 += step_size
            iterations += 1

        elif(iterations <=1):
            #print(iterations, f1, f2)
            print('Found a dip, assuming it is wrong and continuing')
            f0 = f1
            f1 = f2
            f2 = f.move_motor(step_size,1).eval_score()
            score_history.append(f2)
            z2 += step_size
            iterations +=1

        elif(iterations <= 2):
            print('Changing search direction')
            return hill_climbing(f, -step_size)

        else:
            print ('Finised hill climbing')
            return ((z2 - 2 * step_size -2 , z2 - step_size, z2), (f0, f1, f2))

def untested_hill_climbing(f, step_size = 500):
    """ Climb to a higher place, find a smaller interval containing focus position
    (z1, z2, z3),(f1, f2, f3) = hill_climbing(f)

    """
    global scan_direction
    print('Starting hill climbing')
    #f1 = f.eval_score()
    f1 = low_res_score(f.get_image())
    z1 = 0
    #f2 = f.move_motor(step_size, 1).eval_score()
    f.move_motor(step_size, 1)
    f2 = low_res_score(f.get_image())

    z2 = step_size
    score_history.append(f1)
    score_history.append(f2)
    iterations = 0

    while(1):
        #print(f1,f2)
        if(f2 > f1):
            f0 = f1
            f1 = f2
            #f2 = f.move_motor(step_size,1).eval_score()
            f.move_motor(step_size, 1)
            f2 = low_res_score(f.get_image())
            score_history.append(f2)
            z2 += step_size
            iterations += 1

        elif(iterations <=1):
            #print(iterations, f1, f2)
            print('Found a dip, assuming it is wrong and continuing')
            f0 = f1
            f1 = f2
            f.move_motor(step_size,1)
            f2 = low_res_score(f.get_image())
            score_history.append(f2)
            z2 += step_size
            iterations +=1

        elif(iterations <= 2):
            return hill_climbing(f, -step_size)

        else:
            print ('Finised hill climbing')
            return ((z2 - 2 * step_size -2 , z2 - step_size, z2), (f0, f1, f2))

def old_test_autofocus():
    # Get 3 points that encompass the focused position
    # I am assuming that the microscope starts below focus and then moves up
    # the middle value must be bigger than either of the endpoints
    m = microscope_control()
    z1 = 0
    print('Evaluating f1')
    f1 = m.eval_score()
    z2 = 500
    print('Evaluating f2')
    f2 = m.move_motor(z2, 5).eval_score()
    while(True):
        if f2 < f1:
            f2 = m.move_motor(200, 5).eval_score()
            z2 += 200
        else :
            break
    z3 = z2 + 500
    print('Evaluating f3')
    f3 = m.move_motor(500, 5).eval_score()
    while(True):
        if f2 < f3:
            f3 = m.move_motor(200, 5).eval_score()
            z3 += 200
        else :
            break

    #print(f1, f2, f3)

    # Gaussian prediction
    print('Gaussian fitting')
    mu = gaussian_fitting((z1, z2, z3), (f1, f2, f3))

    #print(mu)
    # Move motor to predicted position from z3
    m.move_motor(mu-z3)

def test_z_axis_repeatability():
    m = microscope_control()
    scores = []
    distance = 500
    for i in range(50):
        print('Iteration % d' % i)
        m.move_motor(distance, 5)
        m.move_motor(-distance, 5)
        #scores.append(m.move_motor(-distance, 5).eval_score())
        scores.append(m.eval_score())

    plt.plot(range(len(scores)),scores)
    plt.ylabel('Variance')
    plt.xlabel('Iteration')
    plt.title('Focus score varying repeated movements')
    plt.show()

def test_autofocus(timeout=90):
    global score_history
    start_time = time.time()

    score_history = [] # Clear history
    m = microscope_control(timeout=timeout)
    naive_autofocus(m)

    try:
        return score_history
        # Find small interval containing focus position
        z,f = hill_climbing(m) # uses the raw variance score
        #z,f = untested_hill_climbing(m) # using DWT low resolution images, should have less noise!
        #print('Peak in between', z)
        #time.sleep(5)

        # Gaussian prediction
        print('Gaussian prediction')
        mu = gaussian_fitting(z,f)
        #print('Moving to predicted position: %f' %mu)
        m.move_motor(-z[2]+mu, 2)
        score_history.append(m.eval_score())
        #print('Prediction Score : %f' % score_history[-1])
        interval = (mu-600, mu + 600)

        #print('Interval for fibonacci search', interval)
        #time.sleep(5)

        # Fibonacci search
        (a,b,x, z1, z3, z2) = fibonacci_search(interval, m)
        #print('Interval for parabola fitting: (%f, %f, %f)' %(a,x,b) )
        print('Parabola prediction')
        # # Parabola prediction
        mu = parabola_fitting((z1,z2,z3), (-score_history[-2],-score_history[-1],-score_history[-3]))
        #print ('Moving to predicted position: %f' % mu)
        m.move_motor(-x+mu, pause = 3)
        score_history.append(m.eval_score())
        print('Final Score: %f' %score_history[-1])

        end_time = time.time()
        print('Time takes is %f' %(end_time-start_time))

        #plt.plot(score_history)
        #plt.xlabel('Iterations')
        #plt.ylabel('Score')
        #plt.title('Score history')
        #plt.grid()
        #plt.show()

    except Exception:
        print("timeout")

    return(score_history)

if __name__ == '__main__':
    #m = microscope_control()
    # plot_score(m)
    # z1 = -5; z2 = 5; z3 = 10;
    # f = test_function;
    # x = gaussian_fitting((z1, z2, z3), (f(z1), f(z2), f(z3)))
    # print(x)
    # x = parabola_fitting((z1, z2, z3), (f(z1), f(z2), f(z3)))
    # print(x)
    #test_autofocus()

    # ###########################################################33
    #m = microscope_control()
    #z, f = hill_climbing(m)
    # mu = gaussian_fitting(z,f)
    # print(z , f)
    # print('Moving to predicted position: %f' %mu)
    # m.move_motor(-z[2]+mu, 8)
    # print('Final Score : %f' % m.eval_score())
    # ###############################################################
    #fibonacci_search((z[0],z[1]), m)

    # ########### Testing repeatability of microscope #############
    #test_z_axis_repeatability()
    history = test_autofocus()