# -*- encoding: utf-8 -*-
# @ModuleName: UserService
# @Author: ximo
# @Time: 2023/3/28 14:54
import json
import time

from sqlalchemy import func

from service.Mysql.db_connector import MysqlConnect
from utils import model_json
from sqlalchemy.orm.session import Session
from service.Mysql.model import *

class UserService:
    def __init__(self, mysql_session):
        self.mysql_session = mysql_session

    # ----------------------------InitSpace Start--------------------------------------------
    def get_all_user(self):
        """
        NodeUserInfo
        :return:
        """
        mysql_session = self.mysql_session()
        return mysql_session.query(TbInfoUser).all()

    def get_search_nodes(self):
        """
        NodeSearchInfo
        :return: List< app_user_id int>
        """
        mysql_session = self.mysql_session()
        r = mysql_session.execute("SELECT  DISTINCT tb_search.app_user_id FROM tb_search")
        result = [i[0] for i in r]
        return result

    def get_all_search_record(self):
        """

        :return: List< [app_user_id, from_app_user_id, to_app_user_id, List(record_datetime) ] >
        """
        mysql_session: Session = self.mysql_session()
        query = """
        SELECT app_user_id,
               GROUP_CONCAT(keywords SEPARATOR '!@#@!') AS keywords,
               GROUP_CONCAT(content SEPARATOR '!@#@!') AS content,
               GROUP_CONCAT(record_datetime SEPARATOR '!@#@!') AS record_datetime
        FROM tb_search
        GROUP BY app_user_id;
        """
        result_list = mysql_session.execute(query).all()
        # result_list = mysql_session.query(TbSearch.app_user_id,
        #                                   func.group_concat(TbSearch.keywords, SEPARATOR="!@#@!"),
        #                                   func.group_concat(TbSearch.content, SEPARATOR="!@#@!"),
        #                                   func.group_concat(TbSearch.record_datetime, SEPARATOR="!@#@!")
        #                                   ).group_by(
        #     TbSearch.app_user_id).all()
        result = []
        for r in result_list:
            rr = []
            for k, c, d in zip(r[1].split("!@#@!"), r[2].split("!@#@!"), r[3].split("!@#@!")):
                rr.append({
                    "keywords": k.replace("'", ""),
                    "content": c.replace("'", ""),
                    "record_datetime": d
                })
            result.append((str(r[0]), r[0], r[0], rr))
        return result

    def get_all_app_user(self):
        """
        RelationAppUser
        :return: List<TbInfoAppUser>
        """
        mysql_session: Session = self.mysql_session()
        result = mysql_session.query(TbInfoAppUser).all()
        return result

    def get_all_app_groups(self):
        mysql_session: Session = self.mysql_session()
        result = mysql_session.query(TbInfoGroup, TbInfoApp).join(TbInfoApp, isouter=True).all()
        return result

    def get_all_app_name_user(self):
        """
        提供NodeAppUserInfo
        :return: List<(TbInfoAppUser, TbInfoApp)>
        """
        mysql_session: Session = self.mysql_session()
        # mysql = "select * from "
        # print(mysql_session.query(TbInfoAppUser, TbInfoApp).join(TbInfoApp, isouter=True))
        result = mysql_session.query(TbInfoAppUser, TbInfoApp).join(TbInfoApp, isouter=True).all()
        return result

    def get_all_group_user(self):
        """
        List<TbInfoGroupUser>
        :return:
        """
        # 查询出group user
        mysql_session: Session = self.mysql_session()
        result = mysql_session.query(TbInfoGroupUser).all()
        # 查询记录

        return result

    def get_all_user_telephones(self):
        mysql_session: Session = self.mysql_session()
        result = mysql_session.query(TbInfoTelephone).all()

        return result

    def get_all_user_telephone_record(self):
        """

        :return: List< [from_telephone_id+to_telephone_id, from_telephone_id, to_telephone_id, List(record_datetime) ] >
        """
        mysql_session: Session = self.mysql_session()
        result_list = mysql_session.query(TbTelephoneRecord.from_telephone_id,
                                          TbTelephoneRecord.to_telephone_id,
                                          func.group_concat(TbTelephoneRecord.record_datetime)).group_by(
            TbTelephoneRecord.from_telephone_id, TbTelephoneRecord.to_telephone_id).all()
        result = [(str(r[0]) + ">" + str(r[1]), r[0], r[1], r[2].split(",")) for r in result_list]
        return result

    def get_all_delivery_record(self):
        """

        :return: List< [from_user_id>to_user_id, from_user_id, to_user_id, List(record_datetime) ] >
        """
        mysql_session: Session = self.mysql_session()
        result_list = mysql_session.query(TbDelivery.from_user_id,
                                          TbDelivery.to_user_id,
                                          func.group_concat(TbDelivery.from_address, SEPARATOR="!@#@!"),
                                          func.group_concat(TbDelivery.to_address, SEPARATOR="!@#@!"),
                                          func.group_concat(TbDelivery.record_datetime, SEPARATOR="!@#@!")
                                          ).group_by(
            TbDelivery.from_user_id, TbDelivery.to_user_id).all()
        result = []
        for r in result_list:
            rr = []
            for f_a, t_a, d in zip(r[2].split("!@#@!"), r[3].split("!@#@!"), r[4].split("!@#@!")):
                rr.append({
                    "from_address": f_a.replace("'", ""),
                    "to_address": t_a.replace("'", ""),
                    "record_datetime": d
                })
            result.append((str(r[0]) + ">" + str(r[1]), r[0], r[1], rr))
        return result

    def get_all_personal_content(self):
        """

        :return: List< [from_telephone_id+to_telephone_id, from_telephone_id, to_telephone_id, List(record_datetime) ] >
        """
        mysql_session: Session = self.mysql_session()
        query = """
                SELECT from_app_user_id,
                       to_app_user_id,
                       GROUP_CONCAT(keywords SEPARATOR '!@#@!') AS keywords,
                       GROUP_CONCAT(content SEPARATOR '!@#@!') AS content,
                       GROUP_CONCAT(record_datetime SEPARATOR '!@#@!') AS record_datetime
                FROM tb_content_personal
                GROUP BY from_app_user_id,to_app_user_id;
                """
        result_list = mysql_session.execute(query).all()
        # result_list = mysql_session.query(TbContentPersonal.from_app_user_id,
        #                                   TbContentPersonal.to_app_user_id,
        #                                   func.group_concat(TbContentPersonal.keywords, SEPARATOR="!@#@!"),
        #                                   func.group_concat(TbContentPersonal.content, SEPARATOR="!@#@!"),
        #                                   func.group_concat(TbContentPersonal.record_datetime, SEPARATOR="!@#@!")
        #                                   ).group_by(
        #     TbContentPersonal.from_app_user_id, TbContentPersonal.to_app_user_id).all()
        # result = [[str(r[0]) + ">" + str(r[1]), r[0], r[1], r[2].split("!@#@!")] for r in result_list]
        result = []
        for r in result_list:
            rr = []
            for k, c, d in zip(r[2].split("!@#@!"), r[3].split("!@#@!"), r[4].split("!@#@!")):
                rr.append({
                    "keywords": k.replace("'", ""),
                    "content": c.replace("'", ""),
                    "record_datetime": d
                })

            result.append((str(r[0]) + ">" + str(r[1]), r[0], r[1], rr))
        return result

    # ----------------------------InitSpace End--------------------------------------------

    def get_user_telephones(self, card_id=None):
        """
        获取该人的所有手机号，不指定即返回搜索
        :param card_id:
        :return:
        """
        mysql_session = self.mysql_session()
        if card_id:
            r = mysql_session.query(TbInfoTelephone).join(TbInfoUser).filter(TbInfoUser.card_id == card_id).all()
        else:
            r = mysql_session.query(TbInfoTelephone).join(TbInfoUser).all()
        mysql_session.close()
        return r

    def get_personal_app_info(self, card_id=None):
        mysql_session: Session = self.mysql_session()

        # print(mysql_session)

        if card_id:
            r = mysql_session.query(TbInfoAppUser).join(TbInfoUser).filter(
                TbInfoUser.card_id == card_id).all()

        else:
            r = mysql_session.query(TbInfoAppUser).join(TbInfoUser).join(TbInfoApp).all()
        mysql_session.close()

        return r

    def get_telephone_record(self, filter=None):
        mysql_session = self.mysql_session()
        # print(mysql_session)
        if filter:
            r = mysql_session.query(TbTelephoneRecord).filter_by(**filter).all()
        else:
            r = mysql_session.query(TbTelephoneRecord).all()
        mysql_session.close()
        return r

if __name__ == '__main__':
    # result = UserService().get_user_telephones("vtyCeAkHhl")
    # for i in result:
    #     print(i)
    # print(model_to_dict(result))
    # r = UserService().get_personal_app_info({"id": 1111})
    # print(model_to_dict(r))
    Session = MysqlConnect("10.66.10.234:3306", "root", "234").connect("final")
    # r = Session().execute("select * from A").all()
    # print(r[0][0])
    # d = []
    # # print(r[0][0].split("'"))
    # #
    # # print(json.dumps([{"A": r[0][0]}],ensure_ascii=False))
    # print('\\"'.join(r[0][0].split('"')))
    # d.append({"A": "\\'".join(r[0][0].split("'"))})
    # rr_str = json.dumps(d, ensure_ascii=False)
    # print(rr_str)
    # print(d)
    # rr = json.dumps(d, ensure_ascii=False)
    # print(rr)
    # r_dic = json.loads(rr)
    # print(r_dic)
    # print(r_dic[0]["A"])
    # r = UserService(Session).get_search_nodes()
    # print(r)
    # for i in r:
    #     print(i)
    # r = UserService(Session).get_all_search_record()
    # for i in r:
    #     print(len(i[-1]), i)
    # break
    r = UserService(Session).get_all_personal_content()
    for i in r:
        print(len(i[-1]), i)
        break
    # for i in r:
    #     print(i)
    #     print(i[3])
    #     s = str(i[3])
    #     print(s)
    #     print(eval(s))
    #     break
    # rr = []
    # rr.append({
    #     "keywords": "11",
    #     "content": "11",
    #     "record_datetime": "d"
    # })
    # print(rr)
    # print({
    #     "keywords": "11",
    #     "content": "11",
    #     "record_datetime": "d"
    # })
    # print(time.time())
    # r = UserService(Session).get_personal_app_info()
    # print(model_json.model_to_dict(r))
    # print('*' * 30)
    # r = UserService(Session).get_telephone_record()
    # print(r)
    # print(model_json.model_to_dict(r))
    # # print(model_to_dict(r))
    # print(time.time())
    # print(json.dumps(model_to_dict(r)))
    # r = UserService(Session).get_all_user_telephone_record()
    # print(r)


import socket
import time

from io import BytesIO
from helpers import *
from random import randint
from block import Block
from tx import Tx

TX_DATA_TYPE = 1
BLOCK_DATA_TYPE = 2
FILTERED_BLOCK_DATA_TYPE = 3
COMPACT_BLOCK_DATA_TYPE = 4

NETWORK_MAGIC = b'\xf9\xbe\xb4\xd9'
TESTNET_NETWORK_MAGIC = b'\x0b\x11\x09\x07'

class NetworkEnvelope:
    def __init__(self, command, payload, testnet=False):
        self.command = command
        self.payload = payload
        if testnet:
            self.magic = TESTNET_NETWORK_MAGIC
        else:
            self.magic = NETWORK_MAGIC

    def __repr__(self):
        return '{}: {}'.format(self.command.decode('ascii'), self.payload.hex())

    @classmethod
    def parse(cls, s, testnet=False):

        #this is the point where code is halted as long there's nothing to read
        magic = s.read(4)
        if magic == b'':
            raise RuntimeError('Connection reset!')
        if testnet:
            expected_magic = TESTNET_NETWORK_MAGIC
        else:
            expected_magic = NETWORK_MAGIC
        if magic != expected_magic:
            raise RuntimeError('magic is not right {} vs {}'.format(magic.hex(), expected_magic.hex()))

        cmd = s.read(12)
        cmd = cmd.decode('utf-8').rstrip('\x00').encode()
        p_length = little_endian_to_int(s.read(4))
        checksum = s.read(4)
        payload = s.read(p_length)

        # verify checksum
        if not hash256(payload)[0:4] == checksum:
            raise RuntimeError('Bad Checksum!')

        return cls(cmd, payload)

    def serialize(self):
        '''Returns the byte serialization of the entire network message'''
        # add the network magic
        result = self.magic
        result += self.command + (12 - len(self.command)) * b'\x00'
        result += int_to_little_endian(len(self.payload), 4)
        result += hash256(self.payload)[0:4]
        result += self.payload

        return result

    def stream(self):
        return BytesIO(self.payload)

class VersionMessage:
    command = b'version'

    def __init__(self, version=70015, services=0, timestamp=None,
                 receiver_services=0,
                 receiver_ip=b'\x00\x00\x00\x00', receiver_port=8333,
                 sender_services=0,
                 sender_ip=b'\x00\x00\x00\x00', sender_port=8333,
                 nonce=None, user_agent=b'/bitcoingraffiti:0.1/',
                 latest_block=0, relay=False):
        self.version = version
        self.services = services
        if timestamp is None:
            self.timestamp = int(time.time())
        else:
            self.timestamp = timestamp
        self.receiver_services = receiver_services
        self.receiver_ip = receiver_ip
        self.receiver_port = receiver_port
        self.sender_services = sender_services
        self.sender_ip = sender_ip
        self.sender_port = sender_port
        if nonce is None:
            self.nonce = int_to_little_endian(randint(0, 2**64), 8)
        else:
            self.nonce = nonce
        self.user_agent = user_agent
        self.latest_block = latest_block
        self.relay = relay

    @classmethod
    def parse(cls, s):
        version = little_endian_to_int(s.read(4))
        services = little_endian_to_int(s.read(8))
        timestamp = little_endian_to_int(s.read(8))
        receiver_services = little_endian_to_int(s.read(8))
        receiver_ip = s.read(16)
        receiver_port = s.read(2)
        sender_services = little_endian_to_int(s.read(8))
        sender_ip = s.read(16)
        sender_port = s.read(2)
        nonce = s.read(8)
        user_agent_length = read_varint(s)
        user_agent = s.read(user_agent_length)
        latest_block = little_endian_to_int(s.read(4))
        relay = True if s.read(1) == b'\x01' else False

        print('Peer Version:', version, 'Services', services, bin(services))

        return cls(version, services, timestamp,
                 receiver_services,
                 receiver_ip, receiver_port,
                 sender_services,
                 sender_ip, sender_port,
                 nonce, user_agent,
                 latest_block, relay)

    def serialize(self):
        '''Serialize this message to send over the network'''
        ipv4 = 10 * b'\x00' + 2* b'\xff'

        result = int_to_little_endian(self.version, 4)
        result += int_to_little_endian(self.services, 8)
        result += int_to_little_endian(self.timestamp, 8)
        result += int_to_little_endian(self.receiver_services, 8)
        result += ipv4 + self.receiver_ip
        result += self.receiver_port.to_bytes(2, 'big')
        result += int_to_little_endian(self.sender_services, 8)
        result += ipv4 + self.sender_ip
        result += self.sender_port.to_bytes(2, 'big')
        result += self.nonce + (8 - len(self.nonce)) * b'\x00'
        result += encode_varint(len(self.user_agent))
        result += self.user_agent
        result += int_to_little_endian(self.latest_block, 4)

        '''relay is necessary for letting peer know to send only bloomfilter messages'''
        if self.relay:
            result += b'x\01'
        else:
            result += b'\x00'
        return result

class VerAckMessage:
    command = b'verack'

    def __init__(self):
        pass

    @classmethod
    def parse(cls, s):
        return cls()

    def serialize(self):
        return b''

class PingMessage:
    command = b'ping'

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

    @classmethod
    def parse(cls, s):
        nonce = s.read(8)
        return cls(nonce)

    def serialize(self):
        return self.nonce

class PongMessage:
    command = b'pong'

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

    def parse(cls, s):
        nonce = s.read(8)
        return cls(nonce)

    def serialize(self):
        return self.nonce

class GetAddressMessage:
    command = b'getaddr'

    def __init__(self):
        pass

    @classmethod
    def parse(cls, s):
        return cls()

    def serialize(self):
        return b''

class AddressMessage:
    command = b'addr'

    def __init__(self, count, addr_list):
        self.count = count
        self.addr_list = addr_list

    def __repr__(self):
        return 'Number of addresses: {}\n {}'.format(self.count, self.addr_list)

    @classmethod
    def parse(cls, s):
        count = read_varint(s)
        addr_list = []

        for addr in range(count):
          addr_list.append(NetAddress.parse(s))
          #

        return cls(count, addr_list)

    def serialize(self):
        raise NotImplementedError('Serialization not yet implemented!')

class GetHeadersMessage:
    '''Request Headers'''
    '''To request more headers, you can insert the last hash as a new startblock and repeat
        as startblock is not included in the search'''
    command = b'getheaders'

    def __init__(self, version=70015, num_hashes=1,
        start_block=None, end_block=None):
        self.version = version
        self.num_hashes = num_hashes
        if start_block is None:
            raise RuntimeError('a start block is required')
        self.start_block = start_block
        if end_block is None:
            self.end_block = b'\x00' * 32
        else:
            self.end_block = end_block

    def serialize(self):
        '''Serialize this message to send over the network'''
        result = int_to_little_endian(self.version, 4)
        result += encode_varint(self.num_hashes)
        result += self.start_block[::-1]
        result += self.end_block[::-1]
        return result

class HeadersMessage:
    '''Receive Headers'''
    command = b'headers'

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

    @classmethod
    def parse(cls, stream):
        num_headers = read_varint(stream)
        blocks = []
        for _ in range(num_headers):
            blocks.append(Block.parse(stream))
            num_txs = read_varint(stream)
            if num_txs != 0:
                raise RuntimeError('number of txs not 0')
        return cls(blocks)

class FeefilterMessage:
    '''Receive Feefilter'''
    '''This is the minimum fee per sats/1kb'''
    command = b'feefilter'

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

    @classmethod
    def parse(cls, s):
        fee = little_endian_to_int(s.read(8))
        print('Feefilter: minimum fee is:', fee, 'satoshis')
        return cls(fee)

class MempoolMessage:
    '''Request mempool transactions hashes'''
    '''Response is an inv message'''
    command = b'mempool'

    def __init__(self):
        pass

    def serialize(self):
        return b''

class CmpctMessage:
    '''Request mempool transactions hashes'''
    '''Response is an inv message'''
    command = b'sendcmpct'

    def __init__(self, announce, version):
        self.announce = announce
        self.version = version

    def __repr__(self):
        return '\nAnnounce: {}\nVersion: {}\n'.format(self.announce, self.version)

    @classmethod
    def parse(cls, s):
        announce = little_endian_to_int(s.read(1))
        version = little_endian_to_int(s.read(8))

        return cls(announce, version)

    def serialize(self):
        raise NotImplementedError()

class GetDataMessage:
    command = b'getdata'

    def __init__(self):
        self.data = []

    def add_data(self, data_type, identifier):
        self.data.append((data_type, identifier))

    def serialize(self):
        result = encode_varint(len(self.data))
        # loop through each tuple (data_type, identifier) in self.data
        for data_type, identifier in self.data:
            # data type is 4 bytes Little-Endian
            result += int_to_little_endian(data_type, 4)
            # identifier needs to be in Little-Endian
            result += identifier[::-1]
        return result

class InvMessage:
    '''Receive Inv'''
    '''Inventory Vectors with data'''
    command = b'inv'

    def __init__(self, count, inventory):
        self.count = count
        self.inventory = inventory

    def __repr__(self):
        return '\nCount: {}\n{}'.format(self.count, self.inventory)

    @classmethod
    def parse(cls, s):
        count = read_varint(s)
        inventory = []

        for _ in range(count):
            inventory.append(InventoryVector.parse(s))

        return cls(count, inventory)

    def serialize(self):
        raise NotImplementedError('Serialization not yet implemented!')

class RejectMessage:
    '''Receive Inv'''
    '''Inventory Vectors with data'''
    command = b'reject'

    def __init__(self, message, ccode, reason, data):
        self.message = message
        self.ccode = ccode
        self.reason = reason
        self.data = data

    def __repr__(self):
        return '\nCode: {}\nMessage: {}\nReason: {}\n'.format(self.ccode, self.message, self.reason)

    @classmethod
    def parse(cls, s):
        message_length = read_varint(s)
        message = s.read(message_length)
        ccode = REJECT_CODE_NAMES[little_endian_to_int(s.read(1))]
        reason_length = read_varint(s)
        reason = s.read(reason_length)
        data = None #perhaps able to parse this out

        return cls(message, ccode, reason, data)

    def serialize(self):
        raise NotImplementedError('Serialization not yet implemented!')

class GenericMessage:
    def __init__(self, command, payload):
        self.command = command
        self.payload = payload

    def serialize(self):
        return self.payload

class SimpleNode:

    def __init__(self, host, port=None, testnet=False, logging=False):
        if port is None:
            if testnet:
                port = 18333
            else:
                port = 8333
        self.testnet = testnet
        self.logging = logging
        # connect to socket
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.socket.connect((host, port))
        # create a stream that we can use with the rest of the library
        self.stream = self.socket.makefile('rb', None)

    def handshake(self):
        '''Do a handshake with the other node.
        Handshake is sending a version message and getting a verack back.'''
        version = VersionMessage()
        self.send(version)
        self.wait_for(VerAckMessage, VersionMessage)

    def getAddressesFromHost(self):
        ''' Get peers from host'''
        getaddress = GetAddressMessage()
        self.send(getaddress)
        address = self.wait_for(AddressMessage)
        print(address.addr_list)

    def getHeadersFromBlock(self, sb, eb=None):
        '''gets headers from start block till current block'''
        headers = []

        while len(headers) % 2000 == 0:
            self.send(GetHeadersMessage(start_block=sb, end_block=eb))
            headers += self.wait_for(HeadersMessage).blocks
            sb = headers[-1].hash()

        if (self.logging):
            print('Headers retrieved:', len(headers))

        return headers

    def send(self, message):
        '''Send a message to the connected node'''
        envelope = NetworkEnvelope(message.command, message.serialize(), testnet=self.testnet)

        if self.logging:
            print('sending: {}'.format(envelope))

        if message.command == b'tx':
            print('txID:', message.id())

        self.socket.sendall(envelope.serialize())

    def read(self):
        '''Read a message from the socket'''
        envelope = NetworkEnvelope.parse(self.stream, testnet=self.testnet)
        if self.logging:
            print('receiving: {}'.format(envelope))
        return envelope

    def wait_for(self, *message_classes):
        '''Wait for one of the messages in the list'''
        # initialize the command we have, which should be None
        command = None
        command_to_class = {m.command: m for m in message_classes}
        # loop until the command is in the commands we want
        while command not in command_to_class.keys():

            # get the next network message
            # this is also a halt on the code!!!
            envelope = self.read()

            # set the command to be evaluated
            command = envelope.command
            # we know how to respond to version and ping, handle that here
            if command == VersionMessage.command:
                # send verack
                self.send(VerAckMessage())
            elif command == PingMessage.command:
                # send pong
                self.send(PongMessage(envelope.payload))
            elif command == FeefilterMessage.command:
                pass
                # send pong
        # return the envelope parsed as a member of the right message class
        return command_to_class[command].parse(envelope.stream())

## Other Classes ##
class NetAddress:
    def __init__(self, time, services, ipv, port):
      self.time = time
      self.services = services
      self.ipv = ipv
      self.port = port

    def __repr__(self):
        return '\nTime: {}\nServices: {}\nipv: {}\nport: {}\n'.format(
          self.time, self.services, bytes_to_ip(self.ipv[-4:]), int.from_bytes(self.port, 'big')
        )

    @classmethod
    def parse(cls, s):
        time = little_endian_to_int(s.read(4))
        services = little_endian_to_int(s.read(8))
        ipv = s.read(16)
        port = s.read(2)

        return cls(time, services, ipv, port)

    def serialize(self):
        raise NotImplementedError('Serialization not yet implemented!')

class InventoryVector:
    def __init__(self, obj_type, obj_hash):
      self.obj_type = obj_type
      self.obj_hash = obj_hash

    def __repr__(self):
        return '\n{}: {}'.format(self.type_lookup(), self.obj_hash)

    @classmethod
    def parse(cls, s):
        obj_type = little_endian_to_int(s.read(4))
        obj_hash = s.read(32)[::-1].hex()

        return cls(obj_type, obj_hash)

    def serialize(self):
        raise NotImplementedError('Serialization not yet implemented!')

    def type_lookup(self):
        if self.obj_type == 0:
            return 'ERROR'
        elif self.obj_type == 1:
            return 'MSG_TX'
        elif self.obj_type == 2:
            return 'MSG_BLOCK'
        elif self.obj_type == 3:
            return 'MSG_FILTERED_BLOCK'
        elif self.obj_type == 4:
            return 'MSG_CMPCT_BLOCK'
        elif self.obj_type == 0x40000001:
            return 'MSG_WITNESS_TX'
        elif self.obj_type == 0x40000002:
            return 'MSG_WITNESS_BLOCK'
        elif self.obj_type == 0x40000003:
            return 'MSG_FILTERED_WITNESS_BLOCK'
        else:
            raise ValueError('Unknown InventoryVector data type')

REJECT_CODE_NAMES = {
    0x01: 'REJECT_MALFORMED',
    0x10: 'REJECT_INVALID',
    0x11: 'OBSOLETE',
    0x12: 'REJECT_DUPLICATE',
    0x40: 'REJECT_NONSTANDARD',
    0x41: 'REJECT_DUST',
    0x42: 'REJECT_INSUFFICIENT_FEE',
    0x43: 'REJECT_CHECKPOINT',
}


from rest_framework import generics, views, status
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response

from api.models.score import UserStreakTracker, AssignmentTypeScoreTracker, AssignmentType
from api.serializers.score import UserStreakTrackerSerializer, AssignmentTypeScoreTrackerSerializer

class UserStreakView(views.APIView):

    def get(self, request, format=None):
        user_streaks, created_user_streak = UserStreakTracker.objects.get_or_create(user=request.user)
        assignment_type_streaks = AssignmentTypeScoreTracker.objects.filter(user=request.user)

        # Create if not existing; applies to old users
        if not assignment_type_streaks:
            assignment_types = AssignmentType.objects.all()

            assignment_type_streaks = []

            for assignment_type in assignment_types:
                score_type_tracker, created = AssignmentTypeScoreTracker.objects.get_or_create(
                    user=request.user,
                    assignment_type=assignment_type
                )
                assignment_type_streaks.append(score_type_tracker)

        return Response({
            'user_streak': UserStreakTrackerSerializer(
                user_streaks
            ).data if user_streaks else {},
            'assignment_type_streaks': AssignmentTypeScoreTrackerSerializer(
                assignment_type_streaks,
                many=True
            ).data if assignment_type_streaks else {},
        }, status=status.HTTP_200_OK)


import boto3
from zipfile import ZipFile
import urllib.request as url

BUCKET_NAME = "openoil.org"
TMP_FILE = "/tmp/historical.zip"

def lambda_handler(event, context):
    file = url.URLopener()
    try:
        file.retrieve("http://www.bogc.dnrc.mt.gov/production/historical.zip", TMP_FILE)

        with ZipFile(TMP_FILE) as zip:
            file_leaseProd = zip.read('histLeaseProd.tab')
            file_wellProd = zip.read('histprodwell.tab')
            file_wellData = zip.read('histWellData.tab')

            s3 = boto3.resource('s3')
            s3.Bucket(BUCKET_NAME).put_object(Key='MT_leaseProd.tab',
                                              Body=file_leaseProd)
            s3.Bucket(BUCKET_NAME).put_object(Key='MT_wellProd.tab',
                                              Body=file_wellProd)
            s3.Bucket(BUCKET_NAME).put_object(Key='MT_wellData.tab',
                                              Body=file_wellData)
    except Exception as e:
        print(e)
        raise e


"""
This file holds functions to build audio log-mel spectrograms and to process
them.
"""

import matplotlib.pyplot as plt
import numpy as np
import tensorflow as tf
from sklearn.preprocessing import minmax_scale

import au_constants as auc

EPS = 1.0e-6  # Epsilon, a small value to avoid the log(0) problem

def wave_to_melspecgram(wave):
    """
    Converts an audio waveform into a log-mel spectrogram. Based off of
    https://www.tensorflow.org/api_docs/python/tf/signal/mfccs_from_log_mel_spectrograms

    :param wave: The time series of an audio clip
    :return: np.array
    """
    # Convert the wave into the frequency domain
    stft = tf.signal.stft(
        wave, frame_length=auc.WIN_SIZE, frame_step=auc.STEP_SIZE)
    spectrogram = tf.abs(stft)
    # phase = tf.angle(stft)

    # Warp the linear scale spectrogram into the mel-scale
    num_specgram_bins = stft.shape[-1].value
    linear_to_mel_weight_matrix = tf.signal.linear_to_mel_weight_matrix(
        auc.NUM_MEL_BINS, num_specgram_bins, auc.SR, auc.MIN_HERTZ,
        auc.MAX_HERTZ)
    mel_specgram = tf.tensordot(
        spectrogram, linear_to_mel_weight_matrix, 1)
    mel_specgram.set_shape(
        spectrogram.shape[:-1].concatenate(
            linear_to_mel_weight_matrix.shape[-1:]))

    # Flip the rows and columns so that the mel bins is on the y-axis and
    # time is on the x-axis.
    mel_specgram = tf.transpose(mel_specgram)

    # Compute a stabilized log to get log-magnitude mel-scale spectrogram
    log_mel_specgram = tf.math.log(mel_specgram + EPS)

    sess = tf.compat.v1.Session()
    with sess.as_default():
        # Convert the spectrogram from a tf.Tensor to a np.array
        log_mel_specgram = log_mel_specgram.eval()

    return log_mel_specgram

def normalize_melspecgram(melspecgram):
    """
    Normalizes the amplitude of a log-mel spectrogram to have zero mean and
    unit variance. Performs sample-level amplitude normalization. Unused.

    :param melspecgram: np.array
    :return: np.array
    """
    melspecgram -= np.mean(melspecgram)  # Set the mean to 0
    melspecgram /= np.std(melspecgram)  # Set the variance to 1
    return melspecgram

def scale_melspecgram(melspecgram, amp_range=auc.AMP_RANGE):
    """
    Scales a log-mel spectrogram to have an amplitude range of [-1, 1]. Don't
    use both normalization and scaling.

    :param melspecgram: np.array
    :param amp_range: Tuple specifying the desired range
    :return: np.array
    """
    return minmax_scale(melspecgram, amp_range)

def display_melspecgram(melspecgram):
    """
    Displays a log-mel spectrogram using matplotlib.

    :param melspecgram: The spectrogram data in the form of a 2D np.array.
    """
    plt.pcolormesh(melspecgram, cmap="magma")
    plt.title("Log-Mel Magnitude Spectrogram")
    plt.ylabel("Log-Mel Bins (mel)")
    plt.xlabel("Time (sample)")
    plt.colorbar()
    plt.show()


# Script to add label numbers (used in keras) to the labels
# It looks like the label names are numbered in alphabetical order.
import pandas as pd
from pathlib import Path

BASE = Path.home() / 'Documents' / 'tensorflow' / 'cifar10'
LABELS = BASE / 'data' / 'trainLabels.csv'
labels = pd.read_csv(LABELS)
names = labels.label.unique()
names.sort()
label_map = dict(zip(names, range(10)))
labels['y'] = labels.label.map(label_map)
OUTPATH = BASE / 'data' / 'full_labels.csv'
labels.to_csv(OUTPATH, index=False)


import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from polyrat import *
from pgf import PGF

X = np.linspace(-1,1,int(2e5)).reshape(-1,1)
y = np.abs(X).flatten()
names = ['opt', 'vf', 'ssk']

for degree in [6,10, 14, 18]:

	vf_norms = []
	opt_norms = []
	sk_norms = []
	for seed in range(20):
		print(f"-----{seed:2d}------")
		np.random.seed(seed + 42*degree)		# Tweak the
		xi = np.linspace(-1,1, degree+1)
		yi = np.random.randn(len(xi))
		p0 = LagrangePolynomialInterpolant(xi.reshape(-1,1), np.random.randn(len(xi)))
		q0 = LagrangePolynomialInterpolant(xi.reshape(-1,1), np.random.randn(len(xi)))

		# Construct ratio polynomial
		p = PolynomialApproximation(degree, Basis = ArnoldiPolynomialBasis)
		p.fit(X, p0(X))
		q = PolynomialApproximation(degree, Basis = ArnoldiPolynomialBasis)
		q.fit(X, q0(X))
		rat = RationalRatio(p,q)
		assert np.all(np.isclose(rat(X), p0(X)/q0(X)))

		#rat.refine(X, y, verbose = 2)
		opt_norms.append(np.linalg.norm(rat(X) - y))
		print(f"Optimization: {opt_norms[-1]:10.3e}")

		# Vector fitting
		vf = VectorFittingRationalApproximation(degree, degree, poles0 = q0.roots())
		vf.fit(X, y)
		vf_norms.append(np.linalg.norm(vf(X) - y))
		print(f"Vector Fitting: {vf_norms[-1]:10.3e}")

		# Stabilized SK
		sk = SKRationalApproximation(degree, degree, refine = False, rebase = True)
		sk.fit(X, y, denom0 = q0(X))
		sk_norms.append(np.linalg.norm(sk(X) - y))
		print(f"Stabilized SK: {sk_norms[-1]:10.3e}")

	plt.close()
	ax = sns.swarmplot(data = [np.log10(d) for d in [opt_norms, vf_norms, sk_norms]])
	ax.set_yscale('log')

	for coll, name in zip(ax.collections, names):
		xx, yy = np.array(coll.get_offsets()).T
		pgf = PGF()
		pgf.add('x', xx)
		pgf.add('y', yy)
		if name != 'opt':
			pgf.write(f'data/fig_init_{degree:02d}_{name}.dat')


import torch
import torch.nn as nn
from transformers import Wav2Vec2Model, Wav2Vec2PreTrainedModel

class SLUModel(Wav2Vec2PreTrainedModel):
    def __init__(self, config, pretrained_model, pretrained_dir):
        super().__init__(config)

        self.wav2vec2 = Wav2Vec2Model.from_pretrained(pretrained_model, cache_dir=pretrained_dir)
        self.dropout = nn.Dropout(0.1)
        self.classifier = nn.Linear(config.hidden_size, 23)

        self.init_weights()

    def forward(self, input_values, attention_mask=None):
        outputs = self.wav2vec2(input_values)
        # print(outputs[0].shape)
        output = torch.mean(outputs[0], dim=1)
        logits = self.classifier(self.dropout(output))
        # print(logits.shape)
        return logits


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

import json
from utils.price_comparison import PriceComparison
from exchanges_util.coin_exchange_utils import CoinExchangeUtils
from exchanges_util.trade_satoshi_utils import TradeSatoshiUtils
from exchanges_util.binance_utils import BinanceUtils
from exchanges_util.bittrex_utils import BittrexUtils

# 独自クラスインスタンス化
price_comparison = PriceComparison()
trade_satoshi = TradeSatoshiUtils()
coin_exchange = CoinExchangeUtils()
binance = BinanceUtils()
bittrex = BittrexUtils()

# configファイル読み込み
arbitrage_parameter_file = 'config/arbitrage_parameter.json'
arbitrage_parameter = json.load(open(arbitrage_parameter_file, 'r'))
RATIO = arbitrage_parameter['output_limit_ratio']

if __name__ == '__main__':

    # 価格情報を格納するlist
    price_list = []

    # satoshi価格取得-----------------------
    satoshi_json = trade_satoshi.get_market_price()
    price_list.append(satoshi_json)

    # coin_exchange価格取得------------------
    coin_exchange_json = coin_exchange.get_market_price()
    price_list.append(coin_exchange_json)

    # binance価格取得------------------
    binance_json = binance.get_market_price()
    price_list.append(binance_json)

    # bittrex価格取得------------------
    bittrex_json = bittrex.get_market_price()
    price_list.append(bittrex_json)

    # 指定した倍率以上の通貨ペアと取引所を表示-----------------------------
    price_comparison.print_arbitrage_list(RATIO, price_list)


from multiprocessing import Pool
from timeit import default_timer

def factorial(num):
    if num == 1:
        return num
    else:
        return num * factorial(num - 1)

if __name__ == '__main__':
    start1 = default_timer()
    with Pool(processes = 8) as pool:
        results = pool.map(factorial, [i for i in range(700, 900)])
    # print(results)
    end1 = default_timer()
    print("time taken: ", end1 - start1, "seconds")
    start2 = default_timer()
    for i in range(700, 900):
        results.append(factorial(i))
    # print(results)
    end2 = default_timer()
    print("time taken: ", end2 - start2, "seconds")
    print('5:', factorial(5), ', 7:', factorial(7) )


import numpy as np
import pandas as pd
import scipy
import seaborn as sns
from scipy.integrate import quad
from scipy.optimize import fsolve
from sklearn.metrics import fbeta_score, make_scorer
from matplotlib import pyplot as plt

H_0 = 67.4*1000*100  # cm s^-1 Mpc^-1
c = 29979245800 # cm s^-1
Mpc_to_cm = 3.085677581491367E24
Gyr_to_s = 3.15576E16
Hubble_time = 1/(H_0 / Mpc_to_cm * Gyr_to_s)  # Gyr
Hubble_distance = c/H_0  # Mpc
Omega_b = 0.0224/((H_0)/1000/100/100)**2
Omega_m = 0.315
Omega_Lambda = 0.685
f_IGM = 0.83
chi = 7/8
G = 6.6743e-8 # cm^3 g^-1 s^-2
m_p = 1.67262192e-24 # g
dm_factor = 3*c*H_0/(Mpc_to_cm)**2*1e6*Omega_b*f_IGM*chi/(8*np.pi*G*m_p)
DM_host_lab = 70.0 # pc cm^-3
DM_halo = 30.0

f2_score = make_scorer(fbeta_score, beta=0.5)

def comoving_distance_at_z(z): # Mpc
    zp1 = 1.0+z
    h0_up = np.sqrt(1+Omega_m/Omega_Lambda) * scipy.special.hyp2f1(1/3,1/2,4/3,-Omega_m/Omega_Lambda)
    hz_up = zp1 * np.sqrt(1+Omega_m*zp1**3/Omega_Lambda) * scipy.special.hyp2f1(1/3,1/2,4/3,-Omega_m*zp1**3/Omega_Lambda)
    h0_down = np.sqrt(Omega_Lambda + Omega_m)
    hz_down = np.sqrt(Omega_Lambda + Omega_m * zp1**3)
    return Hubble_distance * (hz_up/hz_down-h0_up/h0_down)

def luminosity_distance_at_z(z): # Mpc
    return (1. + z) * comoving_distance_at_z(z)

def angular_diameter_distance_at_z(z): # Mpc
    return comoving_distance_at_z(z) / (1. + z)

def DM_int(z):
    return (1+z)/(np.sqrt(Omega_m*(1+z)**3+Omega_Lambda))

def DM_from_z(z): # pc cm^-3
    return dm_factor * quad(DM_int,0,z)[0]

def excess_DM(z):
    return DM_halo + DM_from_z(z) + DM_host_lab/(1+z)

def z_from_DM(DM):
    return fsolve(lambda z:excess_DM(z)-DM,0)[0]

def load_chime():
    CHIME = pd.read_csv('chimefrbcat1.csv')

    CHIME.drop([364,365,401,402,512,513],inplace=True) # No flux measurement
    CHIME.reset_index(drop=True,inplace=True)

    z_values = np.zeros(len(CHIME))
    for i,frb in CHIME.iterrows():
        DM = frb['dm_exc_ne2001']
        z = max(0.00225301,z_from_DM(DM)) # z=0.00225301, d_L=10 Mpc
        z_values[i] = z
        if z<=0.00225301:
            print(i,DM,z,frb['tns_name'])

    z_values[CHIME['repeater_name']=='FRB20121102A'] = 0.19273 # FRB 20121102A
    z_values[CHIME['repeater_name']=='FRB20180916B'] = 0.0337 # FRB 20180916B

    brightness_temperature = 1.1e35 * CHIME['flux'] * (CHIME['bc_width']*1000)**(-2) * (CHIME['peak_freq']/1000)**(-2) * (luminosity_distance_at_z(z_values)/1000)**2 / (1+z_values)
    brightness_temperature = brightness_temperature.to_numpy()
    rest_width = CHIME['width_fitb']/(1+z_values)
    frequency_bandwidth = (CHIME['high_freq'] - CHIME['low_freq']) * (1+z_values)
    energy = 1e-23 * CHIME['peak_freq'] * 1e6 * CHIME['fluence'] / 1000 * (4*np.pi*(luminosity_distance_at_z(z_values)*Mpc_to_cm)**2) / (1+z_values)

    CHIME['redshift'] = z_values
    CHIME['bright_temp'] = brightness_temperature
    CHIME['rest_width'] = rest_width
    CHIME['freq_width'] = frequency_bandwidth
    CHIME['energy'] = energy
    CHIME['repeating'] = ['repeating' if row['repeater_name'] != '-9999' else 'non-repeating' for i,row in CHIME.iterrows()]

    return CHIME

def make_confusion_matrix(cf,
                          group_names=None,
                          categories='auto',
                          count=True,
                          percent=True,
                          cbar=True,
                          xyticks=True,
                          xyplotlabels=True,
                          sum_stats=True,
                          figsize=None,
                          cmap='Blues',
                          title=None):

    blanks = ['' for i in range(cf.size)]

    if group_names and len(group_names) == cf.size:
        group_labels = ["{}\n".format(value) for value in group_names]
    else:
        group_labels = blanks

    if count:
        group_counts = ["{0:0.0f}\n".format(value) for value in cf.flatten()]
    else:
        group_counts = blanks

    if percent:
        group_percentages = ["{0:.2%}".format(value) for value in (cf / np.c_[np.sum(cf,axis=1),np.sum(cf,axis=1)]).flatten()]
    else:
        group_percentages = blanks

    box_labels = [f"{v1}{v2}{v3}".strip() for v1, v2, v3 in zip(group_labels, group_counts, group_percentages)]
    box_labels = np.asarray(box_labels).reshape(cf.shape[0], cf.shape[1])

    # CODE TO GENERATE SUMMARY STATISTICS & TEXT FOR SUMMARY STATS
    if sum_stats:
        # Accuracy is sum of diagonal divided by total observations
        accuracy = np.trace(cf) / float(np.sum(cf))

        # if it is a binary confusion matrix, show some more stats
        if len(cf) == 2:
            # Metrics for Binary Confusion Matrices
            precision = cf[1, 1] / sum(cf[:, 1])
            recall = cf[1, 1] / sum(cf[1, :])
            f1_score = 2 * precision * recall / (precision + recall)
            stats_text = "\n\nAccuracy={:0.3f}\nPrecision={:0.3f}\nRecall={:0.3f}\nF1 Score={:0.3f}".format(
                accuracy, precision, recall, f1_score)
        else:
            stats_text = "\n\nAccuracy={:0.3f}".format(accuracy)
    else:
        stats_text = ""

    # SET FIGURE PARAMETERS ACCORDING TO OTHER ARGUMENTS
    if figsize == None:
        # Get default figure size if not set
        figsize = plt.rcParams.get('figure.figsize')

    if xyticks == False:
        # Do not show categories if xyticks is False
        categories = False

    # MAKE THE HEATMAP VISUALIZATION
    plt.figure(figsize=figsize)
    res = sns.heatmap(cf, annot=box_labels, fmt="", cmap=cmap, cbar=cbar, xticklabels=categories, yticklabels=categories)
    for _, spine in res.spines.items():
        spine.set_visible(True)

    if xyplotlabels:
        plt.ylabel('True label')
        plt.xlabel('Predicted label' + stats_text)
    else:
        plt.xlabel(stats_text)

    if title:
        plt.title(title)


import re

import zope.interface
import zope.schema

from pmr2.app.schema.interfaces import InvalidObjectId
from pmr2.app.schema.interfaces import IObjectId, IWorkspaceList, ICurationDict
from pmr2.app.schema.interfaces import ITextLineList

_isobjectid = re.compile(r'^[a-zA-Z0-9_\.\-]*$').match

class ObjectId(zope.schema.BytesLine):
    """\
    This is implemented because zope.schema.Id does not work as
    advertised.
    """

    zope.interface.implements(IObjectId)

    def _validate(self, value):
        """\
        >>> id = ObjectId(__name__='test')
        >>> id.validate("foo")
        >>> id.validate("foo.bar")
        >>> id.validate("foo/bar")
        Traceback (most recent call last):
        ...
        InvalidObjectId: foo/bar
        >>> id.validate("foo bar")
        Traceback (most recent call last):
        ...
        InvalidObjectId: foo bar
        >>> id.validate("http://www.example.org/foo/bar")
        Traceback (most recent call last):
        ...
        InvalidObjectId: http://www.example.org/foo/bar
        """

        super(ObjectId, self)._validate(value)
        if _isobjectid(value):
            return

        raise InvalidObjectId(value)

class WorkspaceList(zope.schema.List):
    """\
    Workspace listing field.
    """

    zope.interface.implements(IWorkspaceList)

class CurationDict(zope.schema.Dict):
    """\
    Curation dictionary.
    """

    zope.interface.implements(
        ICurationDict,
        zope.schema.interfaces.IFromUnicode,
    )

    key_type = zope.schema.TextLine(
        title=u'Key',
    )
    value_type = zope.schema.List(
        title=u'Value',
        value_type=zope.schema.TextLine(title=u'Values',),
    )

    def fromUnicode(self, u):
        """\
        >>> d = CurationDict()
        >>> d.fromUnicode(u'key:value')
        {u'key': [u'value']}
        >>> result = d.fromUnicode(u'key:value\\nkey2:type2\\nkey:value2')
        >>> result[u'key']
        [u'value', u'value2']
        >>> result[u'key2']
        [u'type2']
        """

        result = {}
        for i in u.splitlines():
            k, v = i.split(u':', 1)
            if k not in result:
                result[k] = []
            result[k].append(v)
        return result

class TextLineList(zope.schema.List):
    """\
    Workspace listing field.
    """

    zope.interface.implements(
        ITextLineList,
        zope.schema.interfaces.IFromUnicode,
    )
    value_type = zope.schema.TextLine(title=u'Values',),

    def fromUnicode(self, u):
        """\
        >>> d = TextLineList()
        >>> d.fromUnicode(u'')
        []
        >>> d.fromUnicode(u'test')
        [u'test']
        >>> d.fromUnicode(u'test\\ntest2')
        [u'test', u'test2']
        """

        return u.splitlines()


from collections import Counter, defaultdict
from typing import List, Tuple, Dict

users_interests = [
    ["Hadoop", "Big Data", "HBase", "Java", "Spark", "Storm", "Cassandra"],
    ["NoSQL", "MongoDB", "Cassandra", "HBase", "Postgres"],
    ["Python", "scikit-learn", "scipy", "numpy", "statsmodels", "pandas"],
    ["R", "Python", "statistics", "regression", "probability"],
    ["machine learning", "regression", "decision trees", "libsvm"],
    ["Python", "R", "Java", "C++", "Haskell", "programming languages"],
    ["statistics", "probability", "mathematics", "theory"],
    ["machine learning", "scikit-learn", "Mahout", "neural networks"],
    ["neural networks", "deep learning", "Big Data", "artificial intelligence"],
    ["Hadoop", "Java", "MapReduce", "Big Data"],
    ["statistics", "R", "statsmodels"],
    ["C++", "deep learning", "artificial intelligence", "probability"],
    ["pandas", "R", "Python"],
    ["databases", "HBase", "Postgres", "MySQL", "MongoDB"],
    ["libsvm", "regression", "support vector machines"]
]

# 1. Recommend what is popular
popular_interests = Counter(interest
                            for user_interests in users_interests
                            for interest in user_interests)

def most_popular_new_interests(user_interests: List[str],
                               max_results: int = 5) -> List[Tuple[str, int]]:
    suggestions = [(interest, frequency)
                   for interest, frequency in popular_interests.most_common()
                   if interest not in user_interests]

    return suggestions[:max_results]

# 2. User-Based Collaborative Filtering
unique_interests = sorted({interest
                           for user_interests in users_interests
                           for interest in user_interests})

print(f"The unique interests are: {unique_interests}")

def make_user_interest_vector(user_interests: List[str]) -> List[int]:
    return [1 if interest in user_interests else 0
            for interest in unique_interests]

user_interest_vectors = [make_user_interest_vector(user) for user in users_interests]

from scratch.nlp import cosine_similarity
user_similarities = [[cosine_similarity(interest_vector_i, interest_vector_j)
                      for interest_vector_j in user_interest_vectors]
                     for interest_vector_i in user_interest_vectors]

def most_similar_users_to(user_id: int)->List[Tuple]:
    pairs = [(user, similarity) for user,similarity in enumerate(user_similarities[user_id]) if user != user_id and similarity > 0]
    return sorted(pairs, key=lambda pair: pair[-1], reverse=True)

def user_based_suggestions(user_id: int, include_current_interests: bool = False):
    # Sum up the similarities
    suggestions: Dict[str, float] = defaultdict(float)
    print(most_similar_users_to(user_id))
    for other_user_id, similarity in most_similar_users_to(user_id):
        for interest in users_interests[other_user_id]:
            suggestions[interest] += similarity

    # Convert them to a sorted list
    suggestions = sorted(suggestions.items(),
                         key=lambda pair: pair[-1],  # weight
                         reverse=True)

    # And (maybe) exclude already interests
    if include_current_interests:
        return suggestions
    else:
        return [(suggestion, weight)
                for suggestion, weight in suggestions
                if suggestion not in users_interests[user_id]]

print(user_based_suggestions(1))


# Author: Leyla Noroozbabaee
# Date: 12/12/2021
# To reproduce Figure 1 from original paper, the python file 'Fig1_sim.py' should be run.

import matplotlib.pyplot as plt
import pandas as pd
from sklearn import preprocessing
import numpy as np
# Figure name
prefilename = 'Fig1'

# Set figure dimension (width, height) in inches.
fw, fh = 15, 10
# Set subplots
subpRow, subpCol = 3, 2
ax, lns = {}, {}
# This gives list with the colors from the cycle, which you can use to iterate over.
cycle = plt.rcParams['axes.prop_cycle'].by_key()['color']
# Set subplots
lfontsize, labelfontsize = 10, 15  # legend, label fontsize
fig, axs = plt.subplots(subpRow, subpCol, figsize=(fw, fh), facecolor='w', edgecolor='k')
fig.subplots_adjust(hspace=.3, wspace=.3)
axs = axs.ravel()
var_name = ['Time','fss','dss','f1tc','f2tc','dtc','ical','v','I_Ca_tot']
# Set ylable
tit = ['Steady state','Steady state','Time constant (ms)','Time constant (ms)','I (normalised)','I (normalised)']
# Set Color
cycle = plt.rcParams [ 'axes.prop_cycle' ].by_key() [ 'color' ]

filename = '%s.csv' % (prefilename)
data = pd.read_csv(filename)
print('filename', filename)
data = pd.read_csv(filename)
time = data [ var_name[0] ]
fss_data = data [var_name[1]]
dss_data = data [var_name[2]]
f1tc_data = data [var_name[3]]
f2tc_data = data [var_name[4]]
dtc_data = data [var_name[5]]
ical_data = data [var_name[6]]
v_data = data [var_name[7]]
axs[0].plot( v_data, pow(dss_data,2), 'b')
axs[1].plot( v_data, fss_data, 'b')
axs[2].plot( v_data, dtc_data, 'b')
axs[3].plot( v_data, f1tc_data, 'b',  v_data, f2tc_data, 'b')

I_V = []
prefilename = 'Fig1_5'
filename5 = '%s_%s.csv' % (prefilename, 5)
data5 = pd.read_csv(filename5)
max_ical_data5 = max(abs(data5 ['ical']))
for i in range(11):
    filename = '%s_%s.csv' % (prefilename, i)
    data = pd.read_csv(filename)
    time = data ['Time']
    ical_data = data ['ical']
    max_ical_data = max(data ['ical'])
    print(' max_ical_data ', max_ical_data5)
    if  5<=i<11:
         axs [4].plot( time, ical_data/max_ical_data5, color=cycle [i % 4])
    if max_ical_data  < 0:
        MAX_I_V = (min(ical_data / max_ical_data5))
    else:
        MAX_I_V = (max(ical_data / max_ical_data5))
    I_V.append(MAX_I_V )

V = [50, 40, 30, 20, 10, 0, -10, -20, -30, -40, -50]
print(I_V)
axs[5].plot(V, I_V, '-b')

# To add the extracted data from original paper to your plot, modify the path to have access to the
# "Extracted_data"
prefilename = 'Fig1'
for i in range(6):
    prefilename = 'Extracted_Data/Fig1'
    filename = '%s_%s.csv' % (prefilename, i)
    data = pd.read_csv(filename)
    if i == 3 :
        x_name2 = 'x'
        y_name2 = 'Curve2'
        y_data2 = data [ y_name2 ]
        x_data2 = data [ x_name2 ]
        axs [ i ].plot(x_data2, y_data2, 'k^')
    elif i== 4:
        for j in range(1,6):
            filename = 'Extracted_Data/Fig1_4.csv'
            data = pd.read_csv(filename)
            x_name = 'x'
            y_name = 'Curve%s' %(j)
            x_data = data [ x_name ]
            y_data = data [ y_name ]
            axs [ i ].plot(x_data, y_data, '^')

    x_name = 'x'
    y_name = 'Curve1'
    x_data = data [ x_name ]
    y_data = data [ y_name ]

    axs [ i ].set_ylabel('%s' % (tit [ i ]), fontsize=labelfontsize)
    if i!=4:
       axs [ i ].set_xlim([ -80, 50 ])
       axs [ i ].set_xlabel('V (mV)', fontsize=labelfontsize)
    else:
        axs [ i ].set_xlim([ 0, 60 ])
        axs [ i ].set_xlabel('Time (ms)', fontsize=labelfontsize)
    axs [ i ].plot(x_data, y_data, 'k^')

figfiles = 'Figure_1.png'
plt.savefig(figfiles)
plt.show()


from pymongo import MongoClient
from tkinter import *

root = Tk()
root.geometry("300x300")
client = MongoClient("localhost", 27017)

# insert
def HandleInsert():
    # db
    database = client["student"]
    # collection
    col = database["student_info"]
    name = e1.get()
    col.insert_one({'name': name})
    e1.delete(0, END)
    print("Date successfully inserted...")

l = Label(root, text="Enter Name")
l.grid(row=0, column=1)
e1 = Entry(root)
e1.grid(row=0, column=2)
b1 = Button(root, text="Submit", command=HandleInsert)
b1.grid(row=1, column=2)

root.mainloop()


'''
Created on Oct 20, 2019

@author: camila
'''
import bisect
import sys

import psycopg2
from psycopg2.sql import Identifier, SQL

from ..database.PostGISConnection import PostGISConnection
from ..database.PostgisDataManager import PostgisDataManager
from ..network.MultimodalNetwork import MultimodalNetwork
from ..travel_time_function.ConstantFunction import ConstantFunction
from ..travel_time_function.TimeTable import TimeTable

class CreateTransportationNetwork:

    def __init__(self, region):
        self.region = region
        self.graph = MultimodalNetwork()
        dataManager = PostgisDataManager()
        self.mbr = dataManager.getNetworkMBR(region)
        self.current_node_id = dataManager.getNumNodes(region) + 1

        self.calendar = {}
        self.parent_stops={}
        self.stops = {}
        self.routes_id = []
        self.links = {}

        self.route_transfers = {}
        self.stop_transfers = {}

        self.edges_timetable = {}

        self.conn = PostGISConnection()

    def run(self):
        self.conn.connect()
        self.load()
        self.createTables()
        self.populateTables()
        self.conn.close()

    def createTables(self):
        self.createTableNodes()
        self.createTableEdges()
        self.createTableTimetables()

    def populateTables(self):
        self.populateTableNodes()
        self.populateTableEdgesAndTimetables()

    def createTableNodes(self):
        #node_id, lat, lon, node_type, stop_id=None, route_id=None
        sql = """
        CREATE TABLE IF NOT EXISTS {0} (
            node_id bigint NOT NULL,
            lat double precision NOT NULL,
            long double precision NOT NULL,
            type integer NOT NULL,
            stop_id varchar NULL,
            route_id varchar NULL,
            CONSTRAINT {1} PRIMARY KEY (node_id)
        );
        """
        sql = SQL(sql).format(Identifier("transportation_nodes_"+str(self.region)),
                              Identifier("transportation_nodes_"+str(self.region)+"_pkey"))
        self.conn.executeCommand(sql)

    def populateTableNodes(self):
        print("Creating table nodes...")
        sql = """INSERT INTO {0}(node_id, lat, long, type, stop_id, route_id)
                 VALUES (%s, %s, %s, %s, %s, %s);
            """
        sql = SQL(sql).format(Identifier("transportation_nodes_"+str(self.region)))
        try:
            cursor = self.conn.getCursor()
            for node_id in self.graph.getNodesIds():
                #print(node_id)
                node = self.graph.getNode(node_id)
                if 'type' not in node:
                    continue
                #print(self.region, node_id, node['lat'], node['lon'], node['type'], stop_id, route_id)
                cursor.execute(sql, (node_id, node['lat'], node['lon'], node['type'], node.get('stop_id'), node.get('route_id')))
            self.conn.commit()

        except IOError as e:
            print("I/O error({0}): {1}".format(e.errno, e.strerror))
        except (Exception, psycopg2.DatabaseError) as error:
            print(error)
        except:
            print("Unexpected error:", sys.exc_info()[0])

    def createTableEdges(self):
        #node_from, node_to, edge_type, modes, travel_time_functions, original_edge_id=None, edge_position=None
        sql = """
        CREATE TABLE IF NOT EXISTS {0} (
            source bigint NOT NULL,
            target bigint NOT NULL,
            type integer NOT NULL,
            modes integer[] NOT NULL,
            cost integer NULL,
            timetable_id bigint NULL,
            original_edge_id bigint NULL,
            edge_position integer NULL,
            CONSTRAINT {1} PRIMARY KEY (source, target)
        );
        """
        sql = SQL(sql).format(Identifier("transportation_edges_"+str(self.region)),
                              Identifier("transportation_edges_"+str(self.region) + "_pkey"))
        self.conn.executeCommand(sql)

    def createTableTimetables(self):
        sql = """
        CREATE TABLE IF NOT EXISTS {0} (
            id bigint NOT NULL,
            monday time[] NULL,
            tuesday time[] NULL,
            wednesday time[] NULL,
            thursday time[] NULL,
            friday time[] NULL,
            saturday time[] NULL,
            sunday time[] NULL,
            CONSTRAINT {1} PRIMARY KEY (id)
        );
        """
        sql = SQL(sql).format(Identifier("transportation_timetables_"+str(self.region)),
                              Identifier("transportation_timetables_"+str(self.region) + "_pkey"))
        self.conn.executeCommand(sql)

    def populateTableEdgesAndTimetables(self):
        print("Creating table edges...")
        sql = """INSERT INTO {0}(source, target, type, modes, cost, timetable_id, original_edge_id, edge_position)
                 VALUES (%s, %s, %s, %s, %s, %s, %s, %s);
            """
        sql = SQL(sql).format(Identifier("transportation_edges_"+str(self.region)))

        sql_timetable = """INSERT INTO {}(id, monday, tuesday, wednesday, thursday, friday, saturday, sunday)
                 VALUES (%s, %s, %s, %s, %s, %s, %s, %s);
            """
        sql_timetable = SQL(sql_timetable).format(Identifier("transportation_timetables_"+str(self.region)))
        curr_timetable_id = 0;
        try:
            count = 0
            records = []
            cursor = self.conn.getCursor()
            for edge_id in self.graph.getEdges():
                edge = self.graph.getEdge(edge_id[0], edge_id[1])

                travel_time_functions = edge['travel_time_functions']
                cost = None
                timetable_id = None
                for mode in travel_time_functions:
                    if mode == self.graph.PUBLIC:
                        timetable_id = curr_timetable_id
                        timetable = travel_time_functions[mode].getTable()
                        cursor.execute(sql_timetable, (timetable_id, timetable.get(0), timetable.get(1),
                                                       timetable.get(2), timetable.get(3), timetable.get(4), timetable.get(5), timetable.get(6)))

                        curr_timetable_id += 1
                    else:
                        cost = travel_time_functions[mode].getTravelCost()

                records.append((edge_id[0], edge_id[1], edge['type'], list(edge['modes']), cost, timetable_id,
                                       edge.get('original_edge_id'), edge.get('edge_position')))
                count += 1
                if count % 1000 == 0:
                    #print("Commiting changes...")
                    cursor.executemany(sql, records)
                    self.conn.commit()
                    records = []

            cursor.executemany(sql, records)
            self.conn.commit()
            cursor.close()

        except IOError as e:
            print("I/O error({0}): {1}".format(e.errno, e.strerror))
        except (Exception, psycopg2.DatabaseError) as error:
            print(error)
        except:
            print("Unexpected error:", sys.exc_info()[0])

    def load(self):
        print("Loading GTFS data...")
        self.loadCalendar()
        self.loadStops()
        self.loadRoutes()
        self.loadTrips()
        del self.calendar
        del self.routes_id
        del self.edges_timetable

        #creating links within stations and to the road network
        self.loadLinks()
        self.loadTransferTimes()
        self.addTransfers()

        del self.stops
        del self.parent_stops
        del self.links
        del self.route_transfers
        del self.stop_transfers

    def loadCalendar(self):
        print("Loading calendar...")
        sql = """SELECT service_id, monday, tuesday, wednesday, thursday, friday, saturday, sunday
        FROM {};
        """
        sql = SQL(sql).format(Identifier("calendar_"+str(self.region)))
        try:
            cursor = self.conn.getCursor()
            cursor.execute(sql)

            row = cursor.fetchone()

            while row is not None:
                (service_id, monday, tuesday, wednesday, thursday, friday, saturday, sunday) = row
                self.calendar[service_id] = {0: monday, 1:tuesday, 2:wednesday, 3: thursday,
                                        4:friday, 5:saturday, 6:sunday}
                row = cursor.fetchone()
            cursor.close()
        except IOError as e:
            print("I/O error({0}): {1}".format(e.errno, e.strerror))
        except (Exception, psycopg2.DatabaseError) as error:
            print(error)
        except:
            print("Unexpected error:", sys.exc_info()[0])

    def loadStops(self):
        print("Loading stops...")
        sql = """SELECT stop_id, stop_lat, stop_lon, stop_type, stop_parent
        FROM {};
        """
        sql = SQL(sql).format(Identifier("stops_"+str(self.region)))

        min_lat = float(self.mbr[1])
        min_long = float(self.mbr[0])
        max_lat = float(self.mbr[3])
        max_long = float(self.mbr[2])

        try:
            cursor = self.conn.getCursor()
            cursor.execute(sql)

            row = cursor.fetchone()

            while row is not None:
                (stop_id, stop_lat, stop_lon, stop_type, stop_parent) = row
                if stop_lat >= min_lat and stop_lat <= max_lat and stop_lon >= min_long and stop_lon <= max_long:
                    self.stops[stop_id] = {'lat':stop_lat, 'lon':stop_lon, 'type':stop_type, 'parent':stop_parent}

                row = cursor.fetchone()
            cursor.close()
        except IOError as e:
            print("I/O error({0}): {1}".format(e.errno, e.strerror))
        except (Exception, psycopg2.DatabaseError) as error:
            print(error)
        except:
            print("Unexpected error:", sys.exc_info()[0])

    def loadLinks(self):
        print("Loading links...")
        sql = """SELECT link_id, edge_id, stop_id, source, target, edge_dist, source_ratio, edge_length, ST_X(point_location), ST_Y(point_location)
        FROM {0};
        """
        sql = SQL(sql).format(Identifier("links_"+str(self.region)))

        try:
            cursor = self.conn.getCursor()
            cursor.execute(sql)

            row = cursor.fetchone()

            #parents = self.parent_stops.keys()
            while row is not None:
                (link_id, edge_id, stop_id, source, target, edge_dist, source_ratio, edge_length, lon, lat) = row
                #if stop_id in parents:
                self.links[stop_id] = {'link_id': link_id, 'edge_id': edge_id, 'source':source, 'target':target, 'edge_dist':edge_dist,
                                        'source_ratio':source_ratio, 'edge_length':edge_length, 'lat':lat, 'lon':lon}
                row = cursor.fetchone()
            cursor.close()
        except IOError as e:
            print("I/O error({0}): {1}".format(e.errno, e.strerror))
        except (Exception, psycopg2.DatabaseError) as error:
            print(error)
        except:
            print("Unexpected error:", sys.exc_info()[0])

    def loadTransferTimes(self):
        if self.parent_stops:

            sql_exists = """SELECT EXISTS (
                               SELECT 1
                               FROM   information_schema.tables
                               WHERE  table_name = %s
                           );
            """
            #sql_exists = SQL(sql_exists).format(Identifier("transfers_"+str(self.region)))

            try:
                cursor = self.conn.getCursor()

                cursor.execute(sql_exists, ('transfers_'+str(self.region), ))
                (exists,) = cursor.fetchone()
                if not exists:
                    print("Table does not exist!")
                    return

                print("Loading transfer times...")
                sql = """SELECT from_stop_id, to_stop_id, transfer_type, min_transfer_time, from_route_id, to_route_id, from_trip_id
                FROM {};
                """
                sql = SQL(sql).format(Identifier("transfers_"+str(self.region)))
                cursor.execute(sql)

                row = cursor.fetchone()

                while row is not None:
                    (from_stop_id, to_stop_id, transfer_type, min_transfer_time, from_route_id, to_route_id, from_trip_id) = row
                    if not min_transfer_time:
                        min_transfer_time = MultimodalNetwork.MIN_TRANSFER_TIME
                    if from_stop_id != to_stop_id and not from_trip_id:
                        if not from_route_id:
                            if from_stop_id in self.stop_transfers:
                                self.stop_transfers[from_stop_id][to_stop_id] = min_transfer_time
                            else:
                                self.stop_transfers[from_stop_id] = {to_stop_id : min_transfer_time}
                        else:
                            if from_route_id in self.route_transfers:
                                if to_route_id in self.route_transfers[from_route_id]:
                                    if from_stop_id in self.route_transfers[from_route_id][to_route_id]:
                                        self.route_transfers[from_route_id][to_route_id][from_stop_id][to_stop_id] = min_transfer_time
                                    else:
                                        self.route_transfers[from_route_id][to_route_id][from_stop_id] = {to_stop_id:min_transfer_time}
                                else:
                                    self.route_transfers[from_route_id][to_route_id] = {from_stop_id: {to_stop_id:min_transfer_time}}
                            else:
                                self.route_transfers[from_route_id] = {to_route_id : {from_stop_id: {to_stop_id:min_transfer_time}}}
                    row = cursor.fetchone()

                cursor.close()
            except IOError as e:
                print("I/O error({0}): {1}".format(e.errno, e.strerror))
            except (Exception, psycopg2.DatabaseError) as error:
                print(error)
            except:
                print("Unexpected error:", sys.exc_info()[0])

    def loadRoutes(self):
        print("Loading routes...")
        sql = """SELECT route_id FROM {};
        """
        sql = SQL(sql).format(Identifier("routes_"+str(self.region)))

        try:
            cursor = self.conn.getCursor()
            cursor.execute(sql)

            row = cursor.fetchone()

            while row is not None:
                (route_id,) = row
                self.routes_id.append(route_id)
                row = cursor.fetchone()

            cursor.close()
        except IOError as e:
            print("I/O error({0}): {1}".format(e.errno, e.strerror))
        except (Exception, psycopg2.DatabaseError) as error:
            print(error)
        except:
            print("Unexpected error:", sys.exc_info()[0])

    def loadTrips(self):
        print("Loading trips...")
        sql = """SELECT s.*, t.service_id FROM {0} as s, {1} as t
                WHERE s.trip_id in
                (select trip_id from {1} where route_id=%s) and
                t.trip_id = s.trip_id
                order by trip_id, stop_sequence
                ;
        """
        sql = SQL(sql).format(Identifier("stop_times_"+str(self.region)), Identifier("trips_"+str(self.region)))

        try:
            cursor = self.conn.getCursor()

            for route in self.routes_id:
                #print(route)
                self.edges_timetable = {}
                node_mapping = {}

                cursor.execute(sql, (route, ))

                row = cursor.fetchone()

                previous_trip_id = -1
                previous_node = -1
                previous_departure_time = None
                while row is not None:
                    (trip_id, arrival_time, departure_time, stop_id, stop_sequence, service_id) = row
                    #print(trip_id)

                    if trip_id != previous_trip_id:
                        previous_node = -1

                    if stop_id in node_mapping:
                        node_id = node_mapping[stop_id]

                    else:
                        if stop_id not in self.stops:
                            previous_node = -1
                            row = cursor.fetchone()
                            continue

                        node_id = self.current_node_id
                        node_mapping[stop_id] = node_id

                        stop = self.stops[stop_id]
                        if self.graph.getNode(node_id):
                            print("duplicate node!!", node_id)
                        self.graph.addNode(node_id, stop['lat'], stop['lon'], MultimodalNetwork.TRANSPORTATION, stop_id, route)

                        #print(node_id)
                        if self.stops[stop_id]['parent']:
                            parent = self.stops[stop_id]['parent']
                            if parent in self.parent_stops:
                                self.parent_stops[parent].append(node_id)
                            else:
                                self.parent_stops[parent] = [node_id]
                        elif self.stops[stop_id]['type'] == 0 and not self.stops[stop_id]['parent']:
                            self.parent_stops[stop_id] = [node_id]
                            #print(stop_id, node_id)

                        self.current_node_id += 1
                    row = cursor.fetchone()

                    if previous_node != -1:
                        #create edge from previous_node to node_id
                        self.createTransportationEdge(previous_node, node_id, previous_departure_time, arrival_time, service_id)

                    previous_node = node_id
                    previous_trip_id = trip_id
                    previous_departure_time = departure_time

                self.addTransportationEdges()

            cursor.close()
        except IOError as e:
            print("I/O error({0}): {1}".format(e.errno, e.strerror))
        except (Exception, psycopg2.DatabaseError) as error:
            print(error)
        except:
            print("Unexpected error:", sys.exc_info()[0])

    def addTransportationEdges(self):
        for node_from in self.edges_timetable:
            for node_to in self.edges_timetable[node_from]:
                timetable = self.edges_timetable[node_from][node_to]
                self.graph.addEdge(node_from, node_to, MultimodalNetwork.TRANSPORTATION, {MultimodalNetwork.PUBLIC}, {MultimodalNetwork.PUBLIC:TimeTable(timetable)})
                #print(self.graph.getEdge(node_from, node_to))

    def createTransportationEdge(self, from_node, to_node, departure_time, arrival_time, service_id):
        #print(str(from_node) + "," + str(to_node))
        service = self.calendar[service_id]
        if from_node in self.edges_timetable:
            if to_node in self.edges_timetable[from_node]:
                timetable = self.edges_timetable[from_node][to_node]
                for day in service:
                    if service[day]:
                        self.addNewDeparture(timetable[day], departure_time, arrival_time)
            else:
                timetable = {}
                for i in range(7):
                    timetable[i] = []

                for day in service:
                    if service[day]:
                        self.addNewDeparture(timetable[day], departure_time, arrival_time)

                self.edges_timetable[from_node][to_node] = timetable
        else:
            self.edges_timetable[from_node] = {}
            timetable = {}
            for i in range(7):
                timetable[i] = []

            for day in service:
                if service[day]:
                    self.addNewDeparture(timetable[day], departure_time, arrival_time)
            self.edges_timetable[from_node][to_node] = timetable

    def addNewDeparture(self, list_departures, departure_time, arrival_time):
        if not list_departures:
            bisect.insort(list_departures, [departure_time, arrival_time])
        else:
            pos = bisect.bisect_left(list_departures, [departure_time, arrival_time])
            if pos == len(list_departures) or list_departures[pos] != [departure_time, arrival_time]:
                bisect.insort(list_departures, [departure_time, arrival_time])
        '''
        i = 0
        while i < len(list_departures):
            if list_departures[i][0] == departure_time:
                break
            elif list_departures[i][0] > departure_time:
                list_departures.insert(i, [departure_time, arrival_time])
                break
            else:
                i+=1
        if i == len(list_departures):
            list_departures.append([departure_time, arrival_time])

        '''
    def addTransfers(self):
        print("Adding transfers...")
        for stop in self.links:
            #print(stop)
            #connect the super node to the road network
            stop_id = self.addLinkSuperNodeToRoadNetwork(stop)

            if stop in self.parent_stops:
                list_nodes = self.parent_stops[stop]
                #print(stop, list_nodes)
                for node_from in list_nodes:
                    self.addLinkToSuperNode(node_from, stop_id)
                    for node_to in list_nodes:
                        if node_from != node_to:
                            transfer_time = self.getTransferTime(node_from, node_to)
                            #transfer_time = 0
                            self.graph.addEdge(node_from, node_to, MultimodalNetwork.TRANSFER, {MultimodalNetwork.PEDESTRIAN},
                                           {MultimodalNetwork.PEDESTRIAN:ConstantFunction(transfer_time)})

    def getTransferTime(self, node_from_id, node_to_id):
        node_from = self.graph.getNode(node_from_id)
        node_to = self.graph.getNode(node_to_id)

        stop_from = node_from['stop_id']
        stop_to = node_to['stop_id']
        route_from = node_from['route_id']
        route_to = node_to['route_id']

        transfer_time_stop = MultimodalNetwork.MIN_TRANSFER_TIME
        if stop_from in self.stop_transfers and stop_to in self.stop_transfers[stop_from]:
            transfer_time_stop = self.stop_transfers[stop_from][stop_to]

        if stop_from == stop_to:
            return MultimodalNetwork.MIN_TRANSFER_TIME
        if route_from in self.route_transfers:
            if route_to in self.route_transfers[route_from]:
                if stop_from in self.route_transfers[route_from][route_to] and stop_to in self.route_transfers[route_from][route_to][stop_from]:
                    return self.route_transfers[route_from][route_to][stop_from][stop_to]
                else:
                    return transfer_time_stop

            else:
                return transfer_time_stop
        else:
            return transfer_time_stop

    def addLinkSuperNodeToRoadNetwork(self, super_stop):
        #create super stop node
        if super_stop not in self.stops:
            return
        stop_id = self.current_node_id
        self.current_node_id += 1
        stop = self.stops[super_stop]
        if self.graph.getNode(stop_id):
            print("2 duplicate node!!", stop_id)

        self.graph.addNode(stop_id, stop['lat'], stop['lon'], MultimodalNetwork.SUPER_NODE)
        #print("Adding node:" + str(stop_id))

        link = self.links[super_stop]
        edge_id = link['edge_id']
        source = link['source']
        target = link['target']
        edge_dist = link['edge_dist']
        edge_time = round((edge_dist/MultimodalNetwork.PEDESTRIAN_SPEED)*3600)
        source_ratio = link['source_ratio']

        if source_ratio == 0.0:
            #transfer node is equal to the source
            self.graph.addEdge(stop_id, source, MultimodalNetwork.TRANSFER, {MultimodalNetwork.PEDESTRIAN},
                    {MultimodalNetwork.PEDESTRIAN:ConstantFunction(edge_time)})
            self.graph.addEdge(source, stop_id, MultimodalNetwork.TRANSFER, {MultimodalNetwork.PEDESTRIAN},
                    {MultimodalNetwork.PEDESTRIAN:ConstantFunction(edge_time)})

        elif source_ratio == 1.0:
            #transfer node is equal to the target
            self.graph.addEdge(stop_id, target, MultimodalNetwork.TRANSFER, {MultimodalNetwork.PEDESTRIAN},
                    {MultimodalNetwork.PEDESTRIAN:ConstantFunction(edge_time)})
            self.graph.addEdge(target, stop_id, MultimodalNetwork.TRANSFER, {MultimodalNetwork.PEDESTRIAN},
                    {MultimodalNetwork.PEDESTRIAN:ConstantFunction(edge_time)})

        else:
            node_id = self.current_node_id
            self.current_node_id += 1

            if self.graph.getNode(node_id):
                print("3 duplicate node!!", node_id)

            self.graph.addNode(node_id, link['lat'], link['lon'], MultimodalNetwork.TRANSFER)

            #splitting edge
            length = link['edge_length']
            time_source = round(((source_ratio*length)/MultimodalNetwork.PEDESTRIAN_SPEED)*3600)
            time_target = round((((1-source_ratio)*length)/MultimodalNetwork.PEDESTRIAN_SPEED)*3600)

            self.graph.addEdge(source, node_id, MultimodalNetwork.TRANSFER, {MultimodalNetwork.PEDESTRIAN},
                    {MultimodalNetwork.PEDESTRIAN:ConstantFunction(time_source)}, edge_id, 1)
            self.graph.addEdge(node_id, source, MultimodalNetwork.TRANSFER, {MultimodalNetwork.PEDESTRIAN},
                    {MultimodalNetwork.PEDESTRIAN:ConstantFunction(time_source)}, edge_id, 1)
            self.graph.addEdge(target, node_id, MultimodalNetwork.TRANSFER, {MultimodalNetwork.PEDESTRIAN},
                    {MultimodalNetwork.PEDESTRIAN:ConstantFunction(time_target)},edge_id, 2)
            self.graph.addEdge(node_id, target, MultimodalNetwork.TRANSFER, {MultimodalNetwork.PEDESTRIAN},
                    {MultimodalNetwork.PEDESTRIAN:ConstantFunction(time_target)}, edge_id, 2)

            #connecting new node to super node
            self.graph.addEdge(stop_id, node_id, MultimodalNetwork.TRANSFER, {MultimodalNetwork.PEDESTRIAN},
                    {MultimodalNetwork.PEDESTRIAN:ConstantFunction(edge_time)})
            self.graph.addEdge(node_id, stop_id, MultimodalNetwork.TRANSFER, {MultimodalNetwork.PEDESTRIAN},
                    {MultimodalNetwork.PEDESTRIAN:ConstantFunction(edge_time)})

        return stop_id

    def addLinkToSuperNode(self, node_id, parent_node_id):
        self.graph.addEdge(parent_node_id, node_id, MultimodalNetwork.TRANSFER, {MultimodalNetwork.PEDESTRIAN},
                    {MultimodalNetwork.PEDESTRIAN:ConstantFunction(0)})
        self.graph.addEdge(node_id, parent_node_id, MultimodalNetwork.TRANSFER, {MultimodalNetwork.PEDESTRIAN},
                    {MultimodalNetwork.PEDESTRIAN:ConstantFunction(0)})

    '''
    def addLinkToRoadNetworkSourceTarget(self, node_id, parent):
        link = self.links[parent]
        source = self.osm_mapping[link['source']]
        target = self.osm_mapping[link['target']]
        #print(source, node_id, target)
        source_dist = link['source_dist']
        source_time = round((source_dist/self.graph.PEDESTRIAN_SPEED)*3600)
        target_dist = link['source_dist']
        target_time = round((target_dist/self.graph.PEDESTRIAN_SPEED)*3600)

        #each node is connected to the source and target nodes in the road network

        self.graph.addEdge(source, node_id, self.graph.TRANSFER, {self.graph.PEDESTRIAN},
                                       {self.graph.PEDESTRIAN:ConstantFunction(source_time)})
        self.graph.addEdge(node_id, source, self.graph.TRANSFER, {self.graph.PEDESTRIAN},
                                       {self.graph.PEDESTRIAN:ConstantFunction(source_time)})
        self.graph.addEdge(node_id, target, self.graph.TRANSFER, {self.graph.PEDESTRIAN},
                                       {self.graph.PEDESTRIAN:ConstantFunction(target_time)})
        self.graph.addEdge(target, node_id, self.graph.TRANSFER, {self.graph.PEDESTRIAN},
                                       {self.graph.PEDESTRIAN:ConstantFunction(target_time)})

    '''


from pydantic.error_wrappers import ValidationError

from db.database import Database
from models.base_record_manager import BaseRecordManager
from models.service_account.service_account_model import (
    SERVICE_ACCOUNT_MODEL_NAME, ServiceAccount, ServiceAccountCreate,
    ServiceAccountPartial)

class ServiceAccountManager(BaseRecordManager):
    """ServiceAccountManager to handle CRUD functionality"""

    model = ServiceAccount
    model_name = SERVICE_ACCOUNT_MODEL_NAME

    @classmethod
    def create(cls, db: Database, record: ServiceAccountCreate) -> ServiceAccount:
        """Creates a new ServiceAccount after validating subjects.

        Arguments:
            db {Database} -- Database connection
            record {ServiceAccountCreate} -- New ServiceAccount data

        Returns:
            ServiceAccount -- newly created service_account
        """
        existing_service_account = ServiceAccountManager.find_by_name(
            db, record.metadata.name)
        if existing_service_account:
            raise ValidationError(
                "ServiceAccount with name [%s] already exists" % record.metadata.name)

        return super(ServiceAccountManager, cls).create(db, record)

    @classmethod
    def update(cls, db: Database, record_uuid: str, record: ServiceAccountPartial) -> ServiceAccount:
        """Updates the existing ServiceAccount after validating data

        Arguments:
            db {Database} -- Database connection
            record_uuid {str} -- unique record uuid
            record {BaseModel} -- updating record

        Returns:
            BaseRecord -- Updated record
        """
        existing_service_account = cls.find_by_uuid(db, record_uuid)
        updated_record = cls.model(**record.dict(), uuid=record_uuid)
        if updated_record.metadata.name != existing_service_account.metadata.name:
            if ServiceAccountManager.find_by_name(db, updated_record.metadata.name):
                raise ValidationError(
                    "ServiceAccount with name [%s] already exists" % record.metadata.name)

        return super(ServiceAccountManager, cls).update(db, record_uuid, record)


#座間市HP ハザードマップPDFをDL href要素のテキスト表示部分を抜き出して保存
#座間市HP　https://www.city.zama.kanagawa.jp/www/contents/1613713435129/index.html
#1.ハザードマップ（洪水浸水想定区域凡例等）(647KB)(PDF文書)　だったら、
#1.ハザードマップ（洪水浸水想定区域凡例等）(647KB)(PDF文書).pdfで保存する
import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin
from pathlib import Path
import time

url = "https://www.city.zama.kanagawa.jp/www/contents/1613713435129/index.html"
request = requests.get(url)
print(request.status_code)

#ハザードマップはa hrefに保存されている
soup = BeautifulSoup(request.content,"html.parser")
a_elments = soup.select("a")
print(a_elments)

#hrefのリンクから、pdfファイルのリンクを抜き出す
pdf_url_list = []
#href文書を抜き出す
dic_txtname = {}

#https://www.twilio.com/blog/web-scraping-and-parsing-html-in-python-with-beautiful-soup-jp
#soup.find_all()はWebスクレイピングで最もよく使われるメソッドです。これによりページのすべてのハイパーリンクを反復してURLを出力できます。
for link in soup.find_all("a"):
    href = link.get("href")
    if href.endswith(".pdf"):
        #print(href)
        pdf_url = urljoin(url,href)
        print(pdf_url)
        pdf_url_list.append(pdf_url)
        lntxt = link.getText()
        dic_txtname[pdf_url] = lntxt

print(dic_txtname)
save_folder_path = Path("../learning/Download_Zama")
save_folder_path.mkdir(exist_ok=True)

for r in pdf_url_list:
    r_file = requests.get(r)
    if r_file.status_code == 200:
        print("yes")
        for k,v in dic_txtname.items():
            if k == r :
                save_file = Path(v + ".pdf")
                print(save_file)
                save_path = save_folder_path / save_file
                with save_path.open("wb") as f:
                    f.write(r_file.content)
    else:
        print("no")

    time.sleep(3)