from Appconfig import Appconfig
import re
import os
import xml.etree.cElementTree as ET
from PyQt5 import QtWidgets

class AutoSchematic(QtWidgets.QWidget):

    def __init__(self, parent, modelname):
        QtWidgets.QWidget.__init__(self)
        self.parent = parent
        self.modelname = modelname.split('.')[0]
        self.template = Appconfig.kicad_sym_template.copy()
        self.xml_loc = Appconfig.xml_loc
        self.lib_loc = Appconfig.lib_loc
        if os.name == 'nt':
            eSim_src = Appconfig.src_home
            inst_dir = eSim_src.replace('\\eSim', '')
            self.kicad_nghdl_sym = \
                inst_dir + '/KiCad/share/kicad/symbols/eSim_Nghdl.kicad_sym'
        else:
            self.kicad_nghdl_sym = \
                '/usr/share/kicad/symbols/eSim_Nghdl.kicad_sym'
        self.parser = Appconfig.parser_nghdl

    def createKicadSymbol(self):
        xmlFound = None
        for root, dirs, files in os.walk(self.xml_loc):
            if (str(self.modelname) + '.xml') in files:
                xmlFound = root
                print(xmlFound)
        if xmlFound is None:
            self.getPortInformation()
            self.createXML()
            self.createSym()
        elif (xmlFound == os.path.join(self.xml_loc, 'Nghdl')):
            print('Library already exists...')
            ret = QtWidgets.QMessageBox.warning(
                self.parent, "Warning", '''Library files for this model''' +
                ''' already exist. Do you want to overwrite it?

                If yes press ok, else cancel it and ''' +
                '''change the name of your vhdl file.''',
                QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.Cancel
            )
            if ret == QtWidgets.QMessageBox.Ok:
                print("Overwriting existing libraries")
                self.getPortInformation()
                self.createXML()
                self.removeOldLibrary()     # Removes the existng library
                self.createSym()
            else:
                print("Exiting Nghdl")
                quit()
        else:
            print('Pre existing library...')
            ret = QtWidgets.QMessageBox.critical(
                self.parent, "Error", '''A standard library already ''' +
                '''exists with this name.
Please change the ''' +
                '''name of your vhdl file and upload it again.''',
                QtWidgets.QMessageBox.Ok
            )

            # quit()

    def getPortInformation(self):
        '''
            getting the port information here
        '''
        portInformation = PortInfo(self)
        portInformation.getPortInfo()
        self.portInfo = portInformation.bit_list
        self.input_length = portInformation.input_len

    def createXML(self):
        '''
            creating the XML files in eSim /library/modelParamXML/Nghdl
        '''
        cwd = os.getcwd()
        xmlDestination = os.path.join(self.xml_loc, 'Nghdl')
        self.splitText = ""
        for bit in self.portInfo[:-1]:
            self.splitText += bit + "-V:"
        self.splitText += self.portInfo[-1] + "-V"

        print("changing directory to ", xmlDestination)
        os.chdir(xmlDestination)

        root = ET.Element("model")
        ET.SubElement(root, "name").text = self.modelname
        ET.SubElement(root, "type").text = "Nghdl"
        ET.SubElement(root, "node_number").text = str(len(self.portInfo))
        ET.SubElement(root, "title").text = (
                            "Add parameters for " + str(self.modelname))
        ET.SubElement(root, "split").text = self.splitText
        param = ET.SubElement(root, "param")
        ET.SubElement(param, "rise_delay", default="1.0e-9").text = (
                                    "Enter Rise Delay (default=1.0e-9)")
        ET.SubElement(param, "fall_delay", default="1.0e-9").text = (
                                    "Enter Fall Delay (default=1.0e-9)")
        ET.SubElement(param, "input_load", default="1.0e-12").text = (
                                    "Enter Input Load (default=1.0e-12)")
        ET.SubElement(param, "instance_id", default="1").text = (
                                    "Enter Instance ID (Between 0-99)")
        tree = ET.ElementTree(root)
        tree.write(str(self.modelname) + '.xml')
        print("Leaving the directory ", xmlDestination)
        os.chdir(cwd)

    def findBlockSize(self):
        '''
            Calculates the maximum between input and output ports
        '''
        ind = self.input_length
        return max(
            self.char_sum(self.portInfo[:ind]),
            self.char_sum(self.portInfo[ind:])
        )

    def char_sum(self, ls):
        return sum([int(x) for x in ls])

    def removeOldLibrary(self):
        '''
            removing the old library
        '''
        cwd = os.getcwd()
        os.chdir(self.lib_loc)
        print("Changing directory to ", self.lib_loc)
        sym_file = open(self.kicad_nghdl_sym)
        lines = sym_file.readlines()
        lines = lines[0:-2]
        sym_file.close()

        output = []
        line_reading_flag = False

        for line in lines:
            if line.startswith("(symbol"):      # Eeschema template start
                if line.split()[1] == f"\"{self.modelname}\"":
                    line_reading_flag = True
            if not line_reading_flag:
                output.append(line)
            if line.startswith("))"):           # Eeschema template end
                line_reading_flag = False

        sym_file = open(self.kicad_nghdl_sym, 'w')
        for line in output:
            sym_file.write(line)
        sym_file.close()
        os.chdir(cwd)
        print("Leaving directory, ", self.lib_loc)

    def createSym(self):
        self.dist_port = 2.54         # Distance between two ports (mil)
        self.inc_size = 2.54          # Increment size of a block (mil)
        cwd = os.getcwd()
        os.chdir(self.lib_loc)
        print("Changing directory to ", self.lib_loc)

        # Removing ")" from "eSim_Nghdl.kicad_sym"
        file = open(self.kicad_nghdl_sym, "r")
        content_file = file.read()
        new_content_file = content_file[:-2]
        file.close()
        file = open(self.kicad_nghdl_sym, "w")
        file.write(new_content_file)
        file.close()

        # Appending new schematic block
        sym_file = open(self.kicad_nghdl_sym, "a")
        line1 = self.template["start_def"]
        line1 = line1.split()
        line1 = [w.replace('comp_name', self.modelname) for w in line1]
        self.template["start_def"] = ' '.join(line1)

        if os.stat(self.kicad_nghdl_sym).st_size == 0:
            sym_file.write(
                "(kicad_symbol_lib (version 20211014) " +
                "(generator kicad_symbol_editor)" + "\n\n"
            )  # Eeschema starter code

        sym_file.write(
            self.template["start_def"] + "\n" + self.template["U_field"] + "\n"
        )

        line3 = self.template["comp_name_field"]
        line3 = line3.split()
        line3 = [w.replace('comp_name', self.modelname) for w in line3]
        self.template["comp_name_field"] = ' '.join(line3)

        sym_file.write(self.template["comp_name_field"] + "\n")

        line4 = self.template["blank_field"]
        line4_1 = line4[0]
        line4_2 = line4[1]
        line4_1 = line4_1.split()
        line4_1 = [w.replace('blank_quotes', '""') for w in line4_1]
        line4_2 = line4_2.split()
        line4_2 = [w.replace('blank_quotes', '""') for w in line4_2]
        line4[0] = ' '.join(line4_1)
        line4[1] = ' '.join(line4_2)
        self.template["blank_qoutes"] = line4

        sym_file.write(line4[0] + "\n" + line4[1] + "\n")

        draw_pos = self.template["draw_pos"]
        draw_pos = draw_pos.split()

        draw_pos = \
            [w.replace('comp_name', f"{self.modelname}_0_1") for w in draw_pos]
        draw_pos[8] = str(
            float(draw_pos[8]) + float(self.findBlockSize() * self.inc_size)
        )
        draw_pos_rec = draw_pos[8]

        self.template["draw_pos"] = ' '.join(draw_pos)

        sym_file.write(
            self.template["draw_pos"] + "\n" + self.template["start_draw"] +
            " \"" + f"{self.modelname}_1_1\"" + "\n"
        )

        input_port = self.template["input_port"]
        input_port = input_port.split()
        output_port = self.template["output_port"]
        output_port = output_port.split()
        inputs = self.portInfo[0: self.input_length]
        outputs = self.portInfo[self.input_length:]

        inputs = self.char_sum(inputs)
        outputs = self.char_sum(outputs)

        total = inputs + outputs

        port_list = []

        # Set input & output port
        input_port[4] = draw_pos_rec
        output_port[4] = draw_pos_rec

        for i in range(total):
            if (i < inputs):
                input_port[9] = f"\"in{str(i + 1)}\""
                input_port[13] = f"\"{str(i + 1)}\""
                input_port[4] = \
                    str(float(input_port[4]) - float(self.dist_port))
                input_list = ' '.join(input_port)
                port_list.append(input_list)

            else:
                output_port[9] = f"\"out{str(i - inputs + 1)}\""
                output_port[13] = f"\"{str(i + 1)}\""
                output_port[4] = \
                    str(float(output_port[4]) - float(self.dist_port))
                output_list = ' '.join(output_port)
                port_list.append(output_list)

        for ports in port_list:
            sym_file.write(ports + "\n")
        sym_file.write(
            self.template["end_draw"] + "\n\n" + ")"
        )
        sym_file.close()
        os.chdir(cwd)

        print('Leaving directory, ', self.lib_loc)
        QtWidgets.QMessageBox.information(
            self.parent, "Symbol Added",
            '''Symbol details for this model is added to the \'''' +
            '''eSim_Nghdl.kicad_sym\' in the KiCad shared directory.''',
            QtWidgets.QMessageBox.Ok
        )

class PortInfo:
    '''
        The class contains port information
    '''
    def __init__(self, model):
        self.modelname = model.modelname
        self.model_loc = os.path.join(
            model.parser.get('NGHDL', 'DIGITAL_MODEL'), 'ghdl'
        )
        self.bit_list = []
        self.input_len = 0

    def getPortInfo(self):
        info_loc = os.path.join(self.model_loc, self.modelname + '/DUTghdl/')
        input_list = []
        output_list = []
        read_file = open(info_loc + 'connection_info.txt', 'r')
        data = read_file.readlines()
        read_file.close()

        for line in data:
            if re.match(r'^\s*$', line):
                pass
            else:
                in_items = re.findall(
                    "IN", line, re.MULTILINE | re.IGNORECASE
                )
                out_items = re.findall(
                    "OUT", line, re.MULTILINE | re.IGNORECASE
                )
            if in_items:
                input_list.append(line.split())
            if out_items:
                output_list.append(line.split())

        for in_list in input_list:
            self.bit_list.append(in_list[2])
        self.input_len = len(self.bit_list)
        for out_list in output_list:
            self.bit_list.append(out_list[2])


# -*- coding: utf-8 -*-
# @File    : ResNet50.py
# @Author  : Hua Guo
# @Time    : 2020/3/8 上午8:26
# @Disc    :
from typing import List
import tensorflow as tf
from tensorflow.keras import layers, Model

class ConvBNActivation(Model):
    """
    conv + batch nomalization + relu
    """
    def __init__(self, filter: int, kernel_size: List[int], padding: str, activation: str, stride=None) -> None:
        super(ConvBNActivation, self).__init__()
        if stride is None:
            stride = [1, 1]
        self.conv = layers.Conv2D(
            filters=filter,
            kernel_size=kernel_size,
            padding=padding,
            strides=stride
        )
        self.bn = layers.BatchNormalization()
        self.activation = layers.Activation(activation)

    def call(self, inputs, training=None, mask=None):
        x = self.conv(inputs)
        x = self.bn(x)
        x = self.activation(x)
        return x

class IdentityBlock(Model):
    """S
    In the case where the input activation has the same dimension as the output activation
    Structures are as follow:
        3 conv in the main path
        1 identity in the shortcut path
    """
    def __init__(self, kernel_size: int, filters: List[int]) -> None:
        super(IdentityBlock, self).__init__()
        f1, f2, f3 = filters

        self.con_bn_ac1 = ConvBNActivation(filter=f1, kernel_size=[1, 1], padding="valid", activation="relu")
        self.con_bn_ac2 = ConvBNActivation(filter=f2, kernel_size=[kernel_size, kernel_size], padding="same", activation="relu")
        self.conv = layers.Conv2D(filters=f3, kernel_size=[1, 1], padding="same")
        self.bn = layers.BatchNormalization()
        self.activation = layers.Activation("relu")

    def call(self, inputs, training=None, mask=None):
        x = self.con_bn_ac1(inputs)
        for l in [
            self.con_bn_ac2,
            self.conv,
            self.bn
        ]:
            x = l(x)
        x = tf.math.add(x, inputs)
        return self.activation(x)

class ConvBlock(Model):
    """
    In the case where the dimension of the the input activation is different from that of the output activation
    Structures are as follow:
        3 conv in the main path
        1 conv in the shortcut path
    """
    def __init__(self, mid_kernel_size: int, shortcut_stride: int, filters: List[int]):
        super(ConvBlock, self).__init__()
        f1, f2, f3 = filters
        self.con_bn_ac1 = ConvBNActivation(filter=f1, kernel_size=[1, 1], padding="valid", activation="relu",
                                           stride=[shortcut_stride, shortcut_stride])
        self.con_bn_ac2 = ConvBNActivation(filter=f2, kernel_size=[mid_kernel_size, mid_kernel_size],
                                           padding="same", activation="relu")
        self.conv = layers.Conv2D(filters=f3, kernel_size=[1, 1], padding="same")
        self.bn = layers.BatchNormalization()
        self.activation = layers.Activation("relu")
        self.conv_shortcut = layers.Conv2D(filters=f3, kernel_size=[1, 1], padding="valid",
                                           strides=[shortcut_stride, shortcut_stride])
        self.bn_shortcut = layers.BatchNormalization()

    def call(self, inputs, training=None, mask=None):
        # shortcut branch
        x_short_cut = self.conv_shortcut(inputs)
        x_short_cut = self.bn_shortcut(x_short_cut)
        # main path
        x = self.con_bn_ac1(inputs)
        for l in [
            self.con_bn_ac2,
            self.conv,
            self.bn
        ]:
            x = l(x)
        x = tf.math.add(x, x_short_cut)
        return self.activation(x)

class ResNet50(Model):
    """
    Residual NN with 50 layers
    Structures stages are as follow:
        0. zero padding
        1. conv + bn + Relu + max pooling
        2. Convblock + IdentityBlock*2
        3. Convblock + IdentityBlock*2
        4, Convblock + IdentityBlock*5
        5, Convblock + IdentityBlock*2
        6. avg pooling + flatten + fc
    """
    def __init__(self, class_num: int) -> None:
        super(ResNet50, self).__init__()
        self.class_num = class_num
        # stage 1
        self.con_bn_ac = ConvBNActivation(
            filter=64,
            kernel_size=[7, 7],
            activation="relu",
            padding="valid"
        )
        self.max_pooling = layers.MaxPool2D((3, 3), strides=(2, 2))
        # stage 2
        self.conv_block1 = ConvBlock(
            mid_kernel_size=3,
            filters=[64, 64, 256],
            shortcut_stride=1
        )
        self.identity_block1 = IdentityBlock(
            kernel_size=3,
            filters=[64, 64, 256]
        )
        self.identity_block2 = IdentityBlock(
            kernel_size=3,
            filters=[64, 64, 256]
        )
        # stage 3
        self.conv_block2 = ConvBlock(
            mid_kernel_size=3,
            filters=[128, 128, 512],
            shortcut_stride=2
        )
        self.identity_block3 = IdentityBlock(
            kernel_size=3,
            filters=[128, 128, 512]
        )
        self.identity_block4 = IdentityBlock(
            kernel_size=3,
            filters=[128, 128, 512]
        )
        self.identity_block5 = IdentityBlock(
            kernel_size=3,
            filters=[128, 128, 512]
        )
        # stage 4
        self.conv_block3 = ConvBlock(
            mid_kernel_size=3,
            filters=[256, 256, 1024],
            shortcut_stride=2
        )
        self.identity_block6 = IdentityBlock(
            kernel_size=3,
            filters=[256, 256, 1024]
        )
        self.identity_block7 = IdentityBlock(
            kernel_size=3,
            filters=[256, 256, 1024]
        )
        self.identity_block8 = IdentityBlock(
            kernel_size=3,
            filters=[256, 256, 1024]
        )
        self.identity_block9 = IdentityBlock(
            kernel_size=3,
            filters=[256, 256, 1024]
        )
        self.identity_block10 = IdentityBlock(
            kernel_size=3,
            filters=[256, 256, 1024]
        )
        # stage 5
        self.conv_block4 = ConvBlock(
            mid_kernel_size=3,
            filters=[512, 512, 2048],
            shortcut_stride=2
        )
        self.identity_block11 = IdentityBlock(
            kernel_size=3,
            filters=[512, 512, 2048]
        )
        self.identity_block12 = IdentityBlock(
            kernel_size=3,
            filters=[512, 512, 2048]
        )

        self.avg_pooling = layers.AveragePooling2D(
            pool_size=(2, 2),
            padding="same"
        )
        self.flat = layers.Flatten()
        self.dese = layers.Dense(
            class_num,
            "softmax"
        )

    def call(self, inputs, training=None, mask=None):
        x = layers.ZeroPadding2D(padding=[3, 3])(inputs)
        for block in [
            # stage 1
            self.con_bn_ac,
            self.max_pooling,
            # stage 2
            self.conv_block1,
            self.identity_block1,
            self.identity_block2,
            # stage 3
            self.conv_block2,
            self.identity_block3,
            self.identity_block4,
            self.identity_block5,
            # stage 4
            self.conv_block3,
            self.identity_block6,
            self.identity_block7,
            self.identity_block8,
            self.identity_block9,
            self.identity_block10,
            # stage 5
            self.conv_block4,
            self.identity_block11,
            self.identity_block12,
            self.avg_pooling,
            self.flat,
            self.dese

        ]:
            x = block(x)
        return x

if __name__ == "__main__":
    con_bn_activation = ConvBNActivation(
        filter=10,
        kernel_size=[3, 3],
        padding="valid",
        activation="relu"
    )
    con_bn_activation(tf.ones(shape=(1, 32, 32, 3)))
    print(con_bn_activation.summary())
    # identity = IdentityBlock()
    identity_block = IdentityBlock(
        kernel_size=3,
        filters=[3, 10, 3]
    )
    identity_block(tf.ones(shape=(1, 32, 32, 3)))
    print(identity_block.summary())
    conv_block = ConvBlock(
        mid_kernel_size=3,
        filters=[3, 10, 5],
        shortcut_stride=2
    )
    conv_block(tf.ones(shape=(1, 32, 32, 10)))
    print(conv_block.summary())

    resnet50 = ResNet50(class_num=238)
    resnet50(tf.ones(shape=(1, 32, 32, 3)))
    print(resnet50.summary())


value = [' 'for i in range(9)]            #List in which the input from both human and computer is stored
markp = ""                                #Stores the mark of the player
markc = ""                                #Stores the mark of the computer
def instructions():                       #To display intruction and board layout at the begining
    print("\n\nChoose a cell numbered from 1 to 9 as below and play")
    print("\n\n\t\t\t1 | 2  | 3  ")
    print("\t\t\t----------")
    print("\t\t\t4 | 5  | 6  ")
    print("\t\t\t----------")
    print("\t\t\t7 | 8  | 9  ")
    print("\n-------------------------------------------------------")

def input_values(markp,markc,pos):         #Function to accept input from the player
    positon =  pos -1
    if value[positon]==markc:
        print("\t\t\tDON'T EVEN TRY, STUPID CHEATER!!!")
        exit(0)
    value[positon] = markp

def computer(markp,markc):                #Function which plays the game as computer
    row1 = value[0:3]
    row2 = value[3:6]
    row3 = value[6:9]
    col1 = value[0:7:3]
    col2 = value[1:8:3]
    col3 = value[2:9:3]
    dia1 = [value[0],value[4],value[8]]
    dia2 = [value[2],value[4],value[6]]
    corner = [0,2,6,8]

    def attack_corner():
        for i in corner:
            if value[i]==" ":
                value[i] = markc
                break

    def scan(first,last,skip):
        for i in range(first,last,skip):
            if value[i] == " ":
                value[i] = markc
            else:
                continue

    def comp_logic(mark,id = 2):          #Function which analyse all possible winning moves and play accordingly
            if row1.count(mark)==2 and row1.count(" ") != 0:
                scan(0,3,1)
            elif row2.count(mark)==2 and row2.count(" ") != 0:
                scan(3,6,1)
            elif row3.count(mark)==2 and row3.count(" ") != 0:
                scan(6,9,1)
            elif col1.count(mark)==2 and col1.count(" ") != 0:
                scan(0,7,3)
            elif col2.count(mark)==2 and col2.count(" ") != 0:
                scan(1,8,3)
            elif col3.count(mark)==2 and col3.count(" ") != 0:
                scan(2,9,3)
            elif dia1.count(mark)==2 and dia1.count(" ") != 0:
                scan(0,9,4)
            elif dia2.count(mark)==2 and dia2.count(" ") != 0:
                scan(2,7,2)
            else:
                if id == 1:
                    return True
                elif markc == "X":
                    attack_corner()
                elif value[4] == " ":
                    value[4]=markc
                elif value.count(" ")==1:
                    value[value.index(" ")] = markc
                else:
                    attack_corner()
                return False

    if comp_logic(markc,1):
        comp_logic(markp)

def check_result(markp,markc):             #To check if any player won and to display winning message
    def who(w):
        if value[w] == markp:
                print("\t\t\tSomthing went wrong, you won!")
        else:
            print("\t\t\tHAHA NOOB!!!, COMPUTER WON ")
            exit(0)

    for i in range(0,7,3):
        if (value[i]==value[i+1]== value[i+2]) and value[i] != " ":
            who(i)
            return False
    for i in range(3):
        if (value[i]==value[i+3]==value[i+6]) and value[i] !=" ":
            who(i)
            return False
    if (value[0]==value[4]==value[8]) and value[0] != " ":
        who(0)
        return False
    if (value[2]==value[4]==value[6]) and value[2] != " ":
        who(2)
        return False
    if value.count(" ") == 0:
        print("\t\t\tFINALLY!!, A WORTHY OPPONENT, Its a Draw!!!")
        return False
    return True

def display():                          #To display the board with player moves
    print("\n")
    print("\t\t\t-------------")
    for i in range(0,7,3):
        print("\t\t\t|",value[i],"|",value[i+1],"|",value[i+2],"|")
        print("\t\t\t-------------")
    print("\n-------------------------------------------------------")

#Main body of the program

user=input("\n\t\tchoose your letter (X or O)")    #player choosing his character
user = user.upper()
if user == "X":
    AI = "O"
else:
    AI = "X"
instructions()

loop = True
while(loop):
    if user == "X":
        choice = int(input("\nEnter your choice: "))
        input_values(user,AI,choice)
        computer(user, AI)
        display()
        loop = check_result(user,AI)
    else:
        computer(user, AI)
        display()
        loop = check_result(user,AI)
        choice = int(input("\nEnter your choice: "))
        input_values(user,AI,choice)
        loop = check_result(user,AI)


T = int(input()) # 테스트 케이스 수

for t in range(1, T+1) :
    # 두 수 입력받기
    a, b = list(map(int, input().split()))
    #print a b
    sh = a//b # 몫 계산
    re = a%b # 나머지 계산

    print(f"#{t} {sh} {re}")

SWEA/D1/2029. 몫과 나머지 출력하기/몫과 나머지 출력하기.py

몫과 나머지 출력하기.py


""" Steps that run search queries.

    Queries may either be run directly via PHP using the query script
    or via the HTTP interface.
"""

import json
import os
import io
import re
import logging
from tidylib import tidy_document
import xml.etree.ElementTree as ET
import subprocess
from urllib.parse import urlencode
from collections import OrderedDict
from nose.tools import * # for assert functions

logger = logging.getLogger(__name__)

BASE_SERVER_ENV = {
    'HTTP_HOST' : 'localhost',
    'HTTP_USER_AGENT' : 'Mozilla/5.0 (X11; Linux x86_64; rv:51.0) Gecko/20100101 Firefox/51.0',
    'HTTP_ACCEPT' : 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
    'HTTP_ACCEPT_ENCODING' : 'gzip, deflate',
    'HTTP_CONNECTION' : 'keep-alive',
    'SERVER_SIGNATURE' : '<address>Nominatim BDD Tests</address>',
    'SERVER_SOFTWARE' : 'Nominatim test',
    'SERVER_NAME' : 'localhost',
    'SERVER_ADDR' : '127.0.1.1',
    'SERVER_PORT' : '80',
    'REMOTE_ADDR' : '127.0.0.1',
    'DOCUMENT_ROOT' : '/var/www',
    'REQUEST_SCHEME' : 'http',
    'CONTEXT_PREFIX' : '/',
    'SERVER_ADMIN' : 'webmaster@localhost',
    'REMOTE_PORT' : '49319',
    'GATEWAY_INTERFACE' : 'CGI/1.1',
    'SERVER_PROTOCOL' : 'HTTP/1.1',
    'REQUEST_METHOD' : 'GET',
    'REDIRECT_STATUS' : 'CGI'
}

def compare(operator, op1, op2):
    if operator == 'less than':
        return op1 < op2
    elif operator == 'more than':
        return op1 > op2
    elif operator == 'exactly':
        return op1 == op2
    elif operator == 'at least':
        return op1 >= op2
    elif operator == 'at most':
        return op1 <= op2
    else:
        raise Exception("unknown operator '%s'" % operator)

class GenericResponse(object):

    def match_row(self, row):
        if 'ID' in row.headings:
            todo = [int(row['ID'])]
        else:
            todo = range(len(self.result))

        for i in todo:
            res = self.result[i]
            for h in row.headings:
                if h == 'ID':
                    pass
                elif h == 'osm':
                    assert_equal(res['osm_type'], row[h][0])
                    assert_equal(res['osm_id'], row[h][1:])
                elif h == 'centroid':
                    x, y = row[h].split(' ')
                    assert_almost_equal(float(y), float(res['lat']))
                    assert_almost_equal(float(x), float(res['lon']))
                elif row[h].startswith("^"):
                    assert_in(h, res)
                    assert_is_not_none(re.fullmatch(row[h], res[h]),
                                       "attribute '%s': expected: '%s', got '%s'"
                                          % (h, row[h], res[h]))
                else:
                    assert_in(h, res)
                    assert_equal(str(res[h]), str(row[h]))

    def property_list(self, prop):
        return [ x[prop] for x in self.result ]

class SearchResponse(GenericResponse):

    def __init__(self, page, fmt='json', errorcode=200):
        self.page = page
        self.format = fmt
        self.errorcode = errorcode
        self.result = []
        self.header = dict()

        if errorcode == 200:
            getattr(self, 'parse_' + fmt)()

    def parse_json(self):
        m = re.fullmatch(r'([\w$][^(]*)\((.*)\)', self.page)
        if m is None:
            code = self.page
        else:
            code = m.group(2)
            self.header['json_func'] = m.group(1)
        self.result = json.JSONDecoder(object_pairs_hook=OrderedDict).decode(code)

    def parse_html(self):
        content, errors = tidy_document(self.page,
                                        options={'char-encoding' : 'utf8'})
        #eq_(len(errors), 0 , "Errors found in HTML document:\n%s" % errors)

        b = content.find('nominatim_results =')
        e = content.find('</script>')
        content = content[b:e]
        b = content.find('[')
        e = content.rfind(']')

        self.result = json.JSONDecoder(object_pairs_hook=OrderedDict).decode(content[b:e+1])

    def parse_xml(self):
        et = ET.fromstring(self.page)

        self.header = dict(et.attrib)

        for child in et:
            assert_equal(child.tag, "place")
            self.result.append(dict(child.attrib))

            address = {}
            for sub in child:
                if sub.tag == 'extratags':
                    self.result[-1]['extratags'] = {}
                    for tag in sub:
                        self.result[-1]['extratags'][tag.attrib['key']] = tag.attrib['value']
                elif sub.tag == 'namedetails':
                    self.result[-1]['namedetails'] = {}
                    for tag in sub:
                        self.result[-1]['namedetails'][tag.attrib['desc']] = tag.text
                elif sub.tag in ('geokml'):
                    self.result[-1][sub.tag] = True
                else:
                    address[sub.tag] = sub.text

            if len(address) > 0:
                self.result[-1]['address'] = address

class ReverseResponse(GenericResponse):

    def __init__(self, page, fmt='json', errorcode=200):
        self.page = page
        self.format = fmt
        self.errorcode = errorcode
        self.result = []
        self.header = dict()

        if errorcode == 200:
            getattr(self, 'parse_' + fmt)()

    def parse_html(self):
        content, errors = tidy_document(self.page,
                                        options={'char-encoding' : 'utf8'})
        #eq_(len(errors), 0 , "Errors found in HTML document:\n%s" % errors)

        b = content.find('nominatim_results =')
        e = content.find('</script>')
        content = content[b:e]
        b = content.find('[')
        e = content.rfind(']')

        self.result = json.JSONDecoder(object_pairs_hook=OrderedDict).decode(content[b:e+1])

    def parse_json(self):
        m = re.fullmatch(r'([\w$][^(]*)\((.*)\)', self.page)
        if m is None:
            code = self.page
        else:
            code = m.group(2)
            self.header['json_func'] = m.group(1)
        self.result = [json.JSONDecoder(object_pairs_hook=OrderedDict).decode(code)]

    def parse_xml(self):
        et = ET.fromstring(self.page)

        self.header = dict(et.attrib)
        self.result = []

        for child in et:
            if child.tag == 'result':
                eq_(0, len(self.result), "More than one result in reverse result")
                self.result.append(dict(child.attrib))
            elif child.tag == 'addressparts':
                address = {}
                for sub in child:
                    address[sub.tag] = sub.text
                self.result[0]['address'] = address
            elif child.tag == 'extratags':
                self.result[0]['extratags'] = {}
                for tag in child:
                    self.result[0]['extratags'][tag.attrib['key']] = tag.attrib['value']
            elif child.tag == 'namedetails':
                self.result[0]['namedetails'] = {}
                for tag in child:
                    self.result[0]['namedetails'][tag.attrib['desc']] = tag.text
            elif child.tag in ('geokml'):
                self.result[0][child.tag] = True
            else:
                assert child.tag == 'error', \
                        "Unknown XML tag %s on page: %s" % (child.tag, self.page)

class DetailsResponse(GenericResponse):

    def __init__(self, page, fmt='json', errorcode=200):
        self.page = page
        self.format = fmt
        self.errorcode = errorcode
        self.result = []
        self.header = dict()

        if errorcode == 200:
            getattr(self, 'parse_' + fmt)()

    def parse_html(self):
        content, errors = tidy_document(self.page,
                                        options={'char-encoding' : 'utf8'})
        self.result = {}

@when(u'searching for "(?P<query>.*)"(?P<dups> with dups)?')
def query_cmd(context, query, dups):
    """ Query directly via PHP script.
    """
    cmd = [os.path.join(context.nominatim.build_dir, 'utils', 'query.php'),
           '--search', query]
    # add more parameters in table form
    if context.table:
        for h in context.table.headings:
            value = context.table[0][h].strip()
            if value:
                cmd.extend(('--' + h, value))

    if dups:
        cmd.extend(('--dedupe', '0'))

    proc = subprocess.Popen(cmd, cwd=context.nominatim.build_dir,
                            stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    (outp, err) = proc.communicate()

    assert_equals (0, proc.returncode, "query.php failed with message: %s\noutput: %s" % (err, outp))

    context.response = SearchResponse(outp.decode('utf-8'), 'json')

def send_api_query(endpoint, params, fmt, context):
    if fmt is not None:
        params['format'] = fmt.strip()
    if context.table:
        if context.table.headings[0] == 'param':
            for line in context.table:
                params[line['param']] = line['value']
        else:
            for h in context.table.headings:
                params[h] = context.table[0][h]

    env = dict(BASE_SERVER_ENV)
    env['QUERY_STRING'] = urlencode(params)

    env['SCRIPT_NAME'] = '/%s.php' % endpoint
    env['REQUEST_URI'] = '%s?%s' % (env['SCRIPT_NAME'], env['QUERY_STRING'])
    env['CONTEXT_DOCUMENT_ROOT'] = os.path.join(context.nominatim.build_dir, 'website')
    env['SCRIPT_FILENAME'] = os.path.join(env['CONTEXT_DOCUMENT_ROOT'],
                                          '%s.php' % endpoint)
    env['NOMINATIM_SETTINGS'] = context.nominatim.local_settings_file

    logger.debug("Environment:" + json.dumps(env, sort_keys=True, indent=2))

    if hasattr(context, 'http_headers'):
        env.update(context.http_headers)

    cmd = ['/usr/bin/php-cgi', '-f']
    if context.nominatim.code_coverage_path:
        env['COV_SCRIPT_FILENAME'] = env['SCRIPT_FILENAME']
        env['COV_PHP_DIR'] = os.path.join(context.nominatim.src_dir, "lib")
        env['COV_TEST_NAME'] = '%s:%s' % (context.scenario.filename, context.scenario.line)
        env['SCRIPT_FILENAME'] = \
                os.path.join(os.path.split(__file__)[0], 'cgi-with-coverage.php')
        cmd.append(env['SCRIPT_FILENAME'])
        env['PHP_CODE_COVERAGE_FILE'] = context.nominatim.next_code_coverage_file()
    else:
        cmd.append(env['SCRIPT_FILENAME'])

    for k,v in params.items():
        cmd.append("%s=%s" % (k, v))

    proc = subprocess.Popen(cmd, cwd=context.nominatim.build_dir, env=env,
                            stdout=subprocess.PIPE, stderr=subprocess.PIPE)

    (outp, err) = proc.communicate()
    outp = outp.decode('utf-8')

    logger.debug("Result: \n===============================\n"
                 + outp + "\n===============================\n")

    assert_equals(0, proc.returncode,
                  "query.php failed with message: %s\noutput: %s" % (err, outp))

    assert_equals(0, len(err), "Unexpected PHP error: %s" % (err))

    if outp.startswith('Status: '):
        status = int(outp[8:11])
    else:
        status = 200

    content_start = outp.find('\r\n\r\n')

    return outp[content_start + 4:], status

@given(u'the HTTP header')
def add_http_header(context):
    if not hasattr(context, 'http_headers'):
        context.http_headers = {}

    for h in context.table.headings:
        envvar = 'HTTP_' + h.upper().replace('-', '_')
        context.http_headers[envvar] = context.table[0][h]

@when(u'sending (?P<fmt>\S+ )?search query "(?P<query>.*)"(?P<addr> with address)?')
def website_search_request(context, fmt, query, addr):
    params = {}
    if query:
        params['q'] = query
    if addr is not None:
        params['addressdetails'] = '1'

    outp, status = send_api_query('search', params, fmt, context)

    if fmt is None:
        outfmt = 'html'
    elif fmt == 'jsonv2 ':
        outfmt = 'json'
    else:
        outfmt = fmt.strip()

    context.response = SearchResponse(outp, outfmt, status)

@when(u'sending (?P<fmt>\S+ )?reverse coordinates (?P<lat>.+)?,(?P<lon>.+)?')
def website_reverse_request(context, fmt, lat, lon):
    params = {}
    if lat is not None:
        params['lat'] = lat
    if lon is not None:
        params['lon'] = lon

    outp, status = send_api_query('reverse', params, fmt, context)

    if fmt is None:
        outfmt = 'xml'
    elif fmt == 'jsonv2 ':
        outfmt = 'json'
    else:
        outfmt = fmt.strip()

    context.response = ReverseResponse(outp, outfmt, status)

@when(u'sending (?P<fmt>\S+ )?details query for (?P<query>.*)')
def website_details_request(context, fmt, query):
    params = {}
    if query[0] in 'NWR':
        params['osmtype'] = query[0]
        params['osmid'] = query[1:]
    else:
        params['place_id'] = query
    outp, status = send_api_query('details', params, fmt, context)

    context.response = DetailsResponse(outp, 'html', status)

@when(u'sending (?P<fmt>\S+ )?lookup query for (?P<query>.*)')
def website_lookup_request(context, fmt, query):
    params = { 'osm_ids' : query }
    outp, status = send_api_query('lookup', params, fmt, context)

    if fmt == 'json ':
        outfmt = 'json'
    else:
        outfmt = 'xml'

    context.response = SearchResponse(outp, outfmt, status)

@step(u'(?P<operator>less than|more than|exactly|at least|at most) (?P<number>\d+) results? (?:is|are) returned')
def validate_result_number(context, operator, number):
    eq_(context.response.errorcode, 200)
    numres = len(context.response.result)
    ok_(compare(operator, numres, int(number)),
        "Bad number of results: expected %s %s, got %d." % (operator, number, numres))

@then(u'a HTTP (?P<status>\d+) is returned')
def check_http_return_status(context, status):
    eq_(context.response.errorcode, int(status))

@then(u'the result is valid (?P<fmt>\w+)')
def step_impl(context, fmt):
    context.execute_steps("Then a HTTP 200 is returned")
    eq_(context.response.format, fmt)

@then(u'result header contains')
def check_header_attr(context):
    for line in context.table:
        assert_is_not_none(re.fullmatch(line['value'], context.response.header[line['attr']]),
                     "attribute '%s': expected: '%s', got '%s'"
                       % (line['attr'], line['value'],
                          context.response.header[line['attr']]))

@then(u'result header has (?P<neg>not )?attributes (?P<attrs>.*)')
def check_header_no_attr(context, neg, attrs):
    for attr in attrs.split(','):
        if neg:
            assert_not_in(attr, context.response.header)
        else:
            assert_in(attr, context.response.header)

@then(u'results contain')
def step_impl(context):
    context.execute_steps("then at least 1 result is returned")

    for line in context.table:
        context.response.match_row(line)

@then(u'result (?P<lid>\d+ )?has (?P<neg>not )?attributes (?P<attrs>.*)')
def validate_attributes(context, lid, neg, attrs):
    if lid is None:
        idx = range(len(context.response.result))
        context.execute_steps("then at least 1 result is returned")
    else:
        idx = [int(lid.strip())]
        context.execute_steps("then more than %sresults are returned" % lid)

    for i in idx:
        for attr in attrs.split(','):
            if neg:
                assert_not_in(attr, context.response.result[i])
            else:
                assert_in(attr, context.response.result[i])

@then(u'result addresses contain')
def step_impl(context):
    context.execute_steps("then at least 1 result is returned")

    if 'ID' not in context.table.headings:
        addr_parts = context.response.property_list('address')

    for line in context.table:
        if 'ID' in context.table.headings:
            addr_parts = [dict(context.response.result[int(line['ID'])]['address'])]

        for h in context.table.headings:
            if h != 'ID':
                for p in addr_parts:
                    assert_in(h, p)
                    assert_equal(p[h], line[h], "Bad address value for %s" % h)

@then(u'address of result (?P<lid>\d+) has(?P<neg> no)? types (?P<attrs>.*)')
def check_address(context, lid, neg, attrs):
    context.execute_steps("then more than %s results are returned" % lid)

    addr_parts = context.response.result[int(lid)]['address']

    for attr in attrs.split(','):
        if neg:
            assert_not_in(attr, addr_parts)
        else:
            assert_in(attr, addr_parts)

@then(u'address of result (?P<lid>\d+) is')
def check_address(context, lid):
    context.execute_steps("then more than %s results are returned" % lid)

    addr_parts = dict(context.response.result[int(lid)]['address'])

    for line in context.table:
        assert_in(line['type'], addr_parts)
        assert_equal(addr_parts[line['type']], line['value'],
                     "Bad address value for %s" % line['type'])
        del addr_parts[line['type']]

    eq_(0, len(addr_parts), "Additional address parts found: %s" % str(addr_parts))

@then(u'result (?P<lid>\d+ )?has bounding box in (?P<coords>[\d,.-]+)')
def step_impl(context, lid, coords):
    if lid is None:
        context.execute_steps("then at least 1 result is returned")
        bboxes = context.response.property_list('boundingbox')
    else:
        context.execute_steps("then more than %sresults are returned" % lid)
        bboxes = [ context.response.result[int(lid)]['boundingbox']]

    coord = [ float(x) for x in coords.split(',') ]

    for bbox in bboxes:
        if isinstance(bbox, str):
            bbox = bbox.split(',')
        bbox = [ float(x) for x in bbox ]

        assert_greater_equal(bbox[0], coord[0])
        assert_less_equal(bbox[1], coord[1])
        assert_greater_equal(bbox[2], coord[2])
        assert_less_equal(bbox[3], coord[3])

@then(u'there are(?P<neg> no)? duplicates')
def check_for_duplicates(context, neg):
    context.execute_steps("then at least 1 result is returned")

    resarr = set()
    has_dupe = False

    for res in context.response.result:
        dup = (res['osm_type'], res['class'], res['type'], res['display_name'])
        if dup in resarr:
            has_dupe = True
            break
        resarr.add(dup)

    if neg:
        assert not has_dupe, "Found duplicate for %s" % (dup, )
    else:
        assert has_dupe, "No duplicates found"


from kivymd.uix.screen import MDScreen
from kivymd.uix.list import TwoLineAvatarIconListItem
from kivymd.uix.list import ImageLeftWidget, IRightBodyTouch
from kivymd.uix.dialog import MDDialog
from kivymd.uix.button import MDFlatButton
from kivymd.uix.boxlayout import MDBoxLayout
from kivy.app import App
from kivy.clock import Clock
from kivy.lang.builder import Builder
from kivy.properties import ObjectProperty

from entidades.exercicio import Exercicio
from service.exercicio_service import ExercicioService

Builder.load_file("view/tela_lista_exercicios/telalistaexercicios.kv")

exercicios = [
    {
        'nome':'freio em T',
        'descricao':'faça um T com os patins para diminuir a velocidade ou parar',
        'urlImagem': 'https://i.ytimg.com/vi/DeAZogIb464/maxresdefault.jpg'},
    {
         'nome': 'limões',
         'descricao': 'desenhe limões com os patins',
         'urlImagem': 'https://i.ytimg.com/vi/H1CPIlWfrJU/maxresdefault.jpg'},

    {
        'nome':'freio em cunha',
        'descricao':'faça um V invertido para diminuir a velocidade',
        'urlImagem': 'https://i.ytimg.com/vi/JLS56y636IY/mqdefault.jpg'},
    {
         'nome': 'freio em cunha com passos',
         'descricao': 'vá aproximando as pontas dos patins gradativamente para parar',
         'urlImagem': 'https://i.ytimg.com/vi/XyKnryt-j8Q/maxresdefault.jpg'},
    {
         'nome': 'Freio de calcanhar',
         'descricao': 'use o freio do patins para parar',
         'urlImagem': 'https://i.ytimg.com/vi/-WJ97gUZ0fI/maxresdefault.jpg'}
]

service = ExercicioService()

class TelaListaExercicios(MDScreen):

    def __init__(self, **kw):
        super(TelaListaExercicios, self).__init__(**kw)
        self._on_enter_trig = trig = Clock.create_trigger(self._my_on_enter)
        self.bind(on_enter=trig)

    def _my_on_enter(self, *largs):
        self.listarExercicios()

    def irParaEmail(self):
        self.parent.current = 'email'
        self.limpar()

    def irParaCadastro(self):
        self.parent.current = 'cadastro'
        self.limpar()

    def addExercicio(self):
        for exercicio in exercicios:
            ex = Exercicio(None, exercicio['nome'], exercicio['descricao'], exercicio['urlImagem'])
            service.salvar(ex)
        self.limpar()
        self.listarExercicios()

    def listarExercicios(self):
        try:
            exercicios = service.listar()
            for exercicio in exercicios:
                ex = Exercicio(
                    exercicio[0],
                    exercicio[1],
                    exercicio[2],
                    exercicio[3]
                )
                exercicio_item = ExercicioItem(
                    ex_id = ex.id,
                    text = ex.nome,
                    secondary_text = ex.descricao
                )
                url_imagem = ''
                if (ex.urlImagem == ''):
                    url_imagem = 'view\images\patins.png'
                else:
                    url_imagem = ex.urlImagem
                exercicio_item.add_widget(ImageLeftWidget(source = url_imagem))
                self.ids.container.add_widget(exercicio_item)

        except Exception as e:
            print(e)
            pass

    def limpar(self):
        self.ids.container.clear_widgets()

    def recarregar(self):
        self.limpar()
        self.listarExercicios()

    def build(self):
        return TelaListaExercicios()

class ExercicioItem(TwoLineAvatarIconListItem):
    dialog = None
    dialogExcluir = None
    dialogEditar = None

    def __init__(self, ex_id=None, **kwargs):
        super().__init__(**kwargs)
        self.ex_id = ex_id

    def verDetalhe(self, item, *args):
        if not self.dialog:
            self.dialog = MDDialog(
                title = item.text,
                text = item.secondary_text,
                buttons=[
                    MDFlatButton(
                        text="FECHAR",
                        theme_text_color="Custom",
                        text_color=self.theme_cls.primary_color,
                        on_release = lambda x: self.fecharDialog()

                    ),
                ],
            )
        self.dialog.open()

    def fecharDialog(self, *args):
        self.dialog.dismiss(force = True)

    def excluirItem(self, item):
        self.parent.remove_widget(item)
        service.excluir(item.ex_id)
        self.fecharDialogExcluir()

    def abrirDialogExcluir(self, item):
        self.fecharDialog()
        if not self.dialogExcluir:
            self.dialogExcluir = MDDialog(
                title = 'Confirmar exclusão?',
                text = item.text,
                buttons=[
                    MDFlatButton(
                        text="EXCLUIR",
                        theme_text_color="Custom",
                        text_color=self.theme_cls.primary_color,
                        on_release= lambda x: self.excluirItem(item)
                    ),
                    MDFlatButton(
                        text="CANCELAR",
                        theme_text_color="Custom",
                        text_color=self.theme_cls.primary_color,
                        on_release = lambda x: self.fecharDialogExcluir()

                    ),
                ],
            )
        self.dialogExcluir.open()

    def fecharDialogExcluir(self, *args):
        self.dialogExcluir.dismiss(force = True)

    def abrirDialogEditar(self, item):
        if not self.dialogEditar:
            self.dialogEditar = MDDialog(
                title = 'Editar Exercício',
                type = 'custom',
                content_cls = DialogEditar(ex_id = item.ex_id),
                buttons=[
                    MDFlatButton(
                        text="FECHAR",
                        theme_text_color="Custom",
                        text_color=self.theme_cls.primary_color,
                        on_release = lambda x: self.fecharDialogEditar()

                    ),
                ],
            )

        self.dialogEditar.open()

    def fecharDialogEditar(self, *args):
        self.dialogEditar.dismiss(force = True)

class ItemContainer(IRightBodyTouch, MDBoxLayout):
    adaptative_width = True

class DialogEditar(MDBoxLayout):
    edit_nome: ObjectProperty(None)
    edit_descricao: ObjectProperty(None)
    edit_imagem: ObjectProperty(None)

    def __init__(self, ex_id=None, **kwargs):
        super().__init__()
        self.ex_id = ex_id
        self.carregarCampos(self.ex_id)

    def carregarCampos(self, ex_id):
        exercicio = service.listarUm(ex_id)

        self.edit_nome.text = exercicio[0][1]
        self.edit_descricao.text = exercicio[0][2]
        if exercicio[0][3] is None:
            self.edit_imagem.text = ''
        else:
            self.edit_imagem.text = exercicio[0][3]

    def editarItem(self):
        label = self.ids.edit_texto_erro

        if (self.edit_nome.text == ''):
            label.text = 'O nome é obrigatório'

        elif (self.edit_descricao.text == ''):
            label.text = 'A descrição é obrigatória!'

        else:
            ex = Exercicio(
                self.ex_id,
                self.edit_nome.text,
                self.edit_descricao.text,
                self.edit_imagem.text
            )

            service.salvar(ex)

            label.text = ''
            self.edit_nome.text = ''
            self.edit_descricao.text = ''
            self.edit_imagem.text = ''


from selenium import webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
from selenium.webdriver.chrome.options import Options

# first run "docker-compose up" to launch the webdrivers
chrome_options = Options()
chrome_options.add_argument("--headless")

drivers = []
for port in [5001, 5002, 5003]:
    drivers.append(
        webdriver.Remote(
            command_executor=f'http://localhost:{port}/wd/hub',
            desired_capabilities=DesiredCapabilities.CHROME,
            options=chrome_options)
    )

drivers[0].get("http://www.google.com")
drivers[0].save_screenshot(f'test0.png')
drivers[1].get("http://www.xtreamers.io")
drivers[0].save_screenshot(f'test1.png')
drivers[2].get("http://www.python.org")
drivers[0].save_screenshot(f'test2.png')

for driver in drivers:
    print(driver.title)

for driver in drivers:
    driver.quit()

# docker logs -f chrome1


x,k,d=map(int,input().split())
x=abs(x)
ans=10**15
cur=x
if d*k<=x:
    ans=x-(d*k)
else:
    k-=x//d
    curr=x-d*(x//d)
    if k%2==0:
        ans=curr
    else:
        ans=d-curr

print(ans)


# 백준 1987번 알파벳(BFS)
from sys import stdin
from collections import deque
import copy
input = stdin.readline
n, m = map(int, input().split())
matrix = []
for _ in range(n):
    matrix.append(input().rstrip())

# 동, 남, 서, 북
dx = [0, +1, 0, -1]
dy = [+1, 0, -1, 0]
q = set()
q.add((0, 0, matrix[0][0]))
answer = 0
def bfs(q):
    global answer
    while q:
        x, y, sentence = q.popleft()
        answer = max(answer, len(sentence))
        if answer == 26:        # 모든 알파벳을 돌면 26개가 됨
            return
        for i in range(4):
            temp_x = x + dx[i]
            temp_y = y + dy[i]
            if 0 <= temp_x < n and 0<= temp_y < m:
                if matrix[temp_x][temp_y] not in sentence:
                    q.add((temp_x, temp_y, sentence + matrix[temp_x][temp_y]))
    return
bfs(q)
print(answer)


from collections import OrderedDict

from RMUtilsFramework.rmTimeUtils import rmTimestampToDateAsString
from RMDataFramework.rmForecastInfo import RMForecastInfo
from RMDataFramework.rmMixerData import RMMixerData
from rmDatabase import RMTable
from RMUtilsFramework.rmLogging import log

##-----------------------------------------------------------------------------------------------------
##
##
class RMMixerDataTable(RMTable):
    def initialize(self):
        self.database.execute("CREATE TABLE IF NOT EXISTS mixerData ("\
                                            "forecastID INTEGER NOT NULL, "\
                                            "forecastTimestamp INTEGER NOT NULL, "\
                                            "timestamp NUMERIC NOT NULL, "\
                                            "temperature DECIMAL DEFAULT NULL, "\
                                            "rh DECIMAL DEFAULT NULL, "\
                                            "wind DECIMAL DEFAULT NULL, "\
                                            "solarRad DECIMAL DEFAULT NULL, "\
                                            "skyCover DECIMAL DEFAULT NULL, "\
                                            "rain DECIMAL DEFAULT NULL, "\
                                            "et0 DECIMAL DEFAULT NULL, "\
                                            "pop DECIMAL DEFAULT NULL, "\
                                            "qpf DECIMAL DEFAULT NULL, "\
                                            "condition INTEGER DEFAULT NULL, "\
                                            "pressure DECIMAL DEFAULT NULL, "\
                                            "dewPoint DECIMAL DEFAULT NULL, "\
                                            "minTemp DECIMAL DEFAULT NULL, "\
                                            "maxTemp DECIMAL DEFAULT NULL, "\
                                            "minRH DECIMAL DEFAULT NULL, "\
                                            "maxRH DECIMAL DEFAULT NULL, "\
                                            "et0calc DECIMAL DEFAULT NULL, "\
                                            "et0final DECIMAL DEFAULT NULL, "\
                                            #"FOREIGN KEY(forecastID) REFERENCES forecast(ID), "\
                                            "PRIMARY KEY(forecastID, timestamp)"\
                                            ")")
        self.database.commit()

    def addRecords(self, forecastID, forecastTimestamp, values):
        if(self.database.isOpen()):
            valuesToInsert = [(forecastID,
                               forecastTimestamp,
                               value.timestamp,
                               value.temperature,
                               value.rh,
                               value.wind,
                               value.solarRad,
                               value.skyCover,
                               value.rain,
                               value.et0,
                               value.pop,
                               value.qpf,
                               value.condition,
                               value.pressure,
                               value.dewPoint,
                               value.minTemp,
                               value.maxTemp,
                               value.minRH,
                               value.maxRH,
                               value.et0calc,
                               value.et0final
                                ) for value in values]

            self.database.executeMany("INSERT INTO mixerData(forecastID, forecastTimestamp, timestamp, "\
                                      "temperature, rh, wind, solarRad, skyCover, rain, et0, pop, qpf, "\
                                      "condition, pressure, dewPoint, "\
                                      "minTemp, maxTemp, minRH, maxRH, et0calc, et0final) "\
                                      "VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", valuesToInsert)
            self.database.commit()

    def deleteOlderDataByTimestampCollision(self, values):
        if(self.database.isOpen()):
            timestampsToDelete = [(value.timestamp,) for value in values]
            self.database.executeMany("DELETE FROM mixerData "\
                                  "WHERE timestamp=? ", timestampsToDelete)
            self.database.commit()

    def getRecordsByThreshold(self, minTimestamp = None, maxTimestamp = None, orderAsc = True, asDict = False):
        result = []
        if(self.database.isOpen()):
            cursor = None

            order = "ASC"
            if not orderAsc:
                order = "DESC"

            if(minTimestamp == None and maxTimestamp == None):
                cursor = self.database.execute("SELECT * FROM mixerData ORDER BY timestamp " + order)
            if(maxTimestamp == None):
                cursor = self.database.execute("SELECT * FROM mixerData WHERE timestamp=? ORDER BY timestamp " + order, (minTimestamp, ))
            else:
                cursor = self.database.execute("SELECT * FROM mixerData WHERE ?<=timestamp AND timestamp<? ORDER BY timestamp " + order,
                                    (minTimestamp, maxTimestamp, ))

            for row in cursor:
                mixerData = RMMixerData(row[2])
                mixerData.temperature = row[3]
                mixerData.rh = row[4]
                mixerData.wind = row[5]
                mixerData.solarRad = row[6]
                mixerData.skyCover = row[7]
                mixerData.rain = row[8]
                mixerData.et0 = row[9]
                mixerData.pop = row[10]
                mixerData.qpf = row[11]
                mixerData.condition = row[12]
                mixerData.pressure = row[13]
                mixerData.dewPoint = row[14]
                mixerData.minTemp = row[15]
                mixerData.maxTemp = row[16]
                mixerData.minRH = row[17]
                mixerData.maxRH = row[18]
                mixerData.et0calc = row[19]
                mixerData.et0final = row[20]

                result.append(mixerData)

        return result

    def getLastRecordsByThreshold(self, minTimestamp = None, maxTimestamp = None, orderAsc = True, asDict = False, noOfRecords = None):
        if asDict:
            result = OrderedDict()
        else:
            result = []

        if(self.database.isOpen()):
            cursor = None

            order = "ASC"
            if not orderAsc:
                order = "DESC"

            limit = ""
            if noOfRecords:
                limit = " LIMIT %d" % noOfRecords

            if minTimestamp is None and maxTimestamp is None:
                cursor = self.database.execute("SELECT MAX(forecastID), * FROM mixerData GROUP BY timestamp ORDER BY timestamp " + order + limit)
            elif minTimestamp is None:
                cursor = self.database.execute("SELECT MAX(forecastID), * FROM mixerData WHERE timestamp<=? GROUP BY timestamp ORDER BY timestamp " + order + limit, (maxTimestamp, ))
            elif maxTimestamp is None:
                cursor = self.database.execute("SELECT MAX(forecastID), * FROM mixerData WHERE ?<=timestamp GROUP BY timestamp ORDER BY timestamp " + order + limit, (minTimestamp, ))
            else:
                cursor = self.database.execute("SELECT MAX(forecastID), * FROM mixerData WHERE ?<=timestamp AND timestamp<=? GROUP BY timestamp ORDER BY timestamp " + order + limit,
                                    (minTimestamp, maxTimestamp, ))

            for row in cursor:
                mixerData = RMMixerData(row[3])
                mixerData.temperature = row[4]
                mixerData.rh = row[5]
                mixerData.wind = row[6]
                mixerData.solarRad = row[7]
                mixerData.skyCover = row[8]
                mixerData.rain = row[9]
                mixerData.et0 = row[10]
                mixerData.pop = row[11]
                mixerData.qpf = row[12]
                mixerData.condition = row[13]
                mixerData.pressure = row[14]
                mixerData.dewPoint = row[15]
                mixerData.minTemp = row[16]
                mixerData.maxTemp = row[17]
                mixerData.minRH = row[18]
                mixerData.maxRH = row[19]
                mixerData.et0calc = row[20]
                mixerData.et0final = row[21]

                if asDict:
                    result[row[3]] = mixerData
                else:
                    result.append(mixerData)

        return result

    def getRecordsByForecast(self, useInsertOrder = False):
        result = OrderedDict()
        if(self.database.isOpen()):
            cursor = None
            if useInsertOrder:
                cursor = self.database.execute("SELECT * FROM mixerData ORDER BY forecastID ASC, timestamp ASC")
            else:
                cursor = self.database.execute("SELECT * FROM mixerData ORDER BY forecastID DESC, timestamp ASC")

            for row in cursor:
                forecastID = row[0]
                forecastTimestamp = row[1]

                mixerData = RMMixerData(row[2])
                mixerData.temperature = row[3]
                mixerData.rh = row[4]
                mixerData.wind = row[5]
                mixerData.solarRad = row[6]
                mixerData.skyCover = row[7]
                mixerData.rain = row[8]
                mixerData.et0 = row[9]
                mixerData.pop = row[10]
                mixerData.qpf = row[11]
                mixerData.condition = row[12]
                mixerData.pressure = row[13]
                mixerData.dewPoint = row[14]
                mixerData.minTemp = row[15]
                mixerData.maxTemp = row[16]
                mixerData.minRH = row[17]
                mixerData.maxRH = row[18]
                mixerData.et0calc = row[19]
                mixerData.et0final = row[20]

                if forecastID in result:
                    result[forecastID]["values"].append(mixerData)
                else:
                    result[forecastID] = {"timestamp" : forecastTimestamp, "values": [mixerData, ]}
        return result

    def getRecordsForLastForecast(self):
        forecast = None
        values = None
        if(self.database.isOpen()):

            cursor = self.database.execute("SELECT * FROM mixerData WHERE forecastID=(SELECT MAX(forecastID) from mixerData) ORDER BY timestamp ASC")

            for row in cursor:
                if not forecast:
                    forecast = RMForecastInfo(row[0], row[1])
                    values = []

                mixerData = RMMixerData(row[2])
                mixerData.temperature = row[3]
                mixerData.rh = row[4]
                mixerData.wind = row[5]
                mixerData.solarRad = row[6]
                mixerData.skyCover = row[7]
                mixerData.rain = row[8]
                mixerData.et0 = row[9]
                mixerData.pop = row[10]
                mixerData.qpf = row[11]
                mixerData.condition = row[12]
                mixerData.pressure = row[13]
                mixerData.dewPoint = row[14]
                mixerData.minTemp = row[15]
                mixerData.maxTemp = row[16]
                mixerData.minRH = row[17]
                mixerData.maxRH = row[18]
                mixerData.et0calc = row[19]
                mixerData.et0final = row[20]

                values.append(mixerData)

        return forecast, values

    def getLastRecordForDayForSimulator(self, dayTimestamp):
        result = OrderedDict()

        if(self.database.isOpen()):
            minTimestamp = dayTimestamp
            maxTimestamp = dayTimestamp + 86400

            row = self.database.execute("SELECT * FROM mixerData WHERE ?<=timestamp AND timestamp<? GROUP BY timestamp ORDER BY forecastID DESC LIMIT 1",
                                (minTimestamp, maxTimestamp, )).fetchone()

            if row:
                mixerData = RMMixerData(row[2])
                mixerData.temperature = row[3]
                mixerData.rh = row[4]
                mixerData.wind = row[5]
                mixerData.solarRad = row[6]
                mixerData.skyCover = row[7]
                mixerData.rain = row[8]
                mixerData.et0 = row[9]
                mixerData.pop = row[10]
                mixerData.qpf = row[11]
                mixerData.condition = row[12]
                mixerData.pressure = row[13]
                mixerData.dewPoint = row[14]
                mixerData.minTemp = row[15]
                mixerData.maxTemp = row[16]
                mixerData.minRH = row[17]
                mixerData.maxRH = row[18]
                mixerData.et0calc = row[19]
                mixerData.et0final = row[20]

                mixerDataDict = {
                    row[2]: mixerData
                }

                result = {
                    "forecastID": row[0],
                    "forecastTimestamp": row[1],
                    "data": mixerDataDict
                }

        return result

    def getLastKnownConditionForDay(self, dayTimestamp):
        if(self.database.isOpen()):
            minTimestamp = dayTimestamp
            maxTimestamp = dayTimestamp + 86400

            row = self.database.execute("SELECT condition FROM mixerData WHERE ?<=timestamp AND timestamp<? AND condition IS NOT NULL ORDER BY forecastID DESC, forecastTimestamp DESC LIMIT 1",
                                (minTimestamp, maxTimestamp, )).fetchone()

            if row:
                return row[0]

        return None

    def deleteRecordsByDayThreshold(self, dayTimestamp, commit = True):
        if(self.database.isOpen()):
            self.database.execute("DELETE FROM mixerData WHERE timestamp<?", (dayTimestamp, ))
            if commit:
                self.database.commit()

    def deleteRecordsHistoryByDayThreshold(self, dayTimestamp, commit = True):
        if(self.database.isOpen()):

            # Test Query
            #
            # SELECT * FROM mixerData WHERE NOT EXISTS
            # (SELECT NULL FROM
            #   (SELECT forecastTimestamp fTs, timestamp dayTs FROM mixerData WHERE timestamp<1411096483
            #    EXCEPT SELECT DISTINCT MAX(forecastTimestamp) fTs, timestamp dayTs FROM mixerData WHERE timestamp<1411096483 GROUP BY timestamp
            #   ) toDelete
            #  WHERE mixerData.forecastTimestamp=toDelete.fTs and mixerData.timestamp=toDelete.dayTs
            # );

            query = "DELETE FROM mixerData WHERE EXISTS (SELECT NULL from "\
                                                "("\
                                                    "SELECT forecastTimestamp fTs, timestamp dayTs FROM mixerData WHERE forecastTimestamp<? "\
                                                        "EXCEPT "\
                                                    "SELECT DISTINCT MAX(forecastTimestamp) fTs, timestamp dayTs FROM mixerData WHERE forecastTimestamp<? GROUP BY timestamp "\
                                                ") toDelete "\
                                                "WHERE mixerData.forecastTimestamp=toDelete.fTs and mixerData.timestamp=toDelete.dayTs)"

            self.database.execute(query, (dayTimestamp, dayTimestamp, ))
            if commit:
                self.database.commit()

    def getLastRecordsForecast(self):
        if self.database.isOpen():
            record = self.database.execute("SELECT MAX(forecastID), MAX(forecastTimestamp) FROM mixerData").fetchone()
            return record[0], record[1]
        return None, None

    def clear(self, commit):
        if(self.database.isOpen()):
            self.database.execute("DELETE FROM mixerData")
            if commit:
                self.database.commit()

    def dump(self):
        if self.database.isOpen():
            cursor = self.database.execute("SELECT * FROM mixerData ORDER BY timestamp DESC, forecastID DESC")

            for row in cursor:
                log.debug("fID=%d, fTs=%s,  dTs=%s" % (row[0], rmTimestampToDateAsString(row[1]), rmTimestampToDateAsString(row[2])))


jenis = ["1. Sapi Warrior: 690 hari", "2. Sapi Mage: 420 hari", "3. Sapi Assasin: 530 hari", "4. Sapi Nolep: 330 hari"]

sWarrior = 690
sMage = 420
sAssasin = 530
sNolep = 330
jmlhari = 0

print("TOTAL WAKTU YANG DIBUTUHKAN AGAR SAPI DEWASA")
print("Keterangan: ")

for i in jenis:
    print(i)

while True:
    sapi = int(input("\nMasukkan kode sapi (1/2/3/4): "))
    byksapi = int(input("\nBerapa banyak sapi yang akan diinput: "))
    if sapi == 1:
        jmlhari += sWarrior*byksapi
    elif sapi == 2:
        jmlhari += sMage*byksapi
    elif sapi == 3:
        jmlhari += sAssasin*byksapi
    elif sapi == 4:
        jmlhari += sNolep*byksapi

    tanya = input("\nApakah ada lagi sapi yang ingin dihitung? (Y/T) ")
    if tanya == "Y" or tanya == "y":
        continue
    elif tanya == "T" or tanya == "t":
        break

y = int(jmlhari/365)
m = int((jmlhari%365)/30)
d = int((jmlhari%365)%30)
print(f"\nJadi total waktu yang dibutuhkan ialah {y} tahun {m} bulan {d} hari.")


#! python3
# phoneAndEmail.py - Finds phone numbers and email addresses on the clipboard.

import pyperclip, re

# Create phone regex.
phoneRegex = re.compile(r'''(
            (\d{3}|\(\d{3}\))?               # 区号
            (\s|-|\.)?                       # 分隔符
            (\d{3})                           # 前三位数
            (\s|-|\.)                        # 分隔符
            (\d{4})                           # 后四位数
            (\s*(ext|x|ext.)(\s*\d{2,5}))?  # 分机号
            )''', re.VERBOSE)

# Create email regex.
emailRegex = re.compile(r'''(
            [a-zA-Z0-9._%+-]+               # 用户名
            @                                 # @ 符号
            [a-zA-Z0-9.-]+                  # 一级域名
            (\.[a-zA-Z]{2,4})                # 顶级域名
            )''', re.VERBOSE)

# Find matches in clipboard text.
text = str(pyperclip.paste())
matches = []
# print(phoneRegex.findall(text))
for groups in phoneRegex.findall(text):
    if groups[1] == '':
        phoneNum = '    ' + '-'.join([groups[3], groups[5]])
    elif not groups[1].isnumeric():
        phoneNum = '-'.join([groups[1][1:4], groups[3], groups[5]])
    else:
        phoneNum = '-'.join([groups[1], groups[3], groups[5]])
    if groups[8] != '':
        phoneNum += ' ext' + groups[8]
    matches.append(phoneNum)
for groups in emailRegex.findall(text):
    matches.append(groups[0])

# Copy resaults to the clipboard.
if len(matches) > 0:
    pyperclip.copy('\n'.join(matches))
    print('Copied to clipboard:')
    print('\n'.join(matches))
else:
    print('No phone numbers or email addresses found.')


import re
import sys

def is_valid_address(address):
    is_valid_ip = re.match("^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$", address)

    is_valid_dns = re.match("^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])$", address)

    if is_valid_ip or is_valid_dns:
        return True
    else:
        return False

def get_private_ip_address():
    import socket
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    s.connect(('8.8.8.8', 1))  # connect() for UDP doesn't send packets
    local_ip_address = s.getsockname()[0]
    return local_ip_address

def option_handler(message_request, message_error, message_success, options, position_default ):
    selected = ""
    while str(selected).lower() not in [x.lower() for x in options]:
        print(message_request)
        selected = input()
        if (selected is None or selected == "") and position_default is not None and position_default < len(options):
            selected = options[position_default]
        if str(selected).lower() not in [x.lower() for x in options] and message_error is not None:
            print(message_error)
    if message_success is not None:
        print(message_success)
    return [x.lower() for x in options].index(str(selected).lower())

def check_is_win():
    return sys.platform.startswith('win')


"""
REST

HTTPメソッド クライアントが行いたい処理をサーバーに伝える

GET     データの参照
POST    データの新規登録
PUT     データの更新
DELETE  データの削除
"""

import urllib.request
import json

payload = {'key1': 'value1', 'key2': 'value2'}

# GET
# url = 'http://httpbin.org/get' + '?' + urllib.parse.urlencode(payload)
# print(url)

# with urllib.request.urlopen(url) as f:
    # decode することで人の目できれいに見えるようにできる
    # Json形式で返ってくる
    # print(f.read().decode('utf-8'))
    # Python の辞書型で返す場合
    # 返ってきたものを Python で扱える
    # r = json.loads(f.read().decode('utf-8'))
    # print(type(r))

# POST
# Request のオブジェクトを渡す
payload = json.dumps(payload).encode('utf-8')
# req = urllib.request.Request(
#     'http://httpbin.org/post', data=payload, method='POST'
# )
# with urllib.request.urlopen(req) as f:
#     print(json.loads(f.read().decode('utf-8')))

# PUT
req = urllib.request.Request(
    'http://httpbin.org/put', data=payload, method='PUT'
)
with urllib.request.urlopen(req) as f:
    print(json.loads(f.read().decode('utf-8')))

req = urllib.request.Request(
    'http://httpbin.org/delete', data=payload, method='DELETE'
)
with urllib.request.urlopen(req) as f:
    print(json.loads(f.read().decode('utf-8')))


import matplotlib.pyplot as plt
import numpy as np

def main():
    mapname = 'f1_aut_wide_raceline'
    iteration_no = 1
    TESTMODE = "Benchmark"
    Max_iter = 5
    raceline = np.loadtxt('src/my_waypoint_follower/my_waypoint_follower/' + mapname+'.csv',delimiter=',')
    # raceline_float = raceline_str.astype(np.float)
    while iteration_no <= Max_iter:
        data = np.loadtxt('src/my_waypoint_follower/my_waypoint_follower/csv/'+mapname+'/'+TESTMODE+"/lap"+str(iteration_no)+'.csv',delimiter=',',skiprows=2)
        # print(data)
        plt.figure()
        plt.plot(data[:,0],data[:,1],label = "Actual paths",marker='x',markersize = 1)
        plt.plot(raceline[:,1],raceline[:,2],label = "Desired paths")
        plt.legend()
        plt.savefig(f"src/my_waypoint_follower/my_waypoint_follower/csv/{mapname}/{TESTMODE}/graph/Trajectory_lap_{str(iteration_no)}.svg")
        plt.figure()
        plt.plot(data[:,5],data[:,3],label = "Speed Profile")
        plt.plot(data[:,5],data[:,4],label = "Acttual speed")
        plt.legend()
        plt.savefig(f"src/my_waypoint_follower/my_waypoint_follower/csv/{mapname}/{TESTMODE}/graph/Speed_lap_{str(iteration_no)}.svg")
        iteration_no += 1

    for i in range(0,Max_iter):
        pass

if __name__ == "__main__":
    main()


from typing import Optional, Tuple, Union
import random
import numpy as np
from scipy.ndimage import median_filter
from ..._transform import Transformer

class MedianFilter(Transformer):
    def __init__(
        self,
        filter_size: Union[int, Tuple[int, int]]=(3, 5),
    ) -> None:
        self.filter_size = filter_size

    def augument_median_filter(
        self,
        inp: np.ndarray
    ) -> np.ndarray:

        for b in range(inp.shape[0]):
            for c in range(inp.shape[3]):
                if isinstance(self.filter_size, int):
                    filter_size = self.filter_size
                else:
                    filter_size = np.random.randint(*self.filter_size)
                inp[b, :, :, c] = median_filter(inp[b, :, :, c], filter_size)
        return inp

    def __call__(
        self,
        inp: np.ndarray,
        mask: np.ndarray,
        scale: Optional[float]=None
    ) -> Union[np.ndarray, np.ndarray]:

        inp = self.augument_median_filter(inp)
        return inp, mask

class RandomMedianFilter(Transformer):
    def __init__(self) -> None:
        super().__init__()
        self.median_filter_fn = [MedianFilter(), None]

    def __call__(
        self,
        inp: np.ndarray,
        mask: np.ndarray
    ) -> Union[np.ndarray, np.ndarray]:

        median_filter_fn = random.choice(self.median_filter_fn)
        if median_filter_fn is None:
            return inp, mask
        else:
            return median_filter_fn(inp, mask)


from collections import namedtuple
from pathlib import Path

# Dataset and results root directory
_DATASET_ROOT = Path(__file__).parent / 'data/source file'
_RESULTS_ROOT = Path(__file__).parent / 'data/labeled data'
_MAP_ROOT = Path(__file__).parent / 'data/mapped data'
_RESULTS_ROOT.mkdir(exist_ok=True)

Dataset = namedtuple('Dataset', ['name', 'root', 'versions', 'src', 'labeldata', 'mapdata'])

# Source codes and bug repositories
# DP-CNN use camel, jEdit, lucene, xalan, xerces, synapse, poi
camel = Dataset(
    'camel',
    _DATASET_ROOT / 'camel',
    [1.4, 1.6],
    [_DATASET_ROOT / 'camel/camel-1.4', _DATASET_ROOT / 'camel/camel-1.6'],
    [_RESULTS_ROOT / 'camel/camel-1.4.csv', _RESULTS_ROOT / 'camel/camel-1.6.csv'],
    [_MAP_ROOT / 'camel/camel-1.4.csv', _MAP_ROOT / 'camel/camel-1.6.csv']
)

jedit = Dataset(
    'jedit',
    _DATASET_ROOT / 'jedit',
    [4.0, 4.1],
    [_DATASET_ROOT / 'jedit/jedit-4.0', _DATASET_ROOT / 'jedit/jedit-4.1'],
    [_RESULTS_ROOT / 'jedit/jedit-4.0.csv', _RESULTS_ROOT / 'jedit/jedit-4.1.csv'],
    [_MAP_ROOT / 'jedit/jedit-4.0.csv', _MAP_ROOT / 'jedit/jedit-4.1.csv']
)

lucene = Dataset(
    'lucene',
    _DATASET_ROOT / 'lucene',
    [2.0, 2.2],
    [_DATASET_ROOT / 'lucene/lucene-2.0', _DATASET_ROOT / 'lucene/lucene-2.2'],
    [_RESULTS_ROOT / 'lucene/lucene-2.0.csv', _RESULTS_ROOT / 'lucene/lucene-2.2.csv'],
    [_MAP_ROOT / 'lucene/lucene-2.0.csv', _MAP_ROOT / 'lucene/lucene-2.2.csv']
)

xalan = Dataset(
    'xalan',
    _DATASET_ROOT / 'xalan',
    [2.5, 2.6],
    [_DATASET_ROOT / 'xalan/xalan-2.5', _DATASET_ROOT / 'xalan/xalan-2.6'],
    [_RESULTS_ROOT / 'xalan/xalan-2.5.csv', _RESULTS_ROOT / 'xalan/xalan-2.6.csv'],
    [_MAP_ROOT / 'xalan/xalan-2.5.csv', _MAP_ROOT / 'xalan/xalan-2.6.csv']
)

xerces = Dataset(
    'xerces',
    _DATASET_ROOT / 'xerces',
    [1.2, 1.3],
    [_DATASET_ROOT / 'xerces/xerces-1.2', _DATASET_ROOT / 'xerces/xerces-1.3'],
    [_RESULTS_ROOT / 'xerces/xerces-1.2.csv', _RESULTS_ROOT / 'xerces/xerces-1.3.csv'],
    [_MAP_ROOT / 'xerces/xerces-1.2.csv', _MAP_ROOT / 'xerces/xerces-1.3.csv']
)

synapse = Dataset(
    'synapse',
    _DATASET_ROOT / 'synapse',
    [1.1, 1.2],
    [_DATASET_ROOT / 'synapse/synapse-1.1', _DATASET_ROOT / 'synapse/synapse-1.2'],
    [_RESULTS_ROOT / 'synapse/synapse-1.1.csv', _RESULTS_ROOT / 'synapse/synapse-1.2.csv'],
    [_MAP_ROOT / 'synapse/synapse-1.1.csv', _MAP_ROOT / 'synapse/synapse-1.2.csv']
)

poi = Dataset(
    'poi',
    _DATASET_ROOT / 'poi',
    [2.5, 3.0],
    [_DATASET_ROOT / 'poi/poi-2.5', _DATASET_ROOT / 'poi/poi-3.0'],
    [_RESULTS_ROOT / 'poi/poi-2.5.csv', _RESULTS_ROOT / 'poi/poi-3.0.csv'],
    [_MAP_ROOT / 'poi/poi-2.5.csv', _MAP_ROOT / 'poi/poi-3.0.csv']
)

# Current dataset in use. (change this name to change the dataset)
DATASET = camel

#data after concat will be save to file CSV
_INPUT_ROOT = Path(__file__).parent / 'datainput'

Datainput = namedtuple('Datainput',['name', 'root', 'version', 'label', 'tradgene'])

savecamel = Datainput(
    'camel',
    _INPUT_ROOT / 'camel',
    [1.4, 1.6],
    [_INPUT_ROOT / 'camel/label/camel-1.4.csv', _INPUT_ROOT / 'camel/label/camel-1.6.csv'],
    [_INPUT_ROOT / 'camel/tradgene/camel-1.4.csv', _INPUT_ROOT / 'camel/tradgene/camel-1.6.csv']
)

savejedit = Datainput(
    'jedit',
    _INPUT_ROOT / 'jedit',
    [4.0, 4.1],
    [_INPUT_ROOT / 'jedit/label/jedit-4.0.csv', _INPUT_ROOT / 'jedit/label/jedit-4.1.csv'],
    [_INPUT_ROOT / 'jedit/tradgene/jedit-4.0.csv', _INPUT_ROOT / 'camel/tradgene/jedit-4.1.csv']
)

savelucene = Datainput(
    'lucene',
    _INPUT_ROOT / 'lucene',
    [2.0, 2.2],
    [_INPUT_ROOT / 'lucene/label/lucene-2.0.csv', _INPUT_ROOT / 'lucene/label/lucene-2.2.csv'],
    [_INPUT_ROOT / 'lucene/tradgene/lucene-2.0.csv', _INPUT_ROOT / 'lucene/tradgene/lucene-2.2.csv']
)

savexalan = Datainput(
    'xalan',
    _INPUT_ROOT / 'xalan',
    [2.5, 2.6],
    [_INPUT_ROOT / 'xalan/label/xalan-2.5.csv', _INPUT_ROOT / 'xalan/label/xalan-2.5.csv'],
    [_INPUT_ROOT / 'xalan/tradgene/xalan-2.5.csv', _INPUT_ROOT / 'xalan/tradgene/xalan-2.5.csv']
)

savecxerces = Datainput(
    'xerces',
    _INPUT_ROOT / 'xerces',
    [1.2, 1.3],
    [_INPUT_ROOT / 'xerces/label/xerces-1.2.csv', _INPUT_ROOT / 'xerces/label/xerces-1.3.csv'],
    [_INPUT_ROOT / 'xerces/tradgene/xerces-1.2.csv', _INPUT_ROOT / 'xerces/tradgene/xerces-1.3.csv']
)

savesynapse = Datainput(
    'synapse',
    _INPUT_ROOT / 'synapse',
    [1.1, 1.2],
    [_INPUT_ROOT / 'synapse/label/synapse-1.1.csv', _INPUT_ROOT / 'synapse/label/synapse-1.2.csv'],
    [_INPUT_ROOT / 'synapse/tradgene/synapse-1.1.csv', _INPUT_ROOT / 'synapse/tradgene/synapse-1.2.csv']
)

savepoi = Datainput(
    'poi',
    _INPUT_ROOT / 'poi',
    [2.5, 3.0],
    [_INPUT_ROOT / 'poi/label/poi-2.5.csv', _INPUT_ROOT / 'pot/label/poi-3.0.csv'],
    [_INPUT_ROOT / 'poi/tradgene/poi-2.5.csv', _INPUT_ROOT / 'poi/tradgene/poi-3.0.csv']
)

if __name__ == '__main__':

    print(savecamel.label)


# import typing
from __future__ import annotations
from enum import Enum
from collections import namedtuple
from functools import cmp_to_key
from abc import ABC, abstractmethod

TaggedLine = namedtuple("TaggedLine", "line priorities")

class TreeWorker(ABC):
    @abstractmethod
    def accept(self, tree: Node):
        return tree

class TreeSorter(TreeWorker):
    def accept(self, tree: Node) -> Node:
        for child in tree.children:
            self.accept(child)
        tree.children.sort(key=cmp_to_key(lambda a, b: 0 if Node.is_irrelevant(a.tag) or Node.is_irrelevant(b.tag) else a.tag.value - b.tag.value))
        return tree

class TreeUnspacer(TreeWorker):
    # removing blank lines helps with the sorting
    def accept(self, tree: Node) -> Node:
        tree.children = [n for n in tree.children if n.tag != Tag.BLANK_LINE]
        for child in tree.children:
            self.accept(child)
        return tree

class TreeSpacer(TreeWorker):
    # doesn't work properly, but doesn't matter.
    # Running `gdformat script.gd` fixes spacing anyway.
    def accept(self, tree: Node) -> Node:
        tree.children = [c for c in tree.children if c.tag != Tag.BLANK_LINE]
        for c in tree.children:
            self.accept(c)

        for i in [i for i in range(len(tree.children)) if tree.children[i].children]:
            tree.children.insert(i, Node(Tag.BLANK_LINE, 1, "\n"))

        return tree

class TreePrinter(TreeWorker):
    def accept(self, tree: Node) -> str:
        s = tree.content
        for child in tree.children:
            s += self.accept(child)
        return s

class Node:
    @staticmethod
    def is_irrelevant(tag) -> bool:
        return tag in [Tag.IGNORE, Tag.BLANK_LINE]

    @staticmethod
    def node_comp(n1, n2) -> int:
        return 0 if Node.is_irrelevant(n1.tag) or Node.is_irrelevant(n2.tag) else n1.tag.value - n2.tag.value

    def __init__(self, tag, indent, content):
        self.tag = tag
        self.indent = indent
        self.parent = None
        self.children = []
        self.content = content

    def get_semantic_children(self):
        # only children that are not of type IGNORE
        return [child for child in self.children if not Node.is_irrelevant(child.tag)]

    def add_child(self, node: Node):
        self.children.append(node)
        node.parent = self

    def sort(self):
        for child in self.children:
            child.sort()
        self.children.sort(key=cmp_to_key(Node.node_comp))

    def __str__(self):
        return self.to_string("")

    def to_string(self, indent):
        s = "%s%s(\n" % (indent, self.tag)
        for c in self.children:
            s += c.to_string(indent + "  ")
            s += "\n"
        s += indent + ")"
        return s

class Tag(Enum):
    # https://docs.godotengine.org/en/stable/getting_started/scripting/gdscript/gdscript_styleguide.html#code-order
    ROOT = -1
    TOOL = 10
    CLASS_NAME = 20
    INHERITANCE = 30
    DOCSTRING = 40
    SIGNAL = 50
    ENUM = 60
    CONST = 70
    EXPORT_VAR = 80
    VAR = 90  # public and private
    ONREADY = 100
    FN_INIT = 110
    FN_READY = 120
    FN_BUILTIN = 130
    INNER_CLASS = 140
    STATIC_METHOD = 150
    METHOD = 160
    IGNORE = 1000
    BLANK_LINE = 2000

    def __lt__(self, other):
        return self.value < other.value

def indent_length(ident: str) -> int:
    return len(ident)  # hook in here for tabs vs spaces

# FIXME: make work for different spacing types
class TreeGenerator:
    def __init__(self):
        self._current_block = None

    def classify(self, line: str, line_number: int) -> Tag:
        tag = Tag.IGNORE
        if line.strip() == "":
            tag = Tag.BLANK_LINE
        elif line.startswith("tool"):
            tag = Tag.TOOL
        elif line.startswith("class_name"):
            tag = Tag.CLASS_NAME
        elif line.startswith("extends"):
            tag = Tag.INHERITANCE
        elif line.startswith("#"):
            children = self._current_block.get_semantic_children()
            # if either we have only encountered whitespace so far, or the last node was a docstring itself
            # (or another node that comes before that) then the line is a docstring too.
            # Else, it's just a regular comment → IGNORE
            tag = Tag.DOCSTRING if self._current_block.tag.value <= Tag.DOCSTRING.value and (len(children) == 0 or children[-1].tag.value <= Tag.DOCSTRING.value) else Tag.IGNORE
        elif line.startswith("const"):
            tag = Tag.CONST
        elif line.startswith("signal"):  # FIXME: check for looong signals
            tag = Tag.SIGNAL
        elif line.startswith("var"):
            tag = Tag.VAR
        elif line.startswith("export"):
            tag = Tag.EXPORT_VAR
        elif line.startswith("onready"):
            tag = Tag.ONREADY
        elif line.startswith("static func "):
            tag = Tag.STATIC_METHOD
        elif line.startswith("func _init"):
            tag = Tag.FN_INIT
        elif line.startswith("func _ready"):
            tag = Tag.FN_READY
        elif line.startswith("func _"):
            tag = Tag.FN_BUILTIN
        elif line.startswith("func "):
            tag = Tag.METHOD
        elif line.startswith("enum "):
            tag = Tag.ENUM
        elif line.startswith("class"):
            tag = Tag.INNER_CLASS

        return tag

    def treeify(self, lines):
        self._current_block = Node(Tag.ROOT, -1, "")

        for i in range(len(lines)):
            line = lines[i]
            stripped = line.lstrip()
            tag = self.classify(stripped, i + 1)
            indent = indent_length(line) - indent_length(stripped)
            if not line.endswith("\n"):
                # fix last line of file.
                # If that line is sorted to some other place, the
                # newline would be missing
                line += "\n"

            new_block = Node(tag, indent, line)
            if stripped:  # empty lines don't affect indent
                if indent == self._current_block.indent + 1:  # append to current parent block
                    self._current_block.add_child(new_block)
                elif indent == self._current_block.indent + 2:  # last block was actually a new parent block → fix up
                    self._current_block = self._current_block.children[-1]
                    self._current_block.add_child(new_block)
                    """
                    elif indent < self._current_block.indent:  # dedent → pop block(s)
                        while indent < self._current_block.indent:
                            self._current_block = self._current_block.parent
                        self._current_block.add_child(new_block)
                    """
                else:  # same level → new block
                    while indent < self._current_block.indent:
                        self._current_block = self._current_block.parent
                    assert indent == self._current_block.indent
                    self._current_block.parent.add_child(new_block)
                    self._current_block = new_block
            else:  # whitespace
                self._current_block.add_child(new_block)

        while self._current_block.parent is not None:
            self._current_block = self._current_block.parent

        return self._current_block

def main():
    tg = TreeGenerator()
    with open("./test/FogOfWar3D.gd", "r") as fh:
        lines = fh.readlines()
        tree = tg.treeify(lines)
        for worker in [TreeUnspacer(), TreeSorter(), TreePrinter()]:
            tree = worker.accept(tree)

        print(tree)

if __name__ == "__main__":
    main()


from setuptools import setup, find_packages

VERSION = '0.1.2.0'

setup(
    name="lhub_cli",
    version=VERSION,
    author="Chad Roberts",
    author_email="chad@logichub.com",
    description="LogicHub CLI",
    long_description="A Python package for interacting with LogicHub via shell commands",
    packages=find_packages(),
    install_requires=[
        "lhub ~= 0.2.6",
        "configobj >= 5.0.6",
        "dataclasses_json >= 0.5.6",
        "rsa >= 4.8",
        "requests",
        "tabulate",
        "colorama",
        "structlog",
        "progressbar2",  # Only used in sample scripts for now, and imported not as "progressbar2" but just "progressbar"
    ],
    keywords=["python", "lhub", "LogicHub", "api", "security", "cli"],

    url="https://github.com/deathbywedgie/lhub_cli",
    project_urls={
        "Bug Tracker": "https://github.com/deathbywedgie/lhub_cli/issues",
    },

    # https://pypi.org/classifiers/
    classifiers=[
        "Development Status :: 1 - Planning",
        "Intended Audience :: End Users/Desktop",
        "Intended Audience :: System Administrators",
        "Intended Audience :: Information Technology",
        "Programming Language :: Python :: 3.10",
        "Natural Language :: English",
    ]
)


def plot_section(profname,arg):

    import config
    import numpy as np
    import matplotlib.pyplot as plt
    from scipy.interpolate import griddata

    f_p  = open(config.sdir2+profname+'_p.txt','r')
    f_xy = open(config.tdir2+profname+'_traj.txt','r')

    if arg == 0:
        f_var  = open(config.sdir2+profname+'_t.txt','r')
    if arg == 1:
        f_var  = open(config.sdir2+profname+'_s.txt','r')

    p_arr, s_arr, t_arr, lat_arr, lon_arr, dist_arr = ([] for i in range(6))

    p_cnt = 0
    for p_line in f_p: # Loop over lines and extract variables of interest
        p_line = p_line.strip().split() # removes /n (strip) and converts str to list (split)
        s_line = f_var.readline().strip().split()
        t_line = f_xy.readline().strip().split()
        lat_arr.append(float(t_line[1]))
        lon_arr.append(float(t_line[2]))
        dist_arr.append(float(t_line[3]))

        k = 0

        for i in p_line:
            if float(i)<9000:
                p_arr.append(float(i))
                s_arr.append(float(s_line[k]))
                t_arr.append(dist_arr[-1])
                k = k + 1
        if p_cnt == 0:
            np_elem = np.size(p_arr)
        p_cnt = p_cnt + 1
    f_p.close()
    f_var.close()

    p_arr = -np.asarray(p_arr)
    s_arr = np.asarray(s_arr)
    t_arr = np.asarray(t_arr)

    # define grid.
    xi = np.linspace(0,max(t_arr),p_cnt)
    yi = np.linspace(min(p_arr),0,np_elem)

    # grid the data.
    zi = griddata((t_arr, p_arr), s_arr, (xi[None,:], yi[:,None]), method='linear')
    CS = plt.contour(xi,yi,zi,15,linewidths=0.5,colors='k')
    CS = plt.contourf(xi,yi,zi,15,cmap=plt.cm.jet)

    plt.colorbar() # draw colorbar
    plt.scatter(t_arr,p_arr,marker='o',c='b',s=1) # draw locations of observations
    plt.grid()
    plt.ylabel('Pressure (dbar)',fontsize=5)
    plt.xlabel('Distance (Km)',fontsize=5)

    if arg == 0:
        plt.title('Temperature section - Float: '+profname,fontsize=5)
    if arg == 1:
        plt.title('Salinity section - Float: '+profname,fontsize=5)

    return;


'''
--- Day 9: Marble Mania ---
You talk to the Elves while you wait for your navigation system to initialize. To pass the time, they introduce you to their favorite marble game.

The Elves play this game by taking turns arranging the marbles in a circle according to very particular rules. The marbles are numbered starting with 0 and increasing by 1 until every marble has a number.

First, the marble numbered 0 is placed in the circle. At this point, while it contains only a single marble, it is still a circle: the marble is both clockwise from itself and counter-clockwise from itself. This marble is designated the current marble.

Then, each Elf takes a turn placing the lowest-numbered remaining marble into the circle between the marbles that are 1 and 2 marbles clockwise of the current marble. (When the circle is large enough, this means that there is one marble between the marble that was just placed and the current marble.) The marble that was just placed then becomes the current marble.

However, if the marble that is about to be placed has a number which is a multiple of 23, something entirely different happens. First, the current player keeps the marble they would have placed, adding it to their score. In addition, the marble 7 marbles counter-clockwise from the current marble is removed from the circle and also added to the current player's score. The marble located immediately clockwise of the marble that was removed becomes the new current marble.

For example, suppose there are 9 players. After the marble with value 0 is placed in the middle, each player (shown in square brackets) takes a turn. The result of each of those turns would produce circles of marbles like this, where clockwise is to the right and the resulting current marble is in parentheses:

[-] (0)
[1]  0 (1)
[2]  0 (2) 1
[3]  0  2  1 (3)
[4]  0 (4) 2  1  3
[5]  0  4  2 (5) 1  3
[6]  0  4  2  5  1 (6) 3
[7]  0  4  2  5  1  6  3 (7)
[8]  0 (8) 4  2  5  1  6  3  7
[9]  0  8  4 (9) 2  5  1  6  3  7
[1]  0  8  4  9  2(10) 5  1  6  3  7
[2]  0  8  4  9  2 10  5(11) 1  6  3  7
[3]  0  8  4  9  2 10  5 11  1(12) 6  3  7
[4]  0  8  4  9  2 10  5 11  1 12  6(13) 3  7
[5]  0  8  4  9  2 10  5 11  1 12  6 13  3(14) 7
[6]  0  8  4  9  2 10  5 11  1 12  6 13  3 14  7(15)
[7]  0(16) 8  4  9  2 10  5 11  1 12  6 13  3 14  7 15
[8]  0 16  8(17) 4  9  2 10  5 11  1 12  6 13  3 14  7 15
[9]  0 16  8 17  4(18) 9  2 10  5 11  1 12  6 13  3 14  7 15
[1]  0 16  8 17  4 18  9(19) 2 10  5 11  1 12  6 13  3 14  7 15
[2]  0 16  8 17  4 18  9 19  2(20)10  5 11  1 12  6 13  3 14  7 15
[3]  0 16  8 17  4 18  9 19  2 20 10(21) 5 11  1 12  6 13  3 14  7 15
[4]  0 16  8 17  4 18  9 19  2 20 10 21  5(22)11  1 12  6 13  3 14  7 15
[5]  0 16  8 17  4 18(19) 2 20 10 21  5 22 11  1 12  6 13  3 14  7 15
[6]  0 16  8 17  4 18 19  2(24)20 10 21  5 22 11  1 12  6 13  3 14  7 15
[7]  0 16  8 17  4 18 19  2 24 20(25)10 21  5 22 11  1 12  6 13  3 14  7 15
The goal is to be the player with the highest score after the last marble is used up. Assuming the example above ends after the marble numbered 25, the winning score is 23+9=32 (because player 5 kept marble 23 and removed marble 9, while no other player got any points in this very short example game).

Here are a few more examples:

10 players; last marble is worth 1618 points: high score is 8317
13 players; last marble is worth 7999 points: high score is 146373
17 players; last marble is worth 1104 points: high score is 2764
21 players; last marble is worth 6111 points: high score is 54718
30 players; last marble is worth 5807 points: high score is 37305
'''

import re
import itertools as it
from collections import deque

TEST = '''\
10 players; last marble is worth 1618 points: high score is 8317
13 players; last marble is worth 7999 points: high score is 146373
17 players; last marble is worth 1104 points: high score is 2764
21 players; last marble is worth 6111 points: high score is 54718
30 players; last marble is worth 5807 points: high score is 37305\
'''.split('\n')
INPUT = '452 players; last marble is worth 71250 points'

p = re.compile(r'(\d+) players; last marble is worth (\d+) points.*')
input_ = INPUT

def step(circle, current_position=0, next_marble=0):
    if next_marble % 23 == 0:
        score = next_marble
        next_position = (current_position - 7) % len(circle)
        return circle[:next_position] + circle[next_position + 1:], next_position, score + circle[next_position]
    next_position = (current_position + 2) % len(circle)
    if next_position == 0:
        next_position = len(circle)
    return circle[:next_position] + [next_marble] + circle[next_position:], next_position, 0

def part1(input_):
    n_players, n_marbles = *map(int, p.match(input_).groups()),
    players_score = [0 for player in range(n_players)]
    circle = [0] ; current_position = 0
    for player, marble in zip(it.cycle(range(n_players)),range(1, n_marbles+1)):
        circle, current_position, score = step(circle,current_position,marble)
        players_score[player] += score
    print('Part1: ', max(players_score))

def game(n_marbles):
    circle = deque([0])
    for i in range(23,n_marbles+1,23):
        for j in range(i-22,i):
            circle.rotate(-1)
            circle.append(j)
        circle.rotate(7)
        yield i, i + circle.pop()
        circle.rotate(-1)

def part2(input_):
    n_players, n_marbles = *map(int, p.match(input_).groups()),
    n_marbles = 100 * n_marbles
    players_score = [0 for player in range(n_players)]
    for marble, score in game(n_marbles):
        player = marble % n_players
        players_score[player] += score
    print('Part2: ', max(players_score))

#
# for input_ in TEST:
#     part1(input_)
# part1(INPUT)
part2(INPUT)


import string
import re

def read_ciphertext(file):
    with open(file, "r") as f:
        return "".join(f.readlines()).strip()

def decrypt_caesar(ciphertext, key):
    alphabet = string.ascii_lowercase
    plaintext = ""
    n = ord(key) - ord('A')
    print(n)

    for c in ciphertext:
        if c.lower() in alphabet:
            new_char = alphabet[alphabet.index(c.lower()) - n]
            if c.isupper():
                plaintext += new_char.upper()
            else:
                plaintext += new_char
        else:
            plaintext += c

    return plaintext

def find_flag(text):
    return re.findall("frictf{.*}", text)[0]

if __name__ == '__main__':
    ct = read_ciphertext("chall/data.txt")
    text = decrypt_caesar(ct, 'H')
    print(find_flag(text))