# Data
import numpy as np

# Intelligence
from sklearn.cluster import KMeans, DBSCAN
from sklearn import metrics
import hdbscan

# Visualization
# import matplotlib.pyplot as plt

# System
import datetime
import os
import time
import sys
import importlib as imp
import random as rand
import shutil

sys.dont_write_bytecode = True

now = datetime.datetime.now()
dateTime = str(now.strftime("%Y-%m-%d  %H:%M:%S"))
datetime_dir = str(now.strftime("%Y-%m-%d__%H-%M-%S"))

# Directory will be determined by the user
current_directory = ""

# CLUSTERING INTERFACE
class ClusteringSession(object):
    def run(self, params, threads):
        raise NotImplementedError
    def save_results(self, location):
        raise NotImplementedError
    def save_plots(self, location):
        raise NotImplementedError

# KMEANS
class KMeansSession(ClusteringSession):
    def __init__(self):
        self.n_clusters = 0
        self.data = None
        self.kmeans = None
        self.cluster_centers = None
        self.lables = None
        self.silhouette_score = -1
        self.n_init = 0
        self.n_jobs = 0

    def run(self, data, params, threads):
        self.data = data
        self.n_clusters = int(params['nclusters'])

        kmeans = KMeans(n_clusters=self.n_clusters)
        self.kmeans = kmeans

        kmeans.fit(data)
        self.cluster_centers = kmeans.cluster_centers_
        self.labels = kmeans.labels_

        sample_size = 0
        if len(data) >= 20000:
            sample_size = 20000
        else:
            sample_size = len(data)
        self.silhouette_score = metrics.silhouette_score(data, self.labels, metric='euclidean', sample_size=sample_size)

        return {'sil_score': self.silhouette_score,
                'labels': self.labels.tolist(),
                'n_clusters': self.n_clusters}

# DBSCAN
class DBSCANSession(ClusteringSession):
    def __init__(self):
        self.labels = []
        self.n_clusters = 0
        self.eps = 0
        self.min_samples = 0
        self.silhouette_score = 0
        self.data = None
        self.core_samples_mask = None

    def run(self, data, params, threads):
        self.eps = float(params['eps'])
        self.min_samples = int(params['min'])
        self.data = data
        db = DBSCAN(eps=self.eps, min_samples=self.min_samples).fit(data)

        # Used for plotting
        self.core_samples_mask = np.zeros_like(db.labels_, dtype=bool)
        self.core_samples_mask[db.core_sample_indices_] = True

        self.labels = db.labels_
        self.n_clusters = len(set(self.labels)) - (1 if -1 in self.labels else 0)

        sample_size = 0
        if len(data) >= 20000:
            sample_size = 20000
        else:
            sample_size = len(data)
        self.silhouette_score = metrics.silhouette_score(data, self.labels, metric='euclidean', sample_size=sample_size)

        return {'sil_score': self.silhouette_score,
                'labels': self.labels.tolist(),
                'n_clusters': self.n_clusters}

# HDBSCAN
class HDBSCANSession(ClusteringSession):
    def __init__(self):
        self.labels = []
        self.min_samples = 0
        self.silhouette_score = 0
        self.data = None
        self.n_clusters = 0
        #self.core_samples_mask = None

    def run(self, data, params, threads):
        self.min_samples = int(params['min'])
        self.data = data

        hdb = hdbscan.HDBSCAN(min_samples=self.min_samples, core_dist_n_jobs=threads)
        # print(hdb)
        self.labels = hdb.fit_predict(data)
        self.n_clusters = len(set(self.labels)) - 1

        sample_size = 0
        if len(data) >= 20000:
            sample_size = 20000
        else:
            sample_size = len(data)
        self.silhouette_score = metrics.silhouette_score(data, self.labels, metric='euclidean', sample_size=sample_size)

        del hdb

        return {'sil_score': self.silhouette_score,
                'n_clusters': self.n_clusters}

    def save_results(self, location):
        return super().save_results(location)

    def save_plots(self, location=""):
        current_directory = location + "RESULTS/HDBSCAN/" + datetime_dir
        print(current_directory)
        os.makedirs(current_directory)

# CLUSTER SESSION DICT
SESSION_MAP = {
    'kmeans': KMeansSession,
    'hdbscan': HDBSCANSession,
    'dbscan': DBSCANSession
}

PARAMS_MAP = {
    'kmeans': ['nclusters'],
    'hdbscan': ['min'],
    'dbscan': ['min', 'eps']
}


"""
Hillenbrand, Sean
Moynihan, Chase
Tran, Kenny
Wulwick, Sean
CPSC 452
Project 1
"""

#Row Transportation Cipher

import string
class Row_Transposition:
  #Set Key Function
  def setKey(self, key):
    if key.isalpha():
        return False
    self.key = key
    return True
  #Encrypt Function
  def encrypt(self, plaintext):
    encode = []
    row_number = len(plaintext) % len(str(self.key))
    plaintext = plaintext[:-1]
    while row_number != 0:  # while loop adds filler character 'x' in order to fill out the rows evenly
        plaintext += 'x'
        row_number = len(plaintext) % len(str(self.key))  # if there are any remainders that means the row is not full
    row_number = int(len(plaintext) / len(str(self.key)))
    for key_len_it in range(row_number):
        encode.append([])
        for plaintext_it, i in zip(plaintext, str(self.key)):
            encode[key_len_it].append(plaintext_it)  # appends into encode 1 by 1 the zip of plaintext and key
        plaintext = plaintext[len(str(self.key)):]  # sets plaintext to all characters after length of key
    ciphertext = ''
    for key_it in str(self.key):
        for col_it in range(row_number):
            ciphertext += encode[col_it][int(key_it)-1]  # ciphertext is made by ordering the columns based on the key
    return ciphertext + '\n'
  #Decrypt Function
  def decrypt(self, ciphertext):
    decode = []
    row_number = int(len(ciphertext) / len(str(self.key)))
    for i in range(row_number):
        decode.append([])
        for j in range(len(str(self.key))):
            decode[i].append([])  # decode is empty with no elements in it yet
    for key_it in str(self.key):
        for ciphertext_it, i in zip(ciphertext, range(row_number)):
            decode[i][int(key_it)-1] = ciphertext_it  # the ciphertext ordered in decode based on the key
        ciphertext = ciphertext[row_number:]
    # joined to to make decrypted text
    return ''.join(''.join(letter for letter in sub) for sub in decode) + '\n'


from enum import Enum
from typing import List, Optional, Union

class EOProductLevel(str, Enum):
    L1C = "l1c"
    L2A = "l2a"
    L3A = "l3a"
    RTC = "rtc"

class STACBand(str, Enum):
    BLUE = "blue"
    GREEN = "green"
    RED = ("red",)
    REDEDGE1 = "rededge1"
    REDEDGE2 = "rededge2"
    REDEDGE3 = "rededge3"
    NIR = "nir"
    NIR08 = "nir08"
    NIR09 = "nir09"
    CIRRUS = "cirrus"
    SCL = "scl"
    SWIR16 = "swir16"
    SWIR22 = "swir22"
    VV = "vv"
    VH = "vh"

    def __str__(self):
        return self.value

class EOProductSource(str, Enum):
    SENTINEL2 = "sentinel-2"
    SENTINEL1 = "sentinel-1"
    VENUS = "venus"

class EOProductType(str, Enum):

    DTYPE: Optional[str]
    RESOLUTION: Optional[int]
    FILL_VALUE: Optional[Union[int, float]]
    DEFAULT_ASSETS: Optional[List[str]]
    RGB: Optional[List[str]]

    def __new__(
        cls,
        type: str,
        dtype: Optional[str] = None,
        resolution: Optional[int] = None,
        fill_value: Optional[Union[int, float]] = None,
        default_assets: Optional[List[str]] = [],
        rgb_names: Optional[List[str]] = [],
    ):
        obj = str.__new__(cls, type)  # type: ignore
        obj._value_ = type
        obj.DTYPE = dtype
        obj.RESOLUTION = resolution
        obj.FILL_VALUE = fill_value
        obj.DEFAULT_ASSETS = default_assets
        obj.RGB = rgb_names

        return obj

    SENTINEL2_L2A = (
        f"{EOProductSource.SENTINEL2}-{EOProductLevel.L2A}",
        "uint16",
        10,
        0,
        [
            STACBand.BLUE,
            STACBand.GREEN,
            STACBand.RED,
            STACBand.REDEDGE1,
            STACBand.REDEDGE2,
            STACBand.REDEDGE3,
            STACBand.NIR,
            STACBand.NIR08,
            STACBand.NIR09,
            STACBand.CIRRUS,
            STACBand.SCL,
            STACBand.SWIR16,
            STACBand.SWIR22,
        ],
        [
            STACBand.BLUE,
            STACBand.GREEN,
            STACBand.RED,
        ],
    )
    VENUS_L2A = (
        f"{EOProductSource.VENUS}-{EOProductLevel.L2A}",
        "float32",
        5,
        0,
        [
            "image_file_SRE_B3",
            "image_file_SRE_B4",
            "image_file_SRE_B7",
            "image_file_SRE_B8",
            "image_file_SRE_B9",
            "image_file_SRE_B10",
        ],
        [
            "image_file_SRE_B3",
            "image_file_SRE_B4",
            "image_file_SRE_B7",
        ],
    )

    def __str__(self):
        return self.value

    @property
    def source(self):
        return EOProductSource(str(self.value).rsplit("-", 1)[0])

    @property
    def level(self):
        return EOProductLevel(str(self.value).rsplit("-", 1)[1])

class SCLMaskLabel:
    # Note: This is for Sentinel2 L2A only
    NO_DATA = 0
    SATURED_OR_DEFECTED = 1
    DARK_AREA_PIXELS = 2
    CLOUD_SHADOWS = 3
    VEGETATION = 4
    NOT_VEGETATED = 5
    WATER = 6
    UNCLASSIIFED = 7
    CLOUD_MEDIUM_PROBABILITY = 8
    CLOUD_HIGH_PROBABILITY = 9
    THIN_CIRRUS = 10
    SNOW = 11


import csv
import json
import ast
import codecs
from zipfile import ZipFile
import os

dirpath = os.getcwd()

def fct():

  # Duplicated or no files?
  count = len([name for name in os.listdir(dirpath+'/script/dataSource') if name.endswith(".zip") and "_LinkedInDataExport_" in name])
  if count == 0:
     print ("No LinkedIn Data")
  elif count > 1:
     print ("Duplicated LinkedIn File")
  else:
    # Get the file, unzip and fix it
    for r, d, f in os.walk(dirpath+"/script/dataSource"):
      for file in f:
        #if file.endswith(".zip") and file.startswith("Basic_LinkedInDataExport_"):
        if file.endswith(".zip") and "_LinkedInDataExport_" in file:
          inputFolderZipped = os.path.join(r,file)

          inputFolder = dirpath+'/script/dataSource/LinkedIn_data'
          if not os.path.exists(inputFolder):
             os.mkdir(inputFolder)

          #with zipfile.ZipFile(inputFolderZipped, 'r') as zip_ref:
          #   zip_ref.extractall(inputFolder)

          print ("LinkedIn - Unzip ")

          # Create a ZipFile Object and load sample.zip in it
          with ZipFile(inputFolderZipped, 'r') as zipObj:
             # Get a list of all archived file names from the zip
             listOfFileNames = zipObj.namelist()
             # Iterate over the file names
             for fileName in listOfFileNames:
                 # Check filename endswith csv
                 if fileName.endswith('.csv'):
                     # Extract a single file from zip
                     zipObj.extract(fileName, inputFolder)

          print ("LinkedIn - Fix")
          jsonInputFolder = dirpath+'/script/dataSource/json-LinkedIn_data'
          if not os.path.exists(jsonInputFolder):
             os.mkdir(jsonInputFolder)

          for r, d, f in os.walk(inputFolder):
            file_path = r.replace(inputFolder,jsonInputFolder)
            if not os.path.exists(file_path):
              os.mkdir(file_path)

          # root, d=directories, f = files
          for r, d, f in os.walk(inputFolder):
            file_path = r.replace(inputFolder,jsonInputFolder)
            for file in f:
              if file in ["Profile.csv","Connections.csv","Education.csv","Positions.csv","Skills.csv"]: #file.endswith(".csv")
                with codecs.open(os.path.join(r, file), 'r', encoding='utf8') as f_csv: #encoding='utf8'  mac_roman ISO-8859-1
                  reader = csv.DictReader(f_csv)
                  rows = list(reader)

                  json_data = json.dumps(list(rows))
                  json_arr = ast.literal_eval(json_data)

                  json_str=""
                  for i in range(len(json_arr)):
                     json_str = json_str + str(json.dumps(json_arr[i])) + "\n"

                  newFile = file.split('.')[0]+'.json'

                  with codecs.open(os.path.join(file_path,newFile), 'w', encoding='utf8') as f_json:
                     f_json.write(json_str)
                  f_json.close()


# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution(object):
    def reverseList(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        list_ = []
        front = head
        while head:
            list_.append(head.val)
            head = head.next
        list_ = list(reversed(list_))
        head = front
        index = 0
        rList = ListNode()
        if len(list_) == 0:
            return None
        front = rList
        rList.val = list_[0]
        for i in range(0,len(list_)):
            rList.val = list_[i]
            if i != len(list_)-1:
                rList.next = ListNode()
                rList = rList.next

        rList = front
        return rList


class idea1():

    def __init__(self,list):
        self.flag = False
        self.new_list = []
        self.list = list

    def ChosenTrangle(self):
        '''选择最长的三条边'''
        self.list.sort(reverse = True)

        try:
            self.new_list.append(self.list[0])
            self.new_list.append(self.list[1])
            self.new_list.append(self.list[2])
            self.WhetherTrangle(self.new_list)
        except IndexError:

            #print("zero!")
            self.flag = True

        if self.flag == False:
            self.list.pop(0)
            self.new_list.clear()
            self.ChosenTrangle()

        return self.new_list

    def WhetherTrangle(self,list):
        '''判断是否为三角形'''
        edge1 = list[0]
        edge2 = list[1]
        edge3 = list[2]

        if(edge1+edge2>edge3 and edge2+edge3>edge1 and edge1+edge3>edge2):
            self.flag = True


import atexit
from pathlib import Path

import cv2
import numpy as np

class VideoWriter:
    """Save video using OpenCV"""

    def __init__(
        self,
        path: Path,
        fps: float = 20.0,
        image_shape: str = "HWC",
        fourcc: str = "XVID",
        rgb: bool = True,
    ) -> None:
        self._path = path
        self._writer = None
        self._fps = fps
        self._w_index = image_shape.find("W")
        self._h_index = image_shape.find("H")
        self._fourcc = cv2.VideoWriter_fourcc(*fourcc)
        if self._w_index < 0 or self._h_index < 0:
            raise ValueError(f"Invalid shape: {image_shape}")
        c_index = image_shape.find("C")
        if c_index < 0:
            transpose = self._h_index, self._w_index
        else:
            transpose = self._h_index, self._w_index, c_index

        def convert(image: np.ndarray) -> np.ndarray:
            transposed = np.transpose(image, transpose)
            if rgb:
                return cv2.cvtColor(transposed, cv2.COLOR_RGB2BGR)
            else:
                return transposed

        self._convert = convert
        atexit.register(self.close)

    def _initialize_writer(self, image: np.ndarray) -> None:
        shape = image.shape
        h, w = shape[self._h_index], shape[self._w_index]
        color = len(shape) == 3
        self._writer = cv2.VideoWriter(
            self._path.as_posix(),
            self._fourcc,
            self._fps,
            (w, h),
            color,
        )

    def append(self, image: np.ndarray) -> None:
        if self._writer is None:
            self._initialize_writer(image)

        self._writer.write(self._convert(image))

    def close(self) -> None:
        if self._writer is not None:
            self._writer.release()


"""Given an array of integers nums containing n + 1 integers where each integer is in the range [1, n] inclusive.

There is only one repeated number in nums, return this repeated number.

You must solve the problem without modifying the array nums and uses only constant extra space
To find the repeated number in an array nums without modifying the array and using only constant extra space, you can use the "tortoise and hare" algorithm, also known as Floyd's cycle-finding algorithm.

Here's how you can implement this algorithm:

Initialize two pointers, slow and fast, to the first element of the array.

Move slow one step forward and fast two steps forward in each iteration.

Repeat step 2 until slow and fast meet.

Once slow and fast meet, reset slow to the first element of the array and keep fast at its current position.

Move both slow and fast one step forward in each iteration until they meet again.

The meeting point of slow and fast will be the repeated number in the array."""
def findDuplicate(nums):
    slow = nums[0]
    fast = nums[0]

    # Move slow and fast pointers
    while True:
        slow = nums[slow]
        fast = nums[nums[fast]]
        if slow == fast:
            break

    # Reset slow to the first element
    slow = nums[0]

    # Move slow and fast pointers until they meet again
    while slow != fast:
        slow = nums[slow]
        fast = nums[fast]

    return slow


""" FireObj
This is the module defining fire objects used for fire tracking

FOUR LAYERS OF OBJECTS
    a. Allfires:  the class of all fire events
    b. Fire:      the class of a fire event
    c. Cluster:   the class of active fire pixel cluster (only for supporting)
    d. FirePixel: the class of an active fire pixel
"""

# a. Object - Allfires
class Allfires:
    """ Class of allfire events at a particular time step
    """

    # initilization
    def __init__(self, t):
        """ Initiate the object with current time
        Parameters
        ----------
        t : tuple, (int,int,int,str)
            the year, month, day and 'AM'|'PM'
        """

        # Allfires object has a time stamp
        import FireTime

        # self.t = FireTime.t_nb(t,nb='previous') # initialize the object at the previous time step
        self.t = t

        # Allfires object contains a dict of Fire objects with fireID as the key (will be added after reading active fire data)
        self.fires = {}

        # Initiate lists storing fire ids which will changes at the current time step
        self.fids_expanded = (
            []
        )  # a list of ids for fires with expansion at current time step
        self.fids_new = (
            []
        )  # a list of ids for all new fires formed at current time step
        self.fids_merged = (
            []
        )  # a list of ids for fires with merging at current time step
        self.fids_invalid = (
            []
        )  # a list of ids for fires invalidated at current time step

        # cumulative recordings
        self.heritages = []  # a list of fire heritage relationships (source, target)
        self.id_dict = (
            []
        )  # this list relates the list position of the fire in the allfires object to the fire id
        # (list_index, fireid) (list position can be variable when writing out only active fires)

    # properties
    @property
    def cday(self):
        """ Datetime date of current time step
        """
        from datetime import date

        return date(*self.t[:-1])

    @property
    def ampm(self):
        """ Ampm indicator of current time step
        Parameters
        ----------
        ampm : str, 'AM'|'PM'
           the ampm option calculated from t
        """
        return self.t[-1]

    @property
    def fids(self):
        """ List of fire ids
        """
        return [i for i, f in self.fires.items()]

    @property
    def number_of_fires(self):
        """ Total number of fires (active and inactive) at this time step
        """
        return len(self.fires)

    @property
    def fids_active(self):
        """ List of active fire ids
        """
        return [i for i, f in self.fires.items() if f.isactive]

    @property
    def number_of_activefires(self):
        """ Total number of active fires at this time step
        """
        return len(self.fids_active)

    @property
    def activefires(self):
        """ dict of active fires
        """
        return {i: f for i, f in self.fires.items() if f.isactive}

    @property
    def mayactivefires(self):
        """ dict of active fires and sleepers
        """
        return {i: f for i, f in self.fires.items() if (f.isactive or f.mayreactivate)}

    @property
    def deadfires(self):
        """ dict of inactive fires not going to be reactivated
        """
        return {
            i: f for i, f in self.fires.items() if not (f.isactive or f.mayreactivate)
        }

    @property
    def fids_dead(self):
        """ List of fire ids that is not going to be reactivated
        """
        return [i for i, f in self.fires.items() if not (f.isactive or f.mayreactivate)]

    @property
    def fids_sleeper(self):
        """ List of fire ids that may reactivate
        """
        return [i for i, f in self.fires.items() if f.mayreactivate]

    @property
    def number_of_sleeper(self):
        """ Total number of sleep fires at this time step
        """
        return len(self.fids_sleeper)

    @property
    def fids_valid(self):
        """ List of valid (non-invalid) fire ids
        """
        # return [self.fires[f].fireID for f in self.fires if self.fires[f].invalid is False]
        return [i for i, f in self.fires.items() if f.invalid is False]

    @property
    def number_of_validfires(self):
        """ Total number of valid fires at this time step
        """
        return len(self.fids_valid)

    @property
    def validfires(self):
        """ List of valid fires
        """
        # return [self.fires[fid] for fid in self.fids_valid]
        return {i: f for i, f in self.fires.items() if f.invalid is False}

    @property
    def fids_updated(self):
        """ List of fire id which is updated at this time step
            (expanded, new, merged, invalid)
        """
        fids_updated = list(
            set(
                self.fids_expanded
                + self.fids_new
                + self.fids_merged
                + self.fids_invalid
            )
        )
        return fids_updated

    @property
    def fids_ne(self):
        """ List of fire id which is newly formed or expanded
               at this time step
        """
        fids_ne = sorted(set(self.fids_expanded + self.fids_new))
        return fids_ne

    # functions to be run before tracking VIIRS active fire pixels at each time step
    def update_t(self, t):
        """ Update the time (cday and ampm) for the Allfire object.
        Parameters
        ----------
        t : tuple, (int,int,int,str)
            the year, month, day and 'AM'|'PM'
        """
        self.t = list(t)  # current date and ampm

    def update_t_allfires(self, t):
        """ Update the time (t) for each Fire object in the Allfire object.
        Parameters
        ----------
        t : tuple, (int,int,int,str)
            the year, month, day and 'AM'|'PM'
        """
        for i, f in self.fires.items():
            f.t = list(t)

    def reset_newpixels(self):
        """ Reset newpixels to [] for each fire.
        """
        for i, f in self.fires.items():
            f.newpixels = []

    def cleanup(self, t):
        """ Clean up Allfires obj at each time step
        - update t (for allfires and all fires)
        - clean up lists to record fire changes
        - clean up newpixels for each fire
        """
        # time updated to t
        self.update_t(t)  # update t for allfires
        self.update_t_allfires(t)  # update t

        # reset the fids used to record changes
        self.fids_expanded = (
            []
        )  # a list of ids for fires with expansion at current time step
        self.fids_new = (
            []
        )  # a list of ids for all new fires formed at current time step
        self.fids_merged = (
            []
        )  # a list of ids for fires with merging at current time step
        self.fids_invalid = (
            []
        )  # a list of ids for fires invalidated at current time step

        # reset newpixels for each fire to empty list.
        for i, f in self.fires.items():
            f.newpixels = []

    def newyear_reset(self, regnm):
        """ reset fire ids at the start of a new year
        """
        import FireIO

        # re-id all active fires
        newfires = {}
        fidmapping = []
        fids_keep = self.fids_active + self.fids_sleeper
        for i, fid in enumerate(fids_keep):
            newfires[i] = self.fires[fid]  # record new fireID and fire object
            newfires[i].fireID = i  # also update fireID attribute of fire object
            fidmapping.append((fid, i))
        self.fires = newfires

        # lastyearfires = {}
        # fidmapping = []
        # nfid = 0
        # for f in self.activefires:
        #     ofid = f.fireID
        #     f.fireID = nfid
        #     # lastyearfires.append(f)
        #     lastyearfires[nfid] = f
        #     fidmapping.append((ofid,nfid))
        #     nfid += 1
        # self.fires = lastyearfires

        # clean heritages
        self.heritages = []

        # save the mapping table
        if len(fidmapping) > 0:
            FireIO.save_newyearfidmapping(fidmapping, self.t[0], regnm)

    # functions to be run after tracking VIIRS active fire pixels at each time step
    def record_fids_change(
        self, fids_expanded=None, fids_new=None, fids_merged=None, fids_invalid=None
    ):
        """ Update the list of ids for fires with changes at current time step.
        Parameters
        ----------
        fids_expanded : list
            ids of expanded fires
        fids_new : list
            ids of new formed fires
        fids_merged : list
            ids of fires with other fires merging to them
        fids_invalid : list
            ids of fires invalidated (due to merging with other fires)
        """
        if fids_expanded:
            self.fids_expanded = fids_expanded  # expanded fires
        if fids_new:
            self.fids_new = fids_new  # new formed fires
        if fids_merged:
            self.fids_merged = fids_merged  # fires with merging with other fires
        if fids_invalid:
            self.fids_invalid = (
                fids_invalid  # fires invalidated due to merging with other fires
            )

    def invalidate_statfires(self):
        """ If pixel density of an active fire is too large, assume it's static
                fires and invalidate it.
        """
        try:
            for i, f in self.activefires.items():
                if (f.pixden > 20) & (f.farea < 20):
                    # invalidate the fire
                    f.invalid = True

                    # add the fire id into the fids_invalid list
                    self.fids_invalid.append(f.fireID)
                    print('one static fire invalidated')
        except Exception as e:
            print(e)

    # def updateLCTmax(self):
    #     ''' update Land cover type (dominant LCT for all fire pixels) for active
    #             fires that is small in size (<1000 pixels)
    #     '''
    #     import FireIO
    #     for f in self.activefires:
    #         if (f.n_pixels < 1000):
    #             # get all LCT for the fire pixels
    #             vLCT = FireIO.get_LCT(f.locs)
    #             # extract the LCT with most pixel counts
    #             LCTmax = max(set(vLCT), key = vLCT.count)
    #             f.LCTmax = LCTmax

    # def updateftypes(self):
    #     ''' update fire type and dominant LCT for active fires
    #     '''
    #     import FireFuncs
    #     for f in self.activefires:
    #         if f.n_newpixels > 0:
    #             f.ftype = FireFuncs.set_ftype(f)
    # f.set_ftype()

# b. Object - Fire
class Fire:
    """ Class of a single fire event at a particular time step
    """

    # initilization
    def __init__(self, id, t, pixels, sensor="viirs"):
        """ Initialize Fire class with active fire pixels locations and t. This
                is only called when fire clusters forming a new Fire object.
        Parameters
        ----------
        id : int
            fire id
        t : tuple, (int,int,int,str)
            the year, month, day and 'AM'|'PM'
        pixels : list (nx5)
            latitude, longitude, line, sample, and FRP values of active fire pixels
        sensor : str
            the remote sensing instrument, 'viirs' | 'modis'; no differentiation
            between SNPP and NOAA20
        """
        import FireVector

        # initialize fire id and sensor
        self.fireID = id
        self.mergeid = id  # mergeid is the final fire id the current fire being merged; use current fire id at initialization
        self.sensor = sensor  #

        # initialize current time, fire start time, and fire final time
        tlist = list(t)  # convert (y,m,d,ampm) to [y,m,d,ampm]
        self.t = tlist  # current time
        self.t_st = tlist
        self.t_ed = tlist

        # initialize pixels
        # fpixels = [FirePixel((p[0],p[1]),(p[2],p[3],p[4]),tlist,id) for p in pixels]
        fpixels = pixels
        self.pixels = fpixels  # all pixels
        self.newpixels = fpixels  # new detected pixels
        # self.actpixels = fpixels   # new detected pixels of last active fire detection
        self.ignpixels = fpixels  # pixels at ignition

        # initialize hull using the pixels
        locs = [p.loc for p in fpixels]  # list of [lat,lon]
        # locs_geo = [p.loc_geo for p in fpixels]  # list of [lat,lon]
        hull = FireVector.cal_hull(locs, sensor)  # the hull from all locs
        self.hull = hull  # note fire.hull is not automatically updated (need explicit calculation if changes occur)

        # initialize the exterior pixels (pixels within the inward extbuffer of
        #    the hull; used for saving time for hull calculation of large fires)
        self.extpixels = FireVector.cal_extpixels(fpixels, hull)

        # fline of latest active timestep, used for sleeper threshold
        self.fline_prior = None

        # always set validate at initialization
        self.invalid = False

        # get and record fm1000 value at ignition (at the time of initilization)
        # self.stFM1000 = FireIO.get_stFM1000(hull,locs,tlist)

        # LCTmax
        # vLCT = FireIO.get_LCT(locs)
        # self.LCTmax = max(set(vLCT), key = vLCT.count)

    # properties
    @property
    def cday(self):
        """ Current day (datetime date)
        """
        from datetime import date

        return date(*self.t[:-1])

    @property
    def cdoy(self):
        """ Current day (datetime date)
        """
        return self.cday.timetuple().tm_yday

    @property
    def ampm(self):
        """ Current ampm flag, 'AM'|'PM'
        """
        return self.t[-1]

    @property
    def duration(self):
        """ Time difference between first and last active fire detection
        """
        import FireTime

        duration = FireTime.t_dif(self.t_st, self.t_ed)  # + 0.5
        return duration

    @property
    def t_inactive(self):
        """ Time difference between current time and the last active fire detection
        """
        import FireTime

        t_inactive = FireTime.t_dif(self.t_ed, self.t)
        return t_inactive

    @property
    def isactive(self):
        """ Fire active status
        """
        from FireConsts import maxoffdays

        # invalidated fires are always inactive
        if self.invalid:
            return False
        # otherwise, set to True if no new pixels detected for 5 consecutive days
        return self.t_inactive <= maxoffdays

    @property
    def isdead(self):
        """ Fire active status
        """
        from FireConsts import limoffdays

        # invalidated fires are always inactive
        if self.invalid:
            return False
        # otherwise, set to True if no new pixels detected for 5 consecutive days
        return self.t_inactive > limoffdays

    @property
    def mayreactivate(self):
        """ Fire sleeper status
        """
        from FireConsts import maxoffdays, limoffdays

        # invalidated fires are always inactive
        if self.invalid:
            return False
        # otherwise, set to True if no new pixels detected for 5 consecutive days
        return maxoffdays < self.t_inactive <= limoffdays

    @property
    def isignition(self):
        """ Is the current timestep the ignition?
        when start time == end time; and new pixel > 0
        """
        import FireTime

        if (
            len(self.newpixels) == 0
        ):  # in this case t_st = t_ed because t_ed has not been updated
            ign = 0
        else:
            ign = (FireTime.t_dif(self.t_st, self.t_ed) == 0) * 1
        return ign

    @property
    def locs(self):
        """ List of fire pixel locations (lat,lon)
        """
        return [p.loc for p in self.pixels]

    @property
    def locs_geo(self):
        """ List of fire pixel locations (lat,lon)
        """
        return [p.loc_geo for p in self.pixels]

    @property
    def locsMP(self):
        """ MultiPoint shape of locs
        """
        from shapely.geometry import MultiPoint

        mp = MultiPoint([(p[0], p[1]) for p in self.locs])
        return mp

    @property
    def n_pixels(self):
        """ Total number of fire pixels"""
        return len(self.pixels)

    @property
    def newlocs(self):
        """ List of new fire pixels locations (lat,lon)
        """
        return [p.loc for p in self.newpixels]

    @property
    def newlocs_geo(self):
        """ List of new fire pixels locations (lat,lon)
        """
        return [p.loc_geo for p in self.newpixels]

    @property
    def newlocsMP(self):
        """ MultiPoint shape of newlocs
        """
        from shapely.geometry import MultiPoint

        mp = MultiPoint([(p[0], p[1]) for p in self.newlocs])
        return mp

    @property
    def newpixelatts(self):
        """ List of new fire pixels attributes
        """
        return [
            (p.lon, p.lat, p.frp, p.DS, p.DT, p.datetime, p.ampm, p.sat)
            for p in self.newpixels
        ]

    @property
    def n_newpixels(self):
        """ Total number of new fire pixels
        """
        return len(self.newpixels)

    @property
    def extlocs(self):
        """ List of exterior fire pixel locations (lat,lon)
        """
        return [p.loc for p in self.extpixels]

    @property
    def extlocsMP(self):
        """ MultiPoint shape of extlocs
        """
        from shapely.geometry import MultiPoint

        mp = MultiPoint([(p[0], p[1]) for p in self.extlocs])
        return mp

    @property
    def n_extpixels(self):
        """ Total number of exterior fire pixels
        """
        return len(self.extpixels)

    @property
    def ignlocs(self):
        """ List of fire pixel locations (lat,lon) at ignition time step
        """
        return [p.loc for p in self.ignpixels]

    @property
    def ignlocsMP(self):
        """ MultiPoint shape of ignlocs
        """
        from shapely.geometry import MultiPoint

        mp = MultiPoint([(p[0], p[1]) for p in self.ignlocs])
        return mp

    @property
    def ignlocs_geo(self):
        """ List of fire pixel locations (lat,lon) at ignition time step
        """
        return [p.loc_geo for p in self.ignpixels]

    @property
    def ignlocsMP_geo(self):
        """ MultiPoint shape of ignlocs
        """
        from shapely.geometry import MultiPoint

        mp = MultiPoint([(p[0], p[1]) for p in self.ignlocs_geo])
        return mp

    @property
    def n_ignpixels(self):
        """ Total number of ignition fire pixels
        """
        return len(self.ignpixels)

    @property
    def farea(self):
        """ Fire spatail size of the fire event (km2)
        """
        from FireConsts import area_VI
        import numpy as np

        # get hull
        fhull = self.hull

        # If no hull, return area calculated from number of pixels
        if fhull is None:
            return self.n_pixels * area_VI
        # otherwise, use calConcHarea to calculate area,
        #   but no smaller than area_VI (sometimes calculated hull area is very small)
        else:
            # from pyproj import Geod
            # geod = Geod(ellps="WGS84")
            # area_cal = np.abs(geod.geometry_area_perimeter(self.hull)[0]/1e6)
            area_cal = fhull.area / 1e6
            return max(area_cal, area_VI)

            # import FireVector
            # return max(FireVector.calConcHarea(fhull),area_VI)

    # @property
    # def centroid(self):
    #     ''' Centroid of fire object (lat,lon)
    #     '''
    #     import FireClustering
    #
    #     # get hull
    #     fhull = self.hull
    #
    #     if fhull is not None: # centroid of the hull
    #         cent = (fhull.centroid.y,fhull.centroid.x)
    #     else: # when no hull, use the centroid of all pixels
    #         cent = FireClustering.cal_centroid(self.locs)
    #     return cent

    @property
    def pixden(self):
        """ Fire pixel density (number of pixels per km2 fire area)
        """
        farea = self.farea
        if farea > 0:
            return self.n_pixels / farea
        else:
            return 0

    @property
    def meanFRP(self):
        """ Mean FRP of the new fire pixels
        """
        frps = [p.frp for p in self.newpixels]
        if len(frps) > 0:
            m = sum(frps) / len(frps)
        else:
            m = 0
        return m

    @property
    def ftypename(self):
        """ Fire type name
        """
        import FireFuncs

        return FireFuncs.set_ftypename(self)

    @property
    def fperim(self):
        """ Perimeter length of fire hull
        """
        # get hull
        fhull = self.hull

        if fhull is None:  # if no hull, return zero
            perim = 0
        else:  # otherwise, use the hull length
            # from pyproj import Geod
            # geod = Geod(ellps="WGS84")
            # perim = geod.geometry_length(fhull)/1000 # in km
            perim = fhull.length / 1e3  # km
        return perim

    @property
    def flinepixels(self):
        """ List of all fire pixels near the fire perimeter (fine line pixels)
        """
        from shapely.geometry import Point, MultiLineString
        import FireVector
        from FireConsts import fpbuffer

        # get pixels of last active fire detection
        nps = self.newpixels

        # get hull
        fhull = self.hull

        if fhull is None:  # if no hull, return empty list
            return []
        else:
            try:
                # otherwise, extract the pixels nearl the hull
                # if hull is a polygon, return new pixels near the hull
                if fhull.type == "Polygon":
                    # lr = fhull.exterior.buffer(fpbuffer)
                    lr = FireVector.addbuffer(fhull.exterior, fpbuffer)
                    return [p for p in nps if lr.contains(Point(p.loc[0], p.loc[1]))]

                # if hull is a multipolygon, return new pixels near the hull
                elif fhull.type == "MultiPolygon":
                    # mlr = MultiLineString([x.exterior for x in fhull]).buffer(fpbuffer)
                    mlr = MultiLineString([x.exterior for x in fhull])
                    mlr = FireVector.addbuffer(mlr, fpbuffer)
                    return [p for p in nps if mlr.contains(Point(p.loc[0], p.loc[1]))]

            except Exception as e:
                print(e)
                return []

    @property
    def flplocs(self):
        """ List of fire line pixel locations (lat,lon)
        """
        return [p.loc for p in self.flinepixels]

    @property
    def flplocsMP(self):
        """ MultiPoint shape of flplocs
        """
        from shapely.geometry import Point
        import geopandas as gpd

        mp = [Point(p[0], p[1]) for p in self.flplocs]
        return gpd.GeoSeries(mp)

    @property
    def n_flinepixels(self):
        """ Total number of fire line pixels
        """
        return len(self.flinepixels)

    @property
    def fline(self):
        """ Active fire line MultiLineString shape (segment of fire perimeter with active fires nearby)
        """
        from shapely.geometry import MultiLineString
        from FireConsts import flbuffer, VIIRSbuf
        import FireVector

        if (
            self.n_flinepixels == 0
        ):  # this happens is last active pixels are within the fire scar
            return None

        # get fireline pixel locations, different from flplocsMP since it contains a VIIRS pixel buffer
        flinelocsMP = FireVector.doMultP(self.flplocs, VIIRSbuf)

        # get the hull
        fhull = self.hull

        # calculate the fire line
        if fhull is None:  # if no hull, return None
            return None
        else:  # otherwise, create shape of the active fire line
            if fhull.type == "MultiPolygon":
                # extract exterior of fire perimeter
                mls = MultiLineString([plg.exterior for plg in fhull])
                # return the part which intersects with  bufferred flinelocsMP
                # return mls.intersection(flinelocsMP.buffer(flbuffer))
                flinelocsMP_buf = FireVector.addbuffer(flinelocsMP, flbuffer)
                fline = mls.intersection(flinelocsMP_buf)

            elif fhull.type == "Polygon":
                mls = fhull.exterior
                # return mls.intersection(flinelocsMP.buffer(flbuffer))
                flinelocsMP_buf = FireVector.addbuffer(flinelocsMP, flbuffer)
                fline = mls.intersection(flinelocsMP_buf)
            else:  # if fhull type is not 'MultiPolygon' or 'Polygon', return flinelocsMP
                fline = flinelocsMP

            # we save the fire line to a new property (this is only updated when fline not None)
            self.fline_prior = fline

            return fline

    @property
    def flinelen(self):
        """ The length of active fire line
        """
        from pyproj import Geod

        try:
            flinelen = self.fline.length / 1e3  # km
            # geod = Geod(ellps="WGS84")
            # flinelen = geod.geometry_length(self.fline)/1000 # in km
        except:
            flinelen = 0

        return flinelen

    # functions
    def updateftype(self):
        """ Update fire type
        # do not use ftype as property since it may mess up when t updates (without pixel addition)
        """
        import FireFuncs

        self.ftype = FireFuncs.set_ftype(self)

    def updatefhull(self, newlocs):
        """ Update the hull using old hull and new locs
        """
        import FireVector

        hull = FireVector.cal_hull(newlocs, sensor=self.sensor)
        # use the union to include hull in past time step
        phull = self.hull
        self.hull = phull.union(hull)

    def updateextpixels(self, newpixels):
        """ Update the external pixels
        """
        import FireVector

        pextpixels = self.extpixels
        self.extpixels = FireVector.cal_extpixels(pextpixels + newpixels, self.hull)

# c. Object - Cluster
class Cluster:
    """ class of active fire pixel cluster at a particular time
    """

    # initilization
    def __init__(self, id, pixels, t, sensor="viirs"):
        """ initilization

        Parameters
        ----------
        id : int
            cluster id number
        pixels : 3-element list
            (lat, lon, FRP) of AF pixels
        t : tuple, (int,int,int,str)
            the year, month, day and 'AM'|'PM'
        """
        from datetime import date

        self.cday = date(*t[:-1])  # current date
        self.ampm = t[-1]  # current ampm
        self.id = id
        self.sensor = sensor
        self.pixels = pixels  # (x,y,FRP,...)

    # properties
    @property
    def locs(self):
        """ List of pixel locations (lat,lon)
        """
        return [(p.x, p.y) for p in self.pixels]

    @property
    def centroid(self):
        """ Centroid of the cluster (lat, lon)
        """
        import FireClustering

        return FireClustering.cal_centroid(self.locs)

    @property
    def n_pixels(self):
        """ Number of total pixels
        """
        return len(self.pixels)

    @property
    def hull(self):
        """ Fire concave hull (alpha shape)
        """
        import FireVector

        hull = FireVector.cal_hull(self.locs, self.sensor)
        return hull

    @property
    def b_box(self):
        """ Bounding box of concave hull
        """
        b_box = self.hull.bounds
        return b_box

# d. Object - FirePixel
class FirePixel:
    """ class of an acitve fire pixel, which includes
        loc : location (lat, lon)
        atts : line & sample or viirs pixel, fire radiative power
        t : time (y,m,d,ampm) of record
        origin : the fire id originally recorded (before merging)
    """

    def __init__(self, x, y, lon, lat, frp, DS, DT, ampm, t, Sat, origin):
        self.x = x
        self.y = y
        self.lat = lat
        self.lon = lon
        self.frp = frp  # frp
        # self.t = list(t)      # (year,month,day,ampm)
        self.DS = DS
        self.DT = DT
        self.ampm = ampm
        self.datetime = t  # YYYYMMDD_HHMM
        self.sat = Sat  # satellite
        self.origin = origin  # intially assigned fire id

    @property
    def loc(self):
        return (self.x, self.y)

    @property
    def loc_geo(self):
        return (self.lon, self.lat)


#Quiz: Calculate
#In this quiz you're going to do some calculations for a tiler.
#Two parts of a floor need tiling. One part is 9 tiles wide by 7 tiles long, the other is 5 tiles wide by 7 tiles long. Tiles come in packages of 6.

#1. How many tiles are needed?
#2. You buy 17 packages of tiles containing 6 tiles each. How many tiles will be left over?

#Fill this in with an expression that calculates how many tiles are needed.
length_one= 7
width_one= 9
part_one = length_one * width_one

length_two= 7
width_two= 5
part_two= length_two * width_two

total_tiles_needed = part_one + part_two
print(total_tiles_needed)

# Fill this in with an expression that calculates how many tiles will be left over.
package_tiles= 6
no_packages= 17
total_tiles = package_tiles * no_packages
leftover_tiles = total_tiles - total_tiles_needed
print(leftover_tiles)


#Read all input from file
input_file = open("Day_1_Input.txt", "r")
lines = input_file.read()
input_file.close()

#Add all line from file to a list named list_of_lines
list_of_lines = lines.splitlines()

#counter for the for loop
for_count = 0
first_num = 0
sec_num = 0

for i in list_of_lines:
    for a in list_of_lines[for_count:]:
        ans = int(i) + int(a)
        if ans == 2020:
            first_num = int(i)
            sec_num = int(a)
            break
    else:
        continue
    break
    for_count = for_count + 1

answer = first_num * sec_num
print(answer)


import numpy as np
import pandas as pd
import models.helper as h

def create_polymod_matrix():

    # Read in original Mossong matrix for UK
    cm = pd.read_csv("./data/MOSSONG-britain-per-day.csv", header=None)

    age_groups = ["00-04", "05-09", "10-14", "15-19", "20-24",
                  "25-29", "30-34", "35-39", "40-44", "45-49",
                  "50-54", "55-59", "60-64", "65-69", "70+"]

    cm.columns = age_groups
    cm.index = age_groups

    cm.index.name = "age of contact"
    cm.columns.name = "age group of participant"

    # Note the transpose w.r.t original Mossong matrix to match SEIR model
    # notation
    cm = cm.transpose()

    # cm.to_csv("./data/output_data/mossong_britain_per_day_with_titles.csv")

    #%%
    # Get UK population by age categories of POLYMOD matrix
    ages_df = pd.read_csv("./data/uk_demographic_data/2018-Table 1.csv",
                          index_col=0)
    ages_df = ages_df.loc["UNITED KINGDOM", ]
    ages_df = ages_df.iloc[1:]
    ages_df = pd.DataFrame({"population": ages_df})
    ages_df = ages_df.reset_index()

    # f_tot = ages_df.loc[(ages_df["index"] == "f_tot"), "population"].values
    # m_tot = ages_df.loc[(ages_df["index"] == "m_tot"), "population"].values

    ages_df = ages_df.loc[~(ages_df["index"].isin(["m_tot", "f_tot"])), ]

    ages_df[["sex",
             "year",
             "age"]] = ages_df.loc[:, "index"].str.split(pat="_", n=-1,
                                                         expand=True)

    ages_df["age_bins"] = pd.cut(ages_df["age"].astype("int"),
                                 bins=np.concatenate([np.arange(0, 71, 5),
                                                      [100]]),
                                 right=False)

    pop_by_age_bin = ages_df.groupby("age_bins")["population"].sum()
    pop_by_age_bin.to_csv(h.uk_pop_filepath)

    # Calculation of size of age categories for the bins used in Verity et al
    ages_df["age_bins2"] = pd.cut(ages_df["age"].astype("int"),
                                  bins=np.concatenate([np.arange(0, 81, 10),
                                                       [100]]),
                                  right=False)

    pop_by_age_bin2 = ages_df.groupby("age_bins2")["population"].sum()
    pop_by_age_bin2.to_csv(h.uk_pop_verity_filepath)

    # Correcting contact matrix for reciprocity

    # total daily UK contacts between i and j as reported by participants
    e1 = cm.multiply(pop_by_age_bin.values, axis=0)
    # Symmetrise matrix
    e2 = (e1 + e1.transpose())/2.
    # Divide by population, c_ij = E2_ij/N_i to get corrected number of daily
    # contacts for each participant
    cm_corrected = e2.multiply(1/pop_by_age_bin.values, axis=0)

    cm_corrected.to_csv(h.cm_filepath)


from tkinter import *
from PIL import Image, ImageTk
from tkinter import ttk,messagebox #messagebox for pop up
import sqlite3
import os                          #for working with files and directories

class salesClass:
    def __init__(self, root):  # default constructor
        self.root = root
        self.root.geometry("1000x450+220+120")
        self.root.title("Sales")
        self.root.config(bg="white")
        self.root.focus_force() # to highlight the new window

##=============title===========
        lbl_title = Label(self.root, text="View Customer Bills", font=("goudy old style", 30), bg="#0f4d7d", fg="white", bd=3,relief=RIDGE)
        lbl_title.pack(side=TOP,fill=X,padx=20,pady=5)

##=============contents=====================
    #======content variables================
        self.var_invoice=StringVar()
        self.bill_list=[]

    #======content labels and entries=======
        #===row1===
        lbl_invoice=Label(self.root, text="Invoice No.", font=("goudy old style", 15), bg="white")
        lbl_invoice.place(x=20,y=70)
        txt_invoice = Entry(self.root, textvariable=self.var_invoice,font=("goudy old style", 15), bg="lightyellow")
        txt_invoice.place(x=150, y=70,width=180,height=30)
        btn_search = Button(self.root, text="Search", command=self.search,font=("goudy old style", 15,"bold"), bg="#2196f3",fg="white",cursor="hand2")
        btn_search.place(x=350, y=70, width=150, height=30)
        btn_clear = Button(self.root, text="Clear", command=self.clear,font=("goudy old style", 15,"bold"), bg="lightgrey",cursor="hand2")
        btn_clear.place(x=520, y=70, width=150, height=30)
        #===sales bill frame===
        sales_Frame=Frame(self.root,bd=3,relief=RIDGE)
        sales_Frame.place(x=20,y=120,width=220,relheight=0.7)
            #===Listbox to show files===
                #===scrollbar in listbox===
        scrolly1 = Scrollbar(sales_Frame, orient=VERTICAL)
        scrolly1.pack(side=RIGHT, fill=Y)
        scrollx1 = Scrollbar(sales_Frame, orient=HORIZONTAL)
        scrollx1.pack(side=BOTTOM, fill=X)
                #===Listbox===
        self.sales_list=Listbox(sales_Frame,font=("goudy old style",15),bg="white",yscrollcommand=scrolly1.set, xscrollcommand=scrollx1.set)
        self.sales_list.pack(fill=BOTH,expand=1)       #fill=BOTH to fill the whole frame, expand=1 means expand property is True
        scrolly1.config(command=self.sales_list.yview)
        scrollx1.config(command=self.sales_list.xview)  # to make the scroll bar work

        #to show the content of bill file in the "Bill Area Frame"
        self.sales_list.bind("<ButtonRelease-1>",self.get_bill_data)        #This is an event

        #to show the list of bills in the "Sales bill frame"
        self.show_bill()

        #===bill area frame===
        bill_Frame = Frame(self.root, bd=3, relief=RIDGE)
        bill_Frame.place(x=280, y=120, width=410, relheight=0.7)
            #===Text area to show files===
                # ===Bill Area title===
        lbl_billarea_title = Label(bill_Frame, text="Customer Bill Area", font=("goudy old style", 15), bg="orange")
        lbl_billarea_title.pack(side=TOP, fill=X)
                #===scrollbar in bill area===
        scrolly2 = Scrollbar(bill_Frame, orient=VERTICAL)
        scrolly2.pack(side=RIGHT, fill=Y)
        scrollx2 = Scrollbar(bill_Frame, orient=HORIZONTAL)
        scrollx2.pack(side=BOTTOM, fill=X)
                #===Bill Area text===
        self.bill_area = Text(bill_Frame, font=("goudy old style", 15), bg="lightyellow", yscrollcommand=scrolly2.set,xscrollcommand=scrollx2.set)
        self.bill_area.pack(fill=BOTH,expand=1)         #fill=BOTH to fill the whole frame, expand=1 means expand property is True
        scrolly2.config(command=self.bill_area.yview)
        scrollx2.config(command=self.bill_area.xview)  #to make the scroll bar work

        #=====Image====
            #===accessing the image and resizing===
        self.bill_Photo = Image.open("images/im2.png")
        self.bill_Photo = self.bill_Photo.resize((250, 300), Image.ANTIALIAS)  #ANTIALIAS doesn't change picture quality
        self.bill_Photo = ImageTk.PhotoImage(self.bill_Photo)                  #Image is dynamically placed
            #===placing the image===
        lbl_bill_Photo = Label(self.root, image=self.bill_Photo,bd=0)
        lbl_bill_Photo.place(x=730,y=130)

##============ Functionality =============
    #to show the list of bills in the bills directory
    def show_bill(self):
        del self.bill_list[:]                             #to clear the list
        self.sales_list.delete(0,END)
        #print(os.listdir("../dwivediPnTbilling/bills"))  #the path can also be given as "../dwivediPnTbilling/"
        for i in os.listdir("bills"):
            if i.split(".")[-1]=="txt": #to get and compare the file extension
                self.sales_list.insert(END,i)
                self.bill_list.append(i.split('.')[0])

    #to show the contents of the bill file in the bill area
    def get_bill_data(self,ev):                      #For event we have to pass a parameter
        file_index=self.sales_list.curselection() #curselection helps to show the index of the selected item from the list
        bill_file_name=self.sales_list.get(file_index)
        #print(bill_file_name)
        self.bill_area.delete('1.0',END)        #string indexing starts from 1.0 because it is text entry field
        fp=open(f"bills/{bill_file_name}",'r')
        for i in fp:
            self.bill_area.insert(END,i)
        fp.close()

    #to show the search results
    def search(self):
        if self.var_invoice.get()=="":
            messagebox.showerror("Error","Invoice no. should be required",parent=self.root)
        else:
            #print(self.bill_list,self.var_invoice.get()) #debugging
            if self.var_invoice.get() in self.bill_list:
                #print("Yes find the invoice")            #debugging
                fp = open(f"bills/{self.var_invoice.get()}.txt", 'r')
                self.bill_area.delete('1.0',END)
                for i in fp:
                    self.bill_area.insert(END, i)
                fp.close()
            else:
                messagebox.showerror("Error", "Invalid Invoice no.", parent=self.root)

    #to clear the list
    def clear(self):
        self.show_bill()                     #so that the list of bills doesn't vanish
        self.bill_area.delete("1.0",END)
        self.var_invoice.set("")

if __name__=="__main__": #while dealing with multiple files "main" means this is the main file
    root=Tk()
    obj= salesClass(root) #creating object of Billing Class
    root.mainloop()


# A versão inicial de hand_rank possuia varias subfunções auxiliares
# como straight, two_pair, kind... que agora estão na pasta old_hand_rank
# junto com a versão antiga.

# Refactored hand rank, second version:
def hand_rank(hand):
    """Return a value indicating how high the hand ranks

    Counts is the count of each rank; ranks lists corresponding ranks
    e.g. '7 T 7 9 7' => counts = (3, 1, 1); ranks = (7, 10, 9)

    """
    groups = group(['--23456789TJQKA'.index(r) for r, s in hand])
    counts, ranks = unzip(groups)
    if ranks == (14, 5, 4, 3, 2):
        ranks = (5, 4, 3, 2, 1)
    straight = len(ranks) == 5 and max(ranks) - min(ranks) == 4
    flush = len(set([s for r, s in hand])) == 1
    #                                  Using automatic conversion of bool to int
    return max(count_rankings[counts], 4*straight + 5*flush), ranks

count_rankings = {(5,):10, (4, 1):7, (3, 2):6, (3, 1, 1):3, (2, 2, 1):2,
                  (2, 1, 1, 1):1, (1, 1, 1, 1, 1):0}

# Refactored hand_rank, first version:
def hand_rank_1(hand):
    """Return a value indicating how high the hand ranks

    Counts is the count of each rank; ranks lists corresponding ranks
    e.g. '7 T 7 9 7' => counts = (3, 1, 1); ranks = (7, 10, 9)

    """
    groups = group(['--23456789TJQKA'.index(r) for r, s in hand])
    counts, ranks = unzip(groups)
    if ranks == (14, 5, 4, 3, 2):
        ranks = (5, 4, 3, 2, 1)
    straight = len(ranks) == 5 and max(ranks) - min(ranks) == 4
    flush = len(set([s for r, s in hand])) == 1
    return (9 if (5,) == counts else
            8 if straight and flush else
            7 if (4, 1) == counts else
            6 if (3, 2) == counts else
            5 if flush else
            4 if straight else
            3 if (3, 1, 1) == counts else
            2 if (2, 2, 1) == counts else
            1 if (2, 1, 1, 1) == counts else
            0), ranks

def group(items):
    """Return a list of [(count, x)...], highest count first, then highest
    x first"""
    groups = [(items.count(x), x) for x in set(items)]
    return sorted(groups, reverse=True)

def unzip(pairs): return zip(*pairs)


#! /usr/bin/env python3
#
# Read datagrams from one port and forward them to another host/port
#
# March-2022, Pat Welch, pat@mousebrains.com

from TPWUtils import Logger
from argparse import ArgumentParser
import socket

parser = ArgumentParser()
Logger.addArgs(parser)
parser.add_argument("--listen", type=int, default=10034, help="UDP port to listen to")
parser.add_argument("--ipv4", type=str, default="100.124.34.2",
        help="IP address to send datagrams to")
parser.add_argument("--port", type=int, default=8982, help="UDP port to send datagrams to")
args = parser.parse_args()

logger = Logger.mkLogger(args, fmt="%(asctime)s %(levelname)s: %(message)s")

with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
    s.bind(("", args.listen))
    while True:
        (data, senderAddr) = s.recvfrom(1024)
        index = data.find(b"!")
        if index < 0:
            index = data.find(b"$")
            if index < 0:
                logger.info("Dropping %s", data)
                continue
        try:
            logger.info("Received %s", str(data[index:], "UTF-8").strip())
            s.sendto(data[index:].strip(), (args.ipv4, args.port))
        except:
            logger.exception("Unable to send %s", data)


fin = open("rect-union.in", "r")
fout = open("rect-union.out", "w")

ar = [[0 for i in range(210)] for j in range(210)]
num = int(fin.readline())
arr = []
for i in range(num):
    string = fin.readline()
    string = list(map(int, string.split()))
    for i in range(len(string)):
        string[i] += 105
    arr.append(string)
for ii in arr:
    for i in range(ii[0], ii[2]):
        for j in range(ii[1], ii[3]):
            ar[i][j] += 1

cnt = 0
for i in ar:
    for j in i:
        if j:
            cnt += 1
print(cnt, file=fout)

fin.close()
fout.close()


import re
import base64
import json
import datetime
from io import BytesIO
from xml.etree import ElementTree
from PyPDF2 import PdfReader
from http import HTTPStatus
from flask import current_app, request, make_response
from flask_restx import Namespace, Resource, fields
from formsflow_api_utils.utils import (
    cors_preflight,
    auth,
    profiletime
)
from formsflow_api.schemas import DocumentsListSchema
from formsflow_api_utils.utils.user_context import UserContext, user_context
from formsflow_api_utils.exceptions import BusinessException
from formsflow_api.exceptions import EurotrustException
from formsflow_api.services import FormioServiceExtended, DocumentsService, KeycloakAdminAPIService
from formsflow_api.services.external import EurotrustIntegrationsService
from formsflow_api.models import DocumentStatus

API = Namespace("Documents", description="Temporary documents EP")

document = API.model(
    "Document",
    {
        "id"
    }
)

VALID_STATUSES = [
    "unsigned",
    "signing",
    "signed",
    "expired",
    "rejected"
]

VALID_TYPES = [
    "eAuth"
    "eIdentity"
    "OKEP"
    "eDelivery"
]

@cors_preflight("GET,OPTIONS")
@API.route("", methods=["GET", "OPTIONS"])
class DocumentResource(Resource):
    """Resource for managing documents."""

    @classmethod
    @auth.require
    @profiletime
    @user_context
    @API.doc(
        params={
            "status": {
                "in": "query",
                "description": "Status filter. Valid statuses are: " + ",".join(VALID_STATUSES),
                "default": None
            },
            "createdAfter": {
                "in": "query",
                "description": "Created after filter: ",
                "default": None
            },
            "cursor": {
                "in": "query",
                "description": "Current page",
                "default": None
            },
        }
    )
    def get(cls, **kwargs):
        ### 1. Get user data
        current_app.logger.debug("1. Get user data")
        user: UserContext = kwargs["user"]
        is_verified = getattr(user, 'is_verified', False)
        current_app.logger.debug(f"Is verified - {is_verified}")
        person_identifier = user.token_info["personIdentifier"]
        tenant_key = user.tenant_key

        current_app.logger.debug("2. Check person identifier validity")
        match = re.findall(r"PNOBG-(\d{10})$", person_identifier)
        if not match:
            current_app.logger.debug(BusinessException)
            raise BusinessException(
                "Invalid Personal Identifier bound to user.", HTTPStatus.BAD_REQUEST
            )

        current_app.logger.debug("3. See if the user is verified")
        if not is_verified:
            current_app.logger.debug("4. Try and get an identity_request if exists")
            person_identifier = match[0]
            document_client = DocumentsService()
            identity_request = document_client.get_identity_request(
                person_identifier=person_identifier,
                tenant_key=tenant_key
            )

            if not identity_request:
                identity_request = document_client.create_identity_request(
                    person_identifier=person_identifier,
                    tenant_key=tenant_key
                )

            current_app.logger.debug("5. Spoof response")
            return_dict = {
                "documents": [
                    {
                        "created": identity_request.created.isoformat(),
                        "modified": identity_request.modified.isoformat(),
                        "expired": None,
                        "validUntill": identity_request.valid_untill.isoformat(),
                        "signed": None,
                        "rejected": None,
                        "applicationId": None,
                        "evrotrustThreadId": identity_request.thread_id,
                        "evrotrustTransactionId": identity_request.transaction_id,
                        "fileName": None,
                        "status": "pending",
                        "formioId": None,
                        "referenceNumber": None,
                        "fileUrl": None,
                    }
                ],
                "pagination": {
                    "cursor": None
                }
            }

            return (return_dict, HTTPStatus.OK)

        ## Paginate data
        current_app.logger.debug("4. User is verified, get cursor parameters")
        args = DocumentsListSchema().load(request.args) or {}
        new_cursor = args.get('cursor', None)
        if new_cursor:
            pagination_values = base64.urlsafe_b64decode(new_cursor)
            pagination_values = pagination_values.decode()
            pagination_values = json.loads(pagination_values)
        else:
            pagination_values = {
                "skip": 0,
                "limit": args.get("limit", 5)
            }

        skip = pagination_values.get('skip')
        limit = pagination_values.get("limit")

        current_app.logger.debug("5. Init formio client")
        formio_client = FormioServiceExtended()
        formio_token = formio_client.get_formio_access_token()
        file_formio_path = user.tenant_key + "-" + current_app.config.get('FORMIO_FILE_RESOURCE_PATH')

        status = args.get("status", [])
        if status:
            status = status.split(",")

        current_app.logger.debug("6. Get submissions, getting one more to see if there are further pages")
        related_file_submissions, formio_status = formio_client.get_submissions(
            file_formio_path,
            formio_token=formio_token,
            person_identifier=person_identifier,
            select=['_id', 'data', 'created', 'modified'],
            status=status,
            skip=skip,
            limit=limit + 1, ### Get one more to check if we have more pages
            created_after=args.get("created_after")
        )

        current_app.logger.debug("7. Encode new cursor")
        ### If the returned submissions (limit + 1) are more than the limit, there is another page
        if len(related_file_submissions) > limit:
            skip += limit
            next_cursor = base64.urlsafe_b64encode(
                    json.dumps(
                        {"skip": skip, "limit": limit}
                    ).encode()
                ).decode()
        else:
            next_cursor=None

        current_app.logger.debug("8. Format data")
        returned_submissions = []
        current_index = 0

        api_base = current_app.config.get("FORMSFLOW_API_URL")

        for submission in related_file_submissions:
            if current_index == limit:
                break
            current_index += 1
            submission_data = submission.get("data", {})
            file_list = submission_data.get("file", [])
            if not file_list:
                file_data = {}
            else:
                file_data = file_list[0]

            formio_id = submission.get("_id")
            returned_submissions.append(
                {
                    "created": submission.get("created"),
                    "modified": submission.get("modified"),
                    "expired": submission_data.get("expired"),
                    "validUntill": submission_data.get("validUntill"),
                    "signed": submission_data.get("signed"),
                    "rejected": submission_data.get("rejected"),
                    "applicationId": submission_data.get("applicationId"),
                    "evrotrustThreadId": submission_data.get("evrotrustThreadId"),
                    "evrotrustTransactionId": submission_data.get("evrotrustTransactionId"),
                    "fileName": file_data.get("name"),
                    "status": submission_data.get("status"),
                    "formioId": submission.get("_id"),

                    ### To add
                    "referenceNumber": submission_data.get("referenceId", "TODO"),
                    "fileUrl": f"{api_base}/documents/{formio_id}/serve",
                }
            )

        response, formio_status = {
                "documents": returned_submissions,
                "pagination": {
                    "cursor": next_cursor
                }
            }, formio_status
        return response, formio_status

@cors_preflight("GET,OPTIONS")
@API.route("/<string:submission_formio_id>/serve", methods=["GET", "OPTIONS"])
class DocumentServeBase64(Resource):

    @staticmethod
    @auth.require
    @profiletime
    @user_context
    @API.response(200, "OK:- Successful request.")
    @API.response( 400, "BAD_REQUEST:- Invalid request.")
    @API.response( 404, "NOT_FOUND:- No document found to check status.")
    def get(submission_formio_id: str, **kwargs):
        try:
            user: UserContext = kwargs["user"]
            person_identifier = user.token_info["personIdentifier"]
            formio_client = FormioServiceExtended()

            form_path = user.tenant_key + "-" + current_app.config.get('FORMIO_FILE_RESOURCE_PATH')
            formio_token = formio_client.get_formio_access_token()
            file_form_id = formio_client.fetch_form_id_by_path(form_path=form_path, formio_token=formio_token)

            response = formio_client.debug_get_submission(
                data={
                    "form_id": file_form_id,
                    "sub_id": submission_formio_id
                },
                formio_token=formio_token
            )

            submission_data = response.get("data")
            file_data = submission_data.get("file", [])[-1]
            user_id = submission_data.get("userId")

            if (person_identifier != user_id) or (not file_data):
                return {
                    "type": "Not found",
                    "message": f"No document with supplied formioId {submission_formio_id} found"
                }, HTTPStatus.NOT_FOUND

            file = file_data['url']
            file = re.split(";|,", file)

            ### If the string is as following - data:application/pdf;base64,JVBERi0xLjQKJdPr6eEKMSAwIG9ia...
            ### The above split will make a file corresponding to:
            ### 0 - data:application/pdf - file data type
            ### 1 - base64 - encoding type
            ### 2 - JVBERi0xLjQKJdPr6eEKMSAw... -

            image_binary = base64.b64decode(file[2])
            response = make_response(image_binary)
            current_app.logger.debug(file_data['name'])
            response.headers.set('Content-Type', file_data['type'])
            response.headers.set(
                'Content-Disposition', 'inline', filename=file_data['name'].encode("utf-8"))
            return response

        except BusinessException as err:
            current_app.logger.error(err.error)
            current_app.logger.error(err.status_code)
            if err.status_code == 400:
                response, status = {
                    "type": "Not found",
                    "message": f"No document with supplied formioId {submission_formio_id} found",
                }, HTTPStatus.BAD_REQUEST
            else:
                response, status = {
                    "type": "Bad request error",
                    "message": "Internal server error",
                }, HTTPStatus.BAD_REQUEST

            return response, status

@cors_preflight("GET,OPTIONS")
@API.route("/<string:submission_formio_id>/status", methods=["GET", "OPTIONS"])
class DocumentCheckStatus(Resource):

    @staticmethod
    @auth.require
    @profiletime
    @user_context
    @API.response(200, "OK:- Successful request.")
    @API.response( 400, "BAD_REQUEST:- Invalid request.")
    @API.response( 404, "NOT_FOUND:- No document found to check status.")
    def get(submission_formio_id: str, **kwargs):
        try:
            ### 0. Get user data
            user: UserContext = kwargs["user"]
            person_identifier = user.token_info["personIdentifier"]
            current_app.logger.debug(f"Person Identifier - {person_identifier}")

            match = re.findall(r"PNOBG-(\d{10})$", person_identifier)
            if not match:
                raise BusinessException(
                    "Invalid Personal Identifier bound to user.", HTTPStatus.BAD_REQUEST
                )

            ### 1. Get document resource by submission_formio_id and pnobg
            formio_client = FormioServiceExtended()
            formio_file_resource_path = user.tenant_key + "-" + current_app.config.get('FORMIO_FILE_RESOURCE_PATH')
            formio_token = formio_client.get_formio_access_token()
            generated_files_formio_form_id = formio_client.fetch_form_id_by_path(
                form_path=formio_file_resource_path,
                formio_token=formio_token
            )

            generated_file_resource = formio_client.debug_get_submission(
                data={
                    'form_id': generated_files_formio_form_id,
                    'sub_id': submission_formio_id
                },
                formio_token=formio_token
            )

            ### 2. Check document status in eurotrust
            generated_file_resource_data = generated_file_resource.get("data")
            generated_file_resource_transaction_id = generated_file_resource_data.get("evrotrustTransactionId")

            eurotrust_client = EurotrustIntegrationsService()
            response = eurotrust_client.check_document_status(transaction_id=generated_file_resource_transaction_id)
            eurotrust_status = response["status"]
            status = DocumentStatus.query.filter_by(eurotrust_status=eurotrust_status).first()

            ### 3. Update status
            if not status:
                raise BusinessException(
                    f"No status found {eurotrust_status} in our system",
                    HTTPStatus.NOT_FOUND
                )

            document_service_client = DocumentsService()
            update_response = document_service_client.update_document_status_in_formio(
                formio_id=submission_formio_id,
                status=status
            )

            return (update_response, HTTPStatus.OK)
        except BusinessException as err:
            response, status = {
                "type": "Bad request error",
                "message": (err),
            }, HTTPStatus.BAD_REQUEST

            current_app.logger.warning(response)
            current_app.logger.warning(err)

            return response, status

@cors_preflight("GET,OPTIONS")
@API.route("/authenticate/<string:transaction_id>", methods=["GET", "OPTIONS"])
class AuthenticateResource(Resource):

    @staticmethod
    @auth.require
    @profiletime
    @user_context
    @API.response(200, "OK:- Successful request.")
    @API.response( 400, "BAD_REQUEST:- Invalid request.")
    @API.response( 404, "NOT_FOUND:- No document found to check status.")
    def get(transaction_id: str,**kwargs):
        try:
            user: UserContext = kwargs["user"]
            user_keycloak_id = user.token_info["sub"]

            eurotrust_client = EurotrustIntegrationsService()
            response = eurotrust_client.check_document_status(transaction_id=transaction_id)
            current_app.logger.debug(response.get("status"))
            status = DocumentStatus.query.filter_by(eurotrust_status=response.get("status")).first()
            current_app.logger.debug(status)

            if not status:
                return {
                    "type": "Invalid Status",
                    "message": "Invalid status returned from EuroTrust",
                }, HTTPStatus.BAD_REQUEST

            if status.formio_status != "signed":
                return {
                    "type": "Not signed",
                    "message": "Status for transaction is not signed",
                }, HTTPStatus.BAD_REQUEST

            file_list = eurotrust_client.get_signed_file(transaction_id=transaction_id)

            signed_file_dict = file_list[0]
            signed_file_content = signed_file_dict["content"]
            base64_bytes = BytesIO(base64.b64decode(signed_file_content))

            reader = PdfReader(base64_bytes)
            meta = reader.metadata
            keywords_string = meta.get("/Keywords")

            base64_bytes.close()
            if keywords_string and user_keycloak_id:
                keycloak_client = KeycloakAdminAPIService()
                initial_client = keycloak_client.get_request(url_path=f"users/{user_keycloak_id}")

                xml_string = base64.b64decode(keywords_string)
                xml_tree = ElementTree.ElementTree(ElementTree.fromstring(xml_string))
                root = xml_tree.getroot()

                attributes = initial_client.get("attributes")
                attributes["isVerified"] = True

                for child in root:
                    if not child.tag.startswith("pic"):
                        attributes["evroTrust" + child.tag.capitalize()] = child.text

                response = keycloak_client.update_request(
                    url_path=f"users/{user_keycloak_id}",
                    data={
                        "attributes": attributes
                    }
                )

            return (
                {
                    "status": status.formio_status
                },
                HTTPStatus.OK
            )

        except EurotrustException as err:
            current_app.logger.warning(err)
            return err.error, err.status_code


import random
from turtle import Turtle
import constants

BUFFER_X_FROM_BORDER = (constants.SCREEN_WIDTH / 2) - 20
BUFFER_Y_FROM_BORDER = (constants.SCREEN_HEIGHT / 2) - 20

class Food(Turtle):

    def __init__(self):
        super().__init__()
        self.penup()
        self.shape("circle")
        self.shapesize(stretch_len=0.7, stretch_wid=0.7)
        # self.shapesize(stretch_len=1, stretch_wid=1)
        self.color("yellow")
        self.speed("fastest")
        self.generate()

    def generate(self):
        random_x = random.randint(BUFFER_X_FROM_BORDER * -1, BUFFER_X_FROM_BORDER)
        random_y = random.randint(BUFFER_Y_FROM_BORDER * -1, BUFFER_Y_FROM_BORDER)
        self.goto(random_x, random_y)


from django.db import models
from django import forms
from django.contrib.auth.models import AbstractUser
from django.db.models import Q

class User(AbstractUser):

    USER_TYPE_CHOICES = (
        (1,'patient'),
        (2,'doctor'),
        (3,'staff'),
    )
    user_type = models.PositiveSmallIntegerField(null=True,choices = USER_TYPE_CHOICES)

    date_of_birth = models.DateField(auto_now=False, auto_now_add=False, null=True)
    phone = models.CharField(null=True, max_length=15)

    GENDER_CHOICES = (
        ('Male', 'Male'),
        ('Female', 'Female'),
        ('Other', 'Other'),
    )
    gender = models.CharField(
        max_length = 6,
        choices = GENDER_CHOICES,
        null = True,
        default = 'Other',
    )

    BLOOD_GROUP_CHOICES = (
        ('A+','A+'),
        ('A-','A-'),
        ('B+','B+'),
        ('B-','B-'),
        ('O+','O+'),
        ('O-','O-'),
        ('AB+','AB+'),
        ('AB-','AB-'),
        ('Other','Other'),
    )
    blood_group = models.CharField(
        max_length = 5,
        choices = BLOOD_GROUP_CHOICES,
        null = True,
        default = 'Other',
    )

class Appointment(models.Model):
    # pass
    id = models.AutoField(primary_key = True)
    patient = models.ForeignKey(
        User,
        on_delete = models.CASCADE,
        limit_choices_to = Q(user_type = 1), # type 1 = patient
        related_name = 'patient',
        null = True,
    )
    doctor = models.ForeignKey(
        User,
        on_delete = models.CASCADE,
        limit_choices_to = Q(user_type = 2), # type 2 = doctor
        related_name = 'doctor',
        null = True,
    )
    date_time = models.DateTimeField(auto_now = True)
    blood_pressure = models.CharField(max_length = 10, null = True)
    breath_rate = models.PositiveSmallIntegerField(null = True) # units: bpm
    pulse_rate = models.PositiveSmallIntegerField(null = True) # units: bpm
    body_temperature = models.DecimalField(max_digits = 5, decimal_places = 2, null=True)
    report = models.TextField(max_length = 500, null = True)
    prescription = models.TextField(max_length = 500, null = True)
    prognosis = models.TextField(max_length = 500, null = True)


from django.urls import path,re_path
from . import views

urlpatterns = [
    path('neoLabel/', views.labelAll),
    path('neoType/', views.typeAll),
    path('neoMatch/<str:label>/<str:entity>/', views.matchEntity),
    # path('neoRel/<str:label>/<str:entity>/<str:rel>/', views.matchRel),
    path('neoTypeEntity/', views.matchRel),
    # path('neomerge/', views.neoMerge.as_view()),
    path('neoEntity/', views.entityAll),
    # path('neoEntityType/<str:label1>/<str:entity>/<str:label2>/', views.entityTypeAll),
    path('neoEntityType/', views.entityTypeAll),
    path('neoLevel/', views.levelAll),
    path('neoEntity1Entity2/', views.entity1Entity2),
    # re_path(r'^neoRel/<str:label>/<str:entity>/(?P<rel>\S*)/$', views.matchRel),
]


def trojkat(bok_a, bok_b, bok_c, wysokosc_a):
    obwod = bok_a + bok_b + bok_c
    pole = (bok_a * wysokosc_a) / 2
    return obwod, pole

# kwadrat, prostokat dla studenta 1
def kwadrat(bok):
    obwod = 4*bok
    pole = bok**2
    return obwod, pole

def prostokat(bok_a, bok_b):
    obwod = (2*bok_a)+(2*bok_b)
    pole = bok_a*bok_b
    return obwod, pole

# rownoleglobok i romb dla studenta 2
def rownoleglobok(bok_a, bok_b, wysokosc_a):
    obwod = 2*bok_a + 2*bok_b
    pole = bok_a*wysokosc_a
    return obwod, pole

def romb(bok, wysokosc):
    obwod = 4*bok
    pole = bok*wysokosc
    return obwod, pole

# trapez i kolo dla studenta 3
def trapez(bok_a, bok_b, bok_c, bok_d, wysokosc_a):
    obwod = bok_a + bok_b + bok_c + bok_d
    pole = ((bok_a + bok_b) * wysokosc_a)/ 2
    return obwod, pole

def kolo(promien):
    import math
    pi_zmienna = math.pi
    obwod = 2 * promien * pi_zmienna
    pole = pi_zmienna * promien**2
    return obwod, pole

import math
assert trojkat(10, 15, 16, 8) == (41, 40)
assert trapez(10, 15, 7, 14, 2) == (46, 25)
assert kolo(2) == (4*math.pi, 4*math.pi)
assert trojkat(6, 7, 10, 5) == (23, 15)
assert trapez(20, 17, 12, 8, 6) == (57, 111)
assert kolo(3) == (6*math.pi, 9*math.pi)
assert kwadrat(20) == (80, 400)
assert kwadrat(10) == (40, 100)
assert prostokat(12, 10) == (44, 120)
assert prostokat(6, 8) == (28, 48)
assert rownoleglobok(6, 5, 2) == (22, 12)
assert rownoleglobok(15, 8, 3) == (46, 45)
assert romb(10, 5) == (40, 50)
assert romb(13, 7) == (52, 91)


class YOLODatasetYaml:
    '''
    This class creates the `dataset.yaml` file to train the YOLOv8 model.\n
    `Params`:
    - train_path: the path to training images and labels (you give just the directory that contains the two folders)
    - valid_path: the path to valid images and labels (you give just the directory that contains the two folders)
    - nc: the number of classes to train
    - class_names: here you can enter as much as class names as you want to train, the number of class names should be equal to the number of classes given before\n

    To create the dataset.yaml file, you need to call the method `create_yaml` and also give the path to the location to save the yaml file.\n
    \n\n
    #### Example usage:
    from pycad.datasets import YOLODatasetYaml

    config = YOLODatasetYaml("path/to/train", "path/to/valid", 3, "t1", "t2", "t3")\n
    config.create_yaml("dataset.yaml")
    '''
    def __init__(self, train_path, valid_path, nc, *class_names):
        self.train_path = train_path
        self.valid_path = valid_path
        self.nc = nc
        self.names = []
        self.set_class_names(*class_names)

    def set_class_names(self, *class_names):
        if self.nc != len(class_names):
            raise ValueError(f"The number of classes (nc={self.nc}) must be equal to the number of class names provided ({len(class_names)}).")
        self.names = list(class_names)

    def save(self, save_path):
        with open(save_path, 'w') as outfile:
            outfile.write(f"train: {self.train_path}\n")
            outfile.write(f"val: {self.valid_path}\n")
            outfile.write("\n")  # Adding a blank line
            outfile.write(f"nc: {self.nc}\n")
            outfile.write("names: " + str(self.names).replace("'", '"') + "\n")

    def create_yaml(self, save_path):
        self.save(save_path)


#HWPython09_02_exam04_empList04_정승현.py

'''검색할 연봉 하한값을 입력하세요 : 2500
   검색할 연봉 상한값을 입력하세요 : 3000
   연봉 2500 ~ 3000 인 사원 리스트.

  이름 연봉

'''

import csv
file = open('./_dataSet01/emp2.csv','r')
emp_csv = csv.reader(file)
list_emp=list(emp_csv)

a = int(input('검색할 연봉의 하한값을 입력하세요.:'))
b = int(input('검색할 연봉의 상한값을 입력하세요.:'))

print(f'\n연봉 {a}~{b}인 사원 리스트')
print('='*30)
print('이름\t연봉')
print('='*30)

for x in range(len(list_emp)):
	if int(list_emp[x][-3]) >= a and int(list_emp[x][-3]) <= b:
		print(f'{list_emp[x][1]}\t{list_emp[x][-3]}')


class Solution(object):
    def trap(self, height):
        """
        :type height: List[int]
        :rtype: int
        """
#   1. Initialize left, right pointers to the first and last bars of the height array, respectively.
#   2. Initialize variables left_max and right_max to zero.
#   3. While the left pointer is less than or equal to the right pointer, compare the heights of the bars pointed to by the left and right pointers.
#   4. If the height of the left bar is less than or equal to the height of the right bar, check if the height of the left bar is greater than the left_max variable. If it is, update left_max, otherwise, add left_max - height[left] to the "water" variable. Move the left pointer to the next bar.
#   5. If the height of the right bar is less than the height of the left bar, check if the height of the right bar is greater than the right_max variable. If it is, update right_max, otherwise, add right_max - height[right] to the "water" variable. Move the right pointer to the previous bar.
#   6. Return the value of the "water" variable.
        if not height:
            return 0
        left, right, left_max, right_max, water = 0, len(height) - 1, 0, 0, 0
        while left <= right:
            if height[left] <= height[right]:
                if height[left] > left_max:
                    left_max = height[left]
                else:
                    water += left_max - height[left]
                left += 1
            else:
                if height[right] > right_max:
                    right_max = height[right]
                else:
                    water += right_max - height[right]
                right -= 1
        return water


# python has several functions for creating reading updating and deleting(CRUD)
# THE KEY FUNCTION FOR WORKING WITH FILES IS open()
# the open function takes two parameters
# 1.file name- file to be opened
# 2. mode to open the file with

# "r" - Read - Default value. Opens a file for reading, error if the file does not exist

# "a" - Append - Opens a file for appending, creates the file if it does not exist

# "w" - Write - Opens a file for writing, creates the file if it does not exist

# "x" - Create - Creates the specified file, returns an error if the file exists
try:
	f = open('text.txt','a')
except:
	print('text.txt file does not exist')
try:
	f = open('index.html','w')
except:
	print('not successful')
try:
	f = open('demo2.py','x')
except:
	print('successful')


# -*- coding: utf-8 -*-
from .models import MenuItem
from django.template.loader import render_to_string

def menuhin_breadcrumbs(request):
    """
    How breadcrumbs will be rendered on the site, to a depth of grandchild.
    """
    node0 = MenuItem(title='default', site_id=1,
                     uri='/', depth=0)
    node0.clean()
    node1 = MenuItem(title='child', site_id=1,
                     uri='/child/', depth=1)
    node1.clean()
    node2 = MenuItem(title='grandchild', site_id=1,
                     uri='/grandchild/', depth=2)
    node2.clean()
    return render_to_string('menuhin/show_breadcrumbs.html', {
        'ancestor_nodes': [node0, node1],
        'menu_node': node2,
    })


import argparse
import sys

import related_person
from related_person import Gender, RelatedPerson, RelatedPersonError

class RawPersonRecord(object):
    FIELDS = 5
    def __init__(self, id, name, father_id, mother_id, gender, row):
        self.id = id
        self.name = name
        self.father_id = father_id
        self.mother_id = mother_id
        self.gender = gender
        self.row = row

    @staticmethod
    def make_from_line(line, row):
        l = line.strip().split('\t')
        if len(l) != RawPersonRecord.FIELDS:
            raise ValueError("row {}: has {} fields, not {}".format(row, len(l), RawPersonRecord.FIELDS))
        t = tuple(l+[row])
        return RawPersonRecord(*t)

class LoadPeople(object):
    NULL_ID = '0'

    def __init__(self):
        self.buffer = []
        self.people_index = {}

    @staticmethod
    def all_people(people_index):
        print()
        for id in sorted(people_index.keys()):
            print(str(people_index[id]))

    def phase1(self):
        parser = argparse.ArgumentParser(description="Load related people from a file")
        parser.add_argument('--log_file', '-l', type=str, help="File for logging data")
        parser.add_argument('-p', '--people_data', required=True, type=argparse.FileType('r'),
            help="File with related people, tab delimited; can be provided on stdin")
        return parser.parse_args()

    def phase2(self, people_data):
        # Phase 2:
        row = 0
        errors = []
        bad_ids = set()
        for line in people_data:
            row += 1
            try:
                self.buffer.append(RawPersonRecord.make_from_line(line, row))
            except ValueError as e:
                errors.append(str(e))

        # check IDs, genders, & create RelatedPersons
        for raw_person in self.buffer:
            try:
                # check for dupes
                if raw_person.id in self.people_index:
                    bad_ids.add(raw_person.id)
                    del self.people_index[raw_person.id]
                if raw_person.id in bad_ids:
                    raise RelatedPersonError("duplicate ID: {}".format(raw_person.id))

                # get and check gender
                gender = Gender.get_gender(raw_person.gender)

                # make RelatedPerson
                related_person = RelatedPerson(raw_person.id, raw_person.name, gender)
                self.people_index[raw_person.id] = related_person
            except RelatedPersonError as e:
                errors.append("row {}: {}".format(raw_person.row, str(e)))

        if errors:
            sys.stderr.write('\n- individual errors -\n')
            sys.stderr.write('\n'.join(errors))
            sys.stderr.write('\n')

    def check_parent(self, raw_person, parent):
        if parent == 'mother':
            if raw_person.mother_id != LoadPeople.NULL_ID:
                if raw_person.mother_id not in self.people_index:
                    raise RelatedPersonError("{} missing mother {}".format(raw_person.id, raw_person.mother_id))
        elif parent == 'father':
            if raw_person.father_id != LoadPeople.NULL_ID:
                if raw_person.father_id not in self.people_index:
                    raise RelatedPersonError("{} missing father {}".format(raw_person.id, raw_person.father_id))

    def set_parent(self, raw_person, parent):
        related_person = self.people_index[raw_person.id]
        if parent == 'mother':
            if raw_person.mother_id != LoadPeople.NULL_ID:
                mother = self.people_index[raw_person.mother_id]
                related_person.set_mother(mother)
        elif parent == 'father':
            if raw_person.father_id != LoadPeople.NULL_ID:
                father = self.people_index[raw_person.father_id]
                related_person.set_father(father)

    def phase3(self):
        # Phase 3:
        errors = []
        bad_ids = set()

        for raw_person in self.buffer:
            if raw_person.id in self.people_index:

                # check existence of parents
                for parent in ['mother', 'father']:
                    try:
                        self.check_parent(raw_person, parent)
                    except RelatedPersonError as e:
                        errors.append("row {}: {}".format(raw_person.row, str(e)))
                        bad_ids.add(raw_person.id)

                # set parents, which checks their gender
                if raw_person.id not in bad_ids:
                    for parent in ['mother', 'father']:
                        try:
                            self.set_parent(raw_person, parent)
                        except RelatedPersonError as e:
                            errors.append("row {}: for {} {}".format(raw_person.row, raw_person.id, str(e)))
                            bad_ids.add(raw_person.id)

        # delete all the bad people
        for bad_id in bad_ids:
            del self.people_index[bad_id]

        if errors:
            sys.stderr.write('\n- relatedness errors -\n')
            sys.stderr.write('\n'.join(errors))
            sys.stderr.write('\n')

    def main(self):
        args = self.phase1()
        self.phase2(args.people_data)
        self.phase3()
        self.all_people(self.people_index)

LoadPeople().main()