from enum import Enum, unique
from random import shuffle, random
from itertools import chain
from threading import RLock
from math import floor, log
from minesweeper.utils import digits

@unique
class State(Enum):
    UNTOUCHED = "-"
    FLAGGED = "F"
    DUG = " "

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

class Square:
    REPR_BOMB = "*"

    def __init__(self, row, col, has_bomb, state):
        self.row, self.col = row, col
        self.has_bomb = has_bomb
        self.state = state

    def __repr__(self):
        return "<'%s.%s' object, row=%d, col=%d, has_bomb=%s, state=%s>" % \
               (self.__class__.__module__, self.__class__.__name__, self.row, self.col,
                self.has_bomb, self.state.name)

    def __str__(self):
        if self.state == State.DUG and self.has_bomb:
            return Square.REPR_BOMB
        return self.state.representation

class Board:
    """ Problem 3, point b. Thread safety argument:\n
    Thread safety is currently ensured in Board only. The Square class and any other lack
    any type of coverage. Accessing some of the Board's squares through the Square class can lead to race conditions.

    Board is made thread-safe exclusively by synchronization, by using a reentrant lock (a RLock). The self._squares
    attribute, which can nevertheless be accessed even though it is marked private (Python does not provide access
    protection), can be legitimately accessed and modified by observer and mutator methods. These all use
    synchronization, and as long as a client of Board does not attempt a direct access at self._squares or at an
    instance of Square, race conditions should not occur. (Of course a rewriting of the Square class may be operated,
    for ensuring better security. This, however, is not being done for lack of time.) I do not see any piece of
    code using techniques such as thread confinement, immutability or threadsafe datatypes for ensuring thread
    security on this class. (Thread safety techniques discussed in the lecture notes of this course are, indeed,
    confinement, immutability, thread safe datatypes and synchronization.)

    Besides arguments for the thread-safety of Board, a test to confirm that no race conditions occur inside Board is
    included in board_test.py.
    """
    # Height, width, mines_count number
    DIFF_EASY = (9, 9, 10)
    DIFF_INTERMEDIATE = (16, 16, 40)
    DIFF_HARD = (16, 30, 99)

    def __init__(self, boolean_grid):
        self._squares = list()
        self._lock: RLock = RLock()

        self._lock.acquire()

        for row in range(len(boolean_grid)):
            self._squares.append(list())

            for col in range(len(boolean_grid[row])):
                self._squares[row].append(
                    Square(row, col, boolean_grid[row][col], State.UNTOUCHED)
                )

        self._check_state()
        self._lock.release()

    @staticmethod
    def create_from_probability(height, width, bomb_probability=0.25):
        """
        Create a new board by supplying a **height**, a **width** and a bomb probability parameters.

        :param height: number of rows of the board, each with an even number of elements.
        :param width: number of elements for each row.
        :param bomb_probability: the probability that a cell of the grid has a bomb during creation.
            **bomb_probability** must belong to [0, 1).
        :return: a new Board instance.
        """
        if height * width <= 0:
            raise ValueError("The grid size must be greater than 0 (found %d)" % height * width)
        if not 0 <= bomb_probability < 1:
            raise ValueError("It must be 0 <= bomb_probability <= 1 (bomb_probability = %f)" % bomb_probability)

        squares = list()

        for square in range(height * width):
            squares.append(random() <= bomb_probability)

        return Board(Board._list_to_grid(squares, height, width))

    @staticmethod
    def create_from_difficulty(difficulty=DIFF_EASY):
        """
        Create a new board by supplying a pre-made or a custom difficulty level.

        :param difficulty: a (**height**, **width**, **mines**) tuple.
        :return: a Board instance with **height** rows, each **width**-elements wide, containing
            **mines** mines randomly interspersed in its grid.
        """
        height, width, mines = difficulty

        if height * width <= 0:
            raise ValueError("The grid size must be greater than 0 (found %d)" % height * width)
        if not 0 < mines < height * width:
            raise ValueError("0 < mines < %d not true (mines = %d)" % (height * width, mines))

        squares = Board._random_mines_distribution((height * width) - mines, mines)

        return Board(Board._list_to_grid(squares, height, width))

    @staticmethod
    def create_from_file(path):
        """
        Create a new board as instructed in Problem 4 of the assignment.

        :param path: a string representing a file containing a well-formatted grid of 0s and 1s.
        :return: a new Board instance.
        """

        def read_line(text_line):
            sep = " "
            encoding = {'0': False, '1': True}

            # dict.get() returns None when a given argument is not contained within the dict keys
            line = [encoding.get(i) for i in text_line.strip().split(sep)]

            if None in line:
                raise ValueError("Found invalid content in '%s'. Every line can contain only 0s and 1s" % path)

            return line

        with open(path) as f:
            lines = [read_line(line) for line in f]

            for line in lines:
                if len(line) != len(lines):
                    raise ValueError("Found %d wide line in a %d tall grid, square grid expected" %
                                     (len(line), len(lines)))

        return Board(lines)

    def __repr__(self):
        with self._lock:
            return "<'%s.%s' object, height=%d, width=%d, mines_count=%d>" % \
                   (self.__class__.__module__, self.__class__.__name__, self.height(), self.width(), self.mines_count())

    def __str__(self):

        def format_row(row):
            result = ""

            for square in row:
                if square.state in (State.UNTOUCHED, State.FLAGGED):
                    result += "%s " % str(square)
                elif square.state == State.DUG:
                    if square.has_bomb:
                        result += "%s " % str(square)
                    else:
                        nearby_bombs = len([n for n in self.neighbors(square.row, square.col) if n.has_bomb])

                        if nearby_bombs == 0:
                            result += str(square) + " "
                        else:
                            result += "%d " % nearby_bombs

            return result

        def format_row_header():
            """
            :return: A header line to be displayed on top of the board grid.
            """
            sep = " "
            hmaxdigits = digits(self.width())               # The maximum number of digits that a column index can take
            vpad = sep * (digits(self.height() - 1) + 1)    # The vertical padding whitespace to add before this header
            # The column indices, in string form, padded with the required whitespace
            indices = [(str(i).ljust(hmaxdigits))[::-1] for i in range(self.width())]
            result = ""

            for i in range(hmaxdigits):
                # result is added a new header line at each iteration
                result += vpad + sep.join([index[i] for index in indices])

                if i < hmaxdigits - 1:
                    result += "\n"

            return result

        def vertical_padding(rowindex):
            """
            :param rowindex: index of the board row being displayed
            :return: the padding to be appended in front of a board row to allow proper alignment
            """
            return " " * (digits(self.height() - 1) + 1 - digits(rowindex))

        result = format_row_header() + "\n"

        self._lock.acquire()

        for rowindex, row in zip(range(self.height()), self._squares):
            result += str(rowindex) + vertical_padding(rowindex) + format_row(row) + "\n"

        self._lock.release()

        return result

    def __len__(self):
        with self._lock:
            return sum([len(row) for row in self._squares])

    def __contains__(self, key):
        if not (isinstance(key[0], int) and isinstance(key[1], int)):
            raise ValueError("Arguments must be integers (found %s, %s)" % (key[0], key[1]))

        with self._lock:
            return 0 <= key[0] < len(self._squares) and \
                   0 <= key[1] < len(self._squares[key[0]])

    def __iter__(self):
        with self._lock:
            return iter(chain(*self._squares))

    def square(self, row, col):
        with self._lock:
            return self._squares[row][col]

    def height(self):
        with self._lock:
            return len(self._squares)

    def width(self):
        with self._lock:
            return len(self._squares[0]) if len(self._squares) > 0 else 0

    def mines_count(self):
        """
        :return: an int indicating the number of squares where has_bomb evaluates to true, i.e. those squares
            which have a bomb, or are "mined".
        """
        with self._lock:
            return len([square for square in self if square.has_bomb])

    def set_state(self, row, col, state):
        """
        Set the state of a square indicated by (row, col) to state.
        If state is DUG and the current square has no bomb, then its adjacent squares
        are all dug if none of them has a bomb.

        :param row: row coordinate
        :param col: col coordinate
        :param state: State value to set the (row, col) square into
        """
        self._lock.acquire()

        if (row, col) not in self:
            raise ValueError("%d, %d coordinates are out of range" % (row, col))

        self._squares[row][col].state = state

        if state == State.DUG and not self._squares[row][col].has_bomb:
            neighbors = self.neighbors(row, col)
            nearby_bombs = len([n for n in neighbors if n.has_bomb])

            if nearby_bombs == 0:
                for n in [s for s in neighbors if s.state != State.DUG]:
                    self.set_state(n.row, n.col, State.DUG)

        self._lock.release()

    def neighbors(self, row, col):
        """
        :return: a list containing all those squares which are one square away from the (row, col) square, that is its
            "neighbours".
        """
        self._lock.acquire()

        result = list()
        min_row, max_row = max(row - 1, 0), min(row + 1, len(self._squares) - 1)
        min_col, max_col = max(col - 1, 0), min(col + 1, len(self._squares[row]) - 1)

        for x in range(min_row, max_row + 1):
            for y in range(min_col, max_col + 1):
                if (x, y) != (row, col):
                    result.append(self._squares[x][y])

        self._lock.release()

        return result

    def _check_state(self):
        """
        Performs validity checks on the current instance, raising relevant exceptions when detecting an invalid state.
        :return: True if no inconsistencies were found within the current instance.
        """
        self._lock.acquire()
        expected_line_length = len(self._squares[0]) if len(self._squares) > 0 else None

        for line in self._squares:
            types = {type(square) for square in line}

            if {Square} != types:
                raise ValueError("The board can only contain Square variables within its grid")
            if len(line) != expected_line_length:
                raise ValueError("Found a %d-element-wide line, expected %d" % (len(line), expected_line_length))

        self._lock.release()

        return True

    @staticmethod
    def _random_mines_distribution(empty_squares, mined_squares):
        distribution = [False for i in range(empty_squares)]
        distribution.extend([True for i in range(mined_squares)])
        shuffle(distribution)

        return distribution

    @staticmethod
    def _list_to_grid(squares, height, width):
        """
        Utility method used to convert a flat list of boolean values (representing mined squares) to
        a multi-dimensional list with specified height and width.

        :param squares: one-dimensional list of squares.
        :param height: height of the resulting grid.
        :param width: number of elements for each of the **height** rows.
        :return: a grid-like list with the same values as **squares**.
        """
        return [squares[i * width:(i * width) + width] for i in range(height)]

    def toggle_dug(self, toggles=1):
        """
        Switches the state of every square contained in this board between UNTOUCHED and DUG (see the code
        for more info). If the state of a square is FLAGGED no modification occurs.\n
        This method is primarily used for debug purposes.
        """
        self._lock.acquire()

        for i in range(toggles):
            for s in self:
                if s.state == State.UNTOUCHED:
                    # self.set_state(s.row, s.col, State.DUG)
                    s.state = State.DUG
                elif s.state == State.DUG:
                    # self.set_state(s.row, s.col, State.UNTOUCHED)
                    s.state = State.UNTOUCHED

        self._lock.release()


from flask import request
from app.v2.models.parties_model import Party
from app.v2.util.validate import response, not_admin, response_error
from app.v2.blueprints import bp
from flask_jwt_extended import (jwt_required)
from app.v2.util.jwt_utils import admin_required

@bp.route('/parties', methods=['POST', 'GET'])
@jwt_required
def create_party():
    if request.method == 'POST':
        """ Create party end point """

        restricted = not_admin()
        if restricted:
            return restricted

        data = request.get_json()

        if not data:
            return response("No data was provided", 400)

        try:
            name = data['name']
            hqaddress = data['hqaddress']
        except KeyError as e:
            return response("{} field is required".format(e.args[0]), 400)

        party = Party(name, hqaddress)

        if not party.validate_object():
            return response(party.error_message, party.error_code)

        party.save()

        # return added party
        return response("Your political party was created successfully",
                        201, [party.as_json()])

    elif request.method == 'GET':
        """ Get all parties end point """
        model = Party()
        return response('Success', 200, model.load_all())

@bp.route('/parties/<int:id>', methods=['GET', 'DELETE'])
@jwt_required
def get_party(id):

    model = Party()
    data = model.find_by('id', id)

    if not data:
        return response('Party not found', 404)

    if request.method == 'GET':
        return response('Request was successful', 200, [data])
    else:
        restricted = not_admin()
        if restricted:
            return restricted
        party = model.from_json(data)
        party.delete(party.id)
        return response(
            '{} deleted successfully'.format(party.name), 200, [data])

@bp.route('/parties/<int:id>/name', methods=['PATCH'])
@admin_required
def edit_party(id):

    data = request.get_json()

    if not data:
        return response_error("No data was provided", 400)

    try:
        name = data['name']
    except KeyError as e:
        return response_error(
            "{} field is required".format(e.args[0]), 400)

    model = Party()
    data = model.find_by('id', id)

    if not data:
        return response('Party not found', 404)

    party = model.from_json(data)
    party.name = name

    if not party.validate_object():
        return response(party.error_message, party.error_code)

    party.edit(name)

    return response(
        '{} updated successfully'.format(party.name), 200, [data])


"""Test result log analyser

This script allows the user to train or update the model on script execution logs.

This script requires that `sklean, imb-learn,numpy and pandas` be installed within the Python
environment you are running this script in.

This file can also be imported as a module and contains the following
functions:

    * train_model - trains model from scratch
    * main - the main function of the script
    * update_model - updates an existing model
"""

import datetime
import os
from collections import Counter
import time

# external libraries
import joblib
import numpy as np
import seaborn as sn
from pandas import DataFrame
import matplotlib.pyplot as plt

from sklearn.feature_extraction.text import HashingVectorizer
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import confusion_matrix

from imblearn.under_sampling import EditedNearestNeighbours
from imblearn.under_sampling import TomekLinks

class Model:
    """ Encapsulates classifier related tasks and helps loading and saving model in one go """

    def __init__(self):
        self.time_stamp = datetime.datetime.now().strftime("%Y_%b_%d_%H_%M")

        print('Model Stamp:' + self.time_stamp)

        self.clf = RandomForestClassifier(class_weight='balanced', n_jobs=-1, criterion='gini',
                                          n_estimators=50, warm_start=True)

        self.vector = HashingVectorizer(n_features=2 ** 21, alternate_sign=False, analyzer='word',
                                        decode_error='ignore', token_pattern=r'\b\w{1,}[^\d\W]+\b',
                                        ngram_range=(2, 2))

        # Samplers are not needed during testing
        self.samplers = [
            TomekLinks(random_state=11, sampling_strategy='majority', n_jobs=-1),
            EditedNearestNeighbours(random_state=7, sampling_strategy='majority', n_jobs=-1)
        ]

    def load_model(self, time_stamp):
        """loads the model with provided timestamp
        Parameters:
        timestamp: time_stamp of the model to be loaded
        """
        file_path = os.path.join('models', time_stamp + '_modl.joblib')

        if not os.path.exists(file_path):
            print('No model file found with stamp: ' + time_stamp)
            return

        mdl = load_joblib(file_path)

        # Uses current time stamp for loaded model
        self.clf = mdl.clf
        self.vector = mdl.vector
        self.samplers = mdl.samplers

        print('Model Loaded: ' + time_stamp)

    def fit_transform(self, text_train):
        """ Fit and transform text strings to frequency matrix.
        Parameters: array of training texts
        Returns: matrix of training data
        """

        add_to_log('Transforming..')
        s_time = time.time()

        x_train = self.vector.fit_transform(text_train)

        add_to_log('Transformation Time: ' + str(time.time() - s_time))

        # Save vector and matrix
        self.save_vector()
        self.save_matrix(x_train)

        return x_train

    def under_sample_data(self, matrix, y_train):

        """Remove samples from majority class to address bias in data.
         Reduces rows in x_train and y_train.

        Parameters:
        samples: x_train, labels: y_train

        Returns:
        updated samples: x_train, labels: y_train

       """

        add_to_log('Under Sampling')
        add_to_log('Original distribution %s' % Counter(y_train))
        s_time = time.time()

        x_res = matrix
        y_res = y_train

        for sampler in self.samplers:
            # clean proximity samples using TomeKLinks
            x_res, y_res = sampler.fit_resample(x_res, y_res)

        add_to_log('Adjusted distribution %s' % Counter(y_res))
        add_to_log('Under sampling time: ' + str(time.time() - s_time))

        return x_res, y_res

    def train_classifier(self, x_train, y_train):
        """Train and save a classifier.

        Parameters:
        samples: x_train, labels: y_train, classifier: RandomForest

        Returns:
        relative path to the classifier file inside models directory

       """
        add_to_log('Training Model..')
        s_time = time.time()

        self.clf.fit(x_train, y_train)

        add_to_log('Model Trained')
        add_to_log('Training Time: ' + str(time.time() - s_time))

        clf_path = self.save_classifier()

        return clf_path

    def update_classifier(self, x_train, y_train):
        """Update and save a classifier.

        Parameters:
        samples: x_train, labels: y_train, classifier: RandomForest

        Returns:
        relative path to the classifier file inside models directory

       """
        add_to_log('Training Model..')
        s_time = time.time()

        # Add a new decision tree per 300 samples
        new_estimators = len(y_train) // 300

        self.clf.n_estimators += new_estimators

        add_to_log('New estimators added: ' + str(new_estimators))

        self.clf.fit(x_train, y_train)

        add_to_log('Classifier Updated')
        add_to_log('Training Time: ' + str(time.time() - s_time))
        clf_path = self.save_classifier()

        return clf_path

    def get_predict_prob(self, text):
        """Return class conditional probability for a single sample
        Parameters: sample as text
        Returns: array of class probabilities
       """
        print('Vectorizing..')
        x_test = self.vector.fit_transform([text])
        y_preds = self.clf.predict_proba(x_test)
        print(y_preds[0])
        return y_preds[0]

    def score_accuracy(self, x_test, y_expec):
        """Scores accuracy of the model.
        Parameters: x_test, testing matrix, y_expec: expected labels
        """

        add_to_log('Scoring Model..')
        y_preds = self.clf.predict(x_test)

        acc = np.mean(y_preds == y_expec)
        add_to_log('accurary: ' + str(acc))

        self.print_confusion_matrix(y_expec, y_preds)

    def print_confusion_matrix(self, y_expec, y_preds):
        """Saves confusion matrix in png format.
        Parameters: Expected labels and Predicted labels.
        """

        clf_type = str(type(self.clf))
        clf_name = clf_type.split("'")[1].split('.')[-1]

        dir_path = os.path.join(os.getcwd(), 'cnf_mtrx')
        file_path = os.path.join(dir_path, self.time_stamp + clf_name)

        if not os.path.exists(dir_path):
            os.makedirs(dir_path)

        conf_mat = confusion_matrix(y_true=y_expec, y_pred=y_preds)

        conf_mat_pr = []
        for row in conf_mat:
            conf_mat_pr.append((row / sum(row)))

        add_to_log(conf_mat)
        acc = np.mean(y_preds == y_expec)

        # The order of labels is important
        labels = ['Hardware', 'Other', 'Script', 'Software', 'Tools']
        df_cm = DataFrame(conf_mat, index=labels, columns=labels)
        df_prec = DataFrame(conf_mat_pr, index=labels, columns=labels)

        sns_plot = sn.heatmap(df_cm, annot=True, cmap='Blues', fmt='g')
        sns_plot.set_title("Acc: " + str(acc))
        plt.savefig(file_path)
        plt.figure()

        sns_plot = sn.heatmap(df_prec, annot=True, cmap='Blues', fmt='.2%')
        sns_plot.set_title("Acc: " + str(acc))
        plt.savefig(file_path + '_pr')
        plt.figure()

    def save_vector(self):
        """Saves vector inside the vectors folder.

        Parameters:
        model.time_stamp and vector object example: TF-IDF Vectorizer, Hashing Vectorizer etc.

        Returns:
        relative path to the file inside vectors directory

       """
        dir_path = os.path.join(os.getcwd(), 'vectors')
        file_path = os.path.join(dir_path, self.time_stamp + '_vctr.joblib')

        if not os.path.exists(dir_path):
            os.makedirs(dir_path)

        joblib.dump(self.vector, file_path)

        # Print vector attributes
        add_to_log('Vector Saved ' + file_path)
        if hasattr(self.vector, 'n_features'):
            add_to_log(self.vector.n_features)
        else:
            add_to_log(len(self.vector.get_feature_names()))

        add_to_log(self.vector.token_pattern)
        add_to_log(self.vector.ngram_range)

        if self.vector.stop_words is not None:
            add_to_log('Total Stop Words: ' + str(len(self.vector.stop_words)))
        else:
            add_to_log('No Stop Words')

        return file_path

    def save_matrix(self, x_train):
        """Saves matrix inside the matrix folder.s

        Parameters:
        model.time_stamp and matrix object example: X_train

       """
        dir_path = os.path.join(os.getcwd(), 'matrices')
        file_path = os.path.join(dir_path, self.time_stamp + '_mtrx.joblib')

        if not os.path.exists(dir_path):
            os.makedirs(dir_path)

        joblib.dump(x_train, file_path)
        add_to_log('Matrix Saved ' + file_path)

    def save_classifier(self):

        """Saves classifier inside the models folder.s

        Parameters:
        classifier: classifier object

        Returns:
        relative path to the file inside models directory

       """

        dir_path = os.path.join(os.getcwd(), 'classifiers')
        file_path = os.path.join(dir_path, self.time_stamp + '_clfr.joblib')

        if not os.path.exists(dir_path):
            os.makedirs(dir_path)

        joblib.dump(self.clf, file_path)

        add_to_log('Classifier Saved ' + file_path)

        return file_path

    def save_model(self):
        """ Saves model in self under model folder """

        dir_path = os.path.join(os.getcwd(), 'models')
        file_path = os.path.join(dir_path, self.time_stamp + '_modl.joblib')

        if not os.path.exists(dir_path):
            os.makedirs(dir_path)

        self.samplers = None

        joblib.dump(self, file_path)
        add_to_log('Model Saved ' + file_path)

def load_joblib(file_path):

    """Loads the joblib file specified by file_path.

    Parameters:
    file_path (int): path to the file to load

    Returns:
    Object of the file, example: classifier, selector, vector

   """

    obj_file = joblib.load(file_path)
    add_to_log('File loaded ' + file_path)

    return obj_file

def add_to_log(line):

    """Appends the input to execution_log.txt file and prints as well.

        Parameters:
        line (string): String to be appended to log.
    """

    line = str(line)
    with open('execution_log.txt', 'a') as log:
        log.write(line)
        log.write('\n')
        if line == 'Done':
            log.write('-' * 50)
            log.write('\n')

    print(line)


from BinaryInsertionSort import BinaryInsertionSort
from BubbleSort import BubbleSort
from QuickSort import QuickSort
from typing import List
import easygui
import _io
import sys
import timeit

class FileUtils():

    def getNumerosFromFile(self) -> List[int]:
        numbers = []
        file_content = self._abrir_arquivo()
        for line in file_content:
            valor = int(self._remover_break_line(line))
            numbers.append(valor)
        return numbers

    def _remover_break_line(self, text: str) -> str:
        return text.replace("\n", "")

    def _abrir_arquivo(self) -> _io.TextIOWrapper:
        file_path = self._obter_caminho_do_arquivo_usando_easygui()
        file = open(f"{file_path}", "r")
        return file

    def _obter_caminho_do_arquivo_usando_easygui(self) -> str:
        return easygui.fileopenbox()

class TempoAlgoritmos:

    def obter_tempo_de_execucao_de_cada_algoritmo(self, lista) -> List[float]:
        """Uma lista de contendo o tempo de algoritmo é retornada.

            posicao[0] -> Bubble Sort
            posicao[1] -> Binary Insertion Sort
            posicao[2] -> Quick Sort

        """
        lista_binary = lista.copy()
        lista_quick = lista.copy()
        lista_bubble = lista.copy()

        return [
            self._tempo_do_bubble_sort_para_ordenar_a_lista(lista_bubble),
            self._tempo_do_binary_insertion_sort_para_ordernar_a_lista(lista_binary),
            self._tempo_do_quick_sort_para_ordernar_a_lista(lista_quick)
        ]

    def _tempo_do_binary_insertion_sort_para_ordernar_a_lista(self, lista) -> float:
        binary_insertion_sort = BinaryInsertionSort()
        start = timeit.default_timer()
        binary_insertion_sort.binary_insertion_sort(lista)
        end = timeit.default_timer()

        return end - start

    def _tempo_do_quick_sort_para_ordernar_a_lista(self, lista) -> float:
        quick_sort = QuickSort()
        start = timeit.default_timer()
        quick_sort.quick_sort(lista, 0, len(lista)-1)
        end = timeit.default_timer()

        return end - start

    def _tempo_do_bubble_sort_para_ordenar_a_lista(self, lista) -> float:
        bubble_sort = BubbleSort()
        start = timeit.default_timer()
        bubble_sort.bubble_sort(lista)
        end = timeit.default_timer()

        return end - start


# Author: Abel
# !/usr/bin/python3
# -*- coding: utf-8 -*-
# This program is optimized for python 3.6
# 从HTTP服务器下载数据

import argparse
import http.client  #(python3代替httplib)

REMOTE_SERVER_HOST = 'www.python.org'
REMOTE_SERVER_PATH = '/'

class HTTPClient:

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

    def fetch(self, path):
        h = http.client.HTTPConnection(self.host)

        # Prepare header
        h.putrequest("GET", path)
        h.putheader("User-Agent", __file__)
        h.putheader("Host", self.host)
        h.putheader("Accept", "*/*")
        h.endheaders()

        try:

            r = h.getresponse()
        except Exception as e:
            errcode, errmsg, headers = r
            print(
                "Client failed error code:%s message:%s headers:%s" % (errcode, errmsg, headers))
        else:
            print("Got homepage from %s" % self.host)
        return r.read()

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='HTTP Client Example')
    parser.add_argument(
        '--host', action='store', dest="host", default=REMOTE_SERVER_HOST)
    parser.add_argument(
        '--path', action="store", dest="path", default=REMOTE_SERVER_PATH)
    given_args = parser.parse_args()
    host, path =given_args.host, given_args.path
    client = HTTPClient(host)
    print(client.fetch(path).decode())


'''
Created on Jul 13, 2017

This file contains methods for plotting a single, classified set of data for this practice example
and for plotting two sets in the same window

@author: Chris Newby
'''

from matplotlib import pyplot as plt

def Plot_Data(dat_in, dat_class, title = 'Sample Data'):
    '''
    Function for plotting the data
    specific to the data I'm generating in Making_Data
    '''
    x_list = []
    y_list = []
    color_list = []

    for elem in dat_in:
        x_list.append(elem[0])
        y_list.append(elem[1])

    for elem in dat_class:
        if elem[0] == 1:
            color_list.append("r")
        else:
            color_list.append('b')

    plt.scatter(x = x_list, y = y_list, c=color_list)
    plt.xlabel('x')
    plt.xlim([-1,1])
    plt.ylabel('y')
    plt.ylim([-1,1])
    plt.title(title)
    plt.axes().set_aspect('equal')
    plt.show()

def Plot_two_data(dat_1,class_1,dat_2,class_2, name_1 = 'Sample Data',name_2 = 'Classified Data'):
    '''
    Function for plotting two sets of data together
    '''

    #setting up first data set
    x1_list = []
    y1_list = []
    color1_list = []

    for elem in dat_1:
        x1_list.append(elem[0])
        y1_list.append(elem[1])

    for elem in class_1:
        if elem[0] == 1:
            color1_list.append("r")
        else:
            color1_list.append('b')

    #setting up second data set
    x2_list = []
    y2_list = []
    color2_list = []

    for elem in dat_2:
        x2_list.append(elem[0])
        y2_list.append(elem[1])

    for elem in class_2:
        if elem[0] == 1:
            color2_list.append("r")
        else:
            color2_list.append('b')

    plt.figure(1)
    plt.subplot(121, aspect = 'equal')
    plt.scatter(x = x1_list, y = y1_list, c=color1_list)
    plt.xlim([-1,1])
    plt.ylim([-1,1])
    plt.title(name_1)

    plt.subplot(122, aspect = 'equal')
    plt.scatter(x = x2_list, y = y2_list, c=color2_list)
    plt.xlim([-1,1])
    plt.ylim([-1,1])
    plt.title(name_2)

    plt.show()


import logging
from utils import *
from forex.candle.candle import Candle
from config import CONFIG

# create logger
p_logger = logging.getLogger(__name__)
p_logger.setLevel(logging.INFO)

class Pivot(object):
    """
    Class that represents a single Pivot as identified
    by the Zigzag indicator

    Class variables
    ---------------
    type : int, Required
           Type of pivot. It can be 1 or -1
    candle : Dict
             Candle representing the pivot
    pre : Segment object
          Segment object before this pivot
    aft : Segment object
          Segment object after this pivot
    score : int
            Result of adding the number
            of candles of the 'pre' and 'aft' segment (if defined). Optional
    """

    def __init__(self, type, candle, pre, aft,
                 score=None):
        self.type = type
        self.candle = candle
        self.pre = pre
        self.aft = aft
        self.score = score

    def merge_pre(self, slist, n_candles, diff_th):
        """
        Function to merge 'pre' Segment. It will merge self.pre with previous segment
        if self.pre and previous segment are of the same type (1 or -1) or count of
        previous segment is less than CONFIG.getint('pivots', 'n_candles')

        Parameters
        ----------
        slist : SegmentList object
                SegmentList for PivotList of this Pivot.
                Required
        n_candles : int
                    Skip merge if Segment is greater than 'n_candles'
        diff_th : int
                  % of diff in pips threshold

        Returns
        -------
        Nothing
        """
        p_logger.debug("Running merge_pre")
        p_logger.debug("Analysis of pivot {0}".format(self.candle['time']))
        p_logger.debug("self.pre start pre-merge: {0}".format(self.pre.start()))

        extension_needed = True # if extension_needed is False then no further attempts of extending this self.pre
                                # will be tried
        while extension_needed is True:
            # reduce start of self.pre by one candle in order to retrieve the previous segment
            # by its end
            start_dt = self.pre.start() - periodToDelta(1, self.candle['granularity'])

            # fetch previous segment
            s = None
            if CONFIG.has_option('pivots', 'max_diff'):
                s = slist.fetch_by_end(start_dt, max_diff=0)
            else:
                s = slist.fetch_by_end(start_dt)

            if s is None:
                # This is not necessarily an error, it could be that there is not the required Segment in slist
                # because it is out of the time period
                p_logger.info("No Segment could be retrieved for pivot falling in time {0} "
                              "by using s.fetch_by_end and date: {1} in function 'merge_pre'".format(self.candle['time'],
                                                                                start_dt))
                extension_needed = False
                continue
            if self.pre.type == s.type:
                # merge if type of previous (s) is equal to self.pre
                p_logger.debug("Merge because of same Segment type")
                self.pre = self.pre.prepend(s)
            elif self.pre.type != s.type and s.count < n_candles:
                # merge if types of previous (s) and self.pre are different but
                # s.count is less than CONFIG.getint('pivots', 'n_candles')
                # calculate the % that s.diff is with respect to self.pre.diff
                perc_diff = s.diff*100/self.pre.diff
                # do not merge if perc_diff that s represents with respect
                # to s.pre is > than the defined threshold
                if perc_diff < diff_th:
                    p_logger.debug("Merge because of s.count < n_candles")
                    self.pre = self.pre.prepend(s)
                else:
                    p_logger.debug("Skipping merge because of %_diff")
                    extension_needed = False
            else:
                # exit the while loop, as type of previous (s) and self.pre are different
                # and s.count is greater than CONFIG.getint('pivots', 'n_candles')
                extension_needed = False

        p_logger.debug("self.pre start after-merge: {0}".format(self.pre.start()))
        p_logger.debug("Done merge_pre")

    def merge_aft(self, slist, n_candles, diff_th):
        """
        Function to merge 'aft' Segment. It will merge self.aft with next segment
        if self.aft and next segment are of the same type (1 or -1) or count of
        next segment is less than 'n_candles'

        Parameters
        ----------
        slist : SegmentList object
                SegmentList for PivotList of this Pivot.
                Required
        n_candles : int
                    Skip merge if Segment is greater than 'n_candles'
        diff_th : int
                  % of diff in pips threshold

        Returns
        -------
        Nothing
        """

        p_logger.debug("Running merge_aft")
        p_logger.debug("Analysis of pivot {0}".format(self.candle['time']))
        p_logger.debug("self.aft end before the merge: {0}".format(self.aft.end()))

        extension_needed = True
        while extension_needed is True:
            # increase end of self.aft by one candle
            start_dt = self.aft.end()+periodToDelta(1, self.candle['granularity'])

            # fetch next segment
            s = None
            if CONFIG.has_option('pivots', 'max_diff'):
                s = slist.fetch_by_start(start_dt, max_diff=0)
            else:
                s = slist.fetch_by_start(start_dt)
            if s is None:
                # This is not necessarily an error, it could be that there is not the required Segment in slist
                # because it is out of the time period
                p_logger.info("No Segment could be retrieved for pivot falling in time {0} by using s.fetch_by_"
                              "start and date: {1} in function 'merge_aft'. ".format(self.candle['time'], start_dt))
                extension_needed = False
                continue

            if self.aft.type == s.type:
                p_logger.debug("Merge because of same Segment type")
                # merge
                self.aft = self.aft.append(s)
            elif self.aft.type != s.type and s.count < n_candles:
                # calculate the % that s.diff is with respect to self.pre.diff
                perc_diff = s.diff * 100 / self.aft.diff
                # do not merge if perc_diff that s represents with respect
                # to s.aft is > than the defined threshold
                if perc_diff < diff_th:
                    p_logger.debug("Merge because of s.count < n_candles")
                    self.aft = self.aft.append(s)
                else:
                    p_logger.debug("Skipping merge because of %_diff")
                    extension_needed = False
            else:
                extension_needed = False

        p_logger.debug("self.aft end after-merge: {0}".format(self.aft.end()))
        p_logger.debug("Done merge_aft")

    def calc_score(self, type='diff'):
        """
        Function to calculate the score for this Pivot
        The score will be the result of adding the 'diff'
        values or adding the number of candles of the 'pre' and 'aft'
        segments (if defined)

        Parameters
        ----------
        type : Type of score that will be
               calculated. Possible values: 'diff' , 'candles'
               Default: 'diff'

        Returns
        -------
        int /float with the score of this pivot.
                   It will also set the score class attribute
        """

        if self.pre:
            score_pre = 0
            if type == 'diff':
                score_pre = self.pre.diff
            elif type == 'candles':
                score_pre = self.pre.count
        else:
            score_pre = 0

        if self.aft:
            score_aft = 0
            if type == 'diff':
                score_aft = self.aft.diff
            elif type == 'candles':
                score_aft = self.aft.count
        else:
            score_aft = 0

        self.score = score_pre+score_aft

        return score_pre+score_aft

    def adjust_pivottime(self, clistO):
        '''
        Function to adjust the pivot time
        This is necessary as sometimes the Zigzag algorithm
        does not find the correct pivot

        Parameters
        ----------
        clistO : CandleList object used to identify the
                PivotList, Required
        Returns
        -------
        New adjusted datetime
        '''
        clist = clistO.data['candles'][:-1] # reduce index by 1 so start candle+1 is not included
        new_pc = pre_colour = None
        it = True
        ix = -1
        while it is True:
            c_dict = clist[ix]
            c = Candle(dict_data=c_dict)
            c.set_candle_features()
            if c.colour == "undefined":
                it = False
                new_pc = c
                continue
            if pre_colour is None:
                pre_colour = c.colour
                ix -= 1
            elif c.colour == pre_colour:
                ix -= 1
                continue
            else:
                # change in candle colour
                new_pc = c
                it = False
        return new_pc.time

    def __repr__(self):
        return "Pivot"

    def __str__(self):
        out_str = ""
        for attr, value in self.__dict__.items():
            out_str += "%s:%s " % (attr, value)
        return out_str


from datetime import datetime
from typing import Union

import discord
from dateutil.relativedelta import relativedelta
from discord.ext import commands
from urllib import parse

key_perms = ["kick_members", "ban_members", "administrator", "manage_channels", "manage_server", "manage_messages",
             "mention_everyone", "manage_nicknames", "manage_roles", "manage_webhooks", "manage_emojis"]

voice_perms = ["connect", "deafen_members", "move_members", "mute_members", "priority_speaker", "speak", "stream",
               "use_voice_activation"]

statuses = {
    "idle":
        "<:IDLE:591344823622041600>",
    "dnd":
        "<:DND:591344889384534036>",
    "online":
        "<:ON:591344804307402793>",
    "streaming":
        "<:STRE:591345161766961178>",
    "offline":
        "<:OFF:591344910905376779>"
}

def get_relative_delta(time):
    delta = relativedelta(datetime.now(), time)
    tme = []
    msg = time.strftime("%A, %B %d %Y @ %I:%M%p %Z")
    if delta.years:
        years = delta.years
        tme.append(f"{years} years" if years != 1 else "1 year")
    if delta.months:
        months = delta.months
        tme.append(f"{months} months" if months != 1 else "1 month")
    if delta.days:
        days = delta.days
        tme.append(f"{days} days" if days != 1 else "1 day")
    if len(tme) == 0:
        return msg + "\nToday!"
    msg += "\n"
    msg += ", ".join(tme)
    msg += " ago"
    if len(tme) != 1:
        msg += f" ({(datetime.now() - time).days} days)"
    return msg

class User(commands.Cog):
    def __init__(self, bot):
        self.bot = bot

    @commands.guild_only()
    @commands.group(aliases=["whois"], invoke_without_command=True, description="Check a users information!")
    async def user(self, ctx, *, user: discord.Member = None):
        """
        {"permissions": {"user": [], "bot": ["embed_links"]}}
        """
        if not ctx.invoked_subcommand:
            author, server, message = ctx.author, ctx.guild, ctx.message
            if not user:
                user = author
            em = discord.Embed(color=user.color)
            game = f"{'📱' if user.is_on_mobile() else ''}{statuses[str(user.status)]}" \
                   f" {str(user.status).capitalize()}\n\n"
            if user.activity is None:
                pass
            elif user.activity.type == discord.ActivityType.playing:
                activity = user.activity.to_dict()
                game += f"Playing **{user.activity.name}**"
                if "details" in activity:
                    game += f"\n{activity['details']}"
                if "state" in activity:
                    game += f"\n{activity['state']}"
            elif user.activity.type == discord.ActivityType.watching:
                game += f"Watching {user.activity.name}"
            elif user.activity.type == discord.ActivityType.listening:
                game += f"Listening to {user.activity.title}\n" \
                        f"By {', '.join([x for x in author.activity.artists])}\n" \
                        f"On {user.activity.name}"
            else:
                game += f"Streaming **[{user.activity.name}]({user.activity.url})**"
            em.add_field(name="Status:", value=game, inline=False)

            if user.voice:
                other_people = len(user.voice.channel.members) - 1
                voice = f"In {user.voice.channel.mention}"
                voice += f" with {other_people} others" if other_people else " alone"
            else:
                voice = "Not connected"
            em.add_field(name='Voice:', value=voice, inline=False)

            if len(user.roles) <= 41:
                roles = " ".join([x.mention for x in user.roles if x.name != "@everyone"][::-1])
                roles = roles if roles else "None"
                em.add_field(name=f"Roles [{len(user.roles) - 1}]:", value=roles, inline=False)
            else:
                em.add_field(name=f"Roles [{len(user.roles) - 1}]:", value="Too many to display", inline=False)

            perms = [x[0] for x in iter(ctx.channel.permissions_for(user)) if x[1]]
            permissions = ", ".join([str(x).replace("_", " ").title() for x in perms if x in key_perms])
            permissions = permissions if permissions else "None"
            em.add_field(name="Key Permissions:", value=permissions)

            member_number = sorted(server.members, key=lambda m: m.joined_at).index(user) + 1
            em.set_footer(text=f"Member #{member_number} • User ID: {user.id}")

            name = "BOT: " if user.bot else ""
            name += " ~ ".join((str(user), user.nick)) if user.nick else str(user)

            if user.avatar_url:
                em.set_thumbnail(url=user.avatar_url)
            em.set_author(name=name)

            em.add_field(name="Joined Discord on:", value=get_relative_delta(user.created_at), inline=False)
            em.add_field(name="Joined this server on:", value=get_relative_delta(user.joined_at), inline=False)

            return await ctx.send(embed=em)

    @user.command(name="permissions", aliases=["perms"],
                  description="Check a users permissions for a given Text/Voice channel")
    async def user_permissions(self, ctx, user: discord.Member = None, *,
                               channel: Union[discord.TextChannel, discord.VoiceChannel] = None):
        """
        {"permissions": {"user": [], "bot": ["embed_links"]}}
        """
        if not user:
            user = ctx.author
        if not channel:
            channel = ctx.channel
        perms = channel.permissions_for(user)
        perms_we_have = ""
        perms_we_dont = ""
        if isinstance(channel, discord.TextChannel):
            for perm in perms:
                if perm[0] not in voice_perms:
                    perm_name = perm[0].replace('_', ' ').title()
                    if perm[1]:
                        perms_we_have += f"+\t{perm_name}\n"
                    else:
                        perms_we_dont += f"-\t{perm_name}\n"
        elif isinstance(channel, discord.VoiceChannel):
            for perm in perms:
                if perm[0] in voice_perms:
                    perm_name = perm[0].replace('_', ' ').title()
                    if perm[1]:
                        perms_we_have += f"+\t{perm_name}\n"
                    else:
                        perms_we_dont += f"-\t{perm_name}\n"
        desc = f"```diff\n{perms_we_have}{perms_we_dont}\n```"
        em = discord.Embed(color=user.color, description=desc)
        em.set_author(name=f"{user.name}'s permissions in {channel}:")
        await ctx.send(embed=em)

    @user.command(name="avatar", aliases=["avi"], description="Get a users avatar")
    async def user_avatar(self, ctx, user: discord.Member = None):
        """
        {"permissions": {"user": [], "bot": ["embed_links"]}}
        """
        if not user:
            user = ctx.author
        url = user.avatar_url_as(static_format="png", size=1024)
        em = discord.Embed(color=user.color)
        em.description = f"[Open image]({url})"
        em.set_image(url=url)
        em.set_author(name=f"{user.name}'s avatar")
        await ctx.send(embed=em)

    @commands.command()
    async def ud(self, ctx, *, msg):
        """Urban Dictionary search"""
        number = 1
        if " | " in msg:
            msg, number = msg.rsplit(" | ", 1)
        search = parse.quote(msg)
        async with self.bot.session.get("http://api.urbandictionary.com/v0/define", params={"term": search}) as resp:
            result = await resp.json()
        if not result["list"]:
            return await ctx.send(f"{msg} couldn't be found on Urban Dictionary.")
        else:
            top_result = result["list"][int(number) - 1]
            em = discord.Embed(description=top_result["definition"],
                               url=top_result["permalink"], color=self.bot.color)
            if len(result["list"]) > 1:
                if top_result["example"]:
                    em.add_field(name="Example:", value=top_result["example"])
                em.set_author(name=top_result["word"],
                              icon_url="https://lh5.ggpht.com/oJ67p2f1o35dzQQ9fVMdGRtA7jKQdxUFSQ7vYstyqTp-Xh-H5BAN4T5"
                                       "_abmev3kz55GH=w300")
                number = str(int(number) + 1)
                em.set_footer(text=f"Results: {len(result['list'])}. Use !ud {msg} | {number} to see a different result!")
            else:
                if top_result["example"]:
                    em.add_field(name="Example:", value=top_result["example"])
                em.set_author(name=top_result["word"],
                              icon_url="https://lh5.ggpht.com/oJ67p2f1o35dzQQ9fVMdGRtA7jKQdxUFSQ7vYstyqTp-Xh-H5BAN4T5"
                                       "_abmev3kz55GH=w300")
                em.set_footer(text=f"Results: {len(result['list'])}.")
            await ctx.send(embed=em)

def setup(bot):
    bot.add_cog(User(bot))


import time
import six
import os

import dash_html_components as html
import dash_core_components as dcc
from dash.dependencies import Input, State, Event, Output

from server import app, server
import introduction
import html_components
import core_components
import basic_callbacks
import html_component_appendix
import callbacks_with_dependencies
import dynamic_content
import external_css_and_js
import open_problems
import architecture
import live_updates
import changelog
import plugins
import gallery
import performance
import support
import deployment
import authentication
import installation
import getting_started_part_1
import getting_started_part_2
import urls
import auth
import on_premise_deployment

dcc._js_dist[0]['external_url'] = 'https://cdn.plot.ly/plotly-basic-1.27.1.min.js'

def create_contents(contents):
    h = []
    for i in contents:
        if isinstance(i, list):
            h.append(create_contents(i))
        else:
            h.append(html.Li(i))
    return html.Ul(h)

toc = html.Div(
create_contents([

    dcc.Link(html.A('Introduction'), href="/dash/introduction"),

    html.A('Announcement Letter',
           href="https://medium.com/@plotlygraphs/introducing-dash-5ecf7191b503"),

    dcc.Link(html.A('Gallery'), href="/dash/gallery"),

    dcc.Link(html.A('Installation'), href="/dash/installation"),

    dcc.Link(html.A('Create Your First App - Part 1'), href="/dash/getting-started"),

    dcc.Link(html.A('Create Your First App - Part 2'), href="/dash/getting-started-part-2"),

    dcc.Link(html.A('Performance'), href="/dash/performance"),

    dcc.Link(html.A('Live Updates'), href="/dash/live-updates"),

    dcc.Link(html.A('External CSS and JS'), href="/dash/external-resources"),

    dcc.Link(html.A('Dash Core Components'), href="/dash/dash-core-components"),

    dcc.Link(html.A('Dash HTML Components'), href="/dash/dash-html-components"),

    dcc.Link(html.A('Build Your Own Components'), href="/dash/plugins"),

    dcc.Link(html.A('URL Support'), href="/dash/urls"),

    dcc.Link(html.A('Authentication'), href="/dash/authentication"),

    dcc.Link(html.A('Deployment'), href="/dash/deployment"),

    html.A('FAQ', href="https://community.plot.ly/c/dash"),

    dcc.Link(html.A('Support and Contact'), href="/dash/support")

]), className="toc-chapters"
)

chapters = {
    'index': {
        'url': '/dash/',
        'content': html.Div([
            html.H1('Dash User Guide'),
            toc
        ], className="toc")
    },

    'introduction': {
        'url': '/dash/introduction',
        'content': introduction.layout
    },

    'installation': {
        'url': '/dash/installation',
        'content': installation.layout
    },

    'getting-started': {
        'url': '/dash/getting-started',
        'content': getting_started_part_1.layout
    },

    'getting-started-part-2': {
        'url': '/dash/getting-started-part-2',
        'content': getting_started_part_2.layout
    },

    'dash-core-components': {
        'url': '/dash/dash-core-components',
        'content': core_components.layout
    },

    'dash-html-components': {
        'url': '/dash/dash-html-components',
        'content': [
            html_components.layout,
            # html_component_appendix.layout
        ]
    },

    'external': {
        'url': '/dash/external-resources',
        'content': external_css_and_js.layout
    },

    'plugins': {
        'url': '/dash/plugins',
        'content': plugins.layout
    },

    'gallery': {
        'url': '/dash/gallery',
        'content': gallery.layout
    },

    'live-updates': {
        'url': '/dash/live-updates',
        'content': live_updates.layout
    },

    'performance': {
        'url': '/dash/performance',
        'content': performance.layout
    },

    'urls': {
        'url': '/dash/urls',
        'content': urls.layout
    },

    'deployment': {
        'url': '/dash/deployment',
        'content': deployment.layout
    },

    'deployment-onpremise': {
        'url': '/dash/deployment/on-premise',
        'content': on_premise_deployment.layout
    },

    'auth': {
        'url': '/dash/authentication',
        'content': auth.layout
    },

    'support': {
        'url': '/dash/support',
        'content': support.layout
    }
}

header = html.Div(
    className='header',
    children=html.Div(
        className='container-width',
        style={'height': '100%'},
        children=[
            html.A(html.Img(
                src="https://cdn.rawgit.com/plotly/dash-docs/b1178b4e/images/dash-logo-stripe.svg",
                className="logo"
            ), href='https://plot.ly/products/dash', className="logo-link"),

            html.Div(className="links", children=[
                html.A('pricing', className="link", href="https://plot.ly/products/on-premise"),
                html.A('user guide', className="link active", href="https://plot.ly/dash/"),
                html.A('plotly', className="link", href="https://plot.ly/")
            ])
        ]
    )
)

app.title = 'Dash User Guide and Documentation - Dash by Plotly'

app.layout = html.Div([
    html.Meta(name='viewport', content='width=device-width, initial-scale=1.0'),
    html.Meta(
        name='description',
        content=('Dash User Guide and Documentation. '
                 'Dash is a Python framework for building '
                 'reactive web apps developed by Plotly.')
    ),
    header,
    html.Div([
        html.Div([
            html.Div(
                html.Div(id="chapter", className="content"),
                className="content-container"
            ),
        ], className="container-width")
    ], className="background"),
    dcc.Location(id='location', refresh=False)
])

@app.callback(Output('chapter', 'children'),
    [Input('location', 'pathname')])
def display_content(pathname):
    if pathname is None:
        return chapters['index']['content']
    matched = [c for c in chapters.keys()
               if chapters[c]['url'] == pathname]

    if matched and matched[0] != 'index':
        content = html.Div([
            html.Div(chapters[matched[0]]['content']),
            html.Hr(),
            dcc.Link(html.A('Back to the Table of Contents'), href='/dash/')
        ])
    else:
        content = chapters['index']['content']

    return content

app.css.append_css({
    'external_url': (
        'https://cdn.rawgit.com/plotly/dash-app-stylesheets/8485c028c19c393e9ab85e1a4fafd78c489609c2/dash-docs-base.css',
        'https://cdn.rawgit.com/plotly/dash-app-stylesheets/30b641e2e89753b13e6557b9d65649f13ea7c64c/dash-docs-custom.css',
        'https://fonts.googleapis.com/css?family=Dosis'
    )
})

if 'DYNO' in os.environ:
    app.scripts.config.serve_locally = True
    app.scripts.append_script({
        'external_url': 'https://cdn.rawgit.com/chriddyp/ca0d8f02a1659981a0ea7f013a378bbd/raw/e79f3f789517deec58f41251f7dbb6bee72c44ab/plotly_ga.js'
    })
else:
    app.scripts.config.serve_locally = True

if __name__ == '__main__':
    app.run_server(debug=True, threaded=True, port=8050)


#
# UserAttributes
#
# Authors: Stijn Wopereis (Wopster)
# Description: Adds to the option to add and modify I3D user attributes.
#
# Copyright (c) Stijn Wopereis, 2018

import maya.cmds as cmds
import maya.OpenMaya as OpenMaya

import random
import string

from functools import partial

from I3DExporter import TEXT_WIDTH, DEFAULT_FIELD_WIDTH, I3DUpdateLayers, I3DSaveAttributeBool, I3DSaveAttributeString, I3DSaveAttributeFloat, I3DSaveAttributeInt, \
    I3DAttributeExists

# UserAttributes
UI_OPTIONS_PREDEFINED_USERATTRIBUTETYPES = 'wopster_optionsUserAttributeTypes'
UI_OPTIONS_PREDEFINED_USERATTRIBUTE_NAME = 'wopster_optionsUserAttributeName'
UI_OPTIONS_PREDEFINED_USERATTRIBUTE_VALUE = 'wopster_optionsUserAttributeValue'

UI_CONTROL_USERATTRIBUTES_STRING_NODE_NAME = 'wopster_attributeObjectName'
UI_CONTROL_USERATTRIBUTES_STRING_NODE_INDEX = 'wopster_attributeObjectIndex'

UI_CONTROL_LAYOUT_USERATTRIBUTES = 'wopster_layoutUserAtrributes'
UI_CONTROL_LAYOUT_USERATTRIBUTES_ROWS = 'wopster_attributesRows'
UI_CONTROL_LAYOUT_USERATTRIBUTES_ADD_ATTRIBUTE = 'wopster_layoutUserAtrributesAddNew'
UI_CONTROL_BUTTON_USERATTRIBUTES_ADD_ATTRIBUTE = 'wopster_buttonUserAtrributesAddNew'

TYPE_BOOL = 1
TYPE_INT = 2
TYPE_FLOAT = 3
TYPE_STRING = 4
TYPE_SCRIPTCALLBACK = 5

UI_MENU_USERATTRIBUTES = {
    'bool': TYPE_BOOL,
    'integer': TYPE_INT,
    'long': TYPE_INT,
    'string': TYPE_STRING,
    'float': TYPE_FLOAT,
    'double': TYPE_FLOAT,
    'scriptCallback': TYPE_SCRIPTCALLBACK,
}

class UserAttributes:

    def __init__(self):
        self.userAttributes_type_settings = []

    def delete(self):
        self.userAttributes_type_settings = []
        # pass

    def showWarning(self, text):
        OpenMaya.MGlobal.displayWarning(text)

    def initUI(self, parent):
        tab = cmds.formLayout('TabUserAttributes', parent=parent)
        cmds.columnLayout(adjustableColumn=True)

        # Frame for the current selection
        selection_frame = cmds.frameLayout('ua_selectionFrame', label='Current Selection', parent=tab, w=390, cll=False, mh=2, mw=2)
        current_node_layout = cmds.columnLayout(adjustableColumn=True, parent=selection_frame)

        self.addTextFieldElement(current_node_layout, 'Node Name', UI_CONTROL_USERATTRIBUTES_STRING_NODE_NAME, '', '', editable=False, width=245)
        self.addTextFieldElement(current_node_layout, 'Node Index', UI_CONTROL_USERATTRIBUTES_STRING_NODE_INDEX, '', '', editable=False, width=245)

        attributes_main_frame = cmds.frameLayout(parent=tab, label='Attributes', w=390, cll=False, mh=2, mw=2)
        attributes_scroll_layout = cmds.scrollLayout('scrollAttributes', parent=attributes_main_frame, cr=True, verticalScrollBarAlwaysVisible=False)

        # Add user attribute
        new_attributes_layout = cmds.frameLayout(UI_CONTROL_LAYOUT_USERATTRIBUTES_ADD_ATTRIBUTE, parent=attributes_scroll_layout, label='Add new attribute', w=390, cll=False, mh=2, mw=2)

        # Type of new attribute
        attributes_type_row_layout = cmds.rowLayout(adjustableColumn=2, numberOfColumns=2, parent=new_attributes_layout)
        cmds.text(parent=attributes_type_row_layout, label='Type', width=TEXT_WIDTH, align='left', annotation='')

        type_option_menu = cmds.optionMenu(UI_OPTIONS_PREDEFINED_USERATTRIBUTETYPES, parent=attributes_type_row_layout, annotation='Type',
                                           changeCommand=self.onChangeUserAttributeType)

        for k, _ in UI_MENU_USERATTRIBUTES.iteritems():
            cmds.menuItem(parent=type_option_menu, label=k)

        self.onChangeUserAttributeType(UI_MENU_USERATTRIBUTES['bool'])

        attributes_frame = cmds.frameLayout(UI_CONTROL_LAYOUT_USERATTRIBUTES, label='Current attributes', parent=attributes_scroll_layout, w=390, cll=True, mh=2, mw=2)
        attributes_layout = cmds.columnLayout(adjustableColumn=True, parent=attributes_frame)

        attributes_row_layout = cmds.rowLayout(UI_CONTROL_LAYOUT_USERATTRIBUTES_ROWS, parent=attributes_layout, columnWidth4=(TEXT_WIDTH, TEXT_WIDTH * 2, TEXT_WIDTH, 10),
                                               adjustableColumn=4, numberOfColumns=4, )
        cmds.text(parent=attributes_row_layout, label='Name', width=TEXT_WIDTH, align='left', annotation='')
        cmds.text(parent=attributes_row_layout, label='Value', width=TEXT_WIDTH * 2, align='left', annotation='')
        cmds.text(parent=attributes_row_layout, label='Type', width=TEXT_WIDTH, align='right', annotation='')

        attribute_button_items = cmds.formLayout('AttributeButtons', parent=tab)

        button_load = cmds.button(parent=attribute_button_items, label='Load', height=30, width=150, align='right', command=self.loadObjectUserAttribute)
        button_save = cmds.button(parent=attribute_button_items, label='Save', height=30, width=150, align='left', command=self.updateObjectUserAttribute)
        cmds.formLayout(attribute_button_items, edit=True, attachPosition=((button_load, 'left', 0, 0), (button_load, 'right', 5, 50),
                                                                           (button_save, 'left', 0, 50), (button_save, 'right', 5, 100)))
        cmds.formLayout(tab, edit=True, attachForm=(
            (selection_frame, 'top', 2), (selection_frame, 'left', 2), (selection_frame, 'right', 2),
            (attributes_main_frame, 'top', 74), (attributes_main_frame, 'left', 2), (attributes_main_frame, 'right', 2), (attributes_main_frame, 'bottom', 32),
            (attribute_button_items, 'bottom', 2), (attribute_button_items, 'left', 2), (attribute_button_items, 'right', 2)
        ))

        return tab

    def updateCurrentSelectionNode(self, index, node):
        cmds.textField(UI_CONTROL_USERATTRIBUTES_STRING_NODE_INDEX, edit=True, text=index)
        cmds.textField(UI_CONTROL_USERATTRIBUTES_STRING_NODE_NAME, edit=True, text=node)

    def loadObjectUserAttribute(self, unused):
        object_name = str(cmds.textField(UI_CONTROL_USERATTRIBUTES_STRING_NODE_NAME, q=True, text=True))

        if not len(object_name) > 0:
            self.showWarning('Nothing selected')
            return

        if not self.userAttributes_type_settings is None:
            for v in self.userAttributes_type_settings:
                cmds.deleteUI('userAttribute' + v['key'])

        self.userAttributes_type_settings = []

        if not object_name is None:
            attributes = cmds.listAttr(object_name, userDefined=True)

            if attributes is None:
                self.showWarning('No user attributes found!')
                return

            for name in attributes:
                key = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(5))
                object_key = object_name + "." + name
                type_name = cmds.getAttr(object_key, type=True)
                attribute_type = UI_MENU_USERATTRIBUTES[type_name]

                self.userAttributes_type_settings.append({'type': attribute_type, 'typeName': type_name, 'name': name, 'value': cmds.getAttr(object_key), 'key': key})

            self.updateUserAttributeUI()
        else:
            self.showWarning('Nothing selected')

    def updateObjectUserAttribute(self, unused):
        for v in self.userAttributes_type_settings:
            if v['type'] == TYPE_BOOL:
                updated_value = cmds.checkBox('userAttributeValue' + v['key'], q=True, v=True)
            elif v['type'] == TYPE_INT:
                updated_value = cmds.intField('userAttributeValue' + v['key'], q=True, v=True)
            elif v['type'] == TYPE_FLOAT:
                updated_value = cmds.floatField('userAttributeValue' + v['key'], q=True, v=True)
            else:
                updated_value = cmds.textField('userAttributeValue' + v['key'], q=True, text=True)

            v['value'] = updated_value

        self.saveObjectUserAttribute()

    def updateUserAttributeUI(self):
        attributes_layout = cmds.frameLayout(UI_CONTROL_LAYOUT_USERATTRIBUTES, edit=True)
        for v in self.userAttributes_type_settings:
            layout = cmds.rowLayout('userAttribute' + v['key'], columnWidth4=(TEXT_WIDTH, TEXT_WIDTH * 2, TEXT_WIDTH, 10), adjustableColumn=4, numberOfColumns=4,
                                    parent=attributes_layout)

            cmds.text(label=v['name'], width=TEXT_WIDTH, align='left', annotation='', parent=layout)

            # Switch display type
            if v['type'] == TYPE_BOOL:
                cmds.checkBox('userAttributeValue' + v['key'], label=v['name'], v=v['value'], width=TEXT_WIDTH * 2, parent=layout, annotation='', editable=True)
            elif v['type'] == TYPE_INT:
                cmds.intField('userAttributeValue' + v['key'], v=v['value'], editable=True, width=TEXT_WIDTH * 2, parent=layout)
            elif v['type'] == TYPE_FLOAT:
                cmds.floatField('userAttributeValue' + v['key'], v=v['value'], editable=True, width=TEXT_WIDTH * 2, parent=layout)
            else:
                cmds.textField('userAttributeValue' + v['key'], text=v['value'], width=TEXT_WIDTH * 2, editable=True, parent=layout)

            cmds.text(label=v['typeName'], width=200, annotation='', parent=layout)
            cmds.button('userAttributeDeleteButton', parent=layout, label='X', width=10, align='right', command=partial(self.deleteObjectUserAttribute, v['name']))

    def saveObjectUserAttributes(self, unused):
        object_name = cmds.textField(UI_CONTROL_USERATTRIBUTES_STRING_NODE_NAME, q=True, text=True)

        if not len(object_name) > 0:
            self.showWarning('Nothing selected')
            return

        name = cmds.textField(UI_OPTIONS_PREDEFINED_USERATTRIBUTE_NAME, q=True, text=True)
        type_name = cmds.optionMenu(UI_OPTIONS_PREDEFINED_USERATTRIBUTETYPES, q=True, value=True)

        if type_name == "bool":
            value = cmds.checkBox(UI_OPTIONS_PREDEFINED_USERATTRIBUTE_VALUE, q=True, v=True)
        elif type_name == "integer" or type_name == "long":
            value = cmds.intField(UI_OPTIONS_PREDEFINED_USERATTRIBUTE_VALUE, q=True, v=True)
        elif type_name == "float":
            value = cmds.floatField(UI_OPTIONS_PREDEFINED_USERATTRIBUTE_VALUE, q=True, v=True)
        else:
            value = cmds.textField(UI_OPTIONS_PREDEFINED_USERATTRIBUTE_VALUE, q=True, text=True)

        if not type_name is None and len(name) > 0:
            if not self.userAttributes_type_settings is None:
                for v in self.userAttributes_type_settings:
                    cmds.deleteUI('userAttribute' + v['key'])

            attribute_type = UI_MENU_USERATTRIBUTES[type_name]
            key = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(5))

            self.userAttributes_type_settings.append(
                {'type': attribute_type, 'typeName': type_name, 'name': name, 'value': value, 'key': key})

            self.saveObjectUserAttribute()
            self.updateUserAttributeUI()
            I3DUpdateLayers(str(object_name))
        else:
            self.showWarning('Not all fields are valid!')

    def saveObjectUserAttribute(self):
        object_name = str(cmds.textField(UI_CONTROL_USERATTRIBUTES_STRING_NODE_NAME, q=True, text=True))

        if not len(object_name) > 0:
            self.showWarning('Nothing selected')
            return

        for v in self.userAttributes_type_settings:
            if v['type'] == TYPE_BOOL:
                I3DSaveAttributeBool(object_name, v['name'], v['value'])
            elif v['type'] == TYPE_INT:
                I3DSaveAttributeInt(object_name, v['name'], v['value'])
            elif v['type'] == TYPE_FLOAT:
                I3DSaveAttributeFloat(object_name, v['name'], v['value'])
            elif v['type'] == TYPE_STRING or v['type'] == TYPE_SCRIPTCALLBACK:
                I3DSaveAttributeString(object_name, v['name'], v['value'])

    def onChangeUserAttributeType(self, selected):
        if not selected is None:
            # Delete current UI and redraw
            if cmds.rowLayout(UI_OPTIONS_PREDEFINED_USERATTRIBUTE_NAME + "layout", exists=True):
                cmds.deleteUI(UI_OPTIONS_PREDEFINED_USERATTRIBUTE_NAME + "layout")

            if cmds.rowLayout(UI_OPTIONS_PREDEFINED_USERATTRIBUTE_VALUE + "layout", exists=True):
                cmds.deleteUI(UI_OPTIONS_PREDEFINED_USERATTRIBUTE_VALUE + "layout")

            if cmds.button(UI_CONTROL_BUTTON_USERATTRIBUTES_ADD_ATTRIBUTE, exists=True):
                cmds.deleteUI(UI_CONTROL_BUTTON_USERATTRIBUTES_ADD_ATTRIBUTE)

            attribute_layout = cmds.frameLayout(UI_CONTROL_LAYOUT_USERATTRIBUTES_ADD_ATTRIBUTE, label='Add new attribute', w=390, edit=True, cll=True, mh=2, mw=2)

            self.addTextFieldElement(attribute_layout, 'Name', UI_OPTIONS_PREDEFINED_USERATTRIBUTE_NAME, '', '', editable=True, width=245)

            layout_value = cmds.rowLayout(UI_OPTIONS_PREDEFINED_USERATTRIBUTE_VALUE + "layout", adjustableColumn=2, numberOfColumns=2, parent=attribute_layout)
            cmds.text(UI_OPTIONS_PREDEFINED_USERATTRIBUTE_VALUE + "label", label='Value', width=TEXT_WIDTH, align='left', annotation='', parent=layout_value)

            if selected == "bool":
                cmds.checkBox(UI_OPTIONS_PREDEFINED_USERATTRIBUTE_VALUE, label="", width=245, parent=layout_value, annotation='', editable=True)
            elif selected == "integer" or selected == "long":
                cmds.intField(UI_OPTIONS_PREDEFINED_USERATTRIBUTE_VALUE, editable=True, value=0, width=245, parent=layout_value)
            elif selected == "float":
                cmds.floatField(UI_OPTIONS_PREDEFINED_USERATTRIBUTE_VALUE, editable=True, value=0, width=245, parent=layout_value)
            else:
                cmds.textField(UI_OPTIONS_PREDEFINED_USERATTRIBUTE_VALUE, width=245, editable=True, parent=layout_value)

            cmds.button(UI_CONTROL_BUTTON_USERATTRIBUTES_ADD_ATTRIBUTE, parent=attribute_layout, label='Add', width=126, align='right', command=self.saveObjectUserAttributes)

    def deleteObjectUserAttribute(self, name, unused):
        object_name = str(cmds.textField(UI_CONTROL_USERATTRIBUTES_STRING_NODE_NAME, q=True, text=True))
        object_key = object_name + "." + name

        if I3DAttributeExists(object_name, name):
            cmds.deleteAttr(object_key)

        self.loadObjectUserAttribute(None)

    def addTextFieldElement(self, parent, label, textFieldName, defaultValue='', annotation='', editable=True,
                            width=DEFAULT_FIELD_WIDTH):
        layout = cmds.rowLayout(textFieldName + 'layout', parent=parent, adjustableColumn=2, numberOfColumns=2)
        cmds.text(parent=layout, label=label, width=TEXT_WIDTH, align='left', annotation=annotation)
        cmds.textField(textFieldName, parent=layout, text=defaultValue, annotation=annotation, editable=editable,
                       width=width)

try:
    if not main is None:
        main.delete()
except NameError as e:
    pass

main = UserAttributes()


# coding: utf-8

# In[1]:

from sklearn.externals import joblib
import numpy
from collections import Counter
from sklearn.metrics import confusion_matrix

# In[6]:

X_test_st = numpy.load('../data/X_test_st.npy')
X_test_we = numpy.load('../data/X_test_we.npy')
y_test_pos = numpy.load('../data/y_test_pos.npy')
y_test_dep = numpy.load('../data/y_test_dep.npy')
X_test_words = numpy.load('../data/X_test_words.npy')

# In[3]:

dep_baseline = joblib.load('../models/dep_logisticregression_b.estimator')
dep_classifier = joblib.load('../models/dep_logisticregression.estimator')
pos_baseline = joblib.load('../models/pos_logisticregression_b.estimator')
pos_classifier = joblib.load('../models/pos_linearsvc.estimator')

# In[4]:

y_pred_pos = pos_classifier.predict(X_test_st)
y_pred_pos_baseline = pos_baseline.predict(X_test_we)

# In[16]:

for i, y in enumerate(y_test_pos):
    if y == "VERB" and y_pred_pos[i] == y and y_pred_pos_baseline[i] != y:
        print(X_test_words[i], " ".join(X_test_words[i-10:i+10]))

# In[14]:

for i, y in enumerate(y_test_pos):
    if y == "PART" and y_pred_pos[i] == y and y_pred_pos_baseline[i] != y:
        print(X_test_words[i], y_pred_pos[i], y_pred_pos_baseline[i], " ".join(X_test_words[i-10:i+10]))

# In[18]:

for i, y in enumerate(y_test_pos):
    if y == "NOUN" and y_pred_pos[i] == y and y_pred_pos_baseline[i] == "VERB":
        print(X_test_words[i],
              y_pred_pos[i],
              y_pred_pos_baseline[i],
              " ".join(X_test_words[i-10:i+10]))


#!/usr/local/bin/python

#coding :utf-8
#
# The MIT License (MIT)
#
# Copyright (c) 2016-2018 yutiansut/QUANTAXIS
#
# 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.

"""对应于save x
"""
from QUANTTOOLS.QAStockETL import (QA_SU_save_index_technical_index_day,
                                   QA_SU_save_index_technical_week_day,
                                   QA_SU_save_index_info)
from QUANTAXIS.QASU.main import (QA_SU_save_index_day,QA_SU_save_index_list)
from QUANTTOOLS.QAStockETL.Check import (check_index_day)
from QUANTTOOLS.QAStockETL.Check import (check_index_techindex, check_index_techweek)
from QUANTTOOLS.QAStockETL import (QA_etl_index_technical_day,
                                   QA_etl_index_technical_week)
from QUANTAXIS.QAUtil import QA_util_today_str,QA_util_if_trade
from QUANTTOOLS.QAStockETL.QAUtil.QADate_trade import QA_util_get_real_date
from datetime import datetime

if __name__ == '__main__':
    mark_day = QA_util_today_str()

    if QA_util_if_trade(mark_day):

        QA_SU_save_index_list('tdx')
        QA_SU_save_index_info()

        res = check_index_day(mark_day)
        while res is None or (len(res[0]) + len(res[1])) > 100:
            QA_SU_save_index_day('tdx')
            res = check_index_day(mark_day)

        res = check_index_techindex(mark_day)
        while res is None or (len(res[0]) + len(res[1])) > 100:
            QA_SU_save_index_technical_index_day(start_date = mark_day, end_date = mark_day)
            res = check_index_techindex(mark_day)

        QA_etl_index_technical_day(mark_day, mark_day)

    if datetime.strptime(mark_day,'%Y-%m-%d').weekday() + 1 == 5:
        if QA_util_if_trade(mark_day):
            mark_day = mark_day
        else:
            mark_day = QA_util_get_real_date(mark_day)
        QA_SU_save_index_technical_week_day(start_date = mark_day, end_date = mark_day)

        QA_etl_index_technical_week(mark_day,  mark_day)


# 페어 트레이딩 대상 종목들의 실제 데이터로 학습한다.
# 가상 주가로 초기 학습된 신경망을 실제 데이터를 사용하여
# 추가로 학습 시킨다.
# -----------------------------------------------------------------
from keras.models import Sequential
from keras.layers import Dense, LSTM
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

# plot에서 한글 처리를 위해 아래 폰트를 사용한다
from matplotlib import font_manager, rc
font_name = font_manager.FontProperties(fname="c:/Windows/Fonts/malgun.ttf").get_name()
rc('font', family=font_name)

pair = pd.read_csv("P.Pair종목(200).csv", engine='python')

def npiSpread(codeA, codeB):
    # 해당 종목의 주가 데이터를 가져온다
    p1 = pd.read_pickle('StockData/' + codeA)
    p2 = pd.read_pickle('StockData/' + codeB)

    # 해당 종목의 NPI 주가, NPI 스프레드를 계산한다
    s = pd.DataFrame(columns=['npiA', 'npiB', 'spread'])
    s['npiA'] = (p1['Close'] - p1['Close'].mean()) / p1['Close'].std()
    s['npiB'] = (p2['Close'] - p2['Close'].mean()) / p2['Close'].std()
    s['spread'] = s['npiA'] - s['npiB']

    return s

# LSTM 모델을 빌드한다
def buildModel(nInput):
    model = Sequential()
    model.add(LSTM(10, input_shape=(1,nInput)))
    model.add(Dense(1))
    model.compile(loss='mse', optimizer='adam')
    return model

def simLearning(data):
    for x in data.itertuples():
        nPrior = 10     # 과거 10-기간 데이터로 미래 예측

        # LSTM 모델을 빌드한다
        model = buildModel(nPrior)

        # LSTM weight의 초깃값을 결정한다. 저장된 weight가 있으면 이를 적용한다
        weightFile = x.codeA[0:6] + '-' + x.codeB[0:6] + '.h5'
        try:
            model.load_weights("data/" + weightFile)
            print("기존 학습 결과 Weight를 적용하였습니다.")
        except:
            print("model Weight을 Random 초기화 하였습니다.")

        # 실제 주가의 NPI 스프레드를 생성하고 마지막 nPrior개 데이터를
        # 신경망에 입력하여 nFuture 기간의 스프레드를 예측한다
        nFuture = 10
        df = npiSpread(x.codeA, x.codeB)
        df = df.dropna()
        df = df['spread'].values

        dx = np.copy(df)
        estimate = [dx[-1]]
        for i in range(nFuture):
            # 마지막 nPrior 만큼 입력데이로 다음 값을 예측한다
            xInput = dx[-nPrior:]
            xInput = np.reshape(xInput, (1, 1, nPrior))

            # 다음 값을 예측한다.
            y = model.predict(xInput)[0][0]
            print(xInput, y)
            # 예측값을 저장해 둔다
            estimate.append(y)

            # 이전 예측값을 포함하여 또 다음 값을 예측하기위해 예측한 값을 저장해 둔다
            dx = np.insert(dx, len(dx), y)

        # 원 시계열의 마지막 부분 100개와 예측된 시계열을 그린다
        dtail = df[-100:]
        ax1 = np.arange(1, len(dtail) + 1)
        ax2 = np.arange(len(dtail), len(dtail) + len(estimate))
        plt.figure(figsize=(8, 7))
        plt.plot(ax1, dtail, color='blue', label='Spread', linewidth=1)
        plt.plot(ax2, estimate, color='red', label='Estimate')
        plt.axvline(x=ax1[-1],  linestyle='dashed', linewidth=1)
        plt.title(x.stockA + '-' + x.stockB)
        plt.legend()
        plt.show()
        #print("추정치 : ", estimate)

# weight 값을 출력해 본다
def checkWeight(codeA, codeB):
    # LSTM 모델을 빌드한다
    model = buildModel(10)

    # LSTM weight의 초깃값을 결정한다. 저장된 weight가 있으면 이를 적용한다
    weightFile = codeA + '-' + codeB + '.h5'
    try:
        model.load_weights("data/" + weightFile)
        print("기존 학습 결과 Weight를 적용하였습니다.")
    except:
        print("model Weight을 Random 초기화 하였습니다.")

    np.set_printoptions(precision=3)
    for layer in model.layers:
        weights = layer.get_weights()
        print(weights)
        print()


import time
from gi.repository import Gst
from gi.repository import GstPbutils

Gst.init()
discoverer = GstPbutils.Discoverer()
info = discoverer.discover_uri('file:///home/eric/Downloads/01.mp4')
mysublist = info.get_subtitle_streams()
print(len(mysublist))
i=0
for x in mysublist:
    print (x.get_language(), i, info.get_subtitle_streams()[i].get_language())
    i+=1
uri = 'file:///home/eric/Downloads/01.mp4'

pipeline=Gst.ElementFactory.make("playbin", "playbin")
pipeline.set_property('uri',uri)
pipeline.set_state(Gst.State.PLAYING)
time.sleep(2)
subs = pipeline.get_property('n-text')
print("there are ", subs, " Subtitles")
auds = pipeline.get_property('n-audio')
print("there are ", auds, " Audio streams")
vids = pipeline.get_property('n-video')
print("there are ", vids, " Video Streams")


import json

import random
import os
import h5py
import numpy as np

import torch
from torch.utils.data import Dataset

class VideoDataset(Dataset):

    def get_vocab_size(self):
        return len(self.get_vocab())

    def get_vocab(self):
        return self.ix_to_word

    def get_seq_length(self):
        return self.seq_length

    def __init__(self, opt, mode):
        self.mode = mode  # to load train/val/test data

        # load the json file which contains information about the dataset
        print('DataLoader loading json file: ', opt.input_json)
        info = json.load(open(opt.info_json))
        self.ix_to_word = info['ix_to_word']
        print('vocab size is ', len(self.ix_to_word))
        self.splits = info['videos']
        print('number of train videos: ', len(self.splits['train']))
        print('number of val videos: ', len(self.splits['val']))
        print('number of test videos: ', len(self.splits['test']))
        # open the hdf5 file
        print('DataLoader loading video features: ', opt.feats_dir)
        print('DataLoader loading h5 file: ', opt.input_label_h5)
        self.h5_label_file = h5py.File(
            opt.input_label_h5, 'r', driver='core')

        self.feats_dir = opt.feats_dir

        # load in the sequence data
        self.seq_length = self.h5_label_file['labels'].shape[1]
        print('max sequence length in data is', self.seq_length)
        # load the pointers in full to RAM (should be small enough)
        self.label_start_ix = self.h5_label_file['label_start_ix'][:]
        self.label_end_ix = self.h5_label_file['label_end_ix'][:]

    def __getitem__(self, ix):
        """This function returns a tuple that is further passed to collate_fn
        """
        # which part of data to load
        if self.mode == 'val':
            ix += len(self.splits['train'])
        elif self.mode == 'test':
            ix = ix + len(self.splits['train']) + len(self.splits['val'])

        fc_feat = np.load(os.path.join(self.feats_dir,
                                       'video' + str(ix) + '.npy'))

        label = np.zeros([self.seq_length], dtype='int')
        mask = np.zeros([self.seq_length], dtype='float32')

        # fetch the sequence labels
        ix1 = self.label_start_ix[ix]
        ix2 = self.label_end_ix[ix]
        # random select a caption for this video
        ixl = random.randint(ix1, ix2)
        label = self.h5_label_file['labels'][ixl]

        nonzero_ixs = np.nonzero(label)[0]
        mask[:nonzero_ixs.max() + 2] = 1

        # Used for reward evaluation
        gts = self.h5_label_file['labels'][self.label_start_ix[ix]: self.label_end_ix[ix] + 1]

        # generate mask

        data = {}
        data['fc_feats'] = torch.from_numpy(fc_feat)
        data['labels'] = torch.from_numpy(label)
        data['gts'] = torch.from_numpy(gts)
        data['masks'] = torch.from_numpy(mask)
        data['ix'] = ix
        return data

    def __len__(self):
        return len(self.splits[self.mode])


import logging
import random
import sys
from time import sleep

from PyQt5.QtCore import QMutex, QObject, QThread, pyqtSignal
from PyQt5.QtWidgets import (
    QApplication,
    QLabel,
    QMainWindow,
    QPushButton,
    QVBoxLayout,
    QWidget,
)

logging.basicConfig(format="%(message)s", level=logging.INFO)

balance = 100.00
mutex = QMutex()

class AccountManager(QObject):
    finished = pyqtSignal()
    updatedBalance = pyqtSignal()

    def withdraw(self, person, amount):
        logging.info("%s wants to withdraw $%.2f...", person, amount)
        global balance
        mutex.lock()
        if balance - amount >= 0:
            sleep(1)
            balance -= amount
            logging.info("-$%.2f accepted", amount)
        else:
            logging.info("-$%.2f rejected", amount)
        logging.info("===Balance===: $%.2f", balance)
        self.updatedBalance.emit()
        mutex.unlock()
        self.finished.emit()

class Window(QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setupUi()
        self.threads = []

    def setupUi(self):
        self.setWindowTitle("Account Manager")
        self.resize(200, 150)
        self.centralWidget = QWidget()
        self.setCentralWidget(self.centralWidget)
        button = QPushButton("Withdraw Money!")
        button.clicked.connect(self.startThreads)
        self.balanceLabel = QLabel(f"Current Balance: ${balance:,.2f}")
        layout = QVBoxLayout()
        layout.addWidget(self.balanceLabel)
        layout.addWidget(button)
        self.centralWidget.setLayout(layout)

    def createThread(self, person, amount):
        thread = QThread()
        worker = AccountManager()
        worker.moveToThread(thread)
        thread.started.connect(lambda: worker.withdraw(person, amount))
        worker.updatedBalance.connect(self.updateBalance)
        worker.finished.connect(thread.quit)
        worker.finished.connect(worker.deleteLater)
        thread.finished.connect(thread.deleteLater)
        return thread

    def updateBalance(self):
        self.balanceLabel.setText(f"Current Balance: ${balance:,.2f}")

    def startThreads(self):
        self.threads.clear()
        people = {
            "Alice": random.randint(100, 10000) / 100,
            "Bob": random.randint(100, 10000) / 100,
        }
        self.threads = [
            self.createThread(person, amount)
            for person, amount in people.items()
        ]
        for thread in self.threads:
            thread.start()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = Window()
    window.show()
    sys.exit(app.exec())


from celery import Celery
import time

app = Celery('task', backend= 'redis://localhost', broker= 'redis://localhost')

@app.task()
def task():
    '''
    this is async
    '''
    print('work started')
    time.sleep(5)
    f = open('file.text', 'w', encoding= 'utf-8')
    for i in range(5000):
        for j in range(i):
            f.write(str(i))
        f.write('\n')
    f.close()
    print('work completed')
    return "Task result"


import json
from src.biz.dao import dao_case
import src.utils.comm as comm
from src.utils.enum import exec_status

class CaseMatch:
    _source_sql = ''
    _source_connect_id = 0
    _destination_sql = ''
    _destination_connect_id = 0
    _test_case_type = ''
    _threshlod_low = 0
    _threshlod_high = 0
    _duration_limit = 0

    def __init__(self, case_params):
        self._source_sql = case_params[0]
        self._source_connect_id = case_params[1] if case_params[1] is not None else 0
        self._destination_sql = case_params[2]
        self._destination_connect_id = case_params[3] if case_params[3] is not None else 0
        self._test_case_type = case_params[4]
        self._threshlod_low = case_params[5]
        self._threshlod_high = case_params[6]
        self._duration_limit = case_params[7]

class ExactlyMatch(CaseMatch):
    def __init__(self, case_params):
        CaseMatch.__init__(self, case_params)

    def RunCase(self):
        # step 1 Init
        current_status = exec_status.FAILED
        source_list = dao_case.get_list(
            self._source_connect_id, self._duration_limit, self._source_sql)
        target_list = dao_case.get_list(
            self._destination_connect_id, self._duration_limit, self._destination_sql)
        source_result = json.dumps(source_list)
        target_result = json.dumps(target_list)
        source_set = set(source_list)
        target_set = set(target_list)
        # step 2 duplicate data checking
        if len(source_list) > len(source_set):
            diff = "Source total count:{0}, distinct count:{1}".format(
                len(source_list), len(source_set))
            result_message = "Source side data is duplicate"
            return current_status, diff, result_message, source_result, target_result
        if len(target_list) > len(target_set):
            diff = "Target total count:{0}, distinct count:{1}".format(
                len(target_list), len(target_set))
            result_message = "Target side data is duplicate"
            return current_status, diff, result_message, source_result, target_result
        # step 3 compare the diff between source and target
        source_diff = source_set - target_set
        target_diff = target_set - source_set
        if(len(source_diff) == 0 and len(target_diff) == 0):
            current_status = exec_status.SUCCESS
            diff = ""
            result_message = "Source is totally matched with target --> Source count:{0},target count:{1}".format(
                len(source_list), len(target_list))
            return current_status, diff, result_message, source_result, target_result
        _diff = {
            "source-target": list(source_diff),
            "target-source": list(target_diff)
        }
        diff = json.dumps(_diff)
        result_message = "Source is not matched with target"
        return current_status, diff, result_message, source_result, target_result

class RangeMatch(CaseMatch):
    def __init__(self, case_params):
        CaseMatch.__init__(self, case_params)

    def RunCase(self):
        current_status = exec_status.FAILED
        source_result = ""
        target_result = ""
        diff = ""
        result_message = "execution is not success"

        if (self._source_connect_id > 0 and self._destination_connect_id == 0):
            source_count = dao_case.get_one(
                self._source_connect_id, self._duration_limit, self._source_sql)
            source_num = comm.int_val(source_count[0])
            if(len(source_count) > 0 and source_num is not None):
                source_result = source_num
                if(source_num >= self._threshlod_low and source_num <= self._threshlod_high):
                    current_status = exec_status.SUCCESS
                    result_message = "The value:{0} is in range".format(
                        source_num)
                else:
                    diff = "The value:{0} not in range".format(source_num)

        elif(self._source_connect_id == 0 and self._destination_connect_id > 0):
            target_count = dao_case.get_one(
                self._destination_connect_id, self._duration_limit, self._destination_sql)
            target_num = comm.int_val(target_count[0])
            if(len(target_count) > 0 and target_num is not None):
                target_result = target_num
                if(target_num >= self._threshlod_low and target_num <= self._threshlod_high):
                    current_status = exec_status.SUCCESS
                    result_message = "The value:{0} is in range".format(
                        target_num)
                else:
                    diff = "The value:{0} not in range".format(target_num)

        elif(self._source_connect_id > 0 and self._destination_connect_id > 0):
            source_count = dao_case.get_one(
                self._source_connect_id, self._duration_limit, self._source_sql)
            target_count = dao_case.get_one(
                self._destination_connect_id, self._duration_limit, self._destination_sql)
            if(len(source_count) > 0 and len(target_count) > 0):
                source_result = source_num
                target_result = target_num
                source_num = comm.int_val(source_count[0])
                target_num = comm.int_val(target_count[0])
                if(source_num is not None and target_num is not None):
                    gap_num = abs(source_num - target_num)
                    if(gap_num >= self._threshlod_low and gap_num <= self._threshlod_high):
                        current_status = exec_status.SUCCESS
                        result_message = "The value:{0} is in range".format(
                            gap_num)
                    else:
                        diff = "source_num:{0} - target_num:{1} = {2} not in range".format(
                            source_num, target_num, gap_num)

        return current_status, diff, result_message, source_result, target_result


import matplotlib.pyplot as plt
class AnalyzeData():
    def __init__(self, parent, fname):
        self.phi = []
        self.dB = []
        self.parent = parent
        self.fname = fname

    def show(self, status, name):
        if status:
            plt.axes(projection='polar')
        plt.plot(self.phi, self.dB, '.')

        plt.savefig(name)

    def analyze(self, phi):
        self.phi = []
        self.dB = []
        k = (phi - 90) / -5
        with open(self.fname) as t:
            for i, line in enumerate(t):
                if i > 72 * k + 2 and i < 75 + 72 * k:
                    nums = []
                    num = ""
                    for sym in line:
                        if sym != ' ':
                            num += sym
                        elif len(num) > 0 and sym == ' ':
                            nums.append(float(num))
                            num = ""
                    self.phi.append(nums[0])
                    self.dB.append(nums[2])
        t.close()


# -*- coding: utf-8 -*-
import requests

from yandex_maps import api

def get_yandex_location(api_key, address):
    url = api._get_geocode_url(api_key, address)
    response = requests.get(url)
    try:
        xml = response.text.encode('utf8')
        return api._get_coords(xml)
    except IOError:
        return None, None