# coding=utf-8
'''
Created on Jan 26, 2012

@author: vvitvitskiy
'''
import re
import UserDict
import sap
import string
import command
import fptools
import logger
from collections import namedtuple
import netutils
from sap_db import DbInfo

class IniDocument(UserDict.UserDict):
    r''' Very raw representation of SAP ini file, usually profiles
    Simply a dictionary of keys and values
    '''
    def getAny(self, *names):
        r'@types: tuple[str] -> str or None'
        for name in names:
            if name in self:
                return self.get(name)
        return None

    def findIndexedValues(self, name):
        r''' Find attribute that is indexed like
        attr_name_0=value0
        attr_name_1=value1
        Result will be list [value0, value1]
        @types: str -> list[str]
        @param name: Property name without digit and last underscore
        '''
        index = 0
        values = []
        value = self.get('%s_%s' % (name, index))
        while value:
            values.append(value)
            index += 1
            value = self.get('%s_%s' % (name, index))
        return values

class ProfileParser:
    r''' Base class for profile parsers.
    Each parser for dedicated profile type parses only own data, to take
    full picture - all three parsers has to be applied
    '''

    def __init__(self, sapIniParser):
        r'@types: IniParser'
        assert sapIniParser
        self.__sapIniParser = sapIniParser

    def _getIniParser(self):
        r'@types: -> IniParser'
        return self.__sapIniParser

    def parseAsIniResult(self, content):
        r'@types: str -> IniDocument'
        return self.__sapIniParser.parseValueByNameMapping(content,
                                        valueTransformationFn=string.strip)

    def parseContent(self, content):
        r'@types: str -> Profile'
        document = self._getIniParser().parseValueByNameMapping(content,
                                            None, string.strip)
        return self._parseIniDocument(document)

    def _parseIniDocument(self, document):
        r'''@types: IniDocument -> Profile
        '''
        raise NotImplementedError()

    @staticmethod
    def parseInstance(doc):
        r'@types: IniDocument -> sap.Instance'
        return parse_inst_in_pf(doc)

    @classmethod
    def isApplicable(cls, pfName):
        r'''Determine if parser can be applied to profile with specified name
        @types: PyClass, str -> bool
        '''
        return pfName and cls.PF_NAME_PATTERN.match(pfName) is not None

    @classmethod
    def parseInstanceNameFromPfName(cls, pfName):
        r'@types: PyClass, str -> str or None'
        matchObj = cls.PF_NAME_PATTERN.match(pfName)
        return matchObj and matchObj.group(1)

InstancePfSet = namedtuple('InstancePfSet', ('startPfIni', 'instancePfIni'))

def createPfsIniDoc(defaultPfDoc, startPfDoc, instancePfDoc):
    '''Create ini document that gathers information from all profiles
    so to make lookup in right order
    @types: IniDocument?, IniDocument?, IniDocument? -> IniDocument
    '''
    doc = IniDocument()
    defaultPfDoc and doc.update(defaultPfDoc)
    startPfDoc and doc.update(startPfDoc)
    instancePfDoc and doc.update(instancePfDoc)
    return doc

class AscsInfoPfParser:
    '''
    From doc: http://help.sap.com/saphelp_nw04s/helpdata/en/36/67973c3f5aff39e10000000a114084/content.htm

    Standalone enqueue server is a part of ASCS.
    If you want to use the standalone enqueue server, set the following parameters in the profile files of the enqueue clients (application server instances):
    enque/serverhost = <host name of the enqueue server>
    enque/serverinst = <instance number of the enqueue server>

    From the matters expert's e-mail:
    If "enque/serverinst" is not set then it takes default value $(SAPSYSTEM).

    If enque/serverhost is set, but there is no Standalone enqueue server, SAP system might work, but this case is not supported (by SAP).
    '''
    @staticmethod
    def parse(document):
        instance_nr = (document.get('enque/serverinst')
                       or document.get('SAPSYSTEM'))
        instance_hostname = document.get('enque/serverhost')
        if not instance_hostname:  # there is no standalone enqueue server
            return None, None
        return instance_hostname, instance_nr

class DbInfoPfParser:
    '''
    Based on http://www.sapheaven.com/2012/01/profile-parameters-sap_6540.html
    ADA DB2 DB4 DB6 INF MSS ORA SQL SYB
    '''

    DBINFO_PARAMETERS = (
        (('dbs/db2/ssid', ), ('dbs/db2/hosttcp', 'SAPDBHOST')),
        (('dbs/db4/ssid', ), ('dbs/db4/hosttcp', 'SAPDBHOST')),
        (('dbs/db6/ssid', ), ('dbs/db6/hosttcp', 'SAPDBHOST')),
        (('dbs/mss/dbname',), ('dbs/mss/server',))
    )

    @staticmethod
    def parseAbapSchemaName(iniDocument):
        ''''In case of double stack there is java db instance and ABAP side uses
        own schema
        @types: IniDocument -> str or None
        '''
        return iniDocument.get('dbs/ada/schema')

    @staticmethod
    def parseAbapInstanceDbInfo(iniDocument):
        r'@types: IniDocument -> DbInfo or None'
        dbParameters = DbInfoPfParser.DBINFO_PARAMETERS
        for nameParameters, hostParameters in dbParameters:
            try:
                dbType = iniDocument.getAny('dbms/type')
                name = iniDocument.getAny(*nameParameters)
                if re.match(r'\$\((\w+)\)', name):
                    name = re.search(r'(\w+)', name).group(0)
                hostname = iniDocument.getAny(*hostParameters)
                if name and hostname and dbType:
                    return DbInfo(name, hostname, dbType, None, False)
            except Exception:
                logger.warnException("Database meta-data declaration invalid")

    @staticmethod
    def parseJavaInstanceDbInfo(document):
        r'@types: IniDocument -> DbInfo or None'
        type_ = document.get('j2ee/dbtype')
        name = document.get('j2ee/dbname')
        hostname = (document.get('j2ee/dbhost')
                    or document.get('SAPDBHOST'))
        info = None
        if name and hostname and type_:
            info = DbInfo(name, hostname, type_, None, True)
        return info

    @staticmethod
    def parseDbInfo(iniDocument):
        r'@types: IniDocument -> DbInfo or None'
        dbInfo = DbInfoPfParser.parseJavaInstanceDbInfo(iniDocument)
        if dbInfo:
            schemaName = DbInfoPfParser.parseAbapSchemaName(iniDocument)
            dbInfo = dbInfo._replace(schema=schemaName)
        else:
            dbInfo = DbInfoPfParser.parseAbapInstanceDbInfo(iniDocument)
        return dbInfo

def parse_system_in_pf(doc):
    '''
    Parse system related information from profile
    @types: IniDocument -> sap.System?'''
    sid = doc.get('SAPSYSTEMNAME')
    type_ = doc.get('system/type')
    uuid = doc.get('system/uuid')
    global_host = doc.get('SAPGLOBALHOST')
    if sid:
        return sap.System(sid, globalHost=global_host, type_=type_, uuid_=uuid)

def parse_inst_in_pf(doc):
    '''
    Parse instance related information from profile
    @types: IniDocument -> sap.Instance
    '''
    inst = parseInstanceFromName(doc.get('INSTANCE_NAME'))
    hostname = doc.get('SAPLOCALHOST')
    fqdn = doc.get('SAPLOCALHOSTFULL')
    if not hostname and fqdn and not _has_substitution_variable(fqdn):
        hostname = parse_hostname_from_fqdn(fqdn)
    return sap.Instance(inst.name, inst.number, hostname)

def _has_substitution_variable(value):
    '@types: str -> bool'
    return value.find('$(') > -1

def parse_hostname_from_fqdn(fqdn):
    hostname = fqdn
    if fqdn and fqdn.find('.') > 0:
        hostname = fqdn[0:fqdn.find('.')]
    return hostname

class StartProfileParser(ProfileParser):
    r''' Parser for the SAP START profile. There is one START profile per
    instance. But since SAP NetWeaver 7.3 start profile has been
    removed as separate file and content merged with instance profile '''

    PF_NAME_PATTERN = re.compile(r"START_([A-Za-z]+\d{2})_\w+")

    _Profile = namedtuple('Profile', ('system', 'instance', 'dbInfo'))

    def _parseIniDocument(self, document):
        r'@types: IniDocument -> Profile[System, Instance]'
        system = parse_system_in_pf(document)
        inst = ProfileParser.parseInstance(document)
        db_info = DbInfoPfParser.parseDbInfo(document)
        return self._Profile(system, inst, db_info)

class DefaultProfileParser(ProfileParser):
    r''' Parser for the SAP DEFAULT profile. There is one profile
    per system.'''

    PF_NAME_PATTERN = re.compile('DEFAULT')

    _Profile = namedtuple('Profile', ('system', 'dbHost', 'fqdn', 'abapMsHost',
                                       'jeeScsInstance', 'jeeMsEndpoint',
                                       'jeeDbInfo', 'dbInfo'))

    def _parseScsInstance(self, document):
        r'''@types: IniDocument -> tuple[sap.Instance, Endpoint or None]
        @return: tuple of SCS instance itself and message server endpoint
        '''
        instance = None
        msEndpoint = None
        hostname = document.get('j2ee/scs/host')
        number = document.get('j2ee/scs/system')
        msPort = document.get('j2ee/ms/port')
        if hostname and number:
            instance = sap.Instance('SCS', number, hostname)
            if msPort:
                msEndpoint = netutils.createTcpEndpoint(hostname, msPort)
        return instance, msEndpoint

    def _parseAbapMsEndpoint(self, document):
        r'@types: IniDocument -> Endpoint or None'
        hostname = document.get('rdisp/mshost')
        #TODO: any other parameter for port value ?
        #TODO: what to do with `rdisp/msserv` parameter ?
        port = document.get('rdisp/msserv_internal')
        if hostname and port:
            return netutils.createTcpEndpoint(hostname, port)
        return None

    def _parseIniDocument(self, document):
        r'@types: IniDocument -> Profile'
        system = parse_system_in_pf(document)
        dbHost = document.get('SAPDBHOST')
        fqdn = document.get('SAPFQDN')
        abapMsEndpoint = self._parseAbapMsEndpoint(document)
        scsInstance, jeeMsEndpoint = self._parseScsInstance(document)

        abapDbs = DbInfoPfParser.parseAbapInstanceDbInfo(document)
        abapDb = abapDbs and abapDbs[0] or None

        javaDb = DbInfoPfParser.parseJavaInstanceDbInfo(document)
        return self._Profile(system, dbHost, fqdn, abapMsEndpoint,
                              scsInstance, jeeMsEndpoint,
                              javaDb, abapDb)

    def parse(self, document):
        r'''
        r'@types: IniDocument -> sap.DefaultProfile'
        @deprecated: use `parseContent` instead
        '''
        #TODO: make refactoring to get rid of this method
        pf = self._parseIniDocument(document)
        return sap.DefaultProfile(pf.system)

class InstanceProfileParser(ProfileParser):
    r'''Parser for the SAP instance profile. There is one instance profile per
    instance'''

    PF_NAME_PATTERN = re.compile(r"[A-Za-z]{3}_([A-Za-z]+\d{2})_\w+")

    _Profile = namedtuple('Profile', ('system', 'instance',
                                      'jeeDbDriver', 'jeeEndpoints',
                                      'dbInfo'))

    @staticmethod
    def _parsePortDeclarationToEndpoint(declaration, number, hostname):
        r'''Parse string of format
            PROT=<protocol>, PORT=<number>, TIMEOUT=<number>,
        where PORT may contain $$ substring that has to be replaced with
        instance number where this port is opened

        An example:
        PROT=HTTPS,PORT=443, HOST=hostname, TIMEOUT=3600, EXTBIND=1

        @types: str, str, str -> Endpoint or None
        @param number: instance number
        @param hostname: instance hostname
        '''
        declarationAsIni = declaration.replace(',', '\n')
        iniParser = IniParser()
        iniDoc = iniParser.parseValueByNameMapping(declarationAsIni,
                                                 string.strip, string.strip)
        protocol, port = iniDoc.get('PROT'), iniDoc.get('PORT')
        if not hostname:
            hostname = iniDoc.get('HOST')
        endpoint = None
        if port and hostname:
            # check for the substitution placeholder `$$`
            if port.find('$$') != -1:
                port = port.replace('$$', number)
            # determine port type
            portType = sap.PortTypeEnum.findByName(protocol)
            endpoint = netutils.createTcpEndpoint(hostname, port, portType)
        return endpoint

    def _parseServerPorts(self, document, instanceNumber, hostname):
        r'@types: IniDocument -> tuple[Endpoint]'
        portDeclarations = document.findIndexedValues('icm/server_port')
        parsePortDeclaration = fptools.partiallyApply(
            InstanceProfileParser._parsePortDeclarationToEndpoint, fptools._,
            instanceNumber, hostname)
        return filter(None, map(parsePortDeclaration, portDeclarations))

    def _parseIniDocument(self, document):
        r'@types: IniDocument -> Profile'
        system = parse_system_in_pf(document)
        instance = self.parseInstance(document)
        # determine java side
        # jstartup/release = 700
        # j2ee/dbdriver = D:\sapdb\clients\AGX\runtime\jar\sapdbc.jar

        # ==
        #TODO: can be used to determine whether JEE side is running ?
        # rdisp/j2ee_start = 0

        #TODO: find out the purpose of this port
        # icm/HTTP/j2ee_0 = PREFIX=/,HOST=localhost,CONN=0-500,PORT=5$$00

        #TODO: find out the purpose of this port
        # ms/server_port_0 = PROT=HTTP,PORT=81$$

        jeeDbDriver = document.get('j2ee/dbdriver')
        jeeEndpoints = self._parseServerPorts(document, instance.number,
                                              instance.hostname)
        abapDbs = DbInfoPfParser.parseAbapInstanceDbInfo(document)
        db = abapDbs and abapDbs[0] or None
        return self._Profile(system, instance, jeeDbDriver, jeeEndpoints, db)

    def parse(self, document):
        r''' @types: IniDocument -> sap.InstanceProfile
        @deprecated: use `parseContent` instead
        '''
        pf = self._parseIniDocument(document)
        return sap.InstanceProfile(pf.instance)

class IniParser:
    r''' Generic parser for all ini-like configuration files '''

    @staticmethod
    def parseIniDoc(content):
        r''' Parse content without applying any transformations to parsed keys
        and values except of strip function to value.
        @types: str -> IniDocument
        '''
        return IniParser.parseValueByNameMapping(content,
                                        valueTransformationFn=string.strip)

    @staticmethod
    def parseValueByNameMapping(content, keyTransformationFn=None,
                                               valueTransformationFn=None,
                                               nameValueSeparator='='):
        r'''
        Value is not stripped by default, valueTransformationFn
        may be used for that
        @types: str, (str -> str), (str -> str)  -> IniDocument
        @param keyTransformationFn: transformers for the key before saving
                    value by it. For instance if string.uppercase specified
                    all keys will be in upper case
        @param valueTransformationFn: transformation function applied to each
                    value
        '''
        valueByName = IniDocument()
        for line in content.splitlines():
            line = line.strip()
            if (line
                    # is not commented line
                    and not line.startswith('#')
                    # has mapping of value by name
                    and line.find(nameValueSeparator) != -1):

                name, value = line.split(nameValueSeparator, 1)
                # value part may contain commented substring which
                # has to be truncated
                # if # is not escaped like \#
                matchObj = re.search(r'[^\\](#)', value)
                if matchObj:
                    # found not escaped comment sign
                    value = value[:matchObj.start(1)]
                # apply transformations
                name = name.strip()
                if keyTransformationFn:
                    name = keyTransformationFn(name)
                if valueTransformationFn:
                    value = valueTransformationFn(value)
                valueByName[name] = value
        return valueByName

class IniParserCmdlet(IniParser, command.Cmdlet):
    def __init__(self, keyTransformationFn=None, valueTransformationFn=None):
        self.keyTransformationFn = keyTransformationFn
        self.valueTransformationFn = valueTransformationFn

    def process(self, result):
        return self.parseValueByNameMapping(result,
                        self.keyTransformationFn, self.valueTransformationFn)

def parseIniFile(*args, **kwargs):
    return IniParserCmdlet(*args, **kwargs)

class SapSystemBuilderCmdlet(command.Cmdlet):
    def process(self, result):
        '''
        @types -> UserDict.UserDict -> sap.System
        '''
        assert 'sapsystemname' in result.keys()
        return sap.System(result['sapsystemname'])

def buildSapSystemFromDict(*args, **kwargs):
    return SapSystemBuilderCmdlet(*args, **kwargs)

def getProfilePathFromCommandline(param):
    '''
    @types: str -> str?
    '''
    if not (param or param.strip()):
        logger.debug('No valid parameters on process.')
        return
    # pattern doesn't consider quotes, so there is no spaces
    m = re.match(r'.*\spf\s*=\s*([\w\:\-/\.\\]+)(?:"|$|\s)', param)
    if not m:
        # pattern consider such cases
        # "pf=value" and pf="value"
        m = re.match(r'.*[\s"]pf\s*=[\s"]*([\w\:\-/\.\\\s ]+)(?:"|$)', param)
    return m and m.group(1)

class BaseLayout:
    def __init__(self, pathtools, rootPath, name=None):
        r'''
        @param name: name of entity that holds this layout, instance or system
        @types: file_topology.Path, str, str'''
        assert pathtools and rootPath
        self.__rootPath = pathtools.absolutePath(rootPath)
        self.__name = name
        self.__pt = pathtools

    def getName(self):
        r'@types: -> str?'
        return self.__name

    def _getPathTools(self):
        r'@types: -> file_topology.Path'
        return self.__pt

    def getRootPath(self):
        r'@types: -> str'
        return self.__rootPath

class Layout(BaseLayout):
    r'SAP system layout'

    def getPfDirectory(self):
        r'''Get base directory where instance profiles are saved
        @types: -> str'''
        return self._getPathTools().join(self.getRootPath(), 'SYS', 'profile')

    def getDefaultProfileFilePath(self):
        r'@types: -> str'
        return self._getPathTools().join(self.getPfDirectory(), 'DEFAULT.PFL')

    def composeStartPfPath(self, pfName):
        r''' Compose full path to the start PF based on the instance profile
        name of format '<SID>_<NAME>_<SAPLOCALHOST>'.

        Start profile name has such format 'START_<name>_<SAPLOCALHOST>'
        '@types: str -> str
        '''

        nameWithoutSid = pfName[pfName.find('_'):]
        return self._getPathTools().join(self.getPfDirectory(),
                                        'START%s' % nameWithoutSid)

    def composeInstancePfPath(self, pfName):
        r'@types: str -> str'
        if not pfName:
            raise ValueError("Profile file name is not specified")
        return self._getPathTools().join(self.getPfDirectory(), pfName)

    def composeInstanceDirPath(self, instanceName):
        r''' Compose path to the instance
        @types: str -> str'''
        if not instanceName:
            raise ValueError("Instance name is not specified")
        return self._getPathTools().join(self.getRootPath(), instanceName)

def findSystemBasePath(path, systemName):
    r''' Find root path of system with <systemName> as sub-path of <path>
    @types: str, str -> str?'''
    if not path:
        raise ValueError("Path is not specified")
    if not systemName:
        raise ValueError("SAP System name is not specified")
    index = path.find(systemName)
    return (index != -1
            and path[:index + len(systemName)]
            or None)

def parseInstanceFromName(instanceName):
    r'@types: str -> sap.Instance'
    assert instanceName
    matchObj = re.match(r'\s*([a-z]+?)(\d+)', instanceName, re.I)
    if matchObj:
        return sap.Instance(matchObj.group(1), matchObj.group(2))
    raise ValueError("Wrong instance name")

def parseSapSystemFromInstanceProfileName(profileName):
    r''' Format of profile name is: <SAPSYSTEMNAME>_<INSTANCE_NAME>_<SAPLOCALHOST>
    @types: str -> sap.System
    @raise ValueError: Wrong instance profile name

    @note: potentially relevant only to ABAP instance PF naming
    '''
    if not profileName:
        raise ValueError("Profile name is not specified")
    tokens = profileName.split('_', 2)
    if len(tokens) != 3:
        raise ValueError("Wrong instance profile name")
    systemName = tokens[0]
    instanceName = tokens[1]
    hostname = tokens[2]
    sapSystem = sap.System(systemName)
    instance = parseInstanceFromName(instanceName)
    sapSystem.addInstance(
        sap.Instance(instance.getName(), instance.getNumber(), hostname)
    )
    return sapSystem

# pattern used to parse profile path in the mounted global host directory
# UNIX systems:/usr/sap/<SID>/SYS/profile
# Windows NT: \\<SAPGLOBALHOST>\sapmnt\<SID>\sys\profile\
# For old versions \\SAPGLOBALHOST>\profile.<SID>\
_PF_PATH_AT_GLOBALHOST_PATTERN = re.compile(
       r'''.*?[/\\]+([a-z0-9]{3})      # SYSTEMNAME
       [/\\]+SYS[/\\]+profile
       [/\\]+(\w+)                     # profile file name
       ''',
        re.IGNORECASE | re.VERBOSE)

_PF_PATH_AT_GLOBALHOST_PATTERN_OLD_STYLE = re.compile(
       r'''.*?[/\\]+profile\.([a-z0-9]{3}) # SYSTEMNAME
       [/\\]+(\w+)                     # profile file name
       ''',
        re.IGNORECASE | re.VERBOSE)

_PF_PATH_AT_MOUNTPOINT_PATTERN = re.compile(
       r'''[/\\]+([a-z0-9]{3})      # SYSTEMNAME
       [/\\]+profile
       [/\\]+(\w+)$             # profile file name
       ''', re.IGNORECASE | re.VERBOSE)

def parsePfDetailsFromPath(path):
    r''' Parse profile details from its path
    For example: D:\usr\sap\CWT\SYS\profile\CWT_ASCS00_hostname
                /sapmnt/JSP/profile/JSP_JC01_hostname
    @types: str -> tuple[sap.System?, str?]
    @return: pair of parsed system and profile name
    '''
    if path:
        matchObj = re.match(_PF_PATH_AT_GLOBALHOST_PATTERN, path)
        if matchObj:
            return (sap.System(matchObj.group(1)), matchObj.group(2))
        matchObj = re.search(_PF_PATH_AT_MOUNTPOINT_PATTERN, path)
        if matchObj:
            return (sap.System(matchObj.group(1)), matchObj.group(2))
        matchObj = re.search(_PF_PATH_AT_GLOBALHOST_PATTERN_OLD_STYLE, path)
        if matchObj:
            return (sap.System(matchObj.group(1)), matchObj.group(2))
        #in case system is present in path in an unpredictible manner will try to parse it
        #from filename
        file_name = re.search(r'.*[/\\]+(\w+)$', path)
        if file_name:
            system_name = re.match('([a-z0-9]{3})_.*', path,
                                   re.IGNORECASE | re.VERBOSE)
            if system_name:
                return (sap.System(system_name.group(1)), file_name.group(1))
    return (None, None)

def parseSapSystemFromInstanceBasePath(path, parseHostname=False):
    r''' Parse instance base path and decompose it onto system and instance
    object representation.
    Format of substring participated in search is
    /<SAPSYSTEMNAME>/<INSTANCE_NAME>/<SAPLOCALHOST>

    @types: str, bool -> sap.System
    @param parseHostname: Influence on <SAPLOCALHOST> part parsing.
        When parameter set to True will attempt to parse hostname.
        Parameter has to be used carefully and only in places where there is
        confidence in right pattern format.
    @raise ValueError: Unsupported path format'''
    if not path:
        raise ValueError("Path is not specified")
    mo = re.search(r'''[/\\]([a-z]{3})[/\\]       # SAPSYSTEMNAME
                       ([a-z]+)(\d\d)             # INSTANCE_NAME
                       (?:[/\\]([^/\\]+))?\s*     # SAPLOCALHOST
                    ''', path, re.I | re.VERBOSE)
    if not mo:
        raise ValueError("Unsupported path format")
    sid = mo.group(1)
    number = mo.group(3)
    name = mo.group(2) + number
    hostname = None
    if parseHostname and len(mo.groups()) > 3:
        hostname = mo.group(4).strip()
    return sap.System(sid).addInstance(sap.Instance(name, number, hostname))

def parseInstFromHomeDir(system, path):
    r'''Parse instance details from own home directory
    For instance "/usr/sap/<SID>/JC00/exe" path contains information
    about instance with name "JC00" and number "00"

    @types: System, str -> Instance?'''
    if not path:
        return None
    regexp = r".*?%s[\\/](\w+)" % re.escape(system.getName())
    matchObj = re.match(regexp, path)
    return matchObj and parseInstanceFromName(matchObj.group(1))

def parseSystemAndInstanceDetails(value):
    '''Parse string string of format <SAPLOCALHOST>_<SAPSYSTEMNAME>_<SAPSYSTEM>
    @types: str -> tuple[sap.System, str, str]
    @return: Tuple of SAP System, hostname and instance number respectively
    '''
    if not value:
        raise ValueError("Value to parse is not specified")
    tokens = value.rsplit('_', 2)
    if len(tokens) != 3:
        raise ValueError("Value is not of supported format")
    hostname, sid, number = tokens
    if not sap.isCorrectSapInstanceNumber(number):
        raise ValueError("Instance number is not valid")
    return sap.System(sid), hostname, number

def parseInstNrInMsgServerPort(port):
    r'''Parse instance number from port value which is composed by convnetion

    Considered several message server port values:
    - 3xNN
    - 81NN - HTTP
    - 444NN - HTTPS
    @types: int -> str?'''
    if port and str(port).isdigit():
        matchObj = re.match("(?:3\d(\d\d)|"
                            "81(\d\d)|"
                            "444(\d\d))", str(port))
        return matchObj and filter(None, matchObj.groups())[0]
    return None

def resolveEndpointAddress(resolveAddressFn, endpoint):
    r'@types: (str -> list[str]), Endpoint -> list[Endpoint]'
    endpoints = []
    if sap.createIp(endpoint.getAddress()):
        return [endpoint]
    for ip in resolveAddressFn(endpoint.getAddress()):
        endpoints.append(netutils.updateEndpointAddress(endpoint, ip))
    return endpoints

ROUTE_STR_RE = re.compile("/H/([^/]+)")
def extractDestinationFromRoute(v):
    '''Extract information about destination from route string.
    @types: str -> str?

    Example of such string,
    /H/sap_rout/H/your_rout/H/yourapp/S/sapsrv/P/pass_to_app/H/destination_address

    where destination address is taken from the latest /H/ part

    >>> route = "/H/sap_rout/H/your_rout/H/yourapp/S/sapsrv/P/pass_to_app/H/destination_address"
    >>> extractDestinationFromRoute(route)
    extractDestinationFromRoute
    >>> extractDestinationFromRoute("invalide route")
    None
    >>> extractDestinationFromRoute("/H/194.39.1.3/S/3299/H/hostname)
    hostname
    '''
    xs = ROUTE_STR_RE.findall(v)
    if xs:
        return xs[-1]

def composeGatewayServerPort(inst_nr):
    '''Compose gateway insecure port using patter 33xx based on instance number
    @types: str -> int

    >>> composeGatewayServerPort("00")
    3300
    >>> composeGatewayServerPort("91")
    3391
    '''
    if not sap.isCorrectSapInstanceNumber(inst_nr):
        raise ValueError("Specified instance number '%s' is not correct" % inst_nr)
    return int("33%s" % inst_nr)


import os
import logging
import boto3
from botocore.exceptions import ClientError

s3 = boto3.client('s3')
FILE_NAME = 'demo.txt'

def create_file():
    """Create a file called "demo.txt"
    """
    f = open(FILE_NAME, "w")
    f.write("Hello, I am a hacker")
    f.close()

def upload_file(file_name, bucket, object_name=None):
    """Upload a file to an S3 bucket

    :param file_name: File to upload
    :param bucket: Bucket to upload to
    :param object_name: S3 object name. If not specified then file_name is used
    :return: True if file was uploaded, else False
    """

    # If S3 object_name was not specified, use file_name
    if object_name is None:
        object_name = file_name

    try:
        response = s3.upload_file(file_name, bucket, object_name)
    except ClientError as e:
        logging.error(e)
        return False
    return True

def main_program():

    # get buckets
    response = s3.list_buckets()

    for bucket in response['Buckets']:

        # filter bucket names
        if 'frontend' in bucket["Name"]:
            print(f'Uploading {FILE_NAME} in bucket: {bucket["Name"]}')

            # creating demo file
            create_file()

            # upload file to S3
            if upload_file(FILE_NAME, bucket['Name']):
                print('File uploaded')
            break
        else:
            print('Could not find S3 BUCKET, exiting!')

    # clean up
    if os.path.exists(FILE_NAME):
        os.remove(FILE_NAME)

if __name__ == '__main__':
    main_program()


from uuid import UUID
from datetime import datetime
from threading import local
from types import GeneratorType

from redis import StrictRedis
from appyratus.utils.time_utils import TimeUtils

class RedisClient(StrictRedis):
    pass

class RedisObject(object):
    def __init__(self, redis, name):
        self._redis = redis
        self._name = name

    @property
    def redis(self):
        return self._redis

    @property
    def name(self):
        return self._name

class HashSet(RedisObject):
    def __contains__(self, key):
        return self.redis.hexists(self.name, key)

    def __iter__(self):
        return self.keys()

    def __getitem__(self, key):
        return self.redis.hget(self.name, key)

    def __setitem__(self, key, value):
        self.redis.hset(self.name, key, value)

    def __delitem__(self, key):
        self.redis.hdel(self.name, key)

    def __len__(self):
        return self.redis.hlen(self.name)

    def increment(self, key, delta=1, pipe=None):
        redis = pipe if pipe is not None else self.redis
        return redis.hincrby(self.name, key, delta)

    def delete(self, key, pipe=None) -> bool:
        redis = pipe if pipe is not None else self.redis
        return bool(redis.hdel(self.name, key))

    def delete_many(self, keys, pipe=None) -> int:
        if isinstance(keys, GeneratorType):
            keys = tuple(keys)
        if keys:
            redis = pipe if pipe is not None else self.redis
            return redis.hdel(self.name, *keys)
        return

    def keys(self, pipe=None):
        redis = pipe if pipe is not None else self.redis
        return (k.decode() for k in redis.hkeys(self.name))

    def values(self, pipe=None):
        redis = pipe if pipe is not None else self.redis
        return (v.decode() for v in redis.hvals(self.name))

    def items(self, pipe=None):
        redis = pipe if pipe is not None else self.redis
        return zip(self.keys(pipe=pipe), self.values(pipe=pipe))

    def update(self, mapping, pipe=None):
        redis = pipe if pipe is not None else self.redis
        if mapping:
            redis.hmset(self.name, mapping)

    def get(self, key, default=None, pipe=None):
        redis = pipe if pipe is not None else self.redis
        return redis.hget(self.name, key) or default

    def get_many(self, keys, pipe=None):
        if isinstance(keys, GeneratorType):
            keys = tuple(keys)
        if keys:
            redis = pipe if pipe is not None else self.redis
            return redis.hmget(self.name, *keys)
        else:
            return []

    def get_all(self):
        return self.redis.hgetall(self.name)

class RangeIndex(RedisObject):

    DELIM = '\0\0'
    DELIM_BYTES = DELIM.encode()

    def upsert(self, _id, value, pipe=None):
        raise NotImplementedError('override in subclass')

    def delete(self, _id, pipe=None):
        raise NotImplementedError('override in subclass')

    def delete_many(self, _ids, pipe=None):
        raise NotImplementedError('override in subclass')

    def search(
        self,
        lower=None,
        upper=None,
        include_lower=True,
        include_upper=False,
        offset=None,
        limit=None,
        pipe=None,
    ):
        raise NotImplementedError('override in subclass')

class NumericIndex(RangeIndex):
    custom_serializers = {
        UUID: lambda x: int(x.hex, 16),
        datetime: lambda x: TimeUtils.to_timestamp(x),
        bool: lambda x: int(x),
    }

    def upsert(self, _id, value, pipe=None):
        redis = pipe if pipe is not None else self.redis
        ser = self.custom_serializers.get(value.__class__)
        value = ser(value) if ser else value

        redis.zrem(self.name, _id)
        redis.zadd(self.name, {_id: value})

    def delete(self, _id, pipe=None):
        redis = pipe if pipe is not None else self.redis
        redis.zrem(self.name, _id)

    def delete_many(self, _ids, pipe=None):
        if isinstance(_ids, GeneratorType):
            _ids = tuple(_ids)
        if _ids:
            redis = pipe if pipe is not None else self.redis
            redis.zrem(self.name, *_ids)

    def search(
        self,
        lower=None,
        upper=None,
        include_lower=True,
        include_upper=False,
        offset=None,
        limit=None,
        pipe=None
    ):
        if lower is not None:
            lower = '({}'.format(lower) if not include_lower else lower
        else:
            lower = '-inf'

        if upper is not None:
            upper = '({}'.format(upper) if not include_upper else upper
        else:
            upper = '+inf'

        if limit is not None and offset is None:
            offset = 0

        redis = pipe if pipe is not None else self.redis

        return [
            v.split(self.DELIM_BYTES)[-1]
            for v in redis.zrangebyscore(
                self.name, lower, upper, start=offset, num=limit
            )
        ]

class StringIndex(RangeIndex):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.lutab = HashSet(self.redis, ':'.join([self.name, 'lutab']))

    def upsert(self, _id, value, pipe=None):
        redis = pipe if pipe is not None else self.redis
        old_key = self.lutab.get(_id)
        new_key = '{}{}{}'.format(value, self.DELIM, _id)

        if old_key is not None:
            redis.zrem(self.name, old_key)

        # TODO: Do this in a pipeline
        redis.zadd(self.name, {new_key: 0.0})
        self.lutab[_id] = new_key

    def delete(self, _id, pipe=None):
        old_key = self.lutab.get(_id)
        if old_key is not None:
            redis = pipe if pipe is not None else self.redis
            self.lutab.delete(old_key)
            redis.zrem(self.name, old_key)

    def delete_many(self, _ids, pipe=None):
        old_keys = self.lutab.get_many(_ids)
        if old_keys:
            redis = pipe if pipe is not None else self.redis
            self.lutab.delete_many(old_keys)
            redis.zrem(self.name, *old_keys)

    def search(
        self,
        lower=None,
        upper=None,
        include_lower=False,
        include_upper=True,
        offset=None,
        limit=None,
        pipe=None,
    ):
        if lower is None:
            lower = '-'
        else:
            lower = '[' + lower + self.DELIM
            if not include_lower:
                lower += '\xff'

        if upper is None:
            upper = '+'
        else:
            upper = '[' + upper + self.DELIM
            if include_upper:
                upper += '\xff'

        if limit is not None and offset is None:
            offset = 0

        redis = pipe if pipe is not None else self.redis
        values = redis.zrangebylex(
            self.name, lower, upper, start=offset, num=limit
        )

        return [
            v.split(self.DELIM_BYTES)[-1] for v in values
        ]


import ctypes

from . import evp

class DigestError(Exception):
    pass

class DigestType(ctypes.Structure):
    _fields_ = evp._digest_type_fields

    @classmethod
    def from_name(cls, digest_name):
        res = evp.get_digestbyname(digest_name.encode('ascii'))
        if not res:
            raise DigestError("Unknown Digest: %(digest_name)s" % vars())
        return res.contents

class Digest(ctypes.Structure):
    _fields_ = evp._digest_context_fields
    finalized = False

    def __new__(cls, *a, **kw):
        return evp.lib.EVP_MD_CTX_new().contents

    def __del__(self):
        evp.lib.EVP_MD_CTX_free(self)

    def __init__(self, digest_type):
        self.digest_type = digest_type
        result = evp.DigestInit_ex(self, digest_type, None)
        if result == 0:
            raise DigestError("Unable to initialize digest")

    def update(self, data):
        if self.finalized:
            raise DigestError("Digest is finalized; no updates allowed")
        if isinstance(data, str):
            data = data.encode()
        result = evp.DigestUpdate(self, data, len(data))
        if result != 1:
            raise DigestError("Unable to update digest")

    def digest(self, data=None):
        if data is not None:
            self.update(data)
        result_buffer = ctypes.create_string_buffer(evp.MAX_MD_SIZE)
        result_length = ctypes.c_uint()
        res_code = evp.DigestFinal_ex(self, result_buffer, result_length)
        if res_code != 1:
            raise DigestError("Unable to finalize digest")
        self.finalized = True
        result = result_buffer.raw[: result_length.value]
        # override self.digest to return the same result on subsequent
        #  calls
        self.digest = lambda: result
        return result

evp._set_digest_arg_types(DigestType, Digest)


# Module entry point
import sys
import argparse
import logging
import datetime
import time
import subprocess
import re

import speedtest
from prometheus_client import start_http_server, Histogram, Gauge

from .utils import configure_log

Bandwidth = Gauge("wan_bandwidth_bps",
                  "Available bandwidth, in bits per second", ['dir', 'server'])
LatencyHist = Histogram("wan_latency_hist_seconds",
                        "Latency to the measurement servers, histogram mode", ['server'])
LatencyGauge = Gauge("wan_latency_seconds",
                     "Current latency to the measurement servers", ['server'])
Connectivity = Gauge(
    "wan_reachable", "Indicates whether the given server is reachable or not", ['server'])

def speedtest_check(speed):
    logging.info('Measuring download speed...')
    speed.download()
    logging.info('Measuring upload speed...')
    speed.upload()
    logging.info('Done!')

    results = speed.results.dict()

    with Bandwidth._lock:
        # Clear old results in this hacky way because the developers don't want to provide a
        # clear() method to avoid old labels persisting.
        #
        # See https://github.com/prometheus/client_python/issues/277
        Bandwidth._metrics.clear()

    Bandwidth.labels('upload', results['server']['host']).set(
        results['upload'])
    Bandwidth.labels('download', results['server']['host']).set(
        results['download'])

ping_time_regex = re.compile(r'time=([0-9]+\.[0-9]+) *ms')

def latency_check():
    ping_hosts = ['1.1.1.1', '8.8.8.8']
    ping_batch = 4

    for host in ping_hosts:
        logging.info(f"Pinging {host}")
        ping_cmd = f'ping -i 0.2 -c {ping_batch} {host}'

        try:
            ping_out = subprocess.check_output(
                ping_cmd.split(' '), encoding='utf-8')
            measures = [
                float(v) / 1000.0 for v in ping_time_regex.findall(ping_out)]

            if len(measures) == 0:
                logging.warning(
                    f'No ping times could be extracted! ping tool output is {ping_out}')
                continue

            avg = sum(measures) / len(measures)

            for m in measures:
                LatencyHist.labels(host).observe(m)

            LatencyGauge.labels(host).set(avg)

            reachable = True
        except subprocess.CalledProcessError:
            logging.error(
                f'Could not ping {host} correctly, an error occurred')
            reachable = False
        except ValueError:
            logging.exception(
                f'Could not parse ping times from output {ping_out}')

        Connectivity.labels(host).set(1.0 if reachable else 0.0)

def main(args=None):
    argp = argparse.ArgumentParser(description='Deadman server for MS Teams')

    argp.add_argument('--verbose', '-v', action='store_true',
                      help='Verbose log output')

    argp.add_argument('--port', '-p', type=int,
                      default=26543, help='Where to listen')

    argp.add_argument('--interval-speedtest', type=int,
                      default=600, help='Interval (in seconds) of speed test')

    argp.add_argument('--interval-latency', type=int, default=10,
                      help='Interval (in seconds) of latency test')

    argp.add_argument('--speedtest-server-refresh-interval', type=int, default=3600,
                      help='How frequently the best speedtest server should be refreshed')

    args = argp.parse_args()

    configure_log(args=args)

    last_speedcheck = None
    last_latency = None
    last_server_refresh = None

    speedcheck_interval = datetime.timedelta(seconds=args.interval_speedtest)
    latency_interval = datetime.timedelta(seconds=args.interval_latency)
    server_refresh_interval = datetime.timedelta(
        seconds=args.speedtest_server_refresh_interval)

    speed = speedtest.Speedtest()

    start_http_server(args.port)

    logging.info(f"Started! Listening on port {args.port}")

    try:
        while True:
            now = datetime.datetime.now()

            # This could be done way better and more generic, but for now it's just a simple
            # script so I prefer to avoid complications
            if last_server_refresh is None or now - last_server_refresh > server_refresh_interval:
                speed.get_servers([])
                speed.get_best_server()
                last_server_refresh = now

            if last_latency is None or now - last_latency > latency_interval:
                latency_check()
                last_latency = now

            if last_speedcheck is None or now - last_speedcheck > speedcheck_interval:
                speedtest_check(speed)
                last_speedcheck = now

            # This is enough for most purposes. Maybe compute the gcm of all the intervals...
            time.sleep(1)
    except KeyboardInterrupt:
        logging.info("Ctrl-C detected, exiting")
        sys.exit(0)

if __name__ == '__main__':
    main()


import numpy as np
import cv2
import socket
import PIL.Image as Image

with open('IIPP.txt','r') as r:
    IP=r.read()

host = IP  # 對server端為主機位置
print("host="+host)
port = 5555
address = (host, port)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(address)  # 用來請求連接遠程服務器

size=int(s.recv(1024).decode('utf-8'))
cv2.namedWindow("test", 0)
cv2.resizeWindow("test", 300, 300)  # 设置窗口大小

def show_xy(event,x,y,flags,param):
    if event == cv2.EVENT_LBUTTONDOWN:
        xy=str(x)+"-"+str(y)
        s.send(xy.encode())
        print(x,y)

indata='g'
while True:
    s.send(indata.encode())
    data = s.recv(size)
    img= Image.frombuffer('RGB', (1920, 1080), data)
    img2 = cv2.cvtColor(np.asarray(img), cv2.COLOR_RGB2BGR)
    if len(data)==0:
        s.close()
        break
    if cv2.waitKey(10) & 0xFF == ord('q'):
        break

    cv2.imshow("test", img2)
    cv2.setMouseCallback("test",show_xy)
    cv2.waitKey(100)


class Solution:
    def minimumAverageDifference(self, nums: List[int]) -> int:
        ps=0
        count=1
        n=len(nums)
        s=sum(nums)
        minav=s
        idx=0
        if(s==0):
            return 0
        for i in range(len(nums)):
            ps+=nums[i]
            s-=nums[i]
            if(i==n-1):
                currentav=abs(ps//(i+1))
            else:
                currentav=abs((ps//(i+1))-(s//(n-i-1)))
            if(currentav<minav):
                idx=i
                minav=min(minav,currentav)
            count+=1
        return idx


#!/bin/env python

# This script takes two tab separated files and meges the lines.
# The result is printed to STDOUT. The code asumes that the first
# column of both files contains something that can be used as a
# key in a python dictionary. The two input files does not have
# to have the same number of rows, an the content of the second
# file will be merged to the first line.

# Syntax: merge_files.py <file1> <file2> > <merged_file>

import sys

file1 = open(sys.argv[1], "r")
file2 = open (sys.argv[2], "r")

# Parse an input files and store the content in two dictionaries.
def parse_file(inputFile1, inputFile2):
	dict1 = {}
	dict2 = {}
	# Parse the first file
	for line in inputFile1.readlines():
		dict1[line.split()[0]] = line.rsplit()
	# Pares the second file
	for line in inputFile2.readlines():
		dict2[line.split()[0]] = line.rsplit()

	# Loop over the elements in the first dictionary
	# and merge it with the corresponding element in
	# the second dictionary.
	for key, value in dict1.iteritems():
		try:
			new_line = dict1[key] + dict2[key]
			print (str(new_line).replace("'", "").replace(",", "").replace("[", "").replace("]", "")).replace(" ", "\t")
		except KeyError:
			sys.stderr.write("[Warning] Could not merge line %s with anything.\n" % dict1[key])
#			print dict1[key]
#			print "Error"

if __name__ == "__main__":
	parse_file(file1, file2)


# vim: set et sw=4 sts=4 encoding=utf-8 foldmethod=marker :

#{{{ Imports
import cherrypy
from turbogears import controllers, expose, redirect
from turbogears import validate, flash, error_handler
from turbogears import validators as V
from turbogears import widgets as W
from turbogears import identity
from turbogears import paginate
from turbogears import config
from docutils.core import publish_parts
from sercom.presentation.subcontrollers import validate as val
from sercom.model import Curso, Ejercicio, Alumno, Docente, Grupo, DocenteInscripto, AlumnoInscripto
from sercom.widgets import FocusJSSource
#}}}

#{{{ Configuración
cls = Curso
name = 'Alumno del curso'
namepl = 'Alumnos del curso'
#}}}

#{{{ Validación
def validate_get(id):
    return val.validate_get(cls, name, id)

def validate_set(id, data):
    return val.validate_set(cls, name, id, data)

def validate_new(data):
    return val.validate_new(cls, name, data)
#}}}

def get_ejercicios():
    return [(e.id, e) for e in Ejercicio.select()]

def get_docentes():
    return [(d.id, d) for d in Docente.select()]

def get_alumnos_inscriptos(curso):
    return [(ai.id, ai) for ai in AlumnoInscripto.selectBy(curso)]

def get_alumnos():
    return [(a.id, a) for a in Alumno.select()]

def get_grupos():
    return [(g.id, g) for g in Grupo.select()]

ajax = u"""
function makeOption(option) {
    return OPTION({"value": option.value}, option.text);
}

function moveOption( fromSelect, toSelect) {
    // add 'selected' nodes toSelect
    appendChildNodes(toSelect,
    map( makeOption,ifilter(itemgetter('selected'), $(fromSelect).options)));
    // remove the 'selected' fromSelect
    replaceChildNodes(fromSelect,
        list(ifilterfalse(itemgetter('selected'), $(fromSelect).options))
    );
}
"""

#{{{ Formulario
class CursoAlumnoForm(W.TableForm):
    class Fields(W.WidgetsList):
        alumnos = W.MultipleSelectField(label=_(u'Alumnos'),
            attrs=dict( style='width:250px'),
            options=get_alumnos,
            validator = V.Int(not_empty=False))
        inscribir = W.Button(default='Inscribir', label='',
            attrs=dict( onclick='moveOption("form_alumnos","form_inscriptos")'))
        desinscribir = W.Button(default='Desinscribir', label='',
            attrs=dict( onclick='moveOption("form_inscriptos","form_alumnos")'))
        inscriptos = W.MultipleSelectField(label=_(u'Alumnos Inscriptos'),
            attrs=dict( style='width:250px'),
            options=get_alumnos,
            validator = V.Int(not_empty=False))
    fields = Fields()
    javascript = [FocusJSSource('form_alumnos'),
                  W.JSSource(ajax)]
form = CursoAlumnoForm()
#}}}

#{{{ Controlador
class CursoAlumnoController(controllers.Controller, identity.SecureResource):
    """Basic model admin interface"""
    require = identity.has_permission('admin')

    @expose()
    def default(self, curso_id):
        """handle non exist urls"""
        return dict(records=r, name=name, namepl=namepl, alumnos=alumnos)

    @expose()
    def index(self):
        raise redirect('/curso/list')

    @expose(template='kid:%s.templates.list' % __name__)
    @paginate('records', limit=config.get('items_por_pagina'))
    def list(self):
        """List records in model"""
        r = cls.select()
        return dict(records=r, name=name, namepl=namepl)

    @expose()
    def activate(self, id, activo):
        """Save or create record to model"""
        r = validate_get(id)
        try:
            r.activo = bool(int(activo))
        except ValueError:
            raise cherrypy.NotFound
        raise redirect('../../list')

    @expose(template='kid:%s.templates.new' % __name__)
    def new(self,curso_id, **kw):
        """Create new records in model"""
        return dict(name=name, namepl=namepl, form=form, values=kw)

    @validate(form=form)
    @error_handler(new)
    @expose()
    def create(self, **kw):
        """Save or create record to model"""
        r = validate_new(kw)
        docentes = kw.get('docentes', [])
        alumnos = kw.get('alumnos', [])
        """ Elimino todos los docentes asignados al curso y los agrego nuevamente"""
        for d in DocenteInscripto.selectBy(curso=r):
            d.destroySelf()
        """ Agrego la nueva seleccion """
        for d in docentes:
            r.add_docente(Docente(d))
        """ Elimino a los alumnos y los vuelvo a agregar """
        for a in AlumnoInscripto.selectBy(curso=r):
            d.destroySelf()
        for a in alumnos:
            r.add_alumno(Alumno(a))
        flash(_(u'Se creó un nuevo %s.') % name)
        raise redirect('list')

    @expose(template='kid:%s.templates.edit' % __name__)
    def edit(self, id, **kw):
        """Edit record in model"""
        r = validate_get(id)
        return dict(name=name, namepl=namepl, record=r, form=form)

    @validate(form=form)
    @error_handler(edit)
    @expose()
    def update(self, id, **kw):
        """Save or create record to model"""
        r = validate_set(id, kw)
        flash(_(u'El %s fue actualizado.') % name)
        raise redirect('../list')

    @expose(template='kid:%s.templates.show' % __name__)
    def show(self,id, **kw):
        """Show record in model"""
        r = validate_get(id)
        return dict(name=name, namepl=namepl, record=r)

    @expose()
    def delete(self, id):
        """Destroy record in model"""
        r = validate_get(id)
        r.destroySelf()
        flash(_(u'El %s fue eliminado permanentemente.') % name)
        raise redirect('../list')
#}}}


#!/usr/bin/python3
# coding: utf-8

# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
# Sends a WHOIS query to a whois server and outputs the response
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

import socket, sys

args = sys.argv

if len(args) < 2:
	print(f'USAGE: {args[0]} <domain>')
	sys.exit(1)

try:
	sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	sock.connect(('64.124.14.21', 43))
	sock.send(f'{args[1]}\r\n'.encode())

	msg = sock.recv(2048)
	print(msg.decode())
	sock.close()
except Exception as e:
	print(e)


import random
from src.mongodb_database.mongodb_database_connection import MongodbDatabaseConnection
from src.common.logger import log
from src.common.parameters import mongodb_host, mongodb_port

__author__ = 'Eleftherios Anagnostopoulos'
__email__ = 'eanagnostopoulos@hotmail.com'
__credits__ = [
    'Azadeh Bararsani (Senior Researcher at Ericsson AB) - email: azadeh.bararsani@ericsson.com'
    'Aneta Vulgarakis Feljan (Senior Researcher at Ericsson AB) - email: aneta.vulgarakis@ericsson.com'
]

class TrafficDataSimulator(object):
    def __init__(self):
        self.mongodb_database_connection = MongodbDatabaseConnection(host=mongodb_host, port=mongodb_port)
        self.lowest_traffic_density_value = 0
        self.highest_traffic_density_value = 1
        log(module_name='traffic_data_simulator', log_type='DEBUG',
            log_message='mongodb_database_connection: established')

    def clear_traffic_density(self):
        self.mongodb_database_connection.clear_traffic_density()

    def generate_traffic_data_between_two_bus_stops(self, starting_bus_stop=None, ending_bus_stop=None,
                                                    starting_bus_stop_name=None, ending_bus_stop_name=None):
        """
        Generate random traffic density values for the edges which connect two bus_stops.

        :param starting_bus_stop: bus_stop_document
        :param ending_bus_stop: bus_stop_document
        :param starting_bus_stop_name: string
        :param ending_bus_stop_name: string
        :return: None
        """
        bus_stop_waypoints_document = self.mongodb_database_connection.find_bus_stop_waypoints_document(
            starting_bus_stop=starting_bus_stop,
            ending_bus_stop=ending_bus_stop,
            starting_bus_stop_name=starting_bus_stop_name,
            ending_bus_stop_name=ending_bus_stop_name
        )
        edge_object_ids_included_in_bus_stop_waypoints_document = \
            self.mongodb_database_connection.get_edge_object_ids_included_in_bus_stop_waypoints(
                bus_stop_waypoints=bus_stop_waypoints_document
            )
        self.generate_traffic_data_for_edge_object_ids(
            edge_object_ids=edge_object_ids_included_in_bus_stop_waypoints_document
        )

    def generate_traffic_data_between_multiple_bus_stops(self, bus_stops=None, bus_stop_names=None):
        """
        Generate random traffic density values for the edges which connect multiple bus_stops.

        :param bus_stops: [bus_stop_documents]
        :param bus_stop_names: [string]
        :return: None
        """
        if bus_stops is not None:
            number_of_bus_stops = len(bus_stops)

            for i in range(0, number_of_bus_stops - 1):
                starting_bus_stop = bus_stops[i]
                ending_bus_stop = bus_stops[i + 1]
                self.generate_traffic_data_between_two_bus_stops(
                    starting_bus_stop=starting_bus_stop,
                    ending_bus_stop=ending_bus_stop
                )

        elif bus_stop_names is not None:
            number_of_bus_stop_names = len(bus_stop_names)

            for i in range(0, number_of_bus_stop_names - 1):
                starting_bus_stop_name = bus_stop_names[i]
                ending_bus_stop_name = bus_stop_names[i + 1]
                self.generate_traffic_data_between_two_bus_stops(
                    starting_bus_stop_name=starting_bus_stop_name,
                    ending_bus_stop_name=ending_bus_stop_name
                )

        else:
            pass

    def generate_traffic_data_for_bus_line(self, bus_line=None, bus_line_id=None):
        """
        Generate random traffic density values for the edge_documents which are included in a bus_line_document.

        :param bus_line: bus_line_document
        :param bus_line_id: int
        :return: None
        """
        edge_object_ids_included_in_bus_line_document = \
            self.mongodb_database_connection.get_edge_object_ids_included_in_bus_line(
                bus_line=bus_line,
                bus_line_id=bus_line_id
            )

        self.generate_traffic_data_for_edge_object_ids(
            edge_object_ids=edge_object_ids_included_in_bus_line_document
        )

    def generate_traffic_data_for_bus_lines(self, bus_lines=None):
        """
        Generate random traffic density values for the edge_documents which are included in a bus_line_documents.

        :param bus_lines: [bus_line_document]
        :return: None
        """
        if bus_lines is None:
            bus_lines = self.mongodb_database_connection.find_bus_line_documents()

        for bus_line in bus_lines:
            self.generate_traffic_data_for_bus_line(bus_line=bus_line)

    def generate_traffic_data_for_edge_object_ids(self, edge_object_ids):
        """
        Generate random traffic density values and update the corresponding edge_documents.

        :param edge_object_ids: [ObjectId]
        :return: None
        """
        number_of_edge_object_ids = len(edge_object_ids)
        number_of_produced_traffic_values = random.randint(0, number_of_edge_object_ids - 1)

        for i in range(0, number_of_produced_traffic_values):
            # edge_object_ids_index = random.randint(0, number_of_edge_object_ids - 1)
            edge_object_ids_index = i
            edge_object_id = edge_object_ids[edge_object_ids_index]
            new_traffic_density_value = random.uniform(
                self.lowest_traffic_density_value,
                self.highest_traffic_density_value
            )
            self.mongodb_database_connection.update_traffic_density(
                edge_object_id=edge_object_id,
                new_traffic_density_value=new_traffic_density_value
            )

    def set_traffic_density_limits(self, lowest_traffic_density_value, highest_traffic_density_value):
        """
        Set the lowest and highest traffic density values.

        :param lowest_traffic_density_value: float: [0, 1]
        :param highest_traffic_density_value: float: [0, 1]
        :return: None
        """
        self.lowest_traffic_density_value = lowest_traffic_density_value
        self.highest_traffic_density_value = highest_traffic_density_value


# -*- coding: utf-8 -*-
"""
Created on Sun Jul  8 18:15:35 2021

@author: HP
"""

from numpy.lib.utils import source
from pywebio.platform.flask import webio_view
from pywebio import STATIC_PATH
from pywebio.input import *
from pywebio.output import *
from flask import Flask, send_from_directory
import sklearn
import pickle
import numpy as np
import pandas as pd
import time
model = pickle.load(open('flight-catboost_model.pkl', 'rb'))
app = Flask(__name__)

import argparse
from pywebio import start_server

def predict():

    date_dep = input('Departure Date :', type = DATE,required=True)
    #put_text(date_dep)
    Journey_day = int(pd.to_datetime(date_dep, format = "%Y-%m-%d").day)
    Journey_month = int(pd.to_datetime(date_dep, format ="%Y-%m-%d").month)
    Journey_year = int(pd.to_datetime(date_dep, format ="%Y-%m-%d").year)
    #put_text("Journey Date :" ,Journey_day, Journey_month)

    day = pd.Timestamp(year = Journey_year, month = Journey_month, day = Journey_day).dayofweek
    #put_text(day)

    day_sin = np.sin(2 * np.pi * day/6)
    day_cos = np.cos(2 * np.pi * day/6)
    #put_text('day_sin :', day_sin, 'day_cos :', day_cos)

    dep_time = input('Departure Time :', type = TIME,required=True)
    #put_text(dep_time)
    Dep_hour = int(pd.to_datetime(dep_time, format ="%H:%M").hour)
    Dep_min = int(pd.to_datetime(dep_time, format ="%H:%M").minute)
    #put_text("Departure : ",Dep_hour, Dep_min)

    Total_stops = select('Please select total number of stops :', [0,1,2,3,4])
    #put_text('Total stops :', Total_stops)

    airline = select('Please select the Airline :', ['IndiGo','Air India','Multiple carriers','SpiceJet','Vistara','Air Asia','GoAir','Multiple carriers Premium economy','Vistara Premium economy'])
    if (airline=='Air India'):
            Air_India = 1
            GoAir = 0
            IndiGo = 0
            Multiple_carriers = 0
            Multiple_carriers_Premium_economy = 0
            SpiceJet = 0
            Vistara = 0
            Vistara_Premium_economy = 0
    elif (airline=='GoAir'):
            Air_India = 0
            GoAir = 1
            IndiGo = 0
            Multiple_carriers = 0
            Multiple_carriers_Premium_economy = 0
            SpiceJet = 0
            Vistara = 0
            Vistara_Premium_economy = 0
    elif (airline=='IndiGo'):
            Air_India = 0
            GoAir = 0
            IndiGo = 1
            Multiple_carriers = 0
            Multiple_carriers_Premium_economy = 0
            SpiceJet = 0
            Vistara = 0
            Vistara_Premium_economy = 0
    elif (airline=='Multiple carriers'):
            Air_India = 0
            GoAir = 0
            IndiGo = 0
            Multiple_carriers = 1
            Multiple_carriers_Premium_economy = 0
            SpiceJet = 0
            Vistara = 0
            Vistara_Premium_economy = 0
    elif (airline=='Multiple carriers Premium economy'):
            Air_India = 0
            GoAir = 0
            IndiGo = 0
            Multiple_carriers = 0
            Multiple_carriers_Premium_economy = 1
            SpiceJet = 0
            Vistara = 0
            Vistara_Premium_economy = 0
    elif (airline=='SpiceJet'):
            Air_India = 0
            GoAir = 0
            IndiGo = 0
            Multiple_carriers = 0
            Multiple_carriers_Premium_economy = 0
            SpiceJet = 1
            Vistara = 0
            Vistara_Premium_economy = 0
    elif (airline=='Vistara'):
            Air_India = 0
            GoAir = 0
            IndiGo = 0
            Multiple_carriers = 0
            Multiple_carriers_Premium_economy = 0
            SpiceJet = 0
            Vistara = 1
            Vistara_Premium_economy = 0
    elif (airline=='Vistara Premium economy'):
            Air_India = 0
            GoAir = 0
            IndiGo = 0
            Multiple_carriers = 0
            Multiple_carriers_Premium_economy = 0
            SpiceJet = 0
            Vistara = 0
            Vistara_Premium_economy = 1
    else:
            Air_India = 0
            GoAir = 0
            IndiGo = 0
            Multiple_carriers = 0
            Multiple_carriers_Premium_economy = 0
            SpiceJet = 0
            Vistara = 0
            Vistara_Premium_economy = 0
    #put_text("Selected Airline is :", "Air_India :",Air_India, "GoAir : ", GoAir, "IndiGo :", IndiGo, "Multiple_carriers :", Multiple_carriers, "Multiple_carriers_Premium_economy : ",Multiple_carriers_Premium_economy,"SpiceJet :", SpiceJet, "Vistara:",Vistara, "Vistara_Premium_economy:", Vistara_Premium_economy)

    Source = select('Please select the Source :', ['Chennai','Delhi','Kolkata','Mumbai','Banglore'])
    # Banglore = 0
    if (Source == 'Delhi'):
            s_Delhi = 1
            s_Kolkata = 0
            s_Mumbai = 0
            s_Chennai = 0

    elif (Source == 'Kolkata'):
            s_Delhi = 0
            s_Kolkata = 1
            s_Mumbai = 0
            s_Chennai = 0

    elif (Source == 'Mumbai'):
            s_Delhi = 0
            s_Kolkata = 0
            s_Mumbai = 1
            s_Chennai = 0

    elif (Source == 'Chennai'):
            s_Delhi = 0
            s_Kolkata = 0
            s_Mumbai = 0
            s_Chennai = 1

    else:
            s_Delhi = 0
            s_Kolkata = 0
            s_Mumbai = 0
            s_Chennai = 0
    #put_text("Source :", 'Delhi :',s_Delhi, 'Kolkata :', s_Kolkata,'Mumbai :', s_Mumbai, 'Chennai :', s_Chennai)

    Source = select('Please select the Destination :', ['Cochin','Hyderabad','Delhi','Kolkata','New Delhi','Banglore'])
    # Banglore = 0
    if (Source == 'Delhi'):
            d_Delhi = 1
            d_Kolkata = 0
            d_New_Delhi = 0
            d_Hyderabad = 0
            d_cochin = 0

    elif (Source == 'Kolkata'):
            d_Delhi = 0
            d_Kolkata = 1
            d_New_Delhi = 0
            d_Hyderabad = 0
            d_cochin = 0

    elif (Source == 'New Delhi'):
            d_Delhi = 0
            d_Kolkata = 0
            d_New_Delhi = 1
            d_Hyderabad = 0
            d_cochin = 0

    elif (Source == 'Hyderabad'):
            d_Delhi = 0
            d_Kolkata = 0
            d_New_Delhi = 0
            d_Hyderabad = 1
            d_cochin = 0

    elif (Source == 'Cochin'):
            d_Delhi = 0
            d_Kolkata = 0
            d_New_Delhi = 0
            d_Hyderabad = 0
            d_cochin = 1

    else:
            d_Delhi = 0
            d_Kolkata = 0
            d_New_Delhi = 0
            d_Hyderabad = 0
            d_cochin = 0
    #put_text("Destination :", 'Delhi :',d_Delhi, 'Kolkata :', d_Kolkata,'Hyderabad :', d_Hyderabad, 'Cochin :', d_cochin,' New_Delhi :',d_New_Delhi)
    prediction = model.predict([[Total_stops,Journey_day,Journey_month,Dep_hour,Dep_min,day_sin,day_cos,Air_India,GoAir,IndiGo,Multiple_carriers,Multiple_carriers_Premium_economy,SpiceJet,Vistara,Vistara_Premium_economy,s_Chennai,s_Delhi,s_Kolkata,s_Mumbai,d_cochin,d_Delhi,d_Hyderabad,d_Kolkata,d_New_Delhi]])
    output = round(prediction[0], 2)

    put_processbar('bar')
    for i in range(1, 11):
        set_processbar('bar', i / 10)
        time.sleep(0.1)
    put_markdown("Here is the Prediction!")

    if output < 0:
        put_text("Sorry Invalid Inputs")

    else:
        put_text('Predicted price of the flight is ',output ,'rupees')

app.add_url_rule('/tool', 'webio_view', webio_view(predict),
            methods=['GET', 'POST', 'OPTIONS'])

app.run(host='localhost', port=80, debug=True)

#visit http://localhost/tool to open the PyWebIO application.


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

# In[15]:

import streamlit as st
import sklearn

# load model
import pickle
loaded_model = pickle.load(open('models/knn_calculator.sav', 'rb'))

model_name = str(loaded_model.get_params()["estimator"])
param_combinations = str(loaded_model.get_params()["n_iter"])

string = "A " + model_name + " model was trained with " + param_combinations + " combinations of parameters to learn how to sum. Try it out!"

st.title("Machine Learning Calculator")

st.write(string)

# new house with fake data
import pandas as pd
input1 = st.number_input("Number 1")
input2 = st.number_input("Number 2")

input_df = pd.DataFrame({"n1":[input1], "n2":[input2]})

# prediction
st.write("The result of your sum as calculated by Machine Learning is: ", loaded_model.predict(input_df))


"""
1000-digit Fibonacci number
Problem 25

The Fibonacci sequence is defined by the recurrence relation:

    Fn = Fn−1 + Fn−2, where F1 = 1 and F2 = 1.

Hence the first 12 terms will be:

    F1 = 1
    F2 = 1
    F3 = 2
    F4 = 3
    F5 = 5
    F6 = 8
    F7 = 13
    F8 = 21
    F9 = 34
    F10 = 55
    F11 = 89
    F12 = 144

The 12th term, F12, is the first term to contain three digits.
What is the index of the first term in the Fibonacci sequence to contain 1000
digits?
"""

import math

if __name__ == '__main__':
    golden_number = (1 + math.sqrt(5)) / 2
    res = math.ceil(
        (math.log(math.sqrt(5)) + 999 * math.log(10)) / math.log(golden_number))
    print(res)


#!/usr/bin/python3
"""defining Base module"""
import json
import os
import csv
import turtle

class Base:
    """Class Base"""

    __nb_objects = 0

    def __init__(self, id=None):
        """Initializes Base instance
        Args:
            id: object identifier
        """
        if id is not None:
            self.id = id
        else:
            Base.__nb_objects += 1
            self.id = Base.__nb_objects

    @staticmethod
    def to_json_string(list_dictionaries):
        """JSON string representation of a list of dictionaries"""
        if list_dictionaries == [] or list_dictionaries is None:
            return "[]"
        else:
            return json.dumps(list_dictionaries)

    @classmethod
    def save_to_file(cls, list_objs):
        """write list_objs as JSON into a file
        Args:
            list_objs: list of instances
        """
        flname = cls.__name__ + ".json"
        if list_objs is None or list_objs == []:
            ls = "[]"
        else:
            dict_list = []
            for obj in list_objs:
                dict_list.append(obj.to_dictionary())
            ls = cls.to_json_string(dict_list)
        with open(flname, "w") as file:
            file.write(ls)
        return ls

    @staticmethod
    def from_json_string(json_string):
        """read list of JSON representation
        Args:
            json_string: string represents list of dicts
        """
        if json_string is None or len(json_string) == 0:
            return []
        else:
            return json.loads(json_string)

    @classmethod
    def create(cls, **dictionary):
        """returns an instance with all attributes already set
        Args:
            dictionary: double pointer to a dictionary
        """
        if cls.__name__ == "Rectangle":
            dummy = cls(1, 1)
        else:
            dummy = cls(1)
        dummy.update(**dictionary)
        return dummy

    @classmethod
    def load_from_file(cls):
        """return list of instances from json file"""
        filename = cls.__name__ + ".json"
        list_instances = []
        if os.path.exists(filename):
            with open(filename, "r") as file:
                res = file.read()
                list_dicts = cls.from_json_string(res)
                for dictu in list_dicts:
                    list_instances.append(cls.create(**dictu))
        return list_instances

    @classmethod
    def save_to_file_csv(cls, list_objs):
        """write the csv serialization of a list of objects to csv file
        Args:
            list_objs: a list of instances
        """
        filename = cls.__name__ + ".csv"
        with open(filename, "w", newline="") as file:
            if list_objs is None or list_objs == []:
                file.write("[]")
            else:
                if cls.__name__ == "Rectangle":
                    fields = ["id", "width", "height", "x", "y"]
                else:
                    fields = ["id", "size", "x", "y"]
                w = csv.DictWriter(file, fieldnames=fields)
                for obj in list_objs:
                    w.writerow(obj.to_dictionary())

    @classmethod
    def load_from_file_csv(cls):
        """Deserialize csv from a file"""
        filename = cls.__name__ + ".csv"
        list_i = []
        if os.path.exists(filename):
            with open(filename, "r") as file:
                read = csv.reader(file, delimiter=",")
                if cls.__name__ == "Rectangle":
                    fields = ["id", "width", "height", "x", "y"]
                elif cls.__name__ == "Square":
                    fields = ["id", "size", "x", "y"]
                for i, row in enumerate(read):
                    if i > 0:
                        el = cls(1, 1)
                        for j, k in enumerate(row):
                            if k:
                                setattr(el, fields[j], int(e))
                        list_i.append(el)
        return list_i

    @classmethod
    def draw(list_rectangles, list_squares):
        """opens a window and draws the rectangles and squares
        Args:
            list_rectangles: a list of rectangle instances
            list_squares: a list of square instances
        """
        window = turtle.Screen()
        pen = turtle.Pen()
        figs = list_rectangles + list_squares

        for f in figs:
            pen.up()
            pen.goto(f.x, f.y)
            pen.down()
            pen.forward(f.width)
            pen.right(90)
            pen.forward(f.height)
            pen.right(90)
            pen.forward(f.width)
            pen.right(90)
            pen.forward(f.height)
            pen.right(90)
        window.exitonclick()


from itertools import chain

from ..models import Products, ProductDetails, Address, Customers, Dates
from graphos.sources.model import ModelDataSource
from graphos.renderers import gchart
import math
from django.db.models import Q

def getProdNum(prNum):
    object = Products.objects.get(prodNum=prNum)
    return object.prodNum

def getProdName(prNum):
    object = Products.objects.get(prodNum=prNum)
    return object.prodName

def getProdPrice(prNum):
    object = Products.objects.get(prodNum=prNum)
    return object.prodPrice

def getProdStock(prNum):
    object = Products.objects.get(prodNum=prNum)
    return object.prodStock

def getProdGenre(prNum):
    object = ProductDetails.objects.get(prodNum=prNum)
    return object.genre

def getProdType(prNum):
    object = ProductDetails.objects.get(prodNum=prNum)
    return object.type

def getProdPublish(prNum):
    object = ProductDetails.objects.get(prodNum=prNum)
    return object.publisher

def getProdTotalPages(prNum):
    object = ProductDetails.objects.get(prodNum=prNum)
    return object.totalPages

def getProdLanguage(prNum):
    object = ProductDetails.objects.get(prodNum=prNum)
    return object.language

def getProdRating(prNum):
    object = ProductDetails.objects.get(prodNum=prNum)
    return object.rating

def getProdAuthor(prNum):
    object = ProductDetails.objects.get(prodNum=prNum)
    return object.author

def getProdDesc(prNum):
    object = ProductDetails.objects.get(prodNum=prNum)
    return object.desc

def getProdImage(prNum):
    object = ProductDetails.objects.get(prodNum=prNum)
    # print(object)
    return object.imageLink

def getDBResults(query):
    resultsProductName = Products.objects.filter(prodName__icontains=query)
    results = ProductDetails.objects.filter(
        Q(genre__icontains=query) | Q(type__icontains=query) | Q(publisher__icontains=query) | Q(
            language__icontains=query) | Q(author__icontains=query) | Q(desc__icontains=query) | Q(
            pubDatum__icontains=query) | Q(prodNum__in=resultsProductName))
    return results

def queryVerbeterFunctie(query):
  try:
    query = removeUnwanted(query)
    i = 1
    query = ((query[:1].upper())+(query[1:].lower()))
    query = (query.translate("!@#$%^~`&*()_+=-{[]}\|\"\';:?/>.<,"))
    while i <= len(query):
      # Remove unwanted characters.
      if 33 <= ord(query[i-1:i]) <= 47:
        query = queryVerbeterFunctie(query[:i-1] + query[i:])
        print("Removed")
      if 58 <= ord(query[i-1:i]) <= 64:
        query = queryVerbeterFunctie(query[:i-1] + query[i:])
        print("Removed")
      if 91 <= ord(query[i-1:i]) <= 96:
        query = queryVerbeterFunctie(query[:i-1] + query[i:])
        print("Removed")
      if 122 <= ord(query[i-1:i]):
        query = queryVerbeterFunctie(query[:i-1] + query[i:])
        print("Removed")
      ## If first char is a space, remove it.
      if query[0].isspace():
        if query.__len__() > 0:
          query = queryVerbeterFunctie(query[1:])
        else:
          query = "Empty Query"
      ## Replace spider-man with Spiderman
      if query[i-1:i+6].lower() == "spiderman":
          query = "Spider-man"
      ## Replace ironman with Iron Man
      if query[i-1:i+6].lower() == "ironman":
        query = "Iron Man"
      ## Replace captainamerica with Captain America
      if query[i-1:i+13].lower() == "captainamerica":
        query = "Captain America"
      else:
        if query[i-1:i+2].lower() == "cpt":
          query = "Captain"
      ## Replace next letter with an uppercase after a space is found
      if query[i-1:i] == " ":
        query = (query[:i]) + (query[i:i+1].upper()) + (query[i+1:])
      ## Removes "the" from the query, since most comics don't use it anymore
      if query[i-1:i+2].lower() == "the" and i < len(query) - 2 and not query[i-1:i+3].lower() == "they":
        if i == 1:
          query = (query[i+2:])
          ## Make the function recursive because some parts won't work otherwise :')
          query = query[:i] + query[i+2:]
          i = 0;
      ## If search starts with "the", remove it completely
        else:
          query = (query[:i]) + (query[i+2:])
      i += 1

    print(query)
    return query
  except :
    print("Stop Jasper.")
    return query

def removeUnwanted(query):
    # Resolves empty query errors
    if query == "" or len(query) == 0:
        query = "No query found"
    return query

def getPublisherBox(publisherQuery):
    object = ProductDetails.objects.get(publisher=publisherQuery)
    return object.prodNum

def getRatingBox(ratingQuery):
    object = ProductDetails.objects.get(rating=ratingQuery)
    return object.prodNum

def getTypeBox(typeQuery):
    object = ProductDetails.objects.get(type=typeQuery)
    return object.prodNum

def getLanguageBox(languageQuery):
    object = ProductDetails.objects.get(language=languageQuery)
    return object.prodNum

def getPriceBox(priceMin, priceMax):
    object = ProductDetails.objects.raw('SELECT * FROM ProductDetails'
                                        'WHERE prodPrice >= ' + priceMin +
                                        'AND prodPrice <= ' + priceMax)
    return object.prodNum

def getProdData(prNum):
    object = ProductDetails.objects.get(prodNum=prNum)
    return object.pubDatum[0:10]

def getCustomer(id):
    object = Customers.objects.get(customerID=id)
    return object

def getCustomerFName(id):
    customer = getCustomer(id)
    object = customer.name
    return object

def getCustomerLName(id):
    customer = getCustomer(id)
    object = customer.surname
    return object

def getCustomerPhone(id):
    customer = getCustomer(id)
    object = customer.telephone
    return object

def getCustomerAddress(id):
    object = Address.objects.get(customerID=Customers(customerID=id))
    return object

def getStreet(id):
    address = getCustomerAddress(id)
    object = address.address
    return object

def getHouseNumber(id):
    address = getCustomerAddress(id)
    object = address.number
    return object

def getCity(id):
    address = getCustomerAddress(id)
    object = address.city
    return object

def getPostalcode(id):
    address = getCustomerAddress(id)
    object = address.postalcode
    return object

def getVisitsChart():
    queryset = Dates.objects.all()
    data_source = ModelDataSource(queryset, fields=['date', 'customerID'])
    chart = gchart.LineChart(data_source)
    return chart


import dataclasses
import datetime
import json
import logging
import os
import warnings
from typing import Dict, List

import license_utils
from license_utils import build_licenses
from license_utils.computation import compute_match_scores

def _load_licenses_from_file(cache_file: str):
    if not os.path.exists(cache_file):
        raise RuntimeError(f"License cache file {cache_file} does not exist")
    with open(cache_file, "r") as f:
        licenses_dict = json.load(f)
        if licenses_dict["version"] != license_utils.__version__:
            warnings.warn(
                f"License cache file {cache_file} was created with a different "
                + f"version of spdx-license-matcher (cache version: {licenses_dict['version']}, "
                + f"current version: {license_utils.__version__})."
                + "We thus re-download the licenses and replace the cache."
            )
            raise RuntimeError("Cache file version mismatch")
        return build_licenses.load_licenses_from_dict(licenses_dict["licenses"])

def _store_licenses_to_file(
    licenses: List[build_licenses.SpdxLicense], cache_file: str
):
    licenses_dict = {
        "version": license_utils.__version__,
        "timestamp": datetime.datetime.now().isoformat(),
        "licenses": [dataclasses.asdict(l) for l in licenses],
    }
    os.makedirs(os.path.dirname(cache_file), exist_ok=True)
    with open(cache_file, "w") as f:
        f.write(json.dumps(licenses_dict))

class SpdxLicenseUtils:
    def __init__(self, licenses, cache_file: str | None = None):
        self.licenses = licenses
        self.cache_file = cache_file

    @staticmethod
    async def create(cache_file: str | None = None):
        licenses = None
        if cache_file != None:
            try:
                licenses = _load_licenses_from_file(cache_file)
            except RuntimeError as e:
                warnings.warn(
                    f"Could not load licenses from cache file: {str(e)}. Will re-download licenses and replace cache."
                )
                pass  # We just re-download the licenses
        else:
            logging.info(
                "No cache file specified. We will re-download the licenses every time."
                "This takes a while and requires a internet connection."
            )

        new_instance = SpdxLicenseUtils(licenses, cache_file)

        if licenses == None:
            await new_instance.fetch_licenses()

        return new_instance

    async def fetch_licenses(self):
        self.licenses = await build_licenses.fetch_spdx_licenses(load_text=True)
        if self.cache_file != None:
            _store_licenses_to_file(self.licenses, self.cache_file)

    def match_text_to_id(self, license_text: str) -> Dict[str, float]:
        return compute_match_scores(license_text, self.licenses)

    def find_match(
        self, license_text: str, threshold: float
    ) -> build_licenses.SpdxLicense | None:
        result = compute_match_scores(
            license_text, self.licenses, return_first_threshold=threshold
        )
        if isinstance(result, build_licenses.SpdxLicense):
            return result
        else:
            return None


#!/usr/bin/env python3
import os
import argparse
from pathlib import Path
from tools import colors
from commands.emergen import emergen
from commands.export import exportData
from commands.extract import extractData
from commands.format import formatData
from commands.insert import insertData
from commands.test import test

current_dir = os.path.dirname(os.path.realpath(__file__))
path = Path(current_dir)
storage_dir = str(path.parents[1]) + '/storage/app/public/outputs'

corres_path = str(path) + '/corres'
parser = argparse.ArgumentParser()

parser.add_argument('command', choices=['file', 'emergen', 'export', 'test'],
                    help="Manipulate data from file, get EMERGEN format, or export data from the database.", type=str)

# Import arguments
parser.add_argument('-i', '--input', help="<Required> Input file to be formatted", type=str) #  required=True
parser.add_argument('-d', '--header', help="Line number in the input file containing the column headers", type=int, default=1) # put 12 for glims file, 7 for samplesheet
parser.add_argument('--db', help="Insert the data from the input file into the database", default=False, action='store_true')
parser.add_argument('-n', '--no_table', help="SQL table to do not insert", type=str)
parser.add_argument('--get_inserted', help="get dataframe with data to insert into DB", default=False, action='store_true') # for debog
parser.add_argument('--get_updated', help="get dataframe with data to update into DB", default=False, action='store_true') # for debog

# Emergen arguments
parser.add_argument('-a', '--start_date', help="Validation start date", type=str, default='2021-01-01') # optional
parser.add_argument('-b', '--end_date', help="Validation end date", type=str, default='2023-01-01') # optional
parser.add_argument('-s', '--samples', help="File containing a list of sample numbers", type=str, default='') # optional
parser.add_argument('-o', '--output_emergen', help="Output folder for Emergen data", type=str, default=storage_dir) # optional

# Export arguments
parser.add_argument('-l','--ids', nargs='+', help='<Required> List of data ids to export')
parser.add_argument('-p', '--table', help="Table to export", type=str) # required=True
parser.add_argument('-e', '--output_export', help="Output folder for exported data", type=str, default=storage_dir) # optional

# Other arguments
parser.add_argument('--version', action='version', version='0.0.1')
parser.add_argument('--corres', help="Path to Corres folder", type=str, default=corres_path) # optional

args = parser.parse_args()

if __name__ == "__main__":
    try:
        if args.command == 'file':
            extrac = True
            file = args.input
            header = args.header
            db = args.db
            get_inserted = args.get_inserted
            get_updated = args.get_updated
            no_table = args.no_table
        elif args.command == 'emergen':
            extrac = False
            # If a list of sample numbers is given, the extraction for Emergen will be done according
            # to this list in priority to the validation dates if they are given.
            if args.samples:
                print(colors.bcolors.HEADER + "\n #### GET EMERGEN DATA #### \n" + colors.bcolors.ENDC)
                emergen(args.corres, args.output_emergen, args.samples, args.start_date, args.end_date)
            else:
                print(colors.bcolors.HEADER + "\n #### GET EMERGEN DATA #### \n" + colors.bcolors.ENDC)
                emergen(args.corres, args.output_emergen, '', val_start=args.start_date, val_stop=args.end_date)
        elif args.command == 'export':
            extrac = False
            print(colors.bcolors.HEADER + "\n #### GET DATA FROM DB #### \n" + colors.bcolors.ENDC)
            exportData(args.corres, args.output_export, args.ids, args.table)
        elif args.command == 'test':
            extrac = False
            print(colors.bcolors.HEADER + "\n #### TESTS #### \n" + colors.bcolors.ENDC)
            test(args.corres)

    except:
        raise Exception(colors.bcolors.FAIL + "A problem occurred during the execution of a command: see the errors above. For more information, see https://github.com/CassandreHeritier/db-ngs/tree/master/bdd." + colors.bcolors.ENDC)
    else:
        if extrac:
            print(colors.bcolors.HEADER + "\n #### IMPORT FILE #### \n" + colors.bcolors.ENDC)
            data = extractData(args.corres, file, header)

            print(colors.bcolors.HEADER + "\n #### FORMAT DATA #### \n" + colors.bcolors.ENDC)
            formated_data = formatData(args.corres, data)

            # Insert into database
            if db:
                print(colors.bcolors.HEADER + "\n #### INSERT DATA TO DB #### \n" + colors.bcolors.ENDC)
                insertData(args.corres, formated_data, no_table, get_inserted, get_updated)
                #except:
                #    raise Exception(colors.bcolors.FAIL + "No SQL table has been filled in, please use the --table or -t option followed by the name of the table not to be inserted." + colors.bcolors.ENDC)


# read crimes CSV file
# each entry in CSV has LAT, LONG
# but this will be n^2 complexity
# N: apartments * N: crimes

# optimization after

# or another way
"""
geolocalize all crimes from LAT, LONG to boroughs- identified by Postal code
get total crimes per postal code
this gives a score to each borough

e.g. Lachine - H8T - X number of crimes

1. geo-localize all crime data and add a column
    can probably be done easily in Panda

    reverse geocoding : https://developers.google.com/maps/documentation/geocoding/intro#ReverseGeocoding

    e.g.
    http://maps.googleapis.com/maps/api/geocode/json?sensor=false&latlng=40.7135296,-73.9856844
"""

#  -*- coding: utf-8 -*-

import csv
import json
import pandas as pd
import requests
import pprint

#csvfile = open('crimes.csv', 'r')
df = pd.read_csv('crimes.csv', encoding = "ISO-8859-1")
# df = df[['LAT', 'LONG']]  -> {"LAT":45.5012532105,"LONG":-73.6206786362},{"LAT":45.5242817532,"LONG":-73.5758883043}
#df = map(list, df.values)
#jsonfile = open('crimes.json', 'w')

fieldnames = ("CATEGORIE", "DATE", "QUART", "PDQ", "X", "Y", "LAT", "LONG")

#reader = csv.DictReader( csvfile, fieldnames)
#for row in reader:

# df = df[['LAT', 'LONG']]
# df.to_json("crimes_lat_long.json", orient='values')  # -> [[45.6016777507,-73.5486926833],[45.4449528402,-73.6769260449],[45.6350960394,-73.5028680349],

def reverse_geocode_address(lat, long):
    # address = self.convert_french_accents(address)        # done in parse_apartment_page already

    try:
        # form URL with address in it
        url = " http://maps.googleapis.com/maps/api/geocode/json?sensor=false&latlng={},{}".format(lat, long)

        # request URL
        response = requests.get(url)
        response_json = response.json()

        # Google Map API response
        # https://developers.google.com/maps/documentation/javascript/geocoding#GeocodingResponses

        pprint.pprint(response_json)
        address = response_json['results'][0]['address_components']

        # zipcode is usually the last component, this is efficient and succinct
        # but may not be future-proof
        zipcode = address[len(address) - 1]['long_name']

        # print("{} is at {}, {}".format(zipcode, lat, long))

    except:
        status = response_json['status']
        error_message  = response_json['error_message']
        print(">> failed geocoding for {} {} because of : {}".format(lat, long, status))
        zipcode = "INV"

    return zipcode

crimes_per_borough = {}

for index, row in df.iterrows():
    # print(row['CATEGORIE'] + ':' + str(row['LAT']) + ':' + str(row['LONG']))

    zipcode_result = reverse_geocode_address(row['LAT'], row['LONG'])
    print("{} is at {}, {}".format(zipcode_result, row['LAT'], row['LONG']))

    # get first 3 characters which represent the borough e.g. H2L from H2L3W2
    borough_code = zipcode_result[:3]

    # create borough category if not exist yet, otherwise add 1
    if (borough_code in crimes_per_borough.keys()):
        crimes_per_borough[borough_code] = crimes_per_borough[borough_code] + 1
    else:
        crimes_per_borough[borough_code] = 1

        # 1. reverse-geocode LAT LONG to postal code e.g. H2L
    # 2. sum up each postal code area for each crime

    # pass

pprint.pprint(crimes_per_borough)


import itertools
import pathlib
import re
from typing import List, Tuple

def day14_part1_bitwise(data: List[str]) -> int:
    mask_regex = re.compile(r"mask = (\w+)")
    addr_value_regex = re.compile(r"mem\[(\d+)] = (\d+)")

    memory_layout = dict()

    and_mask, or_mask = -1, -1

    for entry in data:
        addr_value = addr_value_regex.findall(entry)
        if not addr_value:
            mask = mask_regex.findall(entry)[0]
            and_mask, or_mask, _ = get_masks(mask)
            continue

        address, value = int(addr_value[0][0]), int(addr_value[0][1])

        value = (value & and_mask) | or_mask
        memory_layout[address] = value

    return sum(memory_layout.values())

def day14_part2_bitwise(data: List[str]) -> int:
    mask_regex = re.compile(r"mask = (\w+)")
    addr_value_regex = re.compile(r"mem\[(\d+)] = (\d+)")

    memory_layout = dict()

    mask = None
    mask_combinations = None
    or_mask = -1

    for entry in data:
        addr_value = addr_value_regex.findall(entry)
        if not addr_value:
            mask = mask_regex.findall(entry)[0]
            _, or_mask, mask_combinations = get_masks(mask)
            continue

        address, value = int(addr_value[0][0]), int(addr_value[0][1])

        for combination in mask_combinations:
            new_mask = mask.replace("1", " ").replace("0", " ")
            for combo_val in combination:
                new_mask = new_mask.replace("X", combo_val, 1)

            combo_and_mask, combo_or_mask, _ = get_masks(new_mask)

            address = (address & combo_and_mask) | combo_or_mask | or_mask
            memory_layout[address] = value

    return sum(memory_layout.values())

def get_masks(mask: str) -> Tuple[int, int, List[Tuple[int, ...]]]:
    and_mask, or_mask = 2 ** 36 - 1, 0

    for index, char in enumerate(mask):
        if char == "0":
            and_mask &= (2 ** 36 - 1) & ~(1 << (35 - index))
        elif char == "1":
            or_mask |= 1 << (35 - index)

    wildcard_count = sum(char == "X" for char in mask)
    mask_wildcard_combinations = list(itertools.product("01", repeat=wildcard_count))

    return and_mask, or_mask, mask_wildcard_combinations

def get_input_data(file: str) -> List[str]:
    with pathlib.Path(file).open() as f:
        content = f.readlines()

    return content

if __name__ == "__main__":
    print(day14_part1_bitwise(get_input_data("input.txt")))
    print(day14_part2_bitwise(get_input_data("input.txt")))


from swallow.domain import models, services

class OperatorTest(models.AbstractOperator):
    def __call__(self):
        return self.args.args[0] * 3,

class OperatorTest2(models.AbstractOperator):
    def __call__(self):
        ...

class OperatorTestError(models.AbstractOperator):
    def __call__(self):
        raise Exception('Test error occur!')

def test_execute_exit():
    ticket = models.Ticket(
        ticket_id='test ticket id',
        units=[
            models.Unit(
                channel=models.Channel('test channel'),
                operator=OperatorTest
            )
        ]
    )
    message = models.Message(
        models.Args(args=(3, )),
        ticket=ticket
    )

    channel, message = services.execute(message)

    assert channel == models.ChannelEnum.EXIT.value
    assert message.args == (9, )
    assert message.ticket == models.Ticket(
        ticket_id='test ticket id',
        units=[],
        num=0,
        is_last=True
    )

def test_execute_error():
    ticket = models.Ticket(
        ticket_id='test ticket id',
        units=[
            models.Unit(
                channel=models.Channel('test channel'),
                operator=OperatorTestError
            )
        ]
    )
    message = models.Message(models.Args(args=(3, )), ticket)

    channel, message = services.execute(message)

    assert channel == models.ChannelEnum.ERROR.value
    assert message.args.kwargs == {
        'error': 'Test error occur!',
        'operator': 'OperatorTestError',
        'args': models.Args(args=(3, )),
    }
    assert message.ticket == models.Ticket(
        ticket_id=models.TicketID('test ticket id'),
        units=[],
        num=0,
        is_last=True
    )

def test_execute_ok():
    ticket = models.Ticket(
        ticket_id='test ticket id',
        units=[
            models.Unit(
                channel=models.Channel('test channel 1'),
                operator=OperatorTest
            ),
            models.Unit(
                channel=models.Channel('test channel 2'),
                operator=OperatorTest2
            )
        ]
    )
    message = models.Message(
        models.Object(args=(3, )),
        ticket=ticket
    )

    channel, message = services.execute(message)

    assert channel == 'OperatorTest2'
    assert message.object == (9, )
    assert message.ticket == models.Ticket(
        ticket_id='test ticket id',
        units=[
            models.Unit(
                channel=models.Channel('test channel 2'),
                operator=OperatorTest2,
            )
        ],
        num=0,
        is_last=True
    )