# -*- coding: utf-8 -*-
"""
Created on Wed Oct 23 15:05:05 2019

@author: bguilfoyle
"""
import numpy as np
import astropy.io.fits as pyfits
import glob
import matplotlib
import matplotlib.animation as animation
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
from tkinter import *

#==============================================================================
def lingray(x, a=None, b=None):
    """
    Overview: Auxiliary function that specifies the linear gray scale.
    a and b are the cutoffs : if not specified, min and max are used
    """
    if a == None:
        a = np.min(x)
    if b == None:
        b = np.max(x)
    return 255.0 * (x-float(a))/(b-a)
#==============================================================================

#==============================================================================
def loggray(x, a=None, b=None):
    """
    Overview: Auxiliary function that specifies the logarithmic gray scale.
    a and b are the cutoffs : if not specified, min and max are used
    """
    if a == None:
        a = np.min(x)
    if b == None:
        b = np.max(x)
    linval = 10.0 + 990.0 * (x-float(a))/(b-a)
    return (np.log10(linval)-1.0)*0.5 * 255.0
#==============================================================================

#==============================================================================
def correctedImage(raw,dark,flat,bias):
    """
    Overview: Return a corrected image based off basic raw reduction
    """
    return (raw - bias - dark) / flat
#==============================================================================

def addPlot(image,colour,newAlpha):
    """
    Overview: Make a plot using plt.imshow
    """
    plt.imshow(loggray(image), cmap= colour, alpha = newAlpha)
    plt.colorbar()
#==============================================================================

path = "C:/Users/bguilfoyle/Documents/CompPhysics/FYP/seyfertGalaxyThesis/data/seyfertImages/"
rawRPath = path + "raw/*R.fit"
rawHPath = path + "raw/*H.fit"
rawSIIPath = path + "raw/*SII.fit"
rawVPath = path + "raw/*V.fit"
rawPath = path + "raw/*.fit"
biasPath = path + "bias/*.fit"
darkPath = path + "dark/*bin2.fit"
flatPath = path + "flat/Flat_bin2*.fit"

raw = glob.glob(rawRPath)
bias = glob.glob(biasPath)
dark = glob.glob(darkPath)
flat = glob.glob(flatPath)

avgRaw = avgImage(raw)
avgBias = avgImage(bias)
avgDark = avgImage(dark)
avgFlat = avgImage(flat)

finalCombined = correctedImage(avgRaw,avgDark,avgFlat,avgBias)
plt.imshow(loggray(finalCombined), cmap = "Reds")
plt.colorbar()


import matplotlib.pyplot as plt
import numpy as np
import datetime
import os
from scipy.special import erf
from more_itertools import locate

# ##################################   General constants   ##############################################
FS_LABEL = 24
FS_TICKS = 20

# ##################################   General classes   #################################################

class LivePlot:
    def __init__(self, subpl=2, num_y_data=1, x_ext=10, y_ext=6, mk='o', xlabel='x', ylabel='y'):
        self.fig = plt.figure(figsize=(x_ext, y_ext))
        self.subpl_num = subpl
        if subpl == 1:
            self.ax1 = self.fig.add_subplot(111)
        else:
            self.ax1 = self.fig.add_subplot(121)
        plt.plot([], [], marker=mk)
        if num_y_data == 2:
            plt.plot([], [], marker=mk)

        plt.xlabel(xlabel, labelpad=10, fontsize=FS_LABEL)
        plt.ylabel(ylabel, labelpad=10, fontsize=FS_LABEL)
        self.ax1.tick_params(axis='both', labelsize=FS_TICKS)

        if subpl > 1:
            self.ax2 = self.fig.add_subplot(122, polar=True)
            plt.plot([], [], marker=mk)
            plt.xlabel('', labelpad=10, fontsize=FS_LABEL)
            plt.ylabel('', labelpad=10, fontsize=FS_LABEL)
            self.ax2.tick_params(axis='both', labelsize=FS_TICKS)

        self.fig.show()
        self.fig.canvas.draw()
        plt.tight_layout()

    def plot_live(self, xdata, ydata, ydata2=None):
        self.ax1.lines[0].set_xdata(xdata)
        self.ax1.lines[0].set_ydata(ydata)
        if ydata2 is not None:
            self.ax1.lines[1].set_xdata(xdata)
            self.ax1.lines[1].set_ydata(ydata2)
        self.ax1.relim()
        self.ax1.autoscale_view()

        if self.subpl_num > 1:
            xdata = [xx * np.pi / 180 for xx in xdata]
            self.ax2.lines[0].set_xdata(xdata)
            self.ax2.lines[0].set_ydata(ydata)
            self.ax2.relim()
            self.ax2.autoscale_view()

        self.fig.canvas.draw()
        plt.pause(1e-7)

# ##################################   General functions   ##############################################

def data_save(array, figure, type, header):
    # fetch date and time
    now = datetime.datetime.now()
    date_str = now.strftime("%y%m%d %H%M")[:6]
    time_str = now.strftime("%y%m%d %H%M%S")[-6:]
    save_data_dir = r'C:\data\%s\%s' % (date_str, type)
    save_data_file = r'%s\%s_%s' % (save_data_dir, type, time_str)

    if not os.path.isdir(save_data_dir):
        os.makedirs(save_data_dir)
    figure.savefig(save_data_file + '.png', format='png', bbox_inches='tight')
    np.savetxt(save_data_file + '.txt', array, header=header)

def get_work_dir():
    # this function is useful when working from different computers in Dropbox, Google Drive...
    wd = os.getcwd()
    idx = list(locate(wd, lambda x: x == "\\"))
    return wd[:idx[-1]]

def prettify_plot(fig_ax, xlabel='x', ylabel='y'):
    fig_ax.set_xlabel(xlabel, labelpad=10, fontsize=FS_LABEL)
    fig_ax.set_ylabel(ylabel, labelpad=10, fontsize=FS_LABEL)
    fig_ax.tick_params(axis='both', labelsize=FS_TICKS)

def prettify_2d_plot(fig_ax, fig_cb, xlabel='x', ylabel='y', zlabel='z'):
    fig_ax.set_xlabel(xlabel, labelpad=10, fontsize=FS_LABEL)
    fig_ax.set_ylabel(ylabel, labelpad=10, fontsize=FS_LABEL)
    fig_cb.set_label(zlabel, labelpad=20, fontsize=FS_LABEL)
    fig_cb.ax.set_yticklabels(fig_cb.ax.get_yticklabels(), fontsize=FS_TICKS)
    fig_ax.tick_params(axis='both', labelsize=FS_TICKS)

def prettify_3d_plot(fig_ax, fig_cb, xlabel='x', ylabel='y', zlabel='z'):
    fig_ax.set_xlabel(xlabel, labelpad=15, fontsize=FS_LABEL)
    fig_ax.set_ylabel(ylabel, labelpad=20, fontsize=FS_LABEL)
    fig_cb.set_label(zlabel, labelpad=20, fontsize=FS_LABEL)
    fig_cb.ax.set_yticklabels(fig_cb.ax.get_yticklabels(), fontsize=FS_TICKS)
    fig_ax.tick_params(axis='both', labelsize=FS_TICKS)
    fig_ax.set_zticks([])
    fig_ax.w_xaxis.set_pane_color((1.0, 1.0, 1.0, 0.0))
    fig_ax.w_yaxis.set_pane_color((1.0, 1.0, 1.0, 0.0))
    fig_ax.w_zaxis.set_pane_color((1.0, 1.0, 1.0, 0.0))
    fig_ax.w_zaxis.line.set_color((1.0, 1.0, 1.0, 0.0))
    fig_ax.grid(False)

def lorentzian_func(x_array, a0, x0, gamma):
    # I0 = something proportional to the height
    # x0 = peak position
    # gamma = FWHM
    # bg = background
    return a0 * gamma / (np.pi * ((x_array - x0) ** 2 + gamma ** 2))

def gaussian_func(x_array, a0, x0, sigma):
    return a0 * np.exp(-(x_array - x0) ** 2 / (2 * sigma ** 2)) / np.sqrt(2 * np.pi * sigma ** 2)

def voigt_func(x, a0, x0, sigma, gamma):
    # Voigt function = line profile of a Gaussian distribution convoluted with a Lorentzian distribution.
    # input coeff should be one array [height, position, gaussian width sigma, lorentzian width gamma]

    z1 = (x - x0 + 1j * gamma) / (sigma * np.sqrt(2))
    arg1 = np.exp(-z1 ** 2) * (1 - erf(-1j * z1))
    # genuine definition of Voigt function
    f1 = 1 / (sigma * np.sqrt(2 * np.pi)) * np.real(arg1)

    return a0 * f1 / np.max(f1)

def voigt_func_2p(x, a01, x01, sigma1, gamma1, a02, x02, sigma2, gamma2):
    # Voigt function = line profile of a Gaussian distribution convoluted with a Lorentzian distribution.
    # input coeff should be two line vector [height, position, gaussian width sigma, lorentzian width gamma]
    # one array per peak to fit

    z1 = (x - x01 + 1j * gamma1) / (sigma1 * np.sqrt(2))
    z2 = (x - x02 + 1j * gamma2) / (sigma2 * np.sqrt(2))

    arg1 = np.exp(-z1 ** 2) * (1 - erf(-1j * z1))
    arg2 = np.exp(-z2 ** 2) * (1 - erf(-1j * z2))

    # genuine definition of Voigt function
    f1 = 1 / (sigma1 * np.sqrt(2 * np.pi)) * np.real(arg1)
    f2 = 1 / (sigma2 * np.sqrt(2 * np.pi)) * np.real(arg2)

    # row = isnan(F)
    # n_row = find(row == 1)
    # if numel(n_row) ~= 0:
    # F(n_row(1):n_row(end)) = 0
    return a01 * f1 / np.max(f1) + a02 * f2 / np.max(f2)


"""
-- =============== TODO run combination optimization
pai -name tensorflow180
-Dtables="odps://search_student_dev/tables/F_ui,odps://search_student_dev/tables/F_i,odps://search_student_dev/tables/item_0503_0505_clk_rate_2"

-Dscript="odps://search_student_dev/resources/chaoyu.py"
sda
"""

# import time
from collections import defaultdict
import tensorflow as tf

class Pair:
    def __init__(self, user_ID, item_ID, CTR):
        self.user_ID = int(user_ID)
        self.item_ID = int(item_ID)
        self.CTR = float(CTR)

    def __repr__(self):
        return str([self.user_ID, self.item_ID, self.CTR])

import random as rd
# import time
import numpy as np

tf.app.flags.DEFINE_string("tables", "", "fui, ctr, test_data")
tf.app.flags.DEFINE_integer('is_valid', 1,
                            '1: validation; 0: not validation')
tf.app.flags.DEFINE_string("outputs", "", "tables info saving")

FLAGS = tf.app.flags.FLAGS
# [train_table, test_table]
tables = FLAGS.tables.strip().split(",")

F_ui_name = tables[0]
F_ui_col = "group_id,item_id,_c2"

F_i_name = tables[1]
F_i_col = "item_id,score"

test_i_name = tables[2]
test_i_col = "item_id,clk_num"

O = tables[2].split('_')[-3]

def tuple2dict(x, mod='item_score'):
    k = len(x[0])
    if mod == 'item_score':
        d = {}
        for i in range(len(x)):
            d[int(x[i][0])] = float(x[i][1])
        return d

    if mod == 'user_item_score':
        pairs = []
        for i in range(len(x)):
            pairs.append(Pair(x[i][0], x[i][1], x[i][2]))
        # pairs = [Pair(pair.split("_")[0], pair.split("_")[1], score)
        #          for pair, score in pairs.items()]
        return pairs
    if mod == 'test':
        pairs = []
        for i in range(len(x)):
            # test data does not have user_id
            pairs.append(Pair(0, x[i][0], x[i][1]))
        return pairs

def load_table(name="odps://search_student_dev/tables/F_ui",
               cols="user_id,item_id,score",
               batch_size=None):
    reader = tf.python_io.TableReader(name, selected_cols=cols)
    if batch_size is None:
        batch_size = reader.get_row_count()  # return 3

    uis = reader.read(batch_size)
    reader.close()

    print('load: {}, cols: {}, num: {}, exp: {}'.format(name, cols,
                                                        batch_size,
                                                        uis[0]))
    return uis

UI_S = load_table(F_ui_name, F_ui_col)
UI_S_2 = tuple2dict(UI_S, 'user_item_score')

I_S = load_table(F_i_name, F_i_col)
I_S_2 = tuple2dict(I_S, 'item_score')

test_I_S = load_table(test_i_name, test_i_col)
test_I_S_2 = tuple2dict(test_I_S, 'test')

def TopK(F, K, K_choose, mod='sum'):

    if mod == 'sum':
        score_item = {}
        for user in F:
            for item, socre in F[user].items():
                if item not in score_item:
                    score_item[item] = 0
                score_item[item] += socre

        score_item = [[item, socre] for item, socre in score_item.items()]
        score_item.sort(key=lambda x: x[1], reverse=True)
        return {score_item[i][0] for i in range(K)}, \
               {score_item[i][0] for i in range(K, K_choose)}
    if mod == 'avg':
        score_item_list = defaultdict(list)
        score_item = {}
        for user in F:
            for item, score in F[user].items():
                score_item_list[item].append(score)

        for k, v in score_item:
            if len(v) == 0:
                score_item[k] = 0
            else:
                score_item[k] = sum(v) / len(v)
        score_item.sort(key=lambda x: x[1], reverse=True)
        return {score_item[i][0] for i in range(K)}, \
               {score_item[i][0] for i in range(K, K_choose)}

def f(F, S, O):
    obj = 0
    Y = {}

    for user in F:
        put = [[item, score] for item, score in F[user].items()
               if item in S]
        put.sort(key=lambda x: x[1], reverse=True)

        put = put[:min(len(put), O)]

        obj += sum([pair[1] for pair in put])
        Y[user] = [pair[0] for pair in put]

    return obj, Y

def swap_random(S, T):
    S1 = {_ for _ in S}
    T1 = {_ for _ in T}

    i = rd.choice(list(S1))
    j = rd.choice(list(T1))

    S1.remove(i)
    T1.remove(j)
    S1.add(j)
    T1.add(i)

    return S1, T1

def Heuristic_swap_random(M, N, O, K, F,
                          K_choose, times, is_print=True,
                          is_IP=True,
                          epoch=None):
    K_choose = min(K_choose, N)
    # S is select top item, T is candidate item (size_top_item * 2)
    S, T = TopK(F, K, K_choose, mod='sum')
    S0 = {item for item in S}

    obj0, Y0 = f(F, S, O)
    obj_TopK = obj0  # score befor swap
    if is_IP is False:
        return obj0, obj0, S, S

    loop = 0
    if is_print:
        print("\n g-i loop:", loop, "obj_TopK:", obj_TopK)
    flag = True

    while flag:
        flag = False
        for i in range(times):
            loop += 1
            S1, T1 = swap_random(S, T)
            obj1, Y1 = f(F, S1, O)
            if obj0 < obj1:
                S, T = S1, T1
                obj0, Y0 = obj1, Y1
                flag = True
                break
        if is_print:
            print("g-i O: {}, K: {}, loop: {}, obj:{}".format(O, K, loop, obj0))
        if epoch is not None and loop > epoch:
            break

    return obj0, obj_TopK, S, S0

def user_and_item_read(path):
    pairs = pickle.load(open(path, "rb"))
    pairs = [Pair(pair.split("_")[0], pair.split("_")[1], score)
             for pair, score in pairs.items()]
    return pairs

def item_read(path):
    data_train_item = pickle.load(open(path, "rb"))
    data_train_item = {int(k): float(v) for k, v in data_train_item.items()}
    # tmp = load_table('item_score')
    return data_train_item

def data_filter(data_train, data_test, data_train_item):

    num_data_train = len(data_train)
    num_data_test = len(data_test)
    num_data_train_item = len(data_train_item)

    S_item_train = set()
    for pair in data_train:
        S_item_train.add(pair.item_ID)

    S_item_test = set()
    for pair in data_test:
        S_item_test.add(pair.item_ID)

    S_item_train1 = set(data_train_item.keys())

    S = S_item_train & S_item_test & S_item_train1
    print(' item set size: {}, {}, {}, {}'.format(len(S), len(S_item_train), len(S_item_test), len(S_item_train1)))

    set_del_data_train = set()
    for i in range(len(data_train)):
        if data_train[i].item_ID not in S:
            set_del_data_train.add(i)

    set_del_data_test = set()
    for i in range(len(data_test)):
        if data_test[i].item_ID not in S:
            set_del_data_test.add(i)

    set_del_data_train_item = set()
    for k in data_train_item:
        if k not in S:
            set_del_data_train_item.add(k)

    data_train = [data_train[i]
                  for i in range(len(data_train)) if i not in set_del_data_train]
    data_test = [data_test[i]
                 for i in range(len(data_test)) if i not in set_del_data_test]
    data_train_item = {k: v for k, v in data_train_item.items()
                       if k not in set_del_data_train_item}
    print("\ndata_train: ", num_data_train, len(data_train))
    print("\ndata_test: ", num_data_test, len(data_test))
    print("\ndata_train_item: ", num_data_train_item, len(data_train_item))
    return data_train, data_test, data_train_item

def data_read_and_filter():
    data_train_item = I_S_2
    data_train = UI_S_2
    data_test = test_I_S_2
    data_train, data_test, data_train_item = data_filter(
        data_train, data_test, data_train_item)
    return data_train, data_test, data_train_item

def user_and_item_count(data_train):
    # t1 = time.perf_counter()
    D_user = {}
    D_item = {}
    for pair in data_train:
        if pair.user_ID not in D_user:
            D_user[pair.user_ID] = set()
        D_user[pair.user_ID].add(pair.item_ID)

        if pair.item_ID not in D_item:
            D_item[pair.item_ID] = set()
        D_item[pair.item_ID].add(pair.user_ID)
    return D_user, D_item, len(D_user), len(D_item)

def F_generate(data_train):
    F = {}
    for pair in data_train:
        if pair.user_ID not in F:
            F[pair.user_ID] = {}
        F[pair.user_ID][pair.item_ID] = pair.CTR
    return F

def S_item_socre_TopK_generate(data_train_item, K):
    S_temp = [[k, v] for k, v in data_train_item.items()]
    S_temp.sort(key=lambda x: x[1], reverse=True)

    return set([S_temp[i][0] for i in range(min(len(S_temp), K))])

def S_test(S, data_test):
    click = sum([pair.CTR for pair in data_test if pair.item_ID in S])
    return click

def hit(s1, data_test, if_debug=False):

    d = {}
    for pair in data_test:
        d[pair.item_ID] = pair.CTR
    d_sorted = sorted(d.items(), key=lambda item: item[1], reverse=True)

    s2 = set()
    for i in range(k):
        s2.add(d_sorted[i][0])

    common = len(s1 & s2)
    if if_debug:
        print('common , {}'.format(common))
        print(s1 & s2)
        print('s1, {}. s2, {} '.format(list(s1)[:5],
                                       list(s2)[:5])
              )
    print('hit@{}: {}/{}, s1 size: {}, s2 size: {}'.format(len(s1), common, len(s1), len(s1), len(s2)))

if __name__ == '__main__':
    print("group-item comb-opt....")
    # 1 load data
    print('data_read_and_filter')
    data_train, data_test, data_train_item = data_read_and_filter()

    # 2 basic info
    print('get basic info')
    D_user, D_item, M, N = user_and_item_count(data_train)

    # 3 F score
    F = F_generate(data_train)
    K = 500
    # O is extract from table_name

    epoch =None# 2000
    if_debug = False
    # t4 = time.perf_counter()
    print('Heuristic_swap_random')
    obj, obj_F_TopK, S, S_F_TopK = Heuristic_swap_random(M,
                                                         N,
                                                         O,
                                                         K,
                                                         F,
                                                         4 * K,
                                                         times=3000,
                                                         is_print=True,
                                                         is_IP=True,
                                                         epoch=epoch
                                                         )
    print('TRAIN: select item on training set based on F_gi')
    print("obj_F_TopK:", obj_F_TopK)
    print("obj:", obj)

    # 4-get top-k item
    print('TEST: eval on test_set')
    print('top-k item eval')
    S_item_socre_TopK = S_item_socre_TopK_generate(data_train_item, K)

    CTR_TopK = S_test(S_F_TopK, data_test)
    CTR = S_test(S, data_test)
    CTR_item_socre_TopK = S_test(S_item_socre_TopK, data_test)

    print("\nCTR_F_TopK: ", CTR_TopK, 'hit: ', hit(S_F_TopK, data_test, if_debug=if_debug))
    print("\nCTR: ", CTR, 'hit: ', hit(S, data_test))
    print("\nCTR_item_socre_TopK: ", CTR_item_socre_TopK, 'hit: ', hit(S_item_socre_TopK, data_test))
    print(tables)


import time, datetime, random

from flask import Blueprint, render_template, g, jsonify, url_for, request, flash, redirect

from app.users.decorators import requires_login

from models import Report, Widget, get_session

mod = Blueprint('report', __name__, url_prefix='/report')

@mod.route('/')
@requires_login
def home():
	return render_template("report/index.html", user=g.user)

@mod.route('/save', methods=['POST'])
@requires_login
def save():
	r = Report()
	r.client_id = g.user.client_id
	r.name = request.form['name']
	for widget in get_session().query(Widget).filter(Widget.id.in_(request.form.getlist("widgets"))):
		r.widgets.append(widget)
	r.save()
	flash("Report '%s' saved" % (r.name))
	return redirect(url_for('report.home'))

@mod.route('/view/<id>')
@requires_login
def view(id):
	pass


"""Functions that deal with orders logic"""
from datetime import datetime
import candy_delivery_app.database.db as db

def is_order_suitable(courier, order):
    """
    Check whether the order is suitable to the courier
    """

    max_weight = db.get_courier_type_weight(
        db.get_courier_type_id(courier['courier_type'])
    )

    if order['weight'] > max_weight:
        return False

    if order['region'] not in courier['regions']:
        return False

    current_year = int(datetime.now().year)
    current_month = int(datetime.now().month)
    current_day = int(datetime.now().day)

    for working_hour in map(lambda x: x.split('-'),
                            courier['working_hours']):

        work_start = datetime(year=current_year,
                              month=current_month,
                              day=current_day,
                              hour=int(working_hour[0][:2]),
                              minute=int(working_hour[0][3:])
                              )
        work_end = datetime(year=current_year,
                            month=current_month,
                            day=current_day,
                            hour=int(working_hour[1][:2]),
                            minute=int(working_hour[1][3:]),
                            )

        for delivery_hour in map(lambda x: x.split('-'),
                                 order['delivery_hours']):
            delivery_start = datetime(year=current_year,
                                      month=current_month,
                                      day=current_day,
                                      hour=int(delivery_hour[0][:2]),
                                      minute=int(delivery_hour[0][3:]),
                                      )
            delivery_end = datetime(year=current_year,
                                    month=current_month,
                                    day=current_day,
                                    hour=int(delivery_hour[1][:2]),
                                    minute=int(delivery_hour[1][3:]),
                                    )

            if work_start < delivery_end and work_end > delivery_start:
                return True
    return False


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

# The imports in this file are order-sensitive
import re

from flask import Flask, Markup, escape
from flask_assets import Environment, Bundle
from baseframe import baseframe, baseframe_js, baseframe_css
from flask_lastuser import LastUser
import coaster.app

# First, make an app

app = Flask(__name__, instance_relative_config=True)
lastuser = LastUser()

#Prepare assets

assets = Environment(app)
js = Bundle(baseframe_js,
            filters='jsmin', output='js/packed.js')
css = Bundle(baseframe_css, 'css/app.css')

# Configure the app
coaster.app.init_app(app)
lastuser.init_app(app)
assets.register('js_all', js)
assets.register('css_all', css)

# Last, after config, import the models and views

app.register_blueprint(baseframe)
import billgate.models
import billgate.views

EMAIL_RE = re.compile(r'\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b', re.I)

def scrubemail(data, rot13=False, css_junk=None):
    """
    Convert email addresses in text into HTML links,
    and optionally obfuscate them with ROT13 and empty CSS classes,
    to hide from spambots.
    """

    def convertemail(m):
        aclass = ' class="rot13"' if rot13 else ''
        email = m.group(0)
        link = 'mailto:' + email
        if rot13:
            link = link.decode('rot13')
        if css_junk and len(email) > 3:
            third = int(len(email) / 3)
            parts = (email[:third], email[third:third * 2], email[third * 2:])
            if isinstance(css_junk, (tuple, list)):
                css_dirty, css_clean = css_junk
                email = '%sno'\
                    '%sspam'\
                    '%s' % (
                    css_clean, parts[0], css_dirty, css_clean, parts[1],
                    css_dirty, css_clean, parts[2])
            else:
                email = '%sno%sspam%s' % (
                    parts[0], css_junk, parts[1], css_junk, parts[2])
            email = email.replace('@', '@')
        if rot13:
            return '%s' % (aclass, link, email)
        else:
            return '%s' % (aclass, link, email)
    data = EMAIL_RE.sub(convertemail, data)
    return data

@app.template_filter('scrubemail')
def scrubemail_filter(data, css_junk=''):
    return Markup(scrubemail(unicode(escape(data)), rot13=True, css_junk=css_junk))


from joblib import memory
from numba import jit, vectorize
import numpy as np
import pandas as pd
import re
import tempfile

from .tree import Node

RE = re.compile('poly\(([^,]+),\s*(\d+)\)$')
TERM_RE = re.compile('(' + RE.pattern.replace('$', '') + ')(\d+)')

# Cache on disk (but available via mmap) the results of the orthogonal
# polynomials.
#memcache = memory.Memory(cachedir=tempfile.mkdtemp(prefix='poly-cache'),
#                         verbose=1, mmap_mode='r')

def poly_parse(node):
  m = re.match(TERM_RE, node)
  if m is None:
    raise ValueError("not a poly term '%s'" % node)
  term = m.group(1)
  var = m.group(2)
  power = int(m.group(3))
  degree = int(m.group(4))
  assert int(degree) <= int(power), "expected degree <= power"
  return var, power, degree

def poly(x, what, norm2=None, alpha=None):
  if isinstance(what, str):
    _, power, degree = poly_parse(what)
  elif isinstance(what, list):
    assert len(what) == 2, 'unexpected number of arguments to poly()'
    power, degree = what
  else:
    raise ValueError("unexpected type '%s'" % str(type(what)))
  shape = x.shape
  if norm2 and alpha:
    Z = ortho_poly_predict(x.reshape(-1), np.array(norm2), np.asarray(alpha),
                           power)
  else:
    Z, _, _ = ortho_poly_fit(x.reshape(-1), power)
  ret = Z[:, degree].reshape(shape)
  return ret

#@memcache.cache
def ortho_poly_fit(x, degree = 1):
  n = degree + 1
  x = np.asarray(x).flatten()
  if(degree >= len(np.unique(x))):
    stop("'degree' must be less than number of unique points")
  xbar = np.mean(x)
  x = x - xbar
  X = np.fliplr(np.vander(x, n))
  q,r = np.linalg.qr(X)

  z = np.diag(np.diag(r))
  raw = np.dot(q, z)

  norm2 = np.sum(raw**2, axis=0)
  alpha = (np.sum((raw**2)*np.reshape(x,(-1,1)), axis=0)/norm2 + xbar)[:degree]
  Z = raw / np.sqrt(norm2)
  return Z, norm2, alpha

def ortho_poly_predict(x, norm2, alpha, degree = 1):
  x = np.asarray(x).flatten()
  n = degree + 1
  Z = np.empty((len(x), n), dtype=x.dtype)
  Z[:, 0] = 1
  if degree > 0:
    Z[:, 1] = x - alpha[0]
  if degree > 1:
    for i in np.arange(1,degree):
      Z[:, i+1] = (x - alpha[i]) * Z[:, i] - (norm2[i] / norm2[i-1]) * Z[:, i-1]
  Z /= np.sqrt(norm2)
  return Z

@vectorize(nopython=True, cache=True)
def inv_logit(p):
  return np.exp(p) / (1 + np.exp(p))

def scale(x, low, high, x_min=None, x_max=None):
  xx = x.values if isinstance(x, pd.Series) else x
  if x_min is None:
    x_min = x.min()
  if x_max is None:
    x_max = x.max()
  return __scale(xx, np.float32(low), np.float32(high),
                 np.float32(x_min), np.float32(x_max))

@jit(nopython=True, cache=True)
def __scale(x, low, high, x_min=None, x_max=None):
  x_std = (x - x_min) / (x_max - x_min)
  scaled = x_std * (high - low) + low
  return scaled


from pyspark.sql import Window, DataFrame
from pyspark.sql.functions import col, lag
from com.ophelib.utils import regex_expr, feature_picking

__all__ = ["PctChangeDF", "PctChangeWrapper"]

class PctChangeDF(object):

    @staticmethod
    def __build_pct_change_function(x, t, w):
        if isinstance(x, str):
            return ((col(x) / lag(col(x), offset=t).over(w)) - 1).alias(x)
        elif isinstance(x, list):
            return [(col(c) / lag(col(c), offset=t).over(w) - 1).alias(c) for c in x]

    @staticmethod
    def __build_window_partition(self, periods, order_by, pct_cols, partition_by=None, desc=False):
        if desc:
            if partition_by is None:
                win = Window.orderBy(col(order_by).desc())
            else:
                win = Window.partitionBy(partition_by).orderBy(col(order_by).desc())
        else:
            if partition_by is None:
                win = Window.orderBy(col(order_by))
            else:
                win = Window.partitionBy(partition_by).orderBy(col(order_by))
        function = PctChangeDF.__build_pct_change_function(x=pct_cols, t=periods, w=win)
        return self.select(function)

    @staticmethod
    def __infer_sort_column(self):
        regex_match = ['year', 'Year', 'date', 'Date', 'month', 'Month', 'day', 'Day']
        regex_list = self.selectRegex(regex_expr(regex_match)).columns
        if len(regex_list) > 0:
            return regex_list
        elif len(feature_picking(self)['date']) > 0:
            return feature_picking(self)['date']
        else:
            return feature_picking(self)['string']

    @staticmethod
    def __infer_lag_column(self):
        if len(feature_picking(self)['double']) > 0:
            return feature_picking(self)['double']
        elif len(feature_picking(self)['float']) > 0:
            return feature_picking(self)['float']
        elif len(feature_picking(self)['long']) > 0:
            return feature_picking(self)['long']
        else:
            return feature_picking(self)['int']

    @staticmethod
    def pct_change(self, periods=1, order_by=None, pct_cols=None, partition_by=None, desc=None):
        if (order_by is None) and (pct_cols is None):
            infer_sort = PctChangeDF.__infer_sort_column(self)[0]
            infer_lag = PctChangeDF.__infer_lag_column(self)[1]
            return PctChangeDF.__build_window_partition(self, periods, infer_sort, infer_lag)
        return PctChangeDF.__build_window_partition(self, periods, order_by, pct_cols, partition_by, desc)

    @staticmethod
    def remove_element(self, col_remove):
        primary_list = self.columns
        [primary_list.remove(c) for c in col_remove]
        return primary_list

class PctChangeWrapper(object):

    DataFrame.pctChange = PctChangeDF.pct_change
    DataFrame.remove_element = PctChangeDF.remove_element


"""
Asynchronous Advantage Actor Critic (A3C) with discrete action space, Reinforcement Learning.

The Cartpole example.

View more on my tutorial page: https://morvanzhou.github.io/tutorials/

Using:
tensorflow 1.0
gym 0.8.0
"""

import multiprocessing
import threading
import tensorflow as tf
import numpy as np
import gym
import os
import shutil
import matplotlib.pyplot as plt

from gym.wrappers.time_limit import TimeLimit
import argparse
from baselines import logger
from skimage.color import rgb2grey
from skimage.transform import resize
import copy
import sys
from collections import deque

img_lock = threading.Lock()
log_lock = threading.Lock()

GAME = 'CartPole-v0'
OUTPUT_GRAPH = True
LOG_DIR = './log'
N_WORKERS = multiprocessing.cpu_count()
MAX_GLOBAL_EP = 1000
GLOBAL_NET_SCOPE = 'Global_Net'
UPDATE_GLOBAL_ITER = 100 #10
GAMMA = 0.999 # 0.9
ENTROPY_BETA = 0.01 # 0.001
GLOBAL_RUNNING_R = []
GLOBAL_R = []
GLOBAL_EP = 0

env = gym.make(GAME)
N_S = env.observation_space.shape[0]
N_A = env.action_space.n

class ACNet(object):
    def __init__(self, scope, globalAC=None, hard_share=None, soft_sharing_coeff_actor=0.01, soft_sharing_coeff_critic=0.01, gradient_clip_actor=1.0, gradient_clip_critic=1.0, image_shape=None, stack=1):
        self.hard_share = hard_share
        self.image_shape = image_shape
        self.stack = stack

        def input_placeholders():
            if self.image_shape is not None:
                s = tuple([tf.placeholder(tf.float32, [None, ] + list(self.image_shape), 'S') for _ in range(self.stack)])
            else:
                s = tuple([tf.placeholder(tf.float32, [None, N_S], 'S') for _ in range(self.stack)])
            return s

        if scope == GLOBAL_NET_SCOPE:   # get global network
            with tf.variable_scope(scope):
                self.s = input_placeholders()
                self.a_params, self.c_params = self._build_net(scope)[-2:]
        else:   # local net, calculate losses
            with tf.variable_scope(scope):
                self.s = input_placeholders()
                self.a_his = tf.placeholder(tf.int32, [None, ], 'A')
                self.v_target = tf.placeholder(tf.float32, [None, 1], 'Vtarget')

                self.a_prob, self.v, self.a_params, self.c_params = self._build_net(scope)

                td = tf.subtract(self.v_target, self.v, name='TD_error')
                self.t_td = td
                with tf.name_scope('c_loss'):
                    self.c_loss = tf.reduce_mean(tf.square(td))
                    if soft_sharing_coeff_actor > 0:
                        self.c_loss += soft_sharing_coeff_critic*tf.nn.l2_loss(self.l_a - self.l_c)

                with tf.name_scope('a_loss'):
                    log_prob = tf.reduce_sum(tf.log(self.a_prob) * tf.one_hot(self.a_his, N_A, dtype=tf.float32), axis=1, keep_dims=True)
                    self.t_log_prob = log_prob
                    exp_v = log_prob * tf.stop_gradient(td)
                    self.t_exp_v = exp_v
                    entropy = -tf.reduce_sum(self.a_prob * tf.log(self.a_prob + 1e-5),
                                             axis=1, keep_dims=True)  # encourage exploration
                    self.t_entropy = entropy
                    self.exp_v = ENTROPY_BETA * entropy + exp_v
                    self.t_exp_v2 = self.exp_v
                    self.a_loss = tf.reduce_mean(-self.exp_v)
                    if soft_sharing_coeff_critic > 0:
                        self.a_loss += soft_sharing_coeff_actor*tf.nn.l2_loss(self.l_a - self.l_c)

                with tf.name_scope('local_grad'):
                    self.a_grads, _ = tf.clip_by_global_norm(tf.gradients(self.a_loss, self.a_params), gradient_clip_actor)
                    if gradient_clip_actor > 0:
                        self.a_grads, _ = tf.clip_by_global_norm(self.a_grads, gradient_clip_actor)
                    self.c_grads, _ = tf.clip_by_global_norm(tf.gradients(self.c_loss, self.c_params), gradient_clip_critic)
                    if gradient_clip_critic > 0:
                        self.c_grads, _ = tf.clip_by_global_norm(self.c_grads, gradient_clip_critic)

            with tf.name_scope('sync'):
                with tf.name_scope('pull'):
                    self.pull_a_params_op = [l_p.assign(g_p) for l_p, g_p in zip(self.a_params, globalAC.a_params)]
                    self.pull_c_params_op = [l_p.assign(g_p) for l_p, g_p in zip(self.c_params, globalAC.c_params)]
                with tf.name_scope('push'):
                    self.update_a_op = OPT_A.apply_gradients(zip(self.a_grads, globalAC.a_params))
                    self.update_c_op = OPT_C.apply_gradients(zip(self.c_grads, globalAC.c_params))

    def _build_net(self, scope):
        w_init = tf.random_normal_initializer(0., .1)
        inputs = self.s
        if self.hard_share is not None:
            if self.image_shape is not None:
                with tf.variable_scope('conv_inputs'):
                    if self.stack == 2:
                        diff = inputs[1] - inputs[0]
                        inputs = tf.concat([inputs[1], diff], -1)
                    else:
                        inputs = tf.concat(inputs, -1)
                    conv1 = tf.layers.conv2d(inputs, 64, 5, strides=(3,3), padding='same', activation=tf.nn.relu, kernel_initializer=tf.truncated_normal_initializer(), bias_initializer=tf.constant_initializer(1.0), name='c1')
                    conv2 = tf.layers.conv2d(conv1, 32, 5, strides=(3,3), padding='same', activation=tf.nn.relu, kernel_initializer=tf.truncated_normal_initializer(), bias_initializer=tf.constant_initializer(1.0), name='c2')
                    conv3 = tf.layers.conv2d(conv2, 16, 3, strides=(3,3), padding='same', activation=tf.nn.relu, kernel_initializer=tf.truncated_normal_initializer(), bias_initializer=tf.constant_initializer(1.0), name='c3')
                    conv4 = tf.layers.conv2d(conv3, 16, 3, strides=(3,3), padding='same', activation=tf.nn.relu, kernel_initializer=tf.truncated_normal_initializer(), bias_initializer=tf.constant_initializer(1.0), name='c4')
                    inputs = tf.layers.flatten(conv4, name='p3')
            else:
                inputs = tf.concat(inputs, 1)
            if self.hard_share == 'equal_params':
                with tf.variable_scope('shared'):
                    l_s = tf.layers.dense(inputs, 71, tf.nn.relu6, kernel_initializer=w_init, name='ls')
                with tf.variable_scope('actor'):
                    l_a = tf.layers.dense(l_s, 16, tf.nn.relu6, kernel_initializer=w_init, name='la')
                    a_prob = tf.layers.dense(l_a, N_A, tf.nn.softmax, kernel_initializer=w_init, name='ap')
                with tf.variable_scope('critic'):
                    l_c = tf.layers.dense(l_s, 16, tf.nn.relu6, kernel_initializer=w_init, name='lc')
                    v = tf.layers.dense(l_c, 1, kernel_initializer=w_init, name='v')  # state value
            elif False:
                with tf.variable_scope('shared'):
                    l_s = tf.layers.dense(inputs, 100, tf.nn.relu6, kernel_initializer=w_init, name='ls')
                with tf.variable_scope('actor'):
                    l_a = tf.layers.dense(l_s, 10, tf.nn.relu6, kernel_initializer=w_init, name='la')
                    a_prob = tf.layers.dense(l_a, N_A, tf.nn.softmax, kernel_initializer=w_init, name='ap')
                with tf.variable_scope('critic'):
                    l_c = tf.layers.dense(l_s, 10, tf.nn.relu6, kernel_initializer=w_init, name='lc')
                    v = tf.layers.dense(l_c, 1, kernel_initializer=w_init, name='v')  # state value
            else:
                with tf.variable_scope('shared'):
                    l_s = tf.layers.dense(inputs, 200, tf.nn.relu6, kernel_initializer=w_init, name='ls')
                with tf.variable_scope('actor'):
                    l_a = tf.layers.dense(l_s, 10, tf.nn.relu6, kernel_initializer=w_init, name='la')
                    a_prob = tf.layers.dense(l_a, N_A, tf.nn.softmax, kernel_initializer=w_init, name='ap')
                with tf.variable_scope('critic'):
                    l_c = tf.layers.dense(l_s, 10, tf.nn.relu6, kernel_initializer=w_init, name='lc')
                    v = tf.layers.dense(l_c, 1, kernel_initializer=w_init, name='v')  # state value

            s_params = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, scope=scope + '/shared')
            a_params = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, scope=scope + '/actor')
            c_params = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, scope=scope + '/critic')
            return a_prob, v, a_params+s_params, c_params+s_params
        else:
            if self.image_shape is not None:
                with tf.variable_scope('conv_inputs'):
                    if self.stack == 2:
                        diff = inputs[1] - inputs[0]
                        inputs = tf.concat([inputs[1], diff], -1)
                    else:
                        inputs = tf.concat(inputs, -1)
                    conv1 = tf.layers.conv2d(inputs, 64, 8, strides=(5,5), padding='same', activation=tf.nn.relu, kernel_initializer=tf.truncated_normal_initializer(), bias_initializer=tf.constant_initializer(0.1), name='c1')
                    conv2 = tf.layers.conv2d(conv1, 64, 5, strides=(3,3), padding='same', activation=tf.nn.relu, kernel_initializer=tf.truncated_normal_initializer(), bias_initializer=tf.constant_initializer(0.1), name='c2')
                    conv3 = tf.layers.conv2d(conv2, 32, 3, strides=(2,2), padding='same', activation=tf.nn.relu, kernel_initializer=tf.truncated_normal_initializer(), bias_initializer=tf.constant_initializer(0.1), name='c3')
                    conv4 = tf.layers.conv2d(conv3, 16, 3, strides=(2,2), padding='same', activation=tf.nn.relu, kernel_initializer=tf.truncated_normal_initializer(), bias_initializer=tf.constant_initializer(0.1), name='c4')
                    inputs = tf.layers.flatten(conv4, name='p3')
                    '''
                    # TODO DWEBB add stack support here
                    diff = inputs[1] - inputs[0]
                    inputs = tf.concat([inputs[1], diff], -1)
                    conv1 = tf.layers.conv2d(inputs, 64, 8, name='c1')
                    #pool1 = tf.layers.max_pooling2d(conv1, 5, 1, name='p1')
                    relu1 = tf.nn.relu(conv1, name='relu1')
                    conv2 = tf.layers.conv2d(relu1, 32, 8, name='c2')
                    pool2 = tf.layers.max_pooling2d(conv2, 5, 1, name='p2')
                    relu2 = tf.nn.relu(pool2, name='relu2')
                    conv3 = tf.layers.conv2d(relu2, 32, 5, name='c3')
                    pool3 = tf.layers.max_pooling2d(conv3, 5, 1, name='p3')
                    relu3 = tf.nn.relu(pool3, name='relu3')
                    conv4 = tf.layers.conv2d(relu3, 32, 5, name='c4')
                    pool4 = tf.layers.max_pooling2d(conv4, 5, 1, name='p4')
                    relu4 = tf.nn.relu(pool4, name='relu4')
                    inputs = tf.layers.flatten(relu4, name='p3')
                    '''
            else:
                inputs = tf.concat(inputs, 1)
            with tf.variable_scope('actor'):
                l_a = tf.layers.dense(inputs, 100, tf.nn.relu6, kernel_initializer=w_init, name='la')
                self.l_a = l_a
                a_prob = tf.layers.dense(l_a, N_A, tf.nn.softmax, kernel_initializer=w_init, name='ap')
            with tf.variable_scope('critic'):
                l_c = tf.layers.dense(inputs, 100, tf.nn.relu6, kernel_initializer=w_init, name='lc')
                self.l_c = l_c
                v = tf.layers.dense(l_c, 1, kernel_initializer=w_init, name='v')  # state value
        a_params = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, scope=scope + '/actor')
        c_params = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, scope=scope + '/critic')
        if self.image_shape is not None:
            i_params = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, scope=scope + '/conv_inputs')
            a_params += i_params
            c_params += i_params
        return a_prob, v, a_params, c_params

    def get_stats(self, feed_dict):
        return SESS.run([self.a_loss, self.c_loss, self.t_td, self.c_loss, self.t_log_prob, self.t_exp_v, self.t_entropy, self.t_exp_v2, self.a_loss, self.a_grads, self.c_grads], feed_dict)

    def update_global(self, feed_dict):  # run by a local
        a_loss, c_loss, entropy, _, _ = SESS.run([self.c_loss, self.a_loss, self.t_exp_v, self.update_a_op, self.update_c_op], feed_dict)  # local grads applies to global net
        return a_loss, c_loss, entropy[0, 0]

    def pull_global(self):  # run by a local
        SESS.run([self.pull_a_params_op, self.pull_c_params_op])

    def choose_action(self, s):  # run by a local
        if type(s) is not list:
            import ipdb; ipdb.set_trace()
        temp = [obs[np.newaxis, :] for obs in s ]
        feed_dict = {var: obs for var, obs in zip(self.s, temp)}
        prob_weights = SESS.run(self.a_prob, feed_dict=feed_dict)
        action = np.random.choice(range(prob_weights.shape[1]),
                                  p=prob_weights.ravel())  # select action w.r.t the actions prob
        return action

class Worker(object):
    def __init__(self, name, globalAC, hard_share=None, soft_sharing_coeff_actor=0.0, soft_sharing_coeff_critic=0.0, gradient_clip_actor=0.0, gradient_clip_critic=0.0, debug=False, max_ep_steps=200, image_shape=None, stack=1):
        self.env = gym.make(GAME).unwrapped
        self.env = TimeLimit(self.env, max_episode_steps=max_ep_steps)
        self.name = name
        self.AC = ACNet(name, globalAC, hard_share=hard_share, soft_sharing_coeff_actor=soft_sharing_coeff_actor, soft_sharing_coeff_critic=soft_sharing_coeff_critic, gradient_clip_actor=gradient_clip_actor, gradient_clip_critic=gradient_clip_critic, image_shape=image_shape, stack=stack)
        self.debug = debug
        self.image_shape = image_shape
        self.stack = stack

    def work(self):
        def get_img(fn, *args):
            img_lock.acquire()
            results = fn(*args)
            img = self.env.render(mode='rgb_array')
            img_lock.release()
            img = rgb2grey(img)
            img = resize(img, self.image_shape)
            return img, results

        def env_reset_obs():
            return self.env.reset()

        def env_reset_img():
            img, _ = get_img(env_reset_obs)
            return img

        def env_step_obs(a):
            return self.env.step(a)

        def env_step_img(a):
            img, results = get_img(env_step_obs, a)
            return img, results[1], results[2], results[3]

        if self.image_shape is not None:
            env_reset_fn = env_reset_img
            env_step_fn = env_step_img
        else:
            env_reset_fn = env_reset_obs
            env_step_fn = env_step_obs

        global GLOBAL_RUNNING_R, GLOBAL_R, GLOBAL_EP, MAX_GLOBAL_EP
        total_step = 1
        buffer_s, buffer_a, buffer_r = [], [], []
        while not COORD.should_stop() and GLOBAL_EP < MAX_GLOBAL_EP:
            s = env_reset_fn()
            buffer_s = [s]*self.stack
            ep_r = 0
            while True:
                a = self.AC.choose_action(buffer_s[-self.stack:])
                s_, r, done, info = env_step_fn(a)
                if done: r = -5
                ep_r += r
                buffer_s.append(s)
                buffer_a.append(a)
                buffer_r.append(r)

                if total_step % UPDATE_GLOBAL_ITER == 0 or done:   # update global and assign to local net

                    if done:
                        v_s_ = 0   # terminal
                    else:
                        obs_hist = buffer_s[-(self.stack-1):] + [s_,]
                        feed_dict = {var: obs[np.newaxis, :] for var, obs in zip(self.AC.s, obs_hist)}
                        v_s_ = SESS.run(self.AC.v, feed_dict=feed_dict)[0, 0]

                    buffer_v_target = []
                    for r in buffer_r[::-1]:    # reverse buffer r
                        v_s_ = r + GAMMA * v_s_
                        buffer_v_target.append(v_s_)
                    buffer_v_target.reverse()

                    if self.image_shape is not None:
                        buffer_s_ = [buffer_s_[np.newaxis, :] for buffer_s_ in buffer_s]
                    else:
                        buffer_s_ = copy.deepcopy(buffer_s)
                    obs_columns = [np.vstack(buffer_s_[idx:-(self.stack-idx)]) for idx in range(self.stack)]
                    buffer_a, buffer_v_target = np.array(buffer_a), np.vstack(buffer_v_target)
                    feed_dict = {var: obs for var, obs in zip(self.AC.s, obs_columns)}
                    feed_dict[self.AC.a_his] = buffer_a
                    feed_dict[self.AC.v_target] = buffer_v_target
                    if self.debug and self.name == 'W_0':
                        a_loss, c_loss, t_td, c_loss, t_log_prob, t_exp_v, t_entropy, t_exp_v2, a_loss, a_grads, c_grads = self.AC.get_stats(feed_dict)
                        #print("a_loss: ", a_loss.shape, " ", a_loss, "\tc_loss: ", c_loss.shape, " ", c_loss, "\ttd: ", t_td.shape, " ", t_td, "\tlog_prob: ", t_log_prob.shape, " ", t_log_prob, "\texp_v: ", t_exp_v.shape, " ", t_exp_v, "\tentropy: ", t_entropy.shape, " ", t_entropy, "\texp_v2: ", t_exp_v2.shape, " ", t_exp_v2, "\ta_grads: ", [np.sum(weights) for weights in a_grads], "\tc_grads: ", [np.sum(weights) for weights in c_grads])
                        print("a_loss: ", a_loss.shape, " ", a_loss, "\tc_loss: ", c_loss)
                    c_loss, a_loss, entropy = self.AC.update_global(feed_dict)

                    #import ipdb; ipdb.set_trace()
                    buffer_s, buffer_a, buffer_r = buffer_s[-(self.stack):], [], []
                    self.AC.pull_global()

                s = s_
                total_step += 1
                if done:
                    GLOBAL_R.append(ep_r)
                    if len(GLOBAL_RUNNING_R) == 0:  # record running episode reward
                        GLOBAL_RUNNING_R.append(ep_r)
                    else:
                        GLOBAL_RUNNING_R.append(0.99 * GLOBAL_RUNNING_R[-1] + 0.01 * ep_r)

                    log_lock.acquire()
                    logger.record_tabular("global_ep", GLOBAL_EP)
                    logger.record_tabular("name", self.name)
                    logger.record_tabular("ep_r", ep_r)
                    logger.record_tabular("ep_r_weighted", GLOBAL_RUNNING_R[-1])
                    logger.record_tabular("c_loss", c_loss)
                    logger.record_tabular("a_loss", a_loss)
                    logger.record_tabular("entropy", entropy)
                    logger.dump_tabular()
                    log_lock.release()

                    GLOBAL_EP += 1
                    break

def parse_args():
    global MAX_GLOBAL_EP

    parser = argparse.ArgumentParser(description='Run A3C on discrete cart-pole.')
    parser.add_argument('--hard_share', type=str, default='none', help="Indicates whether the models should have an equal number of parameters ('equal_params'), an equal number of hidden units ('equal_hiddens'), or no sharing ('none' -- default).")
    parser.add_argument('--soft_share', type=float, default=0.0, help='Enables soft sharing of both actor and critic parameters, via L2 loss, with the specificied weight.')
    parser.add_argument('--soft_share_actor', type=float, default=0.0, help='Enables soft sharing of actor parameters, via L2 loss, with the specificied weight.')
    parser.add_argument('--soft_share_critic', type=float, default=0.0, help='Enables soft sharing of critic parameters, via L2 loss, with the specificied weight.')
    parser.add_argument('--gradient_clip', type=float, default=0.0, help='Enables gradient clipping of actor and critic parameters with the specificied maximum gradient.')
    parser.add_argument('--gradient_clip_actor', type=float, default=0.0, help='Enables gradient clipping of actor parameters with the specificied maximum gradient.')
    parser.add_argument('--gradient_clip_critic', type=float, default=0.0, help='Enables gradient clipping of critic parameters with the specificied maximum gradient.')
    parser.add_argument('--debug', default=False, action='store_true', help='Enables debugging output.')
    parser.add_argument('--optimizer', default='adagrad', help='Which optimizer to use: rmsprop, adam, adagrad.')
    parser.add_argument('--lr', type=float, default=0.0, help='Sets the learning rate of the actor and critic.')
    parser.add_argument('--lr_a', type=float, default=0.001, help='Sets the learning rate of the actor.')
    parser.add_argument('--lr_c', type=float, default=0.001, help='Sets the learning rate of the critic.')
    parser.add_argument('--max_global_ep', type=int, default=500, help='Sets the maximum number of episodes to be executed across all threads.')
    parser.add_argument('--log', default=False, action='store_true', help='Enables logging.')
    parser.add_argument('--max_ep_steps', type=int, default=2000, help='The number of time steps per episode before calling the episode done.')
    parser.add_argument('--stack', type=int, default=1, help='Number of observations to use for state.')
    parser.add_argument('--image_shape', nargs='*', default=None, help='Designates that images shoud be used in lieu of observations and what shpae to use for them.')
    parser.add_argument('--debug_worker', default=False, action='store_true')
    args = parser.parse_args()

    if args.hard_share not in ['equal_params', 'equal_hiddens', 'none']:
        raise ValueError("Hard sharing options are 'equal_params' and 'equal_hiddens'.")

    if args.hard_share == 'none':
        args.hard_share = None

    soft_share_actor = args.soft_share_actor
    soft_share_critic = args.soft_share_critic
    if args.soft_share > 0:
        soft_share_actor = args.soft_share
        soft_share_critic = args.soft_share

    gradient_clip_actor = args.gradient_clip_actor
    gradient_clip_critic = args.gradient_clip_critic
    if args.gradient_clip > 0:
        gradient_clip_actor = args.gradient_clip
        gradient_clip_critic = args.gradient_clip

    lr_a = args.lr_a
    lr_c = args.lr_c
    if args.lr > 0:
        lr_a = args.lr
        lr_c = args.lr

    MAX_GLOBAL_EP = args.max_global_ep

    if args.log:
        logger.configure('tmp')
        print("logger dir: ", logger.get_dir())

    if args.debug:
        logger.set_level(logger.DEBUG)

    if args.optimizer == 'rmsprop':
        optimizer_class = tf.train.RMSPropOptimizer
    elif args.optimizer == 'adam':
        optimizer_class = tf.train.AdamOptimizer
    elif args.optimizer == 'adagrad':
        optimizer_class = tf.train.AdagradOptimizer

    if args.stack < 1:
        raise ValueError('Number of frames ({}) to stack must be positive.'.format(args.stack))

    image_shape = None
    if args.image_shape is not None:
        image_shape = tuple(map(int, args.image_shape[0].split(','))) + (1,) # Add the number of channels which will always be 1 for grey scale
        if args.stack < 2:
            args.stack = 2 # Automatically incorporate diffs with previous images

    print("hard_share: ", args.hard_share)
    print("soft_share_actor: ", soft_share_actor)
    print("soft_share_critic: ", soft_share_critic)
    print("gradient_clip_actor: ", gradient_clip_actor)
    print("gradient_clip_critic: ", gradient_clip_critic)
    print("learning rate, actor: ", lr_a)
    print("learning rate, critic: ", lr_c)
    print("max_global_ep: ", MAX_GLOBAL_EP)
    print("optimizer_class: ", optimizer_class)
    print("max_ep_steps: ", args.max_ep_steps)
    print("image_shape: ", image_shape)

    return args, soft_share_actor, soft_share_critic, gradient_clip_actor, gradient_clip_critic, lr_a, lr_c, optimizer_class, image_shape

if __name__ == "__main__":
    args, soft_share_actor, soft_share_critic,  gradient_clip_actor, gradient_clip_critic, lr_a, lr_c, optimizer_class, image_shape = parse_args()
    SESS = tf.Session()

    with tf.device("/cpu:0"):
        OPT_A = optimizer_class(lr_a, name='actor_opt')
        OPT_C = optimizer_class(lr_c, name='critic_opt')
        GLOBAL_AC = ACNet(GLOBAL_NET_SCOPE, hard_share=args.hard_share, image_shape=image_shape, stack=args.stack)  # we only need its params
        workers = []
        # Create worker
        for i in range(N_WORKERS):
            i_name = 'W_%i' % i   # worker name
            workers.append(Worker(i_name, GLOBAL_AC, hard_share=args.hard_share, soft_sharing_coeff_actor=soft_share_actor, soft_sharing_coeff_critic=soft_share_critic, gradient_clip_actor=gradient_clip_actor, gradient_clip_critic=gradient_clip_critic, debug=args.debug, max_ep_steps=args.max_ep_steps, image_shape=image_shape, stack=args.stack))

    COORD = tf.train.Coordinator()
    SESS.run(tf.global_variables_initializer())

    if OUTPUT_GRAPH:
        if os.path.exists(LOG_DIR):
            shutil.rmtree(LOG_DIR)
        tf.summary.FileWriter(LOG_DIR, SESS.graph)

    if args.debug_worker:
        workers[0].work()
        sys.exit()

    worker_threads = []
    for worker in workers:
        job = lambda: worker.work()
        t = threading.Thread(target=job)
        t.start()
        worker_threads.append(t)
    COORD.join(worker_threads)

    plt.subplot(2, 1, 1)
    plt.plot(np.arange(len(GLOBAL_RUNNING_R)), GLOBAL_RUNNING_R)
    plt.subplot(2, 1, 2)
    plt.plot(np.arange(len(GLOBAL_R)), GLOBAL_R)
    plt.xlabel('step')
    plt.ylabel('Total moving reward')
    if args.log:
        name = 'plot_'+str(MAX_GLOBAL_EP)+'_sharing_'
        if args.hard_share is not None:
            name += 'hard'
        elif soft_sharing_coeff_actor > 0. or soft_sharing_coeff_critic > 0.:
            name += 'soft'
        else:
            name += 'none'
        name += '_lra_'+str(lr_a)+'_lrc_'+str(lr_c)+'.png'
        plt.savefig()
    else:
        plt.show()

        env = gym.make(GAME).unwrapped
        env = TimeLimit(env, max_episode_steps=args.max_ep_steps)
        s = env.reset()
        buffer_s = [s]*args.stack
        tidx = 0
        done = False
        while tidx < 1000 and not done:
            a = workers[0].AC.choose_action(buffer_s[-args.stack:])
            env.render()
            s_, r, done, info = env.step(a)
            s = s_
            buffer_s.append(s)
            tidx += 1


"""
Code Challenge
  Name:
    Centered Average
  Filename:
    centered.py
  Problem Statement:
    Return the "centered" average of an array of integers, which we'll say is
    the mean average of the values, except ignoring the largest and
    smallest values in the array.
    If there are multiple copies of the smallest value, ignore just one copy,
    and likewise for the largest value.
    Use int division to produce the final average. You may assume that the
    array is length 3 or more.
    Take input from user
  Input:
    1, 2, 3, 4, 100
  Output:
    3
"""
def centered_avg(nums):

   # items = nums
    total =0
    high = max(nums)
    low = min(nums)
    for num in nums:
        total += num
    avg =(total -high-low)/(len(nums)-2)
    return avg

centered =input("\n enter the number " ).split(",")
list1=[]
for item in centered:
    list1.append(int(item))
print(list1)
print(centered_avg(list1))

#while(True):
#
#    centered =input("\n enter the number " )
#    if (centered==""):
#        break
#    centered=int(centered)
#    list1.append(centered)

#print(centered_avg(list1))


# encoding=utf-8
# Author: Yu-Lun Chiang
# Description: Get news

import logging

from bs4 import BeautifulSoup

from .base import BaseMediaNewsCrawler
from ..struct import NewsStruct

logger = logging.getLogger(__name__)

class WantRich(BaseMediaNewsCrawler):
    """Web Crawler for WantRich News"""

    def getInfo(self, link: str) -> NewsStruct:
        return super().getInfo(link)

    @staticmethod
    def _get_content(
        soup: BeautifulSoup,
    ) -> str:

        content_list = soup.find(
            class_="article-body", itemprop="articleBody"
        ).find_all("p")
        content = "\n".join([c.text for c in content_list])
        logger.debug(f"CONTENT:\n {content}")
        return content


# find the impossible ones and minus the counts
# 1 means knocked out while 0 means standing
n = int(input())
pins_num = int(((1 + n) * n) / 2)
pins_condition = pow(2, pins_num)

def binary_convert(i):  # covert to a binary number of base conditions
    # e.g. n = 4, 3 => 0000000011
    bi = ''
    while i > 0:
        bi = str(i % 2) + bi
        i = int(i / 2)
    if len(bi) < pins_num:
        for t in range(0, pins_num - len(bi)):
            bi = '0' + bi
    return bi

def which_line(i):  # get the line where the pin, input the index
    if i < 2:
        return 1
    elif i < 4:
        return 2
    elif i < 7:
        return 3
    elif i < 11:
        return 4
    elif i < 16:
        return 5
    elif i < 22:
        return 6
    elif i < 29:
        return 7
    elif i < 37:
        return 8
    elif i < 46:
        return 9
    elif i < 56:
        return 10
    elif i < 67:
        return 11
    elif i < 79:
        return 12
    elif i < 92:
        return 13
    elif i < 106:
        return 14
    elif i < 121:
        return 15
    elif i < 137:
        return 16
    elif i < 154:
        return 17
    elif i < 172:
        return 18
    elif i < 191:
        return 19
    else:
        return 20

def edge(i):  # weather left or right edge of each line
    # 0->no -1->left 1->right
    left = (2, 4, 7, 11, 16, 22, 29, 37,
            46, 56, 67, 79, 92, 106, 121,
            137, 154, 172, 191)
    right = (3, 6, 10, 15, 21, 28, 36,
             45, 55, 66, 78, 91, 105,
             120, 136, 153, 171, 190, 210)
    if i in left:
        return -1
    elif i in right:
        return 1
    else:
        return 0

def judge(h, temp, minus):  # input the index, binary condition and line
    if temp[h - minus] == '0':
        return False
    return True

def run():
    failures = 0
    for c in range(0, pins_condition):
        temp = binary_convert(c)  # binary condition
        h = pins_num - 1  # h is the index
        bo = True  # if impossible, false
        while h > 0:
            line = which_line(h + 1)
            if temp[h] == '1':
                if edge(h + 1) == -1:
                    bo = judge(h, temp, line - 1)
                if edge(h + 1) == 0:
                    bo1 = judge(h, temp, line - 1)
                    bo2 = judge(h, temp, line)
                    if bo1 or bo2:
                        bo = True
                    else:
                        bo = False
                if edge(h + 1) == 1:
                    bo = judge(h, temp, line)
                if bo:
                    pass
                else:
                    failures += 1
            else:
                pass
            h -= 1
    return failures

print(pins_condition - run())


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

"""
Data structure for implementing experience replay, episode level
"""
from collections import deque
import random
import numpy as np
from ..Policy import TerminalAction, TerminalState
import replay_abc

class ReplayBufferEpisode(replay_abc.ReplayABC):

    def __init__(self, buffer_size, batch_size, random_seed=1234):
        """
        The right side of the deque contains the most recent experiences
        """
        self.buffer_size = buffer_size
        self.batch_size = batch_size
        self.count = 0
        self.buffer = deque()
        self.episode = []
        self.s_prev, self.s_ori_prev, self.a_prev, self.r_prev, self.v_prev, self.distribution_prev = None, None, None, None, None, None

        random.seed(random_seed)

    def record(self, state, state_ori, action, reward, value, distribution, terminal=False):
        """
        Record the experience:
            Turn #  User: state         System: action                  got reward
            Turn 1  User: Cheap         System: location?               -1
            Turn 2  User: North         System: inform(cheap, north)    -1
            Turn 3  User: Bye           System: inform(XXX) --> bye     -1
            Turn 4  User: Terminal_s    System: terminal_a              20

        As:
            Experience 1: (Cheap, location?, -1, North)
            Experience 2: (North, inform(cheap, north), -1+20, Bye)
        """

        if self.s_prev == None and self.s_ori_prev == None and self.a_prev == None and self.r_prev == None and self.distribution_prev == None:
            self.s_prev, self.s_ori_prev, self.a_prev, self.r_prev, self.v_prev, self.distribution_prev = \
                    state, state_ori, action, reward, value.tolist(), distribution
            return
        else:
            if terminal == True:
                try:
                    #- 1  # add dialogue succes reward to last added experience , -1 for goodbye turn
                    self.episode[-1][3] += reward

                    # change this experience to terminal
                    self.episode[-1][-2] = terminal

                    # add episodic experience to buffer
                    if self.count < self.buffer_size:
                        self.buffer.append(self.episode)
                        self.count += 1
                    else:
                        self.buffer.popleft()
                        self.buffer.append(self.episode)

                    self.s_prev, self.s_ori_prev, self.a_prev, self.r_prev, self.v_prev, self.distribution_prev = None, None, None, None, None, None
                    self.episode = []
                except:
                    self.episode = []
            else: # not terminal state
                self.episode.append(\
                    [self.s_prev, self.s_ori_prev, self.a_prev, self.r_prev, self.v_prev, state, state_ori, terminal, self.distribution_prev]\
                )
                self.s_prev, self.s_ori_prev, self.a_prev, self.r_prev, self.v_prev, self.distribution_prev = state, state_ori, action, reward, value, distribution
    def size(self):
        return self.count

    def sample_batch(self):
        batch = []

        if self.count < self.batch_size:
            batch = random.sample(self.buffer, self.count)
        else:
            batch = random.sample(self.buffer, self.batch_size)

        batch = np.array(batch)

        s_batch         = []
        s_ori_batch     = []
        a_batch         = []
        r_batch         = []
        s2_batch        = []
        s2_ori_batch    = []
        v_batch         = []
        t_batch         = []
        mu_batch        = []
        for epi in batch:
            tmp_s, tmp_s_ori, tmp_a, tmp_r, tmp_v, tmp_s2, tmp_s2_ori, tmp_t, tmp_mu = \
                [], [], [], [], [], [], [], [], []
            for exp in epi:
                tmp_s.append(exp[0])
                tmp_s_ori.append(exp[1])
                tmp_a.append(exp[2])
                tmp_r.append(exp[3])
                tmp_s2.append(exp[4])
                tmp_s2_ori.append(exp[5])
                tmp_v.append(exp[6])
                tmp_t.append(exp[7])
                tmp_mu.append(exp[8])

            s_batch.append(tmp_s)
            s_ori_batch.append(tmp_s_ori)
            a_batch.append(tmp_a)
            r_batch.append(tmp_r)
            s2_batch.append(tmp_s2)
            s2_ori_batch.append(tmp_s2_ori)
            v_batch.append(tmp_v)
            t_batch.append(tmp_t)
            mu_batch.append(tmp_mu)

        """
        s_batch         = batch[:,:,0]
        s_ori_batch     = batch[:,:,1]
        a_batch         = batch[:,:,2]
        r_batch         = batch[:,:,3]
        s2_batch        = batch[:,:,4]
        s2_ori_batch    = batch[:,:,5]
        v_batch         = batch[:,:,6]
        t_batch         = batch[:,:,7]
        """

        return s_batch, s_ori_batch, a_batch, r_batch, s2_batch, s2_ori_batch, t_batch, None, v_batch, mu_batch

    """
    def sample_batch_vanilla_PER(self):
        ########
        # pick the samples for experience replay
        # based on prioritised sampling and random selection
        ########

        batch = random.sample(self.buffer, len(self.buffer))

        # determine pos and neg indices
        pos = []
        neg = []
        for r in range(len(batch)):
            if batch[r][2] > 0:
                #if Settings.random.rand() < self.prior_sample_prob:
                if random.random() < 0.8 and len(pos) < self.batch_size/2:
                    pos.append(batch[r])
            else:
                neg.append(batch[r])

        # first append all pos and then
        # fill up to self.minibatch_size with neg

        ExpRep = []
        ExpRep += pos

        random.shuffle(neg)
        neg = neg[-(self.batch_size-len(pos)):]

        ExpRep += neg

        s_batch         = np.array([_[0] for _ in batch])
        s_ori_batch     = np.array([_[1] for _ in batch])
        a_batch         = np.array([_[2] for _ in batch])
        r_batch         = np.array([_[3] for _ in batch])
        s2_batch        = np.array([_[4] for _ in batch])
        s2_ori_batch    = np.array([_[5] for _ in batch])
        t_batch         = np.array([_[6] for _ in batch])

        return s_batch, s_ori_batch, a_batch, r_batch, s2_batch, s2_ori_batch, t_batch, None, None
    """

    def clear(self):
        self.deque.clear()
        self.count = 0
        self.s_prev, self.s_ori_prev, self.a_prev, self.r_prev, self.v_prev, self.distribution_prev = None, None, None, None, None, None
        self.episode = []


import HW4Game as pro

TAIL_PROBS = 1-0.4 # These are constant, using capital to represent
FILP_TIMES = 20
REPEAT_SIZE = 1000
WIN_MON = 100
START_MON = 250

#mygame = pro.Game(id=1, tail_prob=TAIL_PROBS)
#print (mygame.simulate(n_flip_times=FILP_TIMES, win_mon= WIN_MON, start_mon= START_MON))
#print(mygame.get_reward())

# create a cohort
myRepeatgame= pro.repeatation(repeat_size=REPEAT_SIZE, tail_prob= TAIL_PROBS)
# simulate the patient
myRepeatgame.simulate(n_flip_times=FILP_TIMES, win_mon= WIN_MON, start_mon= START_MON)

# print the patient survival time
print(myRepeatgame.get_ave_reward())


import bisect
n = int(input())
seq = [int(input()) for i in range(n)]

LIS = []
for number in seq:
    index = bisect.bisect_left(LIS, number)
    if index >= len(LIS):
       LIS.append(number)
    else:
        LIS[index] = number
print(len(LIS))


#!/usr/bin/python3
class Square:
    """Creates a square"""
    def __init__(self, size=0, position=(0, 0)):
        """Initializes the size of a square
         Args:
            size (int): The size of the square
            position (tuple(int, int)):
                tuple 1: how many spaces to print before the square
                tuple 2: how many new lines to print before the square
        """
        self.size = size
        self.position = position

    @property
    def size(self):
        """Getter - gets the size of the square
        Returns: The size of the square
        """
        return self.__size

    @size.setter
    def size(self, value):
        """Setter - sets the value of the size of the square
        Args:
            value (int): the size of the square
        """
        if type(value) != int:
            print("size must be an integer", end="")
            raise TypeError
        elif value < 0:
            print("size must be >= 0", end="")
            raise ValueError
        else:
            self.__size = value

    @property
    def position(self):
        """Getter - gets the position
        Returns: the value of the position
        """
        return self.__position

    @position.setter
    def position(self, value):
        """Setter - sets the value of the position
        Args:
            value (int): the position of the square
        """
        if type(value) != tuple or len(value) != 2:
            raise TypeError("position must be a tuple of 2 positive integers")
        elif type(value[0]) != int or type(value[1]) != int:
            raise TypeError("position must be a tuple of 2 positive integers")
        elif value[0] < 0 or value[1] < 0:
            raise TypeError("position must be a tuple of 2 positive integers")
        else:
            self.__position = value

    def area(self):
        """Calculates the area of the square
        Returns: The value of the area
        """
        return self.__size**2

    def my_print(self):
        """Prints out the square with #'s"""
        if self.__size != 0:
            for new_line in range(self.__position[1]):
                print()
            for index in range(self.__size):
                print(" "*self.__position[0], end="")
                print("#"*self.__size)
        else:
            print()

    def __str__(self):
        """ Prints the square when prints is called on this class
        """
        new_str = ""
        if self.__size == 0:
            return new_str
        for new_line in range(self.__position[1]):
            new_str += "\n"
        for index in range(self.__size):
            new_str += " "*self.__position[0]
            new_str += "#"*self.__size
            if index != self.__size - 1:
                new_str += "\n"
        return new_str


import math
import random
import torch
from torch_geometric.utils import to_undirected

def train_test_split_edges(data, val_ratio=0.05, test_ratio=0.1):
    r"""Splits the edges of a :obj:`torch_geometric.data.Data` object
    into positive and negative train/val/test edges, and adds attributes of
    `train_pos_edge_index`, `train_neg_adj_mask`, `val_pos_edge_index`,
    `val_neg_edge_index`, `test_pos_edge_index`, and `test_neg_edge_index`
    to :attr:`data`.

    Args:
        data (Data): The data object.
        val_ratio (float, optional): The ratio of positive validation
            edges. (default: :obj:`0.05`)
        test_ratio (float, optional): The ratio of positive test
            edges. (default: :obj:`0.1`)

    :rtype: :class:`torch_geometric.data.Data`
    """

    assert 'batch' not in data  # No batch-mode.

    row, col = data.edge_index

    # Return upper triangular portion.
    mask = row < col
    row, col = row[mask], col[mask]

    n_v = int(math.floor(val_ratio * row.size(0)))
    n_t = int(math.floor(test_ratio * row.size(0)))

    # Positive edges.
    perm = torch.randperm(row.size(0))
    row, col = row[perm], col[perm]

    r, c = row[:n_v], col[:n_v]
    val_pos_edge_index = torch.stack([r, c], dim=0)
    r, c = row[n_v:n_v + n_t], col[n_v:n_v + n_t]
    test_pos_edge_index = torch.stack([r, c], dim=0)

    r, c = row[n_v + n_t:], col[n_v + n_t:]
    train_pos_edge_index = torch.stack([r, c], dim=0)
    train_pos_edge_index = to_undirected(data.train_pos_edge_index)

    return train_pos_edge_index


import re

from pyramid.httpexceptions import HTTPBadRequest
from pyramid.response import Response
from pyramid.view import view_config

from pyramid_debugtoolbar.panels import DebugPanel
from pyramid_debugtoolbar.utils import escape
from pyramid_debugtoolbar.utils import EXC_ROUTE_NAME
from pyramid_debugtoolbar.utils import STATIC_PATH
from pyramid_debugtoolbar.utils import ROOT_ROUTE_NAME

_ = lambda x: x

class TracebackPanel(DebugPanel):
    name = 'traceback'
    template = 'pyramid_debugtoolbar.panels:templates/traceback.dbtmako'
    title = _('Traceback')
    nav_title = title

    def __init__(self, request):
        self.request = request
        self.traceback = None
        self.exc_history = request.exc_history

    @property
    def has_content(self):
        return self.traceback is not None

    def process_response(self, response):
        self.traceback = traceback = getattr(self.request, 'pdbt_tb', None)
        if self.traceback is not None:
            exc = escape(traceback.exception)
            token = self.request.registry.pdtb_token
            url = '' # self.request.route_url(EXC_ROUTE_NAME, _query=qs)
            evalex = self.exc_history.eval_exc

            self.data = {
                'evalex':           evalex and 'true' or 'false',
                'console':          'false',
                'lodgeit_url':      None,
                'title':            exc,
                'exception':        exc,
                'exception_type':   escape(traceback.exception_type),
                'plaintext':        traceback.plaintext,
                'plaintext_cs':     re.sub('-{2,}', '-', traceback.plaintext),
                'traceback_id':     traceback.id,
                'token':            token,
                'url':              url,
            }

        # stop hanging onto the request after the response is processed
        del self.request

    def render_vars(self, request):
        return {
            'static_path': request.static_url(STATIC_PATH),
            'root_path': request.route_url(ROOT_ROUTE_NAME),

            # render the summary using the toolbar's request object, not
            # the original request that generated the traceback!
            'summary': self.traceback.render_summary(
                include_title=False, request=request),
        }

class ExceptionDebugView(object):
    def __init__(self, request):
        self.request = request
        exc_history = request.exc_history
        if exc_history is None:
            raise HTTPBadRequest('No exception history')
        self.exc_history = exc_history
        token = self.request.params.get('token')
        if not token:
            raise HTTPBadRequest('No token in request')
        if not token == request.registry.parent_registry.pdtb_token:
            raise HTTPBadRequest('Bad token in request')
        self.token = token
        frm = self.request.params.get('frm')
        if frm is not None:
            frm = int(frm)
        self.frame = frm
        cmd = self.request.params.get('cmd')
        self.cmd = cmd
        tb = self.request.params.get('tb')
        if tb is not None:
            tb = int(tb)
        self.tb = tb

    @view_config(route_name='debugtoolbar.exception')
    def exception(self):
        tb = self.exc_history.tracebacks[self.tb]
        body = tb.render_full(self.request).encode('utf-8', 'replace')
        response = Response(body, status=500)
        return response

    @view_config(route_name='debugtoolbar.source')
    def source(self):
        exc_history = self.exc_history
        if self.frame is not None:
            frame = exc_history.frames.get(self.frame)
            if frame is not None:
                return Response(frame.render_source(), content_type='text/html')
        return HTTPBadRequest()

    @view_config(route_name='debugtoolbar.execute')
    def execute(self):
        if self.request.exc_history.eval_exc:
            exc_history = self.exc_history
            if self.frame is not None and self.cmd is not None:
                frame = exc_history.frames.get(self.frame)
                if frame is not None:
                    result = frame.console.eval(self.cmd)
                    return Response(result, content_type='text/html')
        return HTTPBadRequest()

def includeme(config):
    config.add_route(EXC_ROUTE_NAME, '/exception')
    config.add_route('debugtoolbar.source', '/source')
    config.add_route('debugtoolbar.execute', '/execute')

    config.add_debugtoolbar_panel(TracebackPanel)
    config.scan(__name__)


import numpy as np
data = {}
try:
    data = np.load('position2.npz')
except Exception as e:
    import make_data_v1

import keras
from keras.layers.core import *
from keras.layers.convolutional import *
from keras.models import Sequential, load_model
from PIL import Image
from random import randint
from tqdm import *

test_name = 'tester-2'
count = 2000
epoch = 5
rand = randint(0, 2000 - count)
count = rand + count

x_train = []
y_train = []
x_test = []
y_test = []
for i in trange(2000):
    r = randint(0, len(data['data'])-1)
    x_train.append(data['data'][r])
    y_train.append(data['label'][r])
for i in trange(1000):
    r = randint(0, len(data['data'])-1)
    x_test.append(data['data'][r])
    y_test.append(data['label'][r])

x_train = np.array(x_train)
y_train = np.array(y_train)
x_test = np.array(x_test)
y_test = np.array(y_test)
x_train, x_test = x_train / 255.0, x_test / 255.0

x_train = x_train.reshape(x_train.shape[0], 28*2, 28*2, 1)
x_test = x_test.reshape(x_test.shape[0], 28*2, 28*2, 1)

print('data OK.')

window_size = 4
test_size = 12
w2x = 2
input_shape = (int(28 * w2x), int(28 * w2x), 1)
# window_shape = (28*window_size, 28*window_size, 1)
window_shape = input_shape
# 数据处理

try:
    model = load_model('%s.hdf5' % test_name)
except Exception as e:
    model = Sequential()
    model.add(Conv2D(5, kernel_size=(3, 3), strides=(1, 1),
                     activation='relu',
                     input_shape=window_shape,
                     # input_shape=(28, 28, 1),
                     name='C1'))
    model.add(MaxPooling2D(pool_size=(2, 2), strides=(1, 1), name='S1'))
    model.add(Conv2D(7, (3, 3), activation='relu', name='C2'))
    model.add(MaxPooling2D(pool_size=(2, 2), name='S2'))
    model.add(Conv2D(9, (3, 3), activation='relu', name='C3'))
    model.add(MaxPooling2D(pool_size=(2, 2), name='S3'))
    model.add(Flatten())
    model.add(Dense(360, activation='relu'))
    model.add(Dense(2, activation='softmax'))

    model.compile(optimizer='adam',
                  loss='sparse_categorical_crossentropy',
                  metrics=['accuracy'])

model.fit(x_train[rand:count], y_train[rand:count], epochs=epoch)
'''
from tqdm import *

for e in range(epoch):
    print('epoch {0}/{1}'.format(e, epoch))
    t = tqdm(range(rand, count))
    for i in t:
        noi = get_noice(window_shape)
        x = x_train[i].reshape(28, 28)
        img = plus(noi, x * 255).reshape(1, window_shape[0], window_shape[1], 1)
        y = y_train[i].reshape(1, 1)
        r = model.train_on_batch(img, y)
        # r = model.train_on_batch(x.reshape(1, 28, 28, 1), y)
        t.set_description('loss: ' + str(r[0]) + ' acc: ' + str(r[1]))

        im = Image.fromarray(img.reshape(window_shape[0], window_shape[1]))
        ids = ids + 1
        im.save(img_path + str(ids) + '.jpg')
        # print(y_train[i])
        with open(img_path + str(ids) + '.dat', 'w') as f:
            f.write(str(y_train[i]))
        with open(img_path + 'ids.txt', 'w') as f:
            f.write(str(ids))
'''
model.save('%s.hdf5' % test_name)

print(model.evaluate(x_test, y_test))
'''
t = tqdm(range(1000))
for i in t:
    noi = get_noice(window_shape)
    x = x_test[i]
    img = plus(noi, x).reshape(1, window_shape[0], window_shape[1], 1)
    y = y_test[i].reshape(1, 1)
    r = model.test_on_batch(img, y)
    # r = model.test_on_batch(x.reshape(1, 28, 28, 1), y)
    t.set_description('loss: ' + str(r[0]) + ' acc: ' + str(r[1]))
'''
print(model.metrics_names)


import numpy as np

from sklearn.utils.testing import assert_equal
from sklearn.utils.testing import assert_raises

from skopt.benchmarks import bench1
from skopt.learning import ExtraTreesRegressor
from skopt.optimizer import Optimizer
from scipy.optimize import OptimizeResult

def test_multiple_asks():
    # calling ask() multiple times without a tell() inbetween should
    # be a "no op"
    base_estimator = ExtraTreesRegressor(random_state=2)
    opt = Optimizer([(-2.0, 2.0)], base_estimator, n_random_starts=1,
                    acq_optimizer="sampling")

    opt.run(bench1, n_iter=3)
    # tell() computes the next point ready for the next call to ask()
    # hence there are three after three iterations
    assert_equal(len(opt.models), 3)
    assert_equal(len(opt.Xi), 3)
    opt.ask()
    assert_equal(len(opt.models), 3)
    assert_equal(len(opt.Xi), 3)
    assert_equal(opt.ask(), opt.ask())

def test_invalid_tell_arguments():
    base_estimator = ExtraTreesRegressor(random_state=2)
    opt = Optimizer([(-2.0, 2.0)], base_estimator, n_random_starts=1)

    # can't have single point and multiple values for y
    assert_raises(ValueError, opt.tell, [1.], [1., 1.])

def test_bounds_checking_1D():
    low = -2.
    high = 2.
    base_estimator = ExtraTreesRegressor(random_state=2)
    opt = Optimizer([(low, high)], base_estimator, n_random_starts=1,
                    acq_optimizer="sampling")

    assert_raises(ValueError, opt.tell, [high + 0.5], 2.)
    assert_raises(ValueError, opt.tell, [low - 0.5], 2.)
    # feed two points to tell() at once
    assert_raises(ValueError, opt.tell, [high + 0.5, high], (2., 3.))
    assert_raises(ValueError, opt.tell, [low - 0.5, high], (2., 3.))

def test_bounds_checking_2D():
    low = -2.
    high = 2.
    base_estimator = ExtraTreesRegressor(random_state=2)
    opt = Optimizer([(low, high), (low+4, high+4)], base_estimator,
                    n_random_starts=1, acq_optimizer="sampling")

    assert_raises(ValueError, opt.tell, [high + 0.5, high + 4.5], 2.)
    assert_raises(ValueError, opt.tell, [low - 0.5, low - 4.5], 2.)

    # first out, second in
    assert_raises(ValueError, opt.tell, [high + 0.5, high + 0.5], 2.)
    assert_raises(ValueError, opt.tell, [low - 0.5, high + 0.5], 2.)

def test_bounds_checking_2D_multiple_points():
    low = -2.
    high = 2.
    base_estimator = ExtraTreesRegressor(random_state=2)
    opt = Optimizer([(low, high), (low+4, high+4)], base_estimator,
                    n_random_starts=1, acq_optimizer="sampling")

    # first component out, second in
    assert_raises(ValueError, opt.tell,
                  [(high + 0.5, high + 0.5), (high + 0.5, high + 0.5)],
                  [2., 3.])
    assert_raises(ValueError, opt.tell,
                  [(low - 0.5, high + 0.5), (low - 0.5, high + 0.5)],
                  [2., 3.])

def test_returns_result_object():
    base_estimator = ExtraTreesRegressor(random_state=2)
    opt = Optimizer([(-2.0, 2.0)], base_estimator, n_random_starts=1,
                    acq_optimizer="sampling")
    result = opt.tell([1.5], 2.)

    assert isinstance(result, OptimizeResult)
    assert_equal(len(result.x_iters), len(result.func_vals))
    assert_equal(np.min(result.func_vals), result.fun)


import sqlite3
import configparser
import os
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
import datetime
import time
from flask import g

ini_path='absgate.ini'

if not os.path.exists(ini_path):
    print("[ERROR] No ini files found")
    exit()
else:
    config = configparser.ConfigParser()
    config.read(ini_path)
    # Читаем значения из конфиг. файла.
    api_secret_key = config.get("API", "secret_key")
    api_db_file = config.get("API DB", "db_file")

EXPIRES_IN_A_YEAR = 365 * 24 * 60 * 60
ts = Serializer(api_secret_key, expires_in = EXPIRES_IN_A_YEAR)

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

def check_key(key):
    g.user = None

    try:
        data = ts.loads(key)
    except:
        return False

    if 'username' in data:
        g.user = data['username']
        g.token = key
        return True

    return False

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

def chek_priv(key, priv):
    g_user_name = g.user
    allow_priv = 0

    try:
        data = ts.loads(key)
    except:
        return False

    if 'username' in data:
        k_user_name = data['username']
    else:
        k_user_name = 'FALUE'

    if g_user_name != k_user_name:
        return False

    if priv in data:
        allow_priv = data[priv]

    if allow_priv == 1:
        return True

    return False


import os
from flask import Flask, jsonify, make_response, render_template, request
from werkzeug.utils import secure_filename

UPLOAD_FOLDER = '/root/law-lab0404/'

app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER

@app.route('/', methods=['GET', 'POST'])
def upload():
    if request.method == 'GET':
        resp = make_response(render_template('upload.html'), 200)
        return resp
    elif request.method == 'POST':
        file = request.files['file']
        if file:
            filename = secure_filename(file.filename)
            file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
        return make_response(jsonify({'state': 'done'}), 200)

if __name__ == '__main__':
    app.run()