import unittest
import os
from StartMaja.Common import ImageTools, ImageIO, FileSystem
from StartMaja.Common.GDalDatasetWrapper import GDalDatasetWrapper
import numpy as np

class TestImageTools(unittest.TestCase):

    def setUp(self):
        self.coordinates = (652594.9112913811, 10.00887639510383, 0,
                            5072876.717295351, 0, -9.974893672262251)
        self.projection = 'PROJCS["WGS 84 / UTM zone 31N",\
                           GEOGCS["WGS 84",DATUM["WGS_1984",\
                           SPHEROID["WGS 84",6378137,298.257223563,\
                           AUTHORITY["EPSG","7030"]],\
                           AUTHORITY["EPSG","6326"]],\
                           PRIMEM["Greenwich",0,\
                           AUTHORITY["EPSG","8901"]],\
                           UNIT["degree",0.0174532925199433,\
                           AUTHORITY["EPSG","9122"]],\
                           AUTHORITY["EPSG","4326"]],\
                           PROJECTION["Transverse_Mercator"],\
                           PARAMETER["latitude_of_origin",0],\
                           PARAMETER["central_meridian",3],\
                           PARAMETER["scale_factor",0.9996],\
                           PARAMETER["false_easting",500000],\
                           PARAMETER["false_northing",0],\
                           UNIT["metre",1,AUTHORITY["EPSG","9001"]],\
                           AXIS["Easting",EAST],AXIS["Northing",NORTH],\
                           AUTHORITY["EPSG","32631"]]'
        self.height = 200
        self.width = 100

    def test_extract_class_threshold(self):
        mask = np.arange(0, 25).reshape(5, 5)
        class_to_extract = 10
        value_type = "threshold"
        expected = np.array([[0, 0, 0, 0, 0],
                             [0, 0, 0, 0, 0],
                             [1, 1, 1, 1, 1],
                             [1, 1, 1, 1, 1],
                             [1, 1, 1, 1, 1]])
        calculated = ImageTools.extract_class(mask, class_to_extract, value_type)
        np.testing.assert_array_almost_equal(expected, calculated)

    def test_extract_class_value(self):
        mask = np.arange(0, 9).reshape(3, 3)
        class_to_extract = [7, 8, 11]
        value_type = "value"
        expected = np.array([[0, 0, 0],
                             [0, 0, 0],
                             [0, 1, 1]])
        calculated = ImageTools.extract_class(mask, class_to_extract, value_type)
        np.testing.assert_array_almost_equal(expected, calculated)

    def test_extract_class_bit(self):
        mask = np.arange(0, 9).reshape(3, 3)
        class_to_extract = [3]
        value_type = "bit"
        expected = np.array([[0, 0, 0],
                             [0, 0, 0],
                             [0, 0, 1]])
        calculated = ImageTools.extract_class(mask, class_to_extract, value_type)
        np.testing.assert_array_almost_equal(expected, calculated)

    def test_normalize(self):
        img = np.arange(0, 9).reshape(3, 3)
        value_range_in = (0, 10)
        value_range_out = (0, 1)
        expected = np.array([[0, .1, .2],
                             [.3, .4, .5],
                             [.6, .7, .8]])
        calculated = ImageTools.normalize(img,
                                          value_range_in=value_range_in,
                                          value_range_out=value_range_out)
        np.testing.assert_array_almost_equal(expected, calculated)

    def test_normalize_clip(self):
        img = np.arange(0, 9).reshape(3, 3)
        value_range_in = (0, 5)
        value_range_out = (0, 1)
        expected = np.array([[0, .2, .4],
                             [.6, .8, 1],
                             [1, 1, 1]])
        calculated = ImageTools.normalize(img,
                                          value_range_in=value_range_in,
                                          value_range_out=value_range_out,
                                          clip=True)
        np.testing.assert_array_almost_equal(expected, calculated)

    def test_normalize_0to255(self):
        img = np.arange(-4, 5).reshape(3, 3) / 5
        value_range_in = (-1, 1)
        value_range_out = (0, 255)
        expected = np.array([[25.5, 51.,  76.5],
                             [102., 127.5, 153.],
                             [178.5, 204., 229.5]])
        calculated = ImageTools.normalize(img,
                                          value_range_in=value_range_in,
                                          value_range_out=value_range_out)
        np.testing.assert_array_almost_equal(expected, calculated)

    def test_gdal_buildvrt(self):
        path = os.path.join(os.getcwd(), "test_gdal_buildvrt.tif")
        vrt = os.path.join(os.getcwd(), "test_vrt.vrt")
        img = np.arange(-4, 5).reshape(3, 3) / 5

        ImageIO.write_geotiff(img, path, self.projection, self.coordinates)
        self.assertTrue(os.path.exists(path))
        driver = ImageTools.gdal_buildvrt(path, dst=vrt)
        self.assertTrue(os.path.exists(vrt))
        np.testing.assert_almost_equal(driver.array, img)
        FileSystem.remove_file(vrt)
        FileSystem.remove_file(path)

    def test_gdal_translate(self):
        img = np.ones((self.height, self.width, 2), np.int16)
        path = os.path.join(os.getcwd(), "test_gdal_translate.tif")
        scaled = os.path.join(os.getcwd(), "scaled.tif")
        out_resolution = (20, -20)
        ImageIO.write_geotiff(img, path, self.projection, self.coordinates)
        self.assertTrue(os.path.exists(path))
        ds = ImageTools.gdal_translate(path, scaled,
                                       tr=" ".join([str(i) for i in out_resolution]),
                                       scale="0 1 0 255")
        self.assertEqual(ds.resolution, out_resolution)
        self.assertEqual(ds.array.shape, (self.height // 2, self.width // 2, 2))
        np.testing.assert_almost_equal(ds.array, 255)
        FileSystem.remove_file(path)
        FileSystem.remove_file(scaled)

    def test_gdal_warp(self):
        img = np.ones((self.height, self.width, 2), np.int16)
        img_rescaled = np.ones((int(self.height/2), int(self.width/2), 2), np.int16)
        out_resolution = (20, -20)
        path = os.path.join(os.getcwd(), "test_gdal_warp.tif")
        scaled = os.path.join(os.getcwd(), "res_changed.tif")
        ImageIO.write_geotiff(img, path, self.projection, self.coordinates)
        self.assertTrue(os.path.exists(path))
        ds = ImageTools.gdal_warp(path, scaled,
                                  tr=" ".join(str(e) for e in out_resolution),
                                  r="max", q=True)
        self.assertTrue(os.path.isfile(scaled))
        self.assertEqual(ds.resolution, out_resolution)
        self.assertEqual(ds.array.shape, (self.height // 2, self.width // 2, 2))
        np.testing.assert_almost_equal(ds.array, img_rescaled)
        FileSystem.remove_file(path)
        FileSystem.remove_file(scaled)

    def test_gdal_buildvrt_concatenate(self):
        from StartMaja.Common import FileSystem
        paths = []
        for i in range(1, 3, 1):
            img = np.ones((i, i, 2), np.int16) * i
            path = os.path.join(os.getcwd(), "test_gdal_merge_%s.tif" % i)
            ImageIO.write_geotiff(img, path, self.projection, self.coordinates)
            self.assertTrue(os.path.exists(path))
            paths.append(path)
        empty = os.path.join(os.getcwd(), "empty.vrt")
        driver = ImageTools.gdal_buildvrt(*paths, dst=empty,
                                          separate=True,
                                          srcnodata=0)
        expected = np.array([[[1, 0],
                              [0, 0]],
                             [[2, 2],
                              [2, 2]]], dtype=np.int16)

        np.testing.assert_almost_equal(driver.array, expected)
        self.assertEqual(driver.nodata_value, 0)
        self.assertEqual(driver.epsg, 32631)
        [FileSystem.remove_file(path) for path in paths]
        FileSystem.remove_file(empty)
        [self.assertFalse(os.path.exists(path)) for path in paths]
        self.assertFalse(os.path.exists(empty))

    def test_gdal_tile_untile(self):
        img = np.arange(0., 100.).reshape((10, 10))
        path = os.path.join(os.getcwd(), "test_gdal_retile.tif")
        tile_folder = os.path.join(os.getcwd(), "tiled")
        ImageIO.write_geotiff(img, path, self.projection, self.coordinates)
        # Add parasitic file - It should not cause problems
        path_parasite = os.path.join(tile_folder, "tile_01_01.tif")
        FileSystem.create_directory(tile_folder)
        ImageIO.write_geotiff(img, path_parasite, self.projection, self.coordinates)
        ds_in = GDalDatasetWrapper.from_file(path)
        self.assertTrue(os.path.exists(path))
        tiles = ImageTools.gdal_retile(ds_in, tile_folder,
                                       TileWidth=2,
                                       TileHeight=2,
                                       Overlap=1)
        self.assertTrue(os.path.isdir(tile_folder))
        self.assertEqual(len(tiles), 81)
        img_read = np.array(ImageIO.tiff_to_array(tiles[-1]))
        expected = np.array([[88, 89],
                             [98, 99]])
        # Some gdal_retile versions are producing the following image:
        # [[87, 89], [97, 99]].
        np.testing.assert_allclose(expected, img_read, atol=1)

        # Untile
        ds_untiled = ImageTools.gdal_buildvrt(*tiles)
        np.testing.assert_allclose(img, ds_untiled.array, atol=1)
        FileSystem.remove_file(path)
        FileSystem.remove_directory(tile_folder)

    def test_merge_then_translate(self):
        datasets = []
        init = np.zeros((2, 2), np.int16)
        path = os.path.join(os.getcwd(), "test_gdal_merge.tif")
        ImageIO.write_geotiff(init, path, self.projection, self.coordinates)
        ds_in = GDalDatasetWrapper.from_file(path)
        for i in range(1, 3, 1):
            img = np.ones((i*2, i*2), np.int16) * i
            ds_n = GDalDatasetWrapper(ds=ds_in.get_ds(), array=img)
            self.assertTrue(os.path.exists(path))
            datasets.append(ds_n)
        ds_merged = ImageTools.gdal_merge(*datasets, dst="out.tif",
                                          separate=True,
                                          q=True,
                                          a_nodata=0)
        # Array of shape (4, 4, 2):
        expected = np.array([[[1, 2],
                              [1, 2],
                              [0, 2],
                              [0, 2]],
                             [[1, 2],
                              [1, 2],
                              [0, 2],
                              [0, 2]],
                             [[0, 2],
                              [0, 2],
                              [0, 2],
                              [0, 2]],
                             [[0, 2],
                              [0, 2],
                              [0, 2],
                              [0, 2]]], dtype=np.int16)
        FileSystem.remove_file("out.tif")
        np.testing.assert_equal(expected.dtype, ds_merged.array.dtype)
        np.testing.assert_almost_equal(expected, ds_merged.array)
        self.assertEqual(ds_merged.nodata_value, 0)
        self.assertEqual(ds_merged.epsg, 32631)
        ds_translate = ImageTools.gdal_translate(ds_merged,
                                                 a_nodata=0)
        FileSystem.remove_file(path)

        np.testing.assert_equal(expected.dtype, ds_translate.array.dtype)
        np.testing.assert_almost_equal(ds_translate.array, expected)
        self.assertEqual(ds_translate.nodata_value, 0)
        self.assertEqual(ds_translate.epsg, 32631)

    def test_gdal_merge_optfile(self):
        datasets, written = [], []
        init = np.zeros((2, 2), np.int16)
        path = os.path.join(os.getcwd(), "test_gdal_merge_optfile.tif")
        ImageIO.write_geotiff(init, path, self.projection, self.coordinates)
        ds_in = GDalDatasetWrapper.from_file(path)
        for i in range(1, 3, 1):
            img = np.ones((i*2, i*2), np.int16) * i
            ds_n = GDalDatasetWrapper(ds=ds_in.get_ds(), array=img)
            p_out = "test_gdal_merge_optfile_%s.tif" % i
            ImageIO.write_geotiff_existing(img, p_out, ds_in.get_ds())
            self.assertTrue(os.path.exists(path))
            datasets.append(ds_n)
            written.append(p_out)
        optfile = "test_gdal_merge_optfile.txt"
        with open(optfile, 'w') as file_handler:
            for item in written:
                file_handler.write("{}\n".format(item))

        ds_merged = ImageTools.gdal_merge(*datasets,
                                          q=True,
                                          a_nodata=0)
        ds_optfile = ImageTools.gdal_merge(optfile=optfile,
                                           q=True,
                                           a_nodata=0)
        # Array of shape (4, 4):
        expected = np.array([[2, 2, 2, 2],
                             [2, 2, 2, 2],
                             [2, 2, 2, 2],
                             [2, 2, 2, 2]], dtype=np.int16)

        FileSystem.remove_file(path)
        [FileSystem.remove_file(p) for p in written]
        FileSystem.remove_file(optfile)
        np.testing.assert_equal(expected.dtype, ds_merged.array.dtype)
        np.testing.assert_almost_equal(expected, ds_merged.array)
        self.assertEqual(ds_merged.nodata_value, 0)
        self.assertEqual(ds_merged.epsg, 32631)
        np.testing.assert_equal(expected.dtype, ds_optfile.array.dtype)
        np.testing.assert_almost_equal(expected, ds_optfile.array)
        self.assertEqual(ds_optfile.nodata_value, 0)
        self.assertEqual(ds_optfile.epsg, 32631)

if __name__ == '__main__':
    unittest.main()


import pandas as pd

df1UP_C1T5 = pd.read_excel("/home/petear/New Folder/C_1-T_5_FC_OPPTAK.xlsx", sheet_name='UP')
df2UP_C7T11 = pd.read_excel("/home/petear/New Folder/C_7-T_11_FC_OPPTAK.xlsx", sheet_name='UP')

#1.1.1
dfUPMerged1_3 = pd.concat([df1UP_C1T5, df2UP_C7T11], axis=0)
dfUPMerged1_3 = dfUPMerged1_3.drop_duplicates(subset=['GeneID'], keep='first')
#sort on logFC column in descending order
dfUPMerged1_3 = dfUPMerged1_3.sort_values(by=['logFC'], ascending=False)

df1DOWN_C1T5 = pd.read_excel("/home/petear/New Folder/C_1-T_5_FC_OPPTAK.xlsx", sheet_name='DOWN')
df2DOWN_C7T11 = pd.read_excel("/home/petear/New Folder/C_7-T_11_FC_OPPTAK.xlsx", sheet_name='DOWN')

#1.1.2
dfDOWNMerged1_3 = pd.concat([df1DOWN_C1T5, df2DOWN_C7T11], axis=0)
dfDOWNMerged1_3 = dfDOWNMerged1_3.drop_duplicates(subset=['GeneID'], keep='first')
dfDOWNMerged1_3 = dfDOWNMerged1_3.sort_values(by=['logFC'], ascending=True)
#find genes that are in both dataframes in the ENTREZID column
#1.3
UnionDF1_3 = pd.concat([dfUPMerged1_3, dfDOWNMerged1_3], axis=0)
UnionDF1_3 = UnionDF1_3.drop_duplicates(subset=['GeneID'], keep='first')
UnionDF1_3 = UnionDF1_3.sort_values(by=['logFC'], ascending=False)
#IntersectDF1_3 = pd.merge(dfUPMerged, dfDOWNMerged, on='GeneID', how='inner')

############################################################################################################
df1UP_C1T2 = pd.read_excel("/home/petear/New Folder/C_1-T_2_FC_OPPTAK.xlsx", sheet_name='UP')
df2UP_C7T8 = pd.read_excel("/home/petear/New Folder/C_7-T_8_FC_OPPTAK.xlsx", sheet_name='UP')

#1.2.1
dfUPMerged1_4 = pd.concat([df1UP_C1T2, df2UP_C7T8], axis=0)
dfUPMerged1_4 = dfUPMerged1_4.drop_duplicates(subset=['GeneID'], keep='first')
dfUPMerged1_4 = dfUPMerged1_4.sort_values(by=['logFC'], ascending=False)

df1DOWN_C1T2 = pd.read_excel("/home/petear/New Folder/C_1-T_2_FC_OPPTAK.xlsx", sheet_name='DOWN')
df2DOWN_C7T8 = pd.read_excel("/home/petear/New Folder/C_7-T_8_FC_OPPTAK.xlsx", sheet_name='DOWN')

#1.2.2
dfDOWNMerged1_4 = pd.concat([df1DOWN_C1T2, df2DOWN_C7T8], axis=0)
dfDOWNMerged1_4 = dfDOWNMerged1_4.drop_duplicates(subset=['GeneID'], keep='first')
dfDOWNMerged1_4 = dfDOWNMerged1_4.sort_values(by=['logFC'], ascending=True)

#1.4
UnionDF1_4 = pd.concat([dfDOWNMerged1_3, dfDOWNMerged1_4], axis=0)
UnionDF1_4 = UnionDF1_4.drop_duplicates(subset=['GeneID'], keep='first')
UnionDF1_4 = UnionDF1_4.sort_values(by=['logFC'], ascending=True)
#IntersectDF1_4 = pd.merge(dfDOWNMerged1_3, dfDOWNMerged1_4, on='GeneID', how='inner')

############################################################################################################

#1.5
UnionDF1_5 = pd.concat([dfUPMerged1_3, dfUPMerged1_4], axis=0)
UnionDF1_5 = UnionDF1_5.drop_duplicates(subset=['GeneID'], keep='first')
UnionDF1_5 = UnionDF1_5.sort_values(by=['logFC'], ascending=False)

IntersectDF1_5 = pd.merge(dfUPMerged1_3, dfUPMerged1_4, on='GeneID', how='inner')
IntersectDF1_5 = IntersectDF1_5.drop_duplicates(subset=['GeneID'], keep='first')
IntersectDF1_5 = IntersectDF1_5.sort_values(by=['logFC'], ascending=False)

############################################################################################################

#2.1.1
dfDegUP_C1T5 = pd.read_excel("/home/petear/New Folder/C_1-T_5_FC_DEGRADERING.xlsx", sheet_name='UP')
dfDegUP_C7T11 = pd.read_excel("/home/petear/New Folder/C_7-T_11_FC_DEGRADERING.xlsx", sheet_name='UP')

dfDegMerged2_1 = pd.concat([dfDegUP_C1T5, dfDegUP_C7T11], axis=0)
dfDegMerged2_1 = dfDegMerged2_1.drop_duplicates(subset=['GeneID'], keep='first')
dfDegMerged2_1 = dfDegMerged2_1.sort_values(by=['logFC'], ascending=False)

#2.1.2
dfDegDOWN_C1T5 = pd.read_excel("/home/petear/New Folder/C_1-T_5_FC_DEGRADERING.xlsx", sheet_name='DOWN')
dfDegDOWN_C7T11 = pd.read_excel("/home/petear/New Folder/C_7-T_11_FC_DEGRADERING.xlsx", sheet_name='DOWN')

dfDegMerged2_2 = pd.concat([dfDegDOWN_C1T5, dfDegDOWN_C7T11], axis=0)
dfDegMerged2_2 = dfDegMerged2_2.drop_duplicates(subset=['GeneID'], keep='first')
dfDegMerged2_2 = dfDegMerged2_2.sort_values(by=['logFC'], ascending=True)

writer = pd.ExcelWriter('AlgoSiScreener.xlsx', engine='xlsxwriter')

dfUPMerged1_3.to_excel(writer, sheet_name='1.1.1')
dfDOWNMerged1_3.to_excel(writer, sheet_name='1.1.2')
UnionDF1_3.to_excel(writer, sheet_name='1.3')
dfUPMerged1_4.to_excel(writer, sheet_name='1.2.1')
dfDOWNMerged1_4.to_excel(writer, sheet_name='1.2.2')
UnionDF1_4.to_excel(writer, sheet_name='1.4')
UnionDF1_5.to_excel(writer, sheet_name='1.5-Uni')
IntersectDF1_5.to_excel(writer, sheet_name='1.5-Int')
dfDegMerged2_1.to_excel(writer, sheet_name='2.1.1')
dfDegMerged2_2.to_excel(writer, sheet_name='2.1.2')

writer.save()


# -*- coding: utf-8 -*-
# @Time:    2021/11/8 10:46
# @File:    299. 猜数字游戏.py
from leetcode import *

class Solution:
    def getHint(self, secret: str, guess: str) -> str:
        A = 0
        nums = [[0] * 10 for _ in range(2)]
        for i in range(len(secret)):
            if secret[i] == guess[i]:
                A += 1
            else:
                nums[0][int(secret[i])] += 1
                nums[1][int(guess[i])] += 1
        B = 0
        for i in range(10):
            B += min(nums[0][i], nums[1][i])
        return str(A) + 'A' + str(B) + 'B'


""" r =int(input("inter the number of rows: "))
num =1
for row in range(1,r+1):
    for col in range(1,row+1):
        print(num,end = " ")
        num+=1
    print()
"""
# fibonachi
n = int(input("enter the number upto u want fibonachi: "))
a,b=0,1
# while b<=n:
for i in range(0,n):
    if b<=i:
      print(b,end=" ")
      a,b=b,a+b


# cost = input("Enter the cost of groceries: ")   #correct
# payment = int(float(cost)/20)                   #only needed float
# if payment is not int:        #this if statement
#     payment += 1                #is not needed
# change = -(float(cost) - int(payment*20))       #bills = (cost//20) + 1
# print(int(payment))                             #change = (bill*20) - cost
# print("Pay with " + str(payment) + " twenties, and get back " + str(change)) #correct

import turtle
window = turtle.Screen()
redCross = turtle.Turtle()
redCross.color("red")
redCross.fillcolor("red")
redCross.begin_fill()
for i in range(4):
    for i in range (2):
        redCross.forward(100)
        redCross.left(90)
    redCross.forward(100)
    redCross.right(90)          #needed to hide the turtle (5)
redCross.end_fill()
window.exitonclick()

# user_input = input("Enter numbers separated by spaces: ")
# nums = user_input.split()

# def print_progression(nums):        #(prog)
#     nums.sort()
#     for i in range(len(nums)):
#         if i is -1:
#            return nums
#         if i < 0 or i is 0:
#            nums = " -> ".join(nums)
#     return nums

# print(print_progression(nums))


# 구명보트
# https://programmers.co.kr/learn/courses/30/lessons/42885

p1, l1 = [70, 50, 80, 50], 100
p2, l2 = [70, 80, 50], 100

from collections import deque

def solution(people, limit):
    answer = 0

    # Q = deque(people)
    # print(Q)
    while True :
        print("지금 무인도에 남은 사람 " + str(people))
        if len(people) == 0 :
            break
        elif len(people) == 1:
            return answer + 1

        M = people[0] #지금 나갈 사람
        temp = 0
        ddack = False
        for i in range(1,len(people)):
            index = 0
            if people[i] + M == limit :
                print("딱맞다!")
                del people[i]
                del people[0]
                answer += 1
                ddack = True
                break
            elif people[i] + M <= limit and people[i] > temp :
                index = i
                temp = people[i]

        if ddack == True :
            continue
        elif index == 0 :
            del people[0]
            answer += 1
        else :
            del people[index]
            del people[0]
            answer += 1

    return answer

print(solution(p1,l1))
print(solution(p2,l2))
print(solution([40,50,60,90], 100 ))
print(solution([160, 150, 140, 60, 50, 40], 200))

# 시간제한도 있다.
def solution2(people, limit):
    answer = 0

    people.sort(reverse=True)
    print(people)
    half = int(limit / 2)
    while True :
        if len(people) == 0:
            return answer
        elif len(people) == 1 :
            return answer + 1

        M = people[0]
        for i in range(1,len(people)):
            if people[i] + M <= limit :
                del people[i]
                del people[0]
                answer += 1
                break

    return answer

# print(solution2(p1,l1))
# print(solution2(p2,l2))
# print(solution2([40,50,60,90], 100 ))
# print(solution2([160, 150, 140, 60, 50, 40], 200))


'''
문제
KOI 사냥터에는 N 마리의 동물들이 각각 특정한 위치에 살고 있다.
사냥터에 온 사냥꾼은 일직선 상에 위치한 M 개의 사대(총을 쏘는 장소)에서만 사격이 가능하다.
편의상, 일직선을 x-축이라 가정하고, 사대의 위치 x1, x2, ..., xM은 x-좌표 값이라고 하자.
각 동물이 사는 위치는 (a1, b1), (a2, b2), ..., (aN, bN)과 같이 x,y-좌표 값으로 표시하자.
동물의 위치를 나타내는 모든 좌표 값은 양의 정수이다.

사냥꾼이 가지고 있는 총의 사정거리가 L이라고 하면, 사냥꾼은 한 사대에서 거리가 L 보다 작거나 같은 위치의 동물들을 잡을 수 있다고 한다.
단, 사대의 위치 xi와 동물의 위치 (aj, bj) 간의 거리는 |xi-aj| + bj로 계산한다.

예를 들어, 아래의 그림과 같은 사냥터를 생각해 보자.
(사대는 작은 사각형으로, 동물의 위치는 작은 원으로 표시되어 있다.)
사정거리 L이 4라고 하면, 점선으로 표시된 영역은 왼쪽에서 세 번째 사대에서 사냥이 가능한 영역이다.

사대의 위치와 동물들의 위치가 주어졌을 때, 잡을 수 있는 동물의 수를 출력하는 프로그램을 작성하시오.

입력
입력의 첫 줄에는 사대의 수 M (1 ≤ M ≤ 100,000), 동물의 수 N (1 ≤ N ≤ 100,000), 사정거리 L (1 ≤ L ≤ 1,000,000,000)이 빈칸을 사이에 두고 주어진다.
두 번째 줄에는 사대의 위치를 나타내는 M개의 x-좌표 값이 빈칸을 사이에 두고 양의 정수로 주어진다.
이후 N개의 각 줄에는 각 동물의 사는 위치를 나타내는 좌표 값이 x-좌표 값, y-좌표 값의 순서로 빈칸을 사이에 두고 양의 정수로 주어진다.
사대의 위치가 겹치는 경우는 없으며, 동물들의 위치가 겹치는 경우도 없다.
모든 좌표 값은 1,000,000,000보다 작거나 같은 양의 정수이다.

출력
출력은 단 한 줄이며, 잡을 수 있는 동물의 수를 음수가 아닌 정수로 출력한다.

서브태스크
번호	배점	제한
1	9
M ≤ 10, N ≤ 10, X ≤ 10

2	14
M ≤ 20, N ≤ 20, X ≤ 20

3	18
M ≤ 100, N ≤ 100

4	19
M ≤ 2,000, N ≤ 2,000

5	40
추가적인 제약 조건은 없다.

예제 입력 1
4 8 4
6 1 4 9
7 2
3 3
4 5
5 1
2 2
1 4
8 4
9 4
예제 출력 1
6
예제 입력 2
1 5 3
3
2 2
1 1
5 1
4 2
3 3
예제 출력 2
5
'''

# 다른 코드 분석
# 핵심 : 모든 사대가 모든 동물들을 검사하는 대신 각 동물의 가장 가까운 양쪽의 사대를 이분 탐색으로 찾아 사냥할 수 있는지 확인

m, n, l = map(int, input().split())
shooters = list(map(int, input().split()))
animals = []
for _ in range(n):
    x, y = map(int, input().split())
    if y <= l:
        animals.append((x, y))
shooters.sort()
animals.sort(key=lambda axis: axis[0]) # axis[0], 즉 x좌표 기준으로 오름차순 정렬
ans = 0
idx = 0
for i in range(len(animals)):
    left, right = idx, len(shooters)-1
    mid = 0
    while left <= right:
        mid = (left+right)//2
        if shooters[mid] <= animals[i][0]:
            if len(shooters) - 1 == mid or shooters[mid+1] > animals[i][0]:
                break
            left = mid + 1
        else:
            right = mid - 1
    idx = mid
    if abs(animals[i][0] - shooters[mid]) + animals[i][1] <= l: # 양쪽의 사대에서 사격이 가능한 동물일 경우 ans에 1 도한다.
        ans += 1
    elif len(shooters) > mid+1 and abs(animals[i][0] - shooters[mid+1]) + animals[i][1] <= l:
        ans += 1
print(ans)


from __future__ import division

import math
import pcbnew

class PadMaker:
    """
    Useful construction functions for common types of pads
    """

    def __init__(self, module):
        self.module = module

    def THPad(self, Vsize, Hsize, drill, shape=pcbnew.PAD_SHAPE_OVAL, rot_degree = 0):
        pad = pcbnew.D_PAD(self.module)
        pad.SetSize(pcbnew.wxSize(Hsize, Vsize))
        pad.SetShape(shape)
        pad.SetAttribute(pcbnew.PAD_ATTRIB_STANDARD)
        pad.SetLayerSet(pad.StandardMask())
        pad.SetDrillSize(pcbnew.wxSize(drill, drill))
        pad.SetOrientation(rot_degree*10)   # rotation is in 0.1 degrees

        return pad

    def THRoundPad(self, size, drill):
        pad = self.THPad(size, size, drill, shape=pcbnew.PAD_SHAPE_CIRCLE)
        return pad

    def NPTHRoundPad(self, drill):
        pad = pcbnew.D_PAD(self.module)
        pad.SetSize(pcbnew.wxSize(drill, drill))
        pad.SetShape(pcbnew.PAD_SHAPE_CIRCLE)
        pad.SetAttribute(pcbnew.PAD_ATTRIB_HOLE_NOT_PLATED)
        pad.SetLayerSet(pad.UnplatedHoleMask())
        pad.SetDrillSize(pcbnew.wxSize(drill, drill))
        return pad

    def SMDPad(self, Vsize, Hsize, shape=pcbnew.PAD_SHAPE_RECT, rot_degree=0):
        pad = pcbnew.D_PAD(self.module)
        pad.SetSize(pcbnew.wxSize(Hsize, Vsize))
        pad.SetShape(shape)
        pad.SetAttribute(pcbnew.PAD_ATTRIB_SMD)
        pad.SetLayerSet(pad.SMDMask())
        pad.SetOrientation(rot_degree*10)   # rotation is in 0.1 degrees

        return pad

    def SMTRoundPad(self, size):
        pad = self.SMDPad(size, size, shape=pcbnew.PAD_SHAPE_CIRCLE)
        return pad

class PadArray:

    def __init__(self):
        self.firstPadNum = 1
        self.pinNames = None
        self.firstPad = None

    def SetPinNames(self, pinNames):
        """
        Set a name for all the pins
        """
        self.pinNames = pinNames

    def SetFirstPadType(self, firstPad):
        self.firstPad = firstPad

    def SetFirstPadInArray(self, fpNum):
        self.firstPadNum = fpNum

    def AddPad(self, pad):
        self.pad.GetParent().Add(pad)

    def GetPad(self, is_first_pad, pos):
        if (self.firstPad and is_first_pad):
            pad = self.firstPad
        else:
            pad = self.pad

        # create a new pad with same characteristics
        pad = pad.Duplicate()
        pad.SetPos0(pos)
        pad.SetPosition(pos)

        return pad

    def GetName(self, *args, **kwargs):

        if self.pinNames is None:
            return self.NamingFunction(*args, **kwargs)

        return self.pinNames

    def NamingFunction(self, *args, **kwargs):
        """
        Implement this as needed for each array type
        """
        raise NotImplementedError;

class PadGridArray(PadArray):

    def __init__(self, pad, nx, ny, px, py, centre=pcbnew.wxPoint(0, 0)):
        PadArray.__init__(self)
        # this pad is more of a "context", we will use it as a source of
        # pad data, but not actually add it
        self.pad = pad
        self.nx = int(nx)
        self.ny = int(ny)
        self.px = px
        self.py = py
        self.centre = centre

    # handy utility function 1 - A, 2 - B, 26 - AA, etc
    # aIndex = 0 for 0 - A
    # alphabet = set of allowable chars if not A-Z,
    #            eg ABCDEFGHJKLMNPRTUVWY for BGA
    def AlphaNameFromNumber(self, n, aIndex=1,
                            alphabet="ABCDEFGHIJKLMNOPQRSTUVWXYZ"):

        div, mod = divmod(n - aIndex, len(alphabet))
        alpha = alphabet[mod]

        if div > 0:
            return self.AlphaNameFromNumber(div, aIndex, alphabet) + alpha

        return alpha

    # right to left, top to bottom
    def NamingFunction(self, x, y):
        return self.firstPadNum + (self.nx * y + x)

    #relocate the pad and add it as many times as we need
    def AddPadsToModule(self, dc):

        pin1posX = self.centre.x - self.px * (self.nx - 1) / 2
        pin1posY = self.centre.y - self.py * (self.ny - 1) / 2

        for x in range(0, self.nx):
            posX = pin1posX + (x * self.px)

            for y in range(self.ny):
                posY = pin1posY + (self.py * y)
                pos = dc.TransformPoint(posX, posY)
                pad = self.GetPad(x == 0 and y == 0, pos)
                pad.SetPadName(self.GetName(x,y))
                self.AddPad(pad)

class EPADGridArray(PadGridArray):

  def NamingFunction(self, nx, ny):
    return self.firstPadNum

class PadZGridArray(PadArray):

    def __init__(self, pad, pad_count, line_count, line_pitch,
                 pad_pitch, centre=pcbnew.wxPoint(0, 0)):
        PadArray.__init__(self)
        # this pad is more of a "context", we will use it as a source of
        # pad data, but not actually add it
        self.pad = pad
        self.pad_count = int(pad_count)
        self.line_count = int(line_count)
        self.line_pitch = line_pitch
        self.pad_pitch = pad_pitch
        self.centre = centre

    # right to left, top to bottom
    def NamingFunction(self, pad_pos):
        return self.firstPadNum + pad_pos

    #relocate the pad and add it as many times as we need
    def AddPadsToModule(self, dc):

        pin1posX = self.centre.x - self.pad_pitch * (self.pad_count - 1) / 2
        pin1posY = self.centre.y + self.line_pitch * (self.line_count - 1) / 2
        line = 0

        for padnum in range(0, self.pad_count):
            posX = pin1posX + (padnum * self.pad_pitch)
            posY = pin1posY - (self.line_pitch * line)

            pos = dc.TransformPoint(posX, posY)
            pad = self.GetPad(padnum == 0, pos)
            pad.SetPadName(self.GetName(padnum))
            self.AddPad(pad)

            line += 1

            if line >= self.line_count:
                line = 0

class PadLineArray(PadGridArray):

    def __init__(self, pad, n, pitch, isVertical,
                 centre=pcbnew.wxPoint(0, 0)):

        if isVertical:
            PadGridArray.__init__(self, pad, 1, n, 0, pitch, centre)
        else:
            PadGridArray.__init__(self, pad, n, 1, pitch, 0, centre)

class PadCircleArray(PadArray):

    def __init__(self, pad, n, r, angle_offset=0, centre=pcbnew.wxPoint(0, 0),
                 clockwise=True):
        PadArray.__init__(self)
        # this pad is more of a "context", we will use it as a source of
        # pad data, but not actually add it
        self.pad = pad
        self.n = int(n)
        self.r = r
        self.angle_offset = angle_offset
        self.centre = centre
        self.clockwise = clockwise

    # around the circle, CW or CCW according to the flag
    def NamingFunction(self, n):
        return str(self.firstPadNum + n)

    #relocate the pad and add it as many times as we need
    def AddPadsToModule(self, dc):
        for pin in range(0, self.n):
            angle = self.angle_offset + (360 / self.n) * pin

            if not self.clockwise:
                angle = -angle

            pos_x = math.sin(angle * math.pi / 180) * self.r
            pos_y = -math.cos(angle  * math.pi / 180) * self.r
            pos = dc.TransformPoint(pos_x, pos_y)
            pad = self.GetPad(pin == 0, pos)
            pad.SetPadName(self.GetName(pin))
            self.AddPad(pad)

class PadCustomArray(PadArray):
    """
    Layout pads according to a custom array of [x,y] data
    """

    def __init__(self, pad, array):
        PadArray.__init__(self)
        self.pad = pad
        self.array = array

    def NamingFunction(self, n):
        return str(self.firstPadNum + n)

    #relocate the pad and add it as many times as we need
    def AddPadsToModule(self, dc):

        for i in range(len(self.array)):
            pos = dc.TransformPoint(self.array[i][0], self.array[i][1])
            pad = self.GetPad(i == 0, pos)
            pad.SetPadName(self.GetName(i))
            self.AddPad(pad)


# leetcode february challenge
#https://leetcode.com/explore/challenge/card/february-leetcoding-challenge-2021/584/week-1-february-1st-february-7th/3628/
class Solution:
    def findLHS(self, nums: List[int]) -> int:
        values = {}
        for num in nums:
            if num not in values:
                values[num] = 0
            values[num] += 1
        # Sort the dictionary
        sortedValues = sorted(values.items(), key=lambda member: member[1],reverse=True)
        maxLength = float('-Inf')
        for key,value in sortedValues:
            nextKey = key + 1
            if nextKey in values:
                maxLength = max(maxLength,values[key]+values[nextKey])
            prevKey = key - 1
            if prevKey in values:
                maxLength = max(maxLength,values[key]+values[prevKey])
        if maxLength > float('-Inf'):
            return maxLength
        return 0


### patient ###
import os
import io
from io import BytesIO
import pdfkit
from supereasypa import app
from flask import render_template, url_for, flash, redirect, request, Blueprint, make_response, send_file
from flask_login import login_user, current_user, logout_user, login_required
from supereasypa import db
from supereasypa.models import User, PriorAuth, Patient, Insurance, Prescriber, Notes, Documents, Drugs, MapApplication
from supereasypa.patients.forms import AddPatient, AddNotesPatient, AddDocsPatient, AddPAFormPatient
from werkzeug.utils import secure_filename
from datetime import date, time
from datetime import datetime, timedelta
from pytz import timezone

UPLOAD_FOLDER = ''
ALLOWED_EXTENSIONS = {'txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'}
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024
config = pdfkit.configuration(
    wkhtmltopdf=r"C:\Users\matth\source\repos\supereasypa\supereasypa\wkhtmltopdf\bin\wkhtmltopdf.exe")

patient = Blueprint('patient', __name__)

@patient.route('/addpatient', methods=['GET', 'POST'])
@login_required
def addpatient():
    form = AddPatient()
    user_logged = current_user.client_id
    allins = Insurance.query.filter_by(client_id=user_logged)
    patient = ''

    if form.validate_on_submit():
        patient = Patient(fname=form.fname.data,
                          lname=form.lname.data,
                          ins_id=form.ins_id.data,
                          phone=form.phone.data,
                          dob=form.dob.data,
                          member_id=form.member_id.data,
                          ins_eff_date=form.ins_eff_date.data,
                          ins_term_date=form.ins_term_date.data,
                          allergies=form.allergies.data,
                          height=form.height.data,
                          weight=form.weight.data,
                          disease_states=form.disease_states.data,
                          address=form.address.data,
                          state=form.state.data,
                          city=form.city.data,
                          zip=form.zip.data,

                          client_id=user_logged)

        db.session.add(patient)
        db.session.commit()
        return redirect(url_for('patient.allpatients'))

    return render_template('patient/addpatient.html', form=form, allins=allins, patient=patient)

@patient.route('/allpatients', methods=['GET', 'POST'])
@login_required
def allpatients():
    page = request.args.get('page', 1, type=int)
    user_logged = current_user.client_id
    allpts = Patient.query.filter_by(client_id=user_logged).paginate(page=page, per_page=100)

    return render_template('patient/all_patients.html', allpts=allpts, user_logged=user_logged)

@patient.route('/printingthis', methods=['GET', 'POST'])
@login_required
def printing():
    allptsct = Patient.query.filter_by(client_id=current_user.client_id).count()
    # prior auth stats #
    allapproved = PriorAuth.query.filter_by(status='Approved', client_id=current_user.client_id).count()
    alldenied = PriorAuth.query.filter_by(status='Denied', client_id=current_user.client_id).count()
    allpending = PriorAuth.query.filter_by(status='Pending', client_id=current_user.client_id).count()
    page = request.args.get('page', 1, type=int)
    user_logged = current_user.client_id
    allpts = Patient.query.filter_by(client_id=user_logged).paginate(page=page, per_page=100)
    today = date.today().strftime("%m/%d/%Y")
    print_html = render_template('reports/test-print.html', allpts=allpts, user_logged=user_logged, page=page, today=today,
                                 allapproved=allapproved, alldenied=alldenied, allpending=allpending, allptsct=allptsct)

    # Convert the HTML to PDF, as target filename give 'False'
    pdf = pdfkit.from_string(print_html, False, configuration=config)

    # Convert the bytes to a file(like)
    file = io.BytesIO(pdf)

    filename = f"Patient Report.pdf"

    # Output to the browser
    return send_file(file,
                     attachment_filename=filename,
                     mimetype='application/pdf',
                     # Give this argument to let the user stay on the current page
                     as_attachment=True,
                     # Set a low cache timeout
                     cache_timeout=-1)

@patient.route('/printptpalist/<int:patient_id>', methods=['GET', 'POST'])
@login_required
def printing_pa_list(patient_id):
    patient_record = Patient.query.get_or_404(patient_id)
    pt_id = patient_record.id
    allptsct = Patient.query.filter_by(client_id=current_user.client_id).count()
    prior_auths = PriorAuth.query.filter_by(patient_id=pt_id).all()
    # prior auth stats #
    allpending = PriorAuth.query.filter_by(status='Pending', client_id=current_user.client_id, patient_id=pt_id).count()
    alldenied = PriorAuth.query.filter_by(status='Denied', client_id=current_user.client_id, patient_id=pt_id).count()
    allapproved = PriorAuth.query.filter_by(status='Approved', client_id=current_user.client_id,
                                            patient_id=pt_id).count()
    page = request.args.get('page', 1, type=int)
    user_logged = current_user.client_id
    allpts = Patient.query.filter_by(client_id=user_logged).paginate(page=page, per_page=100)
    today = date.today().strftime("%m/%d/%Y")

    print_html_pa = render_template('reports/pastatus.html', allpts=allpts, user_logged=user_logged, page=page,
                                    today=today,
                                    allapproved=allapproved, alldenied=alldenied, allpending=allpending,
                                    allptsct=allptsct, patient_record=patient_record
                                    , prior_auths=prior_auths, pt_id=pt_id)

    # Convert the HTML to PDF, as target filename give 'False'
    pdf = pdfkit.from_string(print_html_pa, False, configuration=config)

    # Convert the bytes to a file(like)
    file = io.BytesIO(pdf)

    filename = f"Patient Report.pdf"

    # Output to the browser
    return send_file(file,
                     attachment_filename=filename,
                     mimetype='application/pdf',
                     # Give this argument to let the user stay on the current page
                     as_attachment=True,
                     # Set a low cache timeout
                     cache_timeout=-1)

# view individual patient record ####
@patient.route('/patient/<int:patient_id>', methods=['GET', 'POST'])
@login_required
def viewpatient(patient_id):
    form_pa = AddPAFormPatient()
    patient_record = Patient.query.get_or_404(patient_id)
    user_logged = current_user.client_id  ### curent client id ###
    form = AddNotesPatient()  # quickly add a prior authorization while on a patients record #
    all_drugs = Drugs.query.order_by(Drugs.name.asc()).all() #pulls all drugs
    all_mapapp = MapApplication.query.filter_by(client_id=current_user.client_id,pt_id=patient_record.id).order_by(
        MapApplication.id.asc()).all()

    all_users = User.query.filter_by(client_id=user_logged).all()

    #pulls patient prescribers

    patient_md = PriorAuth.query.distinct().filter_by(client_id=current_user.client_id,patient_id=patient_record.id).all()

    # pull insurance name #
    ins_id = patient_record.ins_id

    insurance_name_pull = Insurance.query.filter_by(id=ins_id).first()

    insurance_name = insurance_name_pull

    # pull prior auth record #

    pt_id = patient_record.id

    prior_auths = PriorAuth.query.filter_by(patient_id=pt_id).all()

    doctors = Prescriber.query.filter_by(client_id=user_logged).all()

    doctors_counts = db.session.query(PriorAuth.prescriber_id, db.func.count()). \
        filter_by(patient_id=pt_id). \
        group_by(PriorAuth.prescriber_id). \
        order_by(PriorAuth.prescriber_id.desc()). \
        all()

    for md_name, count in doctors_counts:
        list_of_md = [md_name, count]

    md_names = Prescriber.query.filter_by(client_id=user_logged). \
        group_by(Prescriber.id). \
        order_by(Prescriber.id.desc()). \
        all()

    print(md_names, doctors_counts)

    allpending = PriorAuth.query.filter_by(status='Pending', client_id=current_user.client_id, patient_id=pt_id).count()

    alldenied = PriorAuth.query.filter_by(status='Denied', client_id=current_user.client_id, patient_id=pt_id).count()
    allapproved = PriorAuth.query.filter_by(status='Approved', client_id=current_user.client_id,
                                            patient_id=pt_id).count()

    # add notes ####
    if form.validate_on_submit():
        notes = Notes(body=form.body.data,
                      client_id=current_user.client_id,
                      created_by=current_user.username,
                      pt_id=pt_id,
                      ins_id=0,
                      md_id=0,
                      pa_id=0)

        db.session.add(notes)
        db.session.commit()
        return redirect(url_for('patient.viewpatient', patient_id=pt_id))

    # return notes into page in notes section ####

    notes_pt = Notes.query.filter_by(pt_id=pt_id).order_by(Notes.id.desc()).all()

    # add prior authorization for the patietn #
    ins_name = ''
    ins_named = ''
    if form_pa.validate_on_submit():
        ins_name = Insurance.query.filter_by(client_id=current_user.client_id, id=form_pa.insurance_id.data).first()
        ins_named = ins_name.name

        priorauth = PriorAuth(drug=form_pa.drug.data,
                              prescriber_id=form_pa.prescriber_id.data,
                              ins_id=form_pa.insurance_id.data,
                              ins_name=ins_named,
                              patient_id=form_pa.patient_id.data,
                              status=form_pa.status.data,
                              user_id=form_pa.user_id.data,
                              notes_init=form_pa.notes_init.data,
                              eff_date=form_pa.eff_date.data,
                              term_date=form_pa.term_date.data,
                              client_id=user_logged)

        db.session.add(priorauth)
        db.session.commit()
        return redirect(url_for('patient.viewpatient', patient_id=pt_id))
    # check to see if the patient has active coverage #
    today = date.today().strftime("%m/%d/%Y")

    current_term_date = patient_record.ins_term_date.strftime("%m/%d/%Y")
    current_eff_date = patient_record.ins_eff_date.strftime("%m/%d/%Y")

    if current_term_date < today or current_eff_date > today:
        status_coverage = 'fa fa-times'
        style = 'btn btn-danger'
        status_message = 'is not active.'
    else:
        status_coverage = 'fas fa-check'
        style = 'btn btn-success'
        status_message = 'is active.'
    # logic to notify user of expiring prior authorizations #

    auth_exp = patient_record.ins_term_date.strftime("%d")
    today_month = date.today().strftime("%d")
    testing = int(today_month) - int(auth_exp)
    if testing == 21:
        alert = 'PA is expiring in 3 weeks'
    elif testing == 14:
        alert = 'PA is expiring in 2 weeks'
    elif testing == 7:
        alert = 'PA is expiring in 1 week'

    else:
        alert = 'PA expired!'

    return render_template('patient/patient.html',
                           patient_record=patient_record, user_logged=user_logged, insurance_name=insurance_name,
                           insurance_name_pull=insurance_name_pull, prior_auths=prior_auths,
                           allpending=allpending, alldenied=alldenied, allapproved=allapproved, pt_id=pt_id, form=form,
                           notes_pt=notes_pt, form_pa=form_pa, all_users=all_users, ins_name=ins_name,
                           ins_named=ins_named, status_coverage=status_coverage, style=style, doctors=doctors,
                           doctors_counts=doctors_counts
                           , md_names=md_names, all_drugs=all_drugs, status_message=status_message,all_mapapp=all_mapapp,
                           patient_md=patient_md)

# view individual patient documents #
def allowed_file(filename):
    return '.' in filename and \
           filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

@patient.route('/patientdocs/<int:patient_id>', methods=['GET', 'POST'])
@login_required
def viewpatientdocs(patient_id):
    form = AddDocsPatient()
    patient_record = Patient.query.get_or_404(patient_id)
    user_logged = current_user.client_id  # current client id #

    pt_id = patient_record.id
    docs_module = Documents.query.filter_by(pt_id=pt_id).order_by(Documents.id.desc()).all()
    # pull prior auth record #
    # upload documents for patient, allowed file types: pdf only!!! #
    if request.method == 'POST':
        # check if the post request has the file part
        if 'file' not in request.files:
            flash('No file part')
            # return redirect(request.url)
        file = request.files['file']
        if file.filename == '':
            flash('No file selected for uploading')
            # return redirect(request.url)
        if file and allowed_file(file.filename):
            filename = secure_filename(file.filename)
            file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))

            # return redirect(request.url)
        else:
            flash('Allowed file types are txt, pdf, png, jpg, jpeg, gif')
    if form.validate_on_submit():
        # commit info to database #
        document = Documents(name=form.name.data,
                             created_by=current_user.username,
                             client_id=current_user.client_id,
                             doc_path='/static/user_uploads/patients/' + filename,
                             description=form.description.data,
                             pt_id=pt_id,
                             ins_id=0,
                             md_id=0,
                             pa_id=0,
                             public='Y')

        db.session.add(document)
        db.session.commit()

        return redirect(url_for('patient.viewpatientdocs', patient_id=pt_id))

    return render_template('documents/docs.html',
                           patient_record=patient_record, user_logged=user_logged, pt_id=pt_id, form=form,
                           docs_module=docs_module
                           )

@patient.route("/updatepatient/<int:patient_id>", methods=['GET', 'POST'])
@login_required
def update(patient_id):
    form = AddPatient()
    user_logged = current_user.client_id
    patient = Patient.query.get_or_404(patient_id)
    ### add insurance ###
    allins = Insurance.query.filter_by(client_id=user_logged)
    ### pulls related patient information ###

    insurance_name_pull = Insurance.query.filter_by(id=patient.ins_id).first()

    insurance_name = f"Current: {insurance_name_pull}"

    allpts = Patient.query.filter_by(client_id=user_logged).all()
    all_users = User.query.filter_by(client_id=user_logged).all()

    if form.validate_on_submit():

        ### insurance name ###

        ### commit form data ###
        patient.fname = form.fname.data
        patient.lname = form.lname.data
        patient.ins_id = form.ins_id.data
        patient.phone = form.phone.data
        patient.dob = form.dob.data
        patient.ins_eff_date = form.ins_eff_date.data
        patient.ins_term_date = form.ins_term_date.data
        patient.allergies = form.allergies.data
        patient.height = form.height.data
        patient.weight = form.weight.data
        patient.address = form.address.data
        patient.state = form.state.data
        patient.city = form.city.data
        patient.zip = form.zip.data
        patient.member_id = form.member_id.data

        db.session.commit()
        return redirect(url_for('patient.viewpatient', patient_id=patient.id))
    elif request.method == 'GET':
        form.fname.data = patient.fname
        form.lname.data = patient.lname
        form.ins_id.data = patient.ins_id
        form.phone.data = patient.phone
        form.dob.data = patient.dob
        form.ins_eff_date.data = patient.ins_eff_date
        form.ins_term_date.data = patient.ins_term_date
        form.allergies.data = patient.allergies
        form.height.data = patient.height
        form.weight.data = patient.weight
        form.address.data = patient.address
        form.state.data = patient.state
        form.city.data = patient.city
        form.zip.data = patient.zip
        form.member_id.data = patient.member_id

    return render_template('patient/addpatient.html', title='Update Patient',
                           form=form, allins=allins, all_users=all_users, patient=patient,
                           insurance_name=insurance_name)

@patient.route("/deletepatient/<int:patient_id>", methods=['POST'])
@login_required
def delete_patient(patient_id):
    patient_record = Patient.query.get_or_404(patient_id)
    db.session.delete(patient_record)
    db.session.commit()
    flash('Deleted!')

    return redirect(url_for('patient.allpatients'))


import sys, os
from pprint import pprint as print
from datetime import date
sys.path.insert(0, os.path.expanduser('~/Galaxy_Box_Integration/'))
from galaxy_api_class import gx_api

class controller:
    def __init__(self):
        self.gx = gx_api(production = False)

    def get_assignables(self):
        # get all assignable images (unsorted)
        today = date.today().strftime("%m/%d/%Y")
        end_date = today.split('/')
        end_date = str(int(end_date[0])+3)+"/"+end_date[1]+'/'+end_date[2]
        launch_date_range = f'{today}...{end_date}'
        params = {
            'query':[{
            'c_WA_Launch_Date_Earliest':launch_date_range,
            'RetouchStatus':'Ready for Revisions',
            'RetoucherName':'=',
            'omit': "false"
            }]
        }
        results = self.gx.find_records(params, layout = "Retoucher_DetailView")
        # abort if no data in the response
        if 'response' not in results or 'data' not in results['response']: return -1
        self.assignables = results['response']['data']

        # later, we'll determine how to assign them

traffic = controller()
traffic.get_assignables()


class BrowserHistory:

    def __init__(self, homepage: str):
        self.browser = [homepage]
        self.idx = 0

    def visit(self, url: str) -> None:
        self.browser.insert(self.idx+1,url)
        self.idx += 1
        self.browser = self.browser[:self.idx+1]

    def back(self, steps: int) -> str:
        if steps > self.idx:
            self.idx = 0
        else:
            self.idx -= steps
        return self.browser[self.idx]

    def forward(self, steps: int) -> str:
        if steps > (len(self.browser) - self.idx - 1):
            self.idx = len(self.browser)-1
        else:
            self.idx += steps
        return self.browser[self.idx]

# intuition:
# 1. A list can be used to store the history of the browser
# 2. A separate index variable can be used to keep track of the current page
# 3. The list can be truncated to the current page index + 1 when a new page is visited to remove the forward history
# 4. The index can be incremented or decremented based on the number of steps and the length of the list, keeping it within the bounds of the list

# solution
# 1. Create a list to store the history of the browser and assign it to the object
# 2. Create an index variable to keep track of the current page and assign it to the object. Initialize it to 0.
# 3. When a new page is visited, insert the new page at the index + 1 position in the list. Increment the index by 1.
# 4. Truncate the list to the index + 1 position to remove the forward history using the list slicing syntax.
# 5. When the back button is pressed, decrement the index by the number of steps. If the number of steps is greater than the index, set the index to 0. Else, set the index to the index - steps.
# 6. When the forward button is pressed, increment the index by the number of steps. If the number of steps is greater than the length of the list - index - 1, set the index to the length of the list - 1. Else, set the index to the index + steps.
# 7. Return the page at the index position in the list in both the back and forward functions.


from typing import List

class Solution:
    def findMinArrowShots(self, points: List[List[int]]) -> int:
        if points == []:
            return 0
        points.sort(key=lambda x:(x[1],x[0]), reverse=True)
        section = [0,0]
        section[0], section[1] = points[0][0]+1, points[0][1]-1
        #print(points)
        #res = []
        result = 0
        for each in points:
            #print(each,section)
            if not (section[0] <= each[0] <= section[1] or section[0] <= each[1] <= section[1]):
                #res.append(each)
                result += 1
                section = each
                continue
            if section[0] <= each[0] <= section[1]:
                section[0] = each[0]
            if section[0] <= each[1] <= section[1]:
                section[1] = each[1]
            #print(section,111)
        #print(res)
        return result

if __name__ == '__main__':
    points = [[10,16],[2,8],[1,6],[7,12]]
    print(Solution().findMinArrowShots(points))

###
###标准答案中给出不用判断左边界，因为每次都在判断左边界是否大于又边界
class Solution:
    def findMinArrowShots(self, points: List[List[int]]) -> int:
        if not points:
            return 0

        points.sort(key=lambda points: points[1])  # 以右边界Xend升序排列

        right_limit = points[0][1]

        n_arrow = 1

        for bolloon in points:
            if bolloon[0] > right_limit:  # 如果左边界大于了目前的最大的有边界，那么就不得不再射一只箭
                right_limit = bolloon[1]
                n_arrow += 1

        return n_arrow

452. 用最少数量的箭引爆气球.py


# encoding = utf-8

from future import standard_library
standard_library.install_aliases()
from builtins import str
import os
import sys
import time
import datetime
import json
from urllib.parse import urlencode
from urllib.request import urlopen
from urllib.request import Request
from urllib2 import urlparse
from urllib.request import build_opener
from urllib.request import ProxyHandler
from urllib.request import install_opener

'''
    IMPORTANT
    Edit only the validate_input and collect_events functions.
    Do not edit any other part in this file.
    This file is generated only once when creating the modular input.
'''
'''
# For advanced users, if you want to create single instance mod input, uncomment this method.
def use_single_instance_mode():
    return True
'''

# Copyright 2019 Jorrit Folmer
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
# of the Software, and to permit persons to whom the Software is furnished to do
# so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

def is_proxy(helper):
    """ Determine whether or not a proxy is configured """
    try:
        proxy = helper.get_proxy()
        proxies = {}
        if proxy.get('proxy_url', False):
            return True
        else:
            return False
    except Exception as e:
        return False

def get_proxies(helper):
    """ Return a proxy dict from proxy settings in addon """
    proxy = helper.get_proxy()
    proxies = {}
    if proxy.get('proxy_url', False):
        if(proxy["proxy_username"] and proxy["proxy_password"]):
            proxy_url = "%s://%s:%s@%s:%s" % (proxy["proxy_type"], proxy["proxy_username"], proxy["proxy_password"], proxy["proxy_url"], proxy["proxy_port"])
            proxies = {
                "http" : proxy_url,
                "https" : proxy_url
            }
        else:
            proxy_url = "%s://%s:%s" % (proxy["proxy_type"], proxy["proxy_url"], proxy["proxy_port"])
            proxies = {
                "http" : proxy_url,
                "https" : proxy_url
            }
    helper.log_debug("proxies dict is : {}".format(proxies))
    return proxies

def get_defender_connectivity(helper, api_endpoint):
    """ Check basic connectivity after saving new inputs in the addon """
    if is_proxy(helper):
        install_opener(build_opener(ProxyHandler(get_proxies(helper))))
    # Do request
    try:
        url = "https://login.windows.net/"
        req = Request(url)
        response = urlopen(req)
    except Exception as e:
        raise Exception("Error connecting to %s: %s" % (url, str(e)))
        exit(1)
    else:
        helper.log_info("Succesfully connected to %s" % url)

def get_defender_access_token(helper, client_id, secret, tenant_id):
    """ Returns an oauth2 access token string from login.windows.net
        given a client_id, secret and tenant_id """

    body = {
        'resource' : 'https://api.securitycenter.windows.com',
        'client_id' : client_id,
        'client_secret' : secret,
        'grant_type' : 'client_credentials'
    }

    # Prepare request
    try:
        url = "https://login.windows.net/%s/oauth2/token" % (tenant_id)
        data = urlencode(body).encode("utf-8")
    except Exception as e:
        raise Exception("Error encoding token request body for client_id %s: %s" % (client_id, str(e)))
        exit(1)
    else:
        helper.log_debug("Succesfully parsed token request prep for %s" % url)

    # Do request
    if is_proxy(helper):
        try:
            proxies = get_proxies(helper)
            install_opener(build_opener(ProxyHandler(proxies)))
        except Exception as e:
            raise Exception("Error setting proxy %s: %s" % (get_proxies(helper), str(e)))
            exit(1)
        else:
            helper.log_debug("Succesfully installed proxies %s" % proxies)
    try:
        helper.log_debug("Sending token request to %s" % url)
        req = Request(url, data)
        response = urlopen(req)
    except Exception as e:
        raise Exception("Error getting token for client_id %s from %s: %s" % (client_id, url, str(e)))
        exit(1)
    else:
        helper.log_info("Succesfully sent token request to %s" % url)
        # Parse request
        try:
            jsonResponse = json.loads(response.read())
            access_token = jsonResponse["access_token"]
        except Exception as e:
            raise Exception("Error parsing token response for client_id %s from %s: %s" % (client_id, url, str(e)))
            exit(1)
        else:
            helper.log_info("Succesfully parsed access_token for client_id %s from o %s" % (client_id, url))
            return access_token

def get_defender_query_results(helper, client_id, access_token, api_endpoint, query):
    headers = {
	'Content-Type' : 'application/json',
	'Accept' : 'application/json',
	'Authorization' : "Bearer " + access_token
    }

    # Prepare request
    try:
        url = "https://%s/api/advancedqueries/run" % api_endpoint
        data = json.dumps({ 'Query' : query }).encode("utf-8")
    except Exception as e:
        raise Exception("Error encoding query request body for client_id %s: %s" % (client_id, str(e)))
        exit(1)
    else:
        helper.log_debug("Succesfully parsed query request prep for %s" % url)

    # Do request
    if is_proxy(helper):
        try:
            proxies = get_proxies(helper)
            install_opener(build_opener(ProxyHandler(proxies)))
        except Exception as e:
            raise Exception("Error setting proxy %s: %s" % (get_proxies(helper), str(e)))
            exit(1)
        else:
            helper.log_debug("Succesfully installed proxies %s" % proxies)
    try:
        helper.log_debug("Sending query request to %s: %s \n %s\n" % (url, headers, data))
        req = Request(url, data, headers)
        response = urlopen(req)
    except Exception as e:
        # 1) Permission for AdvancedQuery.Read.All under WindowsDefenderATP should be granted
        #    under AAD -> App registrations -> WindowsDefenderATPThreatIntelAPI
        # 2) Grant permissions by admin should also be run because we can't ok this question panel through the API
        raise Exception("Error getting query results for client_id %s from %s: %s" % (client_id, url, str(e)))
        exit(1)
    else:
        helper.log_info("Succesfully sent query request to %s" % url)
        try:
            jsonResponse = json.loads(response.read())
            #schema = jsonResponse["Schema"]
            results = jsonResponse["Results"]
        except Exception as e:
            raise Exception("Error parsing query response for client_id %s from %s: %s" % (client_id, url, str(e)))
            exit(1)
        else:
            helper.log_debug("Succesfully parsed query results for client_id %s from o %s" % (client_id, url))
            return results

def validate_input(helper, definition):
    api_endpoint   = definition.parameters.get('api_endpoint', None)
    get_defender_connectivity(helper, api_endpoint)

def collect_events(helper, ew):
    global_account = helper.get_arg('client_id', None)
    client_id = global_account.get("username", None)
    secret = global_account.get("password", None)
    tenant_id = helper.get_arg('tenant_id', None)
    api_endpoint = helper.get_arg('api_endpoint', None)
    query = helper.get_arg('query', None)

    access_token = get_defender_access_token(helper, client_id, secret, tenant_id)
    results = get_defender_query_results(helper, client_id, access_token, api_endpoint, query)
    helper.log_info("Got %d results for client_id %s from %s" % (len(results), client_id, api_endpoint))
    for result in results:
        eventJson = json.dumps(result, indent=2, sort_keys=True)
        event = helper.new_event(eventJson, time=None, host=None, index=helper.get_output_index(),
                                 source=None, sourcetype=helper.get_sourcetype(),
                                 done=True, unbroken=True)
        ew.write_event(event)


import tensorflow as tf
import numpy as np

from models.gpt2 import gpt2

def top_k_logits(logits, k):
    if k == 0:
        # no truncation
        return logits

    def _top_k():
        values, _ = tf.nn.top_k(logits, k=k)
        min_values = values[:, -1, tf.newaxis]
        return tf.where(
            logits < min_values,
            tf.ones_like(logits, dtype=logits.dtype) * -1e10,
            logits,
        )
    return tf.cond(
        tf.equal(k, 0),
        lambda: logits,
        lambda: _top_k(),
    )

def make_sect_and_center(n_bins, overlap, span):
    section_length = (span[1] - span[0])/(n_bins - (n_bins - 1) * overlap)
    sections = [span[0] + i * (1 - overlap) * section_length for i in range(n_bins)]
    sections = [[i, i+section_length] for i in sections]
    centers = [(i+j)/2 for i,j in sections]
    sections[0][0] = -np.inf
    sections[-1][1] = np.inf
    return sections, centers

def sample_sequence(*, params, length, start_token=None, batch_size=None, context=None, temperature=1, gaussian_noise=0, top_k=0):
    n_bins = params['multibin_nbins']
    overlap = params['multibin_overlap']
    s_min = params['multibin_min']
    s_max = params['multibin_max']
    sections, centers = make_sect_and_center(
        n_bins=n_bins,
        overlap=overlap,
        span=(s_min, s_max))
    if start_token is None:
        assert context is not None, 'Specify exactly one of start_token and context!'
    else:
        assert context is None, 'Specify exactly one of start_token and context!'
        context = tf.fill([batch_size, 1], start_token)

    # length = length - params["text_len"]

    def step(params, tokens, past=None):
        if params["precision"] == 'bfloat16':
            with tf.contrib.tpu.bfloat16_scope():
                lm_output = gpt2.model(params=params, X=tokens, past=past, reuse=tf.AUTO_REUSE)

            lm_output["pred"] = tf.cast(lm_output["pred"], tf.float32)

        else:
            lm_output = gpt2.model(params=params, X=tokens, past=past, reuse=tf.AUTO_REUSE)

        pred = lm_output['pred']
        presents = lm_output['present']
        presents.set_shape(gpt2.past_shape(params=params, batch_size=batch_size))
        return {
            'pred': pred,
            'presents': presents,
        }

    with tf.name_scope('sample_sequence'):

        context_output = step(params, context[:, :-1])

        def body(past, prev, output):
            next_outputs = step(params, prev[:, tf.newaxis], past=past)
            pred = next_outputs['pred'][:, -1, :]
            logits = pred[:,:,:,0]
            resids = pred[:,:,:,1]
            logits = top_k_logits(logits, k=top_k) # batch_size x 85 x 21
            regressed = resids + tf.constant(centers)[None,None] # batch_size x 85 x 21
            sampled_bin = tf.multinomial(
                tf.reshape(logits, (-1, n_bins)), # (batch_size x 85) x 21
                num_samples=1,
                output_dtype=tf.int32) # (batch_size x 85) x 1
            sampled_bin = tf.reshape(sampled_bin, (-1, 85)) # batch_size x 85
            idxs = tf.reshape(sampled_bin, (-1,))
            idxs = tf.stack([tf.range(tf.size(idxs)), idxs], axis=-1)
            samples = tf.gather_nd(
                tf.reshape(regressed, (-1, n_bins)), # (batch_size x 85) x 21
                idxs) # (batch_size x 85)
            samples = tf.reshape(samples, (-1, 85))
            samples = samples + tf.random.normal(tf.shape(samples), stddev=gaussian_noise)
            past = tf.concat([past, next_outputs['presents']], axis=-2)
            prev = samples
            output = tf.concat([output, samples[:,None]], axis=1)
            return [past, samples, output,]

        def cond(*args):
            return True

        _, _, tokens = tf.while_loop(
            cond=cond, body=body,
            maximum_iterations=length,
            loop_vars=[
                context_output['presents'],
                context[:, -1],
                context,
            ],
            shape_invariants=[
                tf.TensorShape(gpt2.past_shape(params=params, batch_size=batch_size)),
                tf.TensorShape([None, 85]),
                tf.TensorShape([None, None, 85]),
            ],
            back_prop=False,
        )

        return tokens


import bluetooth
import Tkinter as tki
import threading

class TS:
    def __init__(self):
        """Creating the initial bluetooth connection and defining the char protocol"""
        print("Checking connection...")
        self.serverMACAddress = '20:15:10:12:39:01'
        self.port = 1
        self.s = bluetooth.BluetoothSocket(bluetooth.RFCOMM)
        self.s.connect((self.serverMACAddress, self.port))
        self.isConnected = True
        self.CW = ["A","B","C","D"]
        self.CCW = ["Z","Y","X","W"]
        self.speed = 0#Default at 25%
        #Maps speeds 0 to 3, 0 being 25%, 3 being 100%
        self.threads =[]

    def reconnect(self):
        """Handles the reconnection to the bluetooth module"""
        try:
            self.s.close()
        except Exception as e:
            print("Failed to close socket")
            print(e)
        self.s = bluetooth.BluetoothSocket(bluetooth.RFCOMM)
        self.s.connect((self.serverMACAddress, self.port))

    def _deco(func):
        """Decorator function that handles errors"""
        def blah(self,*arg):
            try:
                func(self,*arg)
            except IOError:
                print("Bluetooth Error, attempting reconnection")
                self.isConnected = False
                try:
                    self.reconnect()
                    self.isConnected = True
                    self.threads = []
                except IOError:
                    print("Reconnection failed, please get in range of the device")

        return blah

    @_deco
    def handshake(self):
        """Handshaking between the arduino to check the connection is valid"""
        print("No: "+str(len(self.threads)))
        indexes_to_del = []
        if len(self.threads)>2:
                    raise IOError
        for i in range(0,len(self.threads)):
            if not self.threads[i].is_alive():
                indexes_to_del.append(i)

        for i in indexes_to_del:#do this otherwise if deleted above, out of index error occurs
            del self.threads[i]

        while True:
            data =  self.s.recv(1024)
            if data =="O":
                print("Hanshake Received")
                return

    def closeConnection(self):
        """Closes the connection and kills the program"""
        print("closing connection...")
        self.s.close()
        quit()

    def change_Focus(self, rate):
        """Changes the speed of the focuser"""
        self.speed = int(rate)
        print("Setting Focus Rate to: " + str(rate))

    @_deco
    def focus_Halt(self,e):
        """sends the H command to the arduino, halting the focuser, additionally has handshake verification"""
        if self.isConnected:
            a = threading.Thread(target=self.handshake)
            self.threads.append(a)
            a.start()
        print("\nHalting focuser\n")
        self.s.send("H")

    @_deco
    def focus_Left(self,e):
        print("sending "+self.CCW[self.speed])
        self.s.send(self.CCW[self.speed])

    @_deco
    def focus_Right(self,e):
        print("sending "+self.CW[self.speed])
        self.s.send(self.CW[self.speed])

class App(TS):

    WINDOW_TITLE = "Telescope Control Software"
    WINDOW_WIDTH = 300
    WINDOW_HEIGHT = 300
    SLEW_OPTIONS = ["0","1","2","3"]

    def __init__(self,root_win,ts):
        """Setting up the frames and windows"""
        self.ts = ts

        root_win.title(self.WINDOW_TITLE)
        root_win.minsize(self.WINDOW_WIDTH,self.WINDOW_HEIGHT)
        #root_win.protocol("WM_DELETE_WINDOW", self.ts.closeConnection)

        self.control = tki.Frame(root_win)
        self.controlFrame()
        self.control.config(height=self.WINDOW_HEIGHT,width=600,borderwidth=2,relief="groove")
        self.control.grid(row=0,column =1,sticky="N")

        self.checkConnection()

    def controlFrame(self):
        """Widgets for Telescope Control Frame"""

        #Focus Buttons
        focusVar = tki.StringVar(self.control)
        slewRevOpt = list(self.SLEW_OPTIONS)

        focus_OptionMenu = tki.OptionMenu(self.control,focusVar,*self.SLEW_OPTIONS,command= lambda x: self.ts.change_Focus(slewRevOpt.index(focusVar.get())))
        self.left_button = tki.Button(self.control,text="<")
        self.right_button = tki.Button(self.control, text=">")

        self.left_button.bind('<ButtonPress-1>',self.ts.focus_Left)
        self.left_button.bind('<ButtonRelease-1>',self.ts.focus_Halt)
        self.right_button.bind('<ButtonPress-1>',self.ts.focus_Right)
        self.right_button.bind('<ButtonRelease-1>',self.ts.focus_Halt)

        #Labels and placement
        tki.Label(self.control,text="Telescope Control").grid(column=0, row=0,columnspan=4,ipadx=50)
        tki.Label(self.control, text="Focus Control").grid(column=0,columnspan=4,row=4)
        tki.Label(self.control,text="Focus Speed").grid(column=0,columnspan=2,row=5)

        focus_OptionMenu.grid(column=2,columnspan=2,row=5)

        self.left_button.grid(column=0,columnspan=2,row=6)
        self.right_button.grid(column=2,columnspan=2,row=6)

    def checkConnection(self):
        """Handle GUI depending on connection status"""
        if self.ts.isConnected:
            self.left_button.config(state = 'normal')
            self.right_button.config(state = "normal")
        else:
            self.left_button.config(state = 'disabled')
            self.right_button.config(state = 'disabled')

        self.left_button.update()
        self.right_button.update()

        root.after(100,self.checkConnection)

if __name__ =="__main__":
    root = tki.Tk()
    app = App(root,TS())
    root.mainloop()
#note checkConnection will re enable the buttons when the reconnect function deletes all the threads, need to deal with the reconnect function thread handling and reconnection.


from os import path
import sys, json, time
import torch
import numpy as np
from model import Net
from dataset import NodeDataset

# Get Directory
BASE_DIR = path.dirname(path.dirname(path.abspath(__file__)))

# Read input data
print('Reading Weights into network')

# Model Build output
model_path=path.join(BASE_DIR, 'data/model_build_outputs/mlp_state_dict.pt')

net = Net()
net.load_state_dict(torch.load(model_path))

print('Reading new dataset')
test_routes_path = path.join(BASE_DIR, 'data/model_apply_inputs/new_route_data.json')
test_travel_path = path.join(BASE_DIR, 'data/model_apply_inputs/new_travel_times.json')
test_pacakge_path = path.join(BASE_DIR, 'data/model_apply_inputs/new_package_data.json')

dataset = NodeDataset(test_pacakge_path, test_travel_path, test_routes_path, train=False)

routes = {route_id: {'proposed': {}} for route_id in data_set.route_ids}

def route_sequencer(start_node, travel_time, start_time, end_time, volume, service):
    #Parameters
    available_nodes = set(range(travel_time.shape[0]))
    visited_nodes = set([])
    sequence = []
    visited_nodes.add(start_node)
    sequence.append(start_node)
    current = start_node

    #Initial state
    d = distance[start_node, :].view(-1,1)

    x = torch.cat([d, service, volume, start_time, end_time], dim=1)

    for i in range(travel_time.shape[0]):
        if len(visited_nodes) == travel_time.shape[0]:
            break

        idx = list(available_nodes-visited_nodes)
        evals = net(x[idx,:]).view(1,-1)
        selected_node = idx[torch.argmax(evals)]

        visited_nodes.add(selected_node)
        sequence.append(selected_node)
        current = selected_node

        #Create new x
        d = distance[current, :].view(-1,1)
        volume[selected_node] = 0
        service[selected_node] = 0
        x = torch.cat([d, service, volume, start_time, end_time], dim=1)

    return sequence

for route_id in tqdm(data_set.route_ids, total=len(data_set.route_ids)):
    keys = np.array(list(data_set.routes[route_id]['stops'].keys()))
    distance = data_set.distance_matrix(route_id)
    ser, vol, st, et = data_set.parse_packages(route_id)
    start_node = data_set.get_start_node(route_id)
    ser, vol, st, et = ser.view(-1,1), vol.view(-1,1), st.view(-1,1), et.view(-1,1)

    sequence = route_sequencer(start_node, distance, st, et, vol, ser)

    for i, stop in enumerate(keys[sequence]):
        routes[route_id]['proposed'][stop] = i

# Write output data
output_path = path.join(BASE_DIR, 'data/model_apply_outputs/proposed_sequences.json')

with open(output_path, 'w') as out_file:
    json.dump(routes, out_file)
    print("Success: The '{}' file has been saved".format(output_path))

print('Done!')


import torch
import torch.nn as nn

class DSCNN(torch.nn.Module):
    def __init__(self, input_shape=(1, 49, 10)):
        self.input_shape = input_shape
        super().__init__()

        # Model layers

        # Input pure conv2d
        self.inputlayer = nn.Conv2d(
            in_channels=1, out_channels=64, kernel_size=(10, 4), stride=(2, 2), padding=(5, 1))
        self.bn = nn.BatchNorm2d(64, momentum=0.99)
        self.relu = nn.ReLU()
        self.dropout1 = nn.Dropout(p=0.2)

        # First layer of separable depthwise conv2d
        # Separable consists of depthwise conv2d followed by conv2d with 1x1 kernels
        self.depthwise1 = nn.Conv2d(
            in_channels=64, out_channels=64, kernel_size=3, padding=1, groups=64)
        self.pointwise1 = nn.Conv2d(
            in_channels=64, out_channels=64, kernel_size=1, stride=1, padding=0)
        self.bn11 = nn.BatchNorm2d(64, momentum=0.99)
        self.relu11 = nn.ReLU()
        self.conv1 = nn.Conv2d(
            in_channels=64, out_channels=64, kernel_size=1, stride=1, padding=0)
        self.bn12 = nn.BatchNorm2d(64, momentum=0.99)
        self.relu12 = nn.ReLU()

        # Second layer of separable depthwise conv2d
        self.depthwise2 = nn.Conv2d(
            in_channels=64, out_channels=64, kernel_size=3, padding=1, groups=64)
        self.pointwise2 = nn.Conv2d(
            in_channels=64, out_channels=64, kernel_size=1, stride=1, padding=0)
        self.bn21 = nn.BatchNorm2d(64, momentum=0.99)
        self.relu21 = nn.ReLU()
        self.conv2 = nn.Conv2d(
            in_channels=64, out_channels=64, kernel_size=1, stride=1, padding=0)
        self.bn22 = nn.BatchNorm2d(64, momentum=0.99)
        self.relu22 = nn.ReLU()

        # Third layer of separable depthwise conv2d
        self.depthwise3 = nn.Conv2d(
            in_channels=64, out_channels=64, kernel_size=3, padding=1, groups=64)
        self.pointwise3 = nn.Conv2d(
            in_channels=64, out_channels=64, kernel_size=1, stride=1, padding=0)
        self.bn31 = nn.BatchNorm2d(64, momentum=0.99)
        self.relu31 = nn.ReLU()
        self.conv3 = nn.Conv2d(
            in_channels=64, out_channels=64, kernel_size=1, stride=1, padding=0)
        self.bn32 = nn.BatchNorm2d(64, momentum=0.99)
        self.relu32 = nn.ReLU()

        # Fourth layer of separable depthwise conv2d
        self.depthwise4 = nn.Conv2d(
            in_channels=64, out_channels=64, kernel_size=3, padding=1, groups=64)
        self.pointwise4 = nn.Conv2d(
            in_channels=64, out_channels=64, kernel_size=1, stride=1, padding=0)
        self.bn41 = nn.BatchNorm2d(64, momentum=0.99)
        self.relu41 = nn.ReLU()
        self.conv4 = nn.Conv2d(
            in_channels=64, out_channels=64, kernel_size=1, stride=1, padding=0)
        self.bn42 = nn.BatchNorm2d(64, momentum=0.99)
        self.relu42 = nn.ReLU()

        self.dropout2 = nn.Dropout(p=0.4)
        self.avgpool = torch.nn.AvgPool2d((25, 5))
        self.out = nn.Linear(64, 12)

    def forward(self, input):

        # Input pure conv2d
        x = self.inputlayer(input)
        x = self.dropout1(self.relu(self.bn(x)))

        # First layer of separable depthwise conv2d
        x = self.depthwise1(x)
        x = self.pointwise1(x)
        x = self.relu11(self.bn11(x))
        x = self.conv1(x)
        x = self.relu12(self.bn12(x))

        # Second layer of separable depthwise conv2d
        x = self.depthwise2(x)
        x = self.pointwise2(x)
        x = self.relu21(self.bn21(x))
        x = self.conv2(x)
        x = self.relu22(self.bn22(x))

        # Third layer of separable depthwise conv2d
        x = self.depthwise3(x)
        x = self.pointwise3(x)
        x = self.relu31(self.bn31(x))
        x = self.conv3(x)
        x = self.relu32(self.bn32(x))

        # Fourth layer of separable depthwise conv2d
        x = self.depthwise4(x)
        x = self.pointwise4(x)
        x = self.relu41(self.bn41(x))
        x = self.conv4(x)
        x = self.relu42(self.bn42(x))

        x = self.dropout2(x)
        x = self.avgpool(x)
        # x = torch.squeeze(x)
        x = x.flatten(1)
        x = self.out(x)

        return x


import sys
input = sys.stdin.readline

# 회원수
n = int(input())

# 회원리스트
member = []
for i in range(n):
    age, name = input().split()
    member.append((int(age), i, name))

member.sort()
for i in range(n):
    print(member[i][0], member[i][2])

'''
# 나이순 정렬
https://www.acmicpc.net/problem/10814

온라인 저지에 가입한 사람들의 나이와 이름이 가입한 순서대로 주어진다.
이때, 회원들을 나이가 증가하는 순으로, 나이가 같으면 먼저 가입한 사람이 앞에 오는 순서로 정렬

-> 오랜만에 혼자 금방 풀어낸 쉬운 문제였다.

[문제점 정리]
1) 처음에 위의 코드에서 member.append((int(age), name))로 해서 sort를 진행했다.
그랬더니 age로 먼저 정렬된 후 name으로도 정렬이 되어서, 문제와 다르게
나이가 같으면 먼저 가입한 사람이 앞에 오는 순서로 정렬이 되지 않았다.
-> 때문에 중간에 가입 순서를 집어 넣어주어 해결했다.

2) sort의 특성과 sort에 lambda를 사용하는 것의 차이가 갑자기 궁금해져 추가로 코드로 실행해보았다.
-> 아래의 코드를 참고해보면 알 수 있듯이,
sort에 key로 설정해준 값인 age로만 정렬을 진행하고, 뒤의 name으로는 정렬을 진행하지 않기 때문에 문제의 조건에 바로 만족시킬 수 있다.
'''
'''
# 회원리스트
member = []
for i in range(n):
    age, name = input().split()
    member.append((int(age), name))

member.sort(key=lambda member:member[0])
for age, name in member:
    print(age, name)
'''


# -*- coding: utf-8 -*-
"""
Created on Tue Jan  8 10:18:42 2019

@author: Administrator
"""
# Begin: Python 2/3 compatibility header small
# Get Python 3 functionality:
from __future__ import\
    absolute_import, print_function, division, unicode_literals
# End: Python 2/3 compatability header small

import tensorflow as tf
import argparse
import imp
import os
import pickle
from MyDataDealer import CrossData,Data

AbaloneData = imp.load_source('Abalone','../Data.py')

parser = argparse.ArgumentParser(description="show some parse for the progess")
parser.add_argument("--DataDir",type=str,default="../uci_data_set/Ecoli.mat",help="the mat data file path")
parser.add_argument("--train_epoch",type=int,default=50,help="number of training epochs")
parser.add_argument("--model_save_name",type=str,default="Abalone.ckpt",help="the file name for model to save")
parser.add_argument("--model_save_dir",type=str,default=None,help="the dir for model to save")
parser.add_argument("--lr", type=float, default=0.001, help="initial learning rate for adam")
parser.add_argument("--batch_size", type=int, default=100, help="number of images in batch")
parser.add_argument("--use_gpu", default=1, type=int, choices=[0,1], help="Whether to use GPU")
parser.add_argument("--nb_item",default=0,choices=[0,1,2,3,4], help="crosssplit data ,it select which group to use")
parser.add_argument("--reload_data", default=True, help="Whether to reload data")
parser.add_argument("-cpdr","--create_partial_data_rate", type=float,default=0.5, help="how much date transpose to partial data ,the value is (0,1)")
parser.add_argument("-npt","--nb_partial_target", type=int, default=1, choices=[1,2,3], help="number of partial target without count the true target")
parse = parser.parse_args()

if parse.use_gpu:
    os.environ["CUDA_VISIBLE_DEVICES"] = "1"
else:
    os.environ["CUDA_VISIBLE_DEVICES"] = ""

#Abalone_data = AbaloneData.UCIData(parse.DataDir)
#X,Y,partial_Y = Abalone_data.createPartialData()
#X = Data.guiYiHua(Abalone_data.data)
#item_data = CrossData(X)
#item_data.cross_split()
#
#l=[]
#for i in range(parse.train_epoch):
#    ind = item_data.next_batch(parse.batch_size,parse.nb_item)
#    print(type(ind),len(ind))
#    l.append(ind)

#createVar = globals()
#for i in range(5):
#    createVar["g"+str(i)] = tf.Graph()
#    print(type(createVar["g"+str(i)]))
#    with exec("g{}.as_default()".format(i)):
#        with tf.variable_scope("Graph{}".format(i)):
#            createVar["xs_g"+str(i)] = tf.placeholder(tf.float32, [None, 7])
#            createVar["ys_g"+str(i)] = tf.placeholder(tf.float32, [None, 29])
#if parse.use_gpu:
#    print(parse.use_gpu)
print(parse.nb_partial_target)


import torch
from torchsummary import summary
from torch.utils.data import Dataset,DataLoader
import torch.nn as nn
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MinMaxScaler

from dataset import load_prepare, boxplot, normalize, split_window, DatasetSales

from Model import ConvNet, train_fn, test_fn

# Time Series Prediction

# Clemence Vast - 2020
# Objectives

# We want to predict the next month for items and shops

#     load and clean data
#     visualize different data representations
#     select interesting data
#     build a CNN
#     train one or multiple items-shop series in the CNN
#     evaluate the CNN and analyze results

# general values
path_csv= "./sales_train.csv"
window = 12 # number of months in the sliding window

# training values
learning_rate = 0.001
epochs = 200

# evaluation values
prediction = []
batch_size = 2
iterations =  int(inputs.shape[0]/2)

def main():
    ## Load DataFrame and visualize info
    train_csv = load_prepare(path_csv)
    print(train_csv.head(10))
    print(train_csv.info())
    print(train_csv.shape)

    # Preparing and cleaning data
    ## let's remove negative values for sales
    train_csv.query('item_price > 0', inplace=True)
    print(train_csv.shape)

    # We want to check if there are some rare exceptions in the values and filter them
    # Box plot
    boxplot(train_csv, "Boxplot of sales")

    # We see that values tend to be under 1000 except 2 values.
    # To clean a little bit our dataset we're going to remove those values.
    train_csv.query('item_cnt_day < 1000', inplace=True)

    # group items by date blocks
    df_date = pd.DataFrame(train_csv.groupby(["date_block_num", "shop_id", "item_id", "item_price"], as_index=False)['item_cnt_day'].sum())
    print(df_date.head(5))

    # Visualize by Month

    plt.plot( "date_block_num", "item_cnt_day", data = df_date.sort_values(by="date_block_num"))

    plt.xticks(rotation=90)

    plt.show()

    #Normalizing

    train_csv["item_csv_day_norm"] = normalize(train_csv["item_cnt_day"])

    print(train_csv)

    # Cleaning
    # Let's check the data and filter when we see unuseful values
    train_csv = train_csv.groupby(['date_block_num',"shop_id", "item_id"]).agg({"item_cnt_day_norm":"count"}, as_index=False)
    print(train_csv)

    ## We could group all values together, by date block

    train_grouped = train_csv.sort_values('date_block_num').groupby(['date_block_num'], as_index=True)
    train_grouped = train_grouped.agg({'item_cnt_day_norm':"mean"})
    train_grouped.rename(columns={"item_cnt_day_norm":"sales_norm"}, inplace=True)
    print(train_grouped.head())

    ## Split values between train and test
    test_proportion = 0.4
    train, test = train_test_split(train_grouped, test_size=test_proportion)

    print('Train proportion : {:.0f}%'.format((1-test_proportion)*100))
    print('Validation proportion : {:.0f}%'.format(test_proportion*100))

    train_x,train_y = split_window(train.sales_norm.values,window)
    valid_x,valid_y = split_window(test.sales_norm.values,window)

    ## preparing Train
    device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
    cnn = ConvNet().to(device)
    optimizer = torch.optim.Adam(cnn.parameters(), lr=learning_rate)
    criterion = nn.MSELoss()

    # Torch summary gives a small summary of the Neural Network with the input size

    print(summary(cnn,[12,1]))

    ## Create sets and Data Loaders

    trainset = DatasetSales(train_x.reshape(train_x.shape[0],train_x.shape[1],1),train_y)
    validset = DatasetSales(valid_x.reshape(valid_x.shape[0],valid_x.shape[1],1),valid_y)
    trainloader = torch.utils.data.DataLoader(trainset,batch_size=2,shuffle=False)
    validationloader = torch.utils.data.DataLoader(trainset,batch_size=2,shuffle=False)

    dataset_loaders = {"train": trainloader, "test": validationloader}

    # Train model
    train_losses = []
    valid_losses = []

    for epoch in range(epochs):
        print('\nEpochs {}/{}'.format(epoch+1,epochs))
        train_fn()
        test_fn()
    # Evaluation of the model

    # We want to print the Loss for both training and validation, to check if the
    # model learned correctly from the features and detect overfitting.

    plt.plot(train_losses,label='Loss train')
    plt.plot(valid_losses,label='Loss validation')
    plt.title('MSE Loss graph')
    plt.legend(bbox_to_anchor=(1.05, 1), loc= 'center left', borderaxespad=0.)
    plt.show()

    targetX , targetY = split_window(train.sales_norm.values,window)
    inputs = targetX.reshape(targetX.shape[0],targetX.shape[1],1)

    cnn.eval()

    for i in range(iterations):
        preds = cnn(torch.tensor(inputs[batch_size*i:batch_size*(i+1)]).float())
        prediction.append(preds.detach().numpy())

    fig, ax = plt.subplots(1, 2,figsize=(11,4))
    ax[0].set_title('Prediction')
    ax[0].plot(prediction)
    ax[1].set_title('Reality')
    ax[1].plot(targetY)
    plt.show()

# Analysis

# Of course my model is not really representing the reality and is not complete, I would normally need to create a model by item-shop duo and then connect them all together for example. To work with a bigger dataset and add additional values I could also use a k-fold technique. Maybe convolutional layers are also not the best way to predict this kind of information. Overall, the Loss looks good but I'm not sure it would with a different dataset of values.

# If I had more time here's what I wouldve done:

#     Build a model for each item-shop duo
#     Connect them all with a fully connected layer
#     Build a model by shop (for all items)
#     Build a model by item (for all shops)

# I could've compare all those models and select my favorite one or analyse them too.