import torch
from torchvision import models
from torch import nn
import sklearn.metrics
import numpy
import scipy.special

class Network(nn.Module):
    def __init__(self,
                 n_anchors,
                 mask_size,
                 arch='resnet50',
                 n_inputs=2,
                 n_outputs=1,
                 pretrained=True,
                 incline=True):

        super(Network, self).__init__()

        if arch == 'resnet18':
            self.model = models.resnet18(pretrained=pretrained)

        elif arch == 'resnet34':
            self.model = models.resnet34(pretrained=pretrained)

        elif arch == 'resnet50':
            self.model = models.resnet50(pretrained=pretrained)

        elif arch == 'resnet101':
            self.model = models.resnet101(pretrained=pretrained)

        elif arch == 'resnet152':
            self.model = models.resnet152(pretrained=pretrained)

        else:
            pass

        self.up1 = torch.nn.Conv2d(2048, 2048 * 2, (3, 3), padding=(1, 1))
        self.up_bn1 = torch.nn.BatchNorm2d(4096)
        self.up2 = torch.nn.Conv2d(1024, 2048, (3, 3), padding=(1, 1))
        self.up_bn2 = torch.nn.BatchNorm2d(2048)
        self.up3 = torch.nn.Conv2d(512, 1024, (3, 3), padding=(1, 1))
        self.up_bn3 = torch.nn.BatchNorm2d(1024)
        self.mask_size = mask_size

        self.ps = torch.nn.PixelShuffle(2)

        self.elu = torch.nn.ELU()

        self.detector = torch.nn.Conv2d(256, (5) * n_anchors, (1, 1))
        self.masker = torch.nn.Conv2d(256, self.mask_size[0] * self.mask_size[1] * n_anchors, (1, 1))

    def forward(self, input):

        x = input[0]

        x = self.model.conv1(x)
        x = self.model.bn1(x)
        x = self.model.relu(x)
        x = self.model.maxpool(x)

        # Scaling down
        layer_1_out = self.model.layer1(x)
        layer_2_out = self.model.layer2(layer_1_out)
        layer_3_out = self.model.layer3(layer_2_out)
        layer_4_out = self.model.layer4(layer_3_out)

        # Scaling up
        layer_4_up = self.elu(self.ps(self.up_bn1(self.up1(layer_4_out))))
        layer_3_up = self.elu(
            self.ps(self.up_bn2(self.up2(layer_3_out + layer_4_up))))
        layer_2_up = self.elu(
            self.ps(self.up_bn3(self.up3(layer_3_up + layer_2_out))))

        # Detecting objects
        result = self.detector(layer_1_out + layer_2_up)
        masks = torch.sigmoid(self.masker(layer_1_out + layer_2_up))

        return [result, masks]

def huber(x, delta=0.5):
    res = torch.abs(x)
    res = (res - 0.5) * (res >= 0.5).float() + (res < 0.5).float() * (res) ** 2
    return res

class Socket():
    def __init__(self, model, anchors,
                 penalize_bbox=True,
                 penalize_mask=True):
        self.model = model
        self.loss_function = torch.nn.BCEWithLogitsLoss()
        self.penalize_bbox = penalize_bbox
        self.penalize_mask = penalize_mask
        self.anchors = anchors

    @staticmethod
    def binary_ce(outputs, targets):
        return - (targets * torch.log(outputs + 1.0e-8) +
                  (1.0 - targets) * torch.log(1.0 - outputs + 1.0e-8))

    def criterion(self, output, target):

        # loss for object detection
        # loss for bounding box misplacement
        # loss for bounding box width and height loss
        # loss for mask
        object_loss = 0.0
        bbox_loss = 0.0
        mask_loss = 0.0

        anchor_size = 5
        mask_size = self.model.mask_size[0] * self.model.mask_size[1]

        for anchor_index in range(len(self.anchors)):
            object_loss = object_loss + (
                torch.nn.functional.binary_cross_entropy_with_logits(
                    output[0][:, anchor_index * 5 + 0, :, :],
                    target[0][:, anchor_index * 5 + 0, :, :]))

            bbox_loss = bbox_loss + (
                target[0][:, anchor_index * anchor_size + 0, :, :] * (
                huber(output[0][:, anchor_index * anchor_size + 1, :, :] -
                          target[0][:, anchor_index * anchor_size + 1, :, :]) +
                huber(output[0][:, anchor_index * anchor_size + 2, :, :] -
                          target[0][:, anchor_index * anchor_size + 2, :, :]) +
                huber(output[0][:, anchor_index * anchor_size + 3, :, :] -
                          target[0][:, anchor_index * anchor_size + 3, :, :]) +
                huber(output[0][:, anchor_index * anchor_size + 4, :, :] -
                          target[0][:, anchor_index * anchor_size + 4, :, :])
                )).sum()

            #print(output[1].shape)
            #print(target[1].shape)
            #print(anchor_index * mask_size, (anchor_index + 1) * mask_size)

            mask_loss = mask_loss + (
                target[0][:, anchor_index * anchor_size, :, :] * (
                    self.binary_ce(
                        output[1][:, anchor_index * mask_size:(anchor_index + 1) * mask_size, :, :],
                        target[1][:, anchor_index * mask_size:(anchor_index + 1) * mask_size, :, :]).mean(dim=1)
                )
            ).sum()

        return object_loss + bbox_loss + mask_loss

    @staticmethod
    def get_bboxes(tensor, anchors):

        result = tensor.data.numpy()

        for anchor_index in range(len(anchors)):

            anchor_position = anchor_index * 5
            result[:, anchor_position + 0, :, :] = result[:, anchor_position + 0, :, :]

            result[:, anchor_position + 1, :, :] = 2.0 * scipy.special.expit(
                tensor[:, anchor_position + 1, :, :]) - 1.0
            result[:, anchor_position + 2, :, :] = 2.0 * scipy.special.expit(
                result[:, anchor_position + 2, :, :]) - 1.0

            result[:, anchor_position + 3, :, :] = numpy.exp(
                result[:, anchor_position + 3, :, :]) * anchors[anchor_index][0]
            result[:, anchor_position + 4, :, :] = numpy.exp(
                result[:, anchor_position + 4, :, :]) * anchors[anchor_index][1]

        return result

    @staticmethod
    def bboxes_iou(predicted, target):

        ious = 0.0
        counts = 0.0

        for anchor_position in range(0, predicted.shape[1], 5):
            intersections = \
                numpy.maximum(numpy.minimum(
                    predicted[:, anchor_position + 1, :, :] + predicted[:, anchor_position + 3, :, :] / 2,
                    target[:, anchor_position + 1, :, :] + target[:, anchor_position + 3, :, :] / 2) -
                 numpy.maximum(
                    predicted[:, anchor_position + 1, :, :] - predicted[:, anchor_position + 3, :, :] / 2,
                    target[:, anchor_position + 1, :, :] - target[:, anchor_position + 3, :, :] / 2), 0) * \
                numpy.maximum(numpy.minimum(
                    predicted[:, anchor_position + 2, :, :] + predicted[:, anchor_position + 4, :, :] / 2,
                    target[:, anchor_position + 2, :, :] + target[:, anchor_position + 4, :, :] / 2) -
                numpy.maximum(
                    predicted[:, anchor_position + 2, :, :] - predicted[:, anchor_position + 4, :, :] / 2,
                    target[:, anchor_position + 2, :, :] - target[:, anchor_position + 4, :, :] / 2), 0)

            unions = (
                predicted[:, anchor_position + 3, :, :] * predicted[:, anchor_position + 4, :, :] +
                target[:, anchor_position + 3, :, :] * target[:, anchor_position + 4, :, :] -
                intersections)

            ious += (intersections / unions * target[:, anchor_position + 0, :, :]).sum()
            counts += target[:, anchor_position + 0, :, :].sum()

        return ious / counts

    @staticmethod
    def mask_iou(predicted, target, mask_size):

        ious = 0.0
        counts = 0.0

        for anchor_index in range(0, int(predicted.shape[1] / mask_size[0] / mask_size[1])):
            mask_start = anchor_index * mask_size[0] * mask_size[1]
            mask_end = mask_start + mask_size[0] * mask_size[1]

            predicted_masks = predicted[:, mask_start:mask_end, :, :]
            target_masks = target[:, mask_start:mask_end, :, :]
            indicators = (target[:, mask_start:mask_end, :, :].sum(dim=1) > 0.1).float()

            intersection = (predicted_masks * target_masks).sum(dim=1)
            union = predicted_masks.sum(dim=1) + target_masks.sum(dim=1) - intersection

            ious += (intersection / (union + 1.0e-8) * indicators).sum()
            counts += indicators.sum()

        return ious / counts

    def metrics(self, outputs, targets):
        # object roc-auc
        # bbox intersection over union
        # mask intersection over union
        # print(outputs[0].size())
        # print(targets[0].size())

        results = []

        prep_outputs = self.get_bboxes(outputs[0], self.anchors)
        prep_targets = self.get_bboxes(targets[0], self.anchors)

        for anchor_position in range(0, targets[0].size(1), 5):

            obj_roc_auc = sklearn.metrics.roc_auc_score(
                prep_targets[:, anchor_position + 0, :, :].flatten(),
                prep_outputs[:, anchor_position + 0, :, :].flatten())

            bboxes_iou = self.bboxes_iou(prep_outputs, prep_targets)
            masks_iou = self.mask_iou((outputs[1] > 0.5).float(), targets[1], self.model.mask_size).item()

            results.append(obj_roc_auc)
            results.append(bboxes_iou)
            results.append(masks_iou)
        #n_bboxes = 0
        #bbox_iou = 0.0

        #obj_targets = targets[:, 0, :, :].data.numpy()

        #if n_bboxes > 0:
        #    bbox_iou = bbox_iou / n_bboxes

        #bce_loss = self.loss_function(outputs[0], targets[0])
        return results


import numpy as np

class MovingAverage(object):
    def __init__(self, window_size):
        self.average = 0
        self.counter = 0
        self.window_size = window_size
        self.window_size_inv = 1/window_size

    def next_val(self, new_val):

        if new_val == None:
            return self.average

        if self.counter >= self.window_size:
            total_sum = self.average * (self.window_size - 1) + new_val
            self.average = total_sum * self.window_size_inv

        elif self.counter < self.window_size:
            total_sum = self.average * (self.counter) + new_val
            self.counter += 1
            self.average = total_sum / self.counter

        else:
            self.average = new_val
            self.counter += 1

        return self.average

    def restart(self):
        self.average = 0
        self.counter = 0

if __name__ == '__main__':

    example_avg = MovingAverage(10)

    for ii in range(50):
        if ii < 11:
            use_val = np.array([10,20])
        elif ii == 11:
            use_val = np.array([110,220])
        else:
            use_val = np.array([-50,300])

        print( example_avg.counter, use_val, example_avg.next_val( use_val ) )


import tensorflow as tf
import load_minst
import numpy as np
import matplotlib.pyplot as plt

batch_size = 100
hidden_units = 300
train_image = load_minst.load_mnist("training", np.arange(10) ,"/home/yuming/cogs181/hw4")[0]
train_label = load_minst.load_mnist("training", np.arange(10) ,"/home/yuming/cogs181/hw4")[1]
test_image = load_minst.load_mnist("testing", np.arange(10) ,"/home/yuming/cogs181/hw4")[0]
test_label = load_minst.load_mnist("testing", np.arange(10) ,"/home/yuming/cogs181/hw4")[1]
newtest_image = test_image.reshape(10000,784)
newtest_label = np.zeros([10000, 10])
#one hot encoding
for i in range(0,len(test_label)):
    newtest_label[i,test_label[i]] = 1

newtrain_image = train_image.reshape(60000,784)
newtrain_label = np.zeros([60000, 10])

#one hot encoding
for i in range(0,len(train_label)):
    newtrain_label[i,train_label[i,0]] = 1
#print("one hot encoing", newtrain_label)
images_batch = tf.placeholder(dtype = tf.float32, shape = [784])
labels_batch = tf.placeholder(dtype = tf.float32, shape = [10])

weights = {
    'c': tf.Variable(tf.random_normal([784, 300])),
    #'c': tf.Variable(tf.random_normal([784, 10], 1, 1)),
    'w': tf.Variable(tf.random_normal([300, 10]))
}

biases = {
    'b1': tf.Variable(tf.random_normal([300])),
    'b2': tf.Variable(tf.random_normal([10]))
}
print("weights of c : ", weights['c'])

x = tf.placeholder(tf.float32, shape = [None, 784])
y_ = tf.placeholder(tf.float32, shape = [None, 10])
def multiplayer_perceptron(x, weights, biases):
    layer1 = tf.matmul(x, weights['c']) + biases['b1']
    layer1 = tf.sigmoid(layer1)
    output = tf.matmul(layer1, weights['w']) + biases['b2']

    return output

y = multiplayer_perceptron(x, weights, biases)

cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels = y_, logits = y))
train_step = tf.train.AdamOptimizer(learning_rate=0.002).minimize(cross_entropy)

sess = tf.InteractiveSession()
sess.run(tf.global_variables_initializer())
def data_iterator():
    batch_idx = 0
    while True:
        index = np.arange(0, newtrain_label.shape[0])
        np.random.shuffle(index)
        shuf_features = newtrain_image[index]
        shuf_labels = newtrain_label[index]
        for batch_idx in range(0, newtrain_label.shape[0], batch_size):
            images_batch = shuf_features[batch_idx:batch_idx+batch_size]
            images_batch = images_batch.astype("float32")
            labels_batch = shuf_labels[batch_idx:batch_idx+batch_size]
            yield images_batch, labels_batch

iter_ = data_iterator()
training_epochs = 150
avg_cost = 0
time = 0
display_step = 1
losschart = np.zeros(training_epochs)
train_time = np.arange(training_epochs)
training_accuracy_chart = np.zeros(training_epochs)
testing_accuracy_chart = np.zeros(training_epochs)
#calculate accu
correct_prediction = tf.equal(tf.arg_max(y, 1), tf.argmax(y_, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
for epoch in range(training_epochs):
    avg_cost = 0
    #print("shape: ", newtrain_image.shape[0])
    total_batch = int(newtrain_image.shape[0]/batch_size)
    for i in range(total_batch):

        #print(time)
        time += 1
        images_batch_val, labels_batch_val = next(iter_)
        #print("image batch val : ", images_batch_val)
        #print("labels batch val : ", labels_batch_val)
        _, loss_val = sess.run([train_step,cross_entropy], feed_dict = {x: images_batch_val, y_: labels_batch_val})
        #print("loss is : ", loss_val)
        avg_cost += loss_val / total_batch
    if epoch % display_step == 0:
        print("ith: ", epoch)
        print("Epoch:", '%04d' % (epoch + 1), "cost=","{:.9f}".format(avg_cost))
        losschart[epoch] = avg_cost

        training_accuracy = accuracy.eval({x: newtrain_image, y_: newtrain_label})
        testing_accuracy = accuracy.eval({x: newtest_image, y_: newtest_label})
        training_accuracy_chart[epoch] = training_accuracy
        testing_accuracy_chart[epoch] = testing_accuracy
        print("Training Accuracy:", training_accuracy)
        print("Test Accuracy:", testing_accuracy)

print("Optimization Finished!")
plt.figure(1)
plt.plot(train_time, losschart)
plt.grid()

plt.figure(2)
plt.plot(train_time, training_accuracy_chart)
plt.xlabel("Training iterations")
plt.ylabel("Training accuracy")
plt.grid()

plt.figure(3)
plt.plot(train_time, testing_accuracy_chart)
plt.xlabel("Training iterations")
plt.ylabel("Testing accuracy")
plt.grid()
plt.show()

print("Final Test Accuracy:", accuracy.eval({x: newtest_image, y_: newtest_label}))


from bs4 import BeautifulSoup
import requests
import json
urlx=input()
url='https://github.com/'+urlx
response=requests.get(url)
info=BeautifulSoup(response.content,"html.parser")
overview_dict={"Repositories":0,"Projects":0,"Stars":0,"Followers":0,"Following":0}
listq=[]
for project in info.findAll('span',attrs={"class":"Counter hide-lg hide-md hide-sm" }):
    listq.append(project.text.strip())
i=0
for key in overview_dict.keys():
    overview_dict[key]=listq[i]
    i+=1
pinned_keys=[]
pinned_values=[]
for pin in info.findAll('a',attrs={"class":"text-bold flex-auto min-width-0"}):
    pinned_values.append("github.com"+pin["href"].strip())
    pinned_keys.append(pin.text.strip())
pinned_dict={}
for i in range(len(pinned_keys)):
    pinned_dict.update({pinned_keys[i]:pinned_values[i]})

popular_keys=[]
popular_values=[]
for pin in info.findAll('a',attrs={"class":"text-bold flex-auto"}):
    popular_values.append("github.com"+pin["href"].strip())
    popular_keys.append(pin.text.strip())
popular_dict={}
for i in range(len(popular_keys)):
    popular_dict.update({popular_keys[i]:popular_values[i]})
array=[]
array.append(overview_dict)
array.append(pinned_dict)
array.append(popular_dict)

with open('gitscrap.json','w') as outfile:
    json.dump(array,outfile)


#!/usr/bin/python2
import time
import rospy
from geometry_msgs.msg import Point, Pose, Quaternion, Twist, Vector3
import sys
import signal
import numpy as np
import serial
from std_msgs.msg import Empty
import os
import math
import json
from uwb_node.msg import uwbmsg
from nav_msgs.msg import Odometry

global pose
global twist
global new_q
twist = Twist()
pose = Pose()
# ser=serial.Serial("/dev/serial/by-id/usb-LeafLabs_Maple-if00",115200)
ser = serial.Serial("/dev/ttyACM0", 115200)

class UWB():

    def __init__(self):
        self.uwb_pub = rospy.Publisher("uwb", uwbmsg, queue_size=50)

    def uwbMsg(self, curr_pos):
        msg = uwbmsg()
        msg.header.stamp = rospy.Time.now()
        msg.curr_pos = curr_pos
        return msg

    def start(self):

        radialPos = prevRadialPos = [0.,0.,0.,0.]

        try:
            line = ser.readline()  # Read starting few junk lines if any
            line = ser.readline()
            line = ser.readline()  # Consistent readings start here
            radialPos = [float(i) for i in line.split(',')]
            prevRadialPos = radialPos
        except ValueError:
            pass

        while(not rospy.is_shutdown()):
            try:
                alpha = 0.0
                rangeNumSamples = 15
                alpha = 2.0/(rangeNumSamples+1.0)
                line = ser.readline()
                radialPos = [float(i) for i in line.split(',')]
                radialPos = [radialPos[z]*alpha + prevRadialPos[z] * (1-alpha) for z in range(0, numAnchors)]

                if 0. in radialPos:
                    radialPos = prevRadialPos

                msg = self.uwbMsg(radialPos)
                print(radialPos)
                self.uwb_pub.publish(msg)
                prevRadialPos = radialPos
            except Exception as e:
                exc_type, exc_obj, exc_tb = sys.exc_info()
                fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
                ser.close()
                #print(exc_type, fname, exc_tb.tb_lineno)
                print("exception")
                print(e)
                pass

if __name__ == '__main__':
    rospy.init_node('uwb_node', anonymous=True)
    uwb_node = UWB()
    uwb_node.start()

    try:
        rospy.spin()
    except rospy.ROSInterruptException:
        print("ROS master not started")
        pass


import copy
import unittest

def zero_matrix(matrix):
    n = len(matrix[0])
    m = len(matrix)
    output = [[True for _ in range(n)] for _ in range(m)]

    for i in range(m):
        for j in range(n):
            if matrix[i][j] == 0:
                output[i] = [0 for _ in range(n)]
                for k in range(m):
                    output[k][j] = 0
    for i in range(m):
        for j in range(n):
            if output[i][j]:
                output[i][j] = matrix[i][j]

    return output

# the above method runs in O(n^3) and uses O(mn) space
# we can run in O(n^2) and O(m+n) space.
def better_zero_matrix(matrix):
    m = len(matrix)
    n = len(matrix[0])
    rows, columns = [], []

    for i in range(m):
        for j in range(n):
            if matrix[i][j] == 0:
                rows.append(i)
                columns.append(j)
                break

    for row in rows:
        matrix[row] = [0 for _ in range(n)]

    for column in columns:
        for i in range(m):
            matrix[i][column] = 0

    return matrix

class Test(unittest.TestCase):
    data = [
        ([
            [1, 2, 3, 4, 0],
            [6, 0, 8, 9, 10],
            [11, 12, 13, 14, 15],
            [16, 0, 18, 19, 20],
            [21, 22, 23, 24, 25]
        ], [
            [0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0],
            [11, 0, 13, 14, 0],
            [0, 0, 0, 0, 0],
            [21, 0, 23, 24, 0]
        ])
    ]

    def test_zero_matrix(self):
        for [test_matrix, expected] in copy.deepcopy(self.data):
            actual = zero_matrix(test_matrix)
            self.assertEqual(actual, expected)

    def test_better_zero_matrix(self):
        for [test_matrix, expected] in copy.deepcopy(self.data):
            actual = better_zero_matrix(test_matrix)
            self.assertEqual(actual, expected)

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


#
# [886] Score of Parentheses
#
# https://leetcode.com/problems/score-of-parentheses/description/
#
# algorithms
# Medium (55.25%)
# Total Accepted:    4.4K
# Total Submissions: 8K
# Testcase Example:  '"()"'
#
# Given a balanced parentheses string S, compute the score of the string based
# on the following rule:
#
#
# () has score 1
# AB has score A + B, where A and B are balanced parentheses strings.
# (A) has score 2 * A, where A is a balanced parentheses string.
#
#
#
#
#
# Example 1:
#
#
# Input: "()"
# Output: 1
#
#
#
# Example 2:
#
#
# Input: "(())"
# Output: 2
#
#
#
# Example 3:
#
#
# Input: "()()"
# Output: 2
#
#
#
# Example 4:
#
#
# Input: "(()(()))"
# Output: 6
#
#
#
#
# Note:
#
#
# S is a balanced parentheses string, containing only ( and ).
# 2 <= S.length <= 50
#
#
#
# Jarron:
#   - recursive

# REVIEW:
#   - O(1)

class Solution:
    def scoreOfParentheses(self, S):
        """
        :type S: str
        :rtype: int
        """
        if S == '':
            return 0
        if S == '()':
            return 1

        count = 0
        for i, s in enumerate(S):
            if s == '(':
                count += 1
            else:
                count -= 1

            if count == 0:
                break

        if S[:i + 1] == '()':
            return 1 + self.scoreOfParentheses(S[i + 1:])

        return 2 * self.scoreOfParentheses(S[1:i]) + self.scoreOfParentheses(S[i + 1:])

    # O(1): use layer
    # def scoreOfParentheses(self, S):
    #     res = layers = 0
    #     for a, b in itertools.izip(S, S[1:]):
    #         layers += 1 if a == '(' else -1
    #         if a + b == '()': res += 2 ** (layers - 1)
    #     return res


from crppcontacts.models import Contact, Tag
from rest_framework import serializers

class ContactSerializer(serializers.ModelSerializer):
    tags = serializers.SlugRelatedField(
        required=False,
        many=True,
        slug_field='name',
        allow_null=True,
        read_only=False,
        queryset=Tag.objects.all()
    )

    class Meta:
        model = Contact
        fields = ( '__all__' )

class TagSerializer(serializers.ModelSerializer):

    class Meta:
        model = Tag
        fields = ( '__all__' )


import sys

for data in sys.stdin:
    # get the input
    interval = [int(x) for x in data.split()]
    interval.sort()
    i, j = interval

    # store the best cycle
    best = 0
    for k in range(i, j + 1):
        counter = 1

        # count the number of cycles
        while k != 1:
            k = k / 2 if k % 2 == 0 else k * 3 + 1
            counter += 1

        # update if necessary
        if counter > best:
            best = counter

    print('%d %d %d' % (i, j, best))


__author__ = 'saeedamen' # Saeed Amen

#
# Copyright 2016 Cuemacro
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the
# License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
# See the License for the specific language governing permissions and limitations under the License.
#

"""
EngineTemplate

Implemented by EngineBokeh, EnglineMatplotlib and EnginePlotly to do underlying plotting

"""

import abc

from math import log10, floor
import numpy
import pandas
import datetime
from chartpy.style import Style
from chartpy.chartconstants import ChartConstants

cc = ChartConstants()

class EngineTemplate(object):

    def init(self):
        return

    @abc.abstractmethod
    def plot_chart(self, data_frame, style, type):
        return

    def get_time_stamp(self):
        return str(datetime.datetime.now()).replace(':', '-').replace(' ', '-').replace(".", "-")

    def get_bar_indices(self, data_frame, style, chart_type, bar_ind):
        has_bar = 'no-bar'
        xd = data_frame.index
        no_of_bars = len(data_frame.columns)

        if style.chart_type is not None:
            if isinstance(style.chart_type, list):
                if 'bar' in style.chart_type:
                    xd = bar_ind
                    no_of_bars = style.chart_type.count('bar')
                    has_bar = 'barv'
                elif 'stacked' in style.chart_type:
                    xd = bar_ind
                    no_of_bars = 1
                    has_bar = 'barv'
            elif 'bar' == style.chart_type:
                xd = bar_ind
                has_bar = 'barv'
            elif 'barh' == style.chart_type:
                xd = bar_ind
                has_bar = 'barh'
            elif 'stacked' == style.chart_type:
                xd = bar_ind
                has_bar = 'barh'
        else:
            if chart_type == 'bar' or chart_type == 'stacked':
                xd = bar_ind
                has_bar = 'barv'

        return xd, bar_ind, has_bar, no_of_bars

    def assign(self, structure, field, default):
        if hasattr(structure, field): default = getattr(structure, field)

        return default

    def assign_list(self, style, field, list):
        if hasattr(style, field):
            list = [str(x) for x in getattr(style, field)]

        return list

    def get_linewidth(self, label, linewidth_1, linewidth_2, linewidth_2_series):
        if label in linewidth_2_series:
            return linewidth_2

        return linewidth_1

    def round_to_1(self, x):
        return round(x, -int(floor(log10(x))))

    def split_data_frame_to_list(self, data_frame, style):
        data_frame_list = []

        if isinstance(data_frame, list):
            data_frame_list = data_frame
        else:
            if style.subplots == True:

                for col in data_frame.columns:
                    data_frame_list.append(
                        pandas.DataFrame(index=data_frame.index, columns=[col], data=data_frame[col]))
            else:
                data_frame_list.append(data_frame)

        return data_frame_list

#######################################################################################################################

from bokeh.plotting import figure, output_file, show, gridplot, save
from bokeh.charts import HeatMap

class EngineBokeh(EngineTemplate):

    def plot_chart(self, data_frame, style, chart_type):

        cm = ColorMaster()

        if style.scale_factor > 0:
            scale_factor = abs(style.scale_factor) * 2/3
        else:
            scale_factor = abs(style.scale_factor)

        try:
            if style.bokeh_plot_mode == "offline_jupyter":
                from bokeh.io import output_notebook
                output_notebook()
        except:
            pass

        try:
            if style.file_output is not None:
                style.html_file_output = style.file_output

            html = style.html_file_output

            if (html is None):
                import time
                style.html_file_output = self.get_time_stamp() + "-bokeh.html"

                html = style.html_file_output

            output_file(html)
        except: pass

        data_frame_list = self.split_data_frame_to_list(data_frame, style)

        plot_list = []

        plot_width = int((style.width * scale_factor))
        plot_height = int((style.height * scale_factor) / len(data_frame_list))

        for data_frame in data_frame_list:
            bar_ind = numpy.arange(1, len(data_frame.index) + 1)

            xd, bar_ind, has_bar, no_of_bars = self.get_bar_indices(data_frame, style, chart_type, bar_ind)

            separate_chart = False

            if chart_type == 'heatmap':
                # TODO

                p1 = HeatMap(data_frame,
                             title='Random', plot_width = plot_width, plot_height = plot_height)

                separate_chart = True

            # if has a vertical bar than categorical x-axis
            elif has_bar == 'barv':
                p1 = figure(
                    plot_width = plot_width,
                    plot_height = plot_height,
                    x_range=[str(x).replace(':','.') for x in data_frame.index]
                    )

                from math import pi
                p1.xaxis.major_label_orientation = pi/2
            elif type(data_frame.index) == pandas.tslib.Timestamp:
                p1 = figure(
                    x_axis_type = "datetime",
                    plot_width = plot_width,
                    plot_height = plot_height,
                    x_range = (xd[0], xd[-1])
                )

            # otherwise numerical axis
            else:
                p1 = figure(
                    plot_width = plot_width,
                    plot_height = plot_height,
                    x_range=(xd[0], xd[-1])
                    )

            # set the fonts
            p1.axis.major_label_text_font_size = str(10) + "pt"
            p1.axis.major_label_text_font = cc.bokeh_font
            p1.axis.major_label_text_font_style = cc.bokeh_font_style

            p1.xaxis.axis_label_text_font_size = str(10) + "pt"
            p1.xaxis.axis_label_text_font = cc.bokeh_font
            p1.xaxis.axis_label_text_font_style = cc.bokeh_font_style
            p1.xaxis.axis_label = style.x_title

            p1.yaxis.axis_label_text_font_size = str(10) + "pt"
            p1.yaxis.axis_label_text_font = cc.bokeh_font
            p1.yaxis.axis_label_text_font_style = cc.bokeh_font_style
            p1.yaxis.axis_label = style.y_title

            p1.legend.location = "top_left"
            p1.legend.label_text_font_size = str(10) + "pt"
            p1.legend.label_text_font = cc.bokeh_font
            p1.legend.label_text_font_style = cc.bokeh_font_style
            p1.legend.background_fill_alpha = 0.75
            p1.legend.border_line_width = 0

            # set chart outline
            p1.outline_line_width = 0

            # Plot.title.text
            p1.title.text_font_size = str(14) + "pt"
            p1.title.text_font = cc.bokeh_font

            # TODO fix label
            # if style.display_source_label:
            #     p1.text([30 * scale_factor, 30 * scale_factor], [0, 0], text = [style.brand_label],
            #         text_font_size = str(10 * scale_factor) + "pt", text_align = "left",
            #         text_font = GraphistyleConstants().bokeh_font)

            color_spec = cm.create_color_list(style, data_frame)
            import matplotlib

            bar_space = 0.2
            bar_width = (1 - bar_space) / (no_of_bars)
            bar_index = 0

            has_bar ='no-bar'

            if not(separate_chart):

                # plot each series in the dataframe separately
                for i in range(0, len(data_frame.columns)):
                    label = str(data_frame.columns[i])
                    glyph_name = 'glpyh' + str(i)

                    # set chart type which can differ for each time series
                    if isinstance(chart_type, list): chart_type_ord = chart_type[i]
                    else: chart_type_ord = chart_type

                    # get the color
                    if color_spec[i] is None:
                        color_spec[i] = self.get_color_list(i)

                    try:
                        color_spec[i] = matplotlib.colors.rgb2hex(color_spec[i])
                    except: pass

                    yd = data_frame.ix[:,i]

                    # plot each time series as appropriate line, scatter etc.
                    if chart_type_ord == 'line':
                        linewidth_t = self.get_linewidth(label,
                            style.linewidth, style.linewidth_2, style.linewidth_2_series)

                        if linewidth_t is None: linewidth_t = 1

                        if style.display_legend:
                            p1.line(xd, yd, color = color_spec[i], line_width=linewidth_t, name = glyph_name,
                                    legend = label,
                            )
                        else:
                            p1.line(xd, data_frame.ix[:,i], color = color_spec[i], line_width=linewidth_t, name = glyph_name)

                    elif(chart_type_ord == 'bar'):
                        bar_pos = [k - (1 - bar_space) / 2. + bar_index * bar_width for k in range(1,len(bar_ind) + 1)]
                        bar_pos_right = [x + bar_width for x in bar_pos]

                        if style.display_legend:
                            p1.quad(top=yd, bottom=0 * yd, left=bar_pos, right=bar_pos_right, color=color_spec[i], legend=label)
                        else:
                            p1.quad(top=yd, bottom=0 * yd, left=bar_pos, right=bar_pos_right, color=color_spec[i])

                        bar_index = bar_index + 1
                        bar_ind = bar_ind + bar_width
                    elif (chart_type_ord == 'barh'):
                        # TODO
                        pass

                    elif chart_type_ord == 'scatter':
                        linewidth_t = self.get_linewidth(label,
                            style.linewidth, style.linewidth_2, style.linewidth_2_series)

                        if linewidth_t is None: linewidth_t = 1

                        if style.display_legend:
                            p1.circle(xd, yd, color = color_spec[i], line_width=linewidth_t, name = glyph_name,
                                    legend = label,
                            )
                        else:
                            p1.circle(xd, yd, color = color_spec[i], line_width=linewidth_t, name = glyph_name)

                p1.grid.grid_line_alpha = 0.3

                # p1.min_border_left = -40
                # p1.min_border_right = 0
                # p1.min_border_top = 0
                # p1.min_border_bottom = 0

                p1.min_border = -50

            plot_list.append(p1)

        p_final = gridplot(plot_list, ncols=1)

        try:
            p_final.title.text = style.title
        except: pass

        if style.silent_display:
            save(p_final)
        else:
            show(p_final)  # open a browser

    def get_color_list(self, i):
        color_palette = cc.bokeh_palette

        return color_palette[i % len(color_palette)]

    def generic_settings(self):
        return

#######################################################################################################################

# matplotlib based libraries
from datetime import timedelta

import matplotlib
import matplotlib.pyplot as plt
import numpy as np

from matplotlib.dates import YearLocator, MonthLocator, DayLocator, HourLocator, MinuteLocator
from matplotlib.ticker import MultipleLocator

class EngineMatplotlib(EngineTemplate):

    def plot_chart(self, data_frame, style, chart_type):

        self.apply_style_sheet(style)

        # create figure & add a subplot
        fig = plt.figure(figsize = ((style.width * abs(style.scale_factor))/style.dpi,
                                    (style.height * abs(style.scale_factor))/style.dpi), dpi = style.dpi)

        if style.title is not None:
            fig.suptitle(style.title, fontsize = 14 * abs(style.scale_factor))

        # matplotlib 1.5
        try:
            cyc = matplotlib.rcParams['axes.prop_cycle']
            color_cycle =  [x['color'] for x in cyc]
        except KeyError:
            # pre 1.5
            pass
            # color_cycle =  matplotlib.rcParams['axes.color_cycle']

        cm = ColorMaster()

        data_frame_list = self.split_data_frame_to_list(data_frame, style)

        subplot_no = 1

        for data_frame in data_frame_list:

            bar_ind = np.arange(0, len(data_frame.index))

            # for bar charts, create a proxy x-axis (then relabel)
            xd, bar_ind, has_bar, no_of_bars = self.get_bar_indices(data_frame, style, chart_type, bar_ind)

            if style.subplots == False and len(data_frame_list) == 1:
                ax = fig.add_subplot(111)
            else:
                ax = fig.add_subplot(2,1,subplot_no)

            subplot_no = subplot_no + 1

            if style.x_title != '': ax.set_xlabel(style.x_title)
            if style.y_title != '': ax.set_ylabel(style.y_title)

            plt.xlabel(style.x_title)
            plt.ylabel(style.y_title)

            # format Y axis
            y_formatter = matplotlib.ticker.ScalarFormatter(useOffset = False)
            ax.yaxis.set_major_formatter(y_formatter)

            # create a second y axis if necessary
            ax2 = []

            if style.y_axis_2_series != []:
                ax2 = ax.twinx()

                # do not use a grid with multiple y axes
                ax.yaxis.grid(False)
                ax2.yaxis.grid(False)

            try:
                # get all the correct colors (and construct gradients if necessary eg. from 'blues')

                # for stacked bar
                yoff_pos = np.zeros(len(data_frame.index.values)) # the bottom values for stacked bar chart
                yoff_neg = np.zeros(len(data_frame.index.values)) # the bottom values for stacked bar chart

                zeros = np.zeros(len(data_frame.index.values))

                # for bar chart
                bar_space = 0.2
                bar_width = (1 - bar_space) / (no_of_bars)
                bar_index = 0

                has_matrix = False

                if not(isinstance(chart_type, list)):
                    if chart_type == 'heatmap':
                        ax.set_frame_on(False)

                        # weird hack, otherwise comes out all inverted!
                        data_frame = data_frame.iloc[::-1]

                        color = style.color

                        if style.color == []:
                            color = cc.chartfactory_default_colormap
                        else:
                            if isinstance(style.color, list):
                                color = style.color[subplot_no - 1]

                        ax.pcolor(data_frame.values, cmap=color, alpha=0.8)

                        has_matrix = True

                if (not(has_matrix)):
                    # plot the lines (using custom palettes as appropriate)
                    color_spec = cm.create_color_list(style, data_frame)

                    # some lines we should exclude from the color and use the default palette
                    for i in range(0, len(data_frame.columns.values)):

                        if isinstance(chart_type, list): chart_type_ord = chart_type[i]
                        else: chart_type_ord = chart_type

                        label = str(data_frame.columns[i])

                        ax_temp = self.get_axis(ax, ax2, label, style.y_axis_2_series)

                        yd = data_frame.ix[:,i]

                        if color_spec[i] is None:
                            color_spec[i] = color_cycle[i % len(color_cycle)]

                        if (chart_type_ord == 'line'):
                            linewidth_t = self.get_linewidth(label,
                                                             style.linewidth, style.linewidth_2, style.linewidth_2_series)

                            if linewidth_t is None: linewidth_t = matplotlib.rcParams['axes.linewidth']

                            ax_temp.plot(xd, yd, label = label, color = color_spec[i],
                                         linewidth = linewidth_t)

                        elif(chart_type_ord == 'bar'):
                            # for multiple bars we need to allocate space properly
                            bar_pos = [k - (1 - bar_space) / 2. + bar_index * bar_width for k in range(0,len(bar_ind))]

                            ax_temp.bar(bar_pos, yd, bar_width, label = label, color = color_spec[i])

                            bar_index = bar_index + 1

                        elif (chart_type_ord == 'barh'):
                            # for multiple bars we need to allocate space properly
                            bar_pos = [k - (1 - bar_space) / 2. + bar_index * bar_width for k in range(0, len(bar_ind))]

                            ax_temp.barh(bar_pos, yd, bar_width, label=label, color=color_spec[i])

                            bar_index = bar_index + 1

                        elif(chart_type_ord == 'stacked'):
                            bar_pos = [k - (1 - bar_space) / 2. + bar_index * bar_width for k in range(0,len(bar_ind))]

                            yoff = np.where(yd > 0, yoff_pos, yoff_neg)

                            ax_temp.bar(bar_pos, yd, label = label, color = color_spec[i], bottom = yoff)

                            yoff_pos = yoff_pos + np.maximum(yd, zeros)
                            yoff_neg = yoff_neg + np.minimum(yd, zeros)

                            # bar_index = bar_index + 1

                        elif(chart_type_ord == 'scatter'):
                            ax_temp.scatter(xd, yd, label = label, color = color_spec[i])

                            if style.line_of_best_fit is True:
                                self.trendline(ax_temp, xd.values, yd.values, order=1, color= color_spec[i], alpha=1,
                                               scale_factor = abs(style.scale_factor))

                # format X axis
                self.format_x_axis(ax, data_frame, style, has_bar, bar_ind, has_matrix)

            except: pass

            if style.display_source_label == True and style.source is not None:
                ax.annotate('Source: ' + style.source, xy = (1, 0), xycoords='axes fraction', fontsize=7 * abs(style.scale_factor),
                            xytext=(-5 * abs(style.scale_factor), 10 * abs(style.scale_factor)), textcoords='offset points',
                            ha='right', va='top', color = style.source_color)

            if style.display_brand_label == True:
                self.create_brand_label(ax, anno = style.brand_label, scale_factor = abs(style.scale_factor))

            leg = []
            leg2 = []

            loc = 'best'

            # if we have two y-axis then make sure legends are in opposite corners
            if ax2 != []: loc = 2

            try:
                leg = ax.legend(loc = loc, prop={'size':10 * abs(style.scale_factor)})
                leg.get_frame().set_linewidth(0.0)
                leg.get_frame().set_alpha(0)

                if ax2 != []:
                    leg2 = ax2.legend(loc = 1, prop={'size':10 * abs(style.scale_factor)})
                    leg2.get_frame().set_linewidth(0.0)
                    leg2.get_frame().set_alpha(0)
            except: pass

            try:
                if style.display_legend is False:
                    if leg != []: leg.remove()
                    if leg2 != []: leg.remove()
            except: pass

        try:
            if (style.file_output is None):
                import time
                style.file_output = self.get_time_stamp() + "-matplotlib.png"

            plt.savefig(style.file_output, transparent=False)
        except: pass

        ####### various matplotlib converters are unstable
        # convert to D3 format with mpld3
        try:
            # output matplotlib charts externally to D3 based libraries
            import mpld3

            if style.display_mpld3 == True:
                mpld3.save_d3_html(fig, style.html_file_output)
                mpld3.show(fig)
        except: pass

        # FRAGILE! convert to Bokeh format
        # better to use direct Bokeh renderer
        try:
            if (style.convert_matplotlib_to_bokeh == True):
                from bokeh.plotting import output_file, show
                from bokeh import mpl

                output_file(style.html_file_output)
                show(mpl.to_bokeh())
        except: pass

        # FRAGILE! convert matplotlib chart to Plotly format
        # recommend using AdapterCufflinks instead to directly plot to Plotly
        try:
            import plotly.plotly as py
            import plotly
            import plotly.tools as tls

            if style.convert_matplotlib_to_plotly == True:
                plotly.tools.set_credentials_file(username = style.plotly_username,
                                                  api_key = style.plotly_api_key)

                py_fig = tls.mpl_to_plotly(fig, strip_style = True)
                plot_url = py.plot_mpl(py_fig, filename = style.plotly_url)
        except:
            pass

        # display in matplotlib window
        try:
            if cc.chartfactory_silent_display == True:
                return fig
            elif style.silent_display == False:
                plt.show()
            else:
                return fig

        except:
            pass

    def apply_style_sheet(self, style):
        # set the matplotlib style sheet & defaults
        matplotlib.rcdefaults()

        # first search ChartPy styles, then try matplotlib
        try: plt.style.use(cc.chartfactory_style_sheet[style.style_sheet])
        except: plt.style.use(style.style_sheet)

        # adjust font size for scale factor
        matplotlib.rcParams.update({'font.size': matplotlib.rcParams['font.size'] * abs(style.scale_factor)})

        # do not use offsets/scientific notation
        matplotlib.rcParams.update({'axes.formatter.useoffset': False})

    def format_x_axis(self, ax, data_frame, style, has_bar, bar_ind, has_matrix):

        if has_matrix:
            x_bar_ind = np.arange(0, len(data_frame.columns))
            y_bar_ind = np.arange(0, len(data_frame.index))

            ax.set_xticks(x_bar_ind + 0.5)
            ax.set_xlim([0, len(x_bar_ind)])
            ax.set_yticks(y_bar_ind + 0.5)
            ax.set_ylim([0, len(y_bar_ind)])

            plt.setp(plt.yticks()[1], rotation=90)

            ax.set_xticklabels(data_frame.columns, minor=False)
            ax.set_yticklabels(data_frame.index, minor=False)

            ax.plot([], [])

            for x in range(len(data_frame.index)):
                for y in range(len(data_frame.columns)):
                    plt.text(x + 0.5, y + 0.5, '%.0f' % data_frame.ix[x, y],
                         horizontalalignment='center',
                         verticalalignment='center',
                         )

            return

        if has_bar == 'barv':
            ax.set_xticks(bar_ind)
            ax.set_xticklabels(data_frame.index)
            ax.set_xlim([-1, len(bar_ind)])

            # if lots of labels make text smaller and rotate
            if len(bar_ind) > 6:
                plt.setp(plt.xticks()[1], rotation=90)
                # plt.gca().tight_layout()
                # matplotlib.rcParams.update({'figure.autolayout': True})
                # plt.gcf().subplots_adjust(bottom=5)
                import matplotlib.dates as mdates

                if style.date_formatter is not None:
                    ax.format_xdata = mdates.DateFormatter(style.date_formatter)

                plt.tight_layout()
                # ax.tick_params(axis='x', labelsize=matplotlib.rcParams['font.size'] * 0.5)
            return
        elif has_bar == 'barh':
            ax.set_yticks(bar_ind)
            ax.set_yticklabels(data_frame.index)
            ax.set_ylim([-1, len(bar_ind)])

            # if lots of labels make text smaller and rotate
            if len(bar_ind) > 6:
                #plt.setp(plt.yticks()[1])
                # plt.gca().tight_layout()
                # matplotlib.rcParams.update({'figure.autolayout': True})
                # plt.gcf().subplots_adjust(bottom=5)
                import matplotlib.dates as mdates

                if style.date_formatter is not None:
                    ax.format_ydata = mdates.DateFormatter(style.date_formatter)

                plt.tight_layout()
                # ax.tick_params(axis='x', labelsize=matplotlib.rcParams['font.size'] * 0.5)
            return

        # format X axis
        dates = data_frame.index

        # scaling for time series plots with hours and minutes only (and no dates)
        if hasattr(data_frame.index[0], 'hour') and not(hasattr(data_frame.index[0], 'month')):
            ax.xaxis.set_major_locator(MultipleLocator(86400./3.))
            ax.xaxis.set_minor_locator(MultipleLocator(86400./24.))
            ax.grid(b = True, which='minor', color='w', linewidth=0.5)

        # TODO have more refined way of formating time series x-axis!

        # scaling for time series plots with dates too
        else:
            # to handle dates
            try:
                dates = dates.to_pydatetime()
                diff = data_frame.index[-1] - data_frame.index[0]

                import matplotlib.dates as md

                if style.date_formatter is not None:
                    # from matplotlib.ticker import Formatter
                    #
                    # class MyFormatter(Formatter):
                    #     def __init__(self, dates, fmt='%H:%M'):
                    #         self.dates = dates
                    #         self.fmt = fmt
                    #
                    #     def __call__(self, x, pos=0):
                    #         'Return the label for time x at position pos'
                    #         ind = int(round(x))
                    #         if ind >= len(self.dates) or ind < 0: return ''
                    #
                    #         return self.dates[ind].strftime(self.fmt)
                    #
                    # formatter = MyFormatter(dates)
                    # ax.xaxis.set_major_formatter(formatter)

                    ax.xaxis.set_major_formatter(md.DateFormatter(style.date_formatter))
                elif diff < timedelta(days = 4):

                    date_formatter = '%H:%M'
                    xfmt = md.DateFormatter(date_formatter)
                    ax.xaxis.set_major_formatter(xfmt)

                    if diff < timedelta(minutes=20):
                        ax.xaxis.set_major_locator(MinuteLocator(byminute=range(60), interval=2))
                        ax.xaxis.set_minor_locator(MinuteLocator(interval=1))
                    elif diff < timedelta(hours=1):
                        ax.xaxis.set_major_locator(MinuteLocator(byminute=range(60), interval=5))
                        ax.xaxis.set_minor_locator(MinuteLocator(interval=2))
                    elif diff < timedelta(hours=6):
                        locator = HourLocator(interval=1)
                        ax.xaxis.set_major_locator(locator)
                        ax.xaxis.set_minor_locator(MinuteLocator(interval=30))
                    elif diff < timedelta(days=3):
                        ax.xaxis.set_major_locator(HourLocator(interval=6))
                        ax.xaxis.set_minor_locator(HourLocator(interval=1))

                elif diff < timedelta(days=10):
                    locator = DayLocator(interval=2)
                    ax.xaxis.set_major_locator(locator)
                    ax.xaxis.set_major_formatter(md.DateFormatter('%d %b %y'))

                    day_locator = DayLocator(interval=1)
                    ax.xaxis.set_minor_locator(day_locator)

                elif diff < timedelta(days=40):
                    locator = DayLocator(interval=10)
                    ax.xaxis.set_major_locator(locator)
                    ax.xaxis.set_major_formatter(md.DateFormatter('%d %b %y'))

                    day_locator = DayLocator(interval=1)
                    ax.xaxis.set_minor_locator(day_locator)

                elif diff < timedelta(days=365 * 0.5):
                    locator = MonthLocator(bymonthday=1, interval=2)
                    ax.xaxis.set_major_locator(locator)
                    ax.xaxis.set_major_formatter(md.DateFormatter('%b %y'))

                    months_locator = MonthLocator(interval=1)
                    ax.xaxis.set_minor_locator(months_locator)

                elif diff < timedelta(days=365 * 2):
                    locator = MonthLocator(bymonthday=1, interval=3)
                    ax.xaxis.set_major_locator(locator)
                    ax.xaxis.set_major_formatter(md.DateFormatter('%b %y'))

                    months_locator = MonthLocator(interval=1)
                    ax.xaxis.set_minor_locator(months_locator)

                elif diff < timedelta(days = 365 * 5):
                    locator = YearLocator()
                    ax.xaxis.set_major_locator(locator)
                    ax.xaxis.set_major_formatter(md.DateFormatter('%Y'))

            except:
                try:
                    # otherwise we have integers, rather than dates
                    # TODO needs smarter more generalised mapping of dates
                    max = dates.max()
                    min = dates.min()

                    big_step = self.round_to_1((max - min)/10)

                    small_step = big_step / 5

                    ax.xaxis.set_major_locator(MultipleLocator(big_step))
                    ax.xaxis.set_minor_locator(MultipleLocator(small_step))

                    plt.xlim(min, max)
                except: pass

    def get_axis(self, ax, ax2, label, y_axis_2_series):

        if label in y_axis_2_series: return ax2

        return ax

    def trendline(self, ax, xd, yd, order=1, color='red', alpha=1, Rval=False, scale_factor = 1):
        """ Make a line of best fit """

        # Calculate trendline
        xd[np.isnan(xd)] = 0
        yd[np.isnan(yd)] = 0

        coeffs = np.polyfit(xd, yd, order)

        intercept = coeffs[-1]
        slope = coeffs[-2]
        if order == 2: power = coeffs[0]
        else: power = 0

        minxd = np.min(xd)
        maxxd = np.max(xd)

        xl = np.array([minxd, maxxd])
        yl = power * xl ** 2 + slope * xl + intercept

        # plot trendline
        ax.plot(xl, yl, color = color, alpha = alpha)

        # calculate R squared
        p = np.poly1d(coeffs)

        ybar = np.sum(yd) / len(yd)
        ssreg = np.sum((p(xd) - ybar) ** 2)
        sstot = np.sum((yd - ybar) ** 2)
        Rsqr = ssreg / sstot

        if Rval == False:
            text = 'R^2 = %0.2f, m = %0.4f, c = %0.4f' %(Rsqr, slope, intercept)

            ax.annotate(text, xy=(1, 1), xycoords='axes fraction', fontsize=8 * abs(scale_factor),
                    xytext=(-5 * abs(scale_factor), 10 * abs(scale_factor)), textcoords='offset points',
                    ha='right', va='top')

            # Plot R^2 value
            # ax.text(0.65, 0.95, text, fontsize = 10 * scale_factor,
            #            ha= 'left',
            #            va = 'top', transform = ax.transAxes)
            pass
        else:
            # return the R^2 value:
            return Rsqr

    def create_brand_label(self, ax, anno, scale_factor):
        ax.annotate(anno, xy = (1, 1), xycoords = 'axes fraction',
                    fontsize = 10 * abs(scale_factor), color = 'white',
                    xytext = (0 * abs(scale_factor), 15 * abs(scale_factor)), textcoords = 'offset points',
                    va = "center", ha = "center",
                    bbox = dict(boxstyle = "round,pad=0.0", facecolor = cc.chartfactory_brand_color))

#######################################################################################################################
cf = None

try:
    import plotly
    import cufflinks as cf
except: pass

import plotly.plotly

class EnginePlotly(EngineTemplate):

    def plot_chart(self, data_frame, style, chart_type):

        mode = 'line'

        if style is None: style = Style()

        marker_size = 1

        x = ''; y = ''; z = ''
        fig = None

        scale = 1

        try:
            if (style.plotly_plot_mode == 'offline_html' and style.scale_factor > 0):
                scale = 2/3
        except:
            pass

        # check other plots implemented by Cufflinks
        if fig is None:

            cm = ColorMaster()

            # create figure
            data_frame_list = self.split_data_frame_to_list(data_frame, style)
            fig_list = []
            cols = []

            for data_frame in data_frame_list:
                cols.append(data_frame.columns)

            cols = list(np.array(cols).flat)

            # get all the correct colors (and construct gradients if necessary eg. from 'Blues')
            # need to change to strings for cufflinks

            color_list = cm.create_color_list(style, [], cols=cols)
            color_spec = []

            # if no colors are specified then just use our default color set from chart constants
            if color_list == [None] * len(color_list):
                color_spec = [None] * len(color_list)

                for i in range(0, len(color_list)):
                    # get the color
                    if color_spec[i] is None:
                        color_spec[i] = self.get_color_list(i)

                    try:
                        color_spec[i] = matplotlib.colors.rgb2hex(color_spec[i])
                    except:
                        pass

            else:
                # otherwise assume all the colors are rgba
                for color in color_list:
                    color = 'rgba' + str(color)
                    color_spec.append(color)

            start = 0

            for i in range(0, len(data_frame_list)):
                data_frame = data_frame_list[i]

                if isinstance(chart_type, list):
                    chart_type_ord = chart_type[i]
                else:
                    chart_type_ord = chart_type

                end = start + len(data_frame.columns)
                color_spec1 = color_spec[start:start + end]
                start = end

                if chart_type_ord == 'surface':
                    fig = data_frame.iplot(kind=chart_type,
                                           title=style.title,
                                           xTitle=style.x_title,
                                           yTitle=style.y_title,
                                           x=x, y=y, z=z,
                                           mode=mode,
                                           size=marker_size,
                                           theme=style.plotly_theme,
                                           bestfit=style.line_of_best_fit,
                                           legend=style.display_legend,
                                           colorscale=style.color,
                                           dimensions=(style.width * abs(style.scale_factor) * scale,
                                                       style.height * abs(style.scale_factor) * scale),
                                           asFigure=True)
                elif chart_type_ord == 'heatmap':
                    fig = data_frame.iplot(kind=chart_type,
                                           title=style.title,
                                           xTitle=style.x_title,
                                           yTitle=style.y_title,
                                           x=x, y=y,
                                           mode=mode,
                                           size=marker_size,
                                           theme=style.plotly_theme,
                                           bestfit=style.line_of_best_fit,
                                           legend=style.display_legend,
                                           colorscale=style.color,
                                           dimensions=(style.width * abs(style.scale_factor) * scale,
                                                       style.height * abs(style.scale_factor) * scale),
                                           asFigure=True)

                    # TODO get annotations to work on Plotly/cufflinks heatmaps

                    # z = data_frame.values
                    #
                    # annotations = []
                    # for n, row in enumerate(z):
                    #     for m, val in enumerate(row):
                    #         val = z[n][m]
                    #         annotations.append(
                    #             dict(
                    #                 text=str(val),
                    #                 x=x[m], y=y[n],
                    #                 xref='x1', yref='y1',
                    #                 font=dict(color='white' if val > 0.5 else 'black'),
                    #                 showarrow=False)
                    #         )
                    #
                    # fig['layout'].update(
                    #     annotations=annotations,
                    # )

                elif chart_type_ord == 'line':
                    chart_type_ord = 'scatter'
                elif chart_type_ord == 'scatter':
                    mode = 'markers'
                    marker_size = 5
                elif chart_type_ord == 'bubble':
                    x = data_frame.columns[0]
                    y = data_frame.columns[1]
                    z = data_frame.columns[2]

                # special case for choropleth which has yet to be implemented in Cufflinks
                # will likely remove this in the future
                elif chart_type_ord == 'choropleth':

                    for col in data_frame.columns:
                        try:
                            data_frame[col] = data_frame[col].astype(str)
                        except:
                            pass

                    if style.color != []:
                        color = style.color
                    else:
                        color = [[0.0, 'rgb(242,240,247)'], [0.2, 'rgb(218,218,235)'], [0.4, 'rgb(188,189,220)'], \
                                 [0.6, 'rgb(158,154,200)'], [0.8, 'rgb(117,107,177)'], [1.0, 'rgb(84,39,143)']]

                    text = ''

                    if 'text' in data_frame.columns:
                        text = data_frame['Text']

                    data = [dict(
                        type='choropleth',
                        colorscale=color,
                        autocolorscale=False,
                        locations=data_frame['Code'],
                        z=data_frame[style.plotly_choropleth_field].astype(float),
                        locationmode=style.plotly_location_mode,
                        text=text,
                        marker=dict(
                            line=dict(
                                color='rgb(255,255,255)',
                                width=1
                            )
                        ),
                        colorbar=dict(
                            title=style.units
                        )
                    )]

                    layout = dict(
                        title=style.title,
                        geo=dict(
                            scope=style.plotly_scope,
                            projection=dict(type=style.plotly_projection),
                            showlakes=True,
                            lakecolor='rgb(255, 255, 255)',
                        ),
                    )

                    fig = dict(data=data, layout=layout)

                if chart_type_ord not in ['surface', 'choropleth', 'heatmap']:

                    fig = data_frame.iplot(kind=chart_type_ord,
                                           title=style.title,
                                           xTitle=style.x_title,
                                           yTitle=style.y_title,
                                           x=x, y=y, z=z,
                                           subplots=False,
                                           mode=mode,
                                           size=marker_size,
                                           theme=style.plotly_theme,
                                           bestfit=style.line_of_best_fit,
                                           legend=style.display_legend,
                                           color=color_spec1,
                                           dimensions=(style.width * abs(style.scale_factor) * scale,
                                                       style.height * abs(style.scale_factor) * scale),
                                           asFigure=True)

                fig.update(dict(layout=dict(legend=dict(
                    x=0.05,
                    y=1
                ))))

                import plotly.graph_objs as go

                if style.thin_margin:
                    fig.update(dict(layout=dict(margin=go.Margin(
                        l=20,
                        r=20,
                        b=40,
                        t=40,
                        pad=0
                    ))))

                fig.update(dict(layout=dict(paper_bgcolor='rgba(0,0,0,0)')))
                fig.update(dict(layout=dict(plot_bgcolor='rgba(0,0,0,0)')))

                fig_list.append(fig)

            if len(fig_list) > 1:
                import cufflinks
                fig = cufflinks.subplots(fig_list)
            else:
                fig = fig_list[0]

        self.publish_plot(fig, style)

    def publish_plot(self, fig, style):
        fig.update(dict(layout=dict(paper_bgcolor='rgba(0,0,0,0)')))
        fig.update(dict(layout=dict(plot_bgcolor='rgba(0,0,0,0)')))

        if style.plotly_plot_mode == 'online':
            plotly.tools.set_credentials_file(username=style.plotly_username, api_key=style.plotly_api_key)

            plotly.plotly.plot(fig, filename=style.plotly_url,
                    world_readable=style.plotly_world_readable,
                    auto_open = not(style.silent_display),
                    asImage=style.plotly_as_image)

        elif style.plotly_plot_mode == 'offline_html':
            if style.html_file_output is not None:
                temp_html = style.html_file_output
            else:
                import time
                style.html_file_output = self.get_time_stamp() + "-plotly.html"
                temp_html = style.html_file_output

            plotly.offline.plot(fig, filename=temp_html, auto_open = not(style.silent_display))

        elif style.plotly_plot_mode == 'offline_jupyter':

            # plot in IPython notebook
            plotly.offline.init_notebook_mode()
            plotly.offline.iplot(fig)

        # plotly.offline.plot(fig, filename=style.file_output, format='png',
        #         width=style.width * style.scale_factor, height=style.height * style.scale_factor)
        try:
            plotly.plotly.image.save_as(fig, filename=style.file_output, format='png',
                                width=style.width * abs(style.scale_factor), height=style.height * abs(style.scale_factor))
        except: pass

    def get_color_list(self, i):
        color_palette = cc.plotly_palette

        return color_palette[i % len(color_palette)]

#######################################################################################################################

class ColorMaster:

    def create_color_list(self, style, data_frame, cols = None):
        if cols is None:
            cols = data_frame.columns

        # get all the correct colors (and construct gradients if necessary eg. from 'blues')
        color = self.construct_color(style, 'color', len(cols) - len(style.color_2_series))
        color_2 = self.construct_color(style, 'color_2', len(style.color_2_series))

        return self.assign_color(cols, color, color_2,
                                 style.exclude_from_color, style.color_2_series)

    def construct_color(self, style, color_field_name, no_of_entries):
        color = []

        if hasattr(style, color_field_name):
            if isinstance(getattr(style, color_field_name), list):
                color = getattr(style, color_field_name, color)
            else:
                try:
                    color = self.create_colormap(no_of_entries, getattr(style, color_field_name))
                except:
                    pass

        return color

    def exclude_from_color(self, style):
        if not (isinstance(style.exclude_from_color, list)):
            style.exclude_from_color = [style.exclude_from_color]

        exclude_from_color = [str(x) for x in style.exclude_from_color]

        return exclude_from_color

    def assign_color(self, labels, color, color_2, exclude_from_color,
                     color_2_series):

        color_list = []

        axis_1_color_index = 0;
        axis_2_color_index = 0

        # convert all the labels to strings
        labels = [str(x) for x in labels]

        # go through each label
        for label in labels:
            color_spec = None

            if label in exclude_from_color:
                color_spec = None

            elif label in color_2_series:
                if color_2 != []:
                    color_spec = self.get_color_code(color_2[axis_2_color_index])
                    axis_2_color_index = axis_2_color_index + 1

            else:
                if color != []:
                    color_spec = self.get_color_code(color[axis_1_color_index])
                    axis_1_color_index = axis_1_color_index + 1

            try:
                color_spec = matplotlib.colors.colorConverter.to_rgba(color_spec)
            except:
                pass

            color_list.append(color_spec)

        return color_list

    def get_color_code(self, code):
        # redefine color names
        dict = cc.chartfactory_color_overwrites

        if code in dict: return dict[code]

        return code

    def create_colormap(self, num_colors, map_name):
        ## matplotlib ref for colors: http://matplotlib.org/examples/color/colormaps_reference.html

        cm = matplotlib.cm.get_cmap(name=map_name)

        return [cm(1. * i / num_colors) for i in range(num_colors)]


n = int(input())
ar = [0] * n

mp, mp1 = {}, {}
for i in range(n):
    ar[i] = input()
    if ar[i] in mp:
        mp[ar[i]] += 1
    else:
        mp[ar[i]] = 1

m = int(input())
br = [0] * m

for j in range(m):
    br[j] = input()
    mp1[br[j]] = mp1[br[j]] + 1 if br[j] in mp1 else 1

res = 0

for i in range(n):
    res = max(res, mp[ar[i]] - ( mp1[ar[i]] if ar[i] in mp1 else 0))

print(res)


import pandas as pd
import numpy as np
from tqdm import tqdm
import os
import datetime

from matplotlib import pyplot as plt
import matplotlib

matplotlib.rcParams["figure.dpi"] = 300
matplotlib.rcParams["xtick.labelsize"] = 13
matplotlib.rcParams["ytick.labelsize"] = 13

colors = plt.rcParams["axes.prop_cycle"].by_key()["color"]

from utils.config import config
from similarityMeasures import getValidTrips
from clusterVisualization import getHierarchicalResult, filterClasses, draw_relative

def changeDetection(user_df, window_size, slidingThres, lag, threshold, influence):
    """
    Change detection for each individual.

    Including sliding window based change detection and HHI index based change detection.
    """
    current_user = user_df["userid"].unique()[0]

    #
    tripClass_df, _ = getHierarchicalResult(current_user)
    # create the analysis folder if not exist
    curr_path = config["resultFig"] + f"\\{current_user}"
    if not os.path.exists(curr_path):
        os.makedirs(curr_path)

    # filter classes, here >3% and not larger than 5
    tripClass_df = filterClasses(tripClass_df)

    ### sliding window change detection
    changePeriods = _slidingWindowDetection(tripClass_df, window_size=window_size, threshold=slidingThres)
    # plot
    _, idx = draw_relative(tripClass_df, window_size)
    for change_point in changePeriods.to_dict("records"):
        plt.axvspan(xmin=idx[change_point["start"]], xmax=idx[change_point["end"]], color="green", alpha=0.2)
    plt.legend("", frameon=False)
    plt.savefig(curr_path + "/count_rel_change.png", bbox_inches="tight", dpi=600)
    plt.close()

    ### HHI change detection
    peaks, HHI_ls, idx = _HHIDetection(
        tripClass_df, window_size=window_size, lag=lag, threshold=threshold, influence=influence
    )
    _plotHHIDetection(peaks, HHI_ls, idx, curr_path)

    return pd.Series([changePeriods.values, peaks["signals"]], index=["windowDetectionPeriods", "HHIDetectionSignals"])

def _HHIDetection(df, window_size=5, lag=5, threshold=3, influence=1):
    """Calculate HHI index of df for each window_size, and detect anomaly signals using __thresholdingAlgo."""
    weeks = (df["endt"].max() - df["startt"].min()).days // 7
    start_date = df["startt"].min().date()

    HHI_ls = []
    # construct the sliding week gdf
    for i in range(0, weeks - window_size + 1):
        curr_start = datetime.datetime.combine(start_date + datetime.timedelta(weeks=i), datetime.time())
        curr_end = datetime.datetime.combine(curr_start + datetime.timedelta(weeks=window_size), datetime.time())

        # current trip
        c_df = df.loc[(df["startt"] >= curr_start) & (df["endt"] < curr_end)]

        # get HHI at each time step
        HHI_ls.append(__getHHI(c_df))

    # apply __thresholdingAlgo to the HHI time series
    peaks = __thresholdingAlgo(HHI_ls, lag=lag, threshold=threshold, influence=influence)

    idx = pd.date_range(
        start=start_date + datetime.timedelta(weeks=window_size), periods=weeks - window_size + 1, freq="W"
    )

    return peaks, HHI_ls, idx

def _plotHHIDetection(peaks, HHI_ls, idx, curr_path):
    """
    Plot the result of the HHI change dection.

    Including:
    1. HHI index, moving mean and upper/lower bound time evolution
    2. Detected signals.
    """

    HHI_df = pd.DataFrame(HHI_ls, columns=["HHI"], index=idx)

    peaks["avgFilter"] = np.insert(peaks["avgFilter"], 0, 0)
    peaks["stdFilter"] = np.insert(peaks["stdFilter"], 0, 0)
    HHI_df["avgFilter"] = peaks["avgFilter"][:-1]
    HHI_df["stdFilter"] = peaks["stdFilter"][:-1]
    HHI_df["HHI"].plot(label="HHI", color=colors[0])

    HHI_df["avgFilter"].plot(label="Moving mean", figsize=(6.4, 2), color=colors[1], alpha=0.5)

    (HHI_df["avgFilter"] + 3 * HHI_df["stdFilter"]).plot(label="Upper/lower bound", color="grey", alpha=0.5)
    (HHI_df["avgFilter"] - 3 * HHI_df["stdFilter"]).plot(color="grey", alpha=0.5)
    plt.legend(["HHI", "Moving mean", "upper/lower bound"])

    plt.ylabel("HHI index", fontsize=16)
    plt.ylim([0.1, 0.6])
    # plt.show()
    plt.savefig(curr_path + "/HHI.png", bbox_inches="tight", dpi=600)
    plt.close()

    signal_df = pd.DataFrame(peaks["signals"], columns=["signal"], index=idx)
    signal_df["signal"].plot(color="red", figsize=(6.4, 2))
    plt.ylabel("Signal", fontsize=16)
    plt.yticks([-1, 0, 1])
    plt.savefig(curr_path + "/signals.png", bbox_inches="tight", dpi=600)
    plt.close()

def _slidingWindowDetection(df, window_size, threshold):
    """Detect the minimum change period where any class has changed larger than threshold."""

    weeks = (df["endt"].max() - df["startt"].min()).days // 7
    start_date = df["startt"].min().date()

    dist_ls = []
    # construct the sliding week gdf
    for i in range(0, weeks - window_size + 1):
        curr_start = datetime.datetime.combine(start_date + datetime.timedelta(weeks=i), datetime.time())
        curr_end = datetime.datetime.combine(curr_start + datetime.timedelta(weeks=window_size), datetime.time())

        # current trip
        c_df = df.loc[(df["startt"] >= curr_start) & (df["endt"] < curr_end)]

        # get the count distribution of each cluster
        cluster_num = c_df.groupby("cluster").size().to_frame("Size")
        distribution = cluster_num / cluster_num.sum()
        dist_ls.append(distribution)

    change_ls = []

    # start to ensure no overlapping change time
    start = 0

    curr_max = 0
    hold_start = -1
    hold_change = -1
    find_subset = False
    for i, curr_dist in enumerate(dist_ls):
        if not find_subset:  # find the starting j
            curr_max = 0
            change_pre = 0
            # iteratively go one time step forward
            for j in range(i - 1, start - 1, -1):
                # get the distribution change of each class
                combined = curr_dist.join(dist_ls[j], lsuffix="l", rsuffix="r")
                change = np.abs(combined["Sizel"] - combined["Sizer"])

                # if the largest distribution change is smaller than the previous timestep
                # add small term to allow pertubation
                if change.max() + 0.05 < change_pre:
                    break
                change_pre = change.max()

                # largest distribution change should be larger than our defined threshold
                if change.max() > threshold:
                    # largest distribution change should be larger than curr_max
                    if change.max() > curr_max:
                        hold_start = j
                        curr_max = change.max()
                        hold_change = change.max()
                        find_subset = True
                    else:  # if change drops, we immediately find the start point as hold_start
                        break

                # cut stable periods and ensure no super long change periods
                if (change < 0.05).all() and (i - j) > 15:
                    start = j - 1
                    break
        else:  # we have now found the start j, now we find the ending i
            combined = curr_dist.join(dist_ls[hold_start], lsuffix="l", rsuffix="r")
            change = np.abs(combined["Sizel"] - combined["Sizer"])
            # we try to find changes larger than hold_change
            if change.max() > hold_change:
                hold_change = change.max()
                if i < len(dist_ls) - 1:
                    continue

            # we now get the change period [hold_start, end]
            if i == len(dist_ls) - 1:
                end = i
            else:
                end = i - 1
            change_ls.append([hold_start, end])
            start = end
            hold_change = -1
            find_subset = False

    change_points = pd.DataFrame(change_ls, columns=["start", "end"])
    return change_points

def __getHHI(df):
    """HHI index calculation."""
    prop = df["cluster"].value_counts(normalize=True).values
    return np.sum(prop ** 2)

def __thresholdingAlgo(y, lag, threshold, influence):
    """
    Peak detection algorithm.
    From https://stackoverflow.com/questions/22583391/peak-signal-detection-in-realtime-timeseries-data
    """
    signals = np.zeros(len(y))
    filteredY = np.array(y)
    avgFilter = [0] * len(y)
    stdFilter = [0] * len(y)
    avgFilter[lag - 1] = np.mean(y[0:lag])
    stdFilter[lag - 1] = np.std(y[0:lag])
    for i in range(lag, len(y)):
        if abs(y[i] - avgFilter[i - 1]) > threshold * stdFilter[i - 1]:
            if y[i] > avgFilter[i - 1]:
                signals[i] = 1
            else:
                signals[i] = -1

            filteredY[i] = influence * y[i] + (1 - influence) * filteredY[i - 1]
            avgFilter[i] = np.mean(filteredY[(i - lag + 1) : i + 1])
            stdFilter[i] = np.std(filteredY[(i - lag + 1) : i + 1])
        else:
            signals[i] = 0
            filteredY[i] = y[i]
            avgFilter[i] = np.mean(filteredY[(i - lag + 1) : i + 1])
            stdFilter[i] = np.std(filteredY[(i - lag + 1) : i + 1])

    return dict(signals=np.asarray(signals), avgFilter=np.asarray(avgFilter), stdFilter=np.asarray(stdFilter))

if __name__ == "__main__":

    time_window = 5
    slidingThres = 0.3
    lag = 5
    threshold = 3
    influence = 1

    t_df = getValidTrips(time_window=time_window)

    tqdm.pandas(desc="change detection")
    detectionResults = t_df.groupby("userid").progress_apply(
        changeDetection,
        window_size=time_window,
        slidingThres=slidingThres,
        lag=lag,
        threshold=threshold,
        influence=influence,
    )
    print(detectionResults)


#! /usr/bin/env python3

from typing import Any, Iterable
from hydra.runner import Runner
from hydra.baseline import Baseline
from hydra.instance import Instance

class Remote(Runner):
    def __init__(self):
        self.jobs = []
        return

    def run(self, baseline: Baseline, data: Iterable[Any]) -> int:
        common = baseline.get_common_files()
        print(f"Creating asset collection for common files: {common}")
        count = 0
        for item in data:
            instance = baseline.get_instance(item)
            self.execute(instance)
            count += 1
        return count

    def get_job(self, uid: int):
        return self.jobs[uid]

    def execute(self, instance: Instance):
        commandline = instance.get_commandline()
        files = instance.get_instance_files()
        if len(files):
            print(f"Creating asset collection for bespoke files: {files}")
        print(f"Running instance REMOTELY with commandline '{commandline}'")
        self.jobs.append((commandline, files))
        return


import math

from PIL import Image, ImageDraw

def get_angle(p1, p2, p3):
    """
    Calculates the angle between three points
    https://en.wikipedia.org/wiki/Law_of_cosines#Applications

    :param p1: center point
    :type p1: tuple
    :type p2: tuple
    :type p3: tuple

    :rtype: float
    """
    f = point_distance
    p12 = f(p1, p2)
    p13 = f(p1, p3)
    p23 = f(p2, p3)

    if p12 == 0 or p13 == 0:
        return math.acos(0)

    result = (p12 ** 2 + p13 ** 2 - p23 ** 2) / (2 * p12 * p13)
    return math.acos(result)

def convert_to_degree(radian):
    return math.degrees(radian)

def point_distance(a, b):
    """
    Calculates distance between two points

    :rtype: float
    """
    return math.sqrt(pow(a[0] - b[0], 2) + pow(a[1] - b[1], 2))

def get_control_points(coords, alpha):
    """
    Returns list of control points that are created from coordinates.

    Result list will be 2 * len(coords)

    :param coords: list of coordinates
    :param alpha: smooth factor
    :rtype : list[tuple(2)]
    """
    assert 0 < alpha < 1

    cpoints = []
    n = len(coords)

    v = [(0, 0), list(coords[n - 1]), list(coords[0])]

    mid = [[0, 0],
           [(v[1][0] + v[2][0]) / 2.0, (v[1][1] + v[2][1]) / 2.0]]
    vdist = [0, point_distance(v[1], v[2])]
    anchor = [0, 0]

    for i in range(n):
        v[0] = v[1]
        v[1] = v[2]
        v[2] = coords[(i + 1) % n]

        mid[0][0] = mid[1][0]
        mid[0][1] = mid[1][1]
        mid[1][0] = (v[1][0] + v[2][0]) / 2.0
        mid[1][1] = (v[1][1] + v[2][1]) / 2.0

        vdist[0] = vdist[1]
        vdist[1] = point_distance(v[1], v[2])

        p = vdist[0] / (vdist[0] + vdist[1])

        anchor[0] = mid[0][0] + p * (mid[1][0] - mid[0][0])
        anchor[1] = mid[0][1] + p * (mid[1][1] - mid[0][1])

        xdelta = anchor[0] - v[1][0]
        ydelta = anchor[1] - v[1][1]

        c0 = (
            alpha * (v[1][0] - mid[0][0] + xdelta) + mid[0][0] - xdelta,
            alpha * (v[1][1] - mid[0][1] + ydelta) + mid[0][1] - ydelta)

        c1 = (
            alpha * (v[1][0] - mid[1][0] + xdelta) + mid[1][0] - xdelta,
            alpha * (v[1][1] - mid[1][1] + ydelta) + mid[1][1] - ydelta)

        cpoints.append([c0, c1])

    return cpoints

def cubic_bezier(start, end, ctrl1, ctrl2, nv):
    """
    Create bezier curve between start and end points

    :param start: start anchor point
    :param end: end anchor point
    :param ctrl1: control point 1
    :param ctrl2: control point 2
    :param nv: number of points should be created between start and end
    :return: list of smoothed points
    """
    result = [start]

    for i in range(nv - 1):
        t = float(i) / (nv - 1)
        tc = 1.0 - t

        t0 = tc * tc * tc
        t1 = 3.0 * tc * tc * t
        t2 = 3.0 * tc * t * t
        t3 = t * t * t
        tsum = t0 + t1 + t2 + t3

        x = (t0 * start[0] + t1 * ctrl1[0] + t2 * ctrl2[0] + t3 * end[0]) / tsum
        y = (t0 * start[1] + t1 * ctrl1[1] + t2 * ctrl2[1] + t3 * end[1]) / tsum

        result.append((x, y))

    result.append(end)
    return result

def line(p0, p1):
    """
    Create line between two points based on Bresenham algorithm
    """

    steep = False
    x0 = p0[0]
    y0 = p0[1]
    x1 = p1[0]
    y1 = p1[1]

    if math.fabs(x0 - x1) < math.fabs(y0 - y1):
        x0, y0 = y0, x0
        x1, y1 = y1, x1
        steep = True

    if x0 > x1:
        x0, x1 = x1, x0
        y0, y1 = y1, y0

    dx = x1 - x0
    dy = y1 - y0

    if dx == 0:
        derror = 0.1
    else:
        derror = math.fabs(dy / dx)

    error = 0.0
    y = y0
    x = x0
    points = []

    while x <= x1:
        points.append((y, x) if steep else (x, y))

        error += derror

        if error > 0.5:
            y += 1 if y1 > y0 else -1
            error -= 1.
        x += 1

    return points

def smooth_points(coords, alpha, min_angle=45):
    """
    Converts a list of points to polygon based on bezier curves

    http://www.elvenprogrammer.org/projects/bezier/reference/

    :param coords: list of coordinates
    :param alpha: smooth factor
    :return: point list of smoothed polygon
    :rtype : list
    """
    vertices_count = len(coords)
    cpoints = get_control_points(coords, alpha)
    points = []

    i = 0
    while i < vertices_count:
        i_prev = (i - 1) % vertices_count
        i_next = (i + 1) % vertices_count
        i_next_2 = (i + 2) % vertices_count

        p_current = coords[i]
        p_prev = coords[i_prev]
        p_next = coords[i_next]
        p_next_2 = coords[i_next_2]

        angle = convert_to_degree(get_angle(p_current, p_prev, p_next))
        angle2 = convert_to_degree(get_angle(p_next, p_current, p_next_2))

        if angle <= min_angle:
            segment = line(p_current, p_next)
        elif angle2 <= min_angle:
            segment = line(p_current, p_next)
        else:
            segment = cubic_bezier(p_current, p_next,
                                   cpoints[i][1], cpoints[i_next][0],
                                   10)
        points.extend(segment)
        i += 1

    return points

def __main():
    print(line((0, 0), (5, 10)))
    print(line((300, 100), (200, 250)))

    im = Image.new('RGBA', (100, 100), (0, 0, 0, 0))
    draw = ImageDraw.Draw(im)

    coords = [(10, 30), (20, 20),
              (30, 10), (50, 10),
              (50, 30), (30, 30),
              (10, 30)]

    vertices_count = len(coords)

    cpoints = get_control_points(coords, 0.5)

    points = []

    for i in range(vertices_count):
        i_next = (i + 1) % vertices_count

        segment = cubic_bezier(coords[i], coords[i_next],
                               cpoints[i][1], cpoints[i_next][0],
                               10)
        points.extend(segment)

    draw.polygon(points, fill='red', outline='black')
    im.save('out2.png')

if __name__ == '__main__':
    __main()


message = '노랑 빨강 녹색 파랑 노랑 빨강 노랑 빨강'
print(message.split())

d = dict()
for c in message.split():
    if c not in d:
        d[c] = 1
    else:
        d[c] = d[c] + 1
print (d)


from unittest import TestCase
from src.data.prepare_dataset import ClassificationTrainsetBuilder

class TestClassificationTrainsetBuilder(TestCase):

    def test_get_formatting_mask_on_single_token_ne(self):
        mask = ClassificationTrainsetBuilder._get_formatting_mask(33)
        self.assertEqual(33, len(mask))
        self.assertEqual(1, sum(mask))

    def test_get_formatting_mask_on_multiple_token_ne(self):
        mask = ClassificationTrainsetBuilder._get_formatting_mask(36)
        self.assertEqual(36, len(mask))
        self.assertEqual(4, sum(mask))


# -----------------------------------------------------------------------------
# WWW 2019 Debiasing Vandalism Detection Models at Wikidata
#
# Copyright (c) 2019 Stefan Heindorf, Yan Scholten, Gregor Engels, Martin Potthast
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# -----------------------------------------------------------------------------

import sys

def sizeof_fmt(num, suffix='B'):
    ''' By Fred Cirera, after https://stackoverflow.com/a/1094933/1870254'''
    for unit in ['', 'Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi']:
        if abs(num) < 1024.0:
            return '%3.1f%s%s' % (num, unit, suffix)
        num /= 1024.0
    return '%.1f%s%s' % (num, 'Yi', suffix)

def top_memory_usage(variables):
    variable_sizes = []
    for name, value in variables.items():
        variable_sizes.append((name, sys.getsizeof(value)))

    for name, size in sorted(variable_sizes, key=lambda x: -x[1])[:10]:
        print('{:>30}: {:>8}'.format(name, sizeof_fmt(size)))


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

import xlsxwriter
import time
import casedatademo,testrequestmodel, alltestcaserunner
from getpath import get_reportpath
from loggerclass import logger

def get_format(wd, option={}):
    return wd.add_format(option)

# 设置居中
def get_format_center(wd, num=1, color='black', bold=False):
    return wd.add_format({'align': 'center', 'valign': 'vcenter', 'border': num, 'font_color': color, 'bold': bold})
# 设置靠左
def get_format_left(wd, num=1, color='black', bold=False):
    return wd.add_format({'align': 'left', 'valign': 'vcenter', 'border': num, 'font_color': color, 'bold': bold})
# 设置边框
def set_border_(wd, num=1):
    return wd.add_format({}).set_border(num)

# 写数据（居中）
def _write_center(worksheet, cl, data, wd):
    return worksheet.write(cl, data, get_format_center(wd))
# 写数据（居中-带字体颜色-带字体加粗）
def _write_center_fontstyle(worksheet, cl, data, wd, color, bold):
    return worksheet.write(cl, data, get_format_center(wd, color=color, bold=bold))
# 写数据（靠左）
def _write_left(worksheet, cl, data, wd):
    return worksheet.write(cl, data, get_format_left(wd))
# 写数据（靠左-带字体颜色）
def _write_left_fontcolor(worksheet, cl, data, wd, color):
    return worksheet.write(cl, data, get_format_left(wd, color=color))

# 生成饼形图
def pie(workbook, worksheet):
    chart1 = workbook.add_chart({'type': 'pie'})
    chart1.add_series({
        'name':       '接口测试统计',
        'categories': '=测试总况!$D$4:$D$5',
        'values':    '=测试总况!$E$4:$E$5',
    })
    chart1.set_title({'name': '接口测试统计'})
    chart1.set_style(10)
    worksheet.insert_chart('A9', chart1, {'x_offset': 25, 'y_offset': 10})

def init(worksheet):
    # 设置列行的宽高
    worksheet.set_column("A:A", 15)
    worksheet.set_column("B:B", 20)
    worksheet.set_column("C:C", 20)
    worksheet.set_column("D:D", 20)
    worksheet.set_column("E:E", 20)
    worksheet.set_column("F:F", 20)

    worksheet.set_row(1, 30)
    worksheet.set_row(2, 30)
    worksheet.set_row(3, 30)
    worksheet.set_row(4, 30)
    worksheet.set_row(5, 30)
    # worksheet.set_row(0, 200)

    define_format_H1 = get_format(workbook, {'bold': True, 'font_size': 18})
    define_format_H2 = get_format(workbook, {'bold': True, 'font_size': 14})
    define_format_H1.set_border(1)

    define_format_H2.set_border(1)
    define_format_H1.set_align("center")
    define_format_H2.set_align("center")
    define_format_H2.set_bg_color("blue")
    define_format_H2.set_color("#ffffff")
    # Create a new Chart object.

    worksheet.merge_range('A1:F1', '接口自动化测试报告', define_format_H1)
    worksheet.merge_range('A2:F2', '测试概括', define_format_H2)
    worksheet.merge_range('A3:A6', data['项目'], get_format_center(workbook))
    # worksheet.insert_image('A1', GetLogoDataPath())

    _write_center(worksheet, "B3", '项目名称', workbook)
    _write_center(worksheet, "B4", '接口版本', workbook)
    _write_center(worksheet, "B5", '脚本语言', workbook)
    _write_center(worksheet, "B6", '测试地址', workbook)

    # data = {"test_name": "MyProject项目接口", "test_version": "v1.0.0",
    #         "test_pl": "Python3", "test_net": testurl}
    _write_center(worksheet, "C3", data['项目名称'], workbook)
    _write_center(worksheet, "C4", data['接口版本'], workbook)
    _write_center(worksheet, "C5", data['脚本语言'], workbook)
    _write_center(worksheet, "C6", data['测试地址'], workbook)
    _write_center(worksheet, "D3", "测试用例总数", workbook)
    _write_center(worksheet, "D4", "测试用例通过数", workbook)
    _write_center(worksheet, "D5", "测试用例失败数", workbook)
    _write_center(worksheet, "D6", "测试日期", workbook)

    data1 = {"test_sum": len(TestReport),
             "test_success": hpassnum,
             "test_failed": len(TestReport) - hpassnum,
             "test_date": timenow}
    _write_center(worksheet, "E3", data1['test_sum'], workbook)
    _write_center(worksheet, "E4", data1['test_success'], workbook)
    color = color1 = 'red'
    bold = True
    if len(TestReport) - hpassnum == 0:
        color = 'black'
        color1 = 'green'
        bold = False
    _write_center_fontstyle(worksheet, "E5", data1['test_failed'], workbook, color=color, bold=bold)
    _write_center(worksheet, "E6", data1['test_date'], workbook)
    _write_center(worksheet, "F3", "测试用例通过率", workbook)
    worksheet.merge_range('F4:F6', str(
        (round(hpassnum / len(TestReport), 2)) * 100) + '%', get_format_center(workbook, color=color1, bold=bold))

    pie(workbook, worksheet)

def test_detail(worksheet):

    # 设置列宽高
    worksheet.set_column("A:A", 30)
    worksheet.set_column("B:B", 20)
    worksheet.set_column("C:C", 20)
    worksheet.set_column("D:D", 20)
    worksheet.set_column("E:E", 20)
    worksheet.set_column("F:F", 20)
    worksheet.set_column("G:G", 20)
    worksheet.set_column("H:H", 20)

    # 设置行的宽高
    for hrow in range(len(TestReport) + 2):
        worksheet.set_row(hrow, 30)

    worksheet.merge_range('A1:H1', '测试详情', get_format(workbook, {'bold': True,
                                                                 'font_size': 18,
                                                                 'align': 'center',
                                                                 'valign': 'vcenter',
                                                                 'bg_color': 'blue',
                                                                 'font_color': '#ffffff'}))
    _write_center_fontstyle(worksheet, "A2", '用例ID', workbook, color="black", bold=True)
    _write_center_fontstyle(worksheet, "B2", '接口名称', workbook, color="black", bold=True)
    _write_center_fontstyle(worksheet, "C2", '接口协议', workbook, color="black", bold=True)
    _write_center_fontstyle(worksheet, "D2", 'URL', workbook, color="black", bold=True)
    _write_center_fontstyle(worksheet, "E2", '参数', workbook, color="black", bold=True)
    _write_center_fontstyle(worksheet, "F2", '预期输出', workbook, color="black", bold=True)
    _write_center_fontstyle(worksheet, "G2", '实际输出', workbook, color="black", bold=True)
    _write_center_fontstyle(worksheet, "H2", '测试结果', workbook, color="black", bold=True)

    #data = {"info": TestReport}  # 获取测试结果被添加到测试报告里

    temp = 3
    #global hpassnum
    for item in TestReport.values():
        #if item["t_result"] == "通过":
        #    hpassnum += 1
        #else:
        #    pass
        _write_center(worksheet, "A" + str(temp), item["t_id"], workbook)
        _write_center(worksheet, "B" + str(temp), item["t_name"], workbook)
        _write_center(worksheet, "C" + str(temp), item["t_method"], workbook)
        _write_left(worksheet, "D" + str(temp), item["t_url"], workbook)
        _write_left(worksheet, "E" + str(temp), item["t_param"], workbook)

        if item["t_result"] == "失败":
            _write_left_fontcolor(worksheet, "F" + str(temp), item["t_hope"], workbook, color='red')
            _write_left_fontcolor(worksheet, "G" + str(temp), item["t_real"], workbook, color='red')
            _write_center_fontstyle(worksheet, "H" + str(temp), item["t_result"], workbook, color='red', bold=True)
        else:
            _write_left(worksheet, "F" + str(temp), item["t_hope"], workbook)
            _write_left(worksheet, "G" + str(temp), item["t_real"], workbook)
            _write_center(worksheet, "H" + str(temp), item["t_result"], workbook)
        temp += 1

try:
    workbook = xlsxwriter.Workbook(get_reportpath())
    worksheet = workbook.add_worksheet("测试总况")
    worksheet2 = workbook.add_worksheet("用例详情")

    # casedatademo.allquestionlist_datademo()
    # casedatademo.choicelist_datademo()
    # casedatademo.vote_datademo()
    # casedatademo.loginpro_datademo()
    # casedatademo.novelSearchApi_datademo()
    # casedatademo.createUserKey_datademo()
    # casedatademo.createUser_datademo()
    #print("result4的结果为:%s" % result)
    #TestReport = result #TestRequest.hlist  # 调用测试结果

    alltestcaserunner.getthreads()
    TestReport = testrequestmodel.result
    # 定义一个变量，用来计算测试通过的用例数量
    hpassnum = 0
    for value in TestReport.values():
        if type(value) == dict:
            if value['t_result'] == "成功":
                hpassnum += 1
    logger.info("总测试用例数量：%d，通过的测试用例数：%d" %(len(TestReport), hpassnum))
    data = casedatademo.get_frist_info()
    timenow = time.strftime("%Y-%m-%d %H:%M", time.localtime(time.time()))

    init(worksheet)
    test_detail(worksheet2)
finally:
    workbook.close()