# python 3.8.1

from web3 import Web3
import pandas as pd
import json
import sys
import requests
from terra_sdk.client.lcd import LCDClient

if len(sys.argv) == 1:
    print('Please pass csv file of (chain,address) to read')
    sys.exit(0)

# hardcoded erc20 abi for reading ERC20 contracts
erc20_abi = [
    {
        "constant": True,
        "inputs": [],
        "name": "name",
        "outputs": [
            {
                "name": "",
                "type": "string"
            }
        ],
        "payable": False,
        "stateMutability": "view",
        "type": "function"
    },
    {
        "constant": False,
        "inputs": [
            {
                "name": "_spender",
                "type": "address"
            },
            {
                "name": "_value",
                "type": "uint256"
            }
        ],
        "name": "approve",
        "outputs": [
            {
                "name": "",
                "type": "bool"
            }
        ],
        "payable": False,
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "constant": True,
        "inputs": [],
        "name": "totalSupply",
        "outputs": [
            {
                "name": "",
                "type": "uint256"
            }
        ],
        "payable": False,
        "stateMutability": "view",
        "type": "function"
    },
    {
        "constant": False,
        "inputs": [
            {
                "name": "_from",
                "type": "address"
            },
            {
                "name": "_to",
                "type": "address"
            },
            {
                "name": "_value",
                "type": "uint256"
            }
        ],
        "name": "transferFrom",
        "outputs": [
            {
                "name": "",
                "type": "bool"
            }
        ],
        "payable": False,
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "constant": True,
        "inputs": [],
        "name": "decimals",
        "outputs": [
            {
                "name": "",
                "type": "uint8"
            }
        ],
        "payable": False,
        "stateMutability": "view",
        "type": "function"
    },
    {
        "constant": True,
        "inputs": [
            {
                "name": "_owner",
                "type": "address"
            }
        ],
        "name": "balanceOf",
        "outputs": [
            {
                "name": "balance",
                "type": "uint256"
            }
        ],
        "payable": False,
        "stateMutability": "view",
        "type": "function"
    },
    {
        "constant": True,
        "inputs": [],
        "name": "symbol",
        "outputs": [
            {
                "name": "",
                "type": "string"
            }
        ],
        "payable": False,
        "stateMutability": "view",
        "type": "function"
    },
    {
        "constant": False,
        "inputs": [
            {
                "name": "_to",
                "type": "address"
            },
            {
                "name": "_value",
                "type": "uint256"
            }
        ],
        "name": "transfer",
        "outputs": [
            {
                "name": "",
                "type": "bool"
            }
        ],
        "payable": False,
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "constant": True,
        "inputs": [
            {
                "name": "_owner",
                "type": "address"
            },
            {
                "name": "_spender",
                "type": "address"
            }
        ],
        "name": "allowance",
        "outputs": [
            {
                "name": "",
                "type": "uint256"
            }
        ],
        "payable": False,
        "stateMutability": "view",
        "type": "function"
    },
    {
        "payable": True,
        "stateMutability": "payable",
        "type": "fallback"
    },
    {
        "anonymous": False,
        "inputs": [
            {
                "indexed": True,
                "name": "owner",
                "type": "address"
            },
            {
                "indexed": True,
                "name": "spender",
                "type": "address"
            },
            {
                "indexed": False,
                "name": "value",
                "type": "uint256"
            }
        ],
        "name": "Approval",
        "type": "event"
    },
    {
        "anonymous": False,
        "inputs": [
            {
                "indexed": True,
                "name": "from",
                "type": "address"
            },
            {
                "indexed": True,
                "name": "to",
                "type": "address"
            },
            {
                "indexed": False,
                "name": "value",
                "type": "uint256"
            }
        ],
        "name": "Transfer",
        "type": "event"
    }
]

# default dev RPCs
web3_evm_providers = {
    'eth': Web3(Web3.HTTPProvider('https://eth-mainnet.alchemyapi.io/v2/demo')),
    'avax': Web3(Web3.HTTPProvider('https://api.avax.network/ext/bc/C/rpc')),
    'ftm': Web3(Web3.HTTPProvider('https://rpc.ftm.tools')),
    'matic': Web3(Web3.HTTPProvider('https://polygon-rpc.com')),
    'oasis': Web3(Web3.HTTPProvider('https://emerald.oasis.dev')),
    'bsc': Web3(Web3.HTTPProvider('https://bsc-dataseed.binance.org')),
    'aurora': Web3(Web3.HTTPProvider('https://mainnet.aurora.dev')),
}
terra_client = LCDClient(chain_id="columbus-5", url="https://lcd.terra.dev")

# solana tokens
r = requests.get('https://raw.githubusercontent.com/solana-labs/token-list/main/src/tokens/solana.tokenlist.json')
solana_tokens = r.json()
print(solana_tokens)

# to store decimals for all contracts
output_decimals = {}

def evmDecimals(origin, sourceAddrRaw):
    sourceAddr = Web3.toChecksumAddress(sourceAddrRaw)

    output_key = origin + '_' + sourceAddr
    if output_key in output_decimals:
        return

    originProvider = web3_evm_providers[origin]
    originContract = originProvider.eth.contract(sourceAddr, abi=erc20_abi)
    symbol = originContract.functions.symbol().call()
    decimals = originContract.functions.decimals().call()

    print(origin, symbol, decimals)
    output_decimals[output_key] = decimals

def solDecimals(sourceAddr):
    output_key = 'sol_' + sourceAddr
    if output_key in output_decimals:
        return

    for token_data in solana_tokens['tokens']:
        if token_data['address'] == sourceAddr:
            print('sol', token_data['symbol'], token_data['decimals'])
            output_decimals[output_key] = token_data['decimals']
            break

def terraDecimals(sourceAddr):
    output_key = 'terra_' + sourceAddr
    if output_key in output_decimals:
        return

    if sourceAddr == 'uusd' or sourceAddr == 'uluna':
        print('terra', sourceAddr, 6)
        output_decimals['terra_' + sourceAddr] = 6
        return

    contract_info = terra_client.wasm.contract_info(sourceAddr)
    decimals = contract_info['init_msg']['decimals']
    symbol = contract_info['init_msg']['symbol']
    print('terra', symbol, decimals)
    output_decimals['terra_' + sourceAddr] = decimals

def getTokenData(chain, raw_addr):
    if chain == 'sol':
        solDecimals(raw_addr)
    elif chain == 'terra':
        terraDecimals(raw_addr)
    else:
        evmDecimals(chain, raw_addr)

# given an input csv file of format (chain, address), where address is assumed to be a contract
# iterate through and get token data for the contract at each address
# see example_input.csv
df = pd.read_csv(sys.argv[1], header=None)
for _, row in df.iterrows():
    getTokenData(row[0], row[1])

# output as decimals_output.json with the decimals from RPC
f = open('decimals_output.json', 'w')
json.dump(output_decimals, f)
f.close()


# -*- coding: utf-8 -*-
import scrapy

class RecipesSpider(scrapy.Spider):
    name = 'recipes'
    allowed_domains = ['https://www.myrecipes.com/']
    start_urls = [
        'https://www.myrecipes.com/recipe/mediterranean-tuna-salad-2'
        ]

    def parse(self, response):
        title = response.\
            xpath('//*[@class="headline heading-content"]/text()')\
            .extract_first()

        totalTime = response.\
            xpath('//*[@class="recipe-meta-item-body"]/text()')\
            .extract_first().strip()

        ingredients = response.\
            xpath('//*[@class="ingredients"]/ul/li/text()').extract()

        instructions = response.\
            xpath('//*[@class="step"]/p/text()').extract()

        nutrients = response.\
            xpath('//*[@class="partial recipe-nutrition"]/ul/li/text()').\
            extract()

        yield {
            'Title': title,
            'TotalTime': totalTime,
            'Ingredients': ingredients,
            'Instructions': instructions,
            'Nutrients': nutrients
        }


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

import matplotlib.pyplot as plt
import numpy as np
import os, os.path
import functools
import tensorflow as tf
import progressbar
from string import Formatter

tf.enable_eager_execution()

CELEBA_PATH_AMZ = "https://s3-us-west-1.amazonaws.com/udacity-dlnfd/datasets/celeba.zip"
NOISE_SIZE = 100

if not tf.test.is_gpu_available():
    print("No GPU")
else:
    from tensorflow.python.client import device_lib
    print(device_lib.list_local_devices())

def custom_progress_text(message):

    message_ = message.replace('(', '{')
    message_ = message_.replace(')', '}')

    keys = [key[1] for key in Formatter().parse(message_)]

    ids = {}
    for key in keys:
        if key is not None:
            ids[key] = float('nan')

    msg = progressbar.FormatCustomText(message, ids)
    return msg

def create_progress_bar(text=None):

    if text is None:
        text = progressbar.FormatCustomText('')
    bar = progressbar.ProgressBar(widgets=[
        progressbar.Percentage(),
        progressbar.Bar(),
        progressbar.AdaptiveETA(), '  ',
        text,
    ])
    return bar

def dowload_images(url=CELEBA_PATH_AMZ):

    path_to_faces = tf.keras.utils.get_file("celebs.zip", url, extract=True)
    img_path = os.path.join(os.path.split(path_to_faces)[0], 'img_align_celeba')

    image_list = []
    for each in os.listdir(img_path):
        full_path = os.path.join(img_path, each)
        if os.path.isfile(full_path):
            image_list.append(full_path)

    return image_list

def create_dataset(image_list, batch_size=50, randomize=True):

    dataset = tf.data.Dataset.from_tensor_slices(image_list)

    # mapping function to load and resize the images
    def load_image(filename, width=56, height=56):
        image_string = tf.read_file(filename)
        image = tf.image.decode_jpeg(image_string)
        image = tf.image.convert_image_dtype(image, tf.float32)

        if image.shape[:2] != [width, height]:
            image = tf.image.crop_to_bounding_box(image, 40, 20, 218 - 80, 178 - 40)
            image = tf.image.resize(image, [width, height])

        return image

    dataset = dataset.map(load_image)
    dataset = dataset.repeat()

    if randomize:
        dataset = dataset.shuffle(len(image_list))

    if batch_size > 0:
        dataset = dataset.batch(batch_size)

    return dataset

def create_generator(noise_shape=(100, 0), show=False):

    BatchNormalization = tf.keras.layers.BatchNormalization
    Dense = tf.keras.layers.Dense
    Conv2DTranspose = tf.keras.layers.Conv2DTranspose
    LeakyReLU = tf.keras.layers.LeakyReLU

    model = tf.keras.Sequential([
        Dense(4 * 4 * 1024, use_bias=False, input_shape=noise_shape, activation='relu'),
        BatchNormalization(),
        tf.keras.layers.Reshape((4, 4, 1024)),

        Conv2DTranspose(filters=512, kernel_size=[4, 4], strides=1),
        BatchNormalization(),
        LeakyReLU(),

        Conv2DTranspose(filters=256, kernel_size=[5, 5], strides=2, padding="same"),
        BatchNormalization(),
        LeakyReLU(),

        Conv2DTranspose(filters=128, kernel_size=[5, 5], strides=2, padding="same"),

        BatchNormalization(),
        LeakyReLU(),

        Conv2DTranspose(filters=3, kernel_size=[5, 5], strides=2, padding="same")

    ], name="Generator")

    if show:
        print(model.summary())

    return model

def create_discriminator(show=False, drop_rate=0.3):

    BatchNormalization = tf.keras.layers.BatchNormalization
    Dense = tf.keras.layers.Dense
    Conv2D = functools.partial(tf.keras.layers.Conv2D, padding='same')
    LeakyReLU = tf.keras.layers.LeakyReLU
    DropOut = tf.keras.layers.Dropout

    model = tf.keras.Sequential([
        Conv2D(filters=64, kernel_size=[5, 5], strides=[2, 2], input_shape=(56, 56, 3)),
        BatchNormalization(),
        LeakyReLU(),
        DropOut(drop_rate),

        Conv2D(filters=128, kernel_size=[5, 5], strides=[2, 2]),
        BatchNormalization(),
        LeakyReLU(),
        DropOut(drop_rate),

        Conv2D(filters=256, kernel_size=[5, 5], strides=[2, 2]),
        BatchNormalization(),
        LeakyReLU(),
        DropOut(drop_rate),

        tf.keras.layers.Flatten(name="Disc_Flat"),

        Dense(1, name="Disc_Logit")

    ], name="Discriminator")
    if show:
        print(model.summary())
    return model

def train_model(nb_epochs, batch_size, disp_freq, save_freq, destination, learning_rate = 2.5e-4, beta1 = 0.45):

    iamges_list = dowload_images()
    nb_images = len(iamges_list)

    dataset = create_dataset(iamges_list, batch_size=batch_size)

    iterator = dataset.make_one_shot_iterator()

    iterator.get_next().shape

    generator = create_generator((NOISE_SIZE,))
    discriminator = create_discriminator()

    gen_optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate, beta1=beta1,
                                           name="Generator_Optimizer")  # define our optimizer
    disc_optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate, beta1=beta1,
                                            name="Discriminator_Optimizer")  # define our optimizer

    checkpoint = tf.train.Checkpoint(gen_optimizer=gen_optimizer, disc_optimizer=disc_optimizer, generator=generator,
                                     discriminator=discriminator)
    checkpoint_prefix = os.path.join(destination, "ckpt")

    checkpoint.restore(tf.train.latest_checkpoint(checkpoint_prefix))

    gen_labels = np.ones((batch_size, 1)).astype(np.float32)
    disc_labels = np.concatenate([np.zeros((batch_size, 1)), np.ones((batch_size, 1))]).astype(np.float32)

    for epoch in range(nb_epochs):

        custom_msg = custom_progress_text("Epoch: %(epoch).0f Gen loss: %(gen_loss)2.2f Disc loss: %(disc_loss)2.2f")
        bar = create_progress_bar(custom_msg)

        for idx in bar(range(nb_images // batch_size)):
            batch = iterator.get_next()
            # draw a batch of random
            noise = np.random.uniform(-1, 1, (batch_size, NOISE_SIZE)).astype(np.float32)

            with tf.GradientTape() as gen_tape, tf.GradientTape() as disc_tape:
                gen_images = generator(noise)

                gen_logits = discriminator(gen_images)
                gen_loss = tf.nn.sigmoid_cross_entropy_with_logits(labels=gen_labels, logits=gen_logits)
                # print("loss shape {}".format(gen_loss.shape))

                real_logits = discriminator(batch)

                disc_logits = tf.concat([gen_logits, real_logits], axis=0)
                disc_loss = tf.nn.sigmoid_cross_entropy_with_logits(labels=disc_labels, logits=disc_logits)

            grads = gen_tape.gradient(gen_loss, generator.variables)
            gen_optimizer.apply_gradients(zip(grads, generator.variables))

            grads = disc_tape.gradient(disc_loss, discriminator.variables)
            disc_optimizer.apply_gradients(zip(grads, discriminator.variables))

            custom_msg.update_mapping(epoch=epoch, gen_loss=gen_loss.numpy().mean(), disc_loss=disc_loss.numpy().mean())

            if (idx + 1) % (nb_images // batch_size // disp_freq) == 0:
                noise = np.random.uniform(-1, 1, (25, NOISE_SIZE)).astype(np.float32)
                gen_images = generator(noise)
                plt.figure(figsize=(10, 10))
                for i in range(25):
                    plt.subplot(5, 5, i + 1)
                    plt.imshow(gen_images[i])
                    plt.grid(False)
                    plt.axis("off")
                filename = os.path.join(destination, "Picture-{}-{}.png".format(epoch, idx))
                plt.savefig(filename)

            if (idx + 1) % (nb_images // batch_size // save_freq) == 0:
                checkpoint.save(file_prefix=checkpoint_prefix)

if __name__ == "__main__":
    import argparse

    parser = argparse.ArgumentParser(description='Train gan on celebrity faces.')
    parser.add_argument('--epochs', type=int, default=20)
    parser.add_argument('--batch-size', type=int, default=50)
    parser.add_argument('--disp-freq', type=int, default=1)
    parser.add_argument('--save-freq', type=int, default=2)
    parser.add_argument('--dest', required=True)

    args = parser.parse_args()

    assert(os.path.isdir(args.dest))

    train_model(nb_epochs=args.epochs, batch_size=args.batch_size, disp_freq=args.disp_freq,
                save_freq=args.save_freq, destination=args.dest)


import random
from datetime import datetime
import requests
from fake_useragent import UserAgent
from bs4 import BeautifulSoup
from opencc import OpenCC
import asyncio
import edge_tts
import os
import re

ua = UserAgent()

now = datetime.now()

seed = now.timestamp()
random.seed(seed)

converter = OpenCC('s2t')

headers = {
    "Accept-Encoding": "gzip, deflate, br",
    "Accept-Language": "zh-TW,zh;q=0.9",
    "Sec-Fetch-Dest": "document",
    "Sec-Fetch-Mode": "navigate",
    "Sec-Fetch-Site": "none",
    "Upgrade-Insecure-Requests": "1",
    "User-Agent": ua.random,
    "Connection": "keep-alive",
    "Host": "www.uukanshu.com",
    "Referer": "https://www.uukanshu.com/",
}

def get_page(url):
    response = requests.get(url, headers=headers)
    return response.text

def page_data(soup):
    page = get_page(url)
    soup = BeautifulSoup(page, 'html.parser')

    timu = converter.convert(soup.find(id="timu").text)
    content = converter.convert(soup.find('div', id='contentbox').text)

    next_link = 'https://www.uukanshu.com' + soup.find('a', id='next')['href']

    content = re.sub(r'\[a-z\]', '', content)

    replace_list = [' ', ',', '\n', '\r', '\u3000', '“', '”',
                    '未完待續', '*', '未完待續', '.', '.', '�', 'uanu', 'UU看書']

    for i in replace_list:
        content = content.replace(i, '\r')

    data_list = content.split('\r')
    data_list = [x for x in data_list if x != '']

    return timu, next_link, data_list

def generate_audio_name(title):
    if '章' in title:
        title = int(title.split('第')[1].split('章')[0])
    elif '節' in title:
        title = int(title.split('第')[1].split('節')[0])
    return title

async def main(output, text):
    voice = "zh-CN-YunyangNeural"
    tts = edge_tts.Communicate(text, voice)
    await tts.save(output)

if __name__ == '__main__':

    text_folder = './text_file'

    url = input('Please enter the URL of your starting UU novel page:')

    if url != '':

        copy_page = int(input('How many pages do you want to copy: '))
        zip_file = input(
            'Whether to compress multiple-page document into a single audio file? (y/n):')

        if zip_file == 'y':

            zip_page = int(input('How many pages do you want to compress:'))

            if isinstance(copy_page, int):
                if not os.path.exists(text_folder):
                    os.makedirs(text_folder)
                print(f'Start copy: {now.strftime("%H:%M:%S")}')

                first_title = ''
                last_title = ''
                first_url = ''
                last_url = ''

                for i in range(copy_page//zip_page):
                    total_text = ''

                    for k in range(zip_page):
                        title, url, text = page_data(url)
                        text = ''.join(text)
                        total_text += text
                        if k == 0:
                            first_url = url
                            first_title = title
                        last_url = url
                        last_title = title

                    now = datetime.now()
                    audio_name = f'{first_title}節_{last_title}節.wav'

                    try:
                        first_title = generate_audio_name(first_title)
                        last_title = generate_audio_name(last_title)

                        with open('./audio_file/url.txt', 'w', encoding='utf-8') as file:
                            file.write(
                                f'first page:{first_url}\n last page:{last_url}')

                        if not os.path.exists(f'./audio_file/第{first_title}節_第{last_title}節.wav'):
                            asyncio.run(
                                main(f'./audio_file/第{first_title}節_第{last_title}節.wav', total_text))
                            pass

                        print(
                            f"Copy {first_title}_{last_title} done. Passed time: {str(datetime.now() - now).split('.')[0]}.")

                    except IndexError:
                        print('Title format error')
        else:
            if isinstance(copy_page, int):

                if not os.path.exists(text_folder):
                    os.makedirs(text_folder)

                print(f'Start copy: {now.strftime("%H:%M:%S")}')

                for i in range(copy_page):
                    title, url, text = page_data(url)
                    text = ''.join(text)
                    now = datetime.now()

                    if not os.path.exists(f'./audio_file/{title}.wav'):
                        asyncio.run(main(f'./audio_file/{title}.wav', text))

                    time_taken = datetime.now() - now
                    print(
                        f'Copy of {title} is done. Time taken: {str(time_taken).split(".")[0]}')

                    with open('./audio_file/Last_url.txt', 'w', encoding='utf-8') as file:
                        file.write(url)


from decimal import Decimal
import typing
from urllib.parse import urljoin

import pydantic
from pydantic.error_wrappers import ValidationError
from pyrsistent import pmap
from typing_extensions import TypedDict

from noobit_markets.base.request import (
    retry_request,
    _validate_data,
)

# Base
from noobit_markets.base import ntypes
from noobit_markets.base.models.result import Result, Err
from noobit_markets.base.models.rest.response import NoobitResponseSymbols, NoobitResponseTrades, T_PublicTradesParsedRes, T_PublicTradesParsedItem
from noobit_markets.base.models.rest.request import NoobitRequestTrades
from noobit_markets.base.models.frozenbase import FrozenBaseModel

# binance
from noobit_markets.exchanges.binance import endpoints
from noobit_markets.exchanges.binance.rest.base import get_result_content_from_req

__all__ = (
    "get_trades_binance"
)

# ============================================================
# BINANCE REQUEST
# ============================================================

class BinanceRequestTrades(FrozenBaseModel):

    symbol: str
    limit: pydantic.PositiveInt

class _ParsedReq(TypedDict):
    symbol: typing.Any
    limit: typing.Any

def parse_request(
        valid_request: NoobitRequestTrades,
        symbol_to_exchange: ntypes.SYMBOL_TO_EXCHANGE
    ) -> _ParsedReq:

    payload: _ParsedReq = {
        "symbol": symbol_to_exchange(valid_request.symbol),
        "limit": 1000
    }

    return payload

#============================================================
# BINANCE RESPONSE
#============================================================

# SAMPLE RESPONSE

# [
#   {
#     "id": 28457,
#     "price": "4.00000100",
#     "qty": "12.00000000",
#     "quoteQty": "48.000012",
#     "time": 1499865549590,
#     "isBuyerMaker": true,
#     "isBestMatch": true
#   }
# ]

class _SingleTrade(FrozenBaseModel):
    id: int
    price: Decimal
    qty: Decimal
    quoteQty: Decimal
    time: int
    isBuyerMaker: bool
    isBestMatch: bool

class BinanceResponseTrades(FrozenBaseModel):

    trades: typing.Tuple[_SingleTrade, ...]

def parse_result(
        result_data: BinanceResponseTrades,
        symbol: ntypes.SYMBOL
    ) -> T_PublicTradesParsedRes:

    parsed_trades = [_single_trade(data, symbol) for data in result_data.trades]

    return tuple(parsed_trades)

def _single_trade(
        data: _SingleTrade,
        symbol: ntypes.SYMBOL
    ) -> T_PublicTradesParsedItem:

    parsed: T_PublicTradesParsedItem = {
        "symbol": symbol,
        "orderID": None,
        "trdMatchID": None,
        # noobit timestamp = ms
        "transactTime": data.time,
        "side": "BUY" if data.isBuyerMaker is False else "SELL",
        # binance only lists market order
        # => trade = limit order lifted from book by market order
        "ordType": "MARKET",
        "avgPx": data.price,
        "cumQty": data.quoteQty,
        "grossTradeAmt": data.price * data.quoteQty,
        "text": None
    }

    return parsed

# ============================================================
# FETCH
# ============================================================

@retry_request(retries=pydantic.PositiveInt(10), logger=lambda *args: print("===xxxxx>>>> : ", *args))
async def get_trades_binance(
        client: ntypes.CLIENT,
        symbol: ntypes.SYMBOL,
        symbols_resp: NoobitResponseSymbols,
        since: typing.Optional[ntypes.TIMESTAMP] = None,
        # prevent unintentional passing of following args
        *,
        logger: typing.Optional[typing.Callable] = None,
        base_url: pydantic.AnyHttpUrl = endpoints.BINANCE_ENDPOINTS.public.url,
        endpoint: str = endpoints.BINANCE_ENDPOINTS.public.endpoints.trades,
    ) -> Result[NoobitResponseTrades, Exception]:

    symbol_to_exchange = lambda x : {k: v.exchange_pair for k, v in symbols_resp.asset_pairs.items()}[x]

    req_url = urljoin(base_url, endpoint)
    method = "GET"
    headers: typing.Dict = {}

    valid_noobit_req = _validate_data(NoobitRequestTrades,  pmap({"symbol": symbol, "symbols_resp": symbols_resp, "since": since}))
    if isinstance(valid_noobit_req, Err):
        return valid_noobit_req

    if logger:
        logger(f"Trades- Noobit Request : {valid_noobit_req.value}")

    parsed_req = parse_request(valid_noobit_req.value, symbol_to_exchange)

    valid_binance_req = _validate_data(BinanceRequestTrades, pmap(parsed_req))
    if valid_binance_req.is_err():
        return valid_binance_req

    if logger:
        logger(f"Trades - Parsed Request : {valid_binance_req.value}")

    result_content = await get_result_content_from_req(client, method, req_url, valid_binance_req.value, headers)
    if result_content.is_err():
        return result_content

    if logger:
        logger(f"Trades - Result Content : {result_content.value}")

    valid_result_content = _validate_data(BinanceResponseTrades, pmap({"trades" :result_content.value}))
    if valid_result_content.is_err():
        return valid_result_content

    parsed_result = parse_result(valid_result_content.value, symbol)

    valid_parsed_response_data = _validate_data(NoobitResponseTrades, pmap({"trades": parsed_result, "rawJson": result_content.value, "exchange": "BINANCE"}))
    return valid_parsed_response_data


import numpy as np

import util.math.interpolate
import util.math.spherical

import util.logging

class Time_Periodic_Earth_Interpolator(util.math.interpolate.Periodic_Interpolator):

    def __init__(self, data_points, data_values, t_len, wrap_around_amount=0, number_of_linear_interpolators=1, single_overlapping_amount_linear_interpolators=0, parallel=False):
        from measurements.constants import EARTH_RADIUS

        util.logging.debug('Initiating time periodic earth interpolator with {} data points, time len {}, wrap around amount {} and {} linear interpolators with single overlapping amount of {}.'.format(len(data_points), t_len, wrap_around_amount, number_of_linear_interpolators, single_overlapping_amount_linear_interpolators))

        # call super constructor
        self.order = number_of_linear_interpolators

        t_scaling = 2 * EARTH_RADIUS / t_len

        super().__init__(
            data_points, data_values,
            point_range_size=(t_len, None, None, None),
            wrap_around_amount=(wrap_around_amount, 0, 0, 0),
            scaling_values=(t_scaling, None, None, None),
            number_of_linear_interpolators=number_of_linear_interpolators,
            single_overlapping_amount_linear_interpolators=single_overlapping_amount_linear_interpolators,
            parallel=parallel)

        assert len(self._data_points) == len(self._data_values) == len(self._data_indices)

    def _modify_points(self, points, is_data_points):
        from measurements.constants import EARTH_RADIUS, MAX_SEA_DEPTH

        points = super()._modify_points(points, is_data_points)

        # if data points, append values for lower and upper bound of depth
        if self.order > 0 and is_data_points:
            lower_depth = 0
            lower_depth_bound = np.min(points[:, 3])
            upper_depth = MAX_SEA_DEPTH
            upper_depth_bound = np.max(points[:, 3])

            util.logging.debug('Lower depth is {}, upper depth is {}.'.format(lower_depth, upper_depth))

            assert lower_depth_bound >= lower_depth and upper_depth_bound <= upper_depth

            if lower_depth_bound > lower_depth:
                lower_depth_bound_indices = np.where(np.isclose(points[:, 3], lower_depth_bound))[0]
                lower_depth_bound_points = points[lower_depth_bound_indices]
                lower_depth_bound_points[:, 3] = lower_depth
                util.logging.debug('{} values appended for lower bound {}.'.format(len(lower_depth_bound_indices), lower_depth))
            else:
                lower_depth_bound_indices = np.array([])
                lower_depth_bound_points = np.array([])
                util.logging.debug('No values appended for lower bound {}.'.format(lower_depth))
            if upper_depth_bound < upper_depth:
                upper_depth_bound_indices = np.where(np.isclose(points[:, 3], lower_depth_bound))[0]
                upper_depth_bound_points = points[upper_depth_bound_indices]
                upper_depth_bound_points[:, 3] = upper_depth
                util.logging.debug('{} values appended for upper bound {}.'.format(len(upper_depth_bound_indices), upper_depth))
            else:
                upper_depth_bound_indices = np.array([])
                upper_depth_bound_points = np.array([])
                util.logging.debug('No values appended for upper bound {}.'.format(upper_depth))

            indices = np.concatenate((lower_depth_bound_indices, np.arange(len(points)), upper_depth_bound_indices), axis=0)
            points = np.concatenate((lower_depth_bound_points, points, upper_depth_bound_points), axis=0)
            self._data_indices = self._data_indices[indices]

        # convert to cartesian
        points[:, 1:] = util.math.spherical.to_cartesian(points[:, 1:], surface_radius=EARTH_RADIUS)

        return points

def periodic_with_coordinates(data, interpolation_points, lsm_base, scaling_values=None, interpolator_options=None):
    util.logging.debug('Interpolating periodic data with coordinates for lsm {} with scaling_values {} and interpolator_options {}.'.format(lsm_base, scaling_values, interpolator_options))

    # convert coordinates to map indices
    data = np.array(data, copy=True)
    data[:, :-1] = lsm_base.coordinates_to_map_indices(data[:, :-1], discard_year=True, int_indices=False)
    interpolation_points = lsm_base.coordinates_to_map_indices(interpolation_points, discard_year=True, int_indices=False)

    # interpolating
    return periodic_with_map_indices(data, interpolation_points, lsm_base, scaling_values=scaling_values, interpolator_options=interpolator_options)

def periodic_with_map_indices(data, interpolation_points, lsm_base, scaling_values=None, interpolator_options=None):
    util.logging.debug('Interpolating periodic data with map indices for lsm {} with scaling_values {} and interpolator_options {}.'.format(lsm_base, scaling_values, interpolator_options))

    assert data.ndim == 2
    assert data.shape[1] == 5
    assert interpolation_points.ndim == 2
    assert interpolation_points.shape[1] == 4

    # split in points and values
    data_points = data[:, :-1]
    data_values = data[:, -1]

    # scaling values
    if scaling_values is None:
        scaling_values = (lsm_base.x_dim / lsm_base.t_dim, None, None, None)

    if interpolator_options is None:
        interpolator_options = (1, 1, 0, 0)

    # prepare wrap_around_amount
    wrap_around_amount = interpolator_options[0]
    try:
        wrap_around_amount = tuple(wrap_around_amount)
    except TypeError:
        wrap_around_amount = (wrap_around_amount,)
    if len(wrap_around_amount) == 1:
        # use same wrap around for t and x
        wrap_around_amount = wrap_around_amount * 2
    if len(wrap_around_amount) == 2:
        # append wrap around for y and z if missing
        wrap_around_amount = wrap_around_amount + (0, 0)

    # create interpolator
    interpolator = util.math.interpolate.Periodic_Interpolator(data_points, data_values, point_range_size=(lsm_base.t_dim, lsm_base.x_dim, lsm_base.y_dim, lsm_base.z_dim), scaling_values=scaling_values, wrap_around_amount=wrap_around_amount, number_of_linear_interpolators=interpolator_options[1], single_overlapping_amount_linear_interpolators=interpolator_options[2], parallel=bool(interpolator_options[3]))

    # interpolating
    interpolation_data = interpolator.interpolate(interpolation_points)
    return interpolation_data

def default_scaling_values(sample_lsm):
    scaling_x = 1
    scaling_y = sample_lsm.x_dim / (sample_lsm.y_dim * 2)
    if scaling_y.is_integer():
        scaling_y = int(scaling_y)
    scaling_t = sample_lsm.x_dim / (sample_lsm.t_dim * 3)
    if scaling_t.is_integer():
        scaling_t = int(scaling_t)
    scaling_z = int(np.floor(sample_lsm.x_dim / sample_lsm.z_dim))
    scaling_values = (scaling_t, scaling_x, scaling_y, scaling_z)
    return scaling_values

class Interpolator_Annual_Periodic:

    def __init__(self, sample_lsm, scaling_values=None):
        self.sample_lsm = sample_lsm
        self.scaling_values = scaling_values

    @property
    def scaling_values(self):
        return self._scaling_values

    @scaling_values.setter
    def scaling_values(self, scaling_values):
        if scaling_values is None:
            scaling_values = default_scaling_values(self.sample_lsm)
        self._scaling_values = scaling_values

    def interpolate_data_for_lsm(self, data, lsm, interpolator_options=None):
        util.logging.debug('Interpolating data for lsm {} with interpolator_options {}.'.format(lsm, interpolator_options))

        sea_indices = lsm.sea_indices
        sea_coordinates = lsm.map_indices_to_coordinates(sea_indices)

        interpolated_values = periodic_with_coordinates(data, sea_coordinates, self.sample_lsm, scaling_values=self.scaling_values, interpolator_options=interpolator_options)
        interpolated_data = np.concatenate((sea_indices, interpolated_values[:, np.newaxis]), axis=1)
        interpolated_map = lsm.insert_index_values_in_map(interpolated_data, no_data_value=np.inf)
        assert np.all(interpolated_map != np.inf)

        util.math.interpolate.change_dim(interpolated_map, 0, lsm.t_dim)
        assert interpolated_map.shape == lsm.dim

        return interpolated_map

    def interpolate_data_for_sample_lsm_with_coordinates(self, data, interpolator_options=None):
        util.logging.debug('Interpolating data with coordinates for lsm {} with interpolator_options {}.'.format(self.sample_lsm, interpolator_options))
        data = np.array(data, copy=True)
        data[:, :-1] = self.sample_lsm.coordinates_to_map_indices(data[:, :-1], discard_year=True, int_indices=False)
        return self.interpolate_data_for_sample_lsm_with_map_indices(data, self.sample_lsm, interpolator_options=interpolator_options)

    def interpolate_data_for_sample_lsm_with_map_indices(self, data, interpolator_options=None):
        util.logging.debug('Interpolating data with map indices for lsm {} with interpolator_options {}.'.format(self.sample_lsm, interpolator_options))

        sea_indices = self.sample_lsm.sea_indices

        interpolated_values = periodic_with_map_indices(data, sea_indices, self.sample_lsm, scaling_values=self.scaling_values, interpolator_options=interpolator_options)
        interpolated_data = np.concatenate((sea_indices, interpolated_values[:, np.newaxis]), axis=1)

        interpolated_map = self.sample_lsm.insert_index_values_in_map(interpolated_data, no_data_value=np.inf)
        assert np.all(interpolated_map != np.inf)
        util.math.interpolate.change_dim(interpolated_map, 0, self.sample_lsm.t_dim)
        assert interpolated_map.shape == self.sample_lsm.dim

        return interpolated_map

    def interpolate_data_for_points_from_interpolated_lsm_data(self, interpolated_lsm_data, interpolation_points):
        util.logging.debug('Interpolationg data for points from interpolated data for lsm {}.'.format(self.sample_lsm))

        # get interpolated points and values
        interpolated_lsm_data_mask = ~np.isnan(interpolated_lsm_data)
        interpolated_lsm_values = interpolated_lsm_data[interpolated_lsm_data_mask]
        interpolated_lsm_indices = np.array(np.where(interpolated_lsm_data_mask)).T
        interpolated_lsm_points = self.sample_lsm.map_indices_to_coordinates(interpolated_lsm_indices)
        interpolated_lsm_points_and_values = np.concatenate([interpolated_lsm_points, interpolated_lsm_values[:, np.newaxis]], axis=1)

        # prepare interpolation points: convert to (rounded) int map indices -> convert to coordinates
        interpolation_points_map_indices = self.sample_lsm.coordinates_to_map_indices(interpolation_points, discard_year=True, int_indices=True)
        interpolation_points = self.sample_lsm.map_indices_to_coordinates(interpolation_points_map_indices)

        # interpolate for points
        interpolated_points_data = periodic_with_coordinates(
            interpolated_lsm_points_and_values, interpolation_points, self.sample_lsm,
            scaling_values=self.scaling_values, interpolator_options=(2 / min([self.sample_lsm.t_dim, self.sample_lsm.x_dim]), 0, 0, 0))

        # return
        assert np.all(np.isfinite(interpolated_points_data))
        return interpolated_points_data

    def interpolate_data_for_points(self, data, interpolation_points, interpolator_options=None):
        util.logging.debug('Interpolationg data for points with interpolator_options {}.'.format(interpolator_options))

        # interpolate for sample lsm
        interpolated_lsm_data = self.interpolate_data_for_lsm(data, self.sample_lsm, interpolator_options=interpolator_options)

        # interpolate for points
        interpolated_points_data = self.interpolate_data_for_points_from_interpolated_lsm_data(interpolated_lsm_data, interpolation_points)
        return interpolated_points_data

        # # get interpolated points and values
        # interpolated_lsm_data_mask = ~np.isnan(interpolated_lsm_data)
        # interpolated_lsm_values = interpolated_lsm_data[interpolated_lsm_data_mask]
        # interpolated_lsm_indices = np.array(np.where(interpolated_lsm_data_mask)).T
        # interpolated_lsm_points = self.sample_lsm.map_indices_to_coordinates(interpolated_lsm_indices)
        # interpolated_lsm_points_and_values = np.concatenate([interpolated_lsm_points, interpolated_lsm_values[:,np.newaxis]], axis=1)
        #
        # # prepare interpolation points: convert to (rounded) int map indices -> convert to coordinates
        # interpolation_points_map_indices = self.sample_lsm.coordinates_to_map_indices(interpolation_points, discard_year=True, int_indices=True)
        # interpolation_points = self.sample_lsm.map_indices_to_coordinates(interpolation_points_map_indices)

        #   # interpolate for points
        # interpolated_data = periodic_with_coordinates(interpolated_lsm_points_and_values, interpolation_points, self.sample_lsm, scaling_values=self.scaling_values, interpolator_options=(2/min([self.sample_lsm.t_dim,self.sample_lsm.x_dim]),0,0,0))
        #
        # # return
        # assert np.all(np.isfinite(interpolated_data))
        # return interpolated_data


########################################################################################################################
# Algorithm: give for every vertex v the component withe k vertices and sum under T that includes the vertex v         #
# In every step we find for every v_i in V the all the connected components with sum under T and with n vertices       #
# (I will refer it as Si_n).                                                                                #
#                                                                                #
# step 1 - for every v_i in V -  Si_1_1 = {v_i} --              only ome component                                     #
# step 2 - Si_2_j = Si_1 + (v_j reachable from Si_1_1){Sj_1_1} --   may be more then one - delete duplicate components #
# .                                                                                #
# .                                                                                #
# step n - Si_n_j = (l = 1..n-1){Si_l_k + (v_j reachable from Si_l_k){Sj_n-l}                                          #
########################################################################################################################

import GraphCreator as gc
import networkx as nx

class ConnectedAlgorithm:
    def __init__(self, edges_file_name, data_file_name, epsilon, connected_size):
        creator = gc.GraphCreator(edges_file_name, data_file_name, connected_size)
        self.G = creator.get_graph()
        self.eps = epsilon
        self.connected_size = connected_size

    def print_good_components(self):
        all_comp = {}
        count = 0
        for v in self.G:
            node = self.G.node[v]['data']
            if node.valid:
                node_comps = node.get_dict_for_size(self.connected_size)
                for key, value in node_comps.items():
                    if key not in all_comp:
                        count += 1
                        all_comp[key] = value

        for key, val in all_comp.items():
            weights_u = []
            for u in all_comp[key][0]:
                u = self.G.node[u]['data']
                weights_u.append(u.colorScore)
            print("component:\t" + all_comp[key][0].__str__())
            print("sum:\t\t" + weights_u.__str__() + " = " + str(all_comp[key][1])
                  + "\n--------------------------------------------------------------\n")
        print ("number of components:\t" + str(count))

    def get_graph(self):
        return self.G

    def get_reachable(self, comp):
        reachable = []
        for node in comp:
            # iterate over all reachable and add if its not already in the neighbors/comp_i
            for node_u in nx.all_neighbors(self.G, node):
                if self.G.node[node_u]['data'].valid and int(node_u) not in reachable and int(node_u) not in comp:
                    reachable.append(int(node_u))
        return reachable

    def get_reachable_comp_list(self, size, reachable):
        # loop over reachable nodes from some vertex
        comp_with_u = {}
        for node_u in reachable:
            u = self.G.node[node_u]['data']
            dict_comp_u = u.get_dict_for_size(size)
            # get components with requested size
            for key, value in dict_comp_u.items():
                if key not in comp_with_u:
                    comp_with_u[key] = value
        return comp_with_u

    def go(self):
        # first initialization for k = 1
        for i in self.G:
            v = self.G.node[i]['data']
            if float(v.colorScore) > self.eps or v.test == 0:
                v.valid = False
            else:
                v.add_comp(1, [i], v.colorScore)
                y = 0

        # first loop for recursive building of the components starting from components of size 1 going up until size = k
        for main_component_size in range(2, self.connected_size + 1):
            # print progress
            progress = (main_component_size-1)*(100 / self.connected_size)
            print('processing...' + str(int(progress)) + "%")

            # second loop iterates over all vertices
            for vertex in self.G:
                v = self.G.node[vertex]['data']
                # valid vertex is a vertex that can be in a CC withe k vertices withe weight under eps
                if not v.valid:
                    continue
                # third loop iterates over a specific vertex list of components under size = t
                for v_comp_size in range(1, main_component_size):
                    # main_component_size is the size of the component we need to compute in that iteration for all
                    # vertices, v_comp_size is the the size of the component we wish to extend
                    # there for we need the components C_j that hold u and holds the following conditions
                    # - the size of C_j + curr_iter_size = component_size
                    # - C_j doesnt share vertices with comp_i

                    dict_comp_v = v.get_dict_for_size(v_comp_size)

                    for key, value in dict_comp_v.items():
                        comp_i = value[0]
                        weight_comp_i = value[1]
                        reachable_comp_size = main_component_size - v_comp_size
                        # get all reachable nodes
                        reachable_nodes = self.get_reachable(comp_i)
                        # get all reachable components
                        # the return list will contain components followed by the weight
                        reachable_comp = self.get_reachable_comp_list(reachable_comp_size, reachable_nodes)
                        for ky, comp in reachable_comp.items():
                            comp_u = comp[0]
                            comp_u_weight = comp[1]
                            if (float(comp_u_weight) + float(weight_comp_i)) > self.eps:
                                continue
                            shared = False
                            for c_node in comp_u:
                                if comp_i.__contains__(int(c_node)):
                                    shared = True
                                    break

                            if not shared:
                                new_comp = comp_i + comp_u
                                new_comp_weight = float(weight_comp_i) + float(comp_u_weight)
                                v.add_comp(main_component_size, new_comp, new_comp_weight)

                # if there is no component of size k that answer the conditions then there is
                # also no component of size k+1
                if v.get_len_for_size(main_component_size) == 0:
                    v.valid = False
        # print progress
        print("processing...100%\n\n--------------------------------------------------------------")


# -*- coding: utf-8 -*-
"""
Created on Wed Mar 13 17:59:50 2019

@author: jonslaton
"""

def strip_header(s):
    return s.split(',')[1].strip()

class csv_record:
    def __init__(self,rec):
        self.test_system = strip_header(rec[0])
        self.setup_file = strip_header(rec[1])
        self.cal_dir = strip_header(rec[2])
        self.part_num = strip_header(rec[3])
        self.operator = strip_header(rec[4])
        self.station = strip_header(rec[5])
        self.date_of_record = strip_header(rec[6])
        self.start_time = ''.join(strip_header(rec[7]).split(':'))
        self.col_header = rec[8].strip('\n')
        self.result = rec[9:-1]
        self.name = '--'.join([self.part_num] + self.result[0].split(',')[0:3] + [self.start_time])

    def print_to_file(self,fdir):
        import pathlib
        pathlib.Path(fdir + 'Splits').mkdir(exist_ok=True)
        with open( fdir + 'Splits/' + self.name + '.csv' ,'w') as f:
            f.write(self.col_header + '\n')
            f.writelines(self.result)

#brief:     A utility function to read csv's into memory.
#param:  fname  A string path to the csv to be read.
#return:    a   A list containing all lines of the csv.
def read_test_csv(fname):
    a = []
    with open(fname,'r') as f:
        for line in f.readlines():
            a += [line]
    return a

def split_records(all_records):
    a = []
    b = []
    i = 0
    start_pos = []
    while i < len(all_records):
        if (all_records[i][0] == '#'):
            start_pos += [i]
            i+=8
        i+=1
    i=0
    while ( (i+1) < len(start_pos) ):
        a += [all_records[start_pos[i]:start_pos[i+1]]]
        i+=1
    a += [all_records[start_pos[i]:-1]]
    for record in a:
        b += [csv_record(record)]
    return b


class student:
    def __init__(self, student_name):
        self.student_name = student_name
    def show_student(self):
        print("Name: ", self.student_name)

class registered_classes(student):
    def __init__(self, student_name, classes):
        self.classes = classes
        student.__init__(self, student_name)

class subject:
    def __init__(self):
        self.sub_name = ['C++', 'Java', 'Python', 'Writing Skills']
        self.sub_code = ['csc123', 'csc456', 'csc1122', 'mpu101']

        self.w = {}
        for i in range(len(self.sub_name)):
            self.w[self.sub_code[i]] = self.sub_name[i]
    def display(self):
        print("Course Code: ", self.sub_code)
        print("Course Name: ", self.sub_name)

c = subject()
c.display()

print('\n')
print('\n')

classes = []
student_name = input("Enter Name: ")
while True:
    sub_code = input("Enter code to register: ")

    if sub_code in  c.sub_code:
        print("***", sub_code, "is successfully registered!")
        classes.append(sub_code)
        print()
        print()
        next = input("Add more subjects?: (y/n) ")
        if next == 'y':
            continue
        else:
            break
    else:
        print("Wrong Code OR code is selected.")
        again = input("Enter code again (or 'x' to stop): ")
        print()
        print()
        next = input("Add more subjects?: (y/n) ")
        if next == 'y':
            continue
        else:
            break

s = student(student_name)
s.show_student()
print("Subjects registered: ")
for i in classes:
    print("**", i, c.w[i])


'''

给你一个非空数组，返回此数组中 第三大的数 。如果不存在，则返回数组中最大的数。

示例 1：
    输入：[3, 2, 1]
    输出：1
    解释：第三大的数是 1 。

示例 2：
    输入：[1, 2]
    输出：2
    解释：第三大的数不存在, 所以返回最大的数 2 。

示例 3：
    输入：[2, 2, 3, 1]
    输出：1
    解释：注意，要求返回第三大的数，是指在所有不同数字中排第三大的数。
    此例中存在两个值为 2 的数，它们都排第二。在所有不同数字中排第三大的数为 1 。

'''
from typing import List

class Solution:
    def thirdMax(self, nums: List[int]) -> int:
        nums.sort(reverse = True)
        diff = 1
        for i in range(1, len(nums)):
            if nums[i] != nums[i - 1]:
                diff += 1
                if diff == 3:  # 此时 nums[i] 就是第三大的数
                    return nums[i]
        return nums[0]

if __name__ == "__main__":
    nums = [3, 5, 8, 91, 76, 2, 6, 2, 52, 7, 2, 1]
    sol = Solution()
    result = sol.thirdMax(nums)
    print (result)


# define the API's primarily used for the restaurant requests
from flask import Flask, request, jsonify
from flask_restful import Resource, Api
from flask_cors import CORS
from sqlalchemy import create_engine
from datetime import datetime
# local files
from config import comSettings
from admin import User, Employee

# PURPOSE - create a resource for staff members at the restaurant
class Staff(Resource):

    def get(self):
        print("All Staff Requested")
        reqDict = dict(request.args)

        if "resID" in reqDict:
            resID = reqDict["resID"]
            dbConfig = comSettings()
            databaseConnection = dbConfig["dbFilePath"] + resID + '.db'
            print(databaseConnection)
            db = create_engine(databaseConnection)
            conn = db.connect()

            # Set the basic response query
            sqlReq = 'SELECT * FROM Staff'

            # remove resID from parameters
            del reqDict["resID"]

            # If there are no arguments, set a basic request for all records
            if len(reqDict) == 0 :
                fullReq = '' + sqlReq + ''
                query = conn.execute(fullReq)
            # If there is one or more arguments, filter the request
            else:
                count = 1
                parReq = ""
                values = []
                # loop through the arguments to build the Where clause
                for field, value in reqDict.items():
                    if count == 1 :
                        parReq = ' WHERE ' + field + ' = ?'
                    else:
                        parReq = parReq + ' AND ' + field + ' = ?'

                    # add the parameter value for the second part of the request
                    values.append(value)
                    count = count + 1
                # build the full query and send the request
                fullReq = '' + sqlReq + parReq + ''
                query = conn.execute(fullReq, values) # This line performs query and returns json result

            result = {'Staff': [dict(zip(tuple (query.keys()) ,i)) for i in query.cursor]}
            conn.close
            return jsonify(result)
        else:
            return jsonify(False)

    def post(self):
        print("Staff Post Requested")
        reqDict = dict(request.args)
        dbConfig = comSettings()
        print ("I am here")
        result = {'status': 'incomplete', 'message': 'No action taken','value': 'none'}

        if "resID" not in reqDict:
            result['status'] = "Error"
            result['message'] = "Database not specified"
            return jsonify(result)
        else:
            resID = reqDict["resID"]
            aJSON = request.get_json(force=True)
            nowDate = datetime.now()
            userID = ""

            # create a login if requested
            if aJSON["Login"] == True:
                # connect to the main database
                databaseConnection = dbConfig["dbFilePath"] + "main" + '.db'
                db = create_engine(databaseConnection)
                conn = db.connect()
                # if a email was defined
                uEmail = aJSON["Email"]
                uName = aJSON["UserName"]
                print(uEmail)
                if uEmail != None and uEmail != "" :
                    # look for a user with that email
                    query = 'SELECT UserID FROM Users WHERE Email = ?'
                    qResult = conn.execute(query, uEmail)
                    conn.close
                    records = qResult.fetchall()
                    print(records)
                    if len(records) == 0 :
                        print("No login found")
                        # create an email based login
                        newUser = User.post(jsonify(aJSON))
                        userID = newUser.get_json(force=True)
                        print(userID)
                        result['message'] = "An new user was created."
                        # create a link Employee record
                    else:
                        record = records[0]
                        userID = record[0]
                        # check if a employee record already exists for that user
                        query = 'SELECT EmployeeID FROM Employees WHERE UserID = ? AND RestaurantID = ?'
                        values = (userID, resID)
                        qResult = conn.execute(query, values)
                        conn.close
                        records = qResult.fetchall()
                        print(records)
                        if len(records) > 0 :
                            result['status'] = "Error"
                            result['message'] = "An employee record with that UserID already exists for this restaurant. Talk to your admin or support if necessary."
                            return jsonify(result)
                        result['message'] = "An existing user with that email was connected to the restaurant."
                elif uName != None and uName != "" :
                    # look for a user with that UserName
                    query = 'SELECT UserID FROM UserView WHERE UserName = ? AND RestaurantID = ?'
                    values = (uName, resID)
                    qResult = conn.execute(query, values)
                    conn.close
                    records = qResult.fetchall()
                    print(records)
                    if len(records) == 0 :
                        print("No login found")
                        # create an userName based login
                        newUser = User.post(jsonify(aJSON))
                        userID = newUser.get_json(force=True)
                        print(userID)
                        result['message'] = "An new user was created."
                        # create a link Employee record
                    else:
                        result['status'] = "Error"
                        result['message'] = "An employee record with that User Name already exists for this restaurant. Talk to your admin or support if necessary."
                        return jsonify(result)

                    aJSON.update({"UserID": userID, "RestaurantID": resID})
                    print (aJSON)
                    newStaff = Employee.post(jsonify(aJSON))
                    staffData = newStaff.get_json(force=True)
                    staffID = staffData["StaffID"]
                    print(staffID)
            else:
                #create a new staff member without a login
                db_connect = create_engine(dbConfig["dbFilePath"] + resID + '.db')
                conn = db_connect.connect()
                postQuery = '''INSERT INTO Staff (
                        FullName,
                        PrefName,
                        Status,
                        Active,
                        CreateDate,
                        CreateUser,
                        ModDate,
                        ModUser
                    ) VALUES (?,?,?,?,?,?,?,?)'''
                postValues = (
                    aJSON["FullName"],
                    aJSON["PrefName"],
                    "New",
                    True,
                    nowDate,
                    aJSON['ModUser'],
                    nowDate,
                    aJSON['ModUser'])

            postResult = conn.execute(postQuery, postValues)
            conn.close
            staffID = postResult.lastrowid
            result['message'] = "A new staff member was created"

        result['status'] = "Success"
        result['value'] = staffID
        return jsonify(result)

    def patch(self):
        print("Staff Patch Requested")
        reqDict = dict(request.args)
        dbConfig = comSettings()

        if "resID" not in reqDict:
            return jsonify("Database not specified")
        else:
            resID = reqDict["resID"]
            databaseConnection = dbConfig["dbFilePath"] + resID + '.db'
            db = create_engine(databaseConnection)
            conn = db.connect()
            aJSON = request.get_json(force=True)

            nowDate = datetime.now()

            # send the update for the staff
            patchQuery = '''UPDATE Staff
                SET FullName = ?,
                    PrefName = ?,
                    Status = ?,
                    Active = ?,
                    ModDate = ?,
                    ModUser = ?
                WHERE StaffID = ?'''
            patchValues = (aJSON["FullName"],
                aJSON["PrefName"],
                aJSON["Status"],
                aJSON["Active"],
                nowDate,
                aJSON["ModUser"],
                aJSON["StaffID"])
            conn.execute(patchQuery, patchValues)
            conn.close
            #empID = postResult.lastrowid
            #print(empID)
            return jsonify("Success")

class ActiveStaff(Resource):

    def get(self):
        print("Active Staff Requested")
        reqDict = request.args

        if "resID" in request.args:
            resID = request.args["resID"]
            dbConfig = comSettings()
            databaseConnection = dbConfig["dbFilePath"] + resID + '.db'
            db = create_engine(databaseConnection)
            conn = db.connect()
            query = conn.execute("SELECT StaffID, FullName FROM Staff WHERE Active = ?","True")
            result = {'Staff': [dict(zip(tuple (query.keys()) ,i)) for i in query.cursor]}
            conn.close
            return jsonify(result)
        else:
            return jsonify("invalid request - no resid found")

        #conn = db_connect.connect() # connect to database


# -*- coding: utf-8 -*-
import datetime
from itertools import product
from math import prod

import sys

from django import forms

from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Submit, Row, Column, Reset, HTML
from crispy_forms.bootstrap import FieldWithButtons, StrictButton, AccordionGroup, TabHolder, Tab, Field
from django.utils.translation import ugettext_lazy as _
from crispy_bootstrap5.bootstrap5 import BS5Accordion

from django.utils import timezone
from users.models import User
from .models import (Product, Warehouse, SupplierInvoice, SupplierInvoiceItem, SupplierReceipt,
PaymentTerm, PaymentMethod)

from bank.models import BankAccount

from isis.models import Tax, Costumer

from asset_app.fields import ListTextWidget

class SupplierInvoiceItemForm(forms.ModelForm):
    SERVICE = 'SERVICE'
    PRODUCT = 'PRODUCT'

    PRODUCT_CHOICES = ((SERVICE, _('Service')), (PRODUCT, _('Product')))
    type = forms.ChoiceField(choices=PRODUCT_CHOICES, initial=PRODUCT, required=False)

    barcode = forms.CharField(label=_("Product code / Barcode"), max_length=100, required=False,
    widget=forms.TextInput(attrs={'autofocus': 'autofocus'}))

    tax = forms.ModelChoiceField(queryset=Tax.objects.filter(active_status=1), initial=1, required=False)
    price = forms.DecimalField(max_digits=18, decimal_places=6, initial=0,
    widget=forms.NumberInput(attrs={'autocomplete': "off"}))
    quantity = forms.DecimalField(max_digits=18, decimal_places=6, initial=0, widget=forms.TextInput)
    discount = forms.DecimalField(max_digits=4, decimal_places=2, initial=0, widget=forms.TextInput)
    invoice = forms.CharField(required=False, widget=forms.NumberInput)
    product = forms.ModelChoiceField(required=False,
    queryset=Product.objects.filter(active_status=1),
    widget=forms.Select(attrs={'class': 'product-select'}))

    def __init__(self, *args, **kwargs):
        super(SupplierInvoiceItemForm, self).__init__(*args, **kwargs)

        self.fields['price'].widget = ListTextWidget(data_list=[], name='price_list')

        self.helper = FormHelper()
        self.helper.form_id = "invoice-items-form-id"
        self.helper.form_class = "form-inline"
        self.helper.layout = Layout(
        BS5Accordion(
            AccordionGroup(_('INVOICE ITEMS'),
            Row('barcode'),
            Row(
                Column('product', css_class='form-group col-md-4 mb-0'),
                Column('type', css_class='form-group col-md-2 mb-0'),
                Column('price', css_class='form-group col-md-2 mb-0'),
                Column('quantity', css_class='form-group col-md-1 mb-0'),
                Column('discount', css_class='form-group col-md-1 mb-0'),
                Column('tax', css_class='form-group col-md-2 mb-0'),
                css_class='form-row'),

                Submit('add_item', _('Add Item'), css_class='btn btn-primary fa fa-plus'),
        ),))

    def clean(self):
        cleaned_data = super().clean()
        print(cleaned_data)

        price = cleaned_data.get('price')
        discount = cleaned_data.get('discount')
        product = cleaned_data.get('product')

        try:
            pr = Product.objects.get(name=product)
            min_price = pr.min_sell_price

            if price < min_price:
                self.errors['price'] = self.error_class(_("""
                Price is lower than the product Minimum selling price {}.""".format(min_price)))

        except Product.DoesNotExist:
            min_price = 0

        if discount is None:
            self.errors['discount'] = self.error_class(_("""
            discount must be between 0 and 99.99."""))
        elif discount > 100 or discount < 0:
            self.errors['discount'] = self.error_class(_("""
            discount must be between 0 and 100."""))

    def clean_invoice(self):
        return None

    class Meta:
        model = SupplierInvoiceItem
        fields = "__all__"

class SupplierInvoiceForm(forms.ModelForm):
    name = forms.CharField(required=False, max_length=50)
    paid_status = forms.IntegerField(required=False, initial=0)
    delivered_status = forms.IntegerField(initial=0, required=False)
    finished_status = forms.IntegerField(initial=0, required=False)
    active_status = forms.IntegerField(initial=1, required=False)
    number = forms.IntegerField(initial=0, required=False)

    supplier = forms.ModelChoiceField(
        queryset=Costumer.objects.filter(is_supplier=1, active_status=1),
        label = _("Please choose Supplier"), initial=1)

    def __init__(self, *args, **kwargs):
        super(SupplierInvoiceForm, self).__init__(*args, **kwargs)

        self.helper = FormHelper()
        self.helper.form_id = "invoice-form-id"
        self.helper.form_class = "invoice-form-class"
        self.helper.layout = Layout(
        HTML("""

{}

        """.format(_('Add/Update SupplierInvoice'),)),
        BS5Accordion(
            AccordionGroup(_('INVOICE DATA'),
                FieldWithButtons('supplier', StrictButton('',  css_class="btn fa fa-plus",
                data_bs_toggle="modal", data_bs_target="#supplier"), css_class='form-group col-md-12 mb-0'),
                Column('invoice', css_class='form-group col-md-3 mb-0'),
                Row(
                    Column('date', css_class='form-group col-md-3 mb-0'),
                    Column('due_date', css_class='form-group col-md-3 mb-0'),
                    FieldWithButtons('warehouse', StrictButton('',  css_class="btn fa fa-plus",
                    data_bs_toggle="modal", data_bs_target="#warehouse"), css_class='form-group col-md-6 mb-0'),
                ),
                Row(
                FieldWithButtons('payment_term', StrictButton('',  css_class="btn fa fa-plus",
                data_bs_toggle="modal", data_bs_target="#payment_term"), css_class='form-group col-md-3 mb-0'),
                FieldWithButtons('payment_method', StrictButton('',  css_class="btn fa fa-plus",
                data_bs_toggle="modal", data_bs_target="#payment_method"), css_class='form-group col-md-3 mb-0'),
                FieldWithButtons('bank_account', StrictButton('',  css_class="btn fa fa-plus",
                data_bs_toggle="modal", data_bs_target="#bank_account"), css_class='form-group col-md-3 mb-0'),
                ),
                Column(Field('notes', rows='2'), css_class='form-group col-md-12 mb-0'),
                Column(Field('public_notes', rows='2'), css_class='form-group col-md-12 mb-0'),),
                HTML('
'),
                Submit('save_invoice', _('Next'), css_class='btn btn-primary fas fa-save'),
                Reset('reset', 'Clear', css_class='btn btn-danger'),
                flush=True,
                always_open=True),
        )

    class Meta:
        model = SupplierInvoice
        exclude = ('date_created', 'date_modified', 'slug', 'created_by', 'modified_by')

class SupplierForm(forms.ModelForm):
    YES = 1
    NO = 0

    COSTUMER_CHOICES = ((NO, _("No")), (YES, _("Yes")))

    name = forms.CharField(label=_('Supplier Name'),
    widget=forms.TextInput, max_length=100)
    parent = forms.ModelChoiceField(label=_('Parent Supplier'),
    queryset=Costumer.objects.filter(is_supplier=1),
    required=False, initial=0)
    is_costumer = forms.ChoiceField(label=_("Is Costumer?"), widget=forms.RadioSelect,
    choices=COSTUMER_CHOICES, initial=NO)
    email = forms.CharField(max_length = 254, widget=forms.EmailInput, required=False)
    website = forms.URLField(max_length = 254, widget=forms.URLInput, required=False)
    current_credit = forms.DecimalField(max_digits=18, decimal_places=6, required=False, initial=0)
    is_supplier = forms.IntegerField(initial=1, required=False, widget=forms.HiddenInput)

    def __init__(self, *args, **kwargs):
        super(SupplierForm, self).__init__(*args, **kwargs)

        self.helper = FormHelper(self)
        self.helper.form_id = "supplier-form-id"
        self.helper.form_class = "supplier-form-class"
        self.helper.layout = Layout(
                HTML("""

{}

        """.format(_('Add/Update Supplier'),)),
            BS5Accordion(
            AccordionGroup(_('Supplier Data'),
            Row(
                Column('name', css_class='form-group col-md-8 mb-0'),
                Column('vat', css_class='form-group col-md-4 mb-0'),
                ),
            Row(
                Column('phone', css_class='form-group col-md-4 mb-0'),
                Column('fax', css_class='form-group col-md-4 mb-0'),
                Column('mobile', css_class='form-group col-md-4 mb-0'),

            ),
            Row(
                Column('country', css_class='form-group col-md-3 mb-0'),
                Column('province', css_class='form-group col-md-3 mb-0'),
                Column('city', css_class='form-group col-md-3 mb-0'),
                Column('zip', css_class='form-group col-md-3 mb-0'),
                ),
            Row(
                Column('warehouse', css_class='form-group col-md-3 mb-0'),
                Column('type', css_class='form-group col-md-3 mb-0'),
                Column('capital', css_class='form-group col-md-3 mb-0'),
                Column('active_status', css_class='form-group col-md-3 mb-0'),
                ),
            Row(
                Column('max_credit', css_class='form-group col-md-3 mb-0'),
                Column('parent', css_class='form-group col-md-3 mb-0'),
                Column('is_costumer', css_class='form-group col-md-6 mb-0'),

            ),
            Row(Column('address', css_class='form-group col-md-12 mb-0'),),
            Row(Column('contacts', css_class='form-group col-md-12 mb-0'),),
            Row(Column('manager', css_class='form-group col-md-12 mb-0'),),
            Row(
                Column('email', css_class='form-group col-md-6 mb-0'),
                Column('website', css_class='form-group col-md-6 mb-0'),
                ),
            # Row(Column(Field('notes', rows='2'), css_class='form-group col-md-12 mb-0'),),
            Submit('save_supplier', _('Save & Close'), css_class='btn btn-primary fas fa-save'),
            Submit('save_supplier_new', _('Save & New'), css_class='btn btn-primary fas fa-save'),
            Reset('reset', 'Clear', css_class='btn btn-danger'),
            ),
            flush=True,
            always_open=True),
        )

    class Meta:
        model = Costumer
        exclude = ('date_created', 'date_modified', 'slug', 'created_by', 'modified_by')

    def clean_parent(self):
        pass

class SupplierReceiptForm(forms.ModelForm):
    supplier = forms.ModelChoiceField(
        queryset=Costumer.objects.filter(active_status=1, is_supplier=1),
        label = _("Please choose Supplier"), initial=1)

    bank_account = forms.ModelChoiceField(queryset=BankAccount.objects.filter(acc_status=1), required=False)

    name = forms.CharField(max_length=100, required=False)
    number = forms.IntegerField(required=False)

    def __init__(self, *args, **kwargs):
        super(SupplierReceiptForm, self).__init__(*args, **kwargs)

        self.helper = FormHelper()
        self.helper.form_id = "supplier_receipt-form-id"
        self.helper.form_class = "supplier_receipt-form-class"
        self.helper.layout = Layout(
        HTML("""

{}

        """.format(_('Add/Update SupplierReceipt'),)),
        BS5Accordion(
            AccordionGroup(_('RECEIPT DATA'),
                Row(
                    Column('supplier', css_class='form-group col-md-8 mb-0'),
                    Column('bank_account', css_class='form-group col-md-4 mb-0'),
                    css_class='form-row'
                ),),
                HTML('
'),
                Submit('save_supplier_receipt', _('Next'), css_class='btn btn-primary fas fa-save'),
                Reset('reset', 'Clear', css_class='btn btn-danger'),
                flush=True,
                always_open=True),
        )

    class Meta:
        model = SupplierReceipt
        exclude = ('date_created', 'date_modified', 'slug', 'created_by', 'modified_by')

    def clean(self):
        cleaned_data = super().clean()

        supplier = cleaned_data.get('supplier')

        if supplier is None or supplier == "":
            self.errors['supplier'] = self.error_class(_("""
            Please choose Supplier or create Invoices First."""))


# -*- encoding: utf-8 -*-

import os
import numpy as np
import pandas as pd

if __name__ == '__main__':

    # 创建dataFrame
    li1 = ['a', 'b', 'c', 'd']
    li2 = [5, 6, 7, 8]
    li3 = [li1, li2]

    print("two dimension: ", li3)

    # 由python的数据类型来创建dataFrame
    # #dict  -> pandas.core.frame.DataFrame dict的key作为列名，value作为列的值
    df1 = pd.DataFrame({"col1": li1, "col2": li2}, index=[1, 2, 3, 4])
    print(df1, type(df1))

    # #list -> DataFrame  list[list1,list2,...] 二维数组, 每行是list1，list2...
    df1_1 = pd.DataFrame(li3, columns=['col1', 'clo2', 'clo3', 'clo4'])
    print("df1_1: ", df1_1)

    # #numpy类型创建dataFrame： numpy.ndarray -> dataFrame
    np1 = np.arange(1, 13)
    print(np1, type(np1))
    np2 = np1.reshape((3, 4))  # ndarray
    print(np2, type(np2))
    df2 = pd.DataFrame(np2, index=[2, 3, 4], columns=[
        "col1", 'col2', 'col3', 'col4'])  # 行索引值是2,3,4

    print("df2 ", df2)

    '''
    reset_index : 重置索引
    参考：https://zhuanlan.zhihu.com/p/110819220

    DataFrame.reset_index(level=None, drop=False, inplace=False, col_level=0, col_fill='')
    level：数值类型可以为：int、str、tuple或list，默认无，仅从索引中删除给定级别。默认情况下移除所有级别。控制了具体要还原的那个等级的索引 。
    drop：当指定drop=False时，则索引列会被还原为普通列；否则，经设置后的新索引值被会丢弃。默认为False。
    inplace：输入布尔值，表示当前操作是否对原数据生效，默认为False。
    col_level：数值类型为int或str，默认值为0，如果列有多个级别，则确定将标签插入到哪个级别。默认情况下，它将插入到第一级。
    col_fill：对象，默认‘’，如果列有多个级别，则确定其他级别的命名方式。如果没有，则重复索引名。
    '''
    df2_new1 = df2.reset_index()  # 会多出一列index
    print("df2_new1: ", df2_new1)
    df2_new2 = df2.reset_index(drop=True)  # 重置索引列，同时index一列被丢掉
    print("df2_new2: ", df2_new2)

    '''
    pivot_table:
    透视表pivot_table()是一种进行分组统计的函数，参数aggfunc决定统计类型。
    pivot_table(data, values=None, index=None, columns=None,aggfunc='mean', fill_value=None, margins=False, dropna=True, margins_name='All')
    pivot_table有四个最重要的参数index、values、columns、aggfunc

    '''
    print('*' * 40)
    df2_new1.loc[1, 'col1'] = 1
    print(df2_new1)

    '''
    df2_new1:

           index  col1  col2  col3  col4
    0      2     1     2     3     4
    1      3     1     6     7     8
    2      4     9    10    11    12
    '''
    # col1列作为索引，进行默认统计,mean;col1的第1，2行的值都为1，要进行聚合统计
    df3 = pd.pivot_table(df2_new1, index=['col1'])
    print(df3)

    # col1列作为索引，进行默认统计,mean;col1的第1，2行的值都为1，要进行聚合统计;只取col2，col3 列进行计算
    df3_2 = pd.pivot_table(df2_new1, index=[
                           'col1'], values=['col2', 'col3'])
    print(df3_2)

    # col1列作为索引进行统计;col1的第1，2行的值都为1，计算sum，mean统计；只取col2，col3 列进行计算
    df3_3 = pd.pivot_table(df2_new1, index=[
                           'col1'], values=['col2', 'col3'], aggfunc=[np.sum, np.mean])
    print(df3_3)


#!/usr/bin/env python

import json
import os.path
import pprint
import pickle
import datetime
import logging

import tabulate
import simplekml
import requests
import matplotlib.dates
import matplotlib.pyplot as pyplot
# import sqlalchemy

STATION_FILE_PATH = 'swedishweather/stations.txt'

BOX_NORTH = 68.604977
BOX_WEST = 17.468811

BOX_SOUTH = 67.140676
BOX_EAST = 20.470848

log = logging.getLogger('swedish-weather')

def convert_from_unixtimestamp(timestamp_ms):
    timestamp_s = timestamp_ms / 1000.0

    if timestamp_s < 0:
        date_ref = datetime.datetime.fromtimestamp(0)
        date_target = datetime.datetime.fromtimestamp(-timestamp_s)
        date_delta = date_target - date_ref

        # print(f"date_ref: {date_ref}")
        # print(f"date_delta: {date_delta}")

        date = date_ref - date_delta
    else:
        date = datetime.datetime.fromtimestamp(timestamp_ms / 1000.0)
    # end if

    return date
# end convert_from_unixtimestamp()

class SwedishStation:
    @classmethod
    def from_dict(cls, station_dict):
        obj = cls()

        obj.__dict__.update(**station_dict)

        obj.from_date = convert_from_unixtimestamp(station_dict['from'])
        obj.to_date = convert_from_unixtimestamp(station_dict['to'])

        return obj
    # end from_dict()

    def __getattr__(self, item):
        if item in self.__dict__:
            return self.__dict__[item]
        else:
            raise AttributeError(item)
        # end if
    # end __getattr__()

    def __repr__(self):
        return f"Station {self.id} {self.name} {self.latitude} N {self.longitude}"
# end class SwedishStation

class SwedishWeather(object):
    PICKLE_PATH = 'weather_stations.pickle'
    BASE_URL = '/api/version/1.0/parameter/1/station/159880.json'

    PARAMETERS = {
        "Min Air Temperature": ("Lufttemperatur", "min, 1 gång per dygn"),
        "Max Air Temperature": ("Lufttemperatur", "max, 1 gång per dygn"),
    }

    def __init__(self):
        self.station_info_dict = {}
        self.station_dict = {}
        self.category_info_dict = {}
        self.categories = {}
    # end __init__()

    @property
    def stations_url(self):
        return 'https://opendata-download-metobs.smhi.se/api/version/1.0/parameter/1.json'
    # end stations_url()

    @property
    def category_url(self):
        return "https://opendata-download-metobs.smhi.se/api/version/latest.json"
    # end category_url()

    def get_stations_info(self):
        request = requests.get(self.stations_url)
        self.station_info_dict = json.loads(request.content)
    # end get_stations_info()

    def get_category_info(self, show=False):
        request = requests.get(self.category_url)
        self.category_info_dict = json.loads(request.content)

        if show:
            pprint.pprint(self.category_info_dict)
            print(list(self.category_info_dict.keys()))
        # end if

        output = []

        for ressource_dict in self.category_info_dict.get('resource'):
            # print(ressource_dict.get('title'), ressource_dict.get('summary'), ressource_dict.get('link'))

            title = ressource_dict.get('title')
            summary = ressource_dict.get('summary')
            key = ressource_dict.get('key')

            output.append((
                title,
                summary,
                key,
            ))

            if title == 'Lufttemperatur' and '1 gång per dygn' in summary:
                self.categories[f"{title} {summary}"] = key
            # end if
        # end for

        if show:
            print()
            print(tabulate.tabulate(output))

            print()
            pprint.pprint(self.categories)
        # end if
    # end get_category_info()

    def save(self):
        with open(self.PICKLE_PATH, 'wb') as f:
            pickle.dump(self, f)
        # end with
    # end save()

    @classmethod
    def from_pickle(cls) -> "SwedishWeather":
        if os.path.exists(cls.PICKLE_PATH):
            with open(cls.PICKLE_PATH, 'rb') as f:
                log.critical(f"From pickle")
                sw = pickle.load(f)
            # end with
        else:
            sw = cls()
            sw.get_stations_info()
            sw.load_stations()
            sw.get_category_info()
        # end if

        return sw
    # end from_pickle()

    def load_stations(self):
        self.station_dict = {}

        for station_dict in self.station_info_dict['station']:
            station = SwedishStation.from_dict(station_dict)

            self.station_dict[station.id] = station
        # end for
    # end load_stations()

    def get_scoped_stations(self):
        for station in self.station_dict.values():
            if (BOX_WEST <= station.longitude <= BOX_EAST) and (BOX_SOUTH <= station.latitude <= BOX_NORTH):
                yield station
            # end if
        # end for
    # end get_scoped_stations()

    def export_stations(self):
        kml = simplekml.Kml()

        for station in self.station_dict.values():
            if (BOX_WEST <= station.longitude <= BOX_EAST) and (BOX_SOUTH <= station.latitude <= BOX_NORTH):

                station_point = kml.newpoint(name=station.name, coords=[(station.longitude, station.latitude, station.height)])
                station_point.altitudemode = simplekml.AltitudeMode.absolute
                station_point.style.iconstyle.icon.href = 'http://maps.google.com/mapfiles/kml/shapes/target.png'

                if station.active:
                    station_point.style.iconstyle.color = simplekml.Color.lightgreen
                else:
                    station_point.style.iconstyle.color = simplekml.Color.red
                # end if

                station_point.description = pprint.pformat(station.__dict__, indent=True)
            # end if
        # end for

        kml.savekmz('swedish_stations.kmz')
    # end export_stations()

    def show_timeline(self):
        station_list = []

        for station in self.station_dict.values():   # type: SwedishStation
            if (BOX_WEST <= station.longitude <= BOX_EAST) and (BOX_SOUTH <= station.latitude <= BOX_NORTH):
                station_list.append((
                    station,
                    station.from_date,
                    station.to_date,
                ))
            # end if
        # end for

        station_list = list(sorted(station_list, key=lambda x: x[1], reverse=True))

        fig, ax = pyplot.subplots()

        x_block_list = []
        y_block_list = []

        for ix, (station, from_date, to_date) in enumerate(station_list):
            x_block_list.append([from_date, to_date])
            # y_block_list.append([station.name, station.name])
            y_block_list.append([ix, ix])

            ax.annotate(station.name, (from_date, ix), ha="right", va='center')
        # end for

        ax.plot(
            list(zip(*x_block_list)),
            list(zip(*y_block_list)),
            'r', marker='o', mfc='r'
        )

        # ax.set_yticks([station.name for station, _, _ in station_list])

        xfmt = matplotlib.dates.DateFormatter('%Y-%m')
        ax.xaxis.set_major_formatter(xfmt)

        pyplot.show()
    # end show_timeline()

    def air_temperature_url(self, station_id: int, min_max='min'):
        try:
            key = self.categories[f'Lufttemperatur {min_max}, 1 gång per dygn']
        except KeyError:
            log.error(f"self.categories: {list(self.categories.keys())}")
            raise
        # end try

        # return f"https://opendata-download-metobs.smhi.se/api/version/1.0/parameter/{key}/station/{station_id}/period.json"
        return f"https://opendata-download-metobs.smhi.se/api/version/1.0/parameter/{key}/station/{station_id}/period/corrected-archive.json"
    # end air_temperature_url()

    def collect_temperature(self, years_back=30.0):
        for station in self.get_scoped_stations():  # type: SwedishStation
            print(station)

            url_min = self.air_temperature_url(station.id, 'min')
            # log.critical(f"url_min: {url_min}")

            response = requests.get(
                url_min,
                headers={'Content-type': 'application/json'}
            )

            temperature_data = json.loads(response.content)

            csv_links = temperature_data.get('data')

            for csv_link in csv_links:
                # print()
                # pprint.pprint(csv_link)

                for link in csv_link.get('link'):
                    csv_url = link.get('href')

                    print(f"csv_url: {csv_url}")
                # end for
            # end for

            break
        # end for
    # end collect_temperature()
# end SwedishWeather

if __name__ == '__main__':
    sw = SwedishWeather.from_pickle()
    # sw.get_category_info()
    # sw.show_category_info()
    # sw.get_stations_info()
    # sw.save()

    # pprint.pprint(sw.station_info_dict)

    # sw.export_stations()
    # sw.show_timeline()

    sw.get_category_info(show=False)
    sw.collect_temperature()
    sw.save()
# end if


import logging
import os

from cryptography.hazmat.primitives.ciphers import Cipher
from cryptography.hazmat.primitives.ciphers import algorithms
from cryptography.hazmat.primitives.ciphers.modes import GCM

# On Windows we have to import a specific backend because the
# default_backend() mechanism doesnt work in Gajim for Windows.
# Its because of how Gajim is build with cx_freeze

if os.name == 'nt':
    from cryptography.hazmat.backends.openssl import backend
else:
    from cryptography.hazmat.backends import default_backend

log = logging.getLogger('gajim.plugin_system.omemo')

def aes_decrypt(_key, iv, payload):
    """ Use AES128 GCM with the given key and iv to decrypt the payload. """
    if len(_key) >= 32:
        # XEP-0384
        log.debug('XEP Compliant Key/Tag')
        data = payload
        key = _key[:16]
        tag = _key[16:]
    else:
        # Legacy
        log.debug('Legacy Key/Tag')
        data = payload[:-16]
        key = _key
        tag = payload[-16:]
    if os.name == 'nt':
        _backend = backend
    else:
        _backend = default_backend()
    decryptor = Cipher(
        algorithms.AES(key),
        GCM(iv, tag=tag),
        backend=_backend).decryptor()
    return decryptor.update(data) + decryptor.finalize()

def aes_encrypt(key, iv, plaintext):
    """ Use AES128 GCM with the given key and iv to encrypt the plaintext. """
    if os.name == 'nt':
        _backend = backend
    else:
        _backend = default_backend()
    encryptor = Cipher(
        algorithms.AES(key),
        GCM(iv),
        backend=_backend).encryptor()
    return encryptor.update(plaintext) + encryptor.finalize(), encryptor.tag


"""
https://leetcode.cn/problems/minimum-bit-flips-to-convert-number/

一次 位翻转 定义为将数字 x 二进制中的一个位进行 翻转 操作，即将 0 变成 1 ，或者将 1 变成 0 。

    比方说，x = 7 ，二进制表示为 111 ，我们可以选择任意一个位（包含没有显示的前导 0 ）并进行翻转。
    比方说我们可以翻转最右边一位得到 110 ，或者翻转右边起第二位得到 101 ，或者翻转右边起第五位（这一位是前导 0 ）得到 10111 等等。

给你两个整数 start 和 goal ，请你返回将 start 转变成 goal 的 最少位翻转 次数。

示例 1：
    输入：start = 10, goal = 7
    输出：3
    解释：10 和 7 的二进制表示分别为 1010 和 0111 。我们可以通过 3 步将 10 转变成 7 ：
    - 翻转右边起第一位得到：1010 -> 1011 。
    - 翻转右边起第三位：1011 -> 1111 。
    - 翻转右边起第四位：1111 -> 0111 。
    我们无法在 3 步内将 10 转变成 7 。所以我们返回 3 。

示例 2：
    输入：start = 3, goal = 4
    输出：3
    解释：3 和 4 的二进制表示分别为 011 和 100 。我们可以通过 3 步将 3 转变成 4 ：
    - 翻转右边起第一位：011 -> 010 。
    - 翻转右边起第二位：010 -> 000 。
    - 翻转右边起第三位：000 -> 100 。
    我们无法在 3 步内将 3 变成 4 。所以我们返回 3 。

提示：
    0 <= start, goal <= 109

"""

"""方法一：位运算"""
class Solution:
    def minBitFlips(self, start: int, goal: int) -> int:
        res = 0
        tmp = start ^ goal  # 只对 start 与 goal 数值不同的二进制位执行翻转操作，求出不同的二进制位数量
        print (tmp)
        while tmp:          # tmp 的二进制表示中 1 的数量即为 start 与 goal 不同的二进制位数量
            res += tmp & 1
            tmp >>= 1
        return res

class Solution:
    def minBitFlips(self, start: int, goal: int) -> int:
        return bin(start ^ goal).count("1")

if __name__ == "__main__":
    start = 10
    goal = 7
    sol = Solution()
    result = sol.minBitFlips(start, goal)
    print (result)

2220_转换数字的最少位翻转次数.py


#!/usr/bin/env python3

from math import inf
import re
import sys

#target_y = 10
target_y = 2000000

beacon_xs = set()

ranges = []

for line in sys.stdin:
  m = re.match('^Sensor at x=(-?\d+), y=(-?\d+): closest beacon is at x=(-?\d+), y=(-?\d+)$', line)
  sx, sy, bx, by = map(int, m.groups())
  range = abs(sx - bx) + abs(sy - by)
  dx = range - abs(sy - target_y)
  if dx >= 0:
    ranges.append((sx - dx, sx + dx))
  if by == target_y:
    beacon_xs.add(bx)

ranges.sort()
covered = 0
last_x = -inf
for x1, x2 in ranges:
  if last_x < x2:
    if last_x < x1:
      covered += x2 - x1 + 1
    else:
      covered += x2 - last_x
    last_x = x2
print(covered - len(beacon_xs))


# 1773. Count Items Matching a Rule

class Solution:
    def countMatches(self, items: List[List[str]], ruleKey: str, ruleValue: str) -> int:

        keyIndex = 0;
        if (ruleKey == 'color'):
            keyIndex = 1;
        elif (ruleKey == 'name'):
            keyIndex = 2;

        counter = 0;
        for indivItem in items:
            if (indivItem[keyIndex] == ruleValue):
                counter += 1;

        return counter;


import json
import numpy
import pandas
import yaml
from kafka.admin import KafkaAdminClient, NewTopic
from kafka import KafkaProducer, KafkaConsumer
from typing import List

def load_configs(path="dao/config.yml"):
    with open(path, "r") as stream:
        try:
            config = yaml.safe_load(stream)
            return config
        except yaml.YAMLError as exc:
            print(exc)

class KafkaConnection:
    def __init__(self, client_id="sonmt"):
        config = load_configs()
        bootstrap_servers = config["kafka_bootstrap_servers"]
        self.bootstrap_servers = bootstrap_servers
        self.admin_client = KafkaAdminClient(
            bootstrap_servers=self.bootstrap_servers,
            client_id=client_id
        )
        self.producer = KafkaProducer(bootstrap_servers=self.bootstrap_servers,
                                      value_serializer=lambda v: json.dumps(v).encode('utf-8'))
        self.consumer = KafkaConsumer(bootstrap_servers=self.bootstrap_servers)

    def create_new_topic(self, topic_names: str or List[str]):
        topic_list = []
        if type(topic_names) == list:
            for topic in topic_names:
                topic_list.append(NewTopic(name=topic, num_partitions=1, replication_factor=1))

        if type(topic_names) == str:
            topic_list = [NewTopic(name=topic_names, num_partitions=1, replication_factor=1)]

        self.admin_client.create_topics(new_topics=topic_list)

    def get_existed_list_topics(self):
        list_topics = self.consumer.topics()
        return list(list_topics)

    def produce_df_to_kafka(self, topic: str, df: pandas.DataFrame):
        existed_list_topics = self.get_existed_list_topics()
        if topic not in existed_list_topics:
            self.create_new_topic(topic)

        cols = df.columns
        row_data = {}

        for ind in df.index:
            for col in cols:
                if type(df[col][ind]) is numpy.int64:
                    row_data[col] = int(df[col][ind])
                else:
                    row_data[col] = df[col][ind]

            self.producer.send(topic, row_data)


"""Run two versions of the dcm2niix Gear on the same inputs and capture resulting job information."""

versions = ["1.0.0_1.0.20200331", "1.2.1_1.0.20201102_dev1"]
output_dir = "~/Documents/flywheel/gears/dcm2niix/tests/instance"

import time
import datetime
import flywheel
import pandas as pd

fw = flywheel.Client()

def main():

    # Find the collection
    collection = fw.collections.find_one("label=dcm2niix_rewrite_test")

    # Find all the acquisitions in the collection
    acquisitions = fw.get_collection_acquisitions(collection.id)

    # For each version, run the gear with default config and save the job information
    for version in versions:

        job_ids = run_dcm2niix_gear(acquisitions, version)
        # wait for the jobs to finish
        time.sleep(400)
        df = collate_job_info(job_ids, version)

        df.reset_index(inplace=True)
        df.rename(columns={"index": "job_id"}, inplace=True)
        date = str(datetime.date.today())
        outfile = f"{output_dir}/dcm2niix_instance_runs_{version}_{date}.csv"
        df.to_csv(outfile, index=False)

def collate_job_info(job_ids, gear_version):

    df = pd.DataFrame()

    for job_id in job_ids:

        job = fw.get_job(job_id)

        # Save job information
        df.loc[job_id, "gear_version"] = gear_version
        df.loc[job_id, "state"] = job.state
        df.loc[job_id, "inputs"] = job.inputs["dcm2niix_input"]["name"]
        df.loc[job_id, "destination_id"] = job.destination["id"]

        # Default behavior of original gear is to not save JSON sidecars
        outputs = [file for file in job.saved_files if not file.endswith(".json")]
        df.loc[job_id, "outputs"] = str(outputs)

        # Calculate time to execute job
        if job.state == "complete":
            timedelta = job.transitions["complete"] - job.transitions["running"]
            df.loc[job_id, "execution_time"] = timedelta.total_seconds()

    return df

def run_dcm2niix_gear(acquisitions, gear_version):

    gear = fw.lookup(f"gears/dcm2niix/{gear_version}")
    job_ids = []

    for acquisition in acquisitions:

        for file in acquisition.get_files():

            if file.type == "dicom":

                inputs = {"dcm2niix_input": acquisition.get_file(file.name)}

                job_id = gear.run(
                    inputs=inputs,
                    destination=acquisition,
                    tags=["dcm2niix_rewrite_test"],
                )
                job_ids.append(job_id)

    return job_ids

main()


# create a 300x300 canvas.
# fill it with a checkerboard pattern.

from tkinter import *

root = Tk()

canvas_width= 300
canvas_height= 300

canvas = Canvas(root, width = canvas_width, height = canvas_height)
canvas.pack()

x = 1
for i in range(1, 28):
    rect = canvas.create_rectangle(1+x, 1+x, 10+x, 10+x, fill='purple')
    x += 11

root.mainloop()