# prompts the user for two integers of any length and adds them together.
# In addition to adding them, it also counts the number of times the "carry"
# operation needs to be carried out.

def main():
    num1, num2 = get_input()
    count, total_sum = count_carries(num1, num2)

    print("{} + {} = {}".format(num1, num2, total_sum))
    print("Number of carries: {}".format(count))

# get user's input, if it is invalid, prompt user to enter again
def get_input():
    num1 = input("Enter the first number: ")
    num2 = input("Enter the second number: ")

    while not num1.isdigit() or int(num1) < 0:
        num1 = input("Your input is not a number or not a positive number."
                     " Enter the first number: ")

    while not num2.isdigit() or int(num2) < 0:
        num2 = input("Your input is not a number or not a positive number."
                     " Enter the second number: ")

    return num1, num2

# convert string num1, num2 into a list with integer numbers
def convert_to_list(num1, num2):
    num1_list = list(num1)
    num1_integer = [int(num) for num in num1_list]
    num2_list = list(num2)
    num2_integer = [int(num) for num in num2_list]

    return num1_integer, num2_integer

# get the sum of two integer list
def sum_integers(num1, num2):
    num1_integer, num2_integer = convert_to_list(num1, num2)

    length_difference = abs(len(num1_integer) - len(num2_integer))
    zero_list = [0] * length_difference

    if len(num1_integer) < len(num2_integer):
        num1_integer = zero_list + (num1_integer)

    else:
        num2_integer = zero_list + (num2_integer)

    integer_list = [(num1_integer[i] + num2_integer[i])
                    for i in range(len(num1_integer))]

    return integer_list

# count carries
# if there is one number in the list, if the number is larger than 9, then
# count plus one and convert the list into an integer
# if there is more than one number in the list, check each number one by
# one from the end index of the list. If the integer is larger than 9, then
# count plus one and the previous number should plus one as well
# when finishing the for loop, if the last integer is larger than 9, then
# it should minus one, because in the for loop, it has added one when index
# is equal to 0
# at last, convert the integer in the list into integer
def count_carries(num1, num2):
    integer_list = sum_integers(num1, num2)
    count = 0

    if len(integer_list) == 1:
        if integer_list[0] > 9:
            count += 1
        total_sum = int("".join(str(j) for j in integer_list))
        return count, total_sum

    else:
        for j in range(len(integer_list) - 1, -1, -1):
            if integer_list[j] > 9:
                count += 1
                integer_list[j-1] += 1
        if integer_list[0] > 9:
            integer_list[-1] -= 1

        new_list = [integer_list[0]]

        for i in range(1, len(integer_list)):
            if integer_list[i] > 9:
                new_list.append(integer_list[i] % 10)
            else:
                new_list.append(integer_list[i])

        total_sum = int("".join([str(j) for j in new_list]))

        return count, total_sum

main()


from model import *
import numpy as np
import matplotlib.pyplot as plt
import sys
from collections import defaultdict

graph = defaultdict(list)

def parse_input(file):

	link = []
	const = []
	with open(file, 'r') as f:
		for i, line in enumerate(f):
			if i == 0:
				N,L = line.split(' ')
			else:
				row = line.split(' ')
				n1,n2 = row[0].split('-')
				link.append((n1,n2))
				c = row[1],row[2],row[3],row[4]
				const.append(((n1,n2),c))

	return N, L, link, const

def built_graph(N,link):
	for n1,n2 in link:
		graph[n1].append(n2)
	print(graph)

if __name__ == '__main__':
	N,L,link,const = parse_input(sys.argv[1])
	built_graph(N,link)


# https://leetcode.com/problems/maximum-gap/
# bucket sort
# 几乎不考
# T: O(n)
# S: O(n)

import math
class Solution:
    def maximumGap(self, nums: List[int]) -> int:
        if not nums or len(nums) < 2:
            return 0

        num_len = len(nums)
        max_val, min_val = nums[0], nums[0]

        for i in range(num_len):
            max_val = max(max_val, nums[i])
            min_val = min(min_val, nums[i])

        gap = math.ceil((max_val - min_val)/ (num_len - 1))
        bucket_min = [float('inf')]*(num_len - 1)
        bucket_max = [-float('inf')]*(num_len - 1)

        for num in nums:
            if num == min_val or num == max_val:
                continue
            bucket = (num - min_val)//gap
            bucket_min[bucket] = min(num, bucket_min[bucket])
            bucket_max[bucket] = max(num, bucket_max[bucket])

        result = 0
        pre = min_val
        for i in range(num_len - 1):
            if bucket_min[i] == float('inf') and bucket_max[i] == -float('inf'):
                continue
            result = max(result, bucket_min[i] - pre)
            pre = bucket_max[i]

        result = max(result, max_val - pre)
        return result


import pytest
import os
from collections import namedtuple
from flask import Flask, jsonify
from flask_influxdb import InfluxDB

App = namedtuple("App", ["ctx", "client"])

influx_db = InfluxDB()

def create_app(config: str) -> Flask:
    app = Flask(__name__)
    app.config.from_pyfile(config)

    influx_db.init_app(app)

    @app.route("/add/<measurement>/<idx>")
    def write(measurement: str, idx: int):
        result = influx_db.write_points(
            [
                {
                    "fields": {
                        "index": idx,
                    },
                    "tags": {
                        "info": "test",
                    },
                    "measurement": measurement,
                }
            ]
        )

        return jsonify(result=result)

    return app

@pytest.fixture(scope="session")
def influx():
    return influx_db

@pytest.fixture()
def app(request):
    """Session-wide test application."""
    rel_dir = os.path.dirname(__file__)
    config = os.path.join(rel_dir, "config.cfg")

    # Create app
    app = create_app(config)

    client = app.test_client()
    ctx = app.app_context()

    yield App(ctx, client)

    # Cleanup
    with ctx:
        influx_db.database.drop("test")

@pytest.fixture()
def app_no_cleanup(request):
    """Session-wide test application."""
    rel_dir = os.path.dirname(__file__)
    config = os.path.join(rel_dir, "config.cfg")

    # Create app
    app = create_app(config)

    client = app.test_client()
    ctx = app.app_context()

    yield App(ctx, client)


import threading
from datetime import datetime

from scooby.plugins_base import Plugin
from scooby.utils import get_stack

threadlocal = threading.local()

def init_threadlocal(threadlocal):
    threadlocal.initialized = True
    threadlocal.thriftpy_plugin_data = None

init_threadlocal(threadlocal)

def parse_args(args):
    parsed = []
    for v in args:
        parsed.append(repr(v))
    return parsed

def parse_kwargs(kwargs):
    parsed = {}
    for k, v in kwargs.items():
        if isinstance(v, bytes):
            v = str(v)
        parsed[k] = v
    return parsed

orig_req = None
def req(self, api, *args, **kwargs):
    if not hasattr(threadlocal, 'initialized'):
        init_threadlocal(threadlocal)

    if not threadlocal.thriftpy_plugin_data:
        return orig_req(self, api, *args, **kwargs)

    start = datetime.now()
    try:
        return orig_req(self, api, *args, **kwargs)
    finally:
        end = datetime.now()
        time_taken = (end - start).total_seconds() * 1000.0
        threadlocal.thriftpy_plugin_data.insert(
            service_name=self._service.__name__,
            func_name=api,
            args=args,
            kwargs=kwargs,
            start=start,
            end=end,
            time_taken=time_taken,
            stack=get_stack()
        )

class ThriftpyPluginData(object):
    def __init__(self):
        self.queries = []

    def insert(self, service_name, func_name, args, kwargs, start, end, time_taken, stack):
        self.queries.append({
            'service_name': service_name,
            'func_name': func_name,
            'args': parse_args(args),
            'kwargs': parse_kwargs(kwargs),
            'start': start.isoformat(),
            'end': end.isoformat(),
            'time_taken': time_taken,
            'stack': stack,
        })

    def as_json_dict(self):
        return {
            'queries': self.queries,
        }

class ThriftpyPlugin(Plugin):
    Data = ThriftpyPluginData

    def __init__(self):
        super(ThriftpyPlugin, self).__init__(name='Thriftpy')

    def should_be_used(self):
        try:
            import thriftpy
            return True
        except ImportError:
            return False

    def instrument(self):
        from thriftpy.thrift import TClient
        global orig_req
        orig_req = TClient._req
        TClient._req = req
        super(ThriftpyPlugin, self).instrument()

    def on_process_request(self, thriftpy_plugin_data, *args, **kwargs):
        init_threadlocal(threadlocal)
        threadlocal.thriftpy_plugin_data = thriftpy_plugin_data

    def on_process_response(self, *args, **kwargs):
        init_threadlocal(threadlocal)
        threadlocal.thriftpy_plugin_data = None


""" Keras models, using the functional interface

build() creates a VAE, encoder and generator
use vae.load_weights('myfile.h5') to load a pre-trained model
"""
from __future__ import division

import config  # incl. random seed

import numpy as np
import collections
from sklearn.decomposition import PCA
import scipy.stats
import keras
from keras.utils import to_categorical
from keras import optimizers, backend as K
from keras.layers import *
from keras.models import Model
from keras.preprocessing.image import ImageDataGenerator

from utils import utils, plot

########################################################################
### Model applications
########################################################################

def transfer_style(encoder, decoder, stylesA, stylesB, samples=[], amt=1.):
    # stylesA, stylesB, samples = lists of samples that can be encoded by `encoder`
    # encoder output must be a np array
    transformation = extract_transformation(encoder, stylesA, stylesB)
    latent_vectors = encoder.predict(samples)
    latent_vectors_ = apply_transformation(latent_vectors, transformation, amt)
    return decoder.predict(latent_vectors_)

def extract_transformation(encoder, stylesA, stylesB) -> np.array:
    # stylesA, stylesB = lists of samples that can be encoded by `encoder`
    # extract the linear latent transformation that corresponds with A -> B
    latent_vectors_A = encoder.predict(stylesA)
    latent_vectors_B = encoder.predict(stylesB)
    return latent_vectors_B.mean(axis=0) - latent_vectors_A.mean(axis=0)

def apply_transformation(vectors: np.array, transformation: np.array,
                         amt=1.) -> np.array:
    # np automatically maps the transformation to every instance with (+)
    return vectors + transformation * amt

def gen_latent(generator,
               batch_size=2,
               latent_dim=2,
               x_encoded=0.,
               latent_indices=(0, 1),
               n=10,
               m=4,
               min_x=0.05,
               max_x=0.95,
               min_y=0.05,
               max_y=0.95,
               assume_gaussion=True,
               plot_result=False,
               v=0):
    """ Original: keras.keras.examples.variational_autoencoder
    :x_encoded :: float | [ float ]

    to swap x,y set `latent_indices`` to (1,0)
    """
    if not isinstance(x_encoded, np.ndarray):
        x_encoded = np.repeat(x_encoded, latent_dim)
    if v: print(x_encoded.shape, x_encoded)
    x_decoded = generator.predict(x_encoded.reshape([1, latent_dim]))

    # Coordinate grid
    grid_x = np.linspace(min_x, max_x, n)
    grid_y = np.linspace(min_y, max_y, m)
    # linearly spaced coordinates on the unit square were transformed through
    # the inverse CDF (ppf) of the Gaussian to produce values of the latent
    # variables z, since the prior of the latent space is Gaussian
    if assume_gaussion:
        grid_x = scipy.stats.norm.ppf(grid_x)
        grid_y = scipy.stats.norm.ppf(grid_y)

    # Generation
    result = collections.defaultdict(dict)
    for yi in grid_x:
        for xi in grid_y:
            z_sample = x_encoded.copy()
            z_sample[np.array(latent_indices)] = (xi, yi)
            # z_sample = np.array([[yi, xi]])
            z_sample = np.tile(z_sample, batch_size).reshape(
                batch_size, latent_dim)
            x_decoded = generator.predict(z_sample, batch_size=batch_size)
            result[yi][xi] = x_decoded[0]

    if plot_result:
        plot.multi(result, v=v)
    return result

########################################################################
### Model construction
########################################################################
"""
If using a pre-trained model, make sure that the number of latent dims and the number of midi-notes are equal
"""

def build(input_shape=(160, 10, 1), latent_dim=10, epsilon_std=1.):
    timesteps, notes, _ = input_shape
    encoder_model, encoder_input, z_mean, z_log_var = encoder(
        input_shape, latent_dim)
    z_input = encoder_model(encoder_input)

    # this function must be defined locally in order for the model to be serializable
    # using the following inline lambda function will result in an error when .to_json() is called
    #   lambda args: sample(args, z_mean, z_log_var, latent_dim, epsilon_std)
    def sample(args):
        z_mean, z_log_var = args
        epsilon = K.random_normal(
            shape=(K.shape(z_mean)[0], latent_dim),
            mean=0.,
            stddev=epsilon_std)
        return z_mean + K.exp(z_log_var) * epsilon

    z_output = Lambda(sample)(z_input)
    decoder_model = decoder(z_output, latent_dim, input_shape)

    # VAE
    vae_input = Input(shape=(input_shape, ))
    vae_input = encoder_input
    vae_output = decoder_model(z_output)
    # vae_output = decoder_model(z_mean)
    vae = Model(vae_input, vae_output, name='vae-model-')

    vae_loss_ = vae_loss(
        vae_input,
        vae_output,
        z_mean,
        z_log_var,
        timesteps,
        notes,
        beta=0.75,
        gamma=0.05)
    vae.add_loss(vae_loss_)
    vae.compile(optimizer='adam')

    # Encoder (matrices -> latent vectors)
    encoder_ = Model(encoder_input, z_mean)
    # Generator (latent vectors -> matrices)
    # generator_input = Input((latent_dim, ))
    # generator_layers_ = utils.composition(decoders, generator_input)
    # generator = Model(generator_input, generator_layers_)
    return vae, encoder_, decoder_model

def build_manual(input_shape=(160, 10, 1), latent_dim=10, epsilon_std=1.):
    """
    this model is not serializable due to the lambda layers
    """
    timesteps, notes, _ = input_shape
    encoder_model, encoder_input, z_mean, z_log_var = encoder(
        input_shape, latent_dim)
    sample_ = lambda args: sample(args, z_mean, z_log_var, latent_dim, epsilon_std)
    z_input = encoder_model(encoder_input)
    z_output = Lambda(sample_)(z_input)
    decoders = list_decoders(input_shape)
    decoded = utils.composition(decoders, z_output, verbose=False)

    # VAE: Full model (to train)
    vae_input = encoder_input
    vae_output = decoded
    vae = Model(vae_input, vae_output)
    vae_loss_ = vae_loss(
        vae_input,
        vae_output,
        z_mean,
        z_log_var,
        timesteps,
        notes,
        beta=0.75,
        gamma=0.05)
    vae.add_loss(vae_loss_)
    vae.compile(optimizer='adam')

    # Encoder (matrices -> latent vectors)
    encoder_ = Model(encoder_input, z_mean)

    # Generator (latent vectors -> matrices)
    generator_input = Input((latent_dim, ))
    generator_layers_ = utils.composition(decoders, generator_input)
    generator = Model(generator_input, generator_layers_)

    return vae, encoder_, generator

# internal functions

def sample(args, z_mean, z_log_var, latent_dim=2, epsilon_std=1.):
    z_mean, z_log_var = args
    epsilon = K.random_normal(
        shape=(K.shape(z_mean)[0], latent_dim), mean=0., stddev=epsilon_std)
    return z_mean + K.exp(z_log_var) * epsilon

def encoder(input_shape, latent_dim=2):
    encoder_input = Input(shape=input_shape)
    nodes = np.prod(input_shape)
    timesteps, notes, channels = input_shape

    # Convolution
    h = encoder_input
    h = Reshape((timesteps, notes))(h)
    h = Conv1D(
        64, kernel_size=2, strides=1, activation='relu', padding='valid')(h)

    h = Bidirectional(LSTM(128))(h)

    # Z Mean, Variance
    z_mean = Dense(latent_dim, name='z_mean')(h)  # no activation='relu'
    z_log_var = Dense(latent_dim, name='z_log_var')(h)  # no activation='relu'

    encoder_output = [z_mean, z_log_var]
    encoder_model = Model(encoder_input, encoder_output, name='encoder_model-')
    return encoder_model, encoder_input, z_mean, z_log_var

def list_decoders(output_shape):
    # decoder_input = z_output
    # h = decoder_input
    # :output_shape = (timesteps, channels, channels) || (batches, filters, timesteps, channels)
    # keras offers just Conv2DTranspose and not Conv1DTranspose
    # - use 2D images during upsampling :: (timesteps, notes, channels) => (timesteps, notes, filters)
    # - use 1D images to optimize reconstruction :: (timesteps, filters) => (timesteps, notes)

    # image_data_format = 'channels_last'
    # goal shape: (timesteps, notes, channels)
    # start with the 'reverse': lots of small imgs => few large img

    timesteps, notes, channels = output_shape

    # keras.examples.variational_autoencoder_deconv.py
    decoders = []
    decoders += [Dense(256)]
    decoders += [LeakyReLU(alpha=0.3)]

    # add a bypass layer
    w = 256
    decoders += [Dense(w, activation='relu')]
    extra_decoders = []
    for _ in range(3):
        extra_decoders += [Dense(w, activation='elu')]

    extra_d = Lambda(lambda layer: utils.composition(extra_decoders, layer))
    decoders += [Lambda(lambda layer: Add()([layer, extra_d(layer)]))]

    decoders += [BatchNormalization(momentum=0.9)]
    n = 10  # 5

    decoders += [RepeatVector(n)]
    decoders += [Bidirectional(LSTM(128, return_sequences=True))]

    # Embedding decoder

    embedding_len = int(timesteps / n)
    filters = 250
    decoders += [TimeDistributed(Dense(filters, activation='relu'))]
    decoders += [
        TimeDistributed(Dense(notes * embedding_len, activation='sigmoid'))
    ]
    decoders += [Reshape((timesteps, notes, 1))]

    return decoders

def decoder(input_, latent_dim=10, output_shape=(40, 10, 1)):
    """ decoder_input = z_output
    decoder.predict :: z -> x
    the decoder models p(x|z), with an assumption over p(z)
    """
    # image_data_format = 'channels_last'
    timesteps, notes, channels = output_shape

    decoder_input = Input(shape=(latent_dim, ))

    h = decoder_input
    h = Dense(256)(h)
    h = LeakyReLU(alpha=0.3)(h)

    # add a bypassed layer
    w = 256
    h_bypass = Dense(w, activation='relu')(h)
    extra_decoders = []
    for _ in range(3):
        h_bypass = Dense(w, activation='elu')(h_bypass)

    h = Add()([h, h_bypass])
    h = BatchNormalization(momentum=0.9)(h)

    n = 10  # 5
    h = RepeatVector(n)(h)
    h = Bidirectional(LSTM(128, return_sequences=True))(h)

    # Embedding decoder

    embedding_len = int(timesteps / n)
    filters = 250
    h = TimeDistributed(Dense(filters, activation='relu'))(h)
    h = TimeDistributed(Dense(notes * embedding_len, activation='sigmoid'))(h)
    h = Reshape((timesteps, notes, 1))(h)

    return Model(decoder_input, h, name='decoder_model-')

def vae_loss(vae_input,
             vae_output,
             z_mean,
             z_log_var,
             timesteps=40,
             notes=9,
             beta=0.5,
             extra_loss_f=keras.losses.mean_absolute_error,
             gamma=0.5):
    """
    vae_input, vae_output == x == y :: np.ndarray
    z_mean, z_log_var :: np.ndarray
    beta = disentanglement amount
    gamma = multiplier for extra loss function
    """
    vae_input_ = K.flatten(vae_input)
    vae_output_ = K.flatten(vae_output)
    # bin. cross-entropy
    xent_loss = timesteps * notes * keras.metrics.binary_crossentropy(
        vae_input_, vae_output_)
    # Kullback-Leibler divergence
    kl_loss = -1. * K.sum(
        1 + z_log_var - K.square(z_mean) - K.exp(z_log_var), axis=-1)
    # (optional) kl_loss = max(kl_loss, free_bits)
    extra_loss = timesteps * notes * extra_loss_f(vae_input_, vae_output_)

    # change beta
    #     beta = ((1.0 - tf.pow(hparams.beta_rate, tf.to_float(self.global_step)))
    #             * hparams.max_beta)
    #     self.loss = tf.reduce_mean(r_loss) + beta * tf.reduce_mean(kl_cost)
    # y_true, y_pred, z_mean, z_log_var, timesteps=150, notes=3, beta=1.

    vae_loss = K.mean(xent_loss + beta * kl_loss + gamma * extra_loss)
    return vae_loss

class ImageDataGenerator(keras.preprocessing.image.ImageDataGenerator):
    def __init__(self,
                 x,
                 batch_size=32,
                 phase_mod=0.2,
                 whitening=False,
                 zca_epsilon=1e-6):
        keras.preprocessing.image.ImageDataGenerator.__init__(
            self,
            featurewise_center=False,  # set input mean to 0 over the dataset
            samplewise_center=False,  # set each sample mean to 0
            featurewise_std_normalization=False,  # divide inputs by dataset std
            samplewise_std_normalization=False,  # divide each input by its std
            zca_epsilon=zca_epsilon,
            zca_whitening=whitening,
            rotation_range=0,  # randomly rotate images in 0 to 180 degrees
            width_shift_range=0.,  # note-channel mod, but not shuffled
            height_shift_range=phase_mod,  # start_t, phase
            horizontal_flip=False,  # reverse
            vertical_flip=False)

        self.x = x
        self.fit(x)
        self.batch_size = batch_size

    def __len__(self):
        # n batches / epoch = #samples / batch_size
        # floor() to prevent occurences of samples multiple times
        return int(np.floor(self.x.shape[0] / self.batch_size))

    def shuffle_3rd_dim(self, x_batch):
        """ Shuffle the 3rd matrix dim with a bias for soft mutations
        :x_batch :: (samples, timesteps, 3rd_dim, channels)
        """
        z_batch = np.empty_like(x_batch)
        for batch_i in range(x_batch.shape[0]):
            indices = np.arange(x_batch.shape[2])
            np.random.shuffle(indices)
            for i, j in enumerate(indices):
                z_batch[batch_i, :, i] = x_batch[batch_i, :, j]

        return z_batch

    def shuffle_3rd_dim_soft(self,
                             x_batch,
                             rate=1,
                             intensity=0.5,
                             scale=0.5,
                             verbose=0):
        """ Shuffle the 3rd matrix dim with a bias for soft mutations
        :x_batch :: (samples, timesteps, 3rd_dim, channels)
        :rate = amount (%) of samples that are mutated
        :intensity = amount of mutations in a sample, relative to len(3rd_dim)
          in range [0, ..]
        :scale = intensity of mutations, relative to len(3rd_dim)
          standard_deviation = scale * len(3rd_dim)
        """
        # z_batch = np.empty_like(x_batch)
        z_batch = x_batch.copy()
        length = x_batch.shape[2]
        indices = np.arange(length)
        std = scale * length
        for batch_i in range(x_batch.shape[0]):
            if np.random.random() < rate:
                if verbose > 1: print('batch_i: %i' % batch_i)
                for i, j in enumerate(
                        self._shuffle_indices(indices, std, verbose)):
                    z_batch[batch_i, :, i] = x_batch[batch_i, :, j]

        return z_batch

    def _shuffle_indices(self, indices, intensity, std=1, verbose=0):
        indices = indices.copy()
        length = indices.shape[0]
        n_iterations = int(round(length * np.random.random()**(1 / intensity)))
        for _ in range(n_iterations):
            i1 = np.random.choice(indices)
            i2 = int((i1 + np.random.normal(0, std)) % length)
            if verbose > 0: print(i1, i2)
            indices[i1], indices[i2] = indices[i2], indices[i1]
        return indices


import time
import math
start = time.time()

def prime(prime):
    i=2
    sqr_prime=math.ceil((pow(prime,1/2)))
    while i<=sqr_prime:
        if prime%i==0 and prime!=i:
            return False
        i=i+1
    return True
def prime_list(max):
    x=2
    somme=0
    while(x<=max):
        if(prime(x)==True):
            somme=somme+x
        x=x+1
    return somme

print(prime_list(2000000))
print(time.time()-start)


### Adapted from https://github.com/kundajelab/dragonn/blob/master/dragonn/plot.py
### Authored by Nathan Boley

import re

import matplotlib
matplotlib.use('pdf')
from matplotlib import pyplot as plt
from matplotlib.patches import PathPatch
from matplotlib.path import Path
import matplotlib.patches as mpatches

from shapely.wkt import loads as load_wkt
from shapely import affinity
import itertools

import numpy as np
from pkg_resources import resource_filename

##########################################################################
# copied from descartes
# https://pypi.python.org/pypi/descartes

class Polygon(object):
    # Adapt Shapely or GeoJSON/geo_interface polygons to a common interface

    def __init__(self, context):
        if hasattr(context, 'interiors'):
            self.context = context
        else:
            self.context = getattr(context, '__geo_interface__', context)

    @property
    def geom_type(self):
        return (
            getattr(self.context, 'geom_type', None) or self.context['type'])

    @property
    def exterior(self):
        return (
            getattr(self.context, 'exterior', None) or self.context['coordinates'][0])

    @property
    def interiors(self):
        value = getattr(self.context, 'interiors', None)
        if value is None:
            value = self.context['coordinates'][1:]
        return value

def PolygonPath(polygon):
    """Constructs a compound matplotlib path from a Shapely or GeoJSON-like
    geometric object"""
    this = Polygon(polygon)
    assert this.geom_type == 'Polygon'

    def coding(ob):
        # The codes will be all "LINETO" commands, except for "MOVETO"s at the
        # beginning of each subpath
        n = len(getattr(ob, 'coords', None) or ob)
        vals = np.ones(n, dtype=Path.code_type) * Path.LINETO
        vals[0] = Path.MOVETO
        return vals
    vertices = np.concatenate(
        [np.asarray(this.exterior)] + [np.asarray(r)
                                       for r in this.interiors])
    codes = np.concatenate(
        [coding(this.exterior)] + [coding(r)
                                   for r in this.interiors])
    return Path(vertices, codes)

def PolygonPatch(polygon, **kwargs):
    """Constructs a matplotlib patch from a geometric object
    The `polygon` may be a Shapely
    or GeoJSON-like object with or without holes.
    The `kwargs` are those supported by the matplotlib.patches.Polygon class
    constructor. Returns an instance of matplotlib.patches.PathPatch.
    Example (using Shapely Point and a matplotlib axes):
      >>> b = Point(0, 0).buffer(1.0)
      >>> patch = PolygonPatch(b, fc='blue', ec='blue', alpha=0.5)
      >>> axis.add_patch(patch)
    """
    return PathPatch(PolygonPath(polygon), **kwargs)

#
# END copied from descartes
#
##########################################################################

##########################################################################
# Initialize the polygon paths for A,C,G,T
#
# Geometry taken from JTS TestBuilder Monospace font with fixed precision model
# of 1000.0
#

A_data = """
MULTIPOLYGON (
((24.7631 57.3346, 34.3963 57.3346, 52.391 -1.422, 44.1555 -1.422, 39.8363
  13.8905, 19.2476 13.8905, 15.0039 -1.422, 6.781 -1.422, 24.7631 57.3346)),
((29.5608 50.3205, 21.1742 20.2623, 37.9474 20.2623, 29.5608 50.3205))
)
"""

C_data = """POLYGON((
52.391 2.5937, 48.5882 0.8417, 44.68 -0.4142, 40.5998 -1.17, 36.2814 -1.422,
32.8755 -1.2671, 29.6656 -0.8024, 26.6518 -0.0278, 23.834 1.0565,
21.2122 2.4507, 18.7865 4.1547, 16.5569 6.1686, 14.5233 8.4922,
12.7087 11.0966, 11.136 13.9527, 9.8053 17.0606, 8.7166 20.4201,
7.8698 24.0314, 7.2649 27.8943, 6.902 32.009, 6.781 36.3754, 6.9027 40.7209,
7.2678 44.8198, 7.8764 48.6722, 8.7283 52.278, 9.8236 55.6371,
11.1624 58.7497, 12.7446 61.6157, 14.5702 64.2351, 16.6133 66.5753,
18.8481 68.6034, 21.2745 70.3195, 23.8926 71.7235, 26.7023 72.8156,
29.7037 73.5956, 32.8967 74.0637, 36.2814 74.2197, 40.5998 73.9697,
44.68 73.2196, 48.5882 71.9696, 52.391 70.2196, 52.391 60.1101,
48.6468 62.739, 44.6331 64.657, 40.4709 65.8289, 36.2814 66.2196,
31.7716 65.7557, 29.7437 65.1758, 27.8672 64.3641, 26.1421 63.3203,
24.5684 62.0447, 23.146 60.5371, 21.875 58.7976, 19.7831 54.6129,
18.289 49.481, 17.3925 43.4019, 17.0936 36.3754, 17.3925 29.3763,
18.289 23.3166, 19.7831 18.1964, 21.875 14.0157, 23.146 12.2762,
24.5684 10.7686, 26.1421 9.4929, 27.8672 8.4492, 29.7437 7.6375,
31.7716 7.0576, 36.2814 6.5937, 40.5354 6.9844, 44.7034 8.1563,
48.6878 10.0743, 52.391 12.7032, 52.391 2.5937))"""

G_data = """POLYGON((
52.391 5.4974, 50.49 3.8964, 48.4724 2.502, 46.3383 1.3144, 44.0877 0.3334,
41.7314 -0.4346, 39.2805 -0.9832, 34.0946 -1.422, 30.9504 -1.2772,
27.9859 -0.843, 25.2009 -0.1191, 22.5956 0.8942, 20.1698 2.197,
17.9236 3.7894, 15.857 5.6713, 13.9699 7.8428, 12.285 10.2753,
10.8248 12.9404, 9.5892 15.8381, 8.5782 18.9685, 7.7919 22.3315,
7.2303 25.9271, 6.8933 29.7553, 6.781 33.8161, 6.8948 37.8674,
7.2362 41.6888, 7.8053 45.2803, 8.6019 48.6419, 9.6262 51.7737, 10.878 54.6755,
12.3575 57.3474, 14.0646 59.7895, 15.9743 61.9712, 18.0615 63.862,
20.3262 65.4618, 22.7685 66.7708, 25.3884 67.789, 28.1857 68.5162,
31.1606 68.9525, 34.3131 69.098, 38.5048 68.7957, 42.5144 67.8889,
46.3638 66.3703, 50.0748 64.2325, 50.0748 54.8075, 46.342 57.8466,
42.5144 59.9716, 38.5266 61.2226, 34.3131 61.6395, 30.1132 61.2053,
28.2228 60.6624, 26.4723 59.9024, 24.8614 58.9253, 23.3904 57.731,
22.0591 56.3195, 20.8675 54.691, 18.9046 50.7806, 17.5025 45.998,
16.6612 40.3432, 16.3808 33.8161, 16.6526 27.1962, 17.4679 21.4959,
18.8267 16.7151, 20.7291 12.8539, 21.8892 11.2595, 23.1951 9.8776,
24.6469 8.7084, 26.2446 7.7517, 27.9883 7.0076, 29.8778 6.4762, 34.0946 6.051,
36.9534 6.2276, 39.4407 6.7575, 41.6331 7.6625, 43.607 8.9644, 43.607 27.2172,
33.7304 27.2172, 33.7304 34.7776, 52.391 34.7776, 52.391 5.4974
))"""

T_data = """POLYGON((
6.781 58.3746, 52.391 58.3746, 52.391 51.5569, 33.6933 51.5569, 33.6933 -1.422,
25.5684 -1.422, 25.5684 51.5569, 6.781 51.5569, 6.781 58.3746
))"""

def standardize_polygons_str(data_str):
    """Given a POLYGON string, standardize the coordinates to a 1x1 grid.
    Input : data_str (taken from above)
    Output: tuple of polygon objects
    """
    # find all of the polygons in the letter (for instance an A
    # needs to be constructed from 2 polygons)
    path_strs = re.findall("\(\(([^\)]+?)\)\)", data_str.strip())

    # convert the data into a numpy array
    polygons_data = []
    for path_str in path_strs:
        data = np.array([
            tuple(map(float, x.split())) for x in path_str.strip().split(",")])
        polygons_data.append(data)

    # standardize the coordinates
    min_coords = np.vstack(data.min(0) for data in polygons_data).min(0)
    max_coords = np.vstack(data.max(0) for data in polygons_data).max(0)
    for data in polygons_data:
        data[:, ] -= min_coords
        data[:, ] /= (max_coords - min_coords)

    polygons = []
    for data in polygons_data:
        polygons.append(load_wkt(
            "POLYGON((%s))" % ",".join(" ".join(map(str, x)) for x in data)))

    return tuple(polygons)

letters_polygons = {}
letters_polygons['A'] = standardize_polygons_str(A_data)
letters_polygons['C'] = standardize_polygons_str(C_data)
letters_polygons['G'] = standardize_polygons_str(G_data)
letters_polygons['T'] = standardize_polygons_str(T_data)

colors = dict(zip(
    'ACGT', (('red', 'white'), ('blue',), ('orange',), ('green',))
))

def add_letter_to_axis(ax, let, x, y, height):
    """Add 'let' with position x,y and height height to matplotlib axis 'ax'.
    """
    for polygon, color in zip(letters_polygons[let], colors[let]):
        new_polygon = affinity.scale(
            polygon, yfact=height, origin=(0, 0, 0))
        new_polygon = affinity.translate(
            new_polygon, xoff=x, yoff=y)
        patch = PolygonPatch(
            new_polygon, edgecolor=color, facecolor=color)
        ax.add_patch(patch)
    return

def plot_bases_on_ax(letter_heights, ax):
    """
    Plot the N letters with heights taken from the Nx4 matrix letter_heights.
    Parameters
    ----------
    letter_heights: Nx4 array
    ax: axis to plot on
    """

    assert letter_heights.shape[1] == 4, letter_heights.shape
    for x_pos, heights in enumerate(letter_heights):
        letters_and_heights = sorted(zip(heights, 'ACGT'))
        y_pos_pos = 0.0
        y_neg_pos = 0.0
        for height, letter in letters_and_heights:
            if height > 0:
                add_letter_to_axis(ax, letter, 0.5 + x_pos, y_pos_pos, height)
                y_pos_pos += height
            elif height < 0:
                add_letter_to_axis(ax, letter, 0.5 + x_pos, y_neg_pos, height)
                y_neg_pos += height
    ax.set_xlim(0, letter_heights.shape[0] + 1)
    ax.set_xticks(np.arange(1, letter_heights.shape[0] + 1))
    ax.set_aspect(aspect='auto', adjustable='box')
    ax.autoscale_view()

def plot_bases(letter_heights, figsize=(12, 6), ylab='bits'):
    """
    Plot the N letters with heights taken from the Nx4 matrix letter_heights.
    Parameters
    ----------
    letter_heights: Nx4 array
    ylab: y axis label
    Returns
    -------
    pyplot figure
    """
    assert letter_heights.shape[1] == 4, letter_heights.shape

    fig = pyplot.figure(figsize=figsize)
    ax = fig.add_subplot(111)
    ax.set_xlabel('pos')
    ax.set_ylabel(ylab)
    plot_bases_on_ax(letter_heights, ax)

    return fig

def plot_pwm(letter_heights,
             figsize=(12, 6), ylab='bits', information_content=True):
    """
    Plots pwm. Displays information content by default.
    """
    if information_content:
        letter_heights = letter_heights * (
            2 + (letter_heights *
                 np.log2(letter_heights)).sum(axis=1))[:, np.newaxis]
    return plot_bases(letter_heights, figsize, ylab=ylab)

def add_letters_to_axis(ax, letter_heights):
    """
    Plots letter on user-specified axis.
    Parameters
    ----------
    ax : axis
    letter_heights: Nx4 array
    """
    assert letter_heights.shape[1] == 4

    x_range = [1, letter_heights.shape[0]]
    pos_heights = np.copy(letter_heights)
    pos_heights[letter_heights < 0] = 0
    neg_heights = np.copy(letter_heights)
    neg_heights[letter_heights > 0] = 0

    for x_pos, heights in enumerate(letter_heights):
        letters_and_heights = sorted(zip(heights, 'ACGT'))
        y_pos_pos = 0.0
        y_neg_pos = 0.0
        for height, letter in letters_and_heights:
            if height > 0:
                add_letter_to_axis(ax, letter, 0.5 + x_pos, y_pos_pos, height)
                y_pos_pos += height
            else:
                add_letter_to_axis(ax, letter, 0.5 + x_pos, y_neg_pos, height)
                y_neg_pos += height

    ax.set_xlim(x_range[0] - 1, x_range[1] + 1)
    ax.set_xticks(range(*x_range) + [x_range[-1]])
    ax.set_aspect(aspect='auto', adjustable='box')
    ax.autoscale_view()

def plot_delta_tracks(track_list, title_list, x_tick_interval=1,
                      track_height=3, axvline_loc=None,
                      plot_file=None):
    """
    track_list = list of tracks of size (seq_len, 4)
    title_list = list of labels corresponding to track_list
    """
    plt.clf()
    width = track_list[0].shape[1]
    fig_width = 20 + width/10
    fig = plt.figure(figsize=(fig_width, track_height*len(track_list)))
    yMax = np.max([arr.max() for arr in track_list]) + .01
    yMin = np.min([arr.min() for arr in track_list]) - .01
    for (i,array) in enumerate(track_list):
        ax = fig.add_subplot(len(track_list),1,i+1)
        if (array.shape[0]==4):
            letter_heights=array.T
            pos_heights = np.copy(letter_heights)
            pos_heights[letter_heights < 0] = 0
            neg_heights = np.copy(letter_heights)
            neg_heights[letter_heights > 0] = 0
            for x_pos, heights in enumerate(letter_heights):
                letters_and_heights = sorted(itertools.izip(heights, 'ACGT'))
                y_pos_pos = 0.0
                y_neg_pos = 0.0
                for height, letter in letters_and_heights:
                    if height > 0:
                        add_letter_to_axis(ax, letter, -0.5+x_pos,
                                           y_pos_pos, height)
                        y_pos_pos += height
                    else:
                        add_letter_to_axis(ax, letter, -0.5+x_pos,
                                           y_neg_pos, height)
                        y_neg_pos += height
            if (i==len(track_list)):
                ax.set_xlabel('pos')
            ax.set_aspect(aspect='auto', adjustable='box')
            ax.autoscale_view()
        elif (array.shape[0]==1):
            ax.plot(range(arr.shape[1]), array.squeeze(), 'k', lw=0.5)
        else:
           raise RuntimeError("Unsure how to deal with shape "+str(arr.shape))
        ax.axhline(0, linestyle='dashed', color='black')
        ax.set_title(title_list[i])
        ax.set_ylabel('Importance Score', fontsize=16)
        ax.set_xlim(-1, array.shape[1]+1)
        ax.set_ylim([yMin, yMax])
        if axvline_loc is not None:
            ax.axvline(axvline_loc)
        xticks_locations=range(-1,array.shape[1]+1)
        ax.set_xticks(xticks_locations[::x_tick_interval])
        ax_2=ax.twiny()
    fig.tight_layout()
    if plot_file is not None:
        plt.savefig(plot_file)
    # plt.show()
    return plt

def plot_dfim(map_array, figsize=(10, 3),
              cmap='plasma'):
    """
    Plot map
    """
    if len(map_array.shape) != 2:
        raise ValueError('Provide map array with shape 2 or unravel map')
    plt.figure(figsize=figsize)
    fig, ax = plt.subplots()
    if map_array.shape[0] == 1:
        im = ax.imshow(map_array, aspect=10, cmap=cmap)
    else:
        im = ax.imshow(map_array, aspect='auto', cmap=cmap)
    values = np.unique(map_array.ravel())
    legend_values=[np.min(values), np.mean(values), np.max(values)]
    colors = [ im.cmap(im.norm(value)) for value in legend_values]
    patches = [ mpatches.Patch(color=colors[i],
                               label="Level {l}".format(
                                l='%.4f'%legend_values[i]))
                   for i in range(len(legend_values))]
    plt.legend(handles=patches, bbox_to_anchor=(1.05, 1),
               loc=2, borderaxespad=0. )
    # plt.show()
    return plt


import numpy as np
from itertools import chain

class KFold():
    """A basic cross-validation iterator.

    Each fold is used once as a testset while the k - 1 remaining folds are
    used for training.

    See an example in the :ref:`User Guide <use_cross_validation_iterators>`.

    Args:
        n_splits(int): The number of folds.
        random_state(int, RandomState instance from numpy, or ``None``):
            Determines the RNG that will be used for determining the folds. If
            int, ``random_state`` will be used as a seed for a new RNG. This is
            useful to get the same splits over multiple calls to ``split()``.
            If RandomState instance, this same instance is used as RNG. If
            ``None``, the current RNG from numpy is used. ``random_state`` is
            only used if ``shuffle`` is ``True``.  Default is ``None``.
        shuffle(bool): Whether to shuffle the ratings in the ``data`` parameter
            of the ``split()`` method. Shuffling is not done in-place. Default
            is ``True``.
    """

    def __init__(self, n_splits=5, random_state=None, shuffle=True):

        self.n_splits = n_splits
        self.shuffle = shuffle
        self.random_state = random_state

    def split(self, data):
        """Generator function to iterate over trainsets and testsets.

        Args:
            data(:obj:`Dataset<surprise.dataset.Dataset>`): The data containing
                ratings that will be divided into trainsets and testsets.

        Yields:
            tuple of (trainset, testset)
        """

        if self.n_splits > len(data.raw_ratings) or self.n_splits < 2:
            raise ValueError('Incorrect value for n_splits={0}. '
                             'Must be >=2 and less than the number '
                             'of ratings'.format(len(data.raw_ratings)))

        # We use indices to avoid shuffling the original data.raw_ratings list.
        indices = np.arange(len(data.raw_ratings))

        start, stop = 0, 0
        for fold_i in range(self.n_splits):
            start = stop
            stop += len(indices) // self.n_splits
            if fold_i < len(indices) % self.n_splits:
                stop += 1

            raw_trainset = [data.raw_ratings[i] for i in chain(indices[:start],
                                                               indices[stop:])]
            raw_testset = [data.raw_ratings[i] for i in indices[start:stop]]

            trainset = data.construct_trainset(raw_trainset)
            testset = data.construct_testset(raw_testset)

            yield trainset, testset

    def get_n_folds(self):

        return self.n_splits


from heppy.framework.analyzer import Analyzer
from heppy.particles.genbrowser import GenBrowser

class AncestorSeeker(Analyzer):

    def process(self, event):
        genjets = getattr(event, self.cfg_ana.input_jets)
        for jet in genjets:
            jet.tags['ancestor'] = 0
            if jet.match:
                genbrowser = GenBrowser([jet.match], event.gen_vertices)
                ancestors = genbrowser.ancestors(jet.match)
                for ancestor in ancestors:
                    if ancestor.pdgid()>=21 and ancestor.pdgid()<=37: #all gauge bosons, incl. bsm
                        jet.tags['ancestor'] = ancestor.pdgid()


import torch
import torch.nn as nn
import torch.nn.functional as F

from geneva.definitions.res_blocks import ResDownBlock

class ImageEncoder(nn.Module):
    def __init__(self, cfg):
        """Encodes Image to 16x16 features maps of depth 256
        , return the 16x16 features as well as the global sum
        pooled features(shape=512)"""
        super().__init__()
        self.encode_image = cfg.use_fg

        if self.encode_image:
            if cfg.img_encoder_type == 'res_blocks':
                self.image_encoder = nn.Sequential(
                    # 3 x 128 x 128
                    ResDownBlock(3, 64, downsample=True,
                                 use_spectral_norm=False),
                    # 64 x 64 x 64
                    nn.BatchNorm2d(64),
                    ResDownBlock(64, 128, downsample=True,
                                 use_spectral_norm=False),
                    # 128 x 32 x 32
                    nn.BatchNorm2d(128),
                    ResDownBlock(128, cfg.image_feat_dim,
                                 downsample=True,
                                 use_spectral_norm=False),
                    nn.BatchNorm2d(cfg.image_feat_dim),
                    # 256 x 16 x 16
                )
            elif cfg.img_encoder_type == 'conv':
                self.image_encoder = nn.Sequential(
                    nn.Conv2d(3, 64, 4, 2, 1, bias=False),
                    nn.ReLU(),
                    nn.BatchNorm2d(64),
                    nn.Conv2d(64, 128, 4, 2, 1, bias=False),
                    nn.ReLU(),
                    nn.BatchNorm2d(128),
                    nn.Conv2d(128, cfg.image_feat_dim, 4, 2, 1,
                              bias=False),
                    nn.BatchNorm2d(cfg.image_feat_dim),
                )

            self.object_detector = nn.Linear(cfg.image_feat_dim,
                                             cfg.num_objects)

        self.cfg = cfg

    def forward(self, img):
        if not self.encode_image:
            return None, None, None

        image_features = self.image_encoder(img)
        pooled_features = torch.sum(image_features, dim=(2, 3))

        object_detections = F.sigmoid(self.object_detector(pooled_features))
        return image_features, pooled_features, object_detections


from .model.LightningWrapper import LightningModel
# from .model.PIDNet import get_pred_model
from .dataloader.dataloader import DataModule
from .configuration.constants import CLASS_WEIGHTS, NUM_INPUT_CHANNELS, NUM_CLASSES

import torch
from lightning import Trainer
from lightning.pytorch.strategies import DDPStrategy
from lightning.pytorch.callbacks import LearningRateMonitor, StochasticWeightAveraging, ModelCheckpoint
from lightning.pytorch.callbacks.early_stopping import EarlyStopping
from lightning.pytorch.loggers import TensorBoardLogger
from .callbacks.ExtraLogger import ValidationFigureLogger, GraphLogger

def main():
    # model = get_pred_model('s', NUM_CLASSES)
    # print(model)
    # model(torch.zeros((1,3,480,640)))
    # return
    batch_size = 6
    dataset = DataModule(batch_size=batch_size, use_ycbcr=False)

    # model = LightningModel.load_from_checkpoint("lightning_logs/version_110/checkpoints/epoch=0-step=4666.ckpt")
    model = LightningModel(
        NUM_INPUT_CHANNELS,
        NUM_CLASSES,
        class_weights=CLASS_WEIGHTS,
        loss_type="focal",
        optimizer="lion",
        enable_validation_plots=True,
        learning_rate=2e-4,
        learning_rate_reduction_factor=0.8,
        tv_regularization_weighting=0.0,
        label_smoothing=0.28,
        batch_size=batch_size,
    )
    trainer = Trainer(
        max_epochs=80,
        min_epochs=5,
        val_check_interval=0.5,
        strategy=DDPStrategy(find_unused_parameters=True),
        callbacks = [
            ModelCheckpoint(save_top_k=5, monitor="Validation/IoU", mode="max"),
            LearningRateMonitor(logging_interval='step'),
            StochasticWeightAveraging(swa_lrs=0.00054),
            EarlyStopping(
                monitor="Validation/IoU",
                min_delta=0.001,
                patience=10,
                mode="max"
            )
        ],
        fast_dev_run=False,
    )
    trainer.fit(model, dataset)

if __name__ == "__main__":
    main()


# Protocol Constants

CMD_FIELD_LENGTH = 16	# Exact length of cmd field (in bytes)
LENGTH_FIELD_LENGTH = 4   # Exact length of length field (in bytes)
MAX_DATA_LENGTH = 10**LENGTH_FIELD_LENGTH-1  # Max size of data field according to protocol
MSG_HEADER_LENGTH = CMD_FIELD_LENGTH + 1 + LENGTH_FIELD_LENGTH + 1  # Exact size of header (CMD+LENGTH fields)
MAX_MSG_LENGTH = MSG_HEADER_LENGTH + MAX_DATA_LENGTH  # Max size of total message
DELIMITER = "|"  # Delimiter character in protocol
DATA_DELIMITER = "#"  # Delimiter in the data part of the message

# Protocol Messages
# In this dictionary we will have all the client and server command names

PROTOCOL_CLIENT = {
"login_msg" : "LOGIN",
"logout_msg" : "LOGOUT",
"get_score" : "MY_SCORE",
"get_high" : "HIGHSCORE",
"logged_users" : "LOGGED",
"get_question" : "GET_QUESTION",
"send_answer" : "SEND_ANSWER",
} # .. Add more commands if needed

PROTOCOL_SERVER = {
"login_ok_msg" : "LOGIN_OK",
"login_failed_msg" : "ERROR",
"send_score" : "YOUR_SCORE",
"send_high" : "ALL_SCORE",
"logged_users" : "LOGGED_ANSWER",
"send_question" : "YOUR_QUESTION",
"no_questions" : "NO_QUESTIONS",
"correct" : "CORRECT_ANSWER",
"incorrect" : "WRONG_ANSWER"
} # ..  Add more commands if needed

# Other constants

ERROR_RETURN = None  # returned in case of an error

def build_message(cmd, data):
	"""
	Gets command name (str) and data field (str) and creates a valid protocol message
	Returns: str, or None if error occured
	"""
	try:
		data = str(data)
		if type(cmd) != str:
			raise Exception
		if cmd not in PROTOCOL_CLIENT.values() and cmd not in PROTOCOL_SERVER.values():
			return None
		elif len(data) > MAX_DATA_LENGTH:
			return None
		full_msg = f'{cmd + " " * (CMD_FIELD_LENGTH - len(cmd))}{DELIMITER}{str(0) * (LENGTH_FIELD_LENGTH - len(str(len(data))))}{len(data)}{DELIMITER}{data}'
		return full_msg
	except Exception:
		print(f"Wrong parameter input: {cmd} or {data}")

def parse_message(data):
	"""
	Parses protocol message and returns command name and data field
	Returns: cmd (str), data (str). If some error occured, returns None, None
	"""
	# try:
	if type(data) != str:
		raise Exception
	elif len(data) > MAX_MSG_LENGTH:
		return (None, None)
	cnt_delimiter = data.count(DELIMITER)
	if cnt_delimiter != 2:
		return (None, None)
	for delim in range(cnt_delimiter):
		delim_index = data.index(DELIMITER)
		field = data[:delim_index]
		if delim == 0:
			cmd = field.strip()
			if cmd not in PROTOCOL_CLIENT.values() and cmd not in PROTOCOL_SERVER.values():
				return (None, None)
			data = data[delim_index + 1:]
		elif delim == 1:
			data_len = field[:delim_index].strip()
			if not data_len.isnumeric():
				return (None, None)
			msg = data[delim_index + 1:]
			# strp_msg = data_len.strip()
			if cmd not in PROTOCOL_SERVER.values() and cmd not in PROTOCOL_CLIENT.values():
				print(cmd)
				strp_msg_len = data_len.lstrip("0")
				if len(msg) != int(strp_msg_len):
					return (None, None)
	return (cmd, msg)
	# except:
	# print(f"Wrong parameter input: {data}")

def split_data(msg, expected_fields):
	"""
	Helper method. gets a string and number of expected fields in it. Splits the string
	using protocol's data field delimiter (|#) and validates that there are correct number of fields.
	Returns: list of fields if all ok. If some error occured, returns None
	"""
	list_of_strings = []
	try:
		if type(expected_fields) != int or type(msg) != str:
			raise Exception
		else:
			cnt_delimiter = msg.count(DATA_DELIMITER)
			if cnt_delimiter != expected_fields:
				return [ERROR_RETURN]
			else:
				for delim in range(cnt_delimiter):
					delim_index = msg.index(DATA_DELIMITER)
					list_of_strings.append(msg[:delim_index])
					if delim == cnt_delimiter - 1:
						list_of_strings.append(msg[delim_index + 1:])
					else:
						msg = msg[delim_index + 1:]
				return list_of_strings
	except:
		print("Wrong parameter input!")

def join_data(msg_fields):
	"""
	Helper method. Gets a list, joins all of it's fields to one string divided by the data delimiter.
	Returns: string that looks like cell1#cell2#cell3
	"""
	try:
		if type(msg_fields) != list:
			raise Exception
		final_str = DATA_DELIMITER.join(msg_fields)
		if len(final_str) > MAX_DATA_LENGTH:
			return [None]
		return final_str
	except:
		print("Wrong parameter input!")


import requests
import argparse
import logging
import sys
import time

def main(args=sys.argv[1:], **kwargs):
    '''Test the date api '''
    mainparser = argparse.ArgumentParser(
            description='''Test an API''')
    mainparser.add_argument(
        '--host',
        dest='host',
        default='http://localhost:3000',
        help='set API Url')
    mainparser.add_argument(
        '-r', '--requests',
        dest='requests',
        default=10,
        help='set number of requests you want on the service'
    )
    parser = mainparser.parse_args(args)

    logging.basicConfig(
        level=logging.INFO,
        format='%(asctime)s %(levelname)-6s %(message)s')
    logging.info(
            f'Testing API {parser.host} with {parser.requests} requests')

    success = 0
    failure = 0
    total = 0
    total_ttlb = 0

    try:
        for count, request in enumerate(range(int(parser.requests))):
            start = time.time()
            r = requests.get(f'{parser.host}')
            ttlb = round((time.time() - start) * 1000, 2)
            if r.status_code is 200:
                success = success + 1
                status = 'SUCCESS'
            else:
                failure = failure + 1
                status = 'FAILURE'

            application_version = r.headers.get('Application-Version')

            logging.info(
                f'{request + 1}: {status} TTLB:{ttlb}MS Version: {application_version}')
            total_ttlb = total_ttlb + ttlb
    except KeyboardInterrupt:
        total = count

    if total is 0:
        total = count + 1

    logging.info('------------------results------------------')
    logging.info(f'Success {success}/{total}')
    logging.info(f'Failure {failure}/{total}')
    logging.info(f'Average TTLB {round(total_ttlb/total, 2)}')

if __name__ == "__main__":
    main()


import copy
import torch
import torch.nn.functional as F

from network.bcq import Actor, Critic, VAE
from algo.algo import Algo
from utils import mmd_loss_gaussian, mmd_loss_laplacian

class DRAC(Algo):
    def __init__(self, env_name, seed, buffer_dir, summary_dir, max_timesteps,
                 eval_freq, batch_size, state_dim, action_dim, max_action,
                 device, gamma=0.99, tau=0.005, lmbda=0.75, phi=0.05):

        super().__init__(
            env_name, seed, buffer_dir, summary_dir, max_timesteps, eval_freq,
            batch_size, state_dim, action_dim, device, gamma, tau, lmbda)

        self.actor = Actor(state_dim, action_dim, max_action, phi).to(device)
        self.actor_target = copy.deepcopy(self.actor)
        self.actor_optimizer = torch.optim.Adam(self.actor.parameters(), lr=1e-3)

        self.critic = Critic(state_dim, action_dim).to(device)
        self.critic_target = copy.deepcopy(self.critic)
        self.critic_optimizer = torch.optim.Adam(self.critic.parameters(), lr=1e-3)

        latent_dim = action_dim * 2
        self.vae = VAE(state_dim, action_dim, latent_dim, max_action, device).to(device)
        self.vae_optimizer = torch.optim.Adam(self.vae.parameters())

    def train(self, iterations):

        for it in range(iterations):
            # Sample replay buffer / batch
            state, action, next_state, reward, not_done = self.store.sample()

            self.update_vae(state, action)

            next_state = torch.repeat_interleave(next_state, 10, 0)
            with torch.no_grad():
                next_action = self.actor_target(next_state, self.vae.decode(next_state))

            self.update_critic(state, action, next_state, next_action, reward, not_done)

            self.update_actor(state)

            self.update_targets()

    def select_action(self, state):
        with torch.no_grad():
            state = torch.FloatTensor(
                state.reshape(1, -1)).repeat(100, 1).to(self.device)
            action = self.actor(state, self.vae.decode(state))
            q1 = self.critic.q1(state, action)
            ind = q1.argmax(0)
        return action[ind].cpu().data.numpy().flatten()

    def update_critic(self, state, action, next_state, next_action, reward, not_done):
        with torch.no_grad():
            next_q1, next_q2 = self.critic_target(
                next_state, next_action)

            next_q = self.lmbda * torch.min(
                next_q1, next_q2) + (1. - self.lmbda) * torch.max(next_q1, next_q2)
            next_q = next_q.reshape(self.batch_size, -1).max(1)[0].reshape(-1, 1)

            target_q = reward + not_done * self.gamma * next_q

        curr_q1, curr_q2 = self.critic(state, action)
        critic_loss = F.mse_loss(curr_q1, target_q) + F.mse_loss(curr_q2, target_q)

        # >>> loss value_aug
        # curr_q1_aug, curr_q2_aug = self.critic(state_aug, action)
        # critic_loss_aug = F.mse_loss(curr_q1.detach(), curr_q1_aug) + F.mse_loss(curr_q2.detach(), curr_q2_aug)
        # >>> loss value_aug

        loss = critic_loss #+ 10.*critic_loss_aug

        self.critic_optimizer.zero_grad()
        loss.backward()
        self.critic_optimizer.step()

    def update_actor(self, state):
        sampled_actions = self.vae.decode(state)
        perturbed_actions = self.actor(state, sampled_actions)

        # state_aug = torch.repeat_interleave(state, 100, 0)
        # noise = torch.normal(0, 1, size=state_aug.size()).to(self.device)
        # state_aug += noise
        # actions_aug = self.vae.decode(state_aug)
        # _, raw_sampled_actions = self.vae.decode_multiple(
        #     state, num_decode=100)  # B x N x d
        # perturbed_actions_aug = self.actor(state_aug, actions_aug)
        # perturbed_actions_aug = perturbed_actions_aug.view(self.batch_size, 100, -1)
        # mmd_loss = mmd_loss_gaussian(
        #     raw_sampled_actions, perturbed_actions_aug, sigma=20)

        actor_loss = (
            -self.critic.q1(state, perturbed_actions)
            # + 0.1 * mmd_loss.view(-1, 1)
        ).mean()
        # actor_loss += -self.critic.q2(state, perturbed_actions).mean()

        # >>> loss value_aug
        # sampled_actions = self.vae.decode(state_aug)
        # perturbed_actions = self.actor(state_aug, sampled_actions)
        # actor_loss_aug = -self.critic.q1(state_aug, perturbed_actions).mean()
        # >>> loss value_aug

        loss = actor_loss #+ 10. * actor_loss_aug

        self.actor_optimizer.zero_grad()
        loss.backward()
        self.actor_optimizer.step()


# Given an api which returns an array of chemical names
# and an array of chemical symbols, display the chemical names
# with their symbol surrounded by square brackets:

# Ex:
# Chemicals array: ['Amazon', 'Microsoft', 'Google']
# Symbols: ['I', 'Am', 'cro', 'Na', 'le', 'abc']

# Output:
# [Am]azon, Mi[cro]soft, Goog[le]

# If the chemical string matches more than one symbol,
#  then choose the one with longest length.
#   (ex. 'Microsoft' matches 'i' and 'cro')

#!/usr/bin/env python

array = ['Amazon', 'Microsoft', 'Google']
symbols = ['I', 'Am', 'cro', 'Na', 'le', 'abc']

values = {}

for symbol in symbols:
	for name in array:
		idx = name.find(symbol)

		if idx == -1 or (name in values and values[name]['length'] > len(symbol)):
			continue

		coded = name[:idx] + '[' + name[idx:idx+len(symbol)] + ']'
		if idx + len(symbol) < len(name):
			coded += name[idx + len(symbol):]

		values[name] = {
			'length': len(symbol),
			'coded': coded
		}

print(values)


from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
from session_directory import load_session_list
import numpy as np
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import data_preprocessing as d_pp
from microscoPy_load import calcium_events as ca_events, calcium_traces as ca_traces, ff_video_fixer as FF
from scipy.stats import zscore, mode
from session_directory import get_session

session_list = load_session_list()

def PCA_session(session_index, bin_length=5, dtype='traces'):
    session = FF.load_session(session_index)

    # Get accepted neurons.
    if dtype == 'traces':
        traces, t = ca_traces.load_traces(session_index)
        traces = zscore(traces, axis=1)

        scaler = StandardScaler()
        traces = scaler.fit_transform(traces)
    elif dtype == 'events':
        traces, t = ca_events.load_events(session_index)
    else:
        raise ValueError('Wrong dtype input.')

    n_neurons = len(traces)

    # Trim the traces to only include instances where mouse is in the chamber.
    t = d_pp.trim_session(t, session.mouse_in_cage)
    traces = d_pp.trim_session(traces, session.mouse_in_cage)
    freezing = d_pp.trim_session(session.imaging_freezing, session.mouse_in_cage)

    samples_per_bin = bin_length * 20
    bins = d_pp.make_bins(t, samples_per_bin)
    n_samples = len(bins) + 1

    X = np.zeros([n_samples, n_neurons])
    for n, trace in enumerate(traces):
        binned_activity = d_pp.bin_time_series(trace, bins)
        avg_activity = [np.mean(chunk) for chunk in binned_activity]

        X[:, n] = avg_activity

    binned_freezing = d_pp.bin_time_series(freezing, bins)
    binned_freezing = [i.any() for i in binned_freezing]

    # lda = LinearDiscriminantAnalysis(solver='eigen',n_components=2,shrinkage='auto')
    # lda.fit(X,binned_freezing)
    # Y = lda.transform(X)

    pca = PCA(n_components=3)
    pca.fit(X)
    Y = pca.transform(X)

    fig = plt.figure()
    ax = Axes3D(fig)
    s = ax.scatter(Y[:, 0], Y[:, 1], Y[:, 2], c=binned_freezing)
    fig.show()

    return X, Y

def PCA_concatenated_sessions(mouse, bin_length=10, dtype='traces',
                              global_cell_idx=None, plot_flag=True,
                              ax=None):
    session_types = ('FC',
                     'E1_1',
                     'E2_1',
                     'RE_1',
                     )
    sessions, _ = get_session(mouse, session_types)

    neural_data, days, t, freezing = \
        d_pp.concatenate_sessions(sessions,
                                  dtype=dtype,
                                  global_cell_idx=global_cell_idx)

    #neural_data = zscore(neural_data,axis=1)
    bins = d_pp.make_bins(t, bin_length*20)
    neural_data = d_pp.bin_time_series(neural_data, bins)

    X = np.nanmean(np.asarray(neural_data[0:-1]), axis=2)
    X = np.append(X, np.nanmean(neural_data[-1], axis=1)[None, :],
                  axis=0)
    X.mask = np.ma.nomask
    good = np.where(~np.isnan(X))[0]
    X = X[good,:]

    # Bin freezing vector.
    binned_freezing = d_pp.bin_time_series(freezing, bins)
    freezing = np.asarray([i.any() for i in binned_freezing])
    freezing = freezing[good]

    binned_days = d_pp.bin_time_series(days, bins)
    day_id, _ = mode(np.asarray(binned_days[0:-1]), axis=1)
    day_id = np.append(day_id, mode(binned_days[-1])[0])
    day_id = day_id[good]

    # pca = PCA(n_components=3)
    # pca.fit(X)
    # Y = pca.transform(X)
    #
    # fig = plt.figure()
    # ax = Axes3D(fig)
    #
    #

    pca = PCA(n_components=2)
    pca.fit(X)
    Y = pca.transform(X)

    if plot_flag:
        if ax is None:
            fig, ax = plt.subplots()

        ax.scatter(Y[freezing, 0], Y[freezing, 1],
                   c=day_id[freezing], s=10,
                   marker='P', cmap='summer',alpha=0.2)
        ax.scatter(Y[~freezing, 0], Y[~freezing, 1],
                   c=day_id[~freezing], s=10,
                   marker='.', cmap='summer',alpha=0.2)

        freezing_center = np.zeros((len(sessions),2))
        nonfreezing_center = np.zeros_like(freezing_center)
        center = np.zeros_like(freezing_center)
        unique_days = np.unique(day_id)
        for i, day in enumerate(unique_days):
            points = Y[(day_id == day) & (freezing)]
            freezing_center[i] = np.mean(points, axis=0)

            points = Y[(day_id == day) & (~freezing)]
            nonfreezing_center[i] = np.mean(points, axis=0)

            points = Y[(day_id == day)]
            center[i] = np.mean(points, axis=0)

        # ax.scatter(freezing_center[:,0], freezing_center[:,1],
        #            marker='P', c=unique_days, cmap='summer', s=200,
        #            edgecolors='k', linewidth=2)
        # ax.scatter(nonfreezing_center[:,0], nonfreezing_center[:,1],
        #            marker='.', c=unique_days, cmap='summer', s=200,
        #            edgecolors='k', linewidth=2)
        ax.scatter(center[:,0], center[:,1], marker='o', c=unique_days,
                   cmap='summer', s=30, edgecolors='k', linewidth=2)
        ax.set_xlabel('PC 1')
        ax.set_ylabel('PC 2')

    return Y, freezing

if __name__ == '__main__':
    mice = ('Janus',
            'Kepler',
            'Mundilfari',
            'Aegir',
            )

    f, ax = plt.subplots(2,2,figsize=(6,6))
    ax = ax.ravel()
    for i, mouse in enumerate(mice):
        PCA_concatenated_sessions(mouse, ax=ax[i])

    f.show()
    pass


from __future__ import print_function

import random

import Pyro4
import pandas as pd

# List of products that will be part of the bazaar
products = ['fish', 'salt', 'boars']

# Constants for readability
BUYER = 'buyer'
SELLER = 'seller'

def main():

    # Currently two possible peer types
    peer_types = ['buyer', 'seller']

    # Reading the csv file for getting the IP's corresponding to the nodes
    df_ip = pd.read_csv('ips.csv', delimiter=',')  # Read in Node IDs as well as IP Addresses
    df_params = pd.read_csv('params.csv', delimiter=',')
    max_items = int(df_params['Value'][0])
    hop_count = int(df_params['Value'][1])
    max_wait_time = int(df_params['Value'][2])

    # Setting the Pyro nameserver host and port
    NS_HOST = df_params['Value'][3]
    NS_PORT = int(df_params['Value'][4])
    n = df_ip.shape[0]

    print('Number of nodes in the network - ', n)
    df_conn = pd.read_csv('connections.csv', delimiter=',')  # Read in the network topology edge-wise

    nodes = {}  # Dictionary that holds the Pyro4 proxy objects

    # Initializing the the nodes
    for index, row in df_ip.iterrows():
        print("Connecting to URI for :", row['Node'])
        ns = Pyro4.locateNS(host=NS_HOST, port=NS_PORT)  # use your own nameserver
        uri = ns.lookup(row['Node'])
        nodes[row['Node']] = Pyro4.Proxy(uri)
        nodes[row['Node']].init(row['Node'], row['IP'],
                                random.choice(peer_types), max_wait_time, max_items, hop_count, NS_HOST,
                                NS_PORT)  # Instantiating the peer with buyer/seller randomly
        print(nodes[row['Node']].get_peertype())

    # Adding adjacent peers for each peer to facilitate lookup
    for index, row in df_conn.iterrows():
        nodes[row['Node1']].add_neighbour(nodes[row['Node2']])
        nodes[row['Node2']].add_neighbour(nodes[row['Node1']])

    # Starting the bazaar
    for node in nodes.values():
        print("Starting node -", node.get_node_id())
        if node.get_peertype() == BUYER:  # Starts the lookup calls for every buyer
            node.node_start()
        print("Started node -", node.get_node_id())

if __name__ == "__main__":
    main()


import os
import clearbit

from django.contrib.auth import get_user_model

from celery import shared_task
from pyhunter import PyHunter

@shared_task
def add_email_status(**kwargs) -> dict:
    """
    Verifying the deliverability of an email address through hunter.io
    """
    api_key: str = os.getenv('HUNTER_API_KEY')
    UserModel = get_user_model()
    hunter: PyHunter = PyHunter(api_key)
    user: UserModel = UserModel.objects.get(username=kwargs.get('username'))
    try:
        result: dict = hunter.email_verifier(kwargs.get('email'))
        if result:
            try:
                user.email_status = result.get('status')
                user.save()
            except KeyError:
                # DO CARE ABOUT EXCEPTION HANDLING
                return {'success': False}
    except Exception:
        # DO CARE ABOUT EXCEPTION HANDLING
        return {'success': False}
    return {'success': True}

@shared_task
def add_additional_data(**kwargs) -> dict:
    """
    Adding additional user info from clearbit
    """
    clearbit.key = os.getenv('CLEARBIT_API_KEY')
    UserModel = get_user_model()
    user: UserModel = UserModel.objects.get(id=kwargs.get('user_id'))
    try:
        response: dict = clearbit.Enrichment.find(email=user.email, stream=True)
        if response and 'person' in response:
            try:
                user.first_name = response['person']['name']['givenName']
                user.last_name = response['person']['name']['familyName']
                user.save()
            except KeyError:
                # DO CARE ABOUT EXCEPTION HANDLING
                return {'success': False}
    except Exception:
        # DO CARE ABOUT EXCEPTION HANDLING
        return {'success': False}
    return {'success': True}


from collections import Counter

def originalDigits(s):
  count = Counter(s)
  uniqueChars = {
    'w': ('two', '2'),
    'u': ('four', '4'),
    'x': ('six', '6'),
    'f': ('five', '5'),
    'z': ('zero', '0'),
    'r': ('three', '3'),
    'g': ('eight',  '8'),
    's': ('seven', '7'),
    'i': ('nine', '9'),
    'n': ('one', '1')
  }
  digits = []

  for char, (word, digit) in uniqueChars.items():
    digit_count = count[char]
    digits.append(digit * digit_count)
    for char in word:
      count[char] -= digit_count

  return ''.join(sorted(digits))

#####

from collections import Counter

def originalDigits(s):
  count = Counter(s)

  # building hashmap digit -> its frequency
  out = {}
  # letter "z" is present only in "zero"
  out["0"] = count["z"]
  # letter "w" is present only in "two"
  out["2"] = count["w"]
  # letter "u" is present only in "four"
  out["4"] = count["u"]
  # letter "x" is present only in "six"
  out["6"] = count["x"]
  # letter "g" is present only in "eight"
  out["8"] = count["g"]
  # letter "h" is present only in "three" and "eight"
  out["3"] = count["h"] - out["8"]
  # letter "f" is present only in "five" and "four"
  out["5"] = count["f"] - out["4"]
  # letter "s" is present only in "seven" and "six"
  out["7"] = count["s"] - out["6"]
  # letter "i" is present in "nine", "five", "six", and "eight"
  out["9"] = count["i"] - out["5"] - out["6"] - out["8"]
  # letter "n" is present in "one", "nine", and "seven"
  out["1"] = count["n"] - out["7"] - 2 * out["9"]

  output = [key * out[key] for key in sorted(out.keys())]
  return "".join(output)


#!/usr/bin/env python

import argparse
import requests
import json
import os

from PIL import Image, ImageFont, ImageDraw
from github import Github
from dotenv import load_dotenv
from datetime import datetime
from googleapiclient.discovery import build

parser = argparse.ArgumentParser()
parser.add_argument('--simulate', '-s', required=False,
                    action='store_true', help="Simulate Inky on Mac")
args = parser.parse_args()

DOSIS_REGULAR_PATH = "fonts/dosis/Dosis-Regular.ttf"
DOSIS_BOLD_PATH = "fonts/dosis/Dosis-Bold.ttf"
GH_IMAGE_PATH = "img/GitHub-Mark-64px.png"
YT_IMAGE_PATH = "img/play-button-red-48.png"
YT_BLACK_IMAGE_PATH = "img/play-button-50.png"
USER_IMAGE_PATH = "img/user-52.png"
ILLUMINATI_IMAGE_PATH = "img/illuminati-100.png"
ILLUMINATI_WHITE_IMAGE_PATH = "img/illuminati-white-100.png"
EYE_WHITE_IMAGE_PATH = "img/eye-white-48.png"

W = 400
H = 300
BLACK = (0, 0, 0)
RED = (255, 0, 0)
WHITE = (255, 255, 255)
INNER_CIRCLE_HEIGHT_RATIO = 0.4

dosis_font_reg = ImageFont.truetype(DOSIS_REGULAR_PATH, size=40)
dosis_font_bold_lg = ImageFont.truetype(DOSIS_BOLD_PATH, size=64)
dosis_font_bold_md = ImageFont.truetype(DOSIS_BOLD_PATH, size=48)
dosis_font_bold_sm = ImageFont.truetype(DOSIS_BOLD_PATH, size=32)

# Coordinates
TOP_LEFT_C = (0, 0)
TOP_RIGHT_C = (W, 0)
BOT_LEFT_C = (0, H)
BOT_RIGHT_C = (W, H)
TOP_MID_C = (W/2, 0)
BOT_MID_C = (W/2, H)

# APIs

load_dotenv()

GITHUB_ACCESS_TOKEN = os.getenv("GITHUB_ACCESS_TOKEN")
GITHUB_API_URL = "https://api.github.com/graphql"

FITBIT_CLIENT_ID = os.getenv("FITBIT_CLIENT_ID")
FITBIT_CLIENT_SECRET = os.getenv("FITBIT_CLIENT_SECRET")

YOUTUBE_API_KEY = os.getenv("YOUTUBE_API_KEY")

YOUTUBE_CHANNEL_ID = "UCO1_BGGMvhw0ehsSBYwSbig"

# Handle Inky libraries
inky_display = None
if not args.simulate:
    from inky import InkyWHAT
    inky_display = InkyWHAT("black")
    RED = inky_display.RED
    BLACK = inky_display.BLACK
    WHITE = inky_display.WHITE
    W = inky_display.WIDTH
    H = inky_display.HEIGHT

def get_num_contributions_today(username):
    # GitHub GQL API: https://docs.github.com/en/free-pro-team@latest/graphql/reference/objects#contributionscollection
    query = """
    query {
        user(login: "%s") {
            name
            contributionsCollection {
                contributionCalendar {
                    colors
                    totalContributions
                    weeks {
                        contributionDays {
                            color
                            contributionCount
                            date
                            weekday
                        }
                        firstDay
                    }
                }
            }
        }
    }""" % username
    print(query)

    r = requests.post(GITHUB_API_URL, data=json.dumps({"query": query}), headers={
                      "Authorization": "bearer {token}".format(token=GITHUB_ACCESS_TOKEN)})
    data = r.json()
    weeks = data["data"]["user"]["contributionsCollection"]["contributionCalendar"]["weeks"]

    num_contributions = 0

    for week in weeks:
        for day in week["contributionDays"]:
            # Date like 2019-11-03
            date = datetime.strptime(day["date"], '%Y-%m-%d').date()
            if date != datetime.today().date():
                continue
            num_contributions = day["contributionCount"]
            break
        if num_contributions > 0:
            # Found current date
            break

    return num_contributions

def get_youtube_stats():
    """
    Gets channel stats.
    """
    youtube = build('youtube', 'v3', developerKey=YOUTUBE_API_KEY)
    request = youtube.channels().list(
        part="statistics",
        id=YOUTUBE_CHANNEL_ID
    )
    response = request.execute()

    return response['items'][0]['statistics']

def get_youtube_top_recent_commment():
    """
    Gets top comment by like count from recent 100(?) comments for the channel.
    """
    youtube = build('youtube', 'v3', developerKey=YOUTUBE_API_KEY)
    comments = youtube.commentThreads().list(
        part="snippet,replies",
        allThreadsRelatedToChannelId=YOUTUBE_CHANNEL_ID
    ).execute()["items"]

    top_comment = max(
        comments,
        key=get_youtube_comment_score
    )
    print("top comment", top_comment)
    return top_comment

def get_youtube_comment_score(comment):
    likes = -1
    try:
        snippet = comment["snippet"]["topLevelComment"]["snippet"]
        published_at = snippet["publishedAt"]
        published_at = datetime.strptime(published_at, "%Y-%m-%dT%H:%M:%SZ")

        # Exponential decay score by published date
        print("delta", datetime.now() - published_at)
        delta_weeks = (datetime.now() - published_at).days / 7
        likes = snippet["likeCount"]
        factor = 0.5
        likes *= (factor ** (delta_weeks))
    except KeyError:
        return -1
    return likes

# Drawing helpers

def reflow_quote(quote, width, font):
    words = quote.split(" ")
    reflowed = '"'
    line_length = 0

    for i in range(len(words)):
        word = words[i] + " "
        word_length = font.getsize(word)[0]
        line_length += word_length

        if line_length < width:
            reflowed += word
        else:
            line_length = word_length
            reflowed = reflowed[:-1] + "\n  " + word

    reflowed = reflowed.rstrip() + '"'

    return reflowed

def init_image():
    img = Image.new("P", (W, H), color=WHITE)
    draw = ImageDraw.Draw(img)
    print("-- Initialized Image (W: {w}, H: {h}) --".format(w=W, h=H))
    return img, draw

def draw_old():
    img, draw = init_image()

    # Draw stripes
    draw.rectangle([TOP_LEFT_C, (W, H/8)], fill=RED)
    draw.rectangle([(0, 2*H/3), BOT_RIGHT_C], fill=RED)

    # Put channel name and YT icon
    title_row_y = int(2*H/7)
    icon_w = 36
    icon_title_padding = 8
    yt_channel_title = "kelseymakesthings"
    title_center_x = W/2 + icon_w/2 + icon_title_padding/2
    draw.text((title_center_x, title_row_y), yt_channel_title,
              fill=BLACK, font=dosis_font_bold_sm, anchor="mm")
    title_size = dosis_font_bold_sm.getsize(yt_channel_title)

    yt_icon_x = int(title_center_x - title_size[0]/2 -
                    icon_w - icon_title_padding)
    yt_img = Image.open(YT_IMAGE_PATH)
    yt_img = yt_img.resize((icon_w, icon_w))
    img.paste(yt_img, box=(yt_icon_x, int(title_row_y - icon_w/2)), mask=yt_img)

    # Get num GitHub contributions
    # num_contributions = get_num_contributions_today("Lbkchen")
    # left_num_c = (W/6, H/2)
    # draw.text(left_num_c, "{n}".format(n=num_contributions),
    #           fill=BLACK, font=dosis_font_bold_md, anchor="mm")

    # Get subs
    youtube_stats = get_youtube_stats()
    num_subscribers = youtube_stats["subscriberCount"]
    subscribers_c = (W/2, H/2)
    num_subscribers = "{n}".format(n=num_subscribers)
    draw.text(subscribers_c, num_subscribers,
              fill=BLACK, font=dosis_font_bold_lg, anchor="mm")
    num_subscribers_size = dosis_font_bold_lg.getsize(num_subscribers)

    icon_w = 32
    icon_padding = 10
    user_img = Image.open(USER_IMAGE_PATH)
    user_img = user_img.resize((icon_w, icon_w))
    user_icon_x = int(W/2 - num_subscribers_size[0]/2 - icon_padding - icon_w)
    user_icon_y = int(H/2 - icon_w/2)
    img.paste(user_img, box=(user_icon_x, user_icon_y), mask=user_img)

    # Get view count
    num_views = youtube_stats["viewCount"]
    num_views = "{n}".format(n=num_views)
    num_views_y = int(5/6 * H)
    num_views_c = (W/2, num_views_y)
    draw.text(num_views_c, num_views, fill=WHITE,
              font=dosis_font_bold_md, anchor="mm")
    num_views_size = dosis_font_bold_md.getsize(num_views)

    icon_w = 25
    icon_padding = 10
    eye_img = Image.open(EYE_WHITE_IMAGE_PATH)
    eye_img = eye_img.resize((icon_w, icon_w))
    eye_icon_x = int(W/2 - num_views_size[0]/2 - icon_padding - icon_w)
    eye_icon_y = int(num_views_y - icon_w/2)
    img.paste(eye_img, box=(eye_icon_x, eye_icon_y), mask=eye_img)

    return img

def draw():
    img, draw = init_image()

    # Draw logo
    icon_w = 50
    icon_padding = 6
    yt_img = Image.open(YT_BLACK_IMAGE_PATH)
    yt_img = yt_img.resize((icon_w, icon_w))
    img.paste(yt_img, box=(icon_padding, icon_padding), mask=yt_img)

    # Get subscribers
    youtube_stats = get_youtube_stats()
    num_subscribers = youtube_stats["subscriberCount"]
    num_subscribers = "{n}".format(n=num_subscribers)
    draw.text((icon_w + icon_padding*2, icon_w/2 + icon_padding), num_subscribers,
              fill=BLACK, font=dosis_font_bold_md, anchor="lm")

    # Draw top comment frame
    footer_h = 36
    frame_edge_padding = 10
    frame_top_y = icon_w + icon_padding*2
    frame_bottom_y = H - footer_h - frame_edge_padding

    draw.rectangle([(frame_edge_padding, frame_top_y),
                    (W - frame_edge_padding, frame_bottom_y)], fill=BLACK)

    # Get YT top comment
    comment = comment = get_youtube_top_recent_commment()
    try:
        quote = comment["snippet"]["topLevelComment"]["snippet"]["textDisplay"]
        author = comment["snippet"]["topLevelComment"]["snippet"]["authorDisplayName"]
    except KeyError:
        quote = "Failed lol"
        author = "pleb"

    quote_padding = 15
    quote_font = dosis_font_bold_sm

    # Check overflow
    # quote = "kelsey when is the mixtape dropping lol this is so funny and reflowed lol so funny and reflowed lol reflowed lol so funny and reflowed lol"
    reflowed_quote = reflow_quote(quote, W - quote_padding*2, quote_font)
    if reflowed_quote.count("\n") + 1 > 5:  # Hard coded line count
        reflowed_quote = "\n".join(reflowed_quote.split("\n")[:5])
        reflowed_quote = " ".join(reflowed_quote.split(" ")[:-1]) + '..."'

    # Draw quote
    draw.multiline_text((quote_padding, frame_top_y + 2), reflowed_quote,
                        fill=WHITE, font=quote_font, align="left")

    # Draw author
    footer_padding = 6
    draw.text((W - footer_padding, H - footer_padding), f"-{author}",
              fill=BLACK, font=dosis_font_bold_sm, anchor="rd")

    return img

def set_inky_display(img):
    # Preview image
    if args.simulate:
        print("-- Showing simulated image now --")
        img.show()
    else:
        print("-- Showing image on inky display now --")
        inky_display.set_image(img)
        inky_display.show()

def main():
    img = draw()
    set_inky_display(img)

if __name__ == "__main__":
    main()


import typing
from collections import namedtuple

Hook = namedtuple('Hook', ('func', 'args', 'kwargs', 'priority'))

class HookManager:

    def __init__(self):
        self.hooks = []  # type: typing.List[Hook]

    def add(self, func, args=None, kwargs=None, priority=100):
        self.hooks.append(Hook(func, args, kwargs, priority))
        self.hooks.sort(key=lambda x: x.priority)

    async def run_hooks(self):
        for hook in self.hooks:
            await hook.func(*hook.args, **hook.kwargs)

hook_manager = HookManager()


# Insertion sort is a simple sorting algorithm for a small number of elements.

# In Insertion sort, you compare the key element with the previous elements. If the previous elements are greater than the key element,
# then you move the previous element to the next position.

def insertionSort(arr):
    #na przedziale od indexu 1 do (rozmiar(tabeli))
    for i in range(1, len(arr)):

        key = arr[i]  # default arr[1]
        # print(key)
        # Move elements of arr[0.. i-1], that are greater than key, to one position ahead of their current position
        j = i - 1
        # print(j)
        while j >=0 and key < arr[j]:  # i == 1, j == 0, key == arr[0]
            arr[j+1] = arr[j]
            j -= 1
        arr[j+1] = key

# Sorting the array [12, 11, 13, 5, 6] using insertionSort
arr = [2004, 105, 600, 1, 5, 28, 125, 1590, -5]
insertionSort(arr)
lst = []
print("Sorted array is: ")
for i in range(len(arr)):
    lst.append(arr[i])
print(lst)

# Time Complexity: O(N^2)
# Auxiliary Space: O(1)


# Data Model:
# ===========
# lines is a list of "\n" terminated strings from the input file
# each line is a coordinate pair row,col that are stored in a list
# as integer tuples.  The list index is the "name" of the coordinate
# grid is matrix (list of lists) of integers -1 means no closest coordinate
# 0..n means that that is the closest coordinate pair

def part1(lines):
    coords = parse(lines)
    grid = build_grid(coords)
    fill_grid(grid, coords)
    # print(grid)
    area = largest_area(grid)
    return area

def part2(lines):
    coords = parse(lines)
    area = safe_area(coords)
    return area

def parse(lines):
    coords = []
    for line in lines:
        x,y = line.strip().split(", ")
        coords.append((int(x),int(y)))
    return coords

def build_grid(coords):
    min_x, min_y, max_x, max_y = get_bounds(coords)
    #print(min_x, min_y, max_x, max_y)
    x_size = max_x - min_x + 1
    y_size = max_y - min_y + 1
    grid = []
    for y in range (0, y_size):
        grid.append([-1] * x_size)
    for i in range(0,len(coords)):
        x,y = coords[i]
        grid[y-min_y][x-min_x] = i
    return grid

def fill_grid(grid, coords):
    min_x, min_y, max_x, max_y = get_bounds(coords)
    for gy, row in enumerate(grid):
        for gx, cell in enumerate(row):
            if cell > -1:
                continue
            closest = -1
            min_dist = max_x + max_y
            for i, coord in enumerate(coords):
                x,y = coord
                x = x - min_x
                y = y - min_y
                dist = abs(x-gx) + abs(y-gy)
                if dist < min_dist:
                    min_dist = dist
                    closest = i
                elif dist == min_dist:
                    closest = -1
            if closest > -1:
                grid[gy][gx] = closest

def fill_grid2(grid, coords):
    min_x, min_y, max_x, max_y = get_bounds(coords)
    for gy, row in enumerate(grid):
        for gx, cell in enumerate(row):
            if cell > -1:
                continue
            closest = -1
            min_dist = max_x + max_y
            for i, coord in enumerate(coords):
                x,y = coord
                x = x - min_x
                y = y - min_y
                dist = abs(x-gx) + abs(y-gy)
                if dist < min_dist:
                    min_dist = dist
                    closest = i
                elif dist == min_dist:
                    closest = -1
            if closest > -1:
                grid[gy][gx] = closest

def largest_area(grid):
    infinite = set() # a set of the indexes on the edges (they have infinite area and are ignored)
    areas = {} # a count by index of the non-infinite areas
    max_x = len(grid[0])
    max_y = len(grid)
    for y in range(0,max_y):
        for x in range(0,max_x):
            area = grid[y][x]
            if area == -1:
                continue
            if x == 0 or x == max_x -1:
                infinite.add(area)
                if area in areas: del areas[area]
            if y == 0 or y == max_y -1:
                infinite.add(area)
                if area in areas: del areas[area]
            if area in infinite:
                continue
            if area in areas:
                areas[area] += 1
            else:
                areas[area] = 1
    # print(areas)
    max_size = 0
    for size in areas.values():
        if size > max_size:
            max_size = size
    return max_size

def safe_area(coords):
    # I do not need a grid, I just look at all cells
    # in the bounds, and add it to the total if
    # it meets the distance criteria
    total = 0
    min_x, min_y, max_x, max_y = get_bounds(coords)
    for x in range(min_x,max_x+1):
        for y in range(min_y,max_y+1):
            dist = 0
            for cx,cy in coords:
                dist += abs(cx-x) + abs(cy-y)
                if dist >= MAX_DIST: break
            if dist < MAX_DIST:
                total += 1
    return total

def get_bounds(coords):
    min_x = min([x for x,_ in coords])
    min_y = min([y for _,y in coords])
    max_x = max([x for x,_ in coords])
    max_y = max([y for _,y in coords])
    return min_x, min_y, max_x, max_y

MAX_DIST = 10_000  # 32 for testing, 10_000 for input

if __name__ == '__main__':
    # lines = open("test.txt").readlines() # as a list of line strings
    lines = open("input.txt").readlines() # as a list of line strings
    print(f"Part 1: {part1(lines)}")
    print(f"Part 2: {part2(lines)}")


### import modules
from argparse import ArgumentTypeError
import argparse
import os
from Bio import SeqIO
import re
import numpy as np
import random
import khmer
import warnings
import pandas as pd
import copy
import matplotlib.pyplot as plt
import seaborn as sb

from script.benchmark_1_pilot_ext_randstrobe_vs_regular_randstrobe import generate_string_list_from_genome, generate_mutated_strings

def get_kmer_set_from_str(seq, ksize):
	"""
	Generate a kmer set from input string
	"""
	temp = set()
	for i in range(len(seq) - ksize + 1):
		temp.add(seq[i:i + ksize])
	return temp

def get_randstrobe_set_from_str(seq, n, l, wmin, wmax, prime):
	"""
	Get a randstrobe set from input string
	"""
	temp = set()
	# loop through index
	for i in range(len(seq) - n * l + 1):
		# max window size: only activate when approaching the tail of seq, o.w. is w_max
		wu = int(min(wmax, (len(seq) - i - l + 1) / (n - 1)))  # in case of wu -wl < 1, use int
		# min window size: make sure no overlap strobes: lenth l < window min
		wl = max(wmin - (wmax - wu), l)
		# manually stop (may generate empty records in the j loop)
		if wu < wl:
			break
		elif wu == wl:
			# start from here, all remaining strobemers are regular kmer (may have wu - wl < 1 -> several kmers at end)
			fix_seq = seq[i:i + n * l]
			temp.add(fix_seq)
			continue

		# ranstrobe: 1st strobe
		rand_seq = seq[i:i + l]
		last_strobe = seq[i:i + l]
		# randstrobe loop
		for j in range(2, n + 1):
			# this will generate empty list when wu <= wl
			select_window = list(range(i + wl + (j - 2) * wu, i + (j - 1) * wu, 1))
			current_pos = 0
			current_hash = prime + 10  # init loop
			# find argmin in current window
			for pos in select_window:
				new_hash = (khmer.hash_no_rc_murmur3(seq[pos:pos + l]) + khmer.hash_no_rc_murmur3(last_strobe)) % prime
				if new_hash < current_hash:
					current_hash = new_hash
					current_pos = pos
			# update last strobe
			last_strobe = seq[current_pos:current_pos + l]
			# add this strobe to randstrobe
			rand_seq += seq[current_pos:current_pos + l]

		# End of current cycle, add the current randstrobe to the set
		temp.add(rand_seq)

	return temp

def is_kmer_an_open_syncmer_both_strand_for_submer(input_string: str, submer_length: int):
	"""
	Determine if a given kmer (string) is an OPEN syncmer at given submer_length via lexicographic order.
	Consider submer for both directions (same as Strobe-align)
	:param input_string: a kmer
	:param submer_length: the length substring in this kmer for syncmer selection
	"""
	temp_start = input_string[:submer_length]
	temp_start = min(temp_start, khmer.reverse_complement(temp_start))
	for i in range(len(input_string) - submer_length + 1):
		another_submer = input_string[i:i+submer_length]
		another_submer = min(another_submer, khmer.reverse_complement(another_submer))
		if temp_start > another_submer:
			return False
	# o.w., the start is minimum, so this is an open syncmer
	return True

def get_syncmer_set_from_kmer_set(kmer_set, submer_length: int):
	"""
	Get a syncmer set from input string
	"""
	temp = set()
	for kmer in kmer_set:
		if is_kmer_an_open_syncmer_both_strand_for_submer(kmer, submer_length):
			temp.add(kmer)

	return temp

### main object to store 3 types of k-mers and calculate JI
class simple_kmer_list_for_seq:
	def __init__(self, seq: str, k: int=20, submer_length:int=15, n: int=2, l: int=10, wmin: int=25, wmax: int=50, prime: int=6229):
		"""
		Create a simple kmer object to store 3 types of k-mers and calculate JI
		"""
		self.seq = seq # input sequence (a single string)
		self.k = k  # kmer length
		self.n = n  # strobe number
		self.l = l  # strobe length
		self.wmin = wmin # strobe window min
		self.wmax = wmax # strobe window max
		self.prime = prime # prime for randstrobe
		self.submer_length = submer_length # submer for syncmer
		### kmer lists:
		self.kmer_set = get_kmer_set_from_str(seq, ksize=k)
		self.randstrobe_set = get_randstrobe_set_from_str(seq, n=n, l=l, wmin=wmin, wmax=wmax, prime=prime)
		self.syncmer_set = get_syncmer_set_from_kmer_set(self.kmer_set, submer_length=submer_length)

	def calculate_ji_with_another_obj(self, other):
		kmer_ji = 1.0 * len(self.kmer_set.intersection(other.kmer_set)) / len(self.kmer_set.union(other.kmer_set))
		randstrobe_ji = 1.0 * len(self.randstrobe_set.intersection(other.randstrobe_set)) / len(self.randstrobe_set.union(other.randstrobe_set))
		syncmer_ji = 1.0 * len(self.syncmer_set.intersection(other.syncmer_set)) / len(self.syncmer_set.union(other.syncmer_set))

		results = [round(kmer_ji, 3), round(randstrobe_ji,3), round(syncmer_ji, 3)]
		return results

### local variables
def local_test_variable():
	"""
	setup var for local test
	"""
	print("Loading local variables")
	genome_file = '/Users/shaopeng/Library/CloudStorage/OneDrive-ThePennsylvaniaStateUniversity/PSU_academic/Koslicki_lab/research/strobemer_truncation/input_genomes/GCA_000014345.1_ASM1434v1_genomic.fna'
	sample_size = 10
	k_value = 20
	p_values = [0.01, 0.03, 0.05, 0.08, 0.1, 0.15, 0.2, 0.3]
	seq_length = 30000
	wmin=25
	wmax=50

### run analysis
if __name__ == '__main__':
	parser = argparse.ArgumentParser(description="Strobemer simulation",
	                                 formatter_class=argparse.ArgumentDefaultsHelpFormatter)
	parser.add_argument('-g', '--genome', help="Path to input genomes")
	parser.add_argument('-k', '--kvalue', type=int, help="K value to use", default="20")
	parser.add_argument('-n', '--sample_size', type=int, help="Number of technical replicates", default=10)
	parser.add_argument('-p', '--p_range', type=str, help="mutation rate range",
	                    default="0.01,0.03,0.05,0.08,0.1,0.15,0.2,0.3")
	parser.add_argument('-w', '--window_min', type=int, help="Min window size", default=25)
	parser.add_argument('-e', '--window_max', type=int, help="Max window size", default=50)
	parser.add_argument('-l', '--seq_length', type=int, help="Seq length for the test", default=30000)

	########################################## read parameters
	args = parser.parse_args()

	if not os.path.exists(args.genome):
		raise Exception("Input file %s does not exist." % args.genome)
	genome_file = os.path.abspath(args.genome)
	print("Input genome file is " + genome_file)

	sample_size = args.sample_size
	print("Permutation sample size is " + str(sample_size))

	k_value = args.kvalue
	print("The k value is ")
	print(k_value)

	p_range = args.p_range
	p_values = [float(x) for x in p_range.split(",")]
	print("The range of mutation rate p values are: ")
	print(p_values)

	seq_length = args.seq_length
	print("The sequence length to keep is %s" % seq_length)
	wmin = args.window_min
	print("Window size min is %s" % wmin)
	wmax = args.window_max
	print("Window size max is %s" % max)

	########################################## Step1: prepare genome
	not_unknown = re.compile('[nN]')
	# read genome files into a long string
	raw_seq = generate_string_list_from_genome(genome_file)
	cleaned_seq_list = []
	for fragment in raw_seq:
		fragment = fragment.upper()
		frag_split_onlyACTG = not_unknown.split(fragment)
		cleaned_seq_list.extend([x for x in frag_split_onlyACTG if len(x) > 0])

	### for this test, we only need 1 string not the multiple records per chr, so manually concatenate it
	out_seq = "".join(cleaned_seq_list)[:seq_length]
	print("The seq length is " + str(len(out_seq)))

	########################################## Step2: loop through mutation rate p and rep 10 times for JI calculation
	original_obj = simple_kmer_list_for_seq(seq=out_seq)
	out_dict = {}

	for mutation_rate_p in p_values:
		out_ji = [0, 0, 0] # init
		for i in range(sample_size):
			mutated_seq = generate_mutated_strings(input_string=out_seq, p=mutation_rate_p)
			mutated_obj = simple_kmer_list_for_seq(seq=mutated_seq)
			ji_out = original_obj.calculate_ji_with_another_obj(mutated_obj)
			out_ji = [sum(x) for x in zip(out_ji, ji_out)]
		# get mean for sample_size times
		out_dict[str(mutation_rate_p)] = [round(x/sample_size,3) for x in out_ji]

	final_table = pd.DataFrame(out_dict)
	final_table.index = ['kmer_JI', 'randstrobe_JI', 'syncmer_JI']
	final_table.to_csv("Compare_JI_of_3_types_of_kmers.csv", header=True)

	# make plot
	out_df = final_table.transpose()
	out_df['mut_p'] = out_df.index
	plot_df = out_df.melt('mut_p', var_name="cols", value_name="JI values")

	fig, axs = plt.subplots(1, 1)
	sb.pointplot(x="mut_p", y="JI values", hue='cols', data=plot_df, ax=axs)
	axs.set_title("Comparison of JIs for 3 types of kmers")
	fig.savefig("_".join(["Compare_JI_3_types_of_kmers.png"]), dpi=300)
	plt.close(fig)


class Solution:
    def canJump(self, nums: List[int]) -> bool:
        end_pos = 0

        for i,num in enumerate(nums):
            if end_pos < i :
                return False
            end_pos = max(end_pos,i+num)
        return True