import socket
from struct import pack,unpack
from json import loads, dumps
from base64 import b64encode, b64decode
from binascii import hexlify,unhexlify
from cmac import CMAC
import time

"""GWMP Identifiers"""
PUSH_DATA = 0
PUSH_ACK = 1
PULL_DATA = 2
PULL_RESP = 3
PULL_ACK = 4
TX_ACK = 5

class Rxpk(object):
    """A Gateway Rxpk (upstream) JSON object.

    The root JSON object shall contain zero or more rxpk
    objects. See Gateway to Server Interface Definition
    Section 6.2.2.

    Attributes:
        tmst (int): value of the gateway time counter when the
                    frame was received (us precision).
        freq (float): Centre frequency of recieved signal (MHz).
        chan (int): Concentrator IF channel on which the frame
                    was received.
        rfch (int): Concentrator RF chain on which the frame
                    was received.
        stat (int): The result of the gateway's CRC test on the
                    frame - 1 = correct, -1 = incorrect, 0 = no test.
        modu (str): Modulation technique - "LORA" or "FSK".
        datr (str): Datarate identifier. For Lora, comprised of
                    "SFnBWm where n is the spreading factor and
                    m is the frame's bandwidth in kHz.
        codr (str): ECC code rate as "k/n" where k is carried
                    bits and n is total bits received.
        rssi (int): The measured received signal strength (dBm).
        lsnr (float): Measured signal to noise ratio (dB).
        data (str): Frame payload encoded in Base64.
        time (str): UTC time of the LoRa frame (us precision).
        size (int): Number of octects in the received frame.

    """

    def __init__(self, tmst=None, freq=None, chan=None, rfch=None,
                 stat=None, modu=None, datr=None, codr=None, rssi=None,
                 lsnr=None, data=None, time=None, size=None):
        """Rxpk initialisation method.

        """
        self.tmst = tmst
        self.freq = freq
        self.chan = chan
        self.rfch = rfch
        self.stat = stat
        self.modu = modu
        self.datr = datr
        self.codr = codr
        self.rssi = rssi
        self.lsnr = lsnr
        self.data = data
        self.time = time
        self.size = size

    @classmethod
    def decode(cls, rxp):
        """Decode Rxpk JSON dictionary.

        Args:
            rxp (dict): Dict representation of rxpk JSON object.

        Returns:
            Rxpk object if successful, None otherwise.

        """

        rkeys = rxp.keys()
        # Check mandatory fields exist
        mandatory = ('tmst', 'freq', 'chan', 'rfch',
                     'stat', 'modu', 'datr', 'codr',
                     'rssi', 'lsnr', 'data')
        if not all (rkeys for k in mandatory):
            return None
        # Mandatory attributes
        tmst = int(rxp['tmst'])
        freq = float(rxp['freq'])
        chan = int(rxp['chan'])
        rfch = int(rxp['rfch'])
        stat = int(rxp['stat'])
        modu = rxp['modu']
        datr = rxp['datr']
        codr = rxp['codr']
        rssi = int(rxp['rssi'])
        lsnr = float(rxp['lsnr'])
        data = b64decode(rxp['data'])
        # Optional attributes
        time = rxp['time'] if 'time' in rkeys else None
        size = int(rxp['size']) if 'size' in rkeys else None
        a = Rxpk(tmst=tmst, freq=freq, chan=chan, rfch=rfch, stat=stat,
                    modu=modu, datr=datr, codr=codr, rssi=rssi, lsnr=lsnr,
                    data=data, time=time, size=size)

        for m, v in a.__dict__.items():
            try:
                for attr, value in v.__dict__.items():
                    print('    '+attr, value)
            except:
                print(m, v)
                continue

        return a

class Stat(object):
    """A Gateway Stat (upstream) JSON object.

    The root JSON object shall contain zero or one stat
    objects. See Gateway to Server Interface Definition
    Section 6.2.1.

    Attributes:
        time (str): UTC time of the LoRa frame (us precision).
        lati (float): Gateway latitude in degress north of the equator.
        long (float): Gateway longitude in degress north of the equator.
        alti (int): Altitude of the gateway's position in metres above sea
                    level
        rxnb (int): Number of radio frames received since gateway start.
        rxok (int): Number of radio frames received with correct CRC since
                    gateway start.
        rwfw (int): Number of radio frames forwarded to the network server
                    since gateway start.
        ackr (int): Percentage of radio frames forwarded to the network
                    server, and acknowledged by the server since gateway
                    start.
        dwnb (int): Number of radio frames received from the network server
                    since gateway start.
        txnb (int): Number of radio frames transmitted since gateway start.

    """

    def __init__(self):
        """Stat initialisation method.

        """
        self.time = None
        self.lati = None
        self.long = None
        self.alti = None
        self.rxnb = None
        self.rxok = None
        self.rwfw = None
        self.ackr = None
        self.dwnb = None
        self.txnb = None

    @classmethod
    def decode(cls, stp):
        """Decode Stat JSON dictionary.

        Args:
            stp (dict): Dict representation of stat JSON object.

        Returns:
            Stat object.

        """

        skeys = stp['stat'].keys()
        s = Stat()

        # Set the attributes
        s.time = stp['stat']['time'] if 'time' in skeys else None
        s.lati = float(stp['stat']['lati']) if 'lati' in skeys else None
        s.long = float(stp['stat']['long']) if 'long' in skeys else None
        s.alti = int(stp['stat']['alti']) if 'alti' in skeys else None
        s.rxnb = int(stp['stat']['rxnb']) if 'rxnb' in skeys else None
        s.rxok = int(stp['stat']['rxok']) if 'rxok' in skeys else None
        s.rwfw = int(stp['stat']['rwfw']) if 'rwfw' in skeys else None
        s.ackr = int(stp['stat']['ackr']) if 'ackr' in skeys else None
        s.dwnb = int(stp['stat']['dwnb']) if 'dwnb' in skeys else None
        s.txnb = int(stp['stat']['txnb']) if 'txnb' in skeys else None

        print('STAT PACKET')
        for attr, value in s.__dict__.items():
            print(attr, value)
        return s

class GatewayMessage():
    """A Gateway Message.

    Messages sent between the LoRa gateway and the LoRa network
    server. The gateway message protocol operates over UDP and
    occupies the data area of a UDP packet. See Gateway to Server
    Interface Definition.

    Attributes:
        version (int): Protocol version - 0x01 or 0x02
        token (str): Arbitrary tracking value set by the gateway.
        id (int): Identifier - see GWMP Identifiers above.
        gatewayEUI (str): Gateway device identifier.
        payload (str): GWMP payload.
        remote (tuple): Gateway IP address and port.
        ptype (str): JSON protocol top-level object type.
    """

    def __init__(self, version=2, token=0, identifier=None,
                 gatewayEUI=None, txpk=None, remote=None,
                 ptype=None):
        """GatewayMessage initialisation method.

        Args:
            version (int): GWMP version.
            token (str): Message token.
            id: GWMP identifier.
            gatewayEUI: gateway device identifier.
            payload: GWMP payload.
            ptype (str): payload type
            remote: (host, port)

        Raises:
            TypeError: If payload argument is set to None.

        """
        self.version = version
        self.token = token
        self.id = identifier
        self.gatewayEUI = gatewayEUI
        self.payload = ''
        self.ptype = ptype
        self.remote = remote

        self.rxpk = None
        self.txpk = txpk
        self.stat = None

    @classmethod
    def decode(cls, data, remote):
        """Create a Message object from binary representation.

        Args:
            data (str): UDP packet data.
            remote (tuple): Gateway address and port.

        Returns:
            GatewayMessage object on success.

        """
        # Check length
        if len(data) < 4:
            raise DecodeError("Message too short.")
        # Decode header
        (version, token, identifer) = unpack('<BHB', data[:4])
        #print('Received Token', token)
        m = GatewayMessage(version=version, token=token, identifier=identifer)
        m.remote = remote
        # Test versions (1 or 2) and supported message types
        if ( m.version not in (1, 2) or
             m.version == 1 and m.id not in (PUSH_DATA, PULL_DATA) or
             m.version == 2 and m.id not in (PUSH_DATA, PULL_DATA, TX_ACK)
             ):
                print('Version',m.version,'ID',m.id)
                pass
                #raise UnsupportedMethod()

        # Decode gateway EUI and payload
        if m.id == PUSH_DATA:
            print('PUSH DATA')
            if len(data) < 12:
                raise DecodeError("PUSH_DATA message too short.")
            m.gatewayEUI = unpack('<Q', data[4:12])[0]
            m.payload = data[12:]
        elif m.id == PULL_DATA:
            print('PULL DATA')
            if len(data) < 12:
                raise DecodeError("PULL_DATA message too short.")
            m.gatewayEUI = unpack('<Q', data[4:12])[0]
            #print('Gateway EUI: ',m.gatewayEUI)
        elif m.id == TX_ACK:
            m.payload = data[4:]

        # Decode PUSH_DATA payload
        if m.id == PUSH_DATA:
            try:
                jdata = loads(m.payload)
            except ValueError:
                raise DecodeError("JSON payload decode error")
            m.ptype = list(jdata.keys())[0]
            # Rxpk payload - one or more.

            if  m.ptype == 'rxpk':
                m.rxpk = []

                for r in jdata['rxpk']:
                    rx = Rxpk.decode(r)
                    if rx is not None:
                        m.rxpk.append(rx)
                if not m.rxpk:
                    raise DecodeError("Rxpk payload decode error")

            # Stat payload
            elif m.ptype == 'stat':
                m.stat = Stat.decode(jdata)
                if m.stat is None:
                    raise DecodeError("Stat payload decode error")
            # Unknown payload type
            else:
                raise DecodeError("Unknown payload type")

        '''for a, v in m.__dict__.items():
            try:
                for attr, value in v.__dict__.items():
                    print('    '+attr,value)
            except:
                print(a, v)
                continue
        '''
        return m

    def encode(self):
        """Create a binary representation of message from Message object.

        Returns:
            String of packed data.

        """
        data = ''
        if self.id == PUSH_ACK:
            data = pack('<BHB', self.version, self.token, self.id)
        elif self.id == PULL_ACK:
            data = pack('<BHB', self.version, self.token, self.id)
        elif self.id == PULL_RESP:
            if self.version == 1:
                self.token = 0
            self.payload = self.txpk.encode()
            print(str(self.payload))
            data = pack('<BHB', self.version, self.token, self.id) + \
                    bytearray(self.payload,'utf-8')
        return data

def sendPullResponse(remote, request, txpk,sock):
    """"Send a PULL_RESP message to a gateway.

    The PULL_RESP message transports its payload, a JSON object,
    from the LoRa network server to the LoRa gateway. The length
    of a PULL_RESP message shall not exceed 1000 octets.

    Args:
        request (GatewayMessage): The decoded Pull Request
        txpk (Txpk): The txpk to be transported
    """
    remote = (remote[0], remote[1])

    m = GatewayMessage(version=request.version, token=request.token,
                identifier=PULL_RESP, gatewayEUI=b'9079494338994186168',
                remote=remote, ptype='txpk', txpk=txpk)
    print("Sending PULL_RESP message to %s:%d" % remote)

    sock.sendto(m.encode(), remote)
    data, address = sock.recvfrom(4096)
    print(data)
    print('received %s bytes from %s' % (len(data), address))

def sendPushAck(remote, request,sock):
    """"Send a PULL_ACK message to a gateway.

    """
    remote = (remote[0], remote[1])

    m = GatewayMessage(version=request.version, token=request.token,
                identifier=PUSH_ACK, gatewayEUI=b'9079494338994186168',
                remote=remote, ptype=None)
    print("Sending PULL_ACK message to %s:%d" % remote)

    sock.sendto(m.encode(), remote)

def sendPullAck(remote, request,sock):
    """"Send a PULL_ACK message to a gateway.

    """
    remote = (remote[0], remote[1])

    m = GatewayMessage(version=request.version, token=request.token,
                identifier=PULL_ACK, gatewayEUI=b'9079494338994186168',
                remote=remote, ptype=None)
    print("Sending PULL_ACK message to %s:%d" % remote)

    sock.sendto(m.encode(), remote)

class Txpk(object):
    """A Gateway Txpk (downstream) JSON object.

    The root JSON object shall contain zero or more txpk
    objects. See Gateway to Server Interface Definition
    Section 6.2.4.

    Attributes:
        imme (bool): If true, the gateway is commanded to
                     transmit the frame immediately
        tmst (int): If "imme" is not true and "tmst" is present,
                    the gateway is commanded to transmit the frame
                    when its internal timestamp counter equals the
                    value of "tmst".
        time (str): UTC time. The precision is one microsecond. The
                    format is ISO 8601 compact format. If "imme" is
                    false or not present and "tmst" is not present,
                    the gateway is commanded to transmit the frame at
                    this time.
        freq (float): The centre frequency on when the frame is to
                    be transmitted in units of MHz.
        rfch (int): The antenna on which the gateway is commanded
                    to transmit the frame.
        powe (int): The output power which what the gateway is
                    commanded to transmit the frame.
        modu (str): Modulation technique - "LORA" or "FSK".
        datr (str): Datarate identifier. For Lora, comprised of
                    "SFnBWm where n is the spreading factor and
                    m is the frame's bandwidth in kHz.
        codr (str): ECC code rate as "k/n" where k is carried
                    bits and n is total bits received.
        ipol (bool): If true, commands gateway to invert the
                    polarity of the transmitted bits. LoRa Server sets
                    value to true when "modu" equals "LORA", otherwise
                    the value is omitted.
        size (int): Number of octets in the received frame.
        data (str): Frame payload encoded in Base64. Padding characters
                    shall not be not added
        ncrc (bool): If not false, disable physical layer CRC generation
                    by the transmitter.
    """

    def __init__(self, imme=False, tmst=None, time=None, freq=None,
                 rfch=None, powe=None, modu=None, datr=None, codr=None,
                 ipol=None, size=None, data=None, ncrc=None):
        """Txpk initialisation method.

        """
        self.imme = imme
        self.tmst = tmst
        self.time = time
        self.freq = freq
        self.rfch = rfch
        self.powe = powe
        self.modu = modu
        self.datr = datr
        self.codr = codr
        self.ipol = ipol
        self.size = size
        self.data = data
        self.ncrc = ncrc
        self.keys = ['imme', 'tmst', 'time', 'freq', 'rfch',
                    'powe', 'modu', 'datr', 'codr', 'ipol',
                    'size', 'data', 'ncrc']
        # Base64 encode data, no padding
        if self.data is not None:
            self.size = len(self.data)
            self.data = b64encode(self.data)
            # Remove padding
            if self.data[-2:] == '==':
                self.data = self.data[:-2]
            elif self.data[-1:] == '=':
                self.data = self.data[:-1]
        else:
            self.size = 0

    def encode(self):
        """Create a JSON string from Txpk object

        """
        # Create dict from attributes. Maintain added order
        #jd = {'txpk': collections.OrderedDict()}
        jd = {'txpk':{}}

        for key in self.keys:
            val = getattr(self, key)

            if val is not None:
                if key == 'data':
                    jd['txpk'][key] = val.decode('utf-8')
                else:
                    jd['txpk'][key] = val
            #print('key',key)
            #print('valtype',type(val),val)
        #print(jd)

        return dumps(jd, separators=(',', ':'))

def intPackBytes(n, length, endian='big'):
    """Convert an integer to a packed binary string representation.

    Args:
        n (int: Integer to convert
        length (int): converted string length
        endian (st)r): endian type: 'big' or 'little'

    Returns:
        A packed binary string.
    """

    if length == 0:
        return ''
    h = '%x' % n
    # There must be a better way to do this
    s = unhexlify(str.zfill(('0'*(len(h) % 2) + h), length*2))
    if endian == 'big':
        return s
    else:
        #return s[::-1]

        return int.to_bytes(n, length, 'little')
    return n

def aesEncrypt(key, data, mode='CMAC'):
    """AES encryption function

    Args:
        key (str): packed 128 bit key
        data (str): packed plain text data
        mode (str): Optional mode specification (CMAC)

    Returns:
        Packed encrypted data string
    """
    dataorder='big'
    keyorder='big'

    if mode == 'CMAC':
        cipher = CMAC()
        # there must be a better way to do this
        key=(int.from_bytes(key[0:4], 'big'),
             int.from_bytes(key[4:8], 'big'),
             int.from_bytes(key[8:12], 'big'),
             int.from_bytes(key[12:16], 'big'))
        if len(data) <= 16:
            length=len(data)*8
            data=data+bytearray((16-len(data)))
            data=[(int.from_bytes(data[0:4], 'big'),
                   int.from_bytes(data[4:8], 'big'),
                   int.from_bytes(data[8:12], 'big'),
                   int.from_bytes(data[12:16], 'big'))]
        elif len(data) > 16:
            length = (len(data)-16)*8
            data=data+bytearray((32-len(data)))
            data=[(int.from_bytes(data[0:4], 'big'),
                   int.from_bytes(data[4:8], 'big'),
                   int.from_bytes(data[8:12], 'big'),
                   int.from_bytes(data[12:16], 'big')),
                  (int.from_bytes(data[16:20], 'big'),
                   int.from_bytes(data[20:24], 'big'),
                   int.from_bytes(data[24:28], 'big'),
                   int.from_bytes(data[28:32], 'big'))]
        else:
            print('Data greater than 32 bytes')
        mic=cipher.cmac(key, data, length)
        mic = mic[0].to_bytes(4, 'big')
        return mic

    else:
        try:
            cipher = AES.new(key,AES.MODE_ECB)
        except:
            cipher = AES(key,AES.MODE_ECB)
        return cipher.encrypt(data)

def buildJoinRequest(dev_eui,app_eui,dev_nonce,app_key):
    data=bytes([0x00])+app_eui+dev_eui+dev_nonce
    mic = aesEncrypt(intPackBytes(app_key, 16), data,
                     mode='CMAC')[0:4]
    return data+mic

APP_KEY=0x00000000000000000000000000000000
APP_EUI=0x0000000000000000
DEV_EUI=0x0000000000000000

def main():
    try:
        f = open('nonce.txt', 'r')
        DEV_NONCE = int(f.readline()) # can be used only once and it appears Helium console drops packets with repeated dev nonce
    except:
        DEV_NONCE = 0x0000
        f=open('nonce.txt', 'w')
        f.write(str(DEV_NONCE))
        f.close()

    app_key=APP_KEY
    app_eui=intPackBytes(APP_EUI,8)
    dev_eui=intPackBytes(DEV_EUI,8)
    dev_nonce=int(DEV_NONCE)
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

    # Bind the socket to the port
    server_address = ('', 1680)
    print('Starting up on%s port %s' % server_address)
    sock.bind(server_address)

    while True:
        print('\n===================================================================')
        data, remote = sock.recvfrom(4096)
        print('received %s bytes from %s' % (len(data), remote))

        # Decode the data from the gateway even though we don't really care
        gm=GatewayMessage()
        message = gm.decode(data, remote)

        # build data payload for OTAA join
        packet=hexlify(buildJoinRequest(dev_eui,app_eui,intPackBytes(dev_nonce,2),app_key))

        if message.id==PULL_DATA:

            txpk = Txpk(imme=True, freq=904.3,
                                   rfch=0, powe=27,
                                   modu="LORA", datr='SF10BW125',
                                   codr="4/5", ipol=False, ncrc=False, data=unhexlify(packet))
            sendPullResponse(remote,message,txpk, sock)

            # update the nonce and write it to file
            f=open('nonce.txt', 'w')
            dev_nonce=dev_nonce+1
            f.write(str(dev_nonce))
            f.close()

        elif message.id==PUSH_DATA:
            sendPushAck(remote, message,sock)

if __name__ == "__main__":
    main()


#!/usr/bin/env python
# -*- coding: utf-8 -*-
r""" for testting the interfaces of the scripts.api. """
import scripts.api as api
import os
import unittest
from unit_test.test_cfg import ApiTestConfig as apiCfg

class AutoGenerateChecker(unittest.TestCase):
    def setUp(self):
        self._cfg = apiCfg

    def test_from_xls_write_py(self):
        r"""
        测试 api.from_xls_write_py()
        """
        self.__clean_up_py_file()
        api.from_xls_write_py(self._cfg.xls_path_1, self._cfg.in_path)
        try:
            import unit_test.testf.info_out1_test1 as o1_t1
            import unit_test.testf.info_out1_test2 as o1_t2
        except ImportError:
            raise Exception('Has not generate file.')
        self.assertEqual(o1_t1.btn_buy, self._cfg.out_test1_btn_buy, 'api.from_xls_write_py() test faild.')
        self.assertEqual(o1_t2.btn_sell, self._cfg.out_test2_btn_sell, 'api.from_xls_write_py() test faild.')

    def test_from_path_write_py(self):
        r"""
        测试 api.from_path_write_py()
        """
        self.__clean_up_py_file()
        api.from_path_write_py(self._cfg.dir_path, self._cfg.in_path)
        try:
            import unit_test.testf.info_out1_test1 as o1_t1
            import unit_test.testf.info_out1_test2 as o1_t2
            import unit_test.testf.info_out2_test1 as o2_t1
            import unit_test.testf.info_out2_test2 as o2_t2
        except ImportError:
            raise Exception('Has not generate file.')
        self.assertEqual(o1_t1.btn_buy, self._cfg.out_test1_btn_buy, 'api.from_path_write_py() test faild.')
        self.assertEqual(o1_t2.btn_sell, self._cfg.out_test2_btn_sell, 'api.from_path_write_py() test faild.')
        self.assertEqual(o2_t1.btn_cancel, self._cfg.out_test1_btn_cancel, 'api.from_path_write_py() test faild.')
        self.assertEqual(o2_t2.btn_close, self._cfg.out_test2_btn_close, 'api.from_path_write_py() test faild.')

    def __clean_up_py_file(self):
        r""" 文件清理 """
        try:
            os.remove(self._cfg.be_del_py1_1)
            os.remove(self._cfg.be_del_py1_2)
        except FileNotFoundError:
            pass
        try:
            os.remove(self._cfg.be_del_py2_1)
            os.remove(self._cfg.be_del_py2_2)
        except FileNotFoundError:
            pass

    def tearDown(self):
        self.__clean_up_py_file()

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


import threading
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *

from src.threads.resources import shapes, menu
from src.threads.frames import frame

class BackgroundFunction(threading.Thread):
  def __init__(self, function, args):
    self.done = False
    self.result = None

    self.function = function
    self.args = args
    threading.Thread.__init__(self)
    threading.Thread.start(self)

  def run(self):
    self.result = self.function(*self.args)
    self.done = True

class Loading(frame.Frame):
  def preGL(self):
    super(Loading, self).preGL()
    glDisable(GL_DEPTH_TEST)
    glMatrixMode(GL_PROJECTION)
    glPushMatrix()
    glLoadIdentity()
    glViewport(0, 0, self.frameWidth, self.frameHeight)
    glOrtho(0, self.frameWidth, self.frameHeight, 0, 0, 1)

    glMatrixMode(GL_MODELVIEW)
    glLoadIdentity()
    glClear(GL_DEPTH_BUFFER_BIT)

  def postGL(self):
    glMatrixMode(GL_PROJECTION)
    glPopMatrix()
    glMatrixMode(GL_MODELVIEW)

  def animateDots(self):
    self.animationCount %= self.dots

    self.dotState = [(0, 0, 0)] * (self.dots)
    for index in xrange(self.animationCount):
      self.dotState[index] = (1, 1, 1)

  def drawDots(self):
    (cx, cy) = (self.frameWidth / 2.0, self.frameHeight / 2.0)
    dy = self.dy

    radius = 5
    dx = 15
    width = dx * self.dots #+ 2 * radius
    offset = width / 2.0
    for circ in xrange(self.dots):
      shapes.Circle(cx + circ*dx - offset, cy + dy, radius,
                    [self.dotState[circ]]).draw()

  def drawSpinning(self):
    (cx, cy) = (self.frameWidth / 2.0, self.frameHeight / 2.0)
    size = 50
    dy = self.dy

    color = (1, 1, 1)
    borderColor = (0, 0, 0)
    shapes.Rectangle(cx,cy-dy,size,size,color,self.spin,borderColor).draw()

  def draw(self):
    self.preGL()
    self.backgroundTex.draw()
    self.animateDots()
    self.drawSpinning()
    self.drawDots()
    self.postGL()

  def timerFired(self, count):
    self.spin += 10
    self.animationCount += 1
    if(self.backgroundTask.done):
      self.dispRef.currentFrame = self.nextFrame

  def __init__(self, displayRef, frameSize, nextFrame, backgroundFunc,
                 args = []):
    super(Loading, self).__init__(displayRef, frameSize)
    self.nextFrame = nextFrame
    self.backgroundTask = BackgroundFunction(backgroundFunc, args)

    (cx, cy) = (self.frameWidth / 2.0, self.frameHeight / 2.0)
    self.backgroundTex = shapes.Texture(cx, cy, "background.png")
    self.spin = 0
    self.dots = 5
    self.dotState = [(0, 0, 0)] * (self.dots)
    self.animationCount = 0
    self.dy = 40


from boxes import *

class MotorEdge(edges.BaseEdge):
    # def margin(self) -> float:
    #    return 30.0
    def __call__(self, l, **kw):
        self.polyline(
            l - 165, 45,
            25 * 2 ** 0.5, -45,
            60, -45,
            25 * 2 ** 0.5, 45,
            55)

class OutsetEdge(edges.OutSetEdge):
    def startwidth(self) -> float:
        return 20.0

class HangerEdge(edges.BaseEdge):
    char = "H"

    def margin(self) -> float:
        return 40.0

    def __call__(self, l, **kw):
        self.fingerHolesAt(0, -0.5 * self.thickness, l, angle=0)
        w = self.settings
        self.polyline(0, -90,
                      22 + w, 90,
                      70, 135,
                      2 ** 0.5 * 12, 45,
                      35, -45,
                      2 ** 0.5 * 0.5 * w, -90,
                      2 ** 0.5 * 0.5 * w, -45,
                      l - 28, 45,
                      2 ** 0.5 * 5, 45, 5, -90)

class RollerEdge(edges.BaseEdge):
    def margin(self) -> float:
        return 20.0

    def __call__(self, l, **kw):
        m = 40 + 100
        self.polyline((l - m) / 2.0, -45,
                      2 ** 0.5 * 20, 45,
                      100, 45,
                      2 ** 0.5 * 20, -45,
                      (l - m) / 2.0)

class RollerEdge2(edges.BaseEdge):
    def margin(self) -> float:
        return self.thickness

    def __call__(self, l, **kw):
        a = 30
        f = 1 / math.cos(math.radians(a))
        self.edges["f"](70)
        self.polyline(0, a, f * 25, -a, l - 190, -a, f * 25, a, 0)
        self.edges["f"](70)

class Rotary(Boxes):
    """Rotary Attachment for engraving cylindrical objects in a laser cutter"""

    ui_group = "Unstable"

    def __init__(self) -> None:
        Boxes.__init__(self)

        self.addSettingsArgs(edges.FingerJointSettings)

        self.argparser.add_argument(
            "--diameter", action="store", type=float, default=72.,
            help="outer diameter of the wheels (including O rings)")
        self.argparser.add_argument(
            "--rubberthickness", action="store", type=float, default=5.,
            help="diameter of the strings of the O rings")
        self.argparser.add_argument(
            "--axle", action="store", type=float, default=6.,
            help="diameter of the axles")
        self.argparser.add_argument(
            "--knifethickness", action="store", type=float, default=8.,
            help="thickness of the knives in mm. Use 0 for use with honey comb table.")
        self.argparser.add_argument(
            "--beamwidth",  action="store", type=float, default=32.,
            help="width of the (aluminium) profile connecting the parts")
        self.argparser.add_argument(
            "--beamheight",  action="store", type=float, default=7.1,
            help="height of the (aluminium) profile connecting the parts")

    def mainPlate(self):
        # Motor block outer side
        t = self.thickness
        d = self.diameter
        a = self.axle
        bw, bh = self.beamwidth, self.beamheight
        hh = 0.5 * d + bh + 2 # hole height
        self.hole(1.0 * d, hh, a/2.)
        #self.hole(1.0 * d, hh, d/2.)
        self.hole(2.0 * d + 5, hh, a/2.)
        #self.hole(2.0 * d + 5, hh, d/2.)
        # Main beam
        self.rectangularHole(1.5*d+2.5, 0.5*bh, bw, bh)

    def frontPlate(self):
        # Motor block inner side with motor mount
        t = self.thickness
        d = self.diameter
        a = self.axle
        bw, bh = self.beamwidth, self.beamheight
        hh = 0.5 * d + bh + 2 # hole height
        self.hole(1.0 * d, hh, a/2.)
        #self.hole(1.0 * d, hh, d/2.)
        self.hole(2.0 * d + 5, hh, a/2.)
        #self.hole(2.0 * d + 5, hh, d/2.)
        # Main beam
        self.rectangularHole(1.5 * d+2.5, 0.5 * bh, bw, bh)
        # Motor
        mx = 2.7 * d + 20
        self.rectangularHole(mx, hh, 36 + 20, 36, r=36 / 2.0)

        for x in (-1, 1):
            for y in (-1,1):
                self.rectangularHole(mx+x * 25, hh + y * 25, 20, 4, r=2)

    def link(self, x, y, a, middleHole=False, move=None):
        t = self.thickness
        overallwidth = x + y
        overallheight = y
        ra = a / 2.0

        if self.move(overallwidth, overallheight, move, before=True):
            return

        self.moveTo(y / 2.0, 0)
        self.hole(0, y / 2., ra)
        self.hole(x, y / 2., ra)

        if middleHole:
            self.hole(x / 2., y / 2., ra)

        self.edge(10)
        self.edges["F"](60)
        self.polyline(x - 70, (180, y / 2.), x, (180, y / 2.))

        self.move(overallwidth, overallheight, move)

    def holderBaseCB(self):
        bw, bh = self.beamwidth, self.beamheight
        self.hole(20, self.hh - 10, self.a / 2)
        self.rectangularHole(self.hl - 70, self.hh - 10, 110, self.a, r=self.a / 2)
        self.rectangularHole(self.hl / 2, 0.5 * bh, bw, bh)

    def holderTopCB(self):
        self.fingerHolesAt(0, 30 - 0.5 * self.thickness, self.hl, 0)
        d = self.diameter / 2.0 + 1
        # XXX
        y = -0.5 * self.diameter + self.th + self.hh - self.beamheight - 2.
        self.hole(self.hl / 2 + d, y, self.axle / 2.0)
        self.hole(self.hl / 2 - d, y, self.axle / 2.0)
        self.hole(self.hl / 2 + d, y, self.diameter / 2.0)
        self.hole(self.hl / 2 - d, y, self.diameter / 2.0)

    def render(self):
        # adjust to the variables you want in the local scope
        t = self.thickness
        d = self.diameter
        a = self.a = self.axle
        bw, bh = self.beamwidth, self.beamheight

        # self.spacing = 0.1 * t

        # Change settings of default edges if needed. E.g.:
        self.edges["f"].settings.setValues(self.thickness, space=2, finger=2,
                                           surroundingspaces=1)
        if self.knifethickness:
            self.addPart(HangerEdge(self, self.knifethickness))
        else:
            self.edges["H"] = self.edges["F"]

        # Holder
        hw = self.hw = 70.
        hh = self.hh = 35. + bh
        hl = self.hl = 240
        # Base
        self.rectangularWall(hl, hh, edges="hfef", callback=[self.holderBaseCB, None,
                                                             lambda: self.rectangularHole(hl / 2 + 50, hh - t / 2 - 1,
                                                                                60, t + 2)], move="up")
        self.rectangularWall(hl, hh, edges="hfef", callback=[self.holderBaseCB], move="up")
        self.rectangularWall(hl, hw, edges="ffff", callback=[lambda: self.hole(hl / 2 - 16 - 20, 25, 5)], move="up")

        with self.saved_context():
            self.rectangularWall(hw, hh, edges="hFeF", callback=[
                lambda: self.hole(hw / 2, hh - 20, 4)],move="right")
            self.rectangularWall(hw, hh, edges="hFeF", move="right")
            # Top
            th = self.th = 30
            #  sides

            self.rectangularWall(hw + 20, th, edges="fFeF", move="right",
                    callback=[lambda: self.fingerHolesAt(20 - 0.5 * t, 0, th)])
            self.rectangularWall(hw + 20, th, edges="fFeF", move="right",
                    callback=[lambda: self.fingerHolesAt(20 - 0.5 * t, 0, th)])

        self.rectangularWall(hw, hh, edges="hFeF", move="up only")
        outset = OutsetEdge(self, None)
        roller2 = RollerEdge2(self, None)
        self.rectangularWall(hl, th, edges=[roller2, "f", "e", "f"], callback=[
            lambda: self.hole(20, 15, a / 2), None, lambda: self.rectangularHole(50, th - 15, 70, a, r=a / 2)],
                             move="up")
        self.rectangularWall(hl, th, edges=[roller2, "f", "e", "f"], callback=[
            lambda: self.hole(20, 15, a / 2), None, lambda: self.rectangularHole(50, th - 15 - t, 70, a, r=a / 2)],
                             move="up")
        self.rectangularWall(hl, th, edges=[roller2, "f", RollerEdge(self, None), "f"], callback=[
            self.holderTopCB], move="up")
        self.rectangularWall(hl, 20 - t, edges="feee", move="up")
        tl = 70
        self.rectangularWall(tl, hw + 20, edges="FeFF", move="right",
                             callback=[None, lambda: self.fingerHolesAt(20 - 0.5 * t, 0, tl)])
        self.rectangularWall(tl, hw + 20, edges="FeFF", move="",
                             callback=[None, lambda: self.fingerHolesAt(20 - 0.5 * t, 0, tl)])
        self.rectangularWall(tl, hw + 20, edges="FeFF", move="left up only",
                             callback=[None, lambda: self.fingerHolesAt(20 - 0.5 * t, 0, tl)])

        # Links
        self.link(hl - 40, 25, a, True, move="up")
        self.link(hl - 40, 25, a, True, move="up")
        self.link(hl - 40, 25, a, True, move="up")
        self.link(hl - 40, 25, a, True, move="up")

        with self.saved_context():
            self.rectangularWall(hw - 2 * t - 2, 60, edges="efef", move="right")
            self.rectangularWall(hw - 4 * t - 4, 60, edges="efef", move="right")
            # Spindle auxiliaries
            self.parts.waivyKnob(50, callback=lambda: self.nutHole("M8"), move="right")
            self.parts.waivyKnob(50, callback=lambda: self.nutHole("M8"), move="right")

        self.rectangularWall(hw - 2 * t - 4, 60, edges="efef", move="up only")

        with self.saved_context():
            slot = edges.SlottedEdge(self, [(30 - t) / 2, (30 - t) / 2], slots=15)
            self.rectangularWall(30, 30, edges=["e", "e", slot, "e"],
                callback=[lambda: self.hole(7, 23, self.axle / 2)], move="right")
            self.rectangularWall(30, 30, edges=["e", "e", slot, "e"],
                callback=[lambda: self.hole(7, 23, self.axle / 2)], move="right")
            leftover = (hw - 6 * t - 6 - 20) / 2.0
            slot = edges.SlottedEdge(self, [leftover, 20, leftover], slots=15)
            self.rectangularWall(hw - 4 * t - 6, 30, edges=[slot, "e", "e", "e"],
                             callback=[lambda: self.hole((hw - 4 * t - 6) / 2., 15, 4)], move="right")
            for i in range(3):
                self.rectangularWall(20, 30,
                                 callback=[lambda: self.nutHole("M8", 10, 15)], move="right")
                self.rectangularWall(20, 30,
                                     callback=[lambda: self.hole(10, 15, 4)], move="right")

        self.rectangularWall(30, 30, move="up only")

        self.h = h = bh + 2 + 1.0 * d # height of outer pieces
        # Other side
        if self.knifethickness:
            ow = 10
            self.rectangularWall(3.6 * d, h, edges="hfFf", callback=[
                lambda:self.rectangularHole(1.8 * d, 0.5 * bh, bw, bh)],
                                 move="up")
            self.rectangularWall(3.6 * d, h, edges="hfFf", callback=[
                lambda:self.rectangularHole(1.8 * d, 0.5 * bh, bw, bh)],
                                 move="up")
            self.rectangularWall(3.6 * d, ow, edges="ffff", move="up")
            self.rectangularWall(3.6 * d, ow, edges="ffff", move="up")
            with self.saved_context():
                self.rectangularWall(ow, h, edges="hFFH", move="right")
                self.rectangularWall(ow, h, edges="hFFH", move="right")
            self.rectangularWall(ow, h, edges="hFFH", move="up only")

        # Motor block
        mw = 40
        self.rectangularWall(3.6 * d, h, edges=["h", "f", MotorEdge(self, None),"f"], callback=[self.mainPlate], move="up")
        self.rectangularWall(3.6 * d, h, edges=["h", "f", MotorEdge(self, None),"f"], callback=[self.frontPlate], move="up")
        self.rectangularWall(3.6 * d, mw, edges="ffff", move="up")
        with self.saved_context():
            self.rectangularWall(mw, h, edges="hFeH", move="right")
            self.rectangularWall(mw, h, edges="hFeH", move="right")

            self.pulley(88, "GT2_2mm", r_axle=a / 2.0, move="right")
            self.pulley(88, "GT2_2mm", r_axle=a / 2.0, move="right")
        self.rectangularWall(mw, h, edges="hFeH", move="up only")
        self.axle = 19

        for i in range(3):
            self.parts.disc(self.diameter - 2 * self.rubberthickness,
                            hole=self.axle, move="right")
        self.parts.disc(self.diameter - 2 * self.rubberthickness,
                        hole=self.axle, move="up right")

        for i in range(3):
            self.parts.disc(self.diameter - 2 * self.rubberthickness,
                            hole=self.axle, move="left")
        self.parts.disc(self.diameter - 2 * self.rubberthickness,
                        hole=self.axle, move="left up")

        for i in range(3):
            self.parts.disc(self.diameter - 2 * self.rubberthickness + 4,
                            hole=self.axle, move="right")
        self.parts.disc(self.diameter - 2 * self.rubberthickness + 4,
                        hole=self.axle, move="right up")


from __future__ import annotations

import inspect
import threading
from abc import abstractmethod, ABC
from datetime import timedelta, datetime
from enum import Enum
from typing import Dict, List, Tuple, Callable, Union, Optional, Generic, Type

import inflect

from typing import TypeVar
from ravendb.json.metadata_as_dictionary import MetadataAsDictionary
from ravendb import constants
from ravendb.documents.operations.configuration import ClientConfiguration, LoadBalanceBehavior, ReadBalanceBehavior
from ravendb.documents.indexes.definitions import SortOptions
from ravendb.tools.utils import Utils

inflect.def_classical["names"] = False
inflector = inflect.engine()

_T = TypeVar("_T")

class DocumentConventions(object):
    __cached_default_type_collection_names: Dict[type, str] = {}

    def __init__(self):
        self._frozen = False

        # Value constraints
        self.identity_parts_separator = "/"
        self.max_number_of_requests_per_session = 30
        self._max_http_cache_size = 128 * 1024 * 1024
        self.max_length_of_query_using_get_url = 1024 + 512

        # Flags
        self.disable_topology_updates = False
        self.use_optimistic_concurrency = False
        self.throw_if_query_page_size_is_not_set = False
        self._send_application_identifier = True
        self._save_enums_as_integers: Optional[bool] = None
        self._disable_atomic_document_writes_in_cluster_wide_transaction: Optional[bool] = None

        # Configuration
        self.json_default_method = DocumentConventions.json_default
        self._original_configuration: Optional[ClientConfiguration] = None
        self._should_ignore_entity_changes: Optional[ShouldIgnoreEntityChanges] = None

        # Collections
        self._list_of_registered_id_conventions: List[Tuple[Type, Callable[[str, object], str]]] = []
        self._list_of_query_value_to_object_converters: List[Tuple[Type, ValueForQueryConverter[object]]] = []

        # Utilities
        self.document_id_generator: Optional[Callable[[str, object], str]] = None
        self._find_identity_property = lambda q: q.__name__ == "key"
        self._find_python_class: Optional[Callable[[str, Dict], str]] = None
        self._find_collection_name: Callable[[Type], str] = self.default_get_collection_name
        self._find_python_class_name: Callable[
            [Type], str
        ] = lambda object_type: f"{object_type.__module__}.{object_type.__name__}"
        self._transform_class_collection_name_to_document_id_prefix = (
            lambda collection_name: self.default_transform_collection_name_to_document_id_prefix(collection_name)
        )

        # Timeouts
        self.request_timeout: timedelta = timedelta.min
        self.first_broadcast_attempt_timeout = timedelta(seconds=5)
        self.second_broadcast_attempt_timeout = timedelta(seconds=30)
        self.wait_for_indexes_after_save_changes_timeout = timedelta(seconds=15)
        self.wait_for_replication_after_save_changes_timeout = timedelta(seconds=15)
        self.wait_for_non_stale_results_timeout = timedelta(seconds=15)

        # Balancing
        self._load_balancer_context_seed: Optional[int] = None
        self._load_balance_behavior: Optional[LoadBalanceBehavior] = LoadBalanceBehavior.NONE
        self._read_balance_behavior: Optional[ReadBalanceBehavior] = ReadBalanceBehavior.NONE
        self._load_balancer_per_session_context_selector: Optional[Callable[[str], str]] = None

        # Async
        self._update_from_lock = threading.Lock()

    def freeze(self):
        self._frozen = True

    def is_frozen(self):
        return self._frozen

    def get_python_class_name(self, entity_type: type):
        return self._find_python_class_name(entity_type)

    @property
    def find_collection_name(self) -> Callable[[type], str]:
        return self._find_collection_name

    @find_collection_name.setter
    def find_collection_name(self, value) -> None:
        self.__assert_not_frozen()
        self._find_collection_name = value

    @property
    def find_python_class(self) -> Callable[[str, Dict], Optional[str]]:
        def __default(key: str, doc: Dict) -> Optional[str]:
            metadata = doc.get(constants.Documents.Metadata.KEY)
            if metadata:
                python_type = metadata.get(constants.Documents.Metadata.RAVEN_PYTHON_TYPE)
                return python_type
            return None

        return self._find_python_class or __default

    @find_python_class.setter
    def find_python_class(self, value: Callable[[str, Dict], str]):
        self.__assert_not_frozen()
        self._find_python_class = value

    def get_python_class(self, key: str, document: Dict) -> str:
        return self.find_python_class(key, document)

    @property
    def transform_class_collection_name_to_document_id_prefix(self) -> Callable[[str], str]:
        return self._transform_class_collection_name_to_document_id_prefix

    @transform_class_collection_name_to_document_id_prefix.setter
    def transform_class_collection_name_to_document_id_prefix(self, value: Callable[[str], str]) -> None:
        self.__assert_not_frozen()
        self._transform_class_collection_name_to_document_id_prefix = value

    @property
    def load_balancer_per_session_context_selector(self) -> Callable[[str], str]:
        return self._load_balancer_per_session_context_selector

    @load_balancer_per_session_context_selector.setter
    def load_balancer_per_session_context_selector(self, value: Callable[[str], str]):
        self.load_balancer_per_session_context_selector = value

    @property
    def max_http_cache_size(self) -> int:
        return self._max_http_cache_size

    @max_http_cache_size.setter
    def max_http_cache_size(self, value: int):
        self._max_http_cache_size = value

    @property
    def save_enums_as_integers(self) -> bool:
        return self._save_enums_as_integers

    @save_enums_as_integers.setter
    def save_enums_as_integers(self, value: bool):
        self._save_enums_as_integers = value

    @property
    def find_python_class_name(self) -> Callable[[type], str]:
        return self._find_python_class_name

    @find_python_class_name.setter
    def find_python_class_name(self, value) -> None:
        self.__assert_not_frozen()
        self._find_python_class_name = value

    @property
    def should_ignore_entity_changes(self) -> ShouldIgnoreEntityChanges:
        return self._should_ignore_entity_changes

    @should_ignore_entity_changes.setter
    def should_ignore_entity_changes(self, value: ShouldIgnoreEntityChanges) -> None:
        self.__assert_not_frozen()
        self._should_ignore_entity_changes = value

    @property
    def load_balancer_context_seed(self) -> int:
        return self._load_balancer_context_seed

    @load_balancer_context_seed.setter
    def load_balancer_context_seed(self, value: int):
        self.__assert_not_frozen()
        self._load_balancer_context_seed = value

    @property
    def load_balance_behavior(self):
        return self._load_balance_behavior

    @load_balance_behavior.setter
    def load_balance_behavior(self, value: LoadBalanceBehavior):
        self.__assert_not_frozen()
        self._load_balance_behavior = value

    @property
    def read_balance_behavior(self) -> ReadBalanceBehavior:
        return self._read_balance_behavior

    @read_balance_behavior.setter
    def read_balance_behavior(self, value: ReadBalanceBehavior):
        self.__assert_not_frozen()
        self._read_balance_behavior = value

    @property
    def send_application_identifier(self) -> bool:
        return self._send_application_identifier

    @property
    def disable_atomic_document_writes_in_cluster_wide_transaction(self) -> bool:
        return self._disable_atomic_document_writes_in_cluster_wide_transaction

    @disable_atomic_document_writes_in_cluster_wide_transaction.setter
    def disable_atomic_document_writes_in_cluster_wide_transaction(self, value: bool):
        self.__assert_not_frozen()
        self._disable_atomic_document_writes_in_cluster_wide_transaction = value

    @staticmethod
    def json_default(o):
        if o is None:
            return None
        if isinstance(o, datetime):
            return Utils.datetime_to_string(o)
        elif isinstance(o, timedelta):
            return Utils.timedelta_to_str(o)
        elif isinstance(o, Enum):
            return o.value
        elif isinstance(o, MetadataAsDictionary):
            return o.metadata
        elif getattr(o, "to_json", None) and getattr(o.to_json, "__call__", None):
            return o.to_json()
        elif getattr(o, "__dict__", None):
            return o.__dict__
        elif isinstance(o, set):
            return list(o)
        elif isinstance(o, (int, float)):
            return str(o)
        else:
            raise TypeError(
                repr(o) + " is not JSON serializable (Try add a json default method to convention"
                " or try to add methods - to_json & classmethod from_json - to object class)"
            )

    @staticmethod
    def default_transform_plural(name):
        return inflector.plural(name)

    @staticmethod
    def default_transform_type_tag_name(name):
        count = sum(1 for c in name if c.isupper())
        if count <= 1:
            return DocumentConventions.default_transform_plural(name.lower())
        return DocumentConventions.default_transform_plural(name)

    @staticmethod
    def build_default_metadata(entity):
        if entity is None:
            return {}
        existing = entity.__dict__.get("@metadata")
        if existing is None:
            existing = {}

        new_metadata = {
            "@collection": DocumentConventions.default_transform_plural(entity.__class__.__name__),
            "Raven-Python-Type": "{0}.{1}".format(entity.__class__.__module__, entity.__class__.__name__),
        }

        existing.update(new_metadata)

        return existing

    def get_collection_name(self, entity_or_type: Union[type, object]) -> str:
        if not entity_or_type:
            return None
        object_type = type(entity_or_type) if not isinstance(entity_or_type, type) else entity_or_type
        collection_name = self._find_collection_name(object_type)
        if collection_name:
            return collection_name

        return self.default_get_collection_name(object_type)

    def generate_document_id(self, database_name: str, entity: object) -> str:
        object_type = type(entity)
        for list_of_registered_id_convention in self._list_of_registered_id_conventions:
            return list_of_registered_id_convention[1](database_name, entity)
        return self.document_id_generator(database_name, entity)

    @staticmethod
    def default_get_collection_name(object_type: type) -> str:
        result = DocumentConventions.__cached_default_type_collection_names.get(object_type)
        if result:
            return result
        # we want to reject queries and other operations on abstract types, because you usually
        # want to use them for polymorphic queries, and that require the conventions to be
        # applied properly, so we reject the behavior and hint to the user explicitly
        if inspect.isabstract(object_type):
            raise ValueError(
                f"Cannot find collection name for abstract class {object_type}, "
                f"only concrete class are supported. "
                f"Did you forget to customize conventions.find_collection_name?"
            )
        result = inflector.plural(str(object_type.__name__))  # todo: hilo multidb problems
        DocumentConventions.__cached_default_type_collection_names[object_type] = result
        return result

    @staticmethod
    def try_get_type_from_metadata(metadata):
        if "Raven-Python-Type" in metadata:
            return metadata["Raven-Python-Type"]
        return None

    @staticmethod
    def uses_range_type(obj):
        if obj is None:
            return False

        if isinstance(obj, int) or isinstance(obj, float):
            return True
        return False

    @staticmethod
    def get_default_sort_option(type_name):
        if not type_name:
            return None
        if type_name == "int" or type_name == "float" or type_name == "long":
            return SortOptions.numeric

    @staticmethod
    def range_field_name(field_name, type_name):
        if type_name == "long":
            field_name = "{0}_L_Range".format(field_name)
        else:
            field_name = "{0}_D_Range".format(field_name)

        return field_name

    def __assert_not_frozen(self) -> None:
        if self._frozen:
            raise RuntimeError(
                "Conventions has been frozen after documentStore.initialize()" " and no changes can be applied to them"
            )

    def clone(self) -> DocumentConventions:
        cloned = DocumentConventions()
        cloned._list_of_registered_id_conventions = [*self._list_of_registered_id_conventions]
        cloned._frozen = self._frozen
        cloned._should_ignore_entity_changes = self._should_ignore_entity_changes
        cloned._original_configuration = self._original_configuration
        cloned._save_enums_as_integers = self._save_enums_as_integers
        cloned.identity_parts_separator = self.identity_parts_separator
        cloned.disable_topology_updates = self.disable_topology_updates
        cloned._find_identity_property = self._find_identity_property

        cloned.document_id_generator = self.document_id_generator

        cloned._find_collection_name = self._find_collection_name
        cloned._find_python_class_name = self.find_python_class_name

        cloned.use_optimistic_concurrency = self.use_optimistic_concurrency
        cloned.throw_if_query_page_size_is_not_set = self.throw_if_query_page_size_is_not_set
        cloned.max_number_of_requests_per_session = self.max_number_of_requests_per_session

        cloned._read_balance_behavior = self._read_balance_behavior
        cloned._load_balance_behavior = self._load_balance_behavior
        self._max_http_cache_size = self._max_http_cache_size

    def update_from(self, configuration: ClientConfiguration):
        if configuration.disabled and self._original_configuration is None:
            return
        with self._update_from_lock:
            if configuration.disabled and self._original_configuration is not None:
                self.max_number_of_requests_per_session = (
                    self._original_configuration.max_number_of_requests_per_session
                    if self._original_configuration.max_number_of_requests_per_session
                    else self.max_number_of_requests_per_session
                )
                self._read_balance_behavior = (
                    self._original_configuration.read_balance_behavior
                    if self._original_configuration.read_balance_behavior
                    else self._read_balance_behavior
                )
                self.identity_parts_separator = (
                    self._original_configuration.identity_parts_separator
                    if self._original_configuration.identity_parts_separator
                    else self.identity_parts_separator
                )
                self._load_balance_behavior = (
                    self._original_configuration.load_balance_behavior
                    if self._original_configuration.load_balance_behavior
                    else self._load_balance_behavior
                )
                self._load_balancer_context_seed = (
                    self._original_configuration.load_balancer_context_seed
                    if self._original_configuration.load_balancer_context_seed
                    else self._load_balancer_context_seed
                )

                self._original_configuration = None
                return

            if self._original_configuration is None:
                self._original_configuration = ClientConfiguration()
                self._original_configuration.etag = -1
                self._original_configuration.max_number_of_requests_per_session = (
                    self.max_number_of_requests_per_session
                )
                self._original_configuration.__read_balance_behavior = self._read_balance_behavior
                self._original_configuration.identity_parts_separator = self.identity_parts_separator
                self._original_configuration.__load_balance_behavior = self._load_balance_behavior
                self._original_configuration.__load_balancer_context_seed = self._load_balancer_context_seed

            # first not None
            self.max_number_of_requests_per_session = next(
                item
                for item in [
                    configuration.max_number_of_requests_per_session,
                    self._original_configuration.max_number_of_requests_per_session,
                    self.max_number_of_requests_per_session,
                ]
                if item is not None
            )

            self._read_balance_behavior = next(
                item
                for item in [
                    configuration.read_balance_behavior,
                    self._original_configuration.read_balance_behavior,
                    self._read_balance_behavior,
                ]
                if item is not None
            )

            self.identity_parts_separator = next(
                item
                for item in [
                    configuration.identity_parts_separator,
                    self._original_configuration.identity_parts_separator,
                    self.identity_parts_separator,
                ]
                if item is not None
            )

            self._load_balance_behavior = next(
                item
                for item in [
                    configuration.load_balance_behavior,
                    self._original_configuration.load_balance_behavior,
                    self._load_balance_behavior,
                ]
                if item is not None
            )

            self._load_balancer_context_seed = (
                configuration.load_balancer_context_seed
                or self._original_configuration.load_balancer_context_seed
                or self._load_balancer_context_seed
            )

    @staticmethod
    def default_transform_collection_name_to_document_id_prefix(collection_name: str) -> str:
        upper_count = len(list(filter(str.isupper, collection_name)))
        if upper_count <= 1:
            return collection_name.lower()

        # multiple capital letters, so probably something that we want to preserve caps on.
        return collection_name

    def try_convert_value_to_object_for_query(
        self, field_name: str, value: object, for_range: bool
    ) -> Tuple[bool, object]:
        for query_value_converter in self._list_of_query_value_to_object_converters:
            if not isinstance(value, query_value_converter[0]):
                continue

            return query_value_converter[1].try_to_convert_value_for_query(field_name, value, for_range)

        return False, None

class ValueForQueryConverter(Generic[_T]):
    @abstractmethod
    def try_to_convert_value_for_query(self, field_name: str, value: _T, for_range: bool) -> Tuple[bool, object]:
        pass

class ShouldIgnoreEntityChanges(ABC):
    @abstractmethod
    def check(
        self,
        session_operations: "InMemoryDocumentSessionOperations",
        entity: object,
        document_id: str,
    ) -> bool:
        pass


import io
import numpy as np

from torch import nn
import torch.utils.model_zoo as model_zoo
import torch.onnx

import onnx
import onnxruntime

# PyTorch Model
import torch.nn as nn
import torch.nn.init as init

class SuperResolutionNet(nn.Module):
    def __init__(self, upscale_factor, inplace=False):
        super(SuperResolutionNet, self).__init__()

        self.relu = nn.ReLU(inplace=inplace)
        self.conv1 = nn.Conv2d(1, 64, (5, 5), (1, 1), (2, 2))
        self.conv2 = nn.Conv2d(64, 64, (3, 3), (1, 1), (1, 1))
        self.conv3 = nn.Conv2d(64, 32, (3, 3), (1, 1), (1, 1))
        self.conv4 = nn.Conv2d(32, upscale_factor ** 2, (3, 3), (1, 1), (1, 1))
        self.pixel_shuffle = nn.PixelShuffle(upscale_factor)

        self._initialize_weights()

    def forward(self, x):
        x = self.relu(self.conv1(x))
        x = self.relu(self.conv2(x))
        x = self.relu(self.conv3(x))
        x = self.pixel_shuffle(self.conv4(x))
        return x

    def _initialize_weights(self):
        init.orthogonal_(self.conv1.weight, init.calculate_gain('relu'))
        init.orthogonal_(self.conv2.weight, init.calculate_gain('relu'))
        init.orthogonal_(self.conv3.weight, init.calculate_gain('relu'))
        init.orthogonal_(self.conv4.weight)

torch_model = SuperResolutionNet(upscale_factor=3)

# pretrained model
model_url = 'https://s3.amazonaws.com/pytorch/test_data/export/superres_epoch100-44c6958e.pth'
batch_size = 1

# initialize model with pretrained pth
map_location = lambda storage, loc: storage
if torch.cuda.is_available():
    map_location = None
torch_model.load_state_dict(model_zoo.load_url(model_url, map_location=map_location))

# evaluate
torch_model.eval()

# define input
x = torch.randn(batch_size, 1, 224, 224, requires_grad=True)
torch_out = torch_model(x)

# 모델 변환 to ONNX
torch.onnx.export(torch_model,               # 실행될 모델
                  x,                         # 모델 입력값 (튜플 또는 여러 입력값들도 가능)
                  "./ONNX/models/super_resolution.onnx",   # 모델 저장 경로 (파일 또는 파일과 유사한 객체 모두 가능)
                  export_params=True,        # 모델 파일 안에 학습된 모델 가중치를 저장할지의 여부
                  opset_version=10,          # 모델을 변환할 때 사용할 ONNX 버전
                  do_constant_folding=True,  # 최적화시 상수폴딩을 사용할지의 여부
                  input_names = ['input'],   # 모델의 입력값을 가리키는 이름
                  output_names = ['output'], # 모델의 출력값을 가리키는 이름
                  dynamic_axes={'input' : {0 : 'batch_size'},    # 가변적인 길이를 가진 차원
                                'output' : {0 : 'batch_size'}})

# ONNX
MODEL_PATH = './ONNX/models/super_resolution.onnx'
onnx_model = onnx.load(MODEL_PATH)

# check model have valid schema
onnx.checker.check_model(onnx_model)

ort_session = onnxruntime.InferenceSession(MODEL_PATH)

def to_numpy(tensor):
    return tensor.detach().cpu().numpy() if tensor.requires_grad else tensor.cpu().numpy()

# ONNX 런타임에서 계산된 결과값
ort_inputs = {ort_session.get_inputs()[0].name: to_numpy(x)}
ort_outs = ort_session.run(None, ort_inputs)

# ONNX 런타임과 PyTorch에서 연산된 결과값 비교
np.testing.assert_allclose(to_numpy(torch_out), ort_outs[0], rtol=1e-03, atol=1e-05)

print("Exported model has been tested with ONNXRuntime, and the result looks good!")


#!/usr/bin/env python
# coding: utf-8

# # 1. 자료형
# ## Background
# - 데이터 타입
# - 제어문
#
# ## Problem
# ### 1. myList = `[[1,2,3],[4,5,6],[7,8]]`에 9를 추가하여 `[[1,2,3],[4,5,6],[7,8,9]]`가 되도록 구현해보세요
# - append와 insert 두가지 방법으로 풀어보세요

# In[1]:

myList = [[1,2,3],[4,5,6],[7,8]]
#myList[2].append(9)
myList[2].insert(2, 9)
print(myList)

# ### 2. Dictionary를 활용해서 학생들의 이름과 점수를 key와 value로 입력하고 추가, 삭제, 업데이트를 진행해보세요.
# 1. score라는 dictionary에 하준 90점, 서윤 86점, 지아 80점을 입력하세요.
# 2. score에 수지 95점을 추가하세요.
# 3. score에서 지아를 삭제하세요.
# 4. score에 기창 98점, 남철 60점, 기성 75점을 <u>한번에</u> 추가해보세요

# In[2]:

score = {'하준':90,'서윤':86,'지아':80}
score['수지'] = 95
del score ['지아']
addinfo = {'기창':98,'남철':60,'기성':75}
score.update(addinfo)
score

# ### 3. 다음 리스트에서 중복된 항목을 없애보세요.
# ```python
# myList = [1,3,2,3,7,6,8,4,10,5,3,8,9]```

# In[3]:

myList = [1,3,2,3,7,6,8,4,10,5,3,8,9]
print(set(myList))

# ### 4. 다음의 세 문장에서 중복으로 사용된 알파벳만 출력해보세요.(대소문자 구분)
# - "Hello python"
# - "Funny programming"
# - "Happy newyear"

# In[7]:

set("Hellopython")&set("Funnyprogramming")&set("Happynewyear")

# ### 5. 다음과 같은 규칙을 가진 숫자의 합을 for문을 사용해서 구현하세요.
# - 1 + (1 + 3) + (1 + 3 + 5) + (1 + 3 + 5 + 7) + ... + (1 + 3 + ... + 19)

# In[34]:

# 첫번쨰 풀이
a = [1,3,5,7,9,11,13,15,17,19]
b = []
c = 0
for i in a:
    if i == 1:
        c = i
        b.append(c)
    else:
        c = c+i
        b.append(c)
print(sum(b))
#두번째 풀이
total = 0
for i in range(1,11):
    subtotal = 0
    for j in range(i):
        subtotal += 2*j+1
    total += subtotal
print(total)


import argparse

import torch

from fairseq.models import ARCH_MODEL_REGISTRY, ARCH_CONFIG_REGISTRY
from fairseq.criterions import CRITERION_REGISTRY
from fairseq.optim import OPTIMIZER_REGISTRY
from fairseq.optim.lr_scheduler import LR_SCHEDULER_REGISTRY

from prune_utils import *

def get_training_parser():
    parser = get_parser('Trainer')
    add_dataset_args(parser, train=True, gen=True)
    add_distributed_training_args(parser)
    add_model_args(parser)
    add_optimization_args(parser)
    add_checkpoint_args(parser)
    add_inference_args(parser)
    add_perf_args(parser)
    add_profiling_args(parser)
    prune_parse_arguments(parser)
    add_multi_round_args(parser)
    return parser

def get_inference_parser():
    parser = get_parser('Generation')
    add_dataset_args(parser, gen=True)
    add_inference_args(parser)
    add_perf_args(parser)
    return parser

def eval_str_list(x, type=float):
    if x is None:
        return None
    if isinstance(x, str):
        x = eval(x)
    try:
        return list(map(type, x))
    except TypeError:
        return [type(x)]

def parse_args_and_arch(parser, input_args=None, parse_known=False):
    # The parser doesn't know about model/criterion/optimizer-specific args, so
    # we parse twice. First we parse the model/criterion/optimizer, then we
    # parse a second time after adding the *-specific arguments.
    # If input_args is given, we will parse those args instead of sys.argv.
    args, _ = parser.parse_known_args(input_args)

    # Add model-specific args to parser.
    if hasattr(args, 'arch'):
        model_specific_group = parser.add_argument_group(
            'Model-specific configuration',
            # Only include attributes which are explicitly given as command-line
            # arguments or which have default values.
            argument_default=argparse.SUPPRESS,
        )
        ARCH_MODEL_REGISTRY[args.arch].add_args(model_specific_group)

    # Add *-specific args to parser.
    if hasattr(args, 'optimizer'):
        OPTIMIZER_REGISTRY[args.optimizer].add_args(parser)
    if hasattr(args, 'lr_scheduler'):
        LR_SCHEDULER_REGISTRY[args.lr_scheduler].add_args(parser)

    # Parse a second time.
    if parse_known:
        args, extra = parser.parse_known_args(input_args)
    else:
        args = parser.parse_args(input_args)
        extra = None

    # Post-process args.
    if hasattr(args, 'lr'):
        args.lr = eval_str_list(args.lr, type=float)
    if hasattr(args, 'update_freq'):
        args.update_freq = eval_str_list(args.update_freq, type=int)
    if hasattr(args, 'max_sentences_valid') and args.max_sentences_valid is None:
        args.max_sentences_valid = args.max_sentences

    args.max_positions = (args.max_source_positions, args.max_target_positions)

    # Apply architecture configuration.
    if hasattr(args, 'arch'):
        ARCH_CONFIG_REGISTRY[args.arch](args)

    # Override args for profiling
    if hasattr(args, 'profile') and args.profile:
        args.max_update = args.profiler_steps

    if parse_known:
        return args, extra
    else:
        return args

def get_parser(desc):
    parser = argparse.ArgumentParser(
        description='Facebook AI Research Sequence-to-Sequence Toolkit -- ' + desc)
    parser.add_argument('--log-interval', type=int, default=1000, metavar='N',
                        help='print aggregated stats and flush json log every N iteration')
    parser.add_argument('--seed', default=1, type=int, metavar='N',
                        help='pseudo random number generator seed')
    parser.add_argument('--amp', action='store_true', help='use Automatic Mixed Precision')
    parser.add_argument('--amp-level', type=str, default="O1", help='choose apm\'s optimization level')
    parser.add_argument('--stat-file', type=str, default='run_log.json', help='Name of the file containing DLLogger output')
    parser.add_argument('--save-dir', metavar='DIR', default='results',
                       help='path to save checkpoints and logs')
    parser.add_argument('--do-sanity-check', action='store_true',
                        help='Perform evaluation on test set before running the training')

    return parser

def add_dataset_args(parser, train=False, gen=False):
    group = parser.add_argument_group('Dataset and data loading')
    group.add_argument('--skip-invalid-size-inputs-valid-test', action='store_true',
                       help='ignore too long or too short lines in valid and test set')
    group.add_argument('--max-tokens', type=int, metavar='N',
                       help='maximum number of tokens in a batch')
    group.add_argument('--max-sentences', '--batch-size', type=int, metavar='N',
                       help='maximum number of sentences in a batch')
    group.add_argument('--sentencepiece', action='store_true',
                        help='use when dataset uses sentencepiece encoding')
    parser.add_argument('-s', '--source-lang', default=None, metavar='SRC',
                        help='source language')
    parser.add_argument('-t', '--target-lang', default=None, metavar='TARGET',
                        help='target language')
    parser.add_argument('--raw-text', action='store_true',
                        help='load raw text dataset')
    parser.add_argument('--left-pad-source', default=True, type=bool, metavar='BOOL',
                        help='pad the source on the left (default: True)')
    parser.add_argument('--left-pad-target', default=False, type=bool, metavar='BOOL',
                        help='pad the target on the left (default: False)')
    parser.add_argument('--max-source-positions', default=1024, type=int, metavar='N',
                        help='max number of tokens in the source sequence')
    parser.add_argument('--max-target-positions', default=1024, type=int, metavar='N',
                        help='max number of tokens in the target sequence')
    parser.add_argument('--pad-sequence', default=1, type=int, metavar='N',
                            help='Pad sequences to a multiple of N')
    if train:
        parser.add_argument('data', metavar='DIR', help='path to data directory')
        group.add_argument('--train-subset', default='train', metavar='SPLIT',
                           choices=['train', 'valid', 'test'],
                           help='data subset to use for training (train, valid, test)')
        group.add_argument('--valid-subset', default='valid', metavar='SPLIT',
                           help='comma separated list of data subsets to use for validation'
                                ' (train, valid, valid1, test, test1)')
        group.add_argument('--max-sentences-valid', type=int, metavar='N',
                           help='maximum number of sentences in a validation batch'
                                ' (defaults to --max-sentences)')
    if gen:
        group.add_argument('--gen-subset', default='test', metavar='SPLIT',
                           help='data subset to generate (train, valid, test)')
        group.add_argument('--num-shards', default=1, type=int, metavar='N',
                           help='shard generation over N shards')
        group.add_argument('--shard-id', default=0, type=int, metavar='ID',
                           help='id of the shard to generate (id < num_shards)')
    return group

def add_distributed_training_args(parser):
    group = parser.add_argument_group('Distributed training')
    group.add_argument('--distributed-world-size', type=int, metavar='N',
                       default=torch.cuda.device_count(),
                       help='total number of GPUs across all nodes (default: all visible GPUs)')
    group.add_argument('--distributed-rank', default=0, type=int,
                       help='rank of the current worker')
    group.add_argument('--local_rank', default=0, type=int,
                       help='rank of the current worker')
    group.add_argument('--distributed-backend', default='nccl', type=str,
                       help='distributed backend')
    group.add_argument('--distributed-init-method', default=None, type=str,
                       help='typically tcp://hostname:port that will be used to '
                            'establish initial connetion')
    group.add_argument('--distributed-port', default=-1, type=int,
                       help='port number (not required if using --distributed-init-method)')
    group.add_argument('--device-id', default=0, type=int,
                       help='which GPU to use (usually configured automatically)')

    group.add_argument('--short-train', action='store_true', help='Only train a few minibatches per epoch, for debug purposes')

    return group

def add_optimization_args(parser):
    group = parser.add_argument_group('Optimization')
    group.add_argument('--max-epoch', '--me', default=0, type=int, metavar='N',
                       help='force stop training at specified epoch')
    group.add_argument('--max-update', '--mu', default=0, type=int, metavar='N',
                       help='force stop training at specified update')
    group.add_argument('--target-bleu', default=0.0, type=float, metavar='TARGET',
                       help='force stop training after reaching target bleu')
    group.add_argument('--clip-norm', default=25, type=float, metavar='NORM',
                       help='clip threshold of gradients')
    group.add_argument('--sentence-avg', action='store_true',
                       help='normalize gradients by the number of sentences in a batch'
                            ' (default is to normalize by number of tokens)')
    group.add_argument('--update-freq', default='1', metavar='N',
                       help='update parameters every N_i batches, when in epoch i')

    # Optimizer definitions can be found under fairseq/optim/
    group.add_argument('--optimizer', default='nag', metavar='OPT',
                       choices=OPTIMIZER_REGISTRY.keys(),
                       help='optimizer: {} (default: nag)'.format(', '.join(OPTIMIZER_REGISTRY.keys())))
    group.add_argument('--lr', '--learning-rate', default='0.25', metavar='LR_1,LR_2,...,LR_N',
                       help='learning rate for the first N epochs; all epochs >N using LR_N'
                            ' (note: this may be interpreted differently depending on --lr-scheduler)')
    group.add_argument('--momentum', default=0.99, type=float, metavar='M',
                       help='momentum factor')
    group.add_argument('--weight-decay', '--wd', default=0.0, type=float, metavar='WD',
                       help='weight decay')

    # Learning rate schedulers can be found under fairseq/optim/lr_scheduler/
    group.add_argument('--lr-scheduler', default='reduce_lr_on_plateau',
                       help='learning rate scheduler: {} (default: reduce_lr_on_plateau)'.format(
                           ', '.join(LR_SCHEDULER_REGISTRY.keys())))
    group.add_argument('--lr-shrink', default=0.1, type=float, metavar='LS',
                       help='learning rate shrink factor for annealing, lr_new = (lr * lr_shrink)')
    group.add_argument('--min-lr', default=1e-5, type=float, metavar='LR',
                       help='minimum learning rate')
    group.add_argument('--min-loss-scale', default=1e-4, type=float, metavar='D',
                       help='minimum loss scale (for FP16 training)')

    # Criterion args
    parser.add_argument('--label-smoothing', default=0., type=float, metavar='D',
                        help='epsilon for label smoothing, 0 means no label smoothing')

    # Parallel backward + all-reduce optimization
    group.add_argument('--enable-parallel-backward-allred-opt', action='store_true',
                       help='enable all reduce of w-gradients in parallel with backward propagation (only for FP16 training)')
    group.add_argument('--parallel-backward-allred-opt-threshold', type=int, default=0, metavar='N',
                       help='min num of contiguous gradient elements before all-reduce is triggered')
    group.add_argument('--enable-parallel-backward-allred-opt-correctness-check', action='store_true',
                       help='compare w-gradient values obtained doing all-reduce in parallel vs. at the end')

    return group

def add_checkpoint_args(parser):
    group = parser.add_argument_group('Checkpointing')
    group.add_argument('--restore-file', default='checkpoint_last.pt',
                       help='filename in save-dir from which to load checkpoint')
    group.add_argument('--save-interval', type=int, default=1, metavar='N',
                       help='save a checkpoint every N epochs')
    group.add_argument('--save-interval-updates', type=int, default=0, metavar='N',
                       help='save a checkpoint (and validate) every N updates')
    group.add_argument('--keep-interval-updates', type=int, default=-1, metavar='N',
                       help='keep last N checkpoints saved with --save-interval-updates')
    group.add_argument('--no-save', action='store_true',
                       help='don\'t save models or checkpoints')
    group.add_argument('--no-epoch-checkpoints', action='store_true',
                       help='only store last and best checkpoints')
    group.add_argument('--validate-interval', type=int, default=1, metavar='N',
                       help='validate every N epochs')
    group.add_argument('--resume', default=None,
                       help='checkpoint to resume, override auto ckpt filename generation')
    group.add_argument('--restart-training', action='store_true',help='load a ckpt but do not load epoch number and lr')
    group.add_argument('--quick-save', action='store_true',
                       help='do not evaluate model and save best or other info, just save the model')
    return group

def add_common_eval_args(group):
    group.add_argument('--path', metavar='FILE',
                       help='path(s) to model file(s), colon separated')
    group.add_argument('--remove-bpe', nargs='?', const='@@ ', default=None,
                       help='remove BPE tokens before scoring')
    group.add_argument('--cpu', action='store_true', help='generate on CPU')
    group.add_argument('--quiet', action='store_true',
                       help='only print final scores')

def add_inference_args(parser):
    group = parser.add_argument_group('Generation')
    add_common_eval_args(group)
    group.add_argument('--beam', default=4, type=int, metavar='N',
                       help='beam size')
    group.add_argument('--nbest', default=1, type=int, metavar='N',
                       help='number of hypotheses to output')
    group.add_argument('--max-len-a', default=0, type=float, metavar='N',
                       help=('generate sequences of maximum length ax + b, '
                             'where x is the source length'))
    group.add_argument('--max-len-b', default=200, type=int, metavar='N',
                       help=('generate sequences of maximum length ax + b, '
                             'where x is the source length'))
    group.add_argument('--min-len', default=1, type=float, metavar='N',
                       help=('minimum generation length'))
    group.add_argument('--no-early-stop', action='store_true',
                       help=('continue searching even after finalizing k=beam '
                             'hypotheses; this is more correct, but increases '
                             'generation time by 50%%'))
    group.add_argument('--unnormalized', action='store_true',
                       help='compare unnormalized hypothesis scores')
    group.add_argument('--no-beamable-mm', action='store_true',
                       help='don\'t use BeamableMM in attention layers')
    group.add_argument('--lenpen', default=1, type=float,
                       help='length penalty: <1.0 favors shorter, >1.0 favors longer sentences')
    group.add_argument('--unkpen', default=0, type=float,
                       help='unknown word penalty: <0 produces more unks, >0 produces fewer')
    group.add_argument('--replace-unk', nargs='?', const=True, default=None,
                       help='perform unknown replacement (optionally with alignment dictionary)')
    group.add_argument('--score-reference', action='store_true',
                       help='just score the reference translation')
    group.add_argument('--prefix-size', default=0, type=int, metavar='PS',
                       help='initialize generation by target prefix of given length')
    group.add_argument('--sampling', action='store_true',
                       help='sample hypotheses instead of using beam search')
    group.add_argument('--sampling-topk', default=-1, type=int, metavar='PS',
                       help='sample from top K likely next words instead of all words')
    group.add_argument('--sampling-temperature', default=1, type=float, metavar='N',
                       help='temperature for random sampling')
    group.add_argument('--print-alignment', action='store_true',
                       help='if set, uses attention feedback to compute and print alignment to source tokens')
    group.add_argument('--model-overrides', default="{}", type=str, metavar='DICT',
                       help='a dictionary used to override model args at generation that were used during model training')
    group.add_argument('--online-eval', action='store_true',
                       help='score model at the end of epoch')
    group.add_argument('--save-predictions', action='store_true',
                       help='Save predictions produced with online evaluation')
    group.add_argument('--test-cased-bleu', action='store_true',
                       help='Use cased bleu for online eval')
    group.add_argument('--bpe-codes', default=None, type=str, metavar='CODES',
                        help='file with bpe codes')
    group.add_argument('--buffer-size', default=64, type=int, metavar='N',
                       help='read this many sentences into a buffer before processing them')
    group.add_argument('--fp16', action='store_true', help='use fp16 precision')

    return group

def add_profiling_args(parser):
    group = parser.add_argument_group('Profiling')
    group.add_argument('--profile', action='store_true',
                       help='Run profiler')
    group.add_argument('--profiler-file', type=str, default=None,
                       help='File to save profiling info into')
    group.add_argument('--profiler-steps', type=int, default=100,
                        help='Override to the max steps argument')
    return group

def add_model_args(parser):
    group = parser.add_argument_group('Model configuration')

    # Model definitions can be found under fairseq/models/
    #
    # The model architecture can be specified in several ways.
    # In increasing order of priority:
    # 1) model defaults (lowest priority)
    # 2) --arch argument
    # 3) --encoder/decoder-* arguments (highest priority)
    group.add_argument(
        '--arch', '-a', default='fconv', metavar='ARCH', required=True,
        choices=ARCH_MODEL_REGISTRY.keys(),
        help='model architecture: {} (default: fconv)'.format(
            ', '.join(ARCH_MODEL_REGISTRY.keys())),
    )

    # Criterion definitions can be found under fairseq/criterions/
    group.add_argument(
        '--criterion', default='cross_entropy', metavar='CRIT',
        choices=CRITERION_REGISTRY.keys(),
        help='training criterion: {} (default: cross_entropy)'.format(
            ', '.join(CRITERION_REGISTRY.keys())),
    )

    return group

def add_perf_args(parser):
    group = parser.add_argument_group('Performance')
    group.add_argument('--fuse-dropout-add', action='store_true',
                       help='Fuse dropout and residual adds.')
    group.add_argument('--fuse-relu-dropout', action='store_true',
                       help='Fuse Relu and Dropout.')
    group.add_argument('--fuse-layer-norm', action='store_true',
                       help='Use APEX\'s FusedLayerNorm instead of torch.nn.LayerNorm')
    group.add_argument('--apply-att-mask', action='store_true', help='apply masks on attention softmax')
    group.add_argument('--apply-dynamic-att-mask',action='store_true', help='apply dynamic masks on attention after softmax')
    group.add_argument('--mhatt-debug', action='store_true', help='Set breakpoint and debug multiheaded attention module')

    return group

def add_multi_round_args(parser):
    group = parser.add_argument_group('multi_round')
    group.add_argument('--load-parallel-model', action="store_true", dest="load_parallel_model",
                        help="load and combine parallel grown model blocks")
    group.add_argument("--num-gap-partition", default=6, type=int, help="number of partition of gap")
    group.add_argument('--parallel-1-dir', default=None, type=str, help='resnet-50 parallel model 1')
    group.add_argument('--parallel-2-dir', default=None, type=str, help='resnet-50 parallel model 2')
    group.add_argument('--parallel-3-dir', default=None, type=str, help='resnet-50 parallel model 3')
    group.add_argument('--parallel-4-dir', default=None, type=str, help='resnet-50 parallel model 4')
    group.add_argument('--parallel-5-dir', default=None, type=str, help='resnet-50 parallel model 5')
    group.add_argument('--parallel-6-dir', default=None, type=str, help='resnet-50 parallel model 6')
    group.add_argument("--combine-without-finetune", action="store_true",
                        help="hard prune the combine model and save without fine-tune")


import f90nml
import argparse
import json

parser = argparse.ArgumentParser(description='This program converts namelist.input file of SKRIPS-WRF to WRF only\'s namelist.input. The main work is to remove `auxinput5` related variables from `time_control` namegroup.')

parser.add_argument('--input', type=str, required=True, help='Input namelist file')
parser.add_argument('--output', type=str, required=True, help='Input namelist file')
parser.add_argument('--overwrite', action="store_true")

args = parser.parse_args()

print("Input file: %s" % (args.input,))
print("Output file: %s" % (args.output,))

namegroup = 'time_control'

in_nml = f90nml.read(args.input)

print("Original namegroup `%s`" % (namegroup,))
print(json.dumps(in_nml[namegroup], indent=4))

for varname in [
    "auxinput5_inname",
    "auxinput5_interval_s",
    "auxinput5_end_d",
    "io_form_auxinput5",
    "auxhist5_outname",
    "auxhist5_interval_s",
    "auxhist5_end_d",
    "io_form_auxhist5",
]:
    print("Removing variable: %s" % (varname,))
    del in_nml[namegroup][varname]

print("Writing file: %s" % (args.output,))
in_nml.end_comma = True
in_nml.write(args.output, force=args.overwrite)


from serial.tools.list_ports import comports
from serial import (
    Serial,
    SerialException,
    FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS,
    PARITY_NONE, PARITY_EVEN, PARITY_ODD, PARITY_MARK, PARITY_SPACE,
    STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWO
)
from threading import Thread, currentThread
import tkinter as tk
import xlsxwriter
from datetime import datetime
import re
from tkinter.scrolledtext import ScrolledText
from tkinter.filedialog import askdirectory
from tkinter import N, S, W, E
import os

desktop = os.path.join(os.path.join(os.environ['USERPROFILE']), 'Desktop')

class MainApplication(tk.Frame):
    def __init__(self, parent, *args, **kwargs):
        tk.Frame.__init__(self, parent, *args, **kwargs)
        self.parent = parent
        self.parent.title('Serial to XLS')
        self.parent.resizable(False, False)

        self.pack(pady=20, padx=40)

        # machine
        machine_label = tk.Label(self, text='Macchina')
        self.machine_field = tk.Entry(self)

        # folder
        folder_label = tk.Label(self, text='Esporta in')
        self.folder_field = tk.Entry(self)
        self.folder_field.insert(0, desktop)
        self.folder_field.bind("<Button-1>", self.open_folder)

        # port
        self.port_var = tk.StringVar(self.parent)
        self.ports = {p.device: p for p in comports()}
        if len(self.ports.keys()) > 0:
            self.port_var.set(list(self.ports.keys()).pop(0))
            port_menu = tk.OptionMenu(self, self.port_var, *self.ports.keys())
        else:
            port_menu = tk.OptionMenu(self, self.port_var, None)
        port_label = tk.Label(self, text="Port")

        # baudrate
        baud_label = tk.Label(self, text='Baudrate')
        self.baud_field = tk.Entry(self)
        self.baud_field.insert(0, 9600)

        # bytesize
        self.byte_var = tk.IntVar(self.parent)
        self.byte_var.set(SEVENBITS)
        byte_label = tk.Label(self, text='Bytetype')
        byte_menu = tk.OptionMenu(
            self, self.byte_var, *[FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS])

        # parity
        self.parity_var = tk.StringVar(self.parent)
        self.parity_var.set(PARITY_EVEN)
        parity_label = tk.Label(self, text='Parity')
        parity_menu = tk.OptionMenu(
            self, self.parity_var, *[PARITY_NONE, PARITY_EVEN, PARITY_ODD, PARITY_MARK, PARITY_SPACE])

        # stopbit
        self.stopbit_var = tk.DoubleVar(self.parent)
        self.stopbit_var.set(STOPBITS_ONE)
        stopbit_label = tk.Label(self, text='Stopbit')
        stopbit_menu = tk.OptionMenu(
            self, self.stopbit_var, *[STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWO])

        # logarea
        self.log_area = ScrolledText(self.parent, width=40, height=10)

        self.button = tk.Button(
            self, text="Start", fg="red", height=5, width=10, command=self.toggle, state='disabled' if len(self.ports.keys()) == 0 else 'normal')

        machine_label.grid(row=0, column=0)
        self.machine_field.grid(row=0, column=1)
        folder_label.grid(row=1, column=0)
        self.folder_field.grid(row=1, column=1)
        port_label.grid(row=2, column=0)
        port_menu.grid(row=2, column=1, sticky=E+W)
        baud_label.grid(row=3, column=0)
        self.baud_field.grid(row=3, column=1, sticky=E+W)
        byte_label.grid(row=4, column=0)
        byte_menu.grid(row=4, column=1, sticky=E+W)
        parity_label.grid(row=5, column=0)
        parity_menu.grid(row=5, column=1, sticky=E+W)
        stopbit_label.grid(row=6, column=0)
        stopbit_menu.grid(row=6, column=1, sticky=E+W)
        self.button.grid(row=0, column=2, rowspan=6, sticky=N+S+E)
        self.log_area.pack()

        self.running = False
        self.current_port = None
        self.thread = None
        self.buffer = ''

    def open_folder(self, e):
        folder = askdirectory()
        if folder:
            self.folder_field.delete(0, tk.END)
            self.folder_field.insert(0, folder)

    def log(self, text):
        self.log_area.config(state='normal')
        self.log_area.insert(tk.INSERT, text + '\n')
        self.log_area.config(state='disabled')

    def handle_data(self, new_data):
        if new_data != '':
            self.buffer += new_data.strip()
            full_match = re.match(r'@00EX((?:[0-9]{4})+)5B\*', self.buffer)
            # print(self.buffer, full_match)
            if full_match:
                self.buffer = ''
                data = full_match.group(1)
                self.log('Ricevuto: %s' % data)
                A = ord('A')
                for i, match in enumerate(re.findall(r'[0-9]{4}', data)):
                    now = datetime.now()
                    self.worksheet.write(
                        'A%s' % self.row_count, now.strftime("%m/%d/%Y"))
                    self.worksheet.write(
                        'B%s' % self.row_count, now.strftime("%H:%M:%S"))
                    self.worksheet.write_number(
                        '%s%s' % (chr(A+i+2), self.row_count), int(match))
                self.row_count += 1
                # print('RECEIVED', data)

    def read_from_port(self, port, baudrate, byte, parity, stopbit):
        # print(port, baudrate, byte, parity, stopbit)
        s = Serial(
            port,
            baudrate=baudrate,
            bytesize=byte,
            parity=parity,
            stopbits=stopbit,
            timeout=0
        )
        t = currentThread()
        self.log('Porta: %s|%s|%s|%s|%s connessa' %
                 (port, baudrate, byte, parity, stopbit))
        while getattr(t, "do_run", True):
            try:
                reading = s.read().decode()
                self.handle_data(reading)
            except SerialException as e:
                self.toggle()
                self.log('Errore di comunicazione')
        s.close()
        self.log('Porta disconnessa')

    def toggle(self):
        self.running = not self.running
        self.button.configure(text='Stop' if self.running else 'Start')

        if self.running:
            xls_title = 'Letture_%s_%s.xlsx' % (self.machine_field.get(), datetime.now().strftime("%m%d%Y%H%M%S"))
            xls_path = os.path.join(self.folder_field.get(), xls_title)
            self.workbook = xlsxwriter.Workbook(xls_path)
            self.worksheet = self.workbook.add_worksheet()
            self.log('Xls: %s' % xls_title)
            self.row_count = 1
            self.current_port = self.ports[self.port_var.get()]
            self.thread = Thread(target=self.read_from_port,
                                 args=(self.current_port.device, int(self.baud_field.get()), self.byte_var.get(), self.parity_var.get(), self.stopbit_var.get()))
            self.thread.start()
        else:
            self.thread.do_run = False
            self.workbook.close()
            self.log('Xls salvato')

if __name__ == "__main__":
    root = tk.Tk()
    MainApplication(root).pack(side="top", fill="both", expand=True)
    root.mainloop()


from django.conf.urls import url

from views import *

urlpatterns = [
    url(r'^$', index),
    url(r'^register$', register),
    url(r'^login$', login),
    url(r'^quotes$', quotes),
    url(r'^addquote$', addquote),
    url(r'^addfave/(?P<id>\d+)$', addfave),
    url(r'^deletefave/(?P<id>\d+)$', deletefave),
    url(r'^showuser/(?P<id>\d+)$', showuser),
    url(r'^deletequote/(?P<id>\d+)$', deletequote),
    url(r'^logout$', logout),
]


# from django.forms.models import modelformset_factory
from django.forms.formsets import formset_factory
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import get_object_or_404, render, render_to_response
from django.core.urlresolvers import reverse
from polls.models import *
import json

input_dict = {
    1: 'radio',     #тип 1.2
    2: 'checkbox',  #тип 1.3
    3: 'radio',     #тип 1.1
}

def index(request):
    return HttpResponse("Hello, world. You're at the polls index.")

def detail(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    return render(request, 'detail.html', {'question': question})

def make_context(amount=10):
    quest_list = []
    index = 0
    AllQuestion = Question.objects.all()[:amount]
    for quest in AllQuestion:
        ChoiceForQuestion = Choice.objects.filter(question=quest.pk)
        chois_list = []
        quest_dict = {}
        index += 1
        if ChoiceForQuestion:
            for chois in ChoiceForQuestion:
                chois_dict = {}
                chois_dict['choice_text'] = chois.choice_text
                chois_dict['choice_cost_positive'] = chois.choice_cost_positive
                chois_dict['choice_cost_negative'] = chois.choice_cost_negative
                chois_dict['choice_is_true'] = chois.choice_is_true
                chois_dict['choice_id'] = chois.id
                chois_list.append(chois_dict)
        quest_dict['question_text'] = quest.question_text
        quest_dict['question_choice'] = chois_list
        quest_dict['question_input_type'] = input_dict[quest.question_type]
        quest_dict['question_type'] = quest.question_type
        quest_dict['question_cost_positive'] = quest.question_cost_positive
        quest_dict['question_cost_negative'] = quest.question_cost_negative
        quest_dict['question_id'] = quest.id
        quest_dict['index'] = index
        quest_list.append(quest_dict)
    return quest_list

def make_context_js(amount=10):
    quest_list = []
    index = 0
    AllQuestion = Question.objects.all()[:amount]
    for quest in AllQuestion:
        ChoiceForQuestion = Choice.objects.filter(question=quest.pk)
        chois_list = []
        quest_dict = {}
        index += 1
        if ChoiceForQuestion:
            for chois in ChoiceForQuestion:
                chois_dict = {}
                chois_dict['choice_text'] = chois.choice_text
                chois_dict['choice_id'] = chois.id
                chois_list.append(chois_dict)
        quest_dict['question_text'] = quest.question_text
        quest_dict['question_choice'] = chois_list
        quest_dict['question_input_type'] = input_dict[quest.question_type]
        quest_dict['question_id'] = quest.id
        quest_dict['index'] = index
        quest_list.append(quest_dict)
    return quest_list

c = make_context()

c_js = make_context_js()

# def test(request):
#
#     return render_to_response('test.html', {
#         'formset': c_js,
#     })

#для jsona
def test(request):

    context_js = json.dumps(c_js, ensure_ascii=False)

    return render_to_response('jstext.html', {
        'formset': context_js,
    })

def vote(request):

    if request.method == 'POST':
        kwargs = [k for k in request.POST.lists()]
        keys_c = [k for k in request.POST.dict().keys()]
        BSum = 0 #Базовая оценка
        YSum = 0 #Продуктивная оценка
        for i in range(0, len(keys_c)):
            quest_id = keys_c[i]
            choice_list = request.POST.getlist(keys_c[i])
            for quest_index in c:
                if quest_index['question_id'] == int(keys_c[i]):
                    quest = quest_index
            asda = 'asd'
            # тип вопроса 1.2
            if quest['question_type'] == 1:
                BSum = BSum + max([v['choice_cost_positive'] for v in quest['question_choice']])
                for choice_index in quest['question_choice']:
                    if choice_index['choice_id'] == int(choice_list[0]):
                        choice_cost = choice_index['choice_cost_positive']
                YSum = YSum + choice_cost
            #остальные типы вопросов
            else:
                BSum = BSum + quest['question_cost_negative']
                if quest['question_type'] == 3:
                    for choice_index in quest['question_choice']:
                        if choice_index['choice_id'] == int(choice_list[0]):
                            if choice_index['choice_is_true']:
                                BSum = BSum - quest['question_cost_negative'] + quest['question_cost_positive']
                                YSum = YSum + quest['question_cost_positive']
                if quest['question_type'] == 2:
                    true_index = 0
                    true_choice = 0
                    for choice_index in quest['question_choice']:
                        if choice_index['choice_is_true']:
                            true_index += 1
                        for choice_selected in choice_list:
                            if int(choice_selected) == choice_index['choice_id']:
                                if choice_index['choice_is_true']:
                                    true_choice += 1

                    if true_choice == true_index:
                        YSum = YSum + quest['question_cost_positive']
        rating = 100 * (YSum/BSum)
        ok = 'неудача'
        if rating > 80:
            ok = 'Отлично'
        elif rating > 65:
            ok = 'Хорошо'
        elif rating > 50:
            ok = 'Удовлетворительно'
        return render_to_response("vote.html", {
            "vote": ok,
        })