#%%
# -*- coding: utf-8 -*-
"""
Class definition of YOLO_v3 style detection model on image and video
"""
import colorsys
import os
from timeit import default_timer as timer

import numpy as np
from keras import backend as K
from keras.models import load_model
from keras.layers import Input
from PIL import Image, ImageFont, ImageDraw

from yolo3.model import yolo_eval, yolo_body, tiny_yolo_body
from yolo3.utils import letterbox_image
import os
from keras.utils import multi_gpu_model

import cv2
from PIL import Image
from scipy import stats
import numpy as np
import base
import windowsBase
#import imageio

class YOLO(object):
    _defaults = {
        "model_path": 'model_data/ets.h5',
        "anchors_path": 'model_data/yolo_anchors.txt',
        "classes_path": 'model_data/ets_classes.txt',
        "score" : 0.3,
        "iou" : 0.45,
        "model_image_size" : (416, 416),
        "gpu_num" : 1,
    }

    @classmethod
    def get_defaults(cls, n):
        if n in cls._defaults:
            return cls._defaults[n]
        else:
            return "Unrecognized attribute name '" + n + "'"

    def __init__(self, **kwargs):
        self.__dict__.update(self._defaults) # set up default values
        self.__dict__.update(kwargs) # and update with user overrides
        self.class_names = self._get_class()
        self.anchors = self._get_anchors()
        self.sess = K.get_session()
        self.boxes, self.scores, self.classes = self.generate()

    def _get_class(self):
        classes_path = os.path.expanduser(self.classes_path)
        with open(classes_path) as f:
            class_names = f.readlines()
        class_names = [c.strip() for c in class_names]
        return class_names

    def _get_anchors(self):
        anchors_path = os.path.expanduser(self.anchors_path)
        with open(anchors_path) as f:
            anchors = f.readline()
        anchors = [float(x) for x in anchors.split(',')]
        return np.array(anchors).reshape(-1, 2)

    def generate(self):
        model_path = os.path.expanduser(self.model_path)
        assert model_path.endswith('.h5'), 'Keras model or weights must be a .h5 file.'

        # Load model, or construct model and load weights.
        num_anchors = len(self.anchors)
        num_classes = len(self.class_names)
        is_tiny_version = num_anchors==6 # default setting
        try:
            self.yolo_model = load_model(model_path, compile=False)
        except:
            self.yolo_model = tiny_yolo_body(Input(shape=(None,None,3)), num_anchors//2, num_classes) \
                if is_tiny_version else yolo_body(Input(shape=(None,None,3)), num_anchors//3, num_classes)
            self.yolo_model.load_weights(self.model_path) # make sure model, anchors and classes match
        else:
            assert self.yolo_model.layers[-1].output_shape[-1] == \
                num_anchors/len(self.yolo_model.output) * (num_classes + 5), \
                'Mismatch between model and given anchor and class sizes'

        print('{} model, anchors, and classes loaded.'.format(model_path))

        # 生成目标边框颜色
        hsv_tuples = [(x / len(self.class_names), 1., 1.)
                      for x in range(len(self.class_names))]
        self.colors = list(map(lambda x: colorsys.hsv_to_rgb(*x), hsv_tuples))
        self.colors = list(
            map(lambda x: (int(x[0] * 255), int(x[1] * 255), int(x[2] * 255)),
                self.colors))
        np.random.seed(10101)  # Fixed seed for consistent colors across runs.
        np.random.shuffle(self.colors)  # Shuffle colors to decorrelate adjacent classes.
        np.random.seed(None)  # Reset seed to default.

        # Generate output tensor targets for filtered bounding boxes.
        self.input_image_shape = K.placeholder(shape=(2, ))
        if self.gpu_num>=2:
            self.yolo_model = multi_gpu_model(self.yolo_model, gpus=self.gpu_num)
        boxes, scores, classes = yolo_eval(self.yolo_model.output, self.anchors,
                len(self.class_names), self.input_image_shape,
                score_threshold=self.score, iou_threshold=self.iou)
        return boxes, scores, classes

    def detect_image(self, image):
        start = timer()

        if self.model_image_size != (None, None): #判断图片是否存在
            assert self.model_image_size[0]%32 == 0, 'Multiples of 32 required'
            assert self.model_image_size[1]%32 == 0, 'Multiples of 32 required'
            #assert断言语句的语法格式 model_image_size[0][1]指图像的w和h，且必须是32的整数倍
            boxed_image = letterbox_image(image, tuple(reversed(self.model_image_size)))
            #letterbox_image()定义在utils.py的第20行。输入参数（图像 ,(w=416,h=416)),输出一张使用填充来调整图像的纵横比不变的新图。
        else:
            new_image_size = (image.width - (image.width % 32),
                              image.height - (image.height % 32))
            boxed_image = letterbox_image(image, new_image_size)
        image_data = np.array(boxed_image, dtype='float32')

        #print(image_data.shape) #（416，416,3）
        image_data /= 255. #归一化
        image_data = np.expand_dims(image_data, 0)  # Add batch dimension.
        #批量添加一维 -> (1,416,416,3) 为了符合网络的输入格式 -> (batch, w, h, c)

        out_boxes, out_scores, out_classes = self.sess.run(
            [self.boxes, self.scores, self.classes],
            #目的为了求boxes,scores,classes，具体计算方式定义在generate（）函数内。在yolo.py第60行
            feed_dict={#喂参数
                self.yolo_model.input: image_data, #图像数据
                self.input_image_shape: [image.size[1], image.size[0]], #图像尺寸
                K.learning_phase(): 0 #学习模式 0=测试模型 1=训练模式
            })

        print('Found {} boxes for {}'.format(len(out_boxes), 'img'))
        # 绘制边框，自动设置边框宽度，绘制边框和类别文字，使用Pillow绘图库

        font = ImageFont.truetype(font='font/FiraMono-Medium.otf',
                    size=np.floor(3e-2 * image.size[1] + 0.5).astype('int32')) #字体
        thickness = (image.size[0] + image.size[1]) // 300 #厚度

        for i, c in reversed(list(enumerate(out_classes))):
            predicted_class = self.class_names[c] #类别
            box = out_boxes[i] #框

            score = out_scores[i] #置信度

            label = '{} {:.2f}'.format(predicted_class, score) #标签
            draw = ImageDraw.Draw(image) #图画
            label_size = draw.textsize(label, font) #文字

            top, left, bottom, right = box
            top = max(0, np.floor(top + 0.5).astype('int32'))
            left = max(0, np.floor(left + 0.5).astype('int32'))
            bottom = min(image.size[1], np.floor(bottom + 0.5).astype('int32'))
            right = min(image.size[0], np.floor(right + 0.5).astype('int32'))
            print(label, (left, top), (right, bottom)) #打印边框坐标

            if top - label_size[1] >= 0: #标签文字
                text_origin = np.array([left, top - label_size[1]])
            else:
                text_origin = np.array([left, top + 1])

            # My kingdom for a good redistributable image drawing library.
            for i in range(thickness): #画框
                draw.rectangle(
                    [left + i, top + i, right - i, bottom - i],
                    outline=self.colors[c])
            draw.rectangle( #文字背景
                [tuple(text_origin), tuple(text_origin + label_size)],
                fill=self.colors[c])
            draw.text(text_origin, label, fill=(0, 0, 0), font=font) #文案
            del draw

        end = timer()
        print(end - start)
        return image

    def close_session(self):
        self.sess.close()

# CV车道检测工具
def do_canny(frame):
	# 将每一帧转化为灰度图像，去除多余信息
	gray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
	# 高斯滤波器，去除噪声，平滑图像
	blur = cv2.GaussianBlur(gray,(5,5),0)
	# 边缘检测
	# minVal = 50
	# maxVal = 150
	canny = cv2.Canny(blur,50,150)

	return canny

def do_segment(frame):
	# 获取图像高度(注意CV的坐标系,正方形左上为0点，→和↓分别为x,y正方向)
	height = frame.shape[0]

	# 创建一个区域,指定点
	polygons = np.array([
		[(400,730),
		 (1280,730),
		 (860,500),
		 (820,500)]
		])

	# 创建一个mask,形状与frame相同，全为0值
	mask = np.zeros_like(frame)

	# 对该mask进行填充，做一个掩码
	# 三角形区域为1
	# 其余为0
	cv2.fillPoly(mask,polygons,255)

	# 将frame与mask做与，抠取需要区域
	segment = cv2.bitwise_and(frame,mask)
	return segment

def calculate_lines(frame,lines):
    try:
        # 建立两个空列表，用于存储左右车道边界坐标
        left = []
        right = []
        # 循环遍历lines
        for line in lines:
            # 将线段信息从二维转化能到一维
            x1,y1,x2,y2 = line.reshape(4)

            # 将一个线性多项式拟合到x和y坐标上，并返回一个描述斜率和y轴截距的系数向量
            parameters = np.polyfit((x1,x2), (y1,y2), 1)
            slope = parameters[0] #斜率
            y_intercept = parameters[1] #截距

            # 通过斜率大小，可以判断是左边界还是右边界
            # 很明显左边界slope<0(注意cv坐标系不同的)
            # 右边界slope>0
            if slope < 0:
                left.append((slope,y_intercept))
            else:
                right.append((slope,y_intercept))

        # 将所有左边界和右边界做平均，得到一条直线的斜率和截距
        left_avg = np.average(left,axis=0)
        right_avg = np.average(right,axis=0)
        # 将这个截距和斜率值转换为x1,y1,x2,y2
        left_line = calculate_coordinate(frame,parameters=left_avg)
        right_line = calculate_coordinate(frame, parameters=right_avg)

        return np.array([left_line,right_line])
    except:
        return None

def calculate_coordinate(frame,parameters):
	# 获取斜率与截距
    try:
        slope, y_intercept = parameters
        # 设置初始y坐标为自顶向下(框架底部)的高度
        # 将最终的y坐标设置为框架底部上方500
        y1 = frame.shape[0]
        y2 = int(y1-500)
        # 根据y1=kx1+b,y2=kx2+b求取x1,x2
        x1 = int((y1-y_intercept)/slope)
        x2 = int((y2-y_intercept)/slope)
        return np.array([x1,y1,x2,y2])
    except TypeError:
        slope, y_intercept = 0, 0
        return np.array([])

def visualize_lines(frame,lines):
    lines_visualize = np.zeros_like(frame)
    try:
        if lines is not None:
            for x1,y1,x2,y2 in lines:
                cv2.line(lines_visualize,(x1,y1),(x2,y2),(0,0,255),5)
        return lines_visualize
    except:
        return np.zeros_like(frame)

def detect_video(yolo, video_path, output_path=""):
    win = base.getWinFromTitle(windowsBase.getWins(), "Simulator")
    if not win:
        print("can't find the window", end='')
        return False

    isOutput = True if output_path != "" else False
    if isOutput:
        print("!!! TYPE:", type(output_path))
        out = cv2.VideoWriter(output_path)

    accum_time = 0
    curr_fps = 0
    fps = "FPS: ??"
    prev_time = timer()
    image_list = []
    while True:
        #获取图像
        window = windowsBase.getWinPic(win[0])
        if window is False:
            print("can't get image", end="")
            break
        #处理图像
        b, g, r = window.split()
        image = Image.merge("RGB",(r,g,b))

        #道路识别部分
        frame = cv2.cvtColor(np.array(window),cv2.COLOR_RGB2BGR)
        canny = do_canny(frame)
        segment = do_segment(canny)
        hough = cv2.HoughLinesP(segment, 1, np.pi/180, 100, minLineLength=100, maxLineGap=50)
        lines = calculate_lines(frame, hough)
        lines_visualize = visualize_lines(frame, lines)

        #物体识别部分
        image = yolo.detect_image(image)
        result = np.asarray(image)
        curr_time = timer()
        exec_time = curr_time - prev_time
        prev_time = curr_time
        accum_time = accum_time + exec_time
        curr_fps = curr_fps + 1
        if accum_time > 1:
            accum_time = accum_time - 1
            fps = "FPS: " + str(curr_fps)
            curr_fps = 0
        cv2.putText(result, text=fps, org=(3, 15), fontFace=cv2.FONT_HERSHEY_SIMPLEX, fontScale=0.50, color=(255, 0, 0), thickness=2)
        result =cv2.addWeighted(result,1,lines_visualize,1,0.1)
        cv2.namedWindow("result", cv2.WINDOW_NORMAL)
        cv2.imshow("result", result)

        # image_list.append(result)
        # if len(image_list)>300:
        #     imageio.mimsave('pic.gif', image_list, duration=0.1)
        #     image_list = []
        #     break
        if isOutput:
            out.write(result)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    yolo.close_session()

# %%


"""
Linda Nguyen
Date: 8/5/19

344. Reverse String
	Modify string in place with O(1) extra memory
"""
def ReverseString(A:int):
	left = 0
	right = len(A) - 1
	while left < right:
		A[left], A[right] = A[right], A[left]
		left += 1
		right -= 1
	return A

if __name__ == "__main__":
	print("344. Reverse String\n")
	input = ['h', 'e', 'l', 'l', 'o']
	print("String: ", input)
	print("Reversed: ", ReverseString(input), '\n')

	input = ['e', 'v', 'e', 'r', 'y', 'o', 'n', 'e']
	print("String: ", input)
	print("Reversed: ", ReverseString(input))


#!/usr/bin/env python
# encoding: utf-8
"""
@author: wushaohong
@time: 2020/8/11 下午2:49
"""
"""295. 数据流的中位数
中位数是有序列表中间的数。如果列表长度是偶数，中位数则是中间两个数的平均值。

例如，

[2,3,4] 的中位数是 3

[2,3] 的中位数是 (2 + 3) / 2 = 2.5

设计一个支持以下两种操作的数据结构：

void addNum(int num) - 从数据流中添加一个整数到数据结构中。
double findMedian() - 返回目前所有元素的中位数。
示例：

addNum(1)
addNum(2)
findMedian() -> 1.5
addNum(3)
findMedian() -> 2
进阶:

如果数据流中所有整数都在 0 到 100 范围内，你将如何优化你的算法？
如果数据流中 99% 的整数都在 0 到 100 范围内，你将如何优化你的算法？"""

class MedianFinder2:
    # 如果数据流中所有整数都在 0 到 100 范围内，你将如何优化你的算法？

    def __init__(self):
        """
        initialize your data structure here.
        """
        self.seq = [0] * 101
        self.left = None
        self.right = None
        self.left_deep = None
        self.right_deep = None

    def addNum(self, num: int) -> None:
        self.seq[num] += 1
        if not self.left:
            self.left = self.right = num
            self.left_deep = self.right_deep = 1
        else:  # 数组非空
            if self.left == self.right and self.left_deep == self.right_deep:
                if num < self.left:
                    if self.left_deep > 1:
                        self.left_deep -= 1
                    else:
                        for i in range(self.left - 1, -1, -1):
                            if self.seq[i] > 0:
                                self.left = i
                                self.left_deep = self.seq[i]
                                break
                elif num == self.left:
                    self.right_deep += 1
                else:  # num>self.left=self.right
                    if self.right_deep < self.seq[self.right]:
                        self.left_deep += 1
                    else:
                        for i in range(self.right + 1, 101):
                            if self.seq[i] > 0:
                                self.right = i
                                self.right_deep = 1
                                break
            elif self.left == self.right and self.left_deep != self.right_deep:
                if num < self.left:
                    self.right_deep -= 1
                else:
                    self.left_deep += 1
            else:  # left<right
                if num < self.left:
                    self.right, self.right_deep = self.left, self.left_deep
                elif num == self.left:
                    self.left_deep += 1
                    self.right, self.right_deep = self.left, self.left_deep
                else:
                    self.left, self.left_deep = self.right, self.right_deep

    def findMedian(self) -> float:
        if self.left == self.right:
            return self.left
        else:
            return (self.left + self.right) / 2

class MedianFinder:

    def __init__(self):
        """
        initialize your data structure here.
        """
        self.seq = []
        self.length = 0

    def addNum(self, num: int) -> None:
        if not self.seq:
            self.seq.append(num)
        else:
            for i, n in enumerate(self.seq):
                if num < n:
                    self.seq.insert(i, num)
                    break
            else:
                self.seq.append(num)
        self.length += 1

    def findMedian(self) -> float:
        m1 = self.length / 2
        m2 = self.length // 2
        if m1 == m2:
            return (self.seq[m2] + self.seq[m2 - 1]) / 2
        else:
            return self.seq[m2]

import heapq

class MedianFinder11:

    def __init__(self):
        """
        initialize your data structure here.
        """
        self.min_heap = []
        self.max_heap = []
        self.count = 0

    def addNum(self, num: int) -> None:
        self.count += 1
        heapq.heappush(self.max_heap, (-num, num))
        _, max_heap_top = heapq.heappop(self.max_heap)
        heapq.heappush(self.min_heap, max_heap_top)
        if self.count & 1:
            min_heap_top = heapq.heappop(self.min_heap)
            heapq.heappush(self.max_heap, (-min_heap_top, min_heap_top))

    def findMedian(self) -> float:
        if self.count & 1:
            return self.max_heap[0][1]
        else:
            return (self.max_heap[0][1] + self.min_heap[0]) / 2

# Your MedianFinder object will be instantiated and called as such:
# obj = MedianFinder()
# obj.addNum(num)
# param_2 = obj.findMedian()


import tkinter as tk
import tkinter.font as tkFont
from tkinter import ttk

# Local packages.
import globals
from src.validators import text_validator

##############################################################################
# Globals.
##############################################################################

##############################################################################
# Functions.
##############################################################################

##############################################################################
# WidgetTextEntry class.
##############################################################################
class WidgetTextEntry(object):
    """
    WidgetTextEntry class for use with the simplelog application.
    Provides a labeled text entry box for GUI entry of log field values.
    """

    DEFAULT_WIDTH = 12

    # ------------------------------------------------------------------------
    def __init__(self, parent, title, field,
        width=DEFAULT_WIDTH,
        to_upper = False,
        validator=None,
        title_padx = 3,
        title_pady = 3,
        title_size = 10,
        entry_padx = 3,
        entry_pady = 3,
        entry_size = 10,):
        """
        Class constructor.

        Parameters
        ----------
        parent : Tk object
            The parent object containing the widget
        title : str
            The widget title to be displayed in the GUI
        field : str
            The ADIF field name of the log entry
        width : int
            The text entry box width in characters
        to_upper : bool
            Converts characters to uppercase if True
        validator : function name
            The name of a validator callback function for the text entry.

        Returns
        -------
        None.
        """
        self.parent = parent
        self.frame = tk.Frame(parent)
        #self.frame = tk.Frame(parent,
        #    highlightbackground="blue",
        #    highlightthickness=2)

        self._title = tk.StringVar(self.frame) # Widget title to be displayed in GUI
        self._title_label = None               # Label object to display the title
        self._adif_field = field.upper()       # ADIF field name corresponding to this log entry
        self._entry_widget = None              # Text entry widget used to enter log info
        self._value = tk.StringVar(self.frame) # Text entry value
        self._validator_cb = None              # Registered validator callback function

        self.title_padx = title_padx           # Title x padding
        self.title_pady = title_pady           # Title y padding
        self.title_font_size = title_size      # Title font size
        self.widget_padx = entry_padx          # Entry object x padding
        self.widget_pady = entry_pady          # Entry object y padding
        self.widget_font_size = entry_size     # Entry object font size
        self.widget_width = width              # Entry text width
        self.to_upper = to_upper               # Convert text entries to uppercase if true

        self.LABEL_BG = 'SlateGray1'

        self.set_title(title)
        if validator is not None:
            self._validator_cb = self.frame.register(validator)
        else:
            self._validator_cb = self.frame.register(text_validator)
        self.init()

    # ------------------------------------------------------------------------
    def _to_upper(self, *args):
        """
        Convert the text entry to upper case.
        """
        self._value.set(self._value.get().upper())

    # ------------------------------------------------------------------------
    def clear(self):
        """
        Clear the text entry widget.
        """
        self.set_value('')

    # ------------------------------------------------------------------------
    def set_focus(self):
        """
        Set focus to the text entry box.
        """
        self._entry_widget.focus_set()

    # ------------------------------------------------------------------------
    def get_title(self):
        """
        Return the widget title string.
        """
        return self._title.get()

    # ------------------------------------------------------------------------
    def set_title(self, value):
        """
        Set the widget title.
        """
        self._title.set(str(value))

    # ------------------------------------------------------------------------
    def get_value(self):
        """
        Return the text entry value.
        """
        return self._value.get()

    # ------------------------------------------------------------------------
    def set_value(self, value):
        """
        Set the text entry value.
        Note that this value is not validated.
        """
        self._value.set(str(value))

    # ------------------------------------------------------------------------
    def get_field(self):
        """
        Return the ADIF field name string.
        """
        return self._adif_field.upper()

    # ------------------------------------------------------------------------
    def set_field(self, value):
        """
        Set the ADIF field name.
        """
        self._adif_field = (str(value).upper())

    # ------------------------------------------------------------------------
    def bind(self, event, bind_fn):
        """
        Bind a function or method to a text entry event.

        Parameters
        ----------
        event : str
            The event to bind, e.g., '<Return>', '<FocusOut>', etc.
        bind_fn : function
            The function to execute when the event occurs
            The function has the signature bind_fn(*args)

        Returns
        -------
        None.
        """
        self._entry_widget.bind(event, bind_fn)

    # ------------------------------------------------------------------------
    def init(self):
        """
        Method to create and initialize the UI widget.
        """
        self.clear()

        # Create the widget title label.
        self._title_label = tk.Label(self.frame,
            textvariable = self._title,
            font=tkFont.Font(size=self.title_font_size))
        self._title_label.grid(
            row=0,
            column=0,
            sticky='W',
            padx=self.title_padx,
            pady=(self.title_pady,0))

        # Create the text entry widget.
        self._entry_widget = tk.Entry(self.frame,
            width = self.widget_width,
            textvariable=self._value,
            font=tkFont.Font(size=self.widget_font_size),
            validate='key',
            validatecommand=(self._validator_cb, '%d', '%i', '%S', '%P'))
        self._entry_widget.grid(
            row=1,
            column=0,
            padx=self.widget_padx,
            pady=(0, self.widget_pady))
        if self.to_upper:
            self._value.trace_add('write', self._to_upper) # Convert all letters to uppercase

##############################################################################
# Main program.
##############################################################################
if __name__ == "__main__":
    print('WidgetTextEntry main program not implemented.')


import os
import sys
import yaml

def add_new_dict_data(original, new):
    """Adds/appends new entries to existing dicts

    Adds new key/value entries to existing dictionaries, and appends
    new leaf values.
    """

    if not hasattr(new, 'items'):
        return

    for key, new_values in new.items():

        # Add our whole sub-dictionary into the tree
        if key not in original:
            original[key] = new_values
            return

        # Only populate missing values
        for val in new_values:
            if val not in original[key]:
                original[key].append(val)

        add_new_dict_data(original[key], new[key])

if __name__ == '__main__':

    repo_root = sys.argv[1]

    kilo_file = '/etc/openstack_deploy.KILO/env.d/neutron.yml'
    repo_liberty_file = os.path.join(repo_root,
                                     'etc/openstack_deploy/env.d/neutron.yml')
    liberty_file = '/etc/openstack_deploy/env.d/neutron.yml'
    flag_file = '/etc/openstack_deploy.KILO/NEUTRON_MIGRATED'

    with open(kilo_file, 'r') as f:
        kilo_dict = yaml.safe_load(f.read())

    with open(repo_liberty_file, 'r') as f:
        liberty_dict = yaml.safe_load(f.read())

    for skel in ('component_skel', 'container_skel', 'physical_skel'):
        add_new_dict_data(kilo_dict[skel], liberty_dict[skel])

    with open(liberty_file, 'w') as f:
        f.write(yaml.safe_dump(kilo_dict, default_flow_style=False,
                               width=1000))

    with open(flag_file, 'w') as f:
        f.write('Neutron variables migrated from kilo to liberty.')


import os
import sys
import numpy as np
import itertools

#from collections import deque

def run(indata):
    L = indata.splitlines(keepends=False)

    # ----------- PART 1 -----------
    #
    C2, C3 = 0, 0
    for l in L:
        val, count = np.unique(np.array(list(l)), return_counts=True)
        if 2 in count:
            C2 += 1
        if 3 in count:
            C3 += 1

    answer = C2 * C3
    print("Part 1: {}".format(answer))

    # ----------- PART 2 -----------
    #
    for l1, l2 in itertools.combinations(L, 2):
        diffpos = np.array(list(l1)) != np.array(list(l2))
        if np.sum(diffpos) == 1:
            answer = ''.join(np.array(list(l1))[diffpos == False])
            break
    print("Part 2: {}".format(answer))

if __name__ == '__main__':
    # Initialize
    ROOT = os.path.dirname(os.path.dirname(__file__))
    sys.path.append(ROOT)
    from aoc_utils import get_input, clipboard_set

    # Get input data
    day = int(os.path.basename(__file__)[3:5])
    year = int(os.path.basename(os.path.dirname(__file__)))
    indata = get_input(day, year)

    # Run
    answer = run(indata)

    # Copy to clipboard?
    if answer is not None:
        clipboard_set(str(answer))


from datetime import datetime

from django.db import models

from calculator_projects.apps.labour_costs.models import LabourCost
from calculator_projects.apps.projects.models import ProjectPlan, ProjectFact
from calculator_projects.apps.stages.models import StagePlan, StageFact
from calculator_projects.apps.users.models import User
import uuid

from calculator_projects.utils.helpers import (defining_duration_per_day, defining_duration_per_hour,
                                               defining_total_price)
from django.utils.translation import gettext_lazy as _

class TaskFactStatus(models.IntegerChoices):
    PLAN = 1, _("План")
    ACTIVE = 2, _("Активный")
    COMPLETED = 3, _("Завершенный")
    CANCELLED = 4, _("Отменено")
    ON_HOLD = 5, _("На удерживании")

# Create your models here.
class TaskPlan(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    description = models.CharField(max_length=200, blank=True, null=True)
    start_time = models.DateField()
    finish_time = models.DateField()
    duration_per_hour = models.IntegerField(default=0.0)
    duration_per_day = models.IntegerField(default=0.0)
    total_price = models.DecimalField(max_digits=1000, decimal_places=2, default=0.0)
    project = models.ForeignKey(
        ProjectPlan, on_delete=models.CASCADE, blank=True, null=True, related_name="project_plan_task",
    )

    created_by = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        blank=True,
        null=True,
        related_name="task_create",
    )
    created_at = models.DateTimeField(default=datetime.now)
    updated_by = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        blank=True,
        null=True,
        related_name="task_update",
    )
    updated_at = models.DateTimeField(blank=True, null=True)
    deleted_status = models.BooleanField(default=False)
    stage = models.ForeignKey(
        StagePlan, on_delete=models.CASCADE, blank=True, null=True
    )

    def __str__(self) -> str:
        return self.description

    class Meta:
        verbose_name = "План Задача"
        verbose_name_plural = "План Задачы"

    def process_price_task(self):
        self.duration_per_day = defining_duration_per_day(self.start_time, self.finish_time)
        self.duration_per_hour = defining_duration_per_hour(self.duration_per_day)
        self.total_price = defining_total_price(self.project.coefficient_of_project, self.duration_per_hour)
        self.save()

class TaskFact(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    description = models.CharField(max_length=200, blank=True, null=True)
    start_time = models.DateTimeField()
    finish_time = models.DateTimeField()
    task_number = models.IntegerField(blank=True, null=True)
    duration_per_hour = models.IntegerField(default=0.0)
    duration_per_day = models.IntegerField(default=0.0)
    total_price = models.DecimalField(max_digits=1000, decimal_places=2, default=0.0)
    task_plan = models.ForeignKey(
        TaskPlan, on_delete=models.CASCADE, blank=True, null=True
    )
    worker = models.ForeignKey(
        User, on_delete=models.CASCADE, blank=True, null=True
    )
    action_status = models.IntegerField(
        choices=TaskFactStatus.choices,
        default=TaskFactStatus.PLAN,
    )

    created_by = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        blank=True,
        null=True,
        related_name="fact_task_create",
    )
    created_at = models.DateTimeField(default=datetime.now)
    updated_by = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        blank=True,
        null=True,
        related_name="fact_task_update",
    )
    updated_at = models.DateTimeField(blank=True, null=True, default=datetime.now)
    deleted_status = models.BooleanField(default=False)
    stage_fact = models.ForeignKey(
        StageFact, on_delete=models.CASCADE, blank=True, null=True
    )
    project_fact = models.ForeignKey(
        ProjectFact,
        on_delete=models.CASCADE,
        blank=True,
        null=True,
        related_name="project_fact",
    )

    def __str__(self):
        return self.description

    class Meta:
        verbose_name = "Факт Задача"
        verbose_name_plural = "Факт Задачы"

    def update_fields(self, task_status, worker, fields):
        self.duration_per_hour = fields['duration_per_hour']
        self.duration_per_day = fields['duration_per_day']
        self.start_time = fields['start_time']
        self.finish_time = fields['finish_time']
        self.action_status = task_status
        self.worker = worker
        self.save()

    def process_price_task(self):
        self.duration_per_day = defining_duration_per_day(self.start_time.date(), self.finish_time.date())
        self.duration_per_hour = defining_duration_per_hour(self.duration_per_day)
        self.total_price = defining_total_price(self.project_fact.coefficient_of_project, self.duration_per_hour)
        self.save()


"""popular_repositories URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/3.1/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from .repo import views
from django.contrib import admin
from django.urls import path, re_path, include
from drf_yasg.views import get_schema_view
from drf_yasg import openapi
from rest_framework import permissions

schema_view = get_schema_view(
   openapi.Info(
      title='Popular GitHub Repositories',
      default_version='v1',
      description='This is a service for checking whether the provided GitHub repository is popular or not.',
      contact=openapi.Contact(email='hugoalexisz@hotmail.com'),
   ),
   public=True,
   permission_classes=(permissions.AllowAny,),
)

urlpatterns = [
    path('admin/', admin.site.urls),
    path('health/', views.is_ok, name='is_ok'),
    path('popularity/', views.calculate_popularity, name='calculate_popularity'),
    re_path(r'^redoc/$', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'),
    re_path(r'^swagger/$', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
]


import os
import jinja2
import webapp2
from handlers import BaseHandler
from models import Service
from helpers import QueryHandler, ServiceHelper

JINJA_ENVIRONMENT = jinja2.Environment(
    loader=jinja2.FileSystemLoader(
        [os.path.join(os.path.dirname(__file__),"../../../templates/admin"),
         os.path.join(os.path.dirname(__file__),"../../../templates/layouts")]))

TEMPLATE = JINJA_ENVIRONMENT.get_template('edit_service.html')

class AdminServiceEditHandler(BaseHandler.BaseHandler):
  def get(self, service_id):
    role = self.session.get('role')
    user_session = self.session.get("user")

    if role != "admin" and role != "staff":
      self.redirect("/users/login?message={0}".format("You are not authorized to view this page"))
      return

    if not self.legacy:
      self.redirect("/#/services/{0}/edit".format(service_key))

    sql_statement = "SELECT * FROM service WHERE id={0}".format(service_id)

    service = QueryHandler.execute_query(sql_statement)
    if len(service) == 0:
      self.redirect("/admin?message=That service does not exist")
      return
    # raise Exception(service)

    template_values = {
      "role": self.session.get("role"),
      "user_session": user_session,
      "message": self.request.get("message"),
      "service": service[0]
    }
    language = None
    if "language" in self.request.cookies:
      language = self.request.cookies["language"]
    else:
      language = "fr"
      self.response.set_cookie("language", "fr")

    language = language.replace('"', '').replace("'", "")
    if language == "fr":

      LEGACY_TEMPLATE = JINJA_ENVIRONMENT.get_template('fr_edit_service.html')
    else:
      LEGACY_TEMPLATE = JINJA_ENVIRONMENT.get_template('edit_service.html')

    self.response.write(LEGACY_TEMPLATE.render(template_values))

  def post(self, service_id):
    role = self.session.get('role')
    user_session = self.session.get("user")

    if role != "admin":
      self.redirect("/users/login?message={0}".format("You are not authorized to view this page"))
      return

    sql_statement = """
      SELECT id FROM service WHERE id="{0}"
      """.format(service_id)
    service = QueryHandler.execute_query(sql_statement)
    if len(service) > 0:
      ServiceHelper.update_record(self, service_id)
      self.redirect("/admin/services/" + service_id + "?message=Update complete")
    else:
      self.redirect("/admin?message=Service does not exist")


"""For the purposes of this simulator, particles are objects which are rendered, and may behave in interesting ways,
but do not have mass like ForceObjects and only remain on the screen for a limited duration.

They can be used to draw debug lines, add some kind of effect, or so forth.

They are updated by the PhysicsCanvas, which they add themselves to.

To make a new particle, just extend the :class:`Particle.Particle` and overwrite the draw and transform methods.

There is no need to override the update and add_to methods.

To use a particle, initialize it, set its displacement to a vector, then call `add_to(physicsCanvas)`

"""

import Physics

import math

from tkinter import *

class Particle:
    """
    The base particle class.

    By default, for debug purposes, just shows a square at the origin that moves SE

    :param duration: The time to display the particle (s)
    :type duration: number
    """
    def __init__(self, duration=1):
        self.physics_canvas = None
        """ Particle gets a reference to PhysicsCanvas at the time add_to is called. """
        self.canvas_id = 0
        """ Id for moving on canvas """
        self.displacement = Physics.Vector(0,0)
        """ Vector from physicsCanvas origin that particle will be placed"""
        self.time_remaining = duration
        """ How much time the particle has left before it's removed from the rendered/referenced objects"""

    def update(self, interval):
        """
        Checks to see if there is time_remaining. If so, calls `self.transform`. Otherwise, removes references.

        No need to overwrite this in extending classes; overwrite `self.transform` instead.

        :param interval: Time since last update, seconds.
        :type interval: number
        """
        self.time_remaining -= interval
        if self.time_remaining <= 0:
            self.physics_canvas.canvas.delete(self.canvas_id)
            index = self.physics_canvas.particles.index(self)
            self.physics_canvas.particles.pop(index)
        else:
            self.transform(interval)

    def add_to(self, physics_canvas):
        """
        Adds this Particle to the physics canvas, appending it to the list of particles to be updated and making the
        internal reference of `self.physics_canvas`.

        Afterwards, calls `self.draw`

        No need to overwrite this in extending classes; overwrite `self.draw` instead.

        :param physics_canvas:
        :return:
        """
        physics_canvas.particles.append(self)
        self.physics_canvas = physics_canvas
        self.draw()

    def draw(self):
        """
        Draws Particle on the physics canvas.

        Overwrite this method on inheriting particles.
        """
        x = self.displacement.x + self.physics_canvas.origin_x
        y = self.displacement.y + self.physics_canvas.origin_y
        self.canvas_id = self.physics_canvas.canvas.create_rectangle(x-10,y+10,x+10,y-10, fill='black')  # e.g.

    def transform(self, interval):
        """
        Called by update. Changes the particle in some way, i.e. movement, scale, etc.

        Overwrite this method on inheriting particles

        :param interval: interval, seconds
        :type interval: number
        """
        c = self.physics_canvas.canvas
        c.scale(self.canvas_id, 0,1, 1.01, 1.01)

class Triangle(Particle):
    """
    Probably can remove this - didn't wind up using

    """
    def __init__(self, duration, x1, y1, x2, y2, x3, y3, color='blue'):
        Particle.__init__(self, duration)
        self.points = (x1, y1, x2, y2, x3, y3)
        self.color = color
        self.displacement = Physics.Vector(0, 0)

    def draw(self):
        x1, y1, x2, y2, x3, y3 = self.points
        self.canvas_id = self.physics_canvas.canvas.create_polygon(x1,y1,x2,y2,x3,y3,0,0, fill=self.color)
        origin_x = self.physics_canvas.origin_x
        origin_y = self.physics_canvas.origin_y
        self.physics_canvas.canvas.moveto(self.canvas_id, self.displacement.x + origin_x, origin_y - self.displacement.y)

    def transform(self, interval):
        pass

class Line(Particle):
    """
    Draws a Line on the canvas from a vector.

    Only required params are duration and vector.

    :param duration: How long to stay on screen (seconds)
    :type duration: number
    :param vector: A vector to calculate the line from
    :type vector: :class:`Physics.Vector`
    :param color: Color of the line, default is gray-purple
    :type color: str
    :param width: Width of line, default is 1
    :type width: int

    """
    def __init__(self, duration, vector, color='#55443C', width=1, arrow=LAST):
        Particle.__init__(self, duration)
        self.vector = vector
        self.color = color
        self.width=width
        self.displacement = Physics.Vector(0, 0)
        self.arrow = arrow

    def draw(self):
        x1 = 0
        x2 = x1 + self.vector.x
        y1 = 0
        y2 = y1 + self.vector.y
        canvas = self.physics_canvas.canvas
        self.canvas_id = canvas.create_line(x1, y1, x2, -y2, fill=self.color, width=self.width, arrow=self.arrow)
        origin_x = self.physics_canvas.origin_x
        origin_y = self.physics_canvas.origin_y
        self.physics_canvas.canvas.move(self.canvas_id, self.displacement.x + origin_x, origin_y - self.displacement.y)

    def transform(self, interval):
        pass


# -*- coding: utf-8 -*-
# (c) 2009-2023 Martin Wendt and contributors; see WsgiDAV https://github.com/mar10/wsgidav
# Licensed under the MIT license:
# http://www.opensource.org/licenses/mit-license.php
"""Unit test for lock_manager.py"""
import os
import sys
import unittest
from tempfile import gettempdir
from time import sleep

from wsgidav.dav_error import DAVError
from wsgidav.lock_man import lock_manager, lock_storage

try:
    from wsgidav.lock_man.lock_storage_redis import LockStorageRedis
except ImportError:
    LockStorageRedis = None

# ========================================================================
# BasicTest
# ========================================================================

class BasicTest(unittest.TestCase):
    """Test lock_manager.LockManager()."""

    principal = "Joe Tester"
    owner = b"joe.tester@example.com"
    root = "/dav/res"
    timeout = 10 * 60  # Default lock timeout 10 minutes

    #     @classmethod
    #     def suite(cls):
    #         """Return test case suite (so we can control the order)."""
    #         suite = TestSuite()
    #         suite.addTest(cls("testPreconditions"))
    # #        suite.addTest(cls("testOpen"))
    #         suite.addTest(cls("testValidation"))
    #         suite.addTest(cls("testLock"))
    #         suite.addTest(cls("testTimeout"))
    #         suite.addTest(cls("testConflict"))
    #         return suite

    def setUp(self):
        storage = lock_storage.LockStorageDict()
        self.lm = lock_manager.LockManager(storage)
        self.lm._verbose = 1

    def tearDown(self):
        del self.lm

    def _acquire(
        self,
        url,
        lock_type,
        lock_scope,
        lock_depth,
        lock_owner,
        timeout,
        principal,
        token_list,
    ):
        """Wrapper for lm.acquire, that returns None instead of raising DAVError."""
        try:
            return self.lm.acquire(
                url=url,
                lock_type=lock_type,
                lock_scope=lock_scope,
                lock_depth=lock_depth,
                lock_owner=lock_owner,
                timeout=timeout,
                principal=principal,
                token_list=token_list,
            )
        except DAVError:
            return None

    def _isLockDict(self, o):
        try:
            _ = o["root"]  # noqa F841
        except Exception:
            return False
        return True

    def _isLockResultOK(self, resultTupleList):
        """Return True, if result is [ (lock_dict, None) ]."""
        try:
            return (
                len(resultTupleList) == 1
                and len(resultTupleList) == 2
                and self._isLockDict(resultTupleList[0][0])
                and resultTupleList[0][1] is None
            )
        except Exception:
            return False

    def _isLockResultFault(self, lock, conflictList, status=None):
        """Return True, if it is a valid result tuple containing a DAVError."""
        try:
            if lock is not None:
                return False
            if len(conflictList) < 1:
                return False
            resultTuple = conflictList[0]
            if (
                len(resultTuple) != 2
                or not self._isLockDict(resultTuple[0])
                or not isinstance(resultTuple[1], DAVError)
            ):
                return False
            elif status and status != DAVError.value:
                return False
            return True
        except Exception:
            return False

    def testPreconditions(self):
        """Environment must be set."""
        self.assertTrue(
            __debug__, "__debug__ must be True, otherwise asserts are ignored"
        )

    #    def testOpen(self):
    #        """Lock manager should be lazy opening on first access."""
    #        lm = self.lm
    # #        assert not lm._loaded, "LM must only be opened after first access"
    #        lm._generate_lock(self.principal, "write", "exclusive", "infinity",
    #                        self.owner,
    #                        "/dav",
    #                        10)
    #        assert lm._loaded, "LM must be opened after first access"

    def testValidation(self):
        """Lock manager should raise errors on bad args."""
        lm = self.lm
        self.assertRaises(
            AssertionError,
            lm._generate_lock,
            lm,
            "writeX",
            "exclusive",
            "infinity",
            self.owner,
            self.root,
            self.timeout,
        )
        self.assertRaises(
            AssertionError,
            lm._generate_lock,
            lm,
            "write",
            "exclusiveX",
            "infinity",
            self.owner,
            self.root,
            self.timeout,
        )
        self.assertRaises(
            AssertionError,
            lm._generate_lock,
            lm,
            "write",
            "exclusive",
            "infinityX",
            self.owner,
            self.root,
            self.timeout,
        )
        self.assertRaises(
            AssertionError,
            lm._generate_lock,
            lm,
            "write",
            "exclusive",
            "infinity",
            None,
            self.root,
            self.timeout,
        )
        self.assertRaises(
            AssertionError,
            lm._generate_lock,
            lm,
            "write",
            "exclusive",
            "infinity",
            self.owner,
            None,
            self.timeout,
        )

    #        assert lm._dict is None, "No locks should have been created by this test"

    def testLock(self):
        """Lock manager should create and find locks."""
        lm = self.lm
        url = "/dav/res"
        # Create a new lock
        lock_dict = lm._generate_lock(
            self.principal,
            "write",
            "exclusive",
            "infinity",
            self.owner,
            url,
            self.timeout,
        )
        # Check returned dictionary
        assert lock_dict is not None
        assert lock_dict["root"] == url
        assert lock_dict["type"] == "write"
        assert lock_dict["scope"] == "exclusive"
        assert lock_dict["depth"] == "infinity"
        assert lock_dict["owner"] == self.owner
        assert lock_dict["principal"] == self.principal

        # Test lookup
        tok = lock_dict.get("token")
        assert lm.get_lock(tok, key="root") == url

        lock_dict = lm.get_lock(tok)

        assert lock_dict is not None
        assert lock_dict["root"] == url
        assert lock_dict["type"] == "write"
        assert lock_dict["scope"] == "exclusive"
        assert lock_dict["depth"] == "infinity"
        assert lock_dict["owner"] == self.owner
        assert lock_dict["principal"] == self.principal

        # We locked "/dav/res", did we?
        assert lm.is_token_locked_by_user(tok, self.principal)

        #        res = lm.get_url_lock_list(url, self.principal)
        res = lm.get_url_lock_list(url)
        self.assertEqual(len(res), 1)

        #        res = lm.get_url_lock_list(url, "another user")
        #        assert len(res) == 0

        assert lm.is_url_locked_by_token(
            "/dav/res", tok
        ), "url not directly locked by lock_token."
        assert lm.is_url_locked_by_token(
            "/dav/res/", tok
        ), "url not directly locked by lock_token."
        assert lm.is_url_locked_by_token(
            "/dav/res/sub", tok
        ), "child url not indirectly locked"

        assert not lm.is_url_locked_by_token(
            "/dav/ressub", tok
        ), "non-child url reported as locked"
        assert not lm.is_url_locked_by_token(
            "/dav", tok
        ), "parent url reported as locked"
        assert not lm.is_url_locked_by_token(
            "/dav/", tok
        ), "parent url reported as locked"

    def testTimeout(self):
        """Locks should be purged after expiration date."""
        lm = self.lm
        timeout = 1
        lock_dict = lm._generate_lock(
            self.principal,
            "write",
            "exclusive",
            "infinity",
            self.owner,
            self.root,
            timeout,
        )

        assert lock_dict is not None
        tok = lock_dict.get("token")
        assert lm.get_lock(tok, key="root") == self.root

        sleep(timeout - 0.5)
        lock_dict = lm.get_lock(tok)
        assert lock_dict is not None, "Lock expired too early"

        sleep(1)
        lock_dict = lm.get_lock(tok)
        assert lock_dict is None, "Lock has not expired"

    def testConflict(self):
        """Locks should prevent conflicts."""
        token_list = []

        # Create a lock for '/dav/res/'
        lock = self._acquire(
            "/dav/res/",
            "write",
            "exclusive",
            "infinity",
            self.owner,
            self.timeout,
            self.principal,
            token_list,
        )
        assert lock, "Could not acquire lock"

        # Try to lock with a slightly different URL (without trailing '/')
        lock = self._acquire(
            "/dav/res",
            "write",
            "exclusive",
            "infinity",
            self.owner,
            self.timeout,
            "another principal",
            token_list,
        )
        assert lock is None, "Could acquire a conflicting lock"

        # Try to lock with another principal
        lock = self._acquire(
            "/dav/res/",
            "write",
            "exclusive",
            "infinity",
            self.owner,
            self.timeout,
            "another principal",
            token_list,
        )
        assert lock is None, "Could acquire a conflicting lock"

        # Try to lock child with another principal
        lock = self._acquire(
            "/dav/res/sub",
            "write",
            "exclusive",
            "infinity",
            self.owner,
            self.timeout,
            "another principal",
            token_list,
        )
        assert lock is None, "Could acquire a conflicting child lock"

        # Try to lock parent with same principal
        lock = self._acquire(
            "/dav/",
            "write",
            "exclusive",
            "infinity",
            self.owner,
            self.timeout,
            self.principal,
            token_list,
        )
        assert lock is None, "Could acquire a conflicting parent lock"

        # Try to lock child with same principal
        lock = self._acquire(
            "/dav/res/sub",
            "write",
            "exclusive",
            "infinity",
            self.owner,
            self.timeout,
            self.principal,
            token_list,
        )
        assert lock is None, "Could acquire a conflicting child lock (same principal)"

# ========================================================================
# ShelveTest
# ========================================================================
class ShelveTest(BasicTest):
    """Test lock_manager.ShelveLockManager()."""

    def setUp(self):
        if sys.version_info < (3, 0):
            modifier = "-py2"  # shelve formats are incompatible
        else:
            modifier = "-py3"
        self.path = os.path.join(
            gettempdir(), "wsgidav-locks{}.shelve".format(modifier)
        )
        storage = lock_storage.LockStorageShelve(self.path)
        self.lm = lock_manager.LockManager(storage)
        self.lm._verbose = 2

    def tearDown(self):
        self.lm.storage.clear()
        self.lm = None
        # Note: os.remove(self.path) does not work, because Shelve may append
        # a file extension.

#         if os.path.exists(self.path):
#             os.remove(self.path)

class RedisTest(BasicTest):
    _redis_connect_failed = None

    def setUp(self):
        if LockStorageRedis is None:
            raise unittest.SkipTest("Test redis installed")
        if RedisTest._redis_connect_failed:
            raise unittest.SkipTest("Test requires a running redis instance (again)")

        try:
            import redis

            r = redis.Redis()
            r.ping()
        except redis.exceptions.ConnectionError:
            RedisTest._redis_connect_failed = True
            raise unittest.SkipTest("Test requires a running redis instance")
        storage = LockStorageRedis()
        self.lm = lock_manager.LockManager(storage)
        self.lm._verbose = 2

    def tearDown(self):
        self.lm.storage.clear()
        self.lm = None

# ========================================================================
# suite
# ========================================================================
# def suite():
#     """Return suites of all test cases."""
#     return TestSuite([BasicTest.suite(),
#                       ShelveTest.suite(),
#                       ])

if __name__ == "__main__":
    unittest.main()
#     suite = suite()
#     TextTestRunner(descriptions=0, verbosity=2).run(suite)


import sys
import gameLib as game
import ABGame
import ABOpening

# 20      21        22
#   17    18    19
#      14 15 16
# 8  9 10    11 12  13
#       6     7
#    3     4     5
# 0        1         2

def available(board):
    loc1 = []
    loc2 = []
    for i in range(23):
        if board[i]=='B':
            loc1.append(i)
            for j in game.neighbors(i):
                if board[j]=='x':
                    loc2.append(j)
    return [loc1,set(loc2)]

def candidate(board,loc):
    locations = []
    if board[loc]=='B':
        for j in game.neighbors(loc):
            if board[j]=='x':
                locations.append(j)
    return locations

if __name__ == "__main__":
    print("enter difficulty (1~4)")
    depth = int(input())
    board = ['x' for _ in range(23)]
    score = 0
    print("opening game")
    for _ in range(9):
        print("AI turn",score)
        res = ABOpening.MaxMin(game.getInverse(board),depth,-float('inf'),float('inf'))
        score = ABOpening.static(board)
        board = res[-1]
        game.show(board)
        print("Your turn",score)
        loc = int(input())
        board[loc] = 'B'
        game.show(board)
        if game.closeMill(loc,board,turn='B'):
            print("Pick the location to remove")
            loc = int(input())
            board[loc] = 'x'
        score = ABOpening.static(board)
        game.show(board)

    #board = game.readBoard("board3.txt")
    print("mid game")
    while abs(score)!=10000:
        print("AI turn",score)
        res = ABGame.MidMaxMin(game.getInverse(board),depth,-float('inf'),float('inf'))
        score = ABGame.static(board)
        board = res[-1]
        game.show(board)
        print("Your turn",score)
        print("Choose loc from : ", available(board))
        print("From",end=' ')
        loc = int(input())
        candidate(board,loc)
        print("to", end=' ' )
        to = int(input())

        board[loc] = 'x'
        board[to] = 'B'
        game.show(board)
        if game.closeMill(to,board,turn='B'):
            print("Pick the location to remove")
            loc = int(input())
            board[loc] = 'x'
        score = ABGame.static(board)
        game.show(board)

    print(score)


"""Infact URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/3.1/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
from main.views import *
from accounts.views import *

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', dashboard_view, name='dashboard'),
    path('categories/', categories_view, name='categories'),
    path('game/<int:category_id>/', game_view, name='game'),
    path('signup/', signup_view, name='sign up'),
    path('login/', login_view, name='login'),
    path('logout/', logout_view),
    path('white-heart/', like_view)
]


class Solution:
    def findKthPositive(self, arr: List[int], k: int) -> int:
      b = 0
      for i in arr:
        s = i - b - 1
        k -= s
        if k <= 0:
          return i + k -1
        b = i

      return arr[-1] + k


#!/usr/bin/python3

import sys

def main():
    print('Number of arguments:', len(sys.argv), 'arguments.')
    print('Argument List:', sys.argv)

    f = open(sys.argv[1], "r", encoding="utf8")
    all_data = ""
    c=0
    state=-1
    for x in f.readlines():
        all_data += x
    f.close()

    x = split(["\n"], all_data)
    x = divide_chunks(x, 1000)
    print(len(x))
    print(type(x))
    f_name = split(["."], sys.argv[1])

    print(f_name[0] + "_1." + f_name[1])
    num=1
    for txt in x:
        f = open(f_name[0] + "_" + str(num) + "." + f_name[1], "w", encoding="utf8")
        print(type(txt))
        #print(txt)
        for t in txt:
            #print(t)
            f.writelines(t + "\n")
        num=num+1
        f.close()

def split(delimiters, string, maxsplit=0):
    import re
    regexPattern = '|'.join(map(re.escape, delimiters))
    return re.split(regexPattern, string, maxsplit)

def divide_chunks(l, n):
    # looping till length l
    k = []
    for i in range(0, len(l), n):
        k.append(l[i:i + n])
    return k

if __name__ == '__main__':
    main()


from Unit import*
import Game_Engine
import Renderer
import UI
from Sound import *

lask_key = None
class Isaac(Unit):      #sub class
    def __init__(self):
        Unit.__init__(self)
        self.tear_size = 1.0
        self.unbeatable_time = 0.0
        self.unbeatable      = False

        self.team = UnitTeam.Ally

        self.way = Way.Down
        self.image_y = 0
        self.next_way = self.way

        self.game_engine = Game_Engine.GameEngine()
        self.sound_manager = SoundManager()
        self.sound_manager.add_sound('resource/sound/tear_shot.wav', SoundType.EFFECT, SoundKey.EFFECT_Normal_Tear)
        self.UI = UI.UI_Manager()

        self.head_renderer = Renderer.Renderer('resource/character/normal_head.png', 54, 40, 2, 0, 0, 1, True)
        self.body_renderer = Renderer.Renderer('resource/character/normal_body.png', 43, 24, 10, 0, 0, 2, False)

    def draw(self, frame_time):
        self.body_renderer.draw(self.x, self.y - 20 - self.image_y)

        self.head_renderer.draw(self.x, self.y)

        self.tear_manager.draw()
        self.UI.draw(frame_time, self)

    def update(self,frame_time):
        self.time_elapsed += frame_time

        self.tear_manager.update(frame_time)
        self.tear_manager.check_frame_out()
        self.tear_manager.check_disappear()

        self.update_unbeatable(frame_time)
        self.state_handler[self.state](frame_time)

    def handle_event(self, event):
        global last_key

        if event.type == SDL_KEYDOWN:
            if event.key != None:
                last_key = event.key

            if event.key in (SDLK_d,):
                self.change_way(Way.Right)
                self.next_way = Way.Right
                self.change_state(UnitState.Move)

            elif event.key in (SDLK_a,):
                self.change_way(Way.Left)
                self.next_way = Way.Left
                self.change_state(UnitState.Move)

            elif event.key in (SDLK_w,):
                self.change_way(Way.Up)
                self.next_way = Way.Up
                self.change_state(UnitState.Move)

            elif event.key in (SDLK_s,):
                self.change_way(Way.Down)
                self.next_way = Way.Down
                self.change_state(UnitState.Move)

            elif event.key == SDLK_UP:
                self.change_way(Way.Up)
                self.change_state(UnitState.Attack)
                self.shot_tear()

            elif event.key == SDLK_DOWN:
                self.change_way(Way.Down)
                self.change_state(UnitState.Attack)
                self.shot_tear()

            elif event.key == SDLK_LEFT:
                self.change_way(Way.Left)
                self.change_state(UnitState.Attack)
                self.shot_tear()

            elif event.key == SDLK_RIGHT:
                self.change_way(Way.Right)
                self.change_state(UnitState.Attack)
                self.shot_tear()

        elif event.type == SDL_KEYUP:
            if (event.key, self.way) == (SDLK_w, Way.Up):
                self.change_state(UnitState.Stop)
            elif (event.key, self.way) == (SDLK_a, Way.Left):
                self.change_state(UnitState.Stop)
            elif (event.key, self.way) == (SDLK_s, Way.Down):
                self.change_state(UnitState.Stop)
            elif (event.key, self.way) == (SDLK_d, Way.Right):
                self.change_state(UnitState.Stop)

    def update_unbeatable(self, frame_time):
        if self.unbeatable:
            self.unbeatable_time += frame_time
            if self.unbeatable_time < 0.5:
                self.head_renderer.set_alpha((1 - self.unbeatable_time * 2))
                self.body_renderer.set_alpha((1 - self.unbeatable_time * 2))
            elif 0.5 <= self.unbeatable_time and 1.0 > self.unbeatable_time:
                self.head_renderer.set_alpha(self.unbeatable_time)
                self.body_renderer.set_alpha(self.unbeatable_time)
            else:
                self.unbeatable = False
                self.unbeatable_time = 0.0

    def get_collision_box(self):
        return self.x - 27, self.y - 28, self.x + 27, self.y + 24

    def change_type(self, item_type):
        #self, image_path, width, height, max_frame_x, max_frame_y = 0, frameX = 0, frameY = 0
        if item_type == ItemType.CommonCold:
            self.head_renderer.change_image('resource/character/common_cold_head.png', 53, 42, 2, 0, 0, 3 - self.way)
            self.body_renderer.change_image('resource/character/common_cold_body.png', 43, 26, 10, 0, 0,self.way)
            self.image_y = 0
            self.tear_size = 1
            self.tear_type = TearType.Commond_Cold

        elif item_type == ItemType.Martyr:
            self.head_renderer.change_image('resource/character/martyr_head.png', 54, 50, 2, 0, 0,  3 - self.way)
            self.body_renderer.change_image('resource/character/normal_body.png', 43, 24, 10, 0, 0,  self.way)
            self.image_y = 5
            self.tear_size = 1.5
            self.tear_type = TearType.Normal

        elif item_type == ItemType.BloodBag:
            self.head_renderer.change_image('resource/character/blood_bag_head.png', 54, 40, 2, 0, 0, 3 - self.way)
            self.body_renderer.change_image('resource/character/normal_body.png', 43, 24, 10, 0, 0,   self.way)
            self.image_y = 0
            self.tear_size = 1
            self.tear_type = TearType.BloodBag

    def change_way(self, way):
        self.way = way
        self.delay = 0

        self.head_renderer.change_frameX(0)
        self.head_renderer.change_frameY(3 - self.way) #3 means WayCount not including diagonal way

        self.body_renderer.change_frameX(0)
        self.body_renderer.change_frameY(self.way)

    def change_state(self, state):
        self.state = state
        self.change_way(self.way)
        self.delay = 0
        self.time_elapsed = 0
        self.head_renderer.set_alpha(1)
        self.body_renderer.set_alpha(1)

    def get_instance(self, name):
        if name == 'Isaac':
            return True
        return False

    def shot_tear(self):
        self.tear_manager.append()
        self.sound_manager.play(SoundKey.EFFECT_Normal_Tear)

    def change_room(self, way):
        if way == Way.Left:
            self.x = 810
        elif way == Way.Right:
            self.x = 150
        elif way == Way.Up:
            self.y = 130
        elif way == Way.Down:
            self.y = 450

        self.tear_manager.clear()

    def check_collision(self, x1, x2, y1, y2):
        if self.unbeatable:
            return False

        if ((x1 < self.x  and x2 > self.x)
            and (y1 < self.y and y2 > self.y)):
            return True

        return False

    def init_position(self):
        self.x, self.y = 490, 280

    def undo_move(self):
        if self.way in (Way.Down, Way.Up):
            self.x, self.y = self.game_engine.undo_move(self.x, self.y, Game_Engine.MovePattern.MoveY)
        elif self.way in (Way.Right, Way.Left):
            self.x, self.y = self.game_engine.undo_move(self.x, self.y, Game_Engine.MovePattern.MoveX)

    def handle_attack(self, frame_time, unit = None):
        self.delay += 1

        self.head_renderer.update()
        if self.delay >= 5:
            self.delay = 0

            if (self.head_renderer.frameX % 2) == 0:
                self.change_way(self.way)
                self.change_state(UnitState.Stop)

    def handle_attacked(self, frame_time, unit = None):
        self.unbeatable = True
        if self.time_elapsed >= 1.0:
            self.unbeatable = False
            self.change_state(UnitState.Idle)
            return

    def handle_move(self, frame_time, unit = None):
        self.body_renderer.update()
        self.x, self.y = self.game_engine.move(frame_time, self.speed, self.x, self.y, self.way)


from django.db import models
from django.db.models.aggregates import Sum
from django.db.models.functions.comparison import Coalesce
from django.db.models.query_utils import Q
from typing import List
from django.db.models import Model
from django.db.models.fields.reverse_related import (
    ManyToOneRel,
    ForeignObjectRel,
)

def add_sum(response, sum_fields, qs, page=None):
    """
        Adds sum of fields in sum_fields to `response.data[sum_field]`
        Can add page_sum too
        runs one query with qs for sum and calculate page sum in python
    """

    aggregates = {}
    for field in sum_fields:
        aggregates[field] = Coalesce(Sum(field), 0)
    response.data['sum'] = qs.aggregate(**aggregates)

    if page:
        page_sum = {}
        for field in sum_fields:
            page_sum[field] = 0
            for item in page:
                page_sum[field] += getattr(item, field)
        response.data['page_sum'] = page_sum

def get_deep_sum(field, filters, related_name='children', depth=4):
    """
        Ex: sum of bed for each level of account tree
    """

    if depth == 1:
        next_depth = 0
    else:
        next_filters = {}
        for key in filters.keys():
            next_filters["{}__{}".format(related_name, key)] = filters[key]

        next_depth = get_deep_sum("{}__{}".format(related_name, field), next_filters, related_name, depth - 1)

    return Coalesce(
        Sum(field, filter=Q(**filters)),
        next_depth
    )

def get_all_relations(model: Model) -> List[ForeignObjectRel]:
    """
    Return all Many to One Relation to point to the given model
    """
    result: List[ForeignObjectRel] = []
    for field in model._meta.get_fields(include_hidden=True):
        if isinstance(field, ManyToOneRel):
            result.append(field)
    return result

def delete_object_recursively(obj: Model, d=0):
    for field in get_all_relations(obj):
        field: ManyToOneRel

        if field.on_delete == models.CASCADE or field.on_delete == models.PROTECT:
            target_model: Model = field.related_model
            target_field: str = field.remote_field.name

            print('- ' * d, target_field, ':')

            related_objs = target_model.objects.filter(
                **{target_field: obj}
            )
            for related_obj in related_objs:
                delete_object_recursively(related_obj, d=d + 1)

    obj.delete()


from .scraper import Scraper as default_scraper
from .parser import *

# 채널 이름 : 옹진군청보건소

#HTTP Request
'''
    @post list
    method : GET
    url_0 = https://www.ongjin.go.kr/open_content/clinic/bbs/bbsMsgList.do?bcd=notice&pgno={}
    header :
        None
'''
'''
    @post info
    method : GET
    url :
        self.channel_main_url + href
    header :
        None
'''
class Scraper(default_scraper):
    def __init__(self, session):
        super().__init__(session)
        self.channel_name = '옹진군청보건소'
        self.post_board_name = '공지사항'


'''
Closest pair problem

This returns the closest pair of numbers.

Usage:

    python closest_pair.py [size of list of numbers]

@author Ariana Fairbanks

@date August 2018
'''

import random
import sys

'''
return the distance between two parameters
'''
def distance(a,b):
    return abs(a-b)

'''
populate the array with listSize unique random numbers between 1 ... 5000
'''
def populate(listSize):
    a = []
    count = 0

    while count < listSize:
        number = random.randint(1,5000)
        if number in a:
            continue
        else:
            a.append(number)
            count += 1

    return a

'''
now determine the closest pair
using brute force algorithm
'''
def closest_pair(values):

    if len(values) < 2:
        return (0, 0)

    pt_a = values[0]
    pt_b = values[1]
    dis = abs(pt_a - pt_b)

    for i in range(len(values)):
        current_a = values[i]
        for j in range(len(values)):
            if j != i:
                current_b = values[j]
                current_dis = abs(current_a - current_b)
                if current_dis < dis:
                    dis = current_dis
                    pt_a = current_a
                    pt_b = current_b

    return (pt_a, pt_b)

'''
This behaves just like the Java main() method
'''
if __name__ == '__main__':
    if len(sys.argv) != 2:
        print('Usage Python closest_pair.py [number of points]')
        quit()
    else:
        numbers = populate(int(sys.argv[1]))

        closest = closest_pair(numbers)

        print('The closest numbers are', closest[0], 'and', closest[1])


# https://binarysearch.com/problems/Pascal's-Triangle/submissions/4441799
class Solution:
    def solve(self, n):
        pascal = [[1], [1,1]]
        i, temp = 2, []

        while i <= n:
            pascal.append(self.calc(pascal[i-1]))
            i += 1

        return pascal[n]

    def calc(self, lst):
        res = [1]
        for i in range(len(lst)-1):
            res.append(lst[i]+lst[i+1])
        res.append(1)
        return res


import sys
input = sys.stdin.readline
n, l = map(int, input().split())

x = n/l - (l-1)/2
while int(x) != x and int(x) >= 0 and l < 101:
    l += 1
    x = n/l - (l-1)/2

x = int(x)
if x >= 0 and l < 101:
    print(*range(x, x+l))
else:
    print(-1)


## Idea is to perform binary search and check which part (left or right) is sorted and accordingly update the left and right indexes

class Solution:
    def search(self, nums: List[int], target: int) -> int:

        l = 0
        r = len(nums) - 1

        while l<=r:

            mid = (l+r) // 2
            if nums[mid] == target:
                return mid
            print(mid)
            if nums[l]<= nums[mid]:

                if target >= nums[l] and target < nums[mid]:
                    r = mid - 1
                else:
                    l = mid + 1
            else:
                if target > nums[mid] and target <= nums[r]:
                    l = mid + 1
                else:
                    r = mid - 1
        return -1


from bs4 import BeautifulSoup
import requests

# Function to extract Product Title
def get_title(soup):
    try:
        # Outer Tag Object
        title = soup.find("span", attrs={"id": 'productTitle'})

        # Inner NavigableString Object
        title_value = title.string

        # Title as a string value
        title_string = title_value.strip()

    except AttributeError:
        title_string = ""

    return title_string

# Function to extract Product Price
def get_price(soup):
    try:
        price = soup.find("span", class_='a-offscreen').string.strip()

    except AttributeError:
        price = ""

    return price

def get_weight(soup):
    try:
        weight = soup.find("span", class_='a-size-base prodDetAttrValue').string.strip()

    except AttributeError:
        weight = ""

    return weight

if __name__ == '__main__':
    # Headers for request
    HEADERS = ({'User-Agent':
                    'Chrome/44.0.2403.157 Safari/537.36',
                'Accept-Language': 'en-US, en;q=0.5'})

    # The webpage URL
    URL = "https://www.amazon.com/Callaway-Driver-Ventus-Regular-Degrees/dp/B09RB45J8K/ref=sr_1_13?crid=1490WB2GFOO09&keywords=50%2Bgrams&qid=1668884457&sprefix=50%2Bgram%2Caps%2C85&sr=8-13&th=1"

    # HTTP Request
    webpage = requests.get(URL, headers=HEADERS)

    # Soup Object containing all data
    soup = BeautifulSoup(webpage.content, "lxml")

    # Function calls to display all necessary product information
    print("Product Title =", get_title(soup))
    print("Product Price =", get_price(soup))
    print("Product Weight =", get_weight(soup))

    print()
    print()


import numpy as np
from .tcp_client_server import TCPServer
from .serialization import serialize, deserialize

def string_to_obs(strings, obs_shapes):
    """ Convert strings back to observations (or states).

    Parameters
    ----------
    strings: list of strings [str_1, ..., str_n]
        which corresponds to the encoded observations (or states)
    obs_shapes: list of tuples [obs_shape_1, ..., obs_shape_n]
        shapes of corresponding observations (or states)

    Returns
    -------
    obs_str: list of np.arrays [obs_1, ..., obs_n]
        which corresponds to the original observations (or states)
        each np.array obs_i has shape (batch_size) + obs_shape_i
    """
    obs_str = []
    for i, str_ in enumerate(strings):
        obs = np.frombuffer(str_, dtype=np.float32)
        obs_str.append(obs.reshape((-1,)+obs_shapes[i]))
    return obs_str

def req_to_episode(req, obs_shapes):
    """ Preprocess deserealized request to obtain episode.
    """
    observations = string_to_obs(req["observations"], obs_shapes)
    actions = np.array(req["actions"], dtype=np.float32)
    rewards = np.array(req["rewards"], dtype=np.float32)
    dones = np.array(req["dones"], dtype=np.bool)
    return [observations, actions, rewards, dones]

class RLServerAPI:

    def __init__(self, num_clients, observation_shapes, state_shapes,
                 ip_address="0.0.0.0", init_port=8777, network_timeout=120):
        """ Class for RL Server which interacts with multiple RL Clients.

        Parameters
        ----------
        num_clients: int
            maximal number of clients
        observation_shapes: list of tuples [obs_shape_1, ..., obs_shape_n]
            which corresponds to observations" shapes
        state_shapes: list of tuples [state_shape_1, ..., state_shape_n]
            which corresponds to states" shapes
        ip_address: str
            ip address of the server
        init_port: int
            port number of the first client, all clients are assumed to be
            connected via consecutive port numbers
            [first_client_port, first_client_port+1, ...]
        network_timeout: int
            network timeout
        """

        self._num_clients = num_clients
        self._observation_shapes = observation_shapes
        self._state_shapes = state_shapes
        self._ip_address = ip_address
        self._init_port = init_port
        self._timeout = network_timeout

    def set_act_batch_callback(self, callback):
        self._act_batch_callback = callback

    def set_store_episode_callback(self, callback):
        self._store_episode_callback = callback

    def start_server(self):
        for i in range(self._num_clients):
            server = TCPServer(self._ip_address,
                               self._init_port+i,
                               self._timeout)
            server.listen(self.agent_listener)

    def agent_listener(self, request):

        req = deserialize(request)
        method = req["method"]

        if method == "act_batch":
            states = string_to_obs(req["states"], self._state_shapes)
            mode = req["mode"]
            response = self._act_batch_callback(states, mode)

        elif method == "store_episode":
            episode = req_to_episode(req, self._observation_shapes)
            self._store_episode_callback(episode)
            response = ""

        return serialize(response)


"""FMA helps us find the collective motion of biomolecules correlated to
a scalar functional quantity of interest. Detailed information about the
method can be found in the following article:

Detection of Functional Modes in Protein Dynamics
J. S. Hub, B. L. de Groot
doi:10.1371/journal.pcbi.1000480

Side note: Notation regarding PCA in the following code is different
from the notation used in the article. The article denotes the vectors
pointing in the direction of maximal variance e_i and the projections
onto these vectors as PC_i. In the following code and comments I denote
the vector pointing in the direction of maximal variance as
PC - principal component and I do not use a special term for the
projections onto these vectors. This notation should be consistent with
that used in the MDAnalysis documentation. """

import MDAnalysis as mda
import numpy as np

def _extract_trj(aligned_u):
    """
    Extract the trajectory from the universe object into a numpy array
    and calculate the mean structure of this trajectory.

    Parameters:

        aligned_u (object): Universe object created from the
        aligned trajectories.

    Returns:

        xyz_t (array (n_frames, 3 * n_atoms)): Trajectory extracted into
        an array.
    """

    trj = aligned_u.trajectory
    atomgroup = aligned_u.select_atoms("all")

    n_frames = len(trj)
    n_atoms = len(aligned_u.atoms)

    # initialize empty array
    xyz_t = np.empty((n_frames, 3 * n_atoms))

    # fill array, for every frame insert structure coordinates
    # ts is just to loop through the trajectory, frame is the actual
    # frame number
    for frame, ts in enumerate(trj):
        xyz_t[frame, :] = atomgroup.positions.ravel()

    return xyz_t

def _get_projs(xyz_t, a):
    """
    Calculate projections of trajectory onto MCM vector a.

    Parameters:

        xyz_t (array (n_frames, 3 * n_atoms)): Trajectory extracted into
        an array.

        a (array (3 * n_atoms, )): The vector pointing in the direction
        of MCM.

    Returns:

        pa_t (array (n_frames, )): Projections onto the vector a.

    """

    n_frames = xyz_t.shape[0]

    # average over time
    xyz_mean = np.mean(xyz_t, axis=0)
    xyz_t_centered = np.subtract(xyz_t, xyz_mean)

    # initialize empty array
    pa_t = np.empty((n_frames,))

    for frame in range(n_frames):
        # fill projs array
        # project the trajectory onto the vector a
        pa_t[frame] = np.dot(a, xyz_t_centered[frame, :])

    return pa_t

def _get_param_values(pa_t, n_ani_frames):
    """
    Calculate parameter values for creating animations.

        Parameters:

            pa_t (array (n_frames, )): Projections onto the vector a.

            n_ani_frames (int): Number of frames for animation.

        Returns:

            param_values (array (len(param_values, )): Parameter
            values used to create animations of MCM and ewMCM.

        """

    # calculate parameter values by creating an equally spaced array
    # from min to max of the projections onto a
    param_values = np.linspace(min(pa_t), max(pa_t), n_ani_frames)

    return param_values

def get_alpha_beta_and_a(pc_object, aligned_u_train, f_train, n_pcs,
                         mutual_information=False):
    """
    Calculates the vector a which point in the direction of MCM.

    Parameters:

        pc_object (object): MDAnalysis object which contains all
        relevant outputs from PCA.

        aligned_u_train (object): Universe object created from
        the aligned trajectories. Training subset.

        f_train (array (n_frames_train, )):   The functional
        quantity related to the motion of the biomolecule. Training
        subset.

        n_pcs (int): Number of PCs describing a large enough percentage
        of total variance.

        mutual_information (bool, optional, default=False): If True, use mutual
        information as a measure of correlation of f and pa.

    Returns:

        alpha (array (n_pcs, )): Coefficients representing the weights
        of PCs in the vector a (normalized).

        beta (array (n_pcs, )): Coefficients representing the weights
        of PCs in the vector a (not normalized).

        a (array (3 * n_atoms, )): The vector pointing in the direction
        of MCM.
    """

    # project the selection onto a subset of PCs
    projs_subset = pc_object.transform(
        aligned_u_train.select_atoms("all"), n_components=n_pcs)

    # extract principal component array from pc_object
    pcs_subset = pc_object.p_components[:, :n_pcs]

    # calculate the covariance matrix of the projections:
    # C_ij = cov(p_i, p_j)
    C = np.cov(projs_subset.T)

    # covariance vector of projections onto PCs and the functional
    # quantity f
    cov_f = np.empty((n_pcs,))
    for pc in range(n_pcs):
        cov_f[pc] = np.cov(projs_subset.T[pc], f_train)[0, 1]

    # equation 5 in the article
    beta = np.linalg.solve(C, cov_f)
    alpha = beta / np.linalg.norm(beta)
    a = np.matmul(pcs_subset, alpha)

    if mutual_information:

        a0 = a
        alpha0 = alpha

    return alpha, beta, a

def make_mcm_ani(aligned_u_train, a, ani_path, n_ani_frames=100):
    """
    Creates an animation of MCM. Sometimes this motion is very
    indistinct when vector a points in the direction of a barrier in the
    energy landscape (see figure 1 in the article).

    Parameters:

        aligned_u_train (object): Universe object created from
        the aligned trajectories. Training subset.

        a (array (3 * n_atoms, )): The vector pointing in the direction
        of MCM.

        ani_path (string): Path to and name of the animation
        without file extension.

        n_ani_frames (int): Number of frames for animation.
    """

    # extract trajectory into array
    xyz_t = _extract_trj(aligned_u_train)
    # average over time
    xyz_mean = np.mean(xyz_t, axis=0)
    pa_t = _get_projs(xyz_t, a)
    # calculate parameter values
    param_values = _get_param_values(pa_t, n_ani_frames)
    n_atoms = len(aligned_u_train.atoms)

    # initialize empty array
    mcm = np.empty((n_ani_frames, n_atoms, 3))

    for frame in range(n_ani_frames):
        # fill animation trajectory array
        # add vector a multiplied by a changing parameter to an average
        # structure
        # also reshape to visualise in 3D space
        mcm[frame, :, :] = np.reshape(xyz_mean + a * param_values[frame],
                                      (n_atoms, 3))

    ref_selection = aligned_u_train.select_atoms("all")
    # create universe which has all the information about the topology
    # of the system
    ani_u = mda.Merge(ref_selection)
    # load in the animation trajectory from an array
    # fac means frames, atoms, coordinates (order of the array
    # dimensions)
    ani_u = ani_u.load_new(mcm, order="fac")
    ani_selection = ani_u.select_atoms("all")
    # write it out into .pdb and .xtc files so it can be visualized in
    # VMD
    ani_selection.write(f"{ani_path}.pdb")
    ani_selection.write(f"{ani_path}.xtc", frames="all")

def get_ew_coefficients(pc_object, alpha, n_pcs):
    """
    A function to help simplify calculating the ewMCM but also needed to
    return the coefficients which can later be plotted to compare with
    alpha.

    Parameters:

        pc_object (object): MDAnalysis object which contains all
        relevant outputs from PCA.

        alpha (array (n_pcs, )): Coefficients representing the weights
        of PCs in the vector a (normalized).

        n_pcs (int): Number of PCs describing a large enough percentage
        of total variance.

    Returns:

        ew_coefficients (array (n_pcs, )): A set of coefficients to
        rescale MCM to ewMCM.
    """

    # extract variance from pc_object
    variance_subset = pc_object.variance[:n_pcs]

    # preparing variables for equation 12 to make it simpler
    alpha_var_elementwise = np.multiply(alpha, variance_subset)
    alpha_sd_elementwise = np.multiply(alpha, np.sqrt(variance_subset))

    # initialize empty array
    ew_coefficients = np.empty((n_pcs,))

    for pc in range(n_pcs):
        # part of equation 12 in the article
        ew_coefficients[pc] = (alpha_var_elementwise[pc]) / (
                np.sum(alpha_sd_elementwise ** 2))

    return ew_coefficients

def make_ew_mcm_ani(pc_object, aligned_u_train, alpha, a, n_pcs, ani_path,
                    n_ani_frames=100):
    """
    Creates an animation of ewMCM, it is a rescaled version of MCM which
    takes into account the probability of the motion.

    Parameters:

        pc_object (object): MDAnalysis object which contains all
        relevant outputs from PCA.

        aligned_u_train (object): Universe object created from
        the aligned trajectories. Training subset.

        alpha (array (n_pcs, )): Coefficients representing the weights
        of PCs in the vector a (normalized).

        a (array (3 * n_atoms, )): The vector pointing in the direction
        of MCM.

        n_pcs (int): Number of PCs describing a large enough percentage
        of total variance.

        ani_path (string): Path to and name of the animation
        without file extension.

        n_ani_frames (int): Number of frames for animation.
    """

    # extract trajectory into array
    xyz_t = _extract_trj(aligned_u_train)
    # average over time
    xyz_mean = np.mean(xyz_t, axis=0)

    n_atoms = int(np.shape(xyz_mean)[0] / 3)

    pa_t = _get_projs(xyz_t, a)
    # calculate parameter values
    param_values = _get_param_values(pa_t, n_ani_frames)

    # extract principal component array from pc_object
    pcs_subset = pc_object.p_components[:, :n_pcs]

    ew_coefficients = get_ew_coefficients(pc_object, alpha, n_pcs)

    # initialize empty array
    ew_params = np.empty((n_ani_frames, n_pcs))

    for frame in range(n_ani_frames):

        for pc in range(n_pcs):
            # rescale projections onto the vector a (ensemble weighting)
            # equation 12 in the article
            ew_params[frame, pc] = param_values[frame] * ew_coefficients[pc]

    # reshape mean coordinates back into (n_atoms, 3)
    xyz_mean = np.reshape(xyz_mean, (n_atoms, 3))
    # initialize empty array
    ew_mcm = np.empty((n_ani_frames, n_atoms, 3))

    for frame in range(n_ani_frames):
        # create ewMCM animation trajectory array, necessary to reshape
        # and add to average structure
        # described in the paragraph bellow equation 12
        flat_ew_mcm = np.matmul(pcs_subset, ew_params[frame, :])
        ew_mcm[frame, :, :] = xyz_mean + np.reshape(flat_ew_mcm, (n_atoms, 3))

    ref_selection = aligned_u_train.select_atoms("all")
    # create universe which has all the information about the topology
    # of the system
    ani_u = mda.Merge(ref_selection)
    # load in the animation trajectory from an array
    # fac means frames, atoms, coordinates
    ani_u = ani_u.load_new(ew_mcm, order="fac")
    ani_selection = ani_u.select_atoms("all")
    # write it out into .pdb and .xtc files so it can be visualized in
    # VMD
    ani_selection.write(f"{ani_path}.pdb")
    ani_selection.write(f"{ani_path}.xtc", frames="all")

def get_f_model(pc_object, aligned_u_test, beta, f_train, n_pcs):
    """
    Predicts values of f from test data based on the model created from
    training data.

    Parameters:

        pc_object (object): MDAnalysis object which contains all
        relevant outputs from PCA.

        aligned_u_test (object): Universe object created from the
        aligned trajectories. Test subset.

        beta (array (n_pcs, )): Coefficients representing the weights
        of PCs in the vector a (not normalized).

        f_train (array (n_frames_train, )):   The functional
        quantity related to the motion of the biomolecule. Training
        subset.

        n_pcs (int): Number of PCs describing a large enough percentage
        of total variance.

    Returns:

        f_model (array (n_frames_test, )): Predicted values of f.

    """

    # calculate projections of test universe
    projs_subset = pc_object.transform(aligned_u_test.select_atoms("all"),
                                       n_components=n_pcs)
    projs_centered = projs_subset - np.mean(projs_subset, axis=0)

    f_train_mean = np.mean(f_train)

    # prepare sum of products of beta_i and test projections onto PC_i
    beta_projs_t = np.matmul(projs_centered, beta)

    # equation 6 in the article
    f_model = f_train_mean + beta_projs_t

    return f_model

def get_rm_and_rc(aligned_u_train, a, f_model, f_train, f_test):
    """
    Calculates correlation coefficients R_m and R_c which are used to evaluate
    Parameters:

        aligned_u_train (object): Universe object created from the
        aligned trajectories. Training subset.

        a (array (3 * n_atoms, )): The vector pointing in the direction
        of MCM.

        f_model (array (n_frames_test, )): Predicted values of f.

        f_train (array (n_frames_train, )):   The functional
        quantity related to the motion of the biomolecule. Training
        subset.

        f_test (array (n_frames_test, )):   The functional quantity
        related to the motion of the biomolecule. Test subset.

    Returns:

        rm (float): Correlation coefficient which was maximized in the
        creation of the model (calculation of vector a). Equation 2 in
        the article.

        rc (float): Cross-validation correlation coefficient, quantifies
        correlation of predicted values of f with the real known values
        of f.

    """

    xyz_t = _extract_trj(aligned_u_train)
    pa_t = _get_projs(xyz_t, a)
    # Pearson correlation coefficients R_m and R_c
    rm = np.corrcoef(pa_t, f_train)[1, 0]
    rc = np.corrcoef(f_model, f_test)[1, 0]

    return rm, rc


import logging
from datetime import datetime

import requests
from DivvyDb.DbObjects.metric import Metric
from DivvyDb.DivvyCloudGatewayORM import DivvyCloudGatewayORM
from DivvyDb.DivvyDb import NewSession, SharedSessionScope
from DivvyJobs.schedules import LazyScheduleGoal
from DivvyPlugins.plugin_helpers import (register_job_module,
                                         unregister_job_module)
from DivvyPlugins.plugin_jobs import PluginHarvester
from DivvySession.DivvySession import EscalatePermissions
from DivvyUtils import schedule

logger = logging.getLogger('ExampleHarvest')

repos_url = "https://api.github.com/orgs/DivvyCloud/repos"
api_version = {"Accept": "application/vnd.github.v3+json"}

class SkeletonHarvester(PluginHarvester):
    """ Example skeleton for a DivvyCloud harvester

    This class inherits from PluginHarvester which implements
    a base method interface for executing a harvest job. The
    lifecycle of a job consists of:

    0) JobScheduler loading schedule interval via `get_harvest_schedule/2` and `get_template_id/2`
    1) job._setup/1
    2) job.do_harvest/1
    3) job._cleanup/1

    Python allows for additional methods to be added to the class which
    can be a convenient way to call business logic. See `repo_getter/1` and
    `make_metric/1` which abstract the read and write logic. If you wanted
    to define your own base class extension, adding methods like this which
    return None/False could be overwritten by a child class to allow for a
    single implementation of `do_harvest/1` while extending the read/write
    behavior over multiple use cases.
    """

    def __init__(self):
        super(SkeletonHarvester, self).__init__()

    def _setup(self):
        """
        Override to perform setup operations in the worker process
        """
        super(SkeletonHarvester, self)._setup()
        """
        Internally DivvyCloud uses this to initialize the generic
        interface for multiple cloud backends.

        # For example: Setup cloud gw

        self._frontend = get_cloud_type_by_organization_service_id(
            self.current_location.organization_service_id
        )
        self._backend = self._frontend.get_cloud_gw(
            self.current_location.region_name
        )

        """

    @classmethod
    def get_harvest_schedule(cls, **job_creation_kwargs):
        """ Sets frequency and worker queue """
        return LazyScheduleGoal(
            queue_name='DivvyCloudHarvest',
            schedulable=schedule.Periodic(hours=1)
        )

    @classmethod
    def get_template_id(cls, **job_creation_kwargs):
        """ This provides a unique name to the job """
        return 'github-repo-harvest'

    def repo_getter(self):
        """ My custom method for talking to Github """
        response = requests.get(repos_url, headers=api_version)
        return response.json()

    @SharedSessionScope(DivvyCloudGatewayORM)
    @EscalatePermissions()
    def do_harvest(self):
        """ Do the harvest

        While not used, the `@SharedSessionScope(DivvyCloudGatewayORM)` decorator
        is require anytime you need to access the MySQL database within a job context.

        Acquire a connection like so; `db = DivvyCloudGatewayORM()` which can be used
        to make SQLAlchemy queries like: `db.session.query(...query)`.

        While we will not use MySQL for persistence. Supposed that we wanted to track
        some numeric values over time for a resource. The Metrics table allows for
        saving those values. In this imaginary case we're not referring to actual divvy
        resources so `target_resource_id` is the fully qualified name of the git repo.

        ```
        with NewSession(DivvyCloudGatewayORM):
            db = DivvyCloudGatewayORM()
            metric_resources = []
            for metric in self.repo_getter():
                for metric_type in ['name', 'html_url']:
                    metric_resources.append(
                        Metric(
                            metric_id='mymetric.github.%s' % metric_type,
                            value=metric.get(metric_type, ''),
                            # Cloud account resource my belong to
                            organization_service_id=None,
                            # Organization resource belongs to
                            organization_id=None,
                            # Unique Id for document, here I'm using the fully qualified repo name.
                            target_resource_id=metric.get('full_name'),
                            creation_timestamp=datetime.strftime(
                                datetime.utcnow(), '%Y-%m-%d %H:%M:%S'
                            )
                        )
                    )

            if metric_resources:
                db.session.bulk_save_objects(metric_resources)
                db.session.commit()

        ```
        Two remaining things to note. Since each harvest will be inserting multiple records,
        we use the SQLAlchemy `bulk_save_objects/1` function to commit them all in one query.
        In certain cases where the insert size is large, it is sometimes necessary to chunk
        the inserts into batch sizes to avoid max packet size limits of mysql queries.

        Here we get each github repo and then insert three metrics for each; name, description,
        and url. Each is associated with the `full_name` attribute which is unique.

        To prove out how the harvesting works you can start the JobScheduler to only run
        this job at a rapid pace though never run a harvester like this in production.

        ```
        divvycloudjobscheduler --modules-whitelist=ExampleHarvest --rapid-fire-debug
        divvycloudworker -h
        ```
        You should see something like this in your harvester logs.

        ```
        2017-10-05 14:51:29,933 ExampleHarvest: INFO     do_harvest  Repo: DivvyCloud/libcloud, Located at: https://github.com/DivvyCloud/libcloud
        2017-10-05 14:51:29,933 ExampleHarvest: INFO     do_harvest  Repo: DivvyCloud/DivvyCloud-ElasticSearch-Exporter, Located at: https://github.com/DivvyCloud/DivvyCloud-ElasticSearch-Exporter
        2017-10-05 14:51:29,933 ExampleHarvest: INFO     do_harvest  Repo: DivvyCloud/slackplugin, Located at: https://github.com/DivvyCloud/slackplugin
        ```
        """
        for metric in self.repo_getter():
            logger.info('Repo: %s, Located at: %s' % (metric.get('full_name'), metric.get('html_url')))

    def _cleanup(self):
        super(SkeletonHarvester, self)._cleanup()

@SharedSessionScope(DivvyCloudGatewayORM)
def list_job_templates():
    # Only 1 job template for this job

    job_templates = [
        SkeletonHarvester.create_job_template(),
    ]

    return job_templates

_JOB_LOADED = False

def load():
    global _JOB_LOADED
    try:
        _JOB_LOADED = register_job_module(__name__)
    except AttributeError:
        pass

def unload():
    global _JOB_LOADED
    if _JOB_LOADED:
        unregister_job_module(__name__)
        _JOB_LOADED = False


import pandas as pd
from typing import Union

def make_lagged(df: Union[pd.Series, pd.DataFrame], periods=1):
	shift = df.shift(periods=periods)
	if hasattr(shift, 'columns'):
		shift.columns = ['{}_lag{}'.format(c, periods) for c in shift.columns]
	elif hasattr(shift, 'name'):
		shift.rename('{}_lag{}'.format(shift.name, periods))
	return shift