# libraries
import numpy as np
from scipy import signal

# scalar for RNG values
TRAINABLE_INIT_SCALE = 0.25

def setTIS(n):
	TRAINABLE_INIT_SCALE = n

# layer superclass
class Layer:
	def __init__(self):
		self.input = None
		self.output = None

	# forward propogation function
	def forward(self, x):
		return x

	# backward propogation function
	def backward(self, output_delta):
		return output_delta

	# update trainable parameters
	def update(self, eta):
		pass

	# reset trainable parameters
	def reset(self):
		pass

# fully connected layer
class Dense(Layer):
	def __init__(self, input_size, output_size):
		super().__init__()

		self.input_size = input_size
		self.output_size = output_size

		self.biases = np.random.randn(output_size, 1) * TRAINABLE_INIT_SCALE
		self.weights = np.random.randn(output_size, input_size) * TRAINABLE_INIT_SCALE

		self.biases_grads_sum = np.zeros((output_size, 1))
		self.weights_grads_sum = np.zeros((self.output_size, self.input_size))

	def forward(self, x):
		self.input = x
		self.output = np.dot(self.weights, self.input) + self.biases
		return self.output

	def backward(self, output_delta):
		biases_delta = output_delta
		weights_delta = np.dot(output_delta, self.input.T)
		input_delta = np.dot(self.weights.T, output_delta)

		self.biases_grads_sum += biases_delta
		self.weights_grads_sum += weights_delta
		return input_delta

	def update(self, eta):
		self.biases -= self.biases_grads_sum * eta
		self.weights -= self.weights_grads_sum * eta

		self.biases_grads_sum = np.zeros((self.output_size, 1))
		self.weights_grads_sum = np.zeros((self.output_size, self.input_size))

	def reset(self):
		self.update(0)
		self.biases = np.random.randn(self.output_size, 1) * TRAINABLE_INIT_SCALE
		self.weights = np.random.randn(self.output_size, self.input_size) * TRAINABLE_INIT_SCALE

# reshape layer
class Reshape(Layer):
	def __init__(self, input_shape, output_shape):
		self.input_shape = input_shape
		self.output_shape = output_shape

	def forward(self, x):
		return np.reshape(x, self.output_shape)

	def backward(self, output_delta):
		return np.reshape(output_delta, self.input_shape)

# convolutional layer
class Convolutional2D(Layer):
	def __init__(self, input_shape, kernel_size, kernel_count):
		super().__init__()
		input_depth, input_height, input_width = input_shape
		self.input_shape = input_shape
		self.input_depth = input_depth
		self.kernel_count = kernel_count
		self.kernels_shape = (kernel_count, input_depth, kernel_size, kernel_size)
		self.output_shape = (kernel_count, input_height - kernel_size + 1, input_width - kernel_size + 1)

		self.biases = np.random.randn(*self.output_shape) * TRAINABLE_INIT_SCALE
		self.kernels = np.random.randn(*self.kernels_shape) * TRAINABLE_INIT_SCALE

		self.biases_grads_sum = np.zeros(self.output_shape)
		self.kernel_grads_sum = np.zeros(self.kernels_shape)

	def forward(self, x):
		self.input = x
		self.output = np.copy(self.biases)

		for i in range(self.kernel_count):
			for j in range(self.input_depth):
				self.output[i] += signal.correlate2d(self.input[j], self.kernels[i, j], 'valid')

		return self.output

	def backward(self, output_delta):
		biases_delta = output_delta
		kernels_delta = np.zeros(self.kernels_shape)
		input_delta = np.zeros(self.input_shape)

		for i in range(self.kernel_count):
			for j in range(self.input_depth):
				kernels_delta[i, j] = signal.correlate2d(self.input[j], output_delta[i], 'valid')
				input_delta[j] += signal.convolve2d(output_delta[i], self.kernels[i, j], 'full')

		self.biases_grads_sum += biases_delta
		self.kernel_grads_sum += kernels_delta
		return input_delta

	def update(self, eta):
		self.biases -= self.biases_grads_sum * eta
		self.kernels -= self.kernel_grads_sum * eta

		self.biases_grads_sum = np.zeros(self.output_shape)
		self.kernel_grads_sum = np.zeros(self.kernels_shape)

	def reset(self):
		self.update(0)
		self.biases = np.random.randn(*self.output_shape) * TRAINABLE_INIT_SCALE
		self.kernels = np.random.randn(*self.kernels_shape) * TRAINABLE_INIT_SCALE

# transposed convolutional layer
class ConvolutionalTranspose2D(Convolutional2D):
	def __init__(self, input_shape, kernel_size, kernel_count):
		input_depth, input_height, input_width = input_shape
		self.input_shape = input_shape
		self.input_depth = input_depth
		self.kernel_count = kernel_count
		self.kernels_shape = (kernel_count, input_depth, kernel_size, kernel_size)
		self.output_shape = (kernel_count, input_height + kernel_size - 1, input_width + kernel_size - 1)

		self.biases = np.random.randn(*self.output_shape) * TRAINABLE_INIT_SCALE
		self.kernels = np.random.randn(*self.kernels_shape) * TRAINABLE_INIT_SCALE

		self.biases_grads_sum = np.zeros(self.output_shape)
		self.kernel_grads_sum = np.zeros(self.kernels_shape)

	def forward(self, x):
		self.input = x
		self.output = np.copy(self.biases)

		for i in range(self.kernel_count):
			for j in range(self.input_depth):
				self.output[i] += signal.correlate2d(self.input[j], self.kernels[i, j], 'full')

		return self.output

	def backward(self, output_delta):
		biases_delta = output_delta
		kernels_delta = np.zeros(self.kernels_shape)
		input_delta = np.zeros(self.input_shape)

		for i in range(self.kernel_count):
			for j in range(self.input_depth):
				kernels_delta[i, j] = signal.correlate2d(self.input[j], output_delta[i], 'valid')
				input_delta[j] += signal.convolve2d(output_delta[i], self.kernels[i, j], 'valid')

		self.biases_grads_sum += biases_delta
		self.kernel_grads_sum += kernels_delta
		return input_delta

# max pooling layer
class MaxPooling2D(Layer):
	def __init__(self, input_shape, pool_size):
		super().__init__()
		input_depth, input_height, input_width = input_shape
		self.input_depth = input_depth
		self.input_shape = input_shape
		self.input_mask = np.zeros(input_shape)

		pool_height, pool_width = pool_size
		self.pool_height = pool_height
		self.pool_width = pool_width

		self.output_height = int(input_height / pool_height)
		self.output_width = int(input_width / pool_width)
		self.output_shape = (self.input_depth, self.output_height, self.output_width)

	def forward(self, x):
		self.input = x
		self.input_mask = np.zeros(self.input_shape)
		self.output = np.zeros(self.output_shape)

		for i in range(self.input_depth):
			for j in range(self.pool_height):
				for k in range(self.pool_width):
					j0 = j*self.pool_height
					j1 = (j+1)*self.pool_height
					k0 = k*self.pool_width
					k1 = (k+1)*self.pool_width

					pool = x[i][j0:j1, k0:k1]
					max_y, max_x = np.unravel_index(pool.argmax(), pool.shape)

					self.input_mask[i][j0+max_y][k0+max_x] = 1
					self.output[i][j][k] = pool[max_y][max_x]

		return self.output

	def backward(self, output_delta):
		input_delta = self.input_mask

		for i in range(self.input_depth):
			for j in range(self.output_height):
				for k in range(self.output_width):
					j0 = j*self.pool_height
					j1 = (j+1)*self.pool_height
					k0 = k*self.pool_width
					k1 = (k+1)*self.pool_width

					input_delta[i][j0:j1, k0:k1] *= output_delta[i][j][k]

		return input_delta

# for padding edges and intra-pixel space of images with zeros
class ZeroPadding2D(Layer):
	def __init__(self, input_shape, extra_padding, intra_padding):
		self.input_shape = input_shape
		self.extra_padding = extra_padding
		self.intra_padding = intra_padding

		self.ep_pattern = ((0,0), (extra_padding,extra_padding), (extra_padding,extra_padding))
		# enable for equal top-left and bottom-right pixel padding
		#self.ep_pattern = ((0,0), (extra_padding,extra_padding+intra_padding), (extra_padding,extra_padding+intra_padding))
		self.ip_pattern = ((0,0), (intra_padding,0), (intra_padding,0))
		self.ip_kernel = np.pad(np.ones((1,1,1)), self.ip_pattern)

	def forward(self, x):
		return np.pad(np.kron(x, self.ip_kernel), self.ep_pattern)

	def backward(self, output_delta):
		ep = self.extra_padding
		# enable for equal top-left and bottom-right pixel padding
		#ep = self.extra_padding + self.intra_padding
		ip = self.intra_padding + 1
		return output_delta[:, ep:-ep or None:ip, ep:-ep or None:ip]


import csv
from datetime import date, timedelta
from .ApiSheetClient import ApiSheetClient
import requests

class SGReader:

    def __init__(self, DDV_Mapping):

        self.EUSIPA_Mapping = {
            "1100 Uncapped Capital Protection": ["Kapitalschutz-Zertifikate"],
            "1120 Capped Capital Protection": [],
            "1130 Capital Protection with Knock-Out": [],
            "1140 Capital protection with Coupon": [],
            "1199 Miscellaneous Capital Protection": [],
            "1200 Discount Certificates": ["Discount-Zertifikate", "Classic Discount-Zertifikat"],
            "1220 Reverse Convertibles": ["Classic Aktienanleihen", "Classic Aktienanleihen", "Aktienanleihen Plus", "Aktienanleihen PlusPro", "Aktienanleihen Protect"],
            "1230 Barrier Reverse Convertibles": [],
            "1240 Capped Outperformance Certificates": ["Sprint-Zertifikat"],
            "1260 Express Certificates": ["Memory Express-Zertifikat", "Duo Memory Express-Zertifikat", "Multi Express-Zertifikat", "Multi Memory Express-Zertifikat", "Stufenexpress-Zertifikat", "Fixkupon Express-Zertifikat", "Duo Fixkupon Express-Zertifikat"],
            "1299 Miscellaneous Yield Enhancement": [],
            "1300 Tracker Certificates": ["Index-Zertifiakte", "Short Index-Zertifikate"],
            "1310 Outperformance Certificates": ["Outperformance-Zertifikat"],
            "1320 Bonus Certificates": ["Classic Bonus-Zertifiakt", "Bonus-Zertifiakte Pro", "Capped Bonus-Zertifiakt", "Capped Bonus-Zertifiakt Pro","Reverse Capped Bonus-Zertifikat"],
            "1399 Miscellaneous Participation": [],
            "2100 Warrants": ["Standard-Optionsscheine", "Discount-Optionsscheine", "Inline-Optionsscheine", "StayLow-Optionsscheine", "StayHigh-Optionsscheine", "Turbo-Optionsscheine", "Classic Turbo-Optionsscheine", "Unlimited Turbo-Optionsscheine", "Smart Turbo-Optionsscheine", "BEST Turbo-Optionsscheine", "X-BEST Turbo Optionsscheine", "Faktor-Optionsscheine"],
            "2199 Miscellaneous Leverage without Knock-Out": [],
            "2200 Knock-Out Warrants": [],
            "2210 Mini-Futures": [],
            "2299 Miscellaneous Leverage with Knock-Out": [],
            "2300 Constant Leverage Certificate": [],
            "2399 Miscellaneous Leverage with Knock-Out": [],
            "1340 Twin-Win Certificates": []
        }

        self.Mapping = {
            "Zertifikate": {
                "Aktienanleihen": {
                    53: {
                        59: "Classic Aktienanleihen",
                        59: "Aktienanleihen Plus",
                        61: "Aktienanleihen PlusPro",
                        62: "Aktienanleihen Protect"
                    },
                },
                "Bonus-Zertifikate": {
                    16: {
                        17: "Classic Bonus-Zertifiakt",
                        18: "Bonus-Zertifiakte Pro",
                        19: "Capped Bonus-Zertifiakt",
                        204: "Capped Bonus-Zertifiakt Pro",
                        86: "Reverse Capped Bonus-Zertifikat"
                    }
                },
                "Kapitalschutz-Zertifikate": {
                    15: {}
                },
                "Discount-Zertifikate": {
                    20: {
                        21: "Classic Discount-Zertifikat"
                    }
                },
                "Express-Zertifikate": {
                    56: {
                        44043: "Memory Express-Zertifikat",
                        44037: "Duo Memory Express-Zertifikat",
                        44044: "Multi Express-Zertifikat",
                        44045: "Multi Memory Express-Zertifikat",
                        44046: "Stufenexpress-Zertifikat",
                        44038: "Fixkupon Express-Zertifikat",
                        44086: "Duo Fixkupon Express-Zertifikat"
                    }
                },
                "Outperformance-Zertifikat": {
                    30: {}
                },
                "Sprint-Zertifikat": {
                    37: {}
                },
                "Alpha-Zertifikat": {
                    93: {}
                },
                "Index-Zertifiakte": {
                    27: {
                        44093: "Short Index-Zertifikate"
                    }
                },
            },
            "Hebelprodukte": {
                "Optionsscheine": {
                    1: {
                        2: "Standard-Optionsscheine",
                        12: "Discount-Optionsscheine",
                        8: "Inline-Optionsscheine",
                        44059: "StayLow-Optionsscheine",
                        44056: "StayHigh-Optionsscheine"
                    }
                },
                "Turbo-Optionsscheine": {
                    42: {
                        43: "Classic Turbo-Optionsscheine",
                        45: "Unlimited Turbo-Optionsscheine",
                        49: "Smart Turbo-Optionsscheine",
                        47: "BEST Turbo-Optionsscheine",
                        7145: "X-BEST Turbo Optionsscheine"
                    }
                },
                "Faktor-Optionsscheine": {
                    228: {}
                }
            }
        }

        self.client = ApiSheetClient("Issuance Data Collection", "SG")

        finaldict = {}
        finaldict["date"] = date.today().strftime('%Y-%m-%d')

        for category in ['Zertifikate', 'Hebelprodukte']:
            resultdict = self.readData(category)
            finaldict[category] = resultdict

        self.client.updateFile(finaldict, DDV_Mapping, self.EUSIPA_Mapping, Volumen=False, ExchangeData=True)

    def createResultDict(self, newProducts):

        count_dict = {}
        for x in newProducts:
            if not x[1] in count_dict.keys():
                count_dict[x[1]] = {}
                count_dict[x[1]]['amount'] = 1
                count_dict[x[1]]['exchange'] = 0
                count_dict[x[1]]['not exchange'] = 0

                if x[2]:
                    count_dict[x[1]]['exchange'] += 1
                else:
                    count_dict[x[1]]['not exchange'] += 1

                count_dict[x[1]]['ISINs'] = [x[0]]
                # product type and then we have the number, so lets do product type as key and then another nested dict with number and examples --> and here at examples we put in some random IDs
            else:
                count_dict[x[1]]['amount'] = count_dict[x[1]]['amount'] + 1
                count_dict[x[1]]['ISINs'].append(x[0])

                if x[2]:
                    count_dict[x[1]]['exchange'] = count_dict[x[1]]['exchange'] + 1
                else:
                    count_dict[x[1]]['not exchange'] = count_dict[x[1]]['not exchange'] + 1

        return count_dict

    def getProducts(self, id, p_type):
        all_products = []
        today = date.today().strftime('%Y-%m-%d')
        pageNum = 1
        nextPage = True
        while nextPage:
            url = "https://www.sg-zertifikate.de/EmcWebApi/api/ProductSearch/Search?PageSize=1000&PageNum={}&ProductClassificationId={}&IssueDateFrom={}".format(str(pageNum), str(id), today)
            print(url)
            response = requests.get(url)
            if response.status_code == 200:
                json = response.json()
                total = json['TotalCount']
                products = json['Products']
                for p in products:
                    isin = p["Isin"]
                    if p['IsSecondaryMarket']:
                        exchange = True
                    else:
                        exchange = False
                    all_products.append([isin, p_type, exchange])
                if not total > (1000*pageNum):
                    nextPage = False
                else:
                    pageNum += 1

        return all_products

    def readData(self, category):

        all_products = []

        for parent_name in self.Mapping[category]:
            parent_id = list(self.Mapping[category][parent_name].keys())[0]
            parent_products = self.getProducts(parent_id, parent_name)

            for sub_id, sub_name in self.Mapping[category][parent_name][parent_id].items():
                sub_products = self.getProducts(sub_id, sub_name)
                if len(sub_products) > 0:
                    [all_products.append(x) for x in sub_products]
                    # remove sub_product from parent product
                    for item in sub_products:
                        for item2 in parent_products:
                            if item[0] == item2[0]:
                                parent_products.remove(item2)

            [all_products.append(x) for x in parent_products]

        return self.createResultDict(all_products)

    '''
    def compare(self, category):
        today = date.today().strftime('%Y-%m-%d')
        newProducts = self.readData(category, today)
        count_dict = {}
        for x in newProducts:
            if not x[1] in count_dict.keys():
                count_dict[x[1]] = {}
                count_dict[x[1]]['amount'] = 1
                count_dict[x[1]]['ISINs'] = [x[0]]
                # product type and then we have the number, so lets do product type as key and then another nested dict with number and examples --> and here at examples we put in some random IDs
            else:
                count_dict[x[1]]['amount'] = count_dict[x[1]]['amount'] + 1
                count_dict[x[1]]['ISINs'].append(x[0])
        return count_dict
'''


# Kasim Terzic (kt54) Feb 2018

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from Lecture04.l04_utils import *

# Load the data from the space-separated txt file.
# This will create a 2D numpy array
# data = np.loadtxt('l04-data.txt')
data = np.loadtxt('/Users/cheetah/Sites/CS5014-Example/Lecture04/l01-data.txt')
factor = np.max(data)

# Extract column 2 (X) and 3 (Y). Add a vector of ones as X_0
x = data[:, 1] / factor
y = data[:, 2] / factor
x = np.c_[np.ones_like(x), x]

# Pick some parameters for our model
theta_start = np.array([0, 0])

theta_new, loss = gradientDescent(x, y, 0.1, theta_start, 1e-8)
print(theta_new, loss)

print(meanSquaredErrorLoss(y, f(x, theta_start)))
plotModel(x, y, f(x, theta_start), title='Random parameters')

print(meanSquaredErrorLoss(y, f(x, theta_new)))
plotModel(x, y, f(x, theta_new), title='After gradient descent')

plotLossFunction(x, y, title='Loss function')
plt.savefig('l04-plot.png')
plt.show()


# -*- coding: utf-8 -*-
"""
Created on Sun Apr  7 11:37:48 2019

@author: Administrator
"""

import json
indices=[1,2,3,1,3,4,2,3,6,3,7,6,5,6,7,5,7,8,3,4,8,3,7,8,1,2,6,1,5,6,1,4,5,4,5,8,2,3,4,2,3,7,6,7,8,3,4,7]
new_indices=[]
for indice in indices:
    new_indices.append(indice-1)
print(new_indices)
filename="data_file.json"
data={
      "meshes": # meshes is a list
         [{"vertices":[0,0,0,1,0,0,1,1,0,0,1,0,0,0,-1,1,0,-1,1,1,-1,0,1,-1],
         "indices":new_indices,
         "uvCount":100,
         "position":[0.5,0.5,-0.5],
         "name":"cube1"}
         ]

      }
with open("data_file.json","w") as write_file:
    json.dump(data,write_file)
json_data = open(filename) # open json file to read
data1 = json.load(json_data) # load the data for parsing
vertice_array=data["meshes"][0]["vertices"]
print(vertice_array)
'''
,
          {"vertices":[0,0,0,1,0,0,1,1,0,0,1,0],
         "indices":[1-1,2-1,3-1,2-1,3-1,4-1],
         "uvCount":200,
         "position":[1,1,1],
         "name":"cube2"}
'''


from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User

from .models import Department, Student, StuDept

class AddStudent(forms.ModelForm):
    class Meta:
        model = Student
        fields = ('name', 'roll', 'city')

class AddDepartment(forms.ModelForm):
    class Meta:
        model = Department
        fields = ('dept_name', 'dept_code')

class AddStuDept(forms.ModelForm):
    class Meta:
        model = StuDept
        fields = ('student', 'dept')

class NewUserForm(UserCreationForm):
    email = forms.EmailField(required=True)

    class Meta:
        model = User
        fields = ("username", "email", "password1", "password2")

    def save(self, commit=True):
        user = super(NewUserForm, self).save(commit=False)
        user.email = self.cleaned_data['email']
        if commit:
            user.save()
        return user


"""Create the footer on every page."""
import dash_core_components as dcc
import dash_html_components as html

footer = html.Div(
    [
        html.H3("Data source"),
        dcc.Markdown(
            """
        COVID-data is downloaded from
        [Johns Hopkins](https://github.com/CSSEGISandData/COVID-19).
    """
        ),
        html.H3("About the author"),
        dcc.Markdown(
            """
        Created by [Martin Høy](mailto:martin@hoy.priv.no),
        March 2020 (updated November 2020).

        Code available on [GitHub](https://github.com/marhoy/covid19).
        Docker image available on [Docker Hub](https://hub.docker.com/r/marhoy/covid).
        """
        ),
    ]
)


import sys
import socket
import os

# Create a TCP/IP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

port = 8889

# Connect the socket to the port where the server is listening
server_address = ('127.0.0.1', port)
print(f"mencoba terhubung ke {server_address} port {port}")
sock.connect(server_address)

command = input()
try:
    s = command
    filenya = s.split(" ")
    filenya = filenya[1].strip()
    command+='\n'
    sock.sendall(command.encode())

    "kirim ukuran file"
    ukuran = os.path.getsize(filenya)
    sock.send(ukuran.to_bytes(4,byteorder='big'))

    "Upload file"
    FileKirim = open(filenya, 'rb')
    for data in FileKirim:
        sock.sendall(data)
    FileKirim.close()

except:
    print('error')
finally:
    response = sock.recv(1024)
    print(response.decode())
    sock.close()


import gym
from gym import error, spaces, utils
from gym.utils import seeding
from gym_distopia.envs.distopia_rewards import PopulationStdEvaluator
from copy import deepcopy
import numpy as np
import json
from matplotlib import pyplot as plt
import pickle
import time

class DistopiaEnv(gym.Env):
    """
    The main OpenAI Gym class. It encapsulates an environment with
    arbitrary behind-the-scenes dynamics. An environment can be
    partially or fully observed.
    The main API methods that users of this class need to know are:
        step
        reset
        render
        close
        seed
    And set the following attributes:
        action_space: The Space object corresponding to valid actions
        observation_space: The Space object corresponding to valid observations
        reward_range: A tuple corresponding to the min and max possible rewards
    Note: a default reward range set to [-inf,+inf] already exists. Set it if you want a narrower range.
    The methods are accessed publicly as "step", "reset", etc.. The
    non-underscored versions are wrapper methods to which we may add
    functionality over time.
    """
    metadata = {'render.modes': ['human']}

    def __init__(self, screen_size, reward_evaluator, num_districts = 4, blocks_per_district = 3,
                    grid_width = 50, raw_padding = 100, num_directions = 5, step_size = 1,
                    init_state = None, skip_first_reset = False, always_reset_to_initial = False, max_steps = 100,
                    record_path = None, terminate_on_fail = False):
        '''
        OBSERVATION (STATE) SPACE:
        The state space for this environment is the x,y coordinates for each block
        There are up to BLOCKS_PER_DISTRICT blocks for each district
        The structure of the space is a TUPLE of districts, each composed of a TUPLE of blocks,
        each composed of an (x,y) tuple

        A note about the blocks: while all the blocks are represented in the space, not all must
        be in the config. To accomplish this, there is a space of 100 px (by default) padding in x.
        When evaluating a config, we first subtract 100 px and strip out all blocks with a negative x.

        A note about evalutaion: the configs are passed to the evaluator as a dictionary of block coords
        keyed on the fiducial id

        REWARD FUNCTION:
        The reward function can either be a function or a list of supported aggregate stats ("sum,avg,std"). It cannot be None.

        ACTION SPACE
        The action space is up/down/left/right for each block. Note that currently (as a MultiDiscrete)
        the agent can move more than one block at a time.

        '''
        super().__init__()
        self._max_steps = max_steps
        self.STEP_SIZE = step_size
        self.NUM_DISTRICTS = num_districts
        self.BLOCKS_PER_DISTRICT = blocks_per_district
        self.GRID_WIDTH = grid_width # width of a grid in pixels
        self.PADDING = raw_padding//self.GRID_WIDTH # px reserved for the "off-screen" blocks
        self.NUM_DIRECTIONS = num_directions # 0,1,2,3,4 --> Do nothing, N, S, E, W
        self.stats = []
        self.record_path = record_path
        self.current_step = 0
        self.terminate_on_fail = terminate_on_fail
        if reward_evaluator is None:
            raise ValueError("Must pass a reward evaluator instance! See distopia_rewards.py.")
        self.evaluator = reward_evaluator
        self.width, self.height = (dim//self.GRID_WIDTH for dim in screen_size)

        self.action_space = spaces.MultiDiscrete([self.NUM_DIRECTIONS]*self.NUM_DISTRICTS * self.BLOCKS_PER_DISTRICT)

        # the state space is the x,y coords of all blocks i.e. (x0,y0,x1,y1,x2,y2...)
        self.observation_space = spaces.Tuple(
            # list of districts
            [spaces.Tuple(
                # list of blocks
                [spaces.Tuple((spaces.Discrete(self.width + self.PADDING),spaces.Discrete(self.height)))
                    for block in range(self.BLOCKS_PER_DISTRICT)])
            for district in range(self.NUM_DISTRICTS)])
        self.observation_space.shape = (self.NUM_DISTRICTS,self.BLOCKS_PER_DISTRICT,2)
        self.reward_range = self.evaluator.calculate_reward_range({'NUM_DISTRICTS':self.NUM_DISTRICTS})
        if init_state is not None:
            skip_first_reset = True
        self.skip_reset = False
        self.always_reset_to_initial = always_reset_to_initial
        self.reset(initial=init_state, skip_next_reset=skip_first_reset) #passing skip flag to prevent auto-reset at the start of most agent episodes

    def dump_stats(self):
        with open("{}_{}.pkl".format(self.record_path,time.time()),'wb') as outfile:
            pickle.dump(self.stats,outfile)

    def record_stat(self,state,reward,success):
        self.stats.append({"state":str(state),"reward":reward, "success":success})

    def get_staged_blocks_dict(self,observation):
        obs_dict = {}
        for i,district in enumerate(observation):
            obs_dict[i] = [block*self.GRID_WIDTH for block in district if block[0] > self.PADDING]
        return obs_dict

    def evaluate(self,observation):
        obs_dict = self.get_staged_blocks_dict(observation)
        return self.evaluator.evaluate(obs_dict)

    def step(self, action):
        """
        Run one timestep of the environment's dynamics. When end of
        episode is reached, you are responsible for calling `reset()`
        to reset this environment's state.
        Accepts an action and returns a tuple (observation, reward, done, info).
        Args:
            action (object): an action provided by the agent
        Returns:
            observation (object): agent's observation of the current environment
            reward (float) : amount of reward returned after previous action
            done (bool): whether the episode has ended, in which case further step() calls will return undefined results
            info (dict): contains auxiliary diagnostic information (helpful for debugging, and sometimes learning)
        """
        self.last_action = action

        info = {"error":""}
        self.current_step += 1
        if self.current_step < self._max_steps:
            done = False
        else:
            done = True
        self.prior_state = deepcopy(self.districts)
        observation, success = self._take_action(action)
        reward = self.evaluate(observation)
        if reward == False:
            #self.reset(initial=self.prior_state) # IMPORTANT: I think reverting the state will cause me to get stuck (since we're only taking 1-step; alternatively we could force starting from a legal state)
            reward = self.reward_range[0]
            if self.terminate_on_fail == True:
                done = True # try this out--ending the episode if illegal action occurs
            info["error"] = "illegal voronoi"
        if self.record_path is not None:
            self.record_stat(observation,reward,success)
        return (observation, reward, done, info)

    def _next_observation(self):
        return self.districts

    def _update_state(self,district,block,old_loc,new_loc):
        self.districts[district][block] = new_loc
        self.occupied[str(new_loc)] = (district,block)
        if old_loc is not None: # note that is ! the same as == here; == tries to do a value compare, is does identity compare, so == fails b/c np array has no truth value
            self.occupied.pop(str(old_loc))

    def _apply_action(self, district, block, action):
        '''
        Inputs:
            district: the district of the block to apply the action to
            block: the block in that district to apply the action to
            action: a number from {0,1,2,3,4} representing the action
        Updates:
            self.districts if possible to apply the action legally
        Returns:
            True if action succeeded, False if it failed

        '''
        success = False
        block_location = self.districts[district][block]
        if action == 0:
            # do nothing
            return True

        elif action == 1:
            # move north
            new_loc = block_location + (0, self.STEP_SIZE)
            if new_loc[1] > self.height or str(new_loc) in self.occupied:
                return False
            else:
                self._update_state(district,block,block_location,new_loc)
                return True

        elif action == 2:
            # move south
            new_loc = block_location + (0, -self.STEP_SIZE)
            if new_loc[1] < 0 or str(new_loc) in self.occupied:
                return False
            else:
                self._update_state(district,block,block_location,new_loc)
                return True

        elif action == 3:
            # move east
            new_loc = block_location + (self.STEP_SIZE, 0)
            if new_loc[0] > self.width or str(new_loc) in self.occupied:
                return False
            else:
                self._update_state(district,block,block_location,new_loc)
                return True

        elif action == 4:
            # move west
            new_loc = block_location + (-self.STEP_SIZE, 0)
            if new_loc[0] < 0 or str(new_loc) in self.occupied:
                return False
            else:
                self._update_state(district,block,block_location,new_loc)
                return True

        else:
            raise ValueError("Invalid action requested: {}. Please pass actions between 0 and {}.".format(action,self.NUM_DIRECTIONS-1))

    def _take_action(self, action):
        '''
        Inputs:
            action: an array of numbers between 0 and the number of moves
            the array is flattened (num_districts * num_blocks per district)
        Returns:
            the current block layout after taking the action
            a boolean list parallel to the input, indicating which succeeded and which failed

        Note that some actions may make other illegal. This function will perform the actions in
        random order in an attempt to reduce bias in which actions get nullified by prior actions.
        '''
        # generate a random order in which to execute the actions
        indices = np.arange(len(action))
        np.random.shuffle(indices)
        successes = []
        # go through the actions, unflattening and applying each one if legal
        for index in indices:
            district = index // self.BLOCKS_PER_DISTRICT
            block = index % self.BLOCKS_PER_DISTRICT
            successes.append(self._apply_action(district,block,action[index]))

        return self.districts, successes

    def place_block(self,occupied,active=None):
        '''
        Get unoccupied x,y coords to place a block on the active zone
        of the table, non-active zone, or neither
        Inputs:
            occupied: a dict containing occupied coords as keys
            active: True to force the placement in the active area
                    False to force the placement in the PADDING area
                    None to not force either
        Returns:
            a numpy array x,y for a block
        '''
        xlow = self.PADDING if (active == True) else 0
        xhigh = self.PADDING if (active == False) else self.PADDING + self.width
        ylow = 0
        yhigh = self.height
        x = np.random.randint(low=xlow, high=xhigh)
        y = np.random.randint(low=ylow, high=yhigh)
        while str(np.asarray([x,y])) in occupied:
            x = np.random.randint(low=xlow, high=xhigh)
            y = np.random.randint(low=ylow, high=yhigh)
        return np.asarray([x,y])

    def reset(self, initial=None, min_active=1, max_active=None, skip_next_reset = False):
        """
        Resets the state of the environment and returns an initial observation.
            initial: a complete inital block layout
            min_active: the min number of blocks that should be in the active area for each district
            max_active: the max number of blocks that can be in the active area for each district
        Returns:
            observation (object): the initial observation.
        """

        if len(self.stats) > 1 and self.record_path is not None:
            self.dump_stats()
            self.stats = []

        self.current_step = 0
        if self.skip_reset == True:
            self.skip_reset = False
            return self.districts
        if skip_next_reset == True:
            self.skip_reset = True
        if initial is not None:
            self.districts = []
            for d in initial:
                new_district = [np.asarray(b) for b in d]
                self.districts.append(new_district)
            self.occupied = {}
            for district in self.districts:
                for block in district:
                    self.occupied[str(block)] = [district,block]
            self.initial_state = deepcopy(self.districts)
            self.initial_occupancy = deepcopy(self.occupied)

        elif self.always_reset_to_initial == True:
            print("resetting from start!")
            self.districts = deepcopy(self.initial_state)
            self.occupied = deepcopy(self.initial_occupancy)

        else:
            if max_active is None:
                max_active = self.BLOCKS_PER_DISTRICT
            # in order to prevent overlaps, hash each block placed on its coords
            self.occupied = {}

            self.districts = [
                [
                    np.zeros(2) for b in range(self.BLOCKS_PER_DISTRICT)
                ] for d in range(self.NUM_DISTRICTS)
            ]

            for i,district in enumerate(self.districts):
                for j,block in enumerate(district[:min_active]):
                    #self.districts[i][j] = block = self.place_block(self.occupied,active=True)
                    #self.occupied[str(block)] = (i,j)
                    self._update_state(i,j,None,self.place_block(self.occupied,active=True))
                for k,block in enumerate(district[min_active:max_active],start=min_active):
                    #self.districts[i][k] = block = self.place_block(self.occupied,active=None) # None-->don't force active, False-->force not active
                    #self.occupied[str(block)] = (i,k)
                    self._update_state(i,k,None,self.place_block(self.occupied,active=None))
        return self.districts

    def render(self, mode='human'):
        """
        Renders the environment.
        The set of supported modes varies per environment. (And some
        environments do not support rendering at all.) By convention,
        if mode is:
        - human: render to the current display or terminal and
          return nothing. Usually for human consumption.
        - rgb_array: Return an numpy.ndarray with shape (x, y, 3),
          representing RGB values for an x-by-y pixel image, suitable
          for turning into a video.
        - ansi: Return a string (str) or StringIO.StringIO containing a
          terminal-style text representation. The text can include newlines
          and ANSI escape sequences (e.g. for colors).
        Note:
            Make sure that your class's metadata 'render.modes' key includes
              the list of supported modes. It's recommended to call super()
              in implementations to use the functionality of this method.
        Args:
            mode (str): the mode to render with
        Example:
        class MyEnv(Env):
            metadata = {'render.modes': ['human', 'rgb_array']}
            def render(self, mode='human'):
                if mode == 'rgb_array':
                    return np.array(...) # return RGB frame suitable for video
                elif mode == 'human':
                    ... # pop up a window and render
                else:
                    super(MyEnv, self).render(mode=mode) # just raise an exception
        """
        if mode == 'human':
            for i,d in enumerate(self.districts):
                x,y = zip(*d)
                plt.scatter(x,y,label='D{}'.format(i))
                plt.axvline(self.PADDING)
                plt.legend(loc=0)
                plt.title(self.last_action)
            plt.show(block=False)
            plt.pause(0.05)
            plt.clf()
            #plt.close()
        else:
            # will raise an exception
            super(DistopiaEnv, self).render(mode=mode)
    def close(self):
        """
        Override close in your subclass to perform any necessary cleanup.
        Environments will automatically close() themselves when
        garbage collected or when the program exits.
        """

    def seed(self, seed=None):
        """Sets the seed for this env's random number generator(s).
        Note:
            Some environments use multiple pseudorandom number generators.
            We want to capture all such seeds used in order to ensure that
            there aren't accidental correlations between multiple generators.
        Returns:
            list<bigint>: Returns the list of seeds used in this env's random
              number generators. The first value in the list should be the
              "main" seed, or the value which a reproducer should pass to
              'seed'. Often, the main seed equals the provided 'seed', but
              this won't be true if seed=None, for example.
        """
        return

if __name__ == '__main__':
    ev = PopulationStdEvaluator()
    de = DistopiaEnv((1920,1080),ev)
    import pdb
    pdb.set_trace()


"""Build Difference Tree Module."""

from collections import OrderedDict

ADDED, DELETED, NESTED = 'added', 'deleted', 'nested'
UNMODIFIED, CHANGED = 'unmodified', 'changed'

def get_ordered_joint_keys(dict1, dict2):
    """Function compares 2 dictionaries and returns joint keys (keys list may
    be sorted or unsorted)

    Args:
        dict1 ([dict]): first dictionary
        dict2 ([dict]): second dictionary

    Returns:
        [list]: if both comparable dictionaries are not empty and not equal,
                function returns list of joint keys sorted alphabetically.
                In case when one of the dictionary is empty or both of them
                are equal, function returns list list of keys "as is"
                (in original order).
    """

    # Initializing output list
    output_list = []

    # Adding sorted keys from dict1 & dict2 into output list
    for key in OrderedDict(dict1):
        output_list.append(key)

    for key in OrderedDict(dict2):
        if key not in output_list:
            output_list.append(key)

    # If one of the dict1 or dict2 is empty, or both dicts are equal
    # return output unsorted
    if (not dict1 or not dict2) or (dict1 == dict2):
        return output_list
    # otherwise return sorted list
    else:
        return sorted(output_list)

def build_diff(input, output):
    """Generate Difference Function.

    Function accepts two dicts (input and output), and discovers
    the difference between keys and values in those dicts.

    Args:
        input ([dict]): input dict (contains original data)
        output ([dict]): output dict (contains modified data)

    Returns:
        difference ([dict]): output dict containing difference
                             between input & output dicts
    """

    # Getting list of joint keys from input & output files
    joint = get_ordered_joint_keys(input, output)

    # Comparing input and output dict's to find differences between keys
    intersected = input.keys() & output.keys()
    deleted = input.keys() - output.keys()
    added = output.keys() - input.keys()

    # Initializing variable containing function output
    difference = {}

    # Traversing each element of the tree
    for key in joint:
        if key in intersected:
            input_val, output_val = input[key], output[key]

            if isinstance(input_val, dict) and isinstance(output_val, dict):
                difference[key] = {'type': NESTED,
                                   'values': build_diff(input_val,
                                                        output_val)
                                   }
            elif input_val == output_val:
                difference[key] = {'type': UNMODIFIED,
                                   'values': input_val}
            else:
                difference[key] = {'type': CHANGED,
                                   'values': (input_val,
                                              output_val
                                              )
                                   }

        if key in added:
            values = output[key]
            if type(values) == dict:
                difference[key] = {'type': ADDED,
                                   'values': build_diff(values,
                                                        values)
                                   }
            else:
                difference[key] = {'type': ADDED,
                                   'values': values}

        if key in deleted:
            values = input[key]
            if type(values) == dict:
                difference[key] = {'type': DELETED,
                                   'values': build_diff(values,
                                                        values)
                                   }
            else:
                difference[key] = {'type': DELETED,
                                   'values': values}

    # Returning function output
    return difference


from typing import List, Optional

from kenning.core.dataset import Dataset
from kenning.datasets.imagenet_dataset import ImageNetDataset
from kenning.modelwrappers.frameworks.tensorflow import TensorFlowWrapper
from kenning.utils.class_loader import load_class
from kenning.utils.logger import KLogger
from kenning.utils.resource_manager import PathOrURI

class TensorFlowImageNet(TensorFlowWrapper):
    """
    General-purpose model wrapper for ImageNet models in TensorFlow.
    """

    default_dataset = ImageNetDataset
    pretrained_model_uri = "kenning:///models/classification/tensorflow_imagenet_mobilenetv3small.h5"  # noqa: E501
    arguments_structure = {
        "modelcls": {
            "argparse_name": "--model-cls",
            "description": "The Keras model class",
            "type": str,
        },
        "modelinputname": {
            "argparse_name": "--model-input-name",
            "description": "Name of the input in the TensorFlow model",
            "type": str,
            "default": "input",
        },
        "modeloutputname": {
            "argparse_name": "--model-output-name",
            "description": "Name of the output in the TensorFlow model",
            "type": str,
            "default": "output",
        },
        "inputshape": {
            "argparse_name": "--input-shape",
            "description": "Input shape",
            "type": int,
            "is_list": True,
            "default": [1, 224, 224, 3],
        },
        "numclasses": {
            "argparse_name": "--num-classes",
            "description": "Output shape",
            "type": int,
            "default": 1000,
        },
        "disablebuiltinpreprocessing": {
            "argparse_name": "--disable-builtin-preprocessing",
            "description": "Removes (if possible) internal preprocessing in the model",  # noqa: E501
            "type": bool,
            "default": False,
        },
    }

    def __init__(
        self,
        model_path: PathOrURI,
        dataset: Dataset,
        from_file: bool = False,
        model_name: Optional[str] = None,
        modelcls: str = "",
        modelinputname: str = "input",
        modeloutputname: str = "output",
        inputshape: List[int] = [1, 224, 224, 3],
        numclasses: int = 1000,
        disablebuiltinpreprocessing: bool = False,
    ):
        """
        Creates model wrapper for TensorFlow classification
        model pretrained on ImageNet dataset.

        Parameters
        ----------
        model_path : PathOrURI
            Path or URI to the model file.
        dataset : Dataset
            The dataset to verify the inference.
        from_file : bool
            True if model should be loaded from file.
        model_name : Optional[str]
            Name of the model used for the report
        modelcls : str
            The model class import path.
            Used for loading keras.applications pretrained models.
        modelinputname : str
            The name of the model input.
        modeloutputname : str
            The name of the model output.
        inputshape : List[int]
            The shape of the input.
        numclasses : int
            Number of classes in the model.
        disablebuiltinpreprocessing : bool
            Tells if the input preprocessing should be removed from the model.

        Raises
        ------
        ValueError
            Raised when dataset batch size and ModelWrapper supported
            sizes do not match
        """
        super().__init__(model_path, dataset, from_file, model_name)
        import tensorflow as tf

        gpus = tf.config.list_physical_devices("GPU")
        for gpu in gpus:
            tf.config.experimental.set_memory_growth(gpu, True)
        self.modelcls = modelcls
        self.modelinputname = modelinputname
        self.modeloutputname = modeloutputname
        self.inputshape = inputshape
        self.numclasses = numclasses
        self.outputshape = [inputshape[0], numclasses]
        self.disablebuiltinpreprocessing = disablebuiltinpreprocessing

        if dataset and dataset.batch_size != self.inputshape[0]:
            KLogger.error(
                "Dataset batch size and ModelWrapper inputshape mismatch"
            )
            KLogger.error(f"batch size: {dataset.batch_size}")
            KLogger.error(f"input shape[0]: {self.inputshape[0]}")
            raise ValueError

    @classmethod
    def _get_io_specification(
        cls, modelinputname, inputshape, modeloutputname, outputshape
    ):
        return {
            "input": [
                {
                    "name": modelinputname,
                    "shape": inputshape,
                    "dtype": "float32",
                }
            ],
            "output": [
                {
                    "name": modeloutputname,
                    "shape": outputshape,
                    "dtype": "float32",
                }
            ],
        }

    @classmethod
    def derive_io_spec_from_json_params(cls, json_dict):
        input_shape = json_dict["inputshape"]
        output_shape = [input_shape[0], json_dict["numclasses"]]
        return cls._get_io_specification(
            json_dict["modelinputname"],
            input_shape,
            json_dict["modeloutputname"],
            output_shape,
        )

    def get_io_specification_from_model(self):
        return self._get_io_specification(
            self.modelinputname,
            self.inputshape,
            self.modeloutputname,
            self.outputshape,
        )

    def prepare_model(self):
        if self.model_prepared:
            return None
        if self.from_file:
            self.load_model(self.model_path)
            self.model_prepared = True
        else:
            if self.disablebuiltinpreprocessing:
                self.model = load_class(self.modelcls)(
                    input_shape=tuple(self.inputshape[1:]),
                    include_preprocessing=False,
                )
            else:
                self.model = load_class(self.modelcls)(
                    input_shape=tuple(self.inputshape[1:])
                )
            self.model_prepared = True
            self.save_model(self.model_path)
            self.model.summary()


n = int(input())

t = []
for i in range(n):
    t.append([int(i) for i in input().split()])

WHITE = 0
GRAY = 1
BLACK = 2
used = [False] * n
color = [WHITE] * n
cycle = False
def dfs(v, p):
    global used
    global cycle
    global color
    used[v] = True
    color[v] = GRAY
    for u in range(n):
        if t[v][u] == 1 and color[u] == GRAY and u != p:
            cycle = True
            return
        if cycle:
            return
        if t[v][u] == 1 and color[u] == WHITE:
            dfs(u, v)
    color[v] = BLACK

k = 0
for v in range(n):
    if not used[v]:
        k += 1
        dfs(v, v)

if not cycle and k == 1:
    print('YES')
else:
    print('NO')


# Iterable --> Dictinory, set , tuple are iterable
user = {
    'name':'golem',
    'age':100,
    'can_dance': False
}

# Iterating the dictionary
for key,value in user.items():
    print(key,value)

"""
Output -->
name golem
age 100
can_dance False
"""

# Iterating with values
for values in user.values():
    print(values)

"""
Output -->
golem
100
False
"""

# Iterative on keys of the dictionary
for keys in user.keys():
    print(keys)
"""
Output -->
name
age
can_dance
"""

# Iteration on set and tuple
set1 = {1,2,3,4,5,6}
print(type(set1))  # Output : <class 'set'>


"""
From Aaron:
    - Can you compute pairwise diversity (pi) for the different background selection partitions for intergenic and intronic data?
    - This can be done in moments using fs.pi()
    - Then by dividing that output by the uL from each subset of data, we get the relative differences in pairwise diversity across datasets
    - I want to see if the relative differences closely match the relative differences of $N_e$ inferred in the different datasets
"""
import gzip
import pickle

import pandas as pd
import moments

# Constant file path and project size for all functions
BASE_PATH = '../../data/230426-AnnotateChunksWithBvalues/data/whole-genome-quartile/q{}'
PROJECT_TO_SIZE = [40, 40, 40, 40]
POPULATIONS = ['YRI', 'IBS', 'CHB', 'MXB']

def load_ml_file(quartile, mut_type):
    """
    Load and process mL file.

    Parameters:
    quartile: the quartile of the data.
    mut_type: the mutation type, either 'intronic' or 'intergenic'.

    Returns:
    mL: the processed content of the mL file as a float.
    """
    file_name = 'mL_introns.txt' if mut_type == 'intronic' else 'mL_intergenic.txt'
    file_path = f'{BASE_PATH.format(quartile)}/{file_name}'

    with open(file_path, 'r') as file:
        mL = float(file.readline().replace('mL:', '').strip())

    return mL

def load_spectrum(quartile, mut_type):
    """
    Load the spectrum project and fold.

    Parameters:
    quartile: the quartile of the data.
    mut_type: the mutation type, either 'intronic' or 'intergenic'.
    """
    file_path = f'{BASE_PATH.format(quartile)}/spectrum-cat_{mut_type}.pkl.gz'

    print('Loading data...')
    with gzip.open(file_path, "rb") as file:
        spectrum = pickle.load(file)

    spectrum = spectrum.project(PROJECT_TO_SIZE)
    spectrum = spectrum.fold()

    return spectrum

def marginalize(spectrum, pop):
    """
    Get the marginal spectrum for a given population.

    Parameters:
    spectrum: The spectrum to be marginalized.
    pop: The population to keep in the marginalized spectrum.

    Returns:
    sf_pop: the marginalized spectrum.
    """
    # Get the indices of all populations except 'pop'
    indexes = [i for i, apop in enumerate(spectrum.pop_ids) if apop != pop]

    # Marginalize the spectrum
    sf_pop = spectrum.marginalize(indexes)

    return sf_pop

def get_pi(quartile, mut_type):
    """
    Get pi values for each population and return the data as a pandas DataFrame.

    Parameters:
    quartile: the quartile of the data.
    mut_type: the mutation type, either 'intronic' or 'intergenic'.

    Returns:
    data: A pandas DataFrame containing the data.
    """
    ml = load_ml_file(quartile, mut_type)
    sfs = load_spectrum(quartile, mut_type)

    # Get pi for each population
    pis = [marginalize(sfs, apop).pi() for apop in POPULATIONS]

    # Put data in a pandas DataFrame
    data = {
        'pop': POPULATIONS,
        'quartile': quartile,
        'mut_type': mut_type,
        'pi': pis,
        'ml': ml,
    }
    return pd.DataFrame(data)

results = [get_pi(quartile, mut_type) for quartile in range(1, 5) for mut_type in ['intronic', 'intergenic']]
results = pd.concat(results)
results.to_csv('results/pi.csv', index=False)


#!/usr/bin/env python3

import random
from functools import cmp_to_key

class Guillotine:
    def __init__(self, rect, rects):
        self.cuts = []
        self.w, self.h = rect
        rects = rects + [(x[1], x[0]) for x in rects if x[0] != x[1]]
        self.rects = sorted(rects, key=cmp_to_key(self.__cmp))

    def cut(self, pieces):
        # cut = self.__cut(0, 0, self.rect[0], self.rect[1])
        cut, tail = self.__stupid_cut(0, 0, self.w, self.h, pieces)
        self.cuts.append(cut)
        return cut

    def pieces(self, cut):
        x, y, w, h, q, gr, gu = cut
        pieces = [(w, h)]
        if gr is not None:
            pieces += self.pieces(gr)

        if gu is not None:
            pieces += self.pieces(gu)

        return pieces

    # def __cut(self, x0, y0, x1, y1):
        # w, h = x1 - x0, y1 - y0
        # rects = map(lambda r: (r, random.randint(0, min(w//r[0], h//r[1]))), rects)
    def change_cut(self, cut):
        pieces = self.pieces(cut)

        return self.cut(self.change(pieces))

    def change(self, pieces):
        change_index = random.randint(0, len(pieces)-1)
        new = random.choice(self.rects)
        pieces = pieces[:change_index] + [new] + pieces[change_index:]
        return self.pieces(self.cut(pieces))

    def __change_pos(self, cut, x0, y0, piece):
        x, y, w, h, q, gr, gu = cut

        if x == x0 and y == y0:
            if gr is not None:
                grx, gry, grw, grh, grq, grgr, grgu = gr
                gr = grx - (w - grx), gry, grw, grh, grq, grgr, grgu
            return (x, y, piece[0], piece[1], 1, gr, gu)
        if gr is not None:
            gr = self.__change_pos(gr, x0, y0, piece)
        if gu is not None:
            gu = self.__change_pos(gu, x0, y0, piece)
        return (x, y, w, h, q, gr, gu)

    def __position_slack(self, cut):
        x, y, w, h, q, gr, gu = cut
        sw, sh = w, h
        pieces = []
        if gr is not None:
            pieces += self.__position_slack(gr)
        else:
            sw += self.w - (x+w)

        if gu is not None:
            pieces += self.__position_slack(gu)
        else:
            sh += self.h - (y+h)

        return [((x, y), (sw, sh))] + pieces

    def __stupid_cut(self, x0, y0, x1, y1, pieces):
        w, h = x1 - x0, y1 - y0
        if len(pieces) > 0:
            p, *tail = pieces
            pw, ph = p
            if pw <= w and ph <= h:
                right_cuts, tail = self.__stupid_cut(x0+pw, y0, x1, y0 + ph, tail)
                above_cuts, tail = self.__stupid_cut(x0, y0+ph, x1, y1, tail)
                return ((x0, y0, pw, ph, 1, right_cuts, above_cuts), tail)
        return (None, pieces)

    def __naive_cut(self, x0, y0, x1, y1):
        w, h = x1 - x0, y1 - y0

        p, q = random.choice(self.__pieces(w, h))
        pw, ph = p
        if pw <= w and ph <= h:
            above_cuts = self.__cut(x0, y0+ph, x1, y1)
            right_cuts = self.__cut(x0+pw, y0, x1, y0 + ph)
            return (x0, y0, pw, ph, 1, right_cuts, above_cuts)
        return None

    def __cut(self, x0, y0, x1, y1):
        w, h = x1 - x0, y1 - y0
        pieces = self.__pieces(w, h)
        if len(pieces) > 0:
            piece, max_quantity = random.choice(pieces)
            # get only a certain number of pieces that can fill the current line
            # rand_quantity = random.randint(1, max_quantity)
            rand_quantity = max_quantity
            pw, ph = piece
            above_cuts = self.__cut(x0, y0+ph, x1, y1)
            right_cuts = self.__cut(x0+pw * rand_quantity, y0, x1, y0 + ph)
            return (x0, y0, piece[0], piece[1], rand_quantity, right_cuts, above_cuts)
        return None

    """
    Return the all the pieces and their quantities that fits the area w x h

    returns a tuple:
    ((piece_w, piece_h), quantity)
    """
    def __pieces(self, w, h):
        rects = [x for x in self.rects if x[0] <= w and x[1] <= h]
        rects = list(map(lambda r: (r, w//r[0]), rects))
        if len(rects) > 0:
            rects = list(filter(lambda r: r[1] > 0, rects))
            return rects
        return []

    def __heuristic_cut(self, x0, y0, x1, y1):
        w, h = x1 - x0, y1 - y0
        rects = [x for x in self.rects if x[0] * x[1] <= w * h]

        for pw, ph in random.sample(rects, min(len(rects), 3)):
            pw, ph = random.choice(rects)
            if pw <= w and ph <= h:
                above_cuts = self.__cut(x0, y0+ph, x1, y1)
                right_cuts = self.__cut(x0+pw, y0, x1, y0 + ph)
                return (x0, y0, pw, ph, right_cuts, above_cuts)
            aux = pw
            pw = ph
            ph = aux
            if pw <= w and ph <= h:
                above_cuts = self.__cut(x0, y0+ph, x1, y1)
                right_cuts = self.__cut(x0+pw, y0, x1, y0 + ph)
                return (x0, y0, pw, ph, right_cuts, above_cuts)

        for pw, ph in rects[::-1]:
            if pw <= w and ph <= h:
                above_cuts = self.__cut(x0, y0+ph, x1, y1)
                right_cuts = self.__cut(x0+pw, y0, x1, y0 + ph)
                return (x0, y0, pw, ph, right_cuts, above_cuts)
            aux = pw
            pw = ph
            ph = aux
            if pw <= w and ph <= h:
                above_cuts = self.__cut(x0, y0+ph, x1, y1)
                right_cuts = self.__cut(x0+pw, y0, x1, y0 + ph)
                return (x0, y0, pw, ph, right_cuts, above_cuts)

    def __cmp(self, a, b):
        return a[0] * a[1] - b[0] * b[1]

# import numpy as np

# xs = np.random.random_integers(1, 10, 10)
# ys = np.random.random_integers(1, 10, 10)
# rects = [(xs[i], ys[i]) for i in range(len(xs))]

# g = Guillotine((20, 20), rects)
# cut = g.cut()
# g.change(cut)


product_kcal_choices = {
    '10': '10',
    '50': '50',
    '100': '100',
    '200': '200',
    '500': '500',
    '1000': '1000',
}

product_protein_choices = {
    '3': 'Niska zawartość białka',
    '20': 'Średnia zawartość białka',
    '50': 'Wysoka zawartość białka',
    '100': 'Bardzo wysoka zawartość białka',
}

product_carbo_choices = {
    '3': 'Niska zawartość węglowodanów',
    '20': 'Średnia zawartość węglowodanów',
    '50': 'Wysoka zawartość węglowodanów',
    '100': 'Bardzo wysoka zawartość węglowodanów',
}

product_fat_choices = {
    '3': 'Niska zawartość tłuszczu',
    '20': 'Średnia zawartość tłuszczu',
    '50': 'Wysoka zawartość tłuszczu',
    '100': 'Bardzo wysoka zawartość tłuszczu',
}

product_category_choices = {
    'drób': 'drób',
    'jaja': 'jaja',
    'mieso': 'mieso',
    'mleczne': 'mleczne',
    'pozostale': 'pozostale',
    'tluszcze': 'tluszcze',
    'wedliny': 'wedliny',
    'zbozowe': 'zbozowe',

}


__author__ = 'kamil'

import unittest
from AlgorytmyCormen.UnionFind.UnionFindBase import UnionFindBase

class RootClimberBase:
    def __init__(self,tab):
        self.__tab=tab

    def getEl(self, x):
        return self.__tab[x]

    def getRoot(self,x):
        pass

class RootClimberRecur(RootClimberBase):
    def __init__(self, tab):
        super().__init__(tab)

    def getRoot(self,x):
        if(x == self.getEl(x)):
            return x
        return self.getRoot(self.getEl(x))

class RootClimberIter(RootClimberBase):
    def __init__(self,tab):
        super().__init__(tab)

    def getRoot(self,x):
        root = x
        while(root != self.getEl(root)):
            root = self.getEl(root)

        return root

class QuickUnion(UnionFindBase):
    def __init__(self, rozmiarTablicy):
        super().__init__(rozmiarTablicy)

    def _getRoot(self, x):
        r = RootClimberIter(self._tab)
        return r.getRoot(x)

    def areConnected(self, p, q):
        return (self._getRoot(p) == self._getRoot(q))

    def union(self,p,q):
        rootP = self._getRoot(p)
        rootQ = self._getRoot(q)
        self._tab[rootP] = rootQ

    def getConnectedComponents(self):
        out = []
        uniqueRoots = []
        for i in range(len(self._tab)):
            root = self._getRoot(i)
            if(root not in uniqueRoots):
                uniqueRoots.append(root)

        for root in uniqueRoots:
            toAdd=[]
            for i in range(len(self._tab)):
                elementsRoot = self._getRoot(i)
                if(elementsRoot == root):
                    toAdd.append(i)

            out.append(tuple(toAdd))

        return out

class RootClimberTest(unittest.TestCase):
    def testIter1(self):
        r = RootClimberIter([0,1,9,4,9,6,6,7,8,9])
        self.checkAll1(r)

    def testRecur1(self):
        r = RootClimberRecur([0,1,9,4,9,6,6,7,8,9])
        self.checkAll1(r)

    def testIter2(self):
        r = RootClimberIter([0,1,1,8,3,0,5,1,8,8])
        self.checkAll2(r)

    def testRecur2(self):
        r = RootClimberRecur([0,1,1,8,3,0,5,1,8,8])
        self.checkAll2(r)

    def checkAll1(self, r):
        self.assertEqual(0, r.getRoot(0))
        self.assertEqual(1, r.getRoot(1))
        self.assertEqual(9, r.getRoot(2))
        self.assertEqual(9, r.getRoot(3))
        self.assertEqual(9, r.getRoot(4))
        self.assertEqual(6, r.getRoot(5))
        self.assertEqual(6, r.getRoot(6))
        self.assertEqual(7, r.getRoot(7))
        self.assertEqual(8, r.getRoot(8))
        self.assertEqual(9, r.getRoot(9))

    def checkAll2(self, r):
        self.assertEqual(0, r.getRoot(0))
        self.assertEqual(1, r.getRoot(1))
        self.assertEqual(1, r.getRoot(2))
        self.assertEqual(8, r.getRoot(3))
        self.assertEqual(8, r.getRoot(4))
        self.assertEqual(0, r.getRoot(5))
        self.assertEqual(0, r.getRoot(6))
        self.assertEqual(1, r.getRoot(7))
        self.assertEqual(8, r.getRoot(8))
        self.assertEqual(8, r.getRoot(9))

# moznaby podziedziczyc testy, ale sa problemy,
# odpalaja sie podwojnie ;<
class QuickUnionTest1(unittest.TestCase):
    def setUp(self):
        self.qf = QuickUnion(10)
        self.qf.union(4,3)
        self.qf.union(3,8)
        self.qf.union(6,5)
        self.qf.union(9,4)
        self.qf.union(2,1)

    def test1(self):
        self.assertFalse(self.qf.areConnected(0,7))
        self.assertTrue(self.qf.areConnected(8,9))
        # 1 elementowe tuple tak wygladaja
        self.assertEqual([(0,), (1,2), (3,4,8,9), (5,6), (7,)], self.qf.getConnectedComponents())

    def test2(self):
        self.qf.union(5,0)
        self.qf.union(7,2)
        self.qf.union(6,1)
        self.qf.union(1,0)

        self.assertTrue(self.qf.areConnected(0,7))
        self.assertEqual([(0,1,2,5,6,7), (3,4,8,9)], self.qf.getConnectedComponents())

class QuickUnionTest2(unittest.TestCase):
    def test(self):
        qf = QuickUnion(10)
        qf.union(4,3)
        qf.union(3,8)
        qf.union(6,5)
        qf.union(9,4)
        qf.union(2,1)
        self.assertTrue(qf.areConnected(8,9))
        self.assertFalse(qf.areConnected(5,0))
        qf.union(5,0)
        qf.union(7,2)
        qf.union(6,1)

        expectedConnectedComponents = [(0,1,2,5,6,7), (3,4,8,9)]
        self.assertEqual(expectedConnectedComponents, qf.getConnectedComponents())

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


# -*- coding: utf-8 -*-
import requests
import time
import f_voice as f_v
import f_hear as f_h
from multiprocessing import Process, current_process,Lock
import f_data as f_d

class session:
    m_a = "https://gpd-friday.herokuapp.com/"
    r_a = "https://gpd-friday.herokuapp.com/read?m_id="
    l_a = "https://gpd-friday.herokuapp.com/error?m_id="
    def create(self,user):
        self.user = user
    def ask(self,quest):
        requests.post(self.m_a,data={"user":self.user,"mes":quest})
        text = ""
        while True:
            time.sleep(3)
            text = requests.get(self.r_a+self.user).text
            if len(text)>5:
                break
        requests.post(self.r_a+self.user,data={"dell":self.user})
        #work with added material
        return text.split("-&&-")[0]

    def log(self):
        q = requests.get(self.l_a+self.user).text
        requests.post(self.l_a+self.user,data={"dell":self.user})
        return q

class assistant:
    cou  = 0
    lock = Lock()
    def create(self,name):
        self.user = name
        self.brain = self.smart_brain()
        self.proc = []

    def do(self,quest):
        p = Process(target= self.brain.brain_storm,name = self.user+"_process_"+str(self.cou),args=(quest,self.lock))
        self.proc.append(p)
        p.start()
        self.cou += 1

    def does(self,d):
        self.ear = f_h.talk()
        self.ear.create(d)
        p = Process(target=self.ear.start_proc ,name = "SpeechRecognition",args=())
        self.proc.append(p)
        p.start()

    class smart_brain:
        def brain_storm(self,quest,loc):
            my_p = current_process().name
            search = session()
            search.create(my_p)
            ans = search.ask(quest)
            say = f_v.audio()
            sound_proc = Process(target= say.tts,name = "Audio",args=(loc,ans,"voice_"+my_p+".mp3"))
            sound_proc.start()
            sound_proc.join()

def start():
    db = f_d.data()
    db.create()
    fri = assistant()
    fri.create("friday")
    fri.does(db)

    while True :
        e = db.read_cou()
        if e != 0:
            fri.do(db.read("audio_"+str(int(e)-1)))
            db.minus_counter()
            db.delete_item("audio_"+str(int(e)-1))

    for y in fri.proc:
        y.join()

if __name__ == "__main__":
    start()


import os
import importlib

from pyrogram import Client

class Config:
    API_ID = int(3716600)# int(os.environ.get("API_ID"))
    API_HASH = str("0ed423ceea4fbb06c0e627d9db0f4a6b")# str(os.environ.get("API_HASH"))
    BOT_TOKEN = str("2023772023:AAELvE7PzeD2hggebtCuN0HM5FWhV9WbXgs")# str(os.environ.get("BOT_TOKEN"))

class NoteBot(Client):
    def __init__(self):
        kwargs = {
            'api_id': Config.API_ID,
            'api_hash': Config.API_HASH,
            'session_name': ":memory:",
            'bot_token': Config.BOT_TOKEN
        }
        super().__init__(**kwargs)

    async def start(self):
        await super().start()
        print("START")
        try:
            path = os.listdir("notemusic/plugins")
            path.remove("creator_commands.py")
            for p in path:
                if p.endswith(".py"):
                    arq = p.replace(".py", "")
                    importlib.import_module("plugins." + arq)
                    importlib.import_module("plugins.creator_commands")
        except Exception as e:
            print(str(e))
            await self.send_message(-1001165341477, f"**❌ OCORREU UM ERRO**\n\nNão foi possível importar os plugins, ocorreu este erro: `{str(e)}`")
        else:
            await self.send_message(-1001165341477, "`NoteMusic iniciado com sucesso!`")

    async def stop(self):
        await super().stop()
        print("STOP")

NoteMusic = NoteBot()


import mimetypes
import os
from email import encoders as email_encoders
from email.mime.base import MIMEBase

from envelopes import Envelope

class AdvancedEnvelope(Envelope):
    def add_src_image(self, file_path, mimetype=None, src_name=None):
        """Attaches a file located at *file_path* to the envelope. If
               *mimetype* is not specified an attempt to guess it is made. If nothing
               is guessed then `application/octet-stream` is used."""
        if not mimetype:
            mimetype, _ = mimetypes.guess_type(file_path)

        if mimetype is None:
            mimetype = 'application/octet-stream'

        type_maj, type_min = mimetype.split('/')
        with open(file_path, 'rb') as fh:
            part_data = fh.read()

            part = MIMEBase(type_maj, type_min)
            part.set_payload(part_data)
            email_encoders.encode_base64(part)

            if not src_name:
                part_filename = os.path.basename(self._encoded(file_path))
                src_name = part_filename
            part.add_header('Content-ID', '<{}>'.format(src_name))
            self._parts.append((mimetype, part))


import pytest
from sqlalchemy.orm.exc import NoResultFound
from tensorhive.models.Group import Group
from tensorhive.exceptions.InvalidRequestException import InvalidRequestException

def test_group_creation(tables):
    new_group = Group(name='test').save()
    assert new_group.id is not None

def test_adding_user_to_a_group(tables, new_user, new_group):
    new_user.save()
    new_group.add_user(new_user)

    assert new_user in new_group.users
    assert new_group in new_user.groups

def test_removing_user_from_a_group(tables, new_group_with_member):
    user = new_group_with_member.users[0]
    new_group_with_member.remove_user(user)

    assert user not in new_group_with_member.users
    assert new_group_with_member not in user.groups

def test_removing_user_from_a_group_that_he_doesnt_belong_to_fails(tables, new_user, new_group):
    new_group.save()
    new_user.save()

    with pytest.raises(InvalidRequestException):
        new_group.remove_user(new_user)

def test_adding_user_to_a_group_that_he_is_already_in_fails(tables, new_group_with_member):
    user = new_group_with_member.users[0]

    with pytest.raises(InvalidRequestException):
        new_group_with_member.add_user(user)

def test_marking_group_as_a_default(tables, new_group):
    new_group.is_default = True
    new_group.save()

    assert Group.get(new_group.id).is_default
    assert new_group in Group.get_default_groups()

def test_get_default_group(tables, new_group):
    new_group.is_default = True
    new_group.save()

    assert new_group in Group.get_default_groups()

def test_get_default_without_default_group(tables, new_group):
    new_group.save()

    assert len(Group.get_default_groups()) == 0

def test_more_than_one_default_group(tables, new_group):
    new_group.is_default = True
    new_group.save()

    another_group = Group(name='AnotherGroup')
    another_group.is_default = True
    another_group.save()

    defaults = Group.get_default_groups()
    assert new_group in defaults
    assert another_group in defaults


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

from flask import Flask
from flask import jsonify
import time
import threading
import requests
import pika

global g_on_light_number
global g_light_time
global light_status
light_status = ""

g_host_name = "localhost"
g_change_request_queue = "change_request_queue"
g_light_time_queue = "light_time_queue"

app = Flask(__name__)

@app.route('/')
def SetUp():
    return "Hello server!"

@app.route("/ledtime")
def get_led_time():
    return jsonify(
        light_number = g_on_light_number,
        time = g_light_time
    )

def receive_message_from_mq():

    connection = pika.BlockingConnection(pika.ConnectionParameters(host=g_host_name))
    channel = connection.channel()

    channel.queue_declare(queue=g_light_time_queue, arguments={'x-message-ttl': int(1000)})

    def callback(ch, method, properties, body):
        global g_on_light_number
        global g_light_time
        global light_status

        decoded_body = body.decode('utf-8')
        # print("Message is Arrived : %s"%(decoded_body))
        if(light_status != decoded_body):
            light_status = decoded_body
            print("Now light status : %s"%(light_status))
            splitted_body = light_status.split(" ")
            g_on_light_number = int(splitted_body[0])
            g_light_time = int(splitted_body[1])

    channel.basic_consume(queue=g_light_time_queue, on_message_callback=callback, auto_ack=True)

    try:
        print("Waiting for messages.")
        channel.start_consuming()
    except KeyboardInterrupt:
        pass

try:
    if __name__== "__main__":

        receive_message_from_mq = threading.Thread(target=receive_message_from_mq)
        receive_message_from_mq.start()

        app.run("0.0.0.0", port="18080")

except KeyboardInterrupt:
    pass

#스레드는 한번만 실행할 수 있다.


from django.urls import path
from . import views

urlpatterns = [
	path('register/',views.register, name='register'),
	path('',views.loginPage, name='loginPage'),
	path('logoutUser/',views.logoutUser, name='logoutUser'),
	path('container/',views.container, name='container'),
	path('allcustomers/',views.allcustomers, name='allcustomers'),
	path('container/<str:pk_test>',views.containerpages, name='containerpages'),
	path('create_container/',views.createContainer,name='createContainer'),
	path('create_customer/',views.createCustomer,name='createCustomer'),
	path('create_groupcustomers/<str:ct_id>',views.createGroupCustomers,name='create-groupcustomers'),
	path('update_customer/<str:pk>',views.updateCustomer,name='updateCustomer'),
	path('update_container/<str:pk_cont>',views.updateContainer,name='updateContainer'),
	path('delete_customer/<str:pk_del>',views.deleteCustomer,name='deleteCustomer'),
	path('delete_container/<str:pk_del_cont>',views.deleteContainer,name='deleteContainer'),
	path('add_customer/',views.addcustomer, name='add_customer'),
	path('remove_all/',views.removeAll, name='removeAll'),

]


import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC
from sklearn.metrics import roc_auc_score
from sklearn.ensemble import RandomForestClassifier

def fines():

    df = pd.read_csv('train.csv', encoding = "ISO-8859-1")
    df.index = df['ticket_id']
    features = ['fine_amount', 'admin_fee', 'state_fee', 'late_fee','discount_amount', 'clean_up_cost', 'judgment_amount']

    df.compliance = df.compliance.fillna(value=-1)
    df = df[df.compliance!=-1]
    df_X = df[features]
    df_X = df_X.fillna(value = -1)
    df_y = df['compliance']
    df_y = df_y.fillna(value = -1)

    X = df_X
    y = df_y

    X_train, X_test, y_train, y_test = train_test_split(X, y, random_state = 0)
    model = RandomForestClassifier(n_estimators = 20, max_depth = 5).fit(X_train, y_train)
    df_test = pd.read_csv('data.csv', encoding = "ISO-8859-1")
    df_test.index = df_test['ticket_id']

    X_test_ii = df_test[features]

    predicted = model.predict_proba(X_test_ii)

    return pd.Series(data = predicted[:,1], index = df_test['ticket_id'])


import joblib
import numpy as np
import os
data_name="p_superv"
input_file = f"data/{data_name}/features.npy"
len_file = f"data/{data_name}/features.length"
output_file = f"data/{data_name}/features.clusters"
km_file = "models/km100.bin"

km = joblib.load(km_file)

features = np.load(input_file)
with open(len_file, 'r') as f:
    lengths = f.read().split("\n")
lengths = [int(l) for l in lengths]
assert sum(lengths) == len(features)
features = np.split(features, np.cumsum(lengths)[:-1])
if os.path.exists(output_file):
    os.remove(output_file)
for f in features:
    clusters = km.predict(f)
    with open(output_file, 'a') as f:
        f.write(" ".join([str(c) for c in clusters]) + "\n")


from sklearn.metrics import confusion_matrix, plot_confusion_matrix, accuracy_score
import matplotlib.pyplot as plt

def AccuracyAndConfusion(xTest, yTest, yPred, model, modelTypeFull):
    """
    Generates and saves a confusion matrix plot to directory, and returns an accuracy score.

    Args:
        xTest (list, required): x test data
        yTest (list, required): y test data
        yPred (list, required): y prediction
        model (model object, required): classifier model object of sklearn
        modelTypeFull (string, required): name of the type of model

    Returns:
        `accuracy`: accuracy score
    """

    classNeg = model.classes_[0]
    classPos = model.classes_[1]

    titles_options = [("Confusion matrix, without normalization", None),
                      (modelTypeFull+ ' Normalized confusion matrix', 'true')]
    for title, normalize in titles_options:
        disp = plot_confusion_matrix(model, xTest, yTest,
                                    display_labels=[classNeg, classPos],
                                    cmap=plt.cm.get_cmap('viridis'),
                                    normalize=normalize)
        disp.ax_.set_title(title)

        print(" ")
        print(title)
        print(disp.confusion_matrix)
    plt.savefig(modelTypeFull+' Confusion Matrix.png')
    plt.close()

    cm = confusion_matrix(yTest, yPred)
    print(" ")
    print(modelTypeFull," Confusion Matrix:")
    print(cm)

    accuracy = accuracy_score(yTest, yPred)
    print(" ")
    print(modelTypeFull," Accuracy Score:")
    print(accuracy)
    return accuracy


class Solution:
    def findingUsersActiveMinutes(self, logs: List[List[int]], k: int) -> List[int]:
        # id -> set()
        # iterate
        id_set = dict()
        for log in logs:
            if log[0] not in id_set:
                id_set[log[0]] = set()
            id_set[log[0]].add(log[1])
        res = [0] * k
        for _set in id_set.values():
            res[len(_set) - 1] += 1
        return res

1817. Finding the Users Active Minutes/solution.py


# https://www.codewars.com/kata/5842df8ccbd22792a4000245/solutions/python
# clever:
# num = list(str(num))
# return ' + '.join(x + '0' * (len(num) - y - 1) for y,x in enumerate(num) if x != '0')

def expanded_form(n):
    out = []
    out2 = []

    while n > 0:
        out.append(n % 10)
        n //= 10

    out.reverse()

    for i, num in enumerate(out):
        if num != 0:
            out2.append(str(num * (10 ** (abs(i - (len(out) - 1))))))

    return ' + '.join(out2)


#!/usr/bin/env python3
'''
Convert my scraped and reformatted publication information to a Drupal-compatible CSV for bulk upload to the BISB website
Niema Moshiri 2019
'''
from PMIDs_to_publications import NA
DOI_URL_PREFIX = "https://doi.org"
ISBN_URL_PREFIX = "https://isbnsearch.org/isbn"
PUBMED_URL_PREFIX = "http://www.ncbi.nlm.nih.gov/pubmed"

# publication types
PUB_TYPE = {'book':'Book Chapter', 'journal':'Journal Article', 'other':''}

if __name__ == "__main__":
    # parse user arguments
    from sys import stderr; import argparse
    parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    parser.add_argument('-i', '--input', required=False, type=str, default='stdin', help="Input Publication Information TSV")
    parser.add_argument('-o', '--output', required=False, type=str, default='stdout', help="Output Drupal CSV")
    args = parser.parse_args()
    if args.input == 'stdin':
        from sys import stdin as infile
    else:
        infile = open(args.input)
    if args.output == 'stdout':
        from sys import stdout as outfile
    else:
        outfile = open(args.output,'w')

    # parse publication info list and reformat output
    outfile.write("title,field_authors,field_doi,field_isbn_number,field_issn_number,field_issue,field_journal,field_pages,field_pmc_id,field_pubmed_id,field_bisb_training_grant,field_type,field_volume,field_year\n")
    for l in infile:
        if l.startswith('PMID\t'):
            continue
        try:
            pmid,pmcid,doi_isbn_url,journal_abbr,journal_full,issn,year,volume,issue,pages,title,authors,training_grant = l.strip().split('\t')
        except Exception as e:
            print("ERROR WITH LINE: %s" % l.strip())
            raise e
        entry = dict()
        entry['title'] = title.strip()
        entry['authors'] = authors.replace('|', ', ')
        entry['training_grant'] = {'Yes':'1', 'No':'0'}[training_grant.strip()]
        if doi_isbn_url.lower().startswith('doi:'):    # parse DOI
            entry['doi'] = ':'.join(doi_isbn_url.split(':')[1:]).strip()
            entry['isbn'] = ''
            entry['pub_type'] = PUB_TYPE['journal']
        elif doi_isbn_url.lower().startswith('isbn:'): # parse ISBN
            entry['doi'] = ''
            entry['isbn'] = ':'.join(doi_isbn_url.split(':')[1:]).strip(); url = '%s/%s' % (ISBN_URL_PREFIX, entry['isbn'])
            entry['pub_type'] = PUB_TYPE['book']
        elif doi_isbn_url.lower().startswith('url:'):  # parse URL
            entry['doi'] = ''
            entry['isbn'] = ''
            entry['pub_type'] = PUB_TYPE['other']
        elif doi_isbn_url.strip() == NA:
            entry['doi'] = ''
            entry['isbn'] = ''
            entry['pub_type'] = ''
        else:
            raise ValueError("Unrecognized DOI/ISBN/URL: %s" % doi_isbn_url.strip())
        entry['issn'] = issn.strip()
        entry['issue'] = issue.strip()
        entry['pmcid'] = pmcid
        if pmid.strip() == NA:
            entry['pmid'] = ''
        else:
            entry['pmid'] = pmid
            entry['pub_type'] = PUB_TYPE['journal'] # override
        entry['volume'] = volume.strip()
        entry['year'] = year.strip()
        entry['journal'] = journal_abbr.strip()
        entry['pages'] = pages.strip()
        for k in entry:
            if entry[k].strip() == NA:
                entry[k] = ''
        outfile.write('%s\n' % (','.join(('"%s"' % entry[k].replace('"',"'")) for k in ['title','authors','doi','isbn','issn','issue','journal','pages','pmcid','pmid','training_grant','pub_type','volume','year'])))