import json

from consumption import ConsumptionBelow100, ConsumptionBelow200, ConsumptionBelow300, ConsumptionAbove300

class Bill:
  # define the constructor
  def __init__(self, name, consumption):
    self.name = name
    self.consumption = int(consumption)

class ConsumptionRepository:
  def get(self):
    bills = self.read_from_file()
    # make an empty list
    consumption_objects = []
    for bill_dict in bills:
      # create an object Consumption
      new_consumption = self.make_consumption(bill_dict['consumption'], bill_dict['name'])
      # add a Consumption object to the list
      consumption_objects.append(new_consumption)
    return consumption_objects

  def make_consumption(self, units, name):
    units = int(units)
    if units < 100:
      return ConsumptionBelow100(units, name)
    if units < 200:
      return ConsumptionBelow200(units, name)
    if units < 300:
      return ConsumptionBelow300(units, name)
    return ConsumptionAbove300(units, name)

  def read_from_file(self):
    # create a File object (handler)
    file = open('electricity_bills.json')
    # read the content of the file, we get a string
    encoded_json = file.read()
    # close the reading channel
    file.close()
    # decode the json
    bills = json.loads(encoded_json)
    return bills


#Recebendo o codgo do produto e a quantidade e retornando o preço

products = {"1":4.00,"2":4.50,"3":5.00,"4":2.00,"5":1.5}

values = input().split()
x,y = values

#quantidade do produto
y = int(y)

total = products[x] * y

print("Total: R$ {:.2f}".format(total))


# Calculate a phone call cost.

## function to get an integer with error checking
def get_int(input_prompt, min_val=int(1), max_val=int(100)):
    return_value=int(0)
    int_val=int(-1)

    try:
        while not ((int_val >= min_val and int_val <= max_val)) :
            get_val=input(input_prompt + f" (Min: {str(min_val)} Max: {str(max_val)} Exit: 0)")
            int_val=int(get_val)

            ## exit if select 0
            if  int_val==0:
                break

        return_value=int_val
    except:
        print ( f"Invalid '{input_prompt}' value entered '" + get_val + "'" )
    finally:
        return return_value

# inits
call_rate=int(15)
vat_rate=float(0.2) ## 20%

# Get user data
num_mins=get_int("Please enter the number of minutes used: ", 1, 9999)

# calcs
basic_charge = num_mins * call_rate  ## in pence
vat_charge = basic_charge * vat_rate ## again in pence

# output
print ( f'Number of minutes used: {num_mins}')
print ( f'Basic call charge: £{(basic_charge/100):.2f}')
print ( f'VAT due: £ {(vat_charge/100):.2f}')  ## this spurious space after the £ was in the spec...
print ( f'Total bill: £{((basic_charge+vat_charge)/100):.2f}')


import numpy as np
import matplotlib.pyplot as plt

def displayData(X):

    num_plots = int(np.size(X,0)**.5)
    fig, ax = plt.subplots(num_plots,num_plots,sharex=True,sharey=True)
    img_num = 0
    for i in range(num_plots):
        for j in range(num_plots):
            # Convert column vector into 20x20 pixel matrix transposes
            img = X[img_num,:].reshape(20,20).T
            ax[i][j].imshow(img,cmap='gray')
            ax[i][j].axis('off')
            img_num += 1
    plt.show()

    return (fig, ax)


# Merge sort tree solution
class merge_sort_tree:

	def __init__(self, size, nums):
		self.size = size
		self.nums = nums
		self.tree = [None] * (2 * size)
		self.build_tree()

	def merge_tree(self, nums1, nums2):
		N, M = len(nums1), len(nums2)
		output, p1, p2 = [], 0, 0
		while p1 < N and p2 < M:
			if nums1[p1] < nums2[p2]:
				output.append(nums1[p1])
				p1 += 1
			else:
				output.append(nums2[p2])
				p2 += 1

		output += nums1[p1:] + nums2[p2:]
		return output

	def build_tree(self):
		for i in range (self.size):
			self.tree[i + self.size] = [2 * self.nums[i]]

		for i in range (self.size - 1, 0, - 1):
			self.tree[i] = self.merge_tree(self.tree[2 * i], self.tree[2 * i + 1])

	def query_tree(self, target, start_idx, end_idx):
		output = 0
		start_idx, end_idx = start_idx + self.size, end_idx + self.size

		while start_idx <= end_idx:
			if ((start_idx & 1) > 0):
				output += bisect.bisect_left(self.tree[start_idx], target)
			if ((end_idx & 1) == 0):
				output += bisect.bisect_left(self.tree[end_idx], target)

			start_idx, end_idx = (start_idx + 1) // 2, (end_idx - 1) // 2

		return output

class Solution:
	def reversePairs(self, nums: List[int]) -> int:
		N, output = len(nums), 0
		MST = merge_sort_tree(N, nums)
		for i in range (0, N - 1):
			output += MST.query_tree(nums[i], i + 1, N - 1)
		return output


'''Write a function that, given a string, returns its longest palindromic substring.
A palindrome is defined as a string that is written the same forward and backward.
Assume that there will only be one longest palindromic substring.
'''

def longestPalindromicSubstring(string):
    currentLongest=[0, 1]
    for i in range(1, len(string)):
        odd = getlongestpalindrome(string, i-1, i+1)
        even = getlongestpalindrome(string, i-1, i)
        longest = max(odd, even, key=lambda x: x[1] - x[0])
        currentLongest = max(longest, currentLongest, key=lambda x: x[1] - x[0])
    return string[currentLongest[0]:currentLongest[1]]

def getlongestpalindrome(string, lidx, ridx):
    while lidx>=0 and ridx<len(string):
        if string[lidx] != string[ridx]:
            break
        lidx -=1
        ridx +=1
    return [lidx+1, ridx]

print(longestPalindromicSubstring('tracecars'))


"""
The list of Rules (Input for allocation)
GlobalRules:
* Rules will be applied that change how the engine is run, or
  specific attributes to the AllocationResult object. (Like an increase)
InstanceRules:
* Each rule will be applied individually on a specific instance history
* In adition to the history and the current running_time

TODO: We have 'Ignore*Rule', it might be nice to have a 'Match*Rule' class
      to define what you DO want counted.. rather than what you don't...
"""
from abc import ABCMeta

from threepio import logger

# Utils
def _needle_in_haystack(haystack, needle):
    for value in haystack:
        if value == needle:
            return True
    return False

# Level 1
class Rule():
    __metaclass__ = ABCMeta

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

# Level 2
class GlobalRule(Rule):

    """
    """

    def apply_global_rule(self, allocation, allocation_result):
        raise NotImplementedError("Should be implemented by subclass.")

class InstanceRule(Rule):

    """
    """

    def apply_rule(self, instance, history, running_time, print_logs=False):
        raise NotImplementedError("Should be implemented by subclass.")

class EngineRule(GlobalRule):

    """
    """

# Level 3
class CarryForwardTime(EngineRule):

    """
    When there is "leftover" time between TimePeriods, carry forward the time.
    """

    def apply_global_rule(self, allocation, allocation_result):
        allocation_result.carry_forward = True

    def __init__(self, name=None):
        if not name:
            name = "Carry Forward between TimePeriodResults"
        super(CarryForwardTime, self).__init__(name)

class FilterOutRule(InstanceRule):

    """
    These rules determine what InstanceHistory status should
    be filtered out of calculation
    """
    __metaclass__ = ABCMeta
    instance_attr = None
    value = None

    def __init__(self, name, value):
        super(FilterOutRule, self).__init__(name)
        self.value = value

class InstanceCountingRule(InstanceRule):

    """
    Each sub-class represents a way of 'counting time'.
    Instance
    """
    __metaclass__ = ABCMeta

    def __init__(self, name):
        super(InstanceCountingRule, self).__init__(name)

class InstanceMultiplierRule(InstanceCountingRule):

    """
    Instance Multiplier Rules.. ALL rules of this type will be applied
    MULTIPLICATIVELY to an instance.
    """
    __metaclass__ = ABCMeta
    multiplier = None

    def __init__(self, name, multiplier):
        super(InstanceMultiplierRule, self).__init__(name)
        self.multiplier = multiplier

# Types of 'FilterOutRule'
class IgnoreStatusRule(FilterOutRule):

    def __init__(self, name, value):
        super(IgnoreStatusRule, self).__init__(name, value)
        self.instance_attr = 'status'

    def apply_rule(self, instance, history, running_time, print_logs=False):
        """
        If a match is found between Status History and the 'needle'
        Then the running_time should be ZEROed.
        """
        if not isinstance(self.value, list):
            values = [self.value]
        else:
            values = self.value
        found_match = _needle_in_haystack(values, history.status)
        if found_match:
            running_time *= 0
            if print_logs:
                logger.debug(">> Ignore Instance Status '%s'. Set Runtime to 0"
                             % (history.status))
        # All misses.
        return running_time

    def _validate_value(self, value):
        if not isinstance(value, str):
            raise Exception("Expects a name to be matched on "
                            "InstanceStatusHistory.status")

class IgnoreMachineRule(FilterOutRule):

    def __init__(self, name, value):
        super(IgnoreMachineRule, self).__init__(name, value)
        self.instance_attr = 'machine'

    def _validate_value(self, value):
        if not isinstance(value, str):
            raise Exception("Expects a machine UUID to be matched on "
                            "Instance.machine.identifier")

    def apply_rule(self, instance, history, running_time, print_logs=False):
        """
        If a match is found between Machine UUID and the 'needle'
        Then the running_time should be ZEROed.
        """
        if not isinstance(self.value, list):
            values = [self.value]
        else:
            values = self.value
        found_match = _needle_in_haystack(values, instance.machine.identifier)
        if found_match:
            running_time *= 0
            if print_logs:
                logger.debug(">> Ignore Machine identifier '%s'."
                             "Set Runtime to 0" % (history.status))
        return running_time

class IgnoreProviderRule(FilterOutRule):

    def _validate_value(self, value):
        if not isinstance(value, str):
            raise Exception("Expects a provider UUID to be matched on "
                            "Instance.provider.identifier")

    def apply_rule(self, instance, history, running_time, print_logs=False):
        """
        If a match is found between Provider ID and the 'needle'
        Then the running_time should be ZEROed.
        """
        if not isinstance(self.value, list):
            values = [self.value]
        else:
            values = self.value
        found_match = _needle_in_haystack(values, instance.provider.identifier)
        if found_match:
            running_time *= 0
            if print_logs:
                logger.debug(">> Ignore Provider identifier '%s'."
                             "Set Runtime to 0"
                             % (history.status))
        return running_time

    def __init__(self, name, value):
        super(IgnoreProviderRule, self).__init__(name, value)
        self.instance_attr = 'provider'

# Types of 'InstanceCountingRule'
class MultiplyBurnTime(InstanceMultiplierRule):

    def apply_rule(self, instance, history, running_time, print_logs=False):
        """
        Multiply the running_time by (multiplier) to adjust the overall burn
        time.
        """
        if print_logs:
            logger.debug(">> %s Current Running Time:%s * Multiplier:%s = %s"
                         % (history.status, running_time, self.multiplier,
                            running_time * self.multiplier))
        running_time *= self.multiplier
        return running_time

    def __init__(self, name, multiplier):
        super(MultiplyBurnTime, self).__init__(name, multiplier)

class MultiplySizeCPU(InstanceMultiplierRule):

    def apply_rule(self, instance, history, running_time, print_logs=False):
        """
        Multiply the running_time by size of CPU * (multiplier)
        """
        if print_logs:
            logger.debug(
                ">> %s Current Running Time:%s * CPU:%s * Multiplier:%s = %s"
                % (history.status, running_time, history.size.cpu,
                   self.multiplier,
                   running_time * history.size.cpu * self.multiplier))
        running_time *= self.multiplier * history.size.cpu
        return running_time

    def __init__(self, name, multiplier):
        super(MultiplySizeCPU, self).__init__(name, multiplier)

class MultiplySizeDisk(InstanceMultiplierRule):

    """
    Units here are ALWAYS in GB
    """

    def apply_rule(self, instance, history, running_time, print_logs=False):
        """
        Multiply the running_time by size of Disk (GB) * (multiplier)
        """
        if print_logs:
            logger.debug(
                ">> %s Current Running Time:%s * Disk:%s * Multiplier:%s = %s"
                % (history.status, running_time, history.size.disk,
                   self.multiplier,
                   running_time * history.size.disk * self.multiplier))
        running_time *= self.multiplier * history.size.disk
        return running_time

    def __init__(self, name, multiplier):
        super(MultiplySizeDisk, self).__init__(name, multiplier)

class MultiplySizeRAM(InstanceMultiplierRule):

    """
    Units here are ALWAYS in MB

    Ex: SizeRAM(1GB)
    Instance 1 : 10 hours used * 8GB = 80 Hours
                 ( unit:(1/1024MB) * value:8*1024 MBs)
    """

    def _gb_to_mb(gb_size):
        return gb_size * 1024

    def _mb_to_gb(mb_size):
        return mb_size / 1024.0

    def apply_rule(self, instance, history, running_time, print_logs=False):
        """
        Multiply the running_time by size of RAM (MB) * (multiplier)
        NOTE: To calculate in GB, set self.multiplier = 1/1024
        """
        if print_logs:
            logger.debug(
                ">> %s Current Running Time:%s * RAM:%s * Multiplier:%s = %s"
                % (history.status, running_time, history.size.disk,
                   self.multiplier,
                   running_time * history.size.disk * self.multiplier))
        running_time *= self.multiplier * history.size.ram
        return running_time

    def __init__(self, name, multiplier):
        super(MultiplySizeRAM, self).__init__(name, multiplier)


# -*- coding:utf-8 -*-
import cv2 as cv
import os
import torch
from natsort import natsorted
from torchvision import transforms

def read_cube(path):
    # print(path)
    imgs = []
    names = natsorted(os.listdir(path))
    for name in names:
        img = cv.imread(os.path.join(path, name), cv.IMREAD_COLOR)
        img = img[:,:,:1]
        # print(path, name, img.shape)
        img = transforms.ToTensor()(img)
        imgs.append(img)
    imgs = torch.stack(imgs, dim=1)
    return imgs

def check_interpolation(imgs, target_cube_size):
    if target_cube_size[-1] != imgs.shape[-1] or target_cube_size[-2] != imgs.shape[-2] or target_cube_size[-3] != \
            imgs.shape[-3]:
        imgs = imgs.unsqueeze(0)
        imgs = torch.nn.functional.interpolate(imgs, size=target_cube_size, mode='trilinear', align_corners=True)
        imgs = imgs.squeeze(0)
    return imgs

def augmentation_torch_multi(images):
    #horizontal flip
    if torch.randint(0, 2, (1,)).item()==0:
        for i in range(len(images)):
            images[i] = torch.flip(images[i], dims=(1,))
    #Vertical flip
    if torch.randint(0, 2, (1,)).item()==0:
        for i in range(len(images)):
            images[i] = torch.flip(images[i], dims=(3,))
    #rot90
    if torch.randint(0, 2, (1,)).item()==0:
        k=torch.randint(1, 4, (1,)).item()
        for i in range(len(images)):
            images[i] = torch.flip(images[i], dims=(3,))
            images[i]=torch.rot90(images[i],k,dims=(1,3))
    for i in range(len(images)):
        images[i] = images[i].detach()
    return images


from typing import Any, Iterator
import io

Map = tuple[tuple[int]]

def find_height_edges(forest: Iterator[Iterator[int]]):
    for line in forest:
        seen: list[int | None] = [None for _ in range(10)]
        for index, height in enumerate(line):
            if seen[height] is None:
                seen[height] = index
                for smaller in range(height):
                    if seen[smaller] is None:
                        seen[smaller] = -1
        yield [index if index != -1 else None for index in seen]

def find_visible(edge_left, edge_right, edge_top, edge_bottom, size: int):
    visible = set()
    for line_idx, row_indices in enumerate(edge_left):
        visible.update(
            (line_idx, row_idx) for row_idx in row_indices if row_idx is not None
        )
    for line_idx, row_indices in enumerate(edge_right):
        visible.update(
            (line_idx, size - row_idx - 1) for row_idx in row_indices if row_idx is not None
        )
    for row_idx, line_indices in enumerate(edge_top):
        visible.update(
            (line_idx, row_idx) for line_idx in line_indices if line_idx is not None
        )
    for row_idx, line_indices in enumerate(edge_bottom):
        visible.update(
            (size - line_idx - 1, row_idx) for line_idx in line_indices if line_idx is not None
        )
    return len(visible)

def scenic_score(down: int, right: int, forest: Map) -> int:
    own_height = forest[down][right]
    score = 1
    for line in (
        (row[right] for row in forest[:down][::-1]),  # up
        forest[down][:right][::-1],  # left
        forest[down][right+1:],  # right
        (row[right] for row in forest[down+1:]),  # down
    ):
        distance = 0
        for distance, height in enumerate(line, start=1):
            if height >= own_height:
                break
        score *= distance
    return score

def solve(data: io.StringIO) -> tuple[Any, Any]:
    board = tuple(tuple(int(tree) for tree in line.strip()) for line in data)
    edge_left = tuple(find_height_edges(board))
    edge_right = tuple(find_height_edges(reversed(line) for line in board))
    edge_top = tuple(find_height_edges(zip(*board)))
    edge_bottom = tuple(find_height_edges(reversed(line) for line in zip(*board)))
    size = len(board)
    max_score = max(
        scenic_score(down, right, board)
        for down in range(1, size)
        for right in range(1, size)
    )
    return find_visible(edge_left, edge_right, edge_top, edge_bottom, size), max_score


from django.contrib.auth import authenticate, login, get_user_model
from django.http import JsonResponse
from django.shortcuts import get_object_or_404
from rest_framework import mixins, viewsets, status
from rest_framework.decorators import action
from rest_framework.permissions import AllowAny
from rest_framework.response import Response
from rest_framework.views import APIView

from core.services import send_email
from customer.models import User
from .serializers import UserSerializer, LoginUserSerializer, \
    ConformationCodeSerializer
from .services import get_tokens_for_user

class UserSingUpApiView(APIView):
    """Вью для отображения регистрации пользователя и
    отправки сообщения на указанный mail кода подтверждения.
    """
    queryset = get_user_model()
    permission_classes = (AllowAny,)

    def post(self, request):
        serializer = UserSerializer(data=request.data)
        if serializer.is_valid(raise_exception=True):
            username = serializer.validated_data['username']
            email = serializer.validated_data['email']
            serializer.save()
            return JsonResponse({'email': email, 'username': username})

class TokenAPIView(APIView):
    """Вью для подтверждения полного доступа к
    сайту зарегистрированного пользователя.
    """
    permission_classes = (AllowAny,)

    def post(self, request):
        serializer = ConformationCodeSerializer(data=request.data)
        if serializer.is_valid(raise_exception=True):
            try:
                username = serializer.validated_data['username']
                code = serializer.data['confirmation_code']
            except ValueError as e:
                raise e
            user = get_object_or_404(User, username=username)
            if code == user.confirmation_code:
                token = get_tokens_for_user(user)
                user.is_active = True
                user.save()
                return JsonResponse({'token': token}, status=OK_STATUS)
            return JsonResponse(
                {'Статус': 'Неверный код подтверждения'}, status=BAD_STATUS)


from controllers import RandomController
import numpy as np
from utils import sample, compute_normalization
from dynamics import NNDynamicsModel
from cheetah_env import HalfCheetahEnvNew
from cost_function import cheetah_cost_fn
import matplotlib.pyplot as plt

env = HalfCheetahEnvNew()
cost_fn = cheetah_cost_fn

random_controller = RandomController(env)
data = sample(env, random_controller, horizon=100, num_paths=1)
normalization = compute_normalization(data)

dyn_model = NNDynamicsModel(env=env,
                            batch_size=512,
                            iterations=60,
                            learning_rate=1e-3,
                            normalization=normalization
                            )
dyn_model.load_params()

s = np.concatenate([d["state"] for d in data])  # (timestep, 8)
a = np.concatenate([d["action"] for d in data])
s_ = np.concatenate([d["next_state"] for d in data])

pre_s=[]
obs = [s[0,:]]
for i in range(100):
    obs=dyn_model.predict(np.array(obs), np.array([a[i,:]]))
    pre_s.append(obs)

pre_s = np.array(pre_s).reshape(100,20)

t=np.linspace(0,100,100)

plt.plot(t, s_[:,5], linewidth=0.4, linestyle='-')
plt.plot(t, pre_s[:,5], linewidth=0.4, linestyle='--')
# plt.plot(t, pre_s, color='blue', linewidth=0.4, linestyle='.')
plt.show()


#!/usr/bin/env python3
#  coding=utf-8
__author__ = 'Guoliang Lin'
Softwarename = "junction_generator"
version = '0.0.1'
bugfixs = ''
__date__ = "2017/6/26"
import optparse
import time
from functools import reduce

GTFDict = {}
JunctionList = []

def printinformations():
    print("%s software version is %s in %s" % (Softwarename, version, __date__))
    print(bugfixs)
    print('Starts at :' + time.strftime('%Y-%m-%d %H:%M:%S'))

def programends():
    print('Ends at :' + time.strftime('%Y-%m-%d %H:%M:%S'))

class GTFfile:
    def __init__(self, listitem):
        self.GeneID = ''
        self.TranscriptID = ''
        self.ExonStart = int(listitem[3]) - 1
        self.ExonEnd = int(listitem[4]) + 1
        self.Scaffold1 = listitem[0]
        self.Fpkm = []
        self.Chain = listitem[6]
        self.Getinfo(listitem[8])

    def Getinfo(self, info):
        tmp = info.split('; ')
        self.GeneID=tmp[0].split(' ')[1].replace('"', '')
        self.TranscriptID=tmp[1].split(' ')[1].replace('"', '')
        mm=tmp[3].split(' ')[1]
        self.Fpkm=float(tmp[3].split(' ')[1].replace('"', ''))

class Junction:
    def __init__(self,listitem:list) -> None:
        """
        :param listitem:list [scaffold,pos,chain,depth]

        """
        super().__init__()
        self.GeneID=[]
        self.Scaffold=listitem[0]
        self.Pos=int(listitem[1])
        self.Chain=listitem[2]
        # self.Depth=listitem[3]
        self.Fpkm=[]
        self.TranscriptID=[]

    def AddGeneID(self,GeneID:str):   # type: (Junction, str) -> None
        if GeneID not in self.GeneID:
            self.GeneID.append(GeneID)

    def AddTranscriptID(self,TranscriptID:str):    # type: (Junction, str) -> None
        if TranscriptID not in self.TranscriptID:
            self.TranscriptID.append(TranscriptID)

    def AddFpkm(self,Fpkm:float):
        self.Fpkm.append(Fpkm)

    def ToString(self):  # type: (Junction) -> str
        String = '\t'.join([self.Scaffold, str(self.Pos), self.Chain, '@'.join(self.GeneID), str((len(self.Fpkm) and max(self.Fpkm)) or "0"),
                            str((len(self.Fpkm) and reduce(lambda x,y:x+y,self.Fpkm)) or "0")])
        return String

class JunctionCombie:
    def __init__(self, listitem):
        self.JunctionS=Junction(listitem)
        self.JunctionE=Junction(listitem[3:])

    def AddGeneID(self, m: list, GeneId):
        if GeneId not in m:
            m.append(GeneId)

    def AddTranscriptID(self, m: list, TranscriptID):
        if TranscriptID not in m:
            m.append(TranscriptID)

    def ToString(self):
        String = '\t'.join([self.JunctionS.ToString(),self.JunctionE.ToString()])
        return String

    def Iscontain(self,GTFitem: GTFfile, Junctionitem: Junction):
        if GTFitem.ExonStart <= Junctionitem.Pos <= GTFitem.ExonEnd:
            Junctionitem.AddGeneID(GTFitem.GeneID)
            Junctionitem.AddTranscriptID(GTFitem.TranscriptID)
            Junctionitem.Fpkm.append(GTFitem.Fpkm)

def _parse_args():
    """Parse the command line for options."""
    usage = 'usage: %prog -i junctionfile  -g gtffile -o OUTPREFIX'
    parser = optparse.OptionParser(usage)
    parser.add_option('-i',
                      '--input', dest='input', type='string',
                      help='input junction file ')
    #    parser.add_option('-f','--fpkm',dest='fpkm_file',type='string',help='input fpkm file')
    #    parser.add_option('-v','--variation', dest='variation', type='string', help='input variation information file')
    parser.add_option('-g', '--gtf', dest='gtf', help='gtf file')
    parser.add_option('-o', '--output', dest='output', type='string', help='input variation information file')
    parser.add_option('-d', '--depth', dest='depth', type='int', default=5, help='depth')
    options, args = parser.parse_args()
    # positional arguments are ignored
    return options

if __name__ == '__main__':
    options = _parse_args()
    with open(options.gtf) as gtffile:
        with open(options.input) as junctionfile:
            with open(options.output, 'w') as outputfile:
                for item in gtffile:
                    item = item.strip()
                    itemlist = item.split('\t')
                    assert isinstance(itemlist, list)
                    if itemlist[2] == 'exon':
                        tmpgtf = GTFfile(itemlist)
                        if tmpgtf.Scaffold1 in GTFDict:
                            GTFDict[tmpgtf.Scaffold1][tmpgtf.Chain].append(tmpgtf)
                        else:
                            GTFDict[tmpgtf.Scaffold1] = {}
                            GTFDict[tmpgtf.Scaffold1]['-'] = []
                            GTFDict[tmpgtf.Scaffold1]['+'] = []
                            GTFDict[tmpgtf.Scaffold1]['.'] = []
                            GTFDict[tmpgtf.Scaffold1][tmpgtf.Chain].append(tmpgtf)
                for key in GTFDict.keys():
                    GTFDict[key]['+'].sort(key=lambda x: (x.ExonStart, x.ExonEnd))
                    GTFDict[key]['-'].sort(key=lambda x: (x.ExonStart, x.ExonEnd))
                for item in junctionfile:
                    itemlist = item.split('\t')
                    junctionlist=[itemlist[0],itemlist[1],itemlist[3],itemlist[0],itemlist[2],itemlist[3]]
                    tmpjunction = JunctionCombie(junctionlist)
                    for Gtfitem in GTFDict[tmpjunction.JunctionS.Scaffold][tmpjunction.JunctionS.Chain]:
                        tmpjunction.Iscontain(Gtfitem, tmpjunction.JunctionS)
                    for Gtfitem in GTFDict[tmpjunction.JunctionE.Scaffold][tmpjunction.JunctionE.Chain]:
                        tmpjunction.Iscontain(Gtfitem, tmpjunction.JunctionE)
                    string = tmpjunction.ToString()
                    outputfile.write(string + '\n')


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

# # Initial Data Exploration
# $$$$
# The purpose of our initial data exploration is to:
#

#
Check the validity of the data and perform data cleaning methods if needed.

#
View the statistical details of the data

#
Perform data visualization to improve our understanding of the data

#
Feature engineer

#
Sort out the imbalanced dataset

#
Perform transformations (standardization, PCA)

#

#
#
# ## Importing required libraries
# Data processing

# In[1]:

import pandas as pd
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
import numpy as np
import copy
import random
import pickle
import json

# Data Visualization

# In[2]:

import matplotlib.pyplot as plt
import seaborn as sns
import matplotlib.patches as mpatches
import plotly.graph_objects as go
import squarify
plt.style.use('ggplot')

# Code Styling

# In[3]:

from typing import List, Dict

# Read in dataframe and bried inspection of the data.

# In[4]:

heart_disease: pd.DataFrame = pd.read_csv("data/heart_2020_cleaned.csv")

# ## Data Cleaning
#
# Check for missing values

# In[5]:

print(f'Does the heart disease dataset contain any null values? {heart_disease.isnull().any().any()}')

# Next, we calculate the basic statistics of each data set. This is a trivial step, and it is designed to increase understanding of the computational problem.

# In[6]:

print("Unique values in the heart disease dataset, stratified by column:", sep='')
print("-----------------------------------------------------------------\n")
for col in heart_disease.columns:
    if heart_disease[col].nunique() < 20:
        if heart_disease[col].nunique() < 3:
            heart_disease[col].value_counts(normalize=True).plot(kind='barh', title=f"Unique values of {col} column", )
            plt.show()

# From this we note the this dataset is imbalanced .i.e, data set with skewed class proportions. This is a common problem in classification problems. We will address this issue later in the notebook.

# In[7]:

heart_disease.describe()

# In[8]:

sns.pairplot(heart_disease[
    ["HeartDisease", "BMI", "PhysicalHealth", "MentalHealth", "SleepTime"]
    ], hue="HeartDisease", plot_kws=dict(s=80, edgecolor="white", linewidth=2.5))
plt.show()

# Surprisingly, the distribution of BMI, mental health and sleep time don't seem to be significantly different when comparing with people who **do or do not** have heart disease. However, the mental health do seem to have a strong correlation with heart disease.

# # Data Visualization
#
# To familiarize ourself with the data, we generate plots that seek to illuminate some research questions.
#
# 1. Are people from certain backgrounds more likely to have heart disease, given their ethnicity?
# 2. Is the percentage of females and males with heart disease similar?
# 3. Do peoples *reported* physical activity correlate with their physical health?
# 4. Which risk factors are most correlated with heart disease?
# 5. What is the flow of patients from  their age to substance misuse to if they have an aliment listed in the dataset to  their likelihood of contracting heart disease?

# In[9]:

def create_stacked_bar_hart(heart_disease: pd.DataFrame) -> plt.figure:
    """
    Args:
        heart_disease (pd.DataFrame): the original heart disease kaggle dataset

    Returns:
        plt.figure: a stacked bar chart of the percentage of people
            with heart disease and without heart disease, stratified by race
    """

    # top bar -> sum all values(HeartDisease=No and HeartDisease=Yes) to find y position of the bars
    total: pd.DataFrame = heart_disease.groupby('Race').count().reset_index()

    # bar chart 1 -> top bars (group of 'HeartDisease=No')
    bar1: sns.barplot = sns.barplot(x="Race",  y="HeartDisease", data=total, color='red')

    # bottom bar ->  take only HeartDisease=Yes values from the data
    HeartDisease: pd.DataFrame = heart_disease[heart_disease.HeartDisease=='Yes'].groupby('Race').count().reset_index()

    # bar chart 2 -> bottom bars (group of 'HeartDisease=Yes')
    bar2: sns.barplot = sns.barplot(x="Race", y="HeartDisease", data=HeartDisease, errorbar=None,  color='green')

    # add legend
    top_bar: mpatches.Patch = mpatches.Patch(color='red', label='HeartDisease = No')
    bottom_bar: mpatches.Patch = mpatches.Patch(color='green', label='HeartDisease = Yes')
    plt.legend(handles=[top_bar, bottom_bar])
    plt.ylabel('Number of Patients')
    plt.xticks(rotation=45,ha='right')
    # show the graph
    plt.show()

# In[10]:

def create_tree_diagram(heart_disease:pd.DataFrame) -> squarify.plot:
    """
    Args:
        heart_disease (pd.DataFrame): the original heart disease kaggle dataset

    Returns:
        squarify.plot: A tree diagram displaying the number of males and females
            that do and don't have heart disease
    """
    heart_disease = heart_disease.copy()
    tree_diagram_df: pd.DataFrame = heart_disease.groupby(['Sex', 'HeartDisease']).count().reset_index()[['Sex','HeartDisease','BMI']]
    tree_diagram_df['Gender_choice'] = tree_diagram_df[['Sex', 'HeartDisease']].agg(', '.join, axis=1)
    tree_diagram_df.rename(columns={'BMI': 'count'}, inplace=True)
    squarify.plot(sizes=tree_diagram_df['count'], label=tree_diagram_df['Gender_choice'], alpha=.4)
    plt.axis('off')
    plt.show()

def create_histplot(heart_disease:pd.DataFrame) -> plt.figure:
    """
    Args:
        heart_disease (pd.DataFrame): the original heart disease kaggle dataset

    Returns:
        plt.figure: Two histograms displaying the number of days in the past 30 days
                    in which patients were physically active.
                    Stratified by people's reported physical health
    """
    heart_disease = heart_disease.copy()
    sns.set(style="darkgrid")
    heart_disease = heart_disease[heart_disease.PhysicalHealth > 0]
    # plotting both distibutions on the same figure
    sns.histplot(heart_disease[heart_disease.PhysicalActivity == 'Yes']['PhysicalHealth'], color="skyblue", label="People who report doing physical activity")
    sns.histplot(heart_disease[heart_disease.PhysicalActivity == 'No']['PhysicalHealth'], color="red", label="People who do not physical activity")
    plt.legend()
    plt.xlabel("People who report that their physical health (physical illness and injury) was not good? (0-30 days).")
    plt.show()

# In[11]:

def create_corr_plot(heart_disease: pd.DataFrame):
    """
    Args:
        heart_disease (pd.DataFrame): the original heart disease kaggle dataset

    Returns:
        squarify.plot: A bar chart displaying the correlation of risk factors vs  heart disease
    """
    heart_disease = heart_disease.copy()
    binary_vars: List[str] = ["HeartDisease",
                        "Smoking",
                        "AlcoholDrinking",
                        "Stroke",
                        "DiffWalking",
                        "Diabetic",
                        "PhysicalActivity",
                        "Asthma",
                        "KidneyDisease",
                        "SkinCancer"]
    for binary_var in binary_vars:
        heart_disease[binary_var] = heart_disease[binary_var].replace({"Yes": 1, "No": 0})
    heart_disease.Diabetic = heart_disease.Diabetic.replace({'No, borderline diabetes': 1, 'Yes (during pregnancy)' : 1}).astype(int)
    heart_disease.corr()[['HeartDisease']].plot.bar(legend=False)
    plt.title("Correlations of HeartDisease variable vs risk factors")

# In[12]:

def create_sankey_chart(sankey_data:pd.DataFrame) -> go.Figure:
  """
  Args:
      heart_disease (pd.DataFrame): contains three columns; source target value.
                                    Indicates the amount of patients moving through each stage of the sankey chart

  Returns:
      go.Figure: A sankey chart indicating the flow of patients in the following pattern:
                    Age -> Substance Abuse -> Alinement -> Heart Disease outcome

  """
  sankey_data = sankey_data.copy()
  # Get unique values for both source and target columns
  unique_source_target_values  = list(pd.unique(sankey_data[['source', 'target']].values.ravel('K')))

  source_target_mapping = {k:v for v,k in enumerate(unique_source_target_values)}
  with open("data/color_sankey_dict.json") as f:
      colour_dict= json.loads(f.read())
  links = sankey_data[['source', 'target', 'value']].copy()

  links["source"] = links["source"].map(source_target_mapping)
  links["target"] = links["target"].map(source_target_mapping)
  links_dict = links.to_dict(orient="list")

  with open('data/link_colours.pkl', 'rb') as f:
      link_colours = pickle.load(f)

  fig = go.Figure(data = [go.Sankey(
      valueformat = ".0f",
      valuesuffix = "TWh",
      # Define nodes
      node = dict(
        pad = 15,
        thickness = 15,
        line = dict(color = "black", width = 0.2),
        label =  unique_source_target_values,
        color =  list(colour_dict.values())
      ),
      link = dict(
        source = links_dict["source"],
        target = links_dict["target"],
        value = links_dict["value"],
        color= link_colours,
      )

      )]
  )
  fig.update_layout(title_text="Patient Flow
 Age -> Substance Abuse -> Alinement -> Heart Disease outcome",
                    font_size=10)
  fig.show()

# In[13]:

create_stacked_bar_hart(heart_disease)

# White people appear to both appear most often in this dataset and have the highest prevalence of heart disease in the their sub-population. The race with the second most heart disease prevalance is heart disease.

# In[14]:

create_tree_diagram(heart_disease)

# It is evident that relataive rate of heart disease is higher in men than in women.

# In[15]:

create_histplot(heart_disease)

# Surprisingly, it seems that peoples reported physical health does not necessarily align with their physical activity levels.

# In[16]:

sankey_data: pd.DataFrame = pd.read_csv('data/full_sankey_data.csv')
create_sankey_chart(sankey_data)

# ## Feature Engineering
#
# A lot of our features contain categorical data. We will need to convert these to numerical values. Feature extraction projects the original high-dimensional features to a new feature space with low dimensionality, while feature selection directly selects a subset of relevant features. Both feature extraction
# and feature selection can improve learning performance, increase computational efficiency, decrease memory storage, and build better
# generalization models. However, as feature extraction creates a set of new features, further analysis is problematic as we cannot retain the
# physical meanings of these features. In contrast, by keeping some of the original features, feature selection maintains the physical
# meanings of the original features and gives models better readability and interpretability.
#
# The columns broadly fall into three categories:
#
#     - Binary Categorical variables
#       -  HeartDisease
#       -  Smoking
#       -  AlcoholDrinking
#       -  Stroke
#       -  DiffWalking
#       -  Diabet
#       -  Physical Activity
#       -  Asthma
#       -  Kidney Disease
#       -  Skin Cancer
#       -  Sex
#     - Continuous variables
#       - BMI
#     - Discrete variables
#       - Sleeptime
#       - PhsycialHealth
#       - MentalHealth
#     - Polytomous variables; these are variables with more than two categories
#       - AgeCategory
#       - Race
#       - GenHealth

# Binary variables with yes or no values are converted to 1 and 0 respectively. The diabetes column currently has four categories: 'Yes', 'No', 'No, borderline diabetes', 'Yes (during pregnancy)'. Our earlier analysis revealed that  the presence of heart dieasease and diabetes are weakly correlated. Therefore, we will combine the 'Yes (during pregnancy)' and 'No, borderline diabetes' categories into the 'Yes' category.
#

# In[17]:

heart_disease['Diabetic'].unique()

# In[18]:

binary_vars: List[str] = ["HeartDisease",
                        "Smoking",
                        "AlcoholDrinking",
                        "Stroke",
                        "DiffWalking",
                        "Diabetic",
                        "PhysicalActivity",
                        "Asthma",
                        "KidneyDisease",
                        "SkinCancer"]

# In[19]:

for binary_var in binary_vars:
    heart_disease[binary_var] = heart_disease[binary_var].replace({"Yes": 1, "No": 0})
heart_disease.Diabetic: pd.Series = heart_disease.Diabetic.replace({'No, borderline diabetes': 1, 'Yes (during pregnancy)' : 1}).astype(int)

# In[20]:

# One-hot encoding
sex_one_hot = pd.get_dummies(heart_disease['Sex'])
heart_disease = heart_disease.join(sex_one_hot)
heart_disease.drop(columns=['Sex'], inplace=True)

# In the dataset, ordinal attributes are present. There is a natural ordering to the categories (i.e. GenHealth, AgeCategory). Thus, we use the `replace()` function to label encode them.

# In[21]:

heart_disease["AgeCategory"].replace({
    '18-24':1,
    '25-29':2,
    '30-34':3,
    '35-39':4,
    '40-44':5,
    '45-49':6,
    '50-54':7,
    '55-59':8,
    '60-64':9,
    '65-69':10,
    '70-74':11,
    '75-79':12,
    '80 or older':13
}, inplace=True)

# In[22]:

heart_disease["GenHealth"].replace({
    'Poor': 1,
    'Fair':2,
    'Good':3,
    'Very good':4,
    'Excellent':5},
    inplace=True)

# Race has no order. Therefore, we decide to take two approaches.
#
# - One-hot-encoding:Increase the dimensions to facilite a better feature selection space step later which produces a final lower dimension feature vector (i.e. every race is a binary feature)
# - Frequency encoding:  Frequency Encoding is an encoding technique that encodes categorical feature values to their respected frequencies. This will preserve the information about the values of distributions. We normalize the frequencies that result in getting the sum of unique values as 1. This is done to avoid the curse of dimensionality and reduce the sparsity in the dataset.
#
# We will evaluate both approaches in our model evaluation.

# In[23]:

# One-hot encoding
race_one_hot: pd.DataFrame = pd.get_dummies(heart_disease['Race'])
heart_disease: pd.DataFrame = heart_disease.join(race_one_hot)

# Frequency encoding using value_counts function
race_freq: pd.Series = heart_disease['Race'].value_counts(normalize=True)

# Mapping the encoded values with original data
heart_disease['Race_freq']: pd.Series = heart_disease['Race'].apply(lambda x : race_freq[x])
heart_disease.drop(columns=['Race'], inplace=True)

# Outliers are extreme values. Outliers can skew the distribution but these are exceptional but genuine data points.  Such distributions can impact certain algorithms such as regression type models (Lasso), k Nearest neighbors and Naive Bayes. However, decision trees and its ensemble (random forest) are not impacted.

# In[24]:

heart_disease.hist(column=["BMI",
     "SleepTime",
     "PhysicalHealth",
     "MentalHealth",
     "AgeCategory",
     "Race_freq",
     "GenHealth"], layout=(4,2))
plt.tight_layout()

# In[25]:

green_diamond: Dict[str, str] = dict(markerfacecolor='g', marker='D')
fig1, ax1 = plt.subplots()
ax1.set_title('Changed Outlier Symbols')
ax1.boxplot(heart_disease["BMI"], flierprops=green_diamond)

# We note that many outliers exist in the BMI column. To rectify this, we take two approaches
#
# - **Turn it into a ordinal variable**: The WHO uses BMI as a convenient rule of thumb used to broadly categorize a person as underweight, normal weight, overweight, or obese based on tissue mass (muscle, fat, and bone) and height. Major adult BMI classifications are underweight (under 18.5 kg/m2), normal weight (18.5 to 24.9), overweight (25 to 29.9), and obese (30 or more). We will encode these describe caegories into ordinal values.
# - **Take log(x) of the BMI column**: Taking the log of a feature is a common trick to reduce the effect of outliers. This is because the log function is monotonically increasing. Therefore, the effect of outliers is reduced.
# Again, both aproaches will be evaluated in our model evaluation.

# In[26]:

bins: List[int] = [0, 18.5, 24.9, 29.9, np.inf]
names: List[int] = [1, 2, 3, 4]
heart_disease['BMI_Bin']: pd.Series = pd.cut(heart_disease['BMI'], bins, labels=names)

# In[27]:

heart_disease["LOG_BMI"]: pd.Series = np.log(heart_disease["BMI"])
heart_disease["LOG_BMI"].hist()

# ### PCA
#
# Standardization is typically used for features of incomparable units. E.g. someone reporting the number of times they were physical active in the last thirty days and BMI. Standardisation will be applied to all features (both orginal and engineered) except the binary variables. We will also standardize the features due to k-means “isotropic” nature. In this case, if we left our variances unequal; we would inversely be putting more weight on features with high variance. In addition, we will perform principal component analysis due to avoid the curse of dimensionality that k-means can suffer from. The function of PCA is to reduce the dimensionality of a data set consisting of many variables correlated with each other, either heavily or lightly, while retaining the variation present in the data set to the maximum extent.
#
# The same is done by transforming the variables (i.e. features) to a new set of variables, which are known as the principal components, ordered such that the retention of variation present decreases as we move down the order of components.
#
# In addition, we will perform principal component analysis due to avoid the curse of dimensionality that some algorithims can suffer from. Initally, PCA is only perfoormed on the *features present within the orginal dataset*. Later on,  we will perform A feature extraction method u by applying different subsets  of training  data to estimate the accuracy of these subsets for all used
# classifiers and measure the quality of the generated subsets  per classification algorithm, and the results of the classifier are shown. We plan to use PCA again for those best performing subets to see if any improvement is made.
#
#
# The function of PCA is to reduce the dimensionality of a data set consisting of many variables correlated with each other,
# either heavily or lightly, while retaining the variation present in the data set to the maximum extent.
#
# The same is done by transforming the variables (i.e. features) to a new set of variables, which are known as the principal components, ordered such that the retention of variation present decreases as we move down the order of components.
#

# The procedure of PCA involves five steps:

# 1) Standardize the data

# 2) Compute covariance matrix

# 3) Identify the eigenvalues and eigenvectors of the covariance matrix and order them according to the eigenvalues

# 4) Compute a feature vector

# 5) Recast the data

#

# #### Standardisation

# We now standardize the data using the following formulae:
#
# $$
# X_i = X_i - \bar{X}~~~~~~~~~~~~~~~~~~X_i = \frac{X_i}{\sigma}
# $$
#
# The standard deviation should equal 1 after standardization

# In[28]:

heart_disease[
    ['PhysicalHealth', 'MentalHealth', 'AgeCategory', 'GenHealth','SleepTime', 'BMI_Bin']
    ] = StandardScaler().fit_transform(heart_disease[['PhysicalHealth', 'MentalHealth', 'AgeCategory', 'GenHealth','SleepTime', 'BMI_Bin']])

# In[29]:

heart_disease.to_csv('data/standardised_heart_disease.csv', index=False)

# We will use the `PCA` function supplied by the `Scikit-learn` library for dimensionality reduction.  But how do we find the optimal number of components? Which eigenvalues are important?  The scree plot below describes the cumulative explained variance for each component. We reach 80% explained variance at the three component mark.

# In[30]:

orginal_features_df: List[str] = heart_disease[[ 'Smoking', 'AlcoholDrinking', 'Stroke',
       'PhysicalHealth', 'MentalHealth', 'DiffWalking', 'AgeCategory', 'PhysicalActivity', 'GenHealth', 'SleepTime', 'Asthma',
       'KidneyDisease', 'SkinCancer', 'Female', 'Male',
       'American Indian/Alaskan Native', 'Asian', 'Black', 'Hispanic', 'Other',
       'White']]

# In[31]:

pca = PCA().fit(orginal_features_df)
plt.plot(np.cumsum(pca.explained_variance_ratio_))
plt.xlabel('number of components')
plt.ylabel('cumulative explained variance')
plt.title('Scree plot')
plt.show()

# We note a slight indent at the the 5th principal compent mark. According to the average-eigenvalue test (Kaiser-Guttman test) we should retain only those eigenvalues that are above the average which is 1.0.

# Jolliffe relaxes this criterium and suggest to retain eigenvalues greater than 0.7.
#

# In[32]:

kasier_criterion: np.int64 = np.where(pca.explained_variance_ > 1)[-1][-1]
print(
        f'Kasier criterion optimal component number: {kasier_criterion}, explained variance: {np.cumsum(pca.explained_variance_ratio_)[kasier_criterion]}'
    )
jolliffe_criterion: np.int64  = np.where(pca.explained_variance_ > 0.7)[-1][-1]
print(
    f'Jolliffe criterion optimal component number: {jolliffe_criterion} , explained variance: {np.cumsum(pca.explained_variance_ratio_)[jolliffe_criterion]}'
    )

#  For the purpose of this investigation, we decide to go with **both** the Jolaliffe criterion, we will retain the first two  components.

# Finally, we fit the `pca` model with the dataframes containing top 2 components , apply the dimensionality reduction on those respective dataframe and save the resulting dataframes.

# In[33]:

pca_2d = PCA(n_components=2)
dim_reduced_2d: pd.DataFrame = pca_2d.fit_transform(orginal_features_df)
dim_reduced_2d = pd.DataFrame(data=dim_reduced_2d, columns=[f'component_{num}' for num in range(1,3)])
dim_reduced_2d = pd.merge(
        heart_disease[['HeartDisease']], dim_reduced_2d, left_index=True, right_index=True
        )
dim_reduced_2d.to_csv("data/dim_reduced_2d.csv", index=False)

# **Note**, later on we will use PCA to identify the variables that contribute most to the variation in the dataset.


# 1966. 프린터 큐

from sys import stdin
from collections import deque

input = stdin.readline
T = int(input())

for _ in range(T):
    N, M = map(int, input().split())
    ranks = list(map(int, input().split()))
    arr = deque((num, i) for i, num in enumerate(ranks))
    ranks.sort(reverse=True)

    sol = 0
    for rank in ranks:
        while rank != arr[0][0]:
            arr.append(arr.popleft())
        sol += 1

        if arr[0][1] == M: break
        arr.popleft()

    print(sol)


from sklearn.cluster import KMeans
import numpy as np
import matplotlib.pyplot as plt
import cv2
import pandas as pd
import glob
import os
from skimage import morphology

square = np.ones((3,3))

def prepare_image(img):
  '''
  This function extracts, from an image of size (n,p), the 3 channels RGB and concatenate them as features in a new matrix of size (n*p , 3)
  '''
  # la transformer en grayscale
  gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
  rouge = img[:,:,0]
  vert = img[:,:,1]
  bleu = img[:,:,2]

  # For Kmeans Segmentation
  n,p = gray.shape
  size = n * p
  R = rouge.flatten()
  G = vert.flatten()
  B= bleu.flatten()

  R = np.reshape(R, (size,1))
  G = np.reshape(G, (size,1))
  B = np.reshape(B, (size,1))

  image = np.concatenate((R,G,B), axis=1)
  return image

def segment_image(img, colors):
  '''This function segment the original image based on a set of colors (legend)'''

  kmeans = KMeans(n_clusters=7, n_init=10, random_state=1)
  train = prepare_image(colors)
  test = prepare_image(img)

  # Here we train the KMeans model using the set of colors (legend)
  model = kmeans.fit(train)
  labels_test = model.predict(test)

  # Here we restore the original shape of the segmented images (both the legend and the original image)
  segmented_test = np.reshape(labels_test, img.shape[:2])
  segmented_train = np.reshape(model.labels_, colors.shape[:2])

  # Here we fix the colors displayed in the legend to have a correct mapping between the colors of clusters returned by KMeans and the colors of the original image
  blue_c = segmented_train[100,0]
  light_blue_c = segmented_train[200,0]
  green_c = segmented_train[400,0]
  yellow_c = segmented_train[600,0]
  red_c = segmented_train[800,0]
  background_c = segmented_train[0,200]
  black_c = segmented_train[900,100]

  # Here, we seperate the clusters (colors) from the segmented image. Each sub-image contains a certain color.
  all_parcel = morphology.binary_opening(((segmented_test == background_c) | (segmented_test == black_c)) ==0)
  green = segmented_test == green_c
  red = segmented_test == red_c
  light_blue = segmented_test == light_blue_c
  yellow = segmented_test == yellow_c
  blue = segmented_test == blue_c
  black = segmented_test == black_c

  # return all the sub-images as a list
  return [all_parcel, green, blue, light_blue, red, yellow, black]

def calcul_surface(images):
  '''
  This function calculates the surface using the list of sub-images
  '''
  black = np.sum(images[6])
  scale = 625 / black

  surfaces = []
  for img in images :
    surfaces.append(np.sum(img)*scale* 0.0001)

  return surfaces

def calcul_percentage(images):
  '''
  This function calculates the percentages of each color considering the total surface of the farm
  '''
  percentages = []
  surfaces = calcul_surface(images)
  S_all_parcel = surfaces[0]

  for img in surfaces[1:6]:
    percentages.append(np.round((img) / S_all_parcel , 3))
  return percentages

colors = cv2.imread('colors.png')
colors = cv2.cvtColor(colors, cv2.COLOR_BGR2RGB)

# Automate the process for all the images, save the data in an Excel file and return it to the user
for map in glob.glob('/content/*.png'):
  base = os.path.basename(map)
  name = os.path.splitext(base)[0]
  if name != 'colors' :
    img2 = cv2.imread(name +'.png')
    img2 = cv2.cvtColor(img2, cv2.COLOR_BGR2RGB)

    images = segment_image(img2, colors)
    percentages = calcul_percentage(images)
    surfaces = calcul_surface(images)
    areas = pd.DataFrame([percentages, surfaces[1:6]], columns=['Green', 'Blue', 'Light blue', 'Red', 'Yellow'], index = ['Percentage of area', 'Surfaces (Ha)'])
    areas.to_excel(name+ ".xls")


def is_spam(message):
    import re

    # Check for spam keywords and suspicious percentage signs
    keywords = ['VIP', '비공개', '추천', '돌파', '타점']
    keywords_found = any(keyword in message for keyword in keywords)

    percentage_sign_found = '%' in message

    # Check for URLs
    url_pattern = re.compile(r'(https?://\S+)')
    url_found = bool(re.search(url_pattern, message))

    # Check for message length
    long_message = len(message.split()) > 6

    if keywords_found or percentage_sign_found or url_found or long_message:
        return True
    else:
        return False


"""Module implementing some base classes useful for implementing dynamical
systems"""

from __future__ import division, print_function, absolute_import
import six
range = six.moves.range
map   = six.moves.map

import numpy as np

from . import mx
from . import caching
from .mx import hashable_state
from .utils import readonlydict

# Constants for finding attractors
MAX_ATTRACTOR_LENGTH = 5
TRANSIENT_LENGTH = 30

class DynamicalSystem(object):
    """Base class for dynamical systems.

    Parameters
    ----------
    discrete_time : bool, optional
        Whether updating should be done using discrete (default) or continuous
        time dynamics.
    """

    #: Whether the dynamical system obeys discrete- or continuous-time dynamics
    discrete_time = True

    def __init__(self, discrete_time=True):
        self.discrete_time = discrete_time

        if self.discrete_time:
            self.iterate = self._iterate_discrete
            self.iterate_1step = self._iterate_1step_discrete
        else:
            self.iterate = self._iterate_continuous

    def iterate(self, start_state, max_time):
        """This method runs the dynamical system for `max_time` starting from
        `start_state` and returns the result.  In fact, this method is set at
        run-time by the constructor to either `_iterateDiscrete` or
        `_iterateContinuous` depending on whether the dynamical system object
        is initialized with `discrete_time=True` or `discrete_time=False`. Thus,
        sub-classes should override `_iterateDiscrete` and `_iterateContinuous`
        instead of this method.  See also
        :meth:`dynpy.dynsys.DynamicalSystem.iterateOneStep`

        Parameters
        ----------
        start_state : numpy array or scipy.sparse matrix
            Which state to start from
        max_time : float
            Until which point to run the dynamical system (number of iterations
            for discrete-time systems or time limit for continuous-time systems)

        Returns
        -------
        numpy array or scipy.sparse matrix
            End state
        """
        raise NotImplementedError

    def iterate_1step(self, start_state):
        """
        This method runs a discrete-time dynamical system for 1 timestep. At
        run-time, the construct either repoints this method to `_iterateOneStep`
        for discrete-time systems, or removes it for continuous time systems.

        Parameters
        ----------
        start_state : numpy array or scipy.sparse matrix
            Which state to start from

        Returns
        -------
        numpy array or scipy.sparse matrix
            Iterated state
        """
        raise NotImplementedError

    def _iterate_1step_discrete(self, start_state):
        raise NotImplementedError

    def _iterate_continuous(self, start_state, max_time=1.0):
        raise NotImplementedError

    def _iterate_discrete(self, start_state, max_time=1.0):
        if max_time == 1.0:
            return self.iterate_1step(start_state)
        elif max_time == 0.0:
            return start_state
        else:
            cur_state = start_state
            for i in range(int(max_time)):
                cur_state = self.iterate_1step(cur_state)
            return cur_state

    def get_trajectory(self, start_state, max_time, num_points=None,
                      logscale=False):
        """This method get a trajectory of a dynamical system starting from
        a particular starting state.

        Parameters
        ----------
        start_state : object
            Which state to start from
        max_time : float
            Until which point to run the dynamical system (number of iterations
            for discrete-time systems or time limit for continuous-time systems)
        num_points : int, optional
            How many timepoints to sample the trajectory at.  This determines
            how big each 'step size' is. By default, equal to ``int(max_time)``
        logscale : bool, optional
            Whether to sample the timepoints on a logscale or not (default)

        Returns
        -------
        trajectory: numpy array
            Array of states corresponding to trajectory

        """
        # TODO: would this accumulate error for continuous case?
        if num_points is None:
            num_points = int(max_time)

        if logscale:
            timepoints = np.logspace(0, np.log10(max_time), num=num_points,
                                     endpoint=True, base=10.0)
        else:
            timepoints = np.linspace(0, max_time, num=num_points, endpoint=True)

        cur_state = start_state
        trajectory = [cur_state,]
        start_state_cls = mx.get_state_cls(start_state)

        for t in range(1, len(timepoints)):
            run_time = timepoints[t]-timepoints[t-1]
            next_state = self.iterate(cur_state, max_time=run_time)
            cur_state = start_state_cls.format_obj(next_state)
            trajectory.append( cur_state )

        return start_state_cls.vstack(trajectory)

class DeterministicDynamicalSystem(DynamicalSystem):
    pass

class StochasticDynamicalSystem(DynamicalSystem):
    pass

class DiscreteStateDynamicalSystem(DynamicalSystem):

    def states(self):
        raise NotImplementedError

    def get_attractor_basins(self, sort=False, start_state_iter=None):
        """Computes the attractors and basins of the current discrete-state
        dynamical system.

        Parameters
        ----------
        sort : bool, optional
            Whether to sort attractors and basin states (slower).
        start_state_iter : iterator, optional
            Iterator to indicate which start-states to start from.  If not
            specified, tries all states.

        Returns
        -------
        basin_atts : list of lists
            A list of the the attractor states for each basin (basin order is
            from largest basin to smallest).
        basin_states : list of lists
            A list of all the states in each basin (basin order is from largest
            basin to smallest).

        """

        state_basins = {}
        attractors   = {}

        iteratefunc = self.iterate

        if start_state_iter is None:
            start_state_iter = self.states()

        for raw_startstate in start_state_iter:
            startstate = hashable_state(raw_startstate)
            if startstate in state_basins:
                continue

            traj = set()
            cstate = startstate
            while True:
                traj.add(cstate)
                cstate = hashable_state(iteratefunc(cstate))

                if cstate in traj:  # cycle closed
                    cur_cycle = []
                    cyclestate = cstate
                    while True:
                        cur_cycle.append(cyclestate)
                        cyclestate = hashable_state(iteratefunc(cyclestate))
                        if cyclestate == cstate:
                            break
                    cur_cycle = tuple(sorted(cur_cycle))

                    if cur_cycle not in attractors:
                        cndx = len(attractors)
                        attractors[cur_cycle] = cndx
                    state_basins[cstate] = attractors[cur_cycle]

                if cstate in state_basins:
                    for s in traj:
                        state_basins[s] = state_basins[cstate]
                    break

        basins = [ [] for _ in range(len(attractors))]
        for state, basin in six.iteritems(state_basins):
            basins[basin].append(state)

        keyfunc = lambda k: (-len(basins[attractors[k]]),k)

        attractor_states = attractors.keys()

        if sort:
            attractor_states = sorted(attractor_states, key=keyfunc)

        basins_states = []
        for att in attractor_states:
            cbasin = basins[attractors[att]]
            if sort:
                cbasin = sorted(cbasin)
            basins_states.append(cbasin)

        return attractor_states, basins_states

    def print_attractor_basins(self):
        """Prints the attractors and basin of the dynamical system

        >>> import dynpy
        >>> rules = [ ['a',['a','b'],[1,1,1,0]],['b',['a','b'],[1,0,0,0]]]
        >>> bn = dynpy.bn.BooleanNetwork(rules=rules)
        >>> bn.print_attractor_basins()
        * BASIN 1 : 2 States
        ATTRACTORS:
              a      b
              1      0
        --------------------------------------------------------------------------------
        * BASIN 2 : 1 States
        ATTRACTORS:
              a      b
              0      0
        --------------------------------------------------------------------------------
        * BASIN 3 : 1 States
        ATTRACTORS:
              a      b
              1      1
        --------------------------------------------------------------------------------

        """
        basin_atts, basin_states = self.get_attractor_basins(sort=True)
        for cur_basin_ndx in range(len(basin_atts)):
            print("* BASIN %d : %d States" %
                (cur_basin_ndx+1, len(basin_states[cur_basin_ndx])))
            print("ATTRACTORS:")
            print(self._get_state_row_title())
            for att in basin_atts[cur_basin_ndx]:
                print(self._get_state_row_repr(att))
            print("".join(['-', ] * 80))

    def _get_state_row_repr(self, state):
        return state

    def _get_state_row_title(self):
        return 'State'

class VectorDynamicalSystem(DynamicalSystem):
    """Mix-in for classes implementing dynamics over multivariate systems.

    Parameters
    ----------
    num_vars : int, optional
        How many variables (i.e., how many 'dimensions' or 'nodes' are in the
        dynamical system). Default is 1
    var_names : list, optional
        Names for the variables (optional).  Default is simply the numeric
        indexes of the variables.
    discrete_time : bool, optional
        Whether dynamical system is discrete or continuous time.
    """

    #: The number of variables in the dynamical system
    num_vars = None

    def __init__(self, num_vars, var_names=None, discrete_time=True):
        super(VectorDynamicalSystem,self).__init__(discrete_time)

        self.num_vars = num_vars
        self.var_names = tuple(var_names if var_names is not None
                               else range(self.num_vars))
        """The names of the variables in the dynamical system"""

    # Make this a cached property so its not necessarily run every time a
    # dynamical systems object is created, whether we need it or not
    @caching.cached_data_prop
    def var_name_ndxs(self):
        """A mapping from variables names to their indexes
        """
        return dict((l, ndx) for ndx, l in enumerate(self.var_names))

    def _get_state_row_repr(self, state):
        row_format = "{:>7}" * self.num_vars
        return row_format.format(*state)

    def _get_state_row_title(self):
        row_format = "{:>7}" * self.num_vars
        return row_format.format(*self.var_names)

class DiscreteStateVectorDynamicalSystem(VectorDynamicalSystem,
    DiscreteStateDynamicalSystem):

    @caching.cached_data_method
    def get_ndx2state_mx(self):
        #: ``(num_states, num_vars)``-shaped matrix that maps from state indexes
        #: to representations in terms of activations of the variables.
        return np.vstack(self.states())

    @caching.cached_data_method
    def get_ndx2state_map(self):
        return readonlydict( enumerate(self.states()) )

    @caching.cached_data_method
    def get_state2ndx_map(self):
        return readonlydict(
            { hashable_state(v):k
              for k, v in six.iteritems(self.get_ndx2state_map()) })

class ProjectedStateSpace(DiscreteStateVectorDynamicalSystem):
    # TODO: Document
    def __init__(self, keep_vars, base_sys, *kargs, **kwargs):
        self.keep_vars = keep_vars
        self.base_sys = base_sys

        var_names = None
        if base_sys.var_names is not None:
            var_names = [base_sys.var_names[i] for i in keep_vars]

        super(ProjectedStateSpace, self).__init__(
            num_vars=len(keep_vars),
            var_names=var_names,
            *kargs, **kwargs)

    def states(self):
        done = set()
        n2smx = self.base_sys.get_ndx2state_mx()
        for c in map(hashable_state, n2smx[:,self.keep_vars]):
            if c not in done:
                done.add(c)
                yield c

class LinearDynamicalSystem(VectorDynamicalSystem):
    # TODO: TESTS
    """This class implements linear dynamical systems, whether continuous or
    discrete-time.  It is also used by :class:`dynpy.dynsys.MarkovChain` to
    implement Markov Chain (discrete-case) or  master equation (continuous-case)
    dynamics.

    For attribute definitions, see documentation of
    :class:`dynpy.dynsys.DynamicalSystem`.

    Parameters
    ----------
    transition_matrix : numpy array or scipy.sparse matrix
        Matrix defining the evolution of the dynamical system, i.e. the
        :math:`\\mathbf{A}` in
        :math:`\\mathbf{x_{t+1}} = \\mathbf{x_{t}}\\mathbf{A}` (in the
        discrete-time case) or
        :math:`\\dot{\\mathbf{x}} = \\mathbf{x}\\mathbf{A}` (in the
        continuous-time case)
    discrete_time : bool, optional
        Whether updating should be done using discrete (default) or continuous
        time dynamics.
    """

    #: Transition matrix for linear system.
    transition_matrix = None

    def __init__(self, transition_matrix, discrete_time=True):
        super(LinearDynamicalSystem, self).__init__(
            num_vars=transition_matrix.shape[0],
            discrete_time=discrete_time)
        self.transition_matrix = transition_matrix
        self.stable_eigenvalue = 1.0 if discrete_time else 0.0

    def get_equilibrium_distribution(self):
        """Get equilibrium state of dynamical system using eigen-decomposition

        Returns
        -------
        numpy array or scipy.sparse matrix
            Equilibrium state
        """

        vals, vecs = mx.get_largest_left_eigs(self.transition_matrix)
        equil_evals = np.flatnonzero(np.abs(vals-self.stable_eigenvalue) < 1e-8)
        if len(equil_evals) != 1:
            raise Exception("Expected one stable eigenvalue, but found " +
                            "%d instead (%s)" % (len(equil_evals), equil_evals))

        dist = np.real_if_close(np.ravel(vecs[equil_evals, :]))
        if np.any(np.iscomplex(equil_evals)):
            raise Exception("Expect equilibrium state to be real! %s" %
                            equil_evals)

        return mx.format_mx(dist)

    def _iterate_1step_discrete(self, start_state):
        # For discrete time systems, one step
        r = mx.format_mx(start_state).dot(self.transition_matrix)
        return r

    def _iterate_discrete(self, start_state, max_time=1.0):
        # For discrete time systems
        if max_time == 0.0:
            return start_state

        cls = mx.get_matrix_cls(self.transition_matrix)
        r = cls.format_mx(start_state).dot(
                cls.pow(self.transition_matrix, int(max_time)))
        return r

    def _iterate_continuous(self, start_state, max_time=1.0):
        if max_time == 0.0:
            return start_state

        cls = mx.get_matrix_cls(self.transition_matrix)
        curStartStates = cls.format_mx(start_state)
        r = curStartStates.dot(
              cls.expm(max_time * (self.transition_matrix)))
        return r

    # TODO
    # def getMultistepDynsys(self, num_iters):
    #     import copy
    #     rObj = copy.copy(self)
    #     rObj.trans = self.transition_matrixCls.pow(self.transition_matrix, num_iters)
    #     return rObj


class Solution(object):
    # def canPartition(self, nums):
    #     """
    #     :type nums: List[int]
    #     :rtype: bool
    #     """
    #     if nums is None or len(nums) == 0:
    #         return True
    #     volumn = 0
    #     for num in nums:
    #         volumn += num
    #     # if sum is odd then false
    #     if volumn % 2 != 0:
    #         return False
    #     # if sum of some elements can be half of total sum then true
    #     volumn /= 2
    #     dp = [False] * (volumn + 1)
    #     dp[0] = True
    #     for i in range(1, len(nums) + 1):
    #         for j in range(volumn, nums[i - 1] - 1, -1):
    #             dp[j] = dp[j] or dp[j - nums[i - 1]]
    #     return dp[volumn]

    def canPartition(self, nums):
        total_sum = sum(nums)
        if total_sum & 1:
            return False
        # if sum of some elements can be half of total sum then true
        target = total_sum >> 1
        dp = [0] * (target + 1)
        dp[0] = 1
        for num in nums:
            for i in range(target, num - 1, -1):
                dp[i] = dp[i] | dp[i - num]
        return dp[target] == 1


import numpy as np
import librosa
import pyaudio
import time
import requests
import json

import chainer
import chainer.links as L
import chainer.functions as F

IFTTT_EVENT = 'laser_machine_state'
IFTTT_KEY = '*********************'
IFTTT_URL = 'https://maker.ifttt.com/trigger/{event}/with/key/{key}'.format(
    event=IFTTT_EVENT, key=IFTTT_KEY)

def make_web_request(state):
    data = {}
    data['value1'] = state
    try:
        response = requests.post(IFTTT_URL, data=data)
        print('{0.status_code}: {0.text}'.format(response))
    except:
        print('Failed to make a web request')

SAMPLING_RATE = 16000
CHUNK = 1 * SAMPLING_RATE
FFT_SIZE = 256
THRESHOLD = 0.8

with open('state_names.json', 'r') as file_to_load:
    STATES = json.load(file_to_load)
    STATES.append('unknown')

N_STATES = len(STATES) - 1

last_state = STATES.index('unknown')

class LaserMachineListener(chainer.Chain):

    def __init__(self, n_mid_units, n_out):
        super(LaserMachineListener, self).__init__()

        with self.init_scope():
            self.l1 = L.Linear(None, n_mid_units)
            self.l2 = L.Linear(None, n_mid_units // 2)
            self.l3 = L.Linear(None, n_out)

    def __call__(self, x):
        h1 = F.relu(self.l1(x))
        h2 = F.relu(self.l2(h1))
        return self.l3(h2)

# NOTE:
# If you changed the value of n_mid_units from the initial value
# at the time of learning, change here also
model = L.Classifier(LaserMachineListener(n_mid_units=128,
                                          n_out=N_STATES))
chainer.serializers.load_npz('laser_machine_listener.model', model)

count = 0
predictions_in_60_sec = np.empty((0, N_STATES))

audio_interface = pyaudio.PyAudio()
audio_stream = audio_interface.open(format=pyaudio.paInt16,
                                    channels=1,
                                    rate=SAMPLING_RATE,
                                    input=True,
                                    frames_per_buffer=CHUNK)

try:
    while True:
        data = np.fromstring(audio_stream.read(CHUNK),
                             dtype=np.int16)

        audio_stream.stop_stream()

        start = time.time()

        state = last_state

        D = librosa.stft(librosa.util.normalize(data),
                         n_fft=FFT_SIZE,
                         window='hamming')
        magnitude = np.abs(D).transpose()

        predictions = F.softmax(model.predictor(magnitude)).data
        predictions_mean = predictions.mean(axis=0)
        predictions_in_60_sec = np.vstack([predictions_in_60_sec, predictions])
        count = count + 1

        elapsed_time = time.time() - start

        localtime = '{0.tm_hour:02d}:{0.tm_min:02d}:{0.tm_sec:02d}'.format(
            time.localtime(time.time()))
        print('{0:s} {1:s} ({2:.3f}, processed in {3:.3f} seconds)'.format(
            localtime,
            STATES[predictions_mean.argmax()],
            predictions_mean.max(),
            elapsed_time))

        if predictions_mean.max() > THRESHOLD:
            state = predictions_mean.argmax()

        if last_state != state:
            print('Changed: {0} > {1}'.format(
                STATES[last_state], STATES[state]))
            last_state = state

        if (count == 60):
            start = time.time()
            state_in_60_sec = predictions_in_60_sec.mean(axis=0).argmax()
            make_web_request(STATES[state_in_60_sec])
            predictions_in_60_sec = np.empty((0, N_STATES))
            count = 0
            elapsed_time = time.time() - start
            print('Made a request in {0:.3f} seconds)'.format(elapsed_time))

        audio_stream.start_stream()

except KeyboardInterrupt:
    print('Requested to terminate')

finally:
    audio_stream.stop_stream()
    audio_stream.close()
    audio_interface.terminate()
    print('Terminated')


from tkinter import *

class App(Tk):
    def __init__(self):
        super(App, self).__init__()
        self.geometry("500x500")
        self.config(bg="black")

        #Create Frame Aand scrollbar
        self.my_frame=Frame(self)
        self.my_frame.pack()
        self.my_scrolbar=Scrollbar(self.my_frame,orient=VERTICAL)
        # LIST BOX wigdet
        ## SINGLE,BRoWSE
        self.my_listbox=Listbox(self.my_frame,width=20,height=20,bg="gray",fg="white",yscrollcommand=self.my_scrolbar.set,selectmode=MULTIPLE)

        self.my_listbox.pack(side=LEFT)
        #confige scroll box
        self.my_scrolbar.config(command=self.my_listbox.yview)
        self.my_scrolbar.pack(side=RIGHT,fill=Y)

        ##Add item to listbox
        self.my_listbox.insert(0,"this is an item")
        self.my_listbox.insert(0, "this is 2 item")
        self.my_listbox.insert(0, "this is 3 item")

        self.my_list=['one','two','three']

        for i in range(20):
            for item in self.my_list:
                self.my_listbox.insert(3,item)

        self.my_button=Button(text="Delete",command=self.delete_func)
        self.my_button.pack()
        self.my_button2 = Button(text="Select", command=self.select)
        self.my_button2.pack()
        self.mylabel=Label(self,text="")
        self.mylabel.pack(pady=10)
        self.my_button2 = Button(text="Deleteall", command=self.delete_all)
        self.my_button2.pack()

    def delete_func(self):
        print(self.my_listbox.get(ANCHOR))

    def delete_all(self):
        self.my_listbox.delete(0,END)
    def select(self):
        self.mylabel.config(text=self.my_listbox.get(ANCHOR))

if __name__ == '__main__':
    app=App()
    app.mainloop()


"""VPU and Covar Unit Tests.
Run: pytest --cov=src --cov-report term-missing
"""
import numpy as np
from src.var_processor.vpu import VPU, project, BinaryVPU
from src.var_processor.buffer_vpu import BufferVPU
from src.tests.wrapper_vpu import VPUWrapper
from src.var_processor.pb_threshold import signal_pre_processor

def rand_same(size=2, negative=False):
    """Create 1D array of same binary values."""
    a = np.empty([size, 1])
    if not negative:
        # Choose value that is 0 or 1
        rand_int = np.random.randint(2)
    else:
        # Choose value that is -1, 0 or 1 with uniform distribution
        rand_int = np.random.randint(3)
    if rand_int == 0:
        a.fill(0)
    if rand_int == 1:
        a.fill(1)
    if rand_int == 2:
        a.fill(-1)
    return a

def rand_diff(size=2, negative=False):
    """Create 1D array with single 1 and rest 0."""
    a = np.zeros([size, 1])
    index = np.random.randint(size)
    if negative and np.random.randint(2):
        a[index] = -1
    else:
        a[index] = 1
    return a

def rand_opposite(size=2, negative=False):
    """Create a 1D array with opposite values."""
    # Create a random binary of size "size"
    rand_array = np.random.randint(2, size=(size, 1))
    if negative:
        rand_array = np.where(rand_array == 0, -1, 1)
    return rand_array

def test_rand():
    """Test random array generation as above."""
    # Test rand_same with negative numbers
    for i in range(0, 100):
        assert (rand_same() >= 0).all()
    neg_sum = 0
    for i in range(0, 100):
        if (rand_same(negative=True) < 0).all():
            neg_sum += 1
    # Check there are some negative values
    assert neg_sum > 0
    # Check zero mean
    rolling_sum = np.zeros(shape=(2, 1))
    for i in range(0, 1000):
        rolling_sum = rolling_sum + rand_same(negative=True)
    # Mean should be near 0
    assert np.allclose(rolling_sum/1000, np.zeros(shape=(2, 1)), atol=0.1)
    # Check opposites - for negative we should always have a sum of length
    rand_array = rand_opposite(size=2, negative=True)
    assert np.abs(rand_array).sum() == 2
    rand_array = rand_opposite(size=3, negative=True)
    assert np.abs(rand_array).sum() == 3

def test_project():
    """Test the VPU projection."""
    in_1 = np.ones(shape=(2, 1))
    in_2 = np.ones(shape=(2, 1))
    # Test vector multiplication
    out = project(in_1.T, in_2)
    assert np.array_equal(np.dot(in_1.T, in_2), out)
    assert out.shape == (1, 1)
    # Test scalar multiplication
    r = 1
    out = project(r, in_1)
    assert np.array_equal(in_1, out)

def test_vpu():
    """Test the VPU."""
    # Intialise VPU
    vpu = VPU(2)
    # Test Iteration
    for _ in range(0, 150):
        data_in = np.random.randint(2, size=(2, 1))
        r_backward = np.random.randint(2, size=(1, 1))
        vpu.update_cov(data_in)
        _ = vpu.iterate(data_in, r_backward)
    old_cov = vpu.cu.covariance
    assert old_cov.any()
    # Test print representation
    string = vpu.__repr__()
    assert "2" in string
    assert "Eigenvector" in string
    # Test reset
    vpu.reset()
    new_cov = vpu.cu.covariance
    assert not np.array_equal(old_cov, new_cov)

def test_buffer_vpu():
    """Test the BufferVPU."""
    # Intialise VPU
    vpu = BufferVPU(2, 4)
    assert vpu.forward_buffer.shape == (2, 4)
    assert vpu.backward_buffer.shape == (1, 4)
    assert vpu.cu.covariance.shape == (8, 8)
    assert vpu.pi.ev.shape == (8, 1)
    # Test Iteration
    for _ in range(0, 130):
        data_in = np.random.randint(2, size=(2, 1))
        r_backward = np.random.randint(2, size=(1, 1))
        vpu.update_cov(data_in)
        _ = vpu.iterate(data_in, r_backward)
    old_cov = vpu.cu.covariance
    assert old_cov.any()
    vpu.reset()
    new_cov = vpu.cu.covariance
    assert not np.array_equal(old_cov, new_cov)

def test_vpu_function_same():
    """More advanced testing of VPU function."""
    size = 2
    vpu = VPU(size)
    # Test with binary arrays of [0, 0] and [1, 1]
    for _ in range(0, 1000):
        vpu.update_cov(rand_same(size=size), power_iterate=True)
    half_matrix = np.ones(shape=(size, size))*(127/2)
    root_two = np.ones(shape=(size, 1))*(127)*(np.sqrt(size)/size)
    assert np.allclose(vpu.cu.covariance, half_matrix, atol=15)
    assert np.allclose(np.abs(vpu.pi.eigenvector), root_two, atol=5)
    # Test forward projection
    ones = np.ones(shape=(2, 1), dtype=np.int8)
    processed_data = ones*(np.sqrt(2)/2)
    r = vpu.forward(processed_data).astype(np.int8)
    assert np.allclose(np.abs(r), 126, atol=5)
    # Test with ternary values
    size = 2
    vpu = VPU(size)
    for _ in range(0, 1000):
        vpu.update_cov(
            rand_same(size=size, negative=True),
            power_iterate=True
        )
    # Eigenvector is still the same
    assert np.allclose(np.abs(vpu.pi.eigenvector), root_two, atol=5)
    # Test with size = 4
    size = 4
    vpu = VPU(size)
    for _ in range(0, 1000):
        vpu.update_cov(rand_same(negative=True, size=size), power_iterate=True)
    # Check all values of covariance matrix are the same
    root_four = np.ones(shape=(size, 1))*(127)*(np.sqrt(size)/size)
    assert np.allclose(np.abs(vpu.pi.eigenvector), root_four, atol=5)

def test_vpu_function_diff():
    """Test random different 1D length 2 binary arrays."""
    size = 2
    vpu = VPU(size)
    # Test with differences
    for _ in range(0, 1000):
        vpu.update_cov(rand_diff(size=size), power_iterate=True)
    half_I_matrix = np.identity(size)*(127/2)
    assert np.allclose(vpu.cu.covariance, half_I_matrix, atol=15)
    # Eigenvalues should be 0, 127 or vice versa and negatives
    assert np.allclose(np.abs(vpu.pi.eigenvector).sum(), 127, atol=5)
    # Test forward projection
    ones = np.ones(shape=(2, 1), dtype=np.int8)
    processed_data = ones*(np.sqrt(2)/2)
    r = vpu.forward(processed_data).astype(np.int8)
    assert np.allclose(np.abs(r), 89, atol=5)
    # Test with ternary values
    size = 2
    vpu = VPU(size)
    for _ in range(0, 1000):
        vpu.update_cov(
            rand_same(size=size, negative=True),
            power_iterate=True
        )
    # Eigenvector is still the same
    root_two = np.ones(shape=(size, 1))*(127)*(np.sqrt(size)/size)
    assert np.allclose(np.abs(vpu.pi.eigenvector), root_two, atol=5)
    # Test with size = 4
    size = 4
    vpu = VPU(size)
    for _ in range(0, 1000):
        vpu.update_cov(rand_same(negative=True, size=size), power_iterate=True)
    # Check all values of covariance matrix are the same
    root_four = np.ones(shape=(size, 1))*(127)*(np.sqrt(size)/size)
    assert np.allclose(np.abs(vpu.pi.eigenvector), root_four, atol=5)

def test_vpu_binary():
    """Test the VPU with non linearity."""
    # Check with size two and different entries
    size = 2
    vpu = BinaryVPU(size)
    for _ in range(0, 1000):
        vpu.update_cov(rand_diff(size=size), power_iterate=True)
    assert np.allclose(np.abs(vpu.pi.eigenvector).sum(), 127, atol=5)
    sum_r = 0
    for i in range(0, 100):
        rand_input = np.random.randint(low=-1, high=2, size=(2, 1))
        r = vpu.forward(rand_input)
        assert r in [-1, 0, 1]
        sum_r += r
    assert sum_r < 100 and sum_r > -100
    # Check with size = 4
    size = 4
    vpu = BinaryVPU(size)
    for _ in range(0, 1000):
        vpu.update_cov(rand_diff(size=size), power_iterate=True)
    assert np.allclose(np.abs(vpu.pi.eigenvector).sum(), 127, atol=5)
    for i in range(0, 100):
        rand_input = np.random.randint(low=-1, high=2, size=(size, 1))
        r = vpu.forward(rand_input)
        assert r in [-1, 0, 1]
    # Check same entries for size = 4
    size = 4
    vpu = BinaryVPU(size)
    for _ in range(0, 1000):
        vpu.update_cov(rand_same(size=size), power_iterate=True)
    assert np.allclose(
        np.abs(vpu.pi.eigenvector),
        63*np.ones(shape=(size, 1))
    )
    for i in range(0, 100):
        rand_input = np.random.randint(low=-1, high=2, size=(size, 1))
        r = vpu.forward(rand_input)
        assert r in [-1, 0, 1]
    # Check same with negatives
    size = 4
    vpu = BinaryVPU(size)
    for _ in range(0, 1000):
        vpu.update_cov(rand_same(negative=True, size=size), power_iterate=True)
    assert np.allclose(
        np.abs(vpu.pi.eigenvector),
        63*np.ones(shape=(size, 1))
    )
    for i in range(0, 100):
        rand_input = np.random.randint(low=-1, high=2, size=(size, 1))
        r = vpu.forward(rand_input)
        assert r in [-1, 0, 1]

def test_forward_and_back():
    """Test forward and back BinaryVPU function."""
    size = 4
    vpu = BinaryVPU(size)
    for _ in range(0, 1000):
        rand_val = np.random.randint(low=-1, high=2, size=(size, 1))
        vpu.update_cov(rand_val, power_iterate=True)
    for i in range(0, 100):
        rand_input = np.random.randint(low=-1, high=2, size=(size, 1))
        r = vpu.forward(rand_input)
        pred_inputs = vpu.backward(r)
        assert r in [-1, 0, 1]
        assert pred_inputs.max() <= 1 and pred_inputs.min() >= -1
        print(rand_input, r, pred_inputs)

def test_recontruction():
    """Use the VPU Wrapper to test advanced function."""
    # Initialise two VPUs and wrappers
    data_in = np.random.randint(254, size=(2, 1))
    mean = np.asarray([127, 127]).reshape(-1, 1)
    vpu_1 = BinaryVPU(2)
    vpu_2 = BinaryVPU(2)
    wrapper_1 = VPUWrapper(vpu_1)
    wrapper_2 = VPUWrapper(vpu_2)
    for _ in range(0, 1000):
        # First VPU
        ternary_input = signal_pre_processor(data_in, mean)
        _, _, residual = wrapper_1.iterate(ternary_input)
        # Second VPU
        _ = wrapper_2.iterate(residual)
    est = (wrapper_1.pred_estimate*mean+mean)+(wrapper_2.pred_estimate*mean)
    assert np.allclose(data_in, est, rtol=0.10, atol=10)


import datetime
import logging
import os

import discord
from dateutil import parser, tz

import api
import util
import watcher

# Fetch environment variables

def _bool(e):
    return e.lower() not in ('false', 'no', 'off', '0')

DISCORD_TOKEN = os.environ['DISCORD_TOKEN']
DISCORD_CHANNEL = int(os.environ['DISCORD_CHANNEL'])
DRY_RUN = _bool(os.environ.get('DRY_RUN', 'true'))

FOCUS_TEAM_ID = int(os.environ['FOCUS_TEAM_ID'])
PATTERNS_FILE = os.environ['PATTERNS_FILE']

SKIP_CURRENT = _bool(os.environ.get('SKIP_CURRENT', 'true'))

# set up logging

logging.basicConfig(
    format='%(asctime)s %(levelname)-8s:%(name)-16s: %(message)s',
    level='WARNING',
    datefmt='%Y-%m-%d %H:%M:%S',
)

logging.getLogger('trash').setLevel('INFO')
logging.getLogger('trash.main').setLevel('DEBUG')
logging.getLogger('trash.watch').setLevel('DEBUG')
logging.getLogger('trash.api.plays').setLevel('DEBUG')

# main logic. this is the only place we have to worry about discord

log = logging.getLogger('trash.main')

dcli = discord.Client()

@dcli.event
async def on_ready():
    channel: discord.TextChannel = dcli.get_channel(DISCORD_CHANNEL)

    # print to log if dry run
    if not DRY_RUN:
        send = channel.send
    else:
        _dry = logging.getLogger('trash.dry')

        async def send(text):
            _dry.info(text)

    while True:
        game = await api.next_game(FOCUS_TEAM_ID)
        if not game:
            log.warning('could not find a live or scheduled game.')
            await util.sleep(days=1)
            continue

        title = f'{game.teams.home.team.name} vs. {game.teams.away.team.name}'

        date = parser.parse(game.gameDate)
        utcnow = datetime.datetime.now(tz.tzutc())

        delay = date - utcnow - datetime.timedelta(seconds=30)
        log.info('waiting for game %s (%s)', game.gamePk, title)

        # if we didn't have to sleep, game is in progress
        in_progress = not await util.sleep(delay)
        log.info('watching game %s (%s)', game.gamePk, title)

        # send the message if the game is new or we aren't skipping
        if in_progress and SKIP_CURRENT:
            log.debug('not notifying because game is already in progress')
        else:
            await send(f'watching {title}')

        # game watching logic is here.
        # send is a callback so we don't have to worry about discord in that module
        await watcher.watch(
            game=game,
            focus_id=FOCUS_TEAM_ID,
            patterns_file=open(PATTERNS_FILE),
            send=send,
            skip=SKIP_CURRENT
        )

if __name__ == '__main__':
    dcli.run(DISCORD_TOKEN)