#!/usr/bin/env python

import os
import sys
import re
import argparse
import random
from collections import Counter

import matplotlib as mpl
mpl.use( "Agg" )
mpl.rcParams["pdf.fonttype"] = 42
mpl.rcParams["font.sans-serif"] = "Arial"
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import pylab
import numpy as np
from scipy.stats import rankdata
import scipy.cluster.hierarchy as sch

from zopy.table2 import table
from zopy.utils import die, warn, path2name
import zopy.mplutils2 as mu
from zopy.dictation import col2dict, col2dict2

#-------------------------------------------------------------------------------
# constants
#-------------------------------------------------------------------------------

c_max_lab     = 50
c_metacmap    = "Dark2"
c_font1       = 7
c_font2       = 8
c_font3       = 10
c_eps         = 1e-20
c_str_other   = "Other"
c_str_none    = "None"
c_other_color = "0.75"
c_none_color  = "white"

sys.setrecursionlimit( 10000 )

#-------------------------------------------------------------------------------
# cli
#-------------------------------------------------------------------------------

def get_args( ):
    parser = argparse.ArgumentParser( )
    parser.add_argument( "table", help="" )
    parser.add_argument( "--lastcol",
                         help="" )
    parser.add_argument( "--lastrow",
                         help="" )
    parser.add_argument( "--colmeta",
                         nargs="+",
                         help="" )
    parser.add_argument( "--colmeta-colors",
                         nargs="+",
                         help="" )
    parser.add_argument( "--rowmeta",
                         nargs="+",
                         help="" )
    parser.add_argument( "--rowmeta-colors",
                         nargs="+",
                         help="" )
    parser.add_argument( "--max-levels",
                         type=int,
                         help="" )
    parser.add_argument( "--colsort",
                         default=["none"],
                         nargs="+",
                         help="" )
    parser.add_argument( "--rowsort",
                         default=["none"],
                         nargs="+",
                         help="" )
    parser.add_argument( "--dump-colsort-order",
                         action="store_true",
                         help="" )
    parser.add_argument( "--dump-rowsort-order",
                         action="store_true",
                         help="" )
    parser.add_argument( "--cmap",
                         default="inferno",
                         help="" )
    parser.add_argument( "--transform",
                         choices=["none", "sqrt", "log2", "log10"],
                         default="none",
                         help="" )
    parser.add_argument( "--limits",
                         nargs="+",
                         type=float,
                         help="" )
    parser.add_argument( "--units",
                         default="units",
                         help="" )
    parser.add_argument( "--rowlabel",
                         default="rows",
                         help="")
    parser.add_argument( "--collabel",
                         default="cols",
                         help="" )
    parser.add_argument( "--override-rownames",
                         default=None,
                         help="")
    parser.add_argument( "--override-colnames",
                         default=None,
                         help="" )
    parser.add_argument( "--debug",
                         action="store_true", help="" )
    parser.add_argument( "--hscale",
                         action="store_true",
                         help="" )
    parser.add_argument( "--vscale",
                         action="store_true",
                         help="" )
    parser.add_argument( "--hstretch",
                         type=float,
                         default=1.0,
                         help="" )
    parser.add_argument( "--vstretch",
                         type=float,
                         default=1.0,
                         help="" )
    parser.add_argument( "--legend-scale",
                         type=float,
                         default=1.0,
                         help="" )
    parser.add_argument( "--metascale",
                         action="store_true",
                         help="" )
    parser.add_argument( "--grid",
                         default="", # x y or xy
                         help="")
    parser.add_argument( "--rowbreaks",
                         help="")
    parser.add_argument( "--colbreaks",
                         help="" )
    parser.add_argument( "--break-color",
                         default="white",
                         help="" )
    parser.add_argument( "--linkage",
                         default="average",
                         help="" )
    parser.add_argument( "--engine",
                         choices=["imshow", "pcolormesh", "pcolorfast"],
                         default="imshow",
                         help="" )
    parser.add_argument( "--output",
                         default="heatmap.pdf",
                         help="" )
    parser.add_argument( "--overrides",
                         nargs="+",
                         default=[],
                         help="" )
    parser.add_argument( "--eps-noise",
                         action="store_true",
                         help="" )
    parser.add_argument( "--cbar-extent",
                         default=0.5,
                         type=float,
                         help="" )
    parser.add_argument( "--grid-inches",
                         default=0.25,
                         type=float,
                         help="" )
    parser.add_argument( "--title",
                         help="" )
    parser.add_argument( "--force-labels",
                         action="store_true",
                         help="" )
    parser.add_argument( "--dots",
                         default=None,
                         nargs="+",
                         help="" )
    args = parser.parse_args( )
    return args

#-------------------------------------------------------------------------------
# custom cmap
#-------------------------------------------------------------------------------

bbcry = {
    'red':
    ( (0.0, 0.0, 0.0),
      (0.25, 0.0, 0.0),
      (0.50, 0.0, 0.0),
      (0.75, 1.0, 1.0),
      (1.0, 1.0, 1.0) ),
    'green':
    ( (0.0, 0.0, 0.0),
      (0.25, 0.0, 0.0),
      (0.50, 1.0, 1.0),
      (0.75, 0.0, 0.0),
      (1.0, 1.0, 1.0) ),
    'blue':
    ( (0.0, 0.0, 0.0),
      (0.25, 1.0, 1.0),
      (0.50, 1.0, 1.0),
      (0.75, 0.0, 0.0),
      (1.0, 0.0, 1.0) ),
}
bbcry = mpl.colors.LinearSegmentedColormap( "bbcry", bbcry, 256 )
pylab.register_cmap( name="bbcry", cmap=bbcry )

#-------------------------------------------------------------------------------
# utility functions
#-------------------------------------------------------------------------------

def subseq( seq, index ):
    """numpy-style slicing and indexing for lists"""
    return [seq[i] for i in index]

def metacolors( values, cmap ):
    found_other = False
    found_none = False
    unique = set( values )
    if c_str_other in unique:
        found_other = True
        unique -= {c_str_other}
    if c_str_none in unique:
        found_none = True
        unique -= {c_str_none}
    if os.path.exists( cmap ):
        cmap = col2dict( cmap, value=1 )
        for k in unique:
            if k not in cmap:
                cmap[k] = c_none_color
        cmap = {l:c for l, c in cmap.items( ) if l in unique}
    else:
        ncol = mu.ncolors( len( unique ), cmap )
        cmap = {}
        for k, c in zip( sorted( unique ), ncol ):
            cmap[k] = c
    if found_other:
        cmap[c_str_other] = c_other_color
    if found_none:
        cmap[c_str_none] = c_none_color
    return cmap

def set_cbar_ticks( ax, lims, poormin=False, poormax=False ):
    vmin, vmax = lims
    tot = vmax - vmin
    scale = 10 ** np.floor( np.log10( tot / 2.0 ) )
    if tot / scale < 5:
        scale /= 2
    if tot / scale > 12:
        scale /= 0.5
    start = scale * int( vmin / scale )
    ticks = []
    ticklabels = []
    precision = 0
    if scale < 1:
        precision = len( str( scale ).split( "." )[1] )
    while start <= vmax:
        ticks.append( (start - vmin) / tot )
        ticklabels.append( round( start, precision ) )
        start += scale
    # sometimes first tick is 0, then 1 or 10, etc.
    """
    if abs( ticklabels[1] ) > 1:
        ticklabels = map( int, ticklabels )
    """
    ticklabels = map( str, ticklabels )
    # indicate cbar min encapsulates <=
    if poormin:
        ticklabels[0] = u"\u2264" + ticklabels[0]
    # indicate cbar max encapsulates >=
    if poormax:
        ticklabels[-1] = u"\u2265" + ticklabels[-1]
    ax.yaxis.set_ticks( ticks )
    ax.yaxis.set_ticklabels( ticklabels )
    # avoids weirdness where colors don't extend to bottom of axis
    ax.set_ylim( 0, 1 )
    mu.resize_yticklabels( ax, c_font2 )

def acheck( array, func ):
    n = 0
    d = 0
    for row in array:
        for x in row:
            d += 1
            if func( x ):
                n += 1
    return n, (n / float( d ))

def file_order( path ):
    warn( "reading header order from", path )
    order = {}
    counter = 0
    with open( path ) as fh:
        for line in fh:
            line = line.strip( )
            order[line] = counter
            counter += 1
    return order

def relevel( levels, max_levels=None ):
    counts = Counter( levels )
    counts = sorted( counts, key=lambda x: -counts[x] )
    if max_levels is None or len( counts ) <= max_levels:
        return levels
    else:
        counts = {k for k in counts[0:max_levels]}
        levels = [l if l in counts else c_str_other for l in levels]
        return levels

def add_dots( axes, df, path ):
    rowmap = {r:i for i, r in enumerate( df.row )}
    colmap = {c:i for i, c in enumerate( df.col )}
    kwargs = {"color":"black", "edgecolor":"none", "s":7}
    with open( path ) as fh:
        for line in fh:
            items = line.strip( ).split( "\t" )
            if items[0] == "#kwargs":
                for item in items[1:]:
                    k, v = item.split( ":" )
                    kwargs[k] = v
            else:
                r, c = items
                if r in rowmap and c in colmap:
                    r = rowmap[r] + 0.5
                    c = colmap[c] + 0.5
                    axes.heatmap.scatter( c, r, **kwargs )
    return [path, kwargs]

#-------------------------------------------------------------------------------
# utility classes
#-------------------------------------------------------------------------------

class Dimensions:

    def __init__( self, scale=1 ):
        self.scale       = scale
        self.title_r     = scale * 1
        self.coltree_r   = scale * 3
        self.rowtree_c   = scale * 3
        self.colmeta_r   = scale * 1
        self.rowmeta_c   = scale * 1
        self.colnames_r  = scale * 6
        self.rownames_c  = scale * 12
        self.cbar_c      = scale * 8
        self.cbar_c2     = scale * 1
        self.legend_c    = scale * 8
        self.heat_r      = scale * 16
        self.heat_c      = scale * 24
        self.cbar_extent = 0.5
        self.update( )

    def update( self ):
        self.rmargin    = self.title_r + self.coltree_r + self.colmeta_r
        self.cmargin    = self.rowtree_c + self.rowmeta_c + self.cbar_c
        self.rsize      = self.title_r + self.coltree_r + self.colmeta_r + self.heat_r + self.colnames_r
        self.csize      = self.rowtree_c + self.rowmeta_c + self.heat_c + self.rownames_c \
                          + self.cbar_c + self.legend_c

class DataFrame:

    def __init__( self, path,
                  lastcol=None, lastrow=None,
                  colmeta=None, rowmeta=None,
                  eps_noise=False, ):
        self.tbl = table( path )
        self.bak = self.tbl.copy( )
        # strip / save metadata
        if lastrow is not None:
            self.tbl.head( lastrow, invert=True )
        if lastcol is not None:
            self.tbl.head( lastcol, invert=True, transposed=True )
        self.row = self.tbl.rowheads[:]
        self.col = self.tbl.colheads[:]
        if eps_noise:
            self.tbl.float( )
            self.tbl.apply_entries( lambda x: x + c_eps * random.random( ) )
        self.dat = self.tbl.table2array( )
        # colmetas from file / table
        if colmeta is None:
            self.colmeta = None
            self.colmetaname = None
        else:
            self.colmeta = []
            self.colmetaname = []
            for x in colmeta:
                if os.path.exists( x ):
                    warn( "Loading col metadata from file:", x )
                    temp = col2dict( x, value=1 )
                    self.colmeta.append( [temp.get( k, c_str_none ) for k in self.col] )
                    self.colmetaname.append( path2name( x ) )
                else:
                    temp = self.bak.rowdict( x )
                    self.colmeta.append( [temp.get( k, c_str_none ) for k in self.col] )
                    self.colmetaname.append( x )
        # rowmetas from file / table
        if rowmeta is None:
            self.rowmeta = None
            self.rowmetaname = None
        else:
            self.rowmeta = []
            self.rowmetaname = []
            for x in rowmeta:
                if os.path.exists( x ):
                    warn( "Loading row metadata from file:", x )
                    temp = col2dict( x, value=1 )
                    self.rowmeta.append( [temp.get( k, c_str_none ) for k in self.row] )
                    self.rowmetaname.append( path2name( x ) )
                else:
                    temp = self.bak.coldict( x )
                    self.rowmeta.append( [temp.get( k, c_str_none ) for k in self.row] )
                    self.rowmetaname.append( x )

    def colsort( self, metric, linkage="average" ):
        Z = None
        if metric == "none":
            order = range( len( self.col ) )
        elif metric == "names":
            order = sorted( range( len( self.col ) ), key=lambda i: self.col[i] )
        elif metric == "mean":
            order = sorted( range( len( self.col ) ), key=lambda i: np.mean( self.dat[:, i] ) )
        elif os.path.exists( metric ):
            d = file_order( metric )
            if len( d ) != len( self.col ):
                warn( "dimension mismatch with order in", metric, len( d ), len( self.col ) )
            order = [0 for k in self.col]
            for i, k in enumerate( self.col ):
                if k in d:
                    order[d[k]] = i
                else:
                    warn( "no position for", k, "in", metric )
        elif "metadata" in metric:
            index = 0 if ":" not in metric else ( int( metric.split( ":" )[1] ) - 1 )
            values = self.colmeta[index]
            order = sorted( range( len( values ) ), key=lambda i: values[i] )
        # note: linkage assumes things to cluster = rows; we want cols
        elif metric == "spearman":
            temp = [rankdata( col ) for col in self.dat.transpose( )]
            temp = np.array( temp )
            try:
                Z = sch.linkage( temp, method=linkage, metric="correlation" )
                order = sch.leaves_list( Z )
            except:
                warn( "Spearman clustering failed" )
                Z = None
                order = range( len( self.col ) )
        else:
            Z = sch.linkage( self.dat.transpose(), method=linkage, metric=metric )
            order = sch.leaves_list( Z )
        self.dat = self.dat[:, order]
        self.col = subseq( self.col, order )
        if self.colmeta is not None:
            self.colmeta = [subseq( x, order ) for x in self.colmeta]
        return Z

    def rowsort( self, metric, linkage="average" ):
        Z = None
        if metric == "none":
            order = range( len( self.row ) )
        elif metric == "names":
            order = sorted( range( len( self.row ) ), key=lambda i: self.row[i], reverse=True )
        elif metric == "mean":
            order = sorted( range( len( self.row ) ), key=lambda i: np.mean( self.dat[i] ) )
        elif os.path.exists( metric ):
            d = file_order( metric )
            if len( d ) != len( self.row ):
                warn( "dimension mismatch with order in", metric, len( d ), len( self.row ) )
            order = [0 for k in self.row]
            for i, k in enumerate( self.row ):
                if k in d:
                    order[d[k]] = i
                else:
                    warn( "no position for", k, "in", metric )
        elif "metadata" in metric:
            index = 0 if ":" not in metric else ( int( metric.split( ":" )[1] ) - 1 )
            values = self.rowmeta[index]
            order = sorted( range( len( values ) ), key=lambda i: values[i], reverse=True )
        elif metric == "spearman":
            temp = [rankdata( col ) for col in self.dat.transpose( )]
            temp = np.array( temp )
            try:
                Z = sch.linkage( temp.transpose( ), method=linkage, metric="correlation" )
                order = sch.leaves_list( Z )
            except:
                warn( "Spearman clustering failed" )
                Z = None
                order = range( len( self.row ) )
        else:
            Z = sch.linkage( self.dat, method=linkage, metric=metric )
            order = sch.leaves_list( Z )
        self.dat = self.dat[order, :]
        self.row = subseq( self.row, order )
        if self.rowmeta is not None:
            self.rowmeta = [subseq( x, order ) for x in self.rowmeta]
        return Z

    def transform( self, method ):
        if method == "none":
            pass
        elif method == "sqrt":
            self.dat = np.sqrt( self.dat )
        elif "log" in method:
            eps = min( [k for row in self.dat for k in row if k > 0] )
            warn( "Applying Laplace smoothing with constant:", eps )
            self.dat = np.log10( self.dat + eps )
            base = int( method.replace( "log", "" ) )
            warn( "Log transforming with base", base )
            self.dat /= np.log10( base )

class HeatmapAxes:

    def __init__( self, d ):
        self.d = d
        self.axes = {}
        self.has_colmetaplot = False
        self.has_rowmetaplot = False
        # heatmap
        self.heatmap = plt.subplot2grid(
            (d.rsize, d.csize),
            (d.rmargin, d.cmargin),
            rowspan=d.heat_r,
            colspan=d.heat_c,
            )
        self.axes["heatmap"] = self.heatmap
        # title
        if d.title_r > 0:
            self.title = plt.subplot2grid(
                (d.rsize, d.csize),
                (0, d.cmargin),
                rowspan=d.title_r,
                colspan=d.heat_c,
            )
            self.axes["title"] = self.title
        # coltree
        if d.coltree_r > 0:
            self.coltree = plt.subplot2grid(
                (d.rsize, d.csize),
                (d.title_r, d.cmargin),
                rowspan=d.coltree_r,
                colspan=d.heat_c,
            )
            self.axes["coltree"] = self.coltree
        # rowtree
        if d.rowtree_c > 0:
            self.rowtree = plt.subplot2grid(
                (d.rsize, d.csize),
                (d.rmargin, d.cbar_c),
                rowspan=d.heat_r,
                colspan=d.rowtree_c,
            )
            self.axes["rowtree"] = self.rowtree
        # colmeta
        if d.colmeta_r > 0:
            self.colmeta = plt.subplot2grid(
                (d.rsize, d.csize),
                (d.title_r + d.coltree_r, d.cmargin),
                rowspan=d.colmeta_r,
                colspan=d.heat_c,
            )
            self.axes["colmeta"] = self.colmeta
        # rowmeta
        if d.rowmeta_c > 0:
            self.rowmeta = plt.subplot2grid(
                (d.rsize, d.csize),
                (d.rmargin, d.cbar_c + d.rowtree_c),
                rowspan=d.heat_r,
                colspan=d.rowmeta_c,
            )
            self.axes["rowmeta"] = self.rowmeta
        # colnames
        if d.colnames_r > 0:
            self.colnames = plt.subplot2grid(
                (d.rsize, d.csize),
                (d.rmargin + d.heat_r, d.cmargin),
                rowspan=d.colnames_r,
                colspan=d.heat_c,
            )
            self.axes["colnames"] = self.colnames
        # rownames
        if d.rownames_c > 0:
            self.rownames = plt.subplot2grid(
                (d.rsize, d.csize),
                (d.rmargin, d.cmargin + d.heat_c),
                rowspan=d.heat_r,
                colspan=d.rownames_c,
            )
            self.axes["rownames"] = self.rownames
        # cbar
        delta = int( d.heat_r * ( 1.0 - d.cbar_extent ) / 2.0 )
        self.cbar = plt.subplot2grid(
            (d.rsize, d.csize),
            (d.rmargin + delta, d.cbar_c - d.cbar_c2),
            rowspan=d.heat_r - 2 * delta,
            colspan=d.cbar_c2,
        )
        self.axes["cbar"] = self.cbar
        # legend
        self.legend = plt.subplot2grid(
            (d.rsize, d.csize),
            (d.rmargin, d.cmargin + d.heat_c + d.rownames_c),
            rowspan=d.heat_r,
            colspan=d.legend_c,
        )
        self.axes["legend"] = self.legend

    def set_title( self, title="Untitled Heatmap" ):
        self.title.text( 0.5, 0.5, title, ha="center", va="center" )

    def collabel( self, df, ax_label, scaled=False, path=None ):
        ax_label = "{} (n={:,})".format( ax_label, len( df.col ) )
        # override col names from the table?
        mapping = {}
        if path is not None:
            mapping = col2dict( path, value=1 )
        for l in df.col:
            if l not in mapping:
                mapping[l] = "" if path is not None else l
        if len( df.col ) > c_max_lab and not scaled:
            warn( "Too many column labels." )
            cx = sum( self.colnames.get_xlim( ) ) / 2.0
            cy = sum( self.colnames.get_ylim( ) ) / 2.0
            self.colnames.text( cx, cy, ax_label, size=c_font3, ha="center", va="center" )
        else:
            ypos = self.colnames.get_ylim( )[1]
            self.colnames.set_xlim( 0, len( df.col ) )
            for i, l in enumerate( df.col ):
                self.colnames.text( i + 0.5, ypos, mapping[l],
                                    rotation=90, rotation_mode="anchor",
                                    va="center", ha="right",
                                    size=c_font1, clip_on=False, )
            cx = sum( self.colnames.get_xlim( ) ) / 2.0
            cy = 0
            self.colnames.text( cx, cy, ax_label, size=c_font3, ha="center", va="bottom" )

    def rowlabel( self, df, ax_label, scaled=False, path=None ):
        ax_label = "{} (n={:,})".format( ax_label, len( df.row ) )
        # override row names from the table?
        mapping = {}
        if path is not None:
            mapping = col2dict( path, value=1 )
        for l in df.row:
            if l not in mapping:
                mapping[l] = "" if path is not None else l
        if len( df.row ) > c_max_lab and not scaled:
            warn( "Too many row labels." )
            cx = sum( self.rownames.get_xlim( ) ) / 2.0
            cy = sum( self.rownames.get_ylim( ) ) / 2.0
            self.rownames.text( cx, cy, ax_label, size=c_font3, ha="center", va="center", rotation=90,
                                rotation_mode="anchor" )
        else:
            self.rownames.set_ylim( 0, len( df.row ) )
            for i, l in enumerate( df.row ):
                self.rownames.text( 0, i + 0.5, mapping[l],
                                    va="center", size=c_font1, clip_on=True, )
            cx = self.rownames.get_xlim( )[1]
            cy = sum( self.rownames.get_ylim( ) ) / 2.0
            self.rownames.text( cx, cy, ax_label, size=c_font3, ha="center", va="bottom", rotation=90,
                                rotation_mode="anchor" )

    def get_blocks( self, values, cmap ):
        i = 0
        blocks = []
        n = len( values )
        start = 0
        span = 0
        for i in range( n ):
            span += 1
            if i == n-1 or cmap[values[i]] != cmap[values[i+1]]:
                blocks.append( [start, span, cmap[values[i]]] )
                start = i + 1
                span = 0
        return blocks

    def colmetaplot( self, df, cmaps=None, max_levels=None ):
        self.has_colmetaplot = True
        if cmaps is None:
            cmaps = [c_metacmap for k in df.colmeta]
        self.colmeta.set_ylim( 0, len( df.colmeta ) )
        self.colmeta.set_xlim( 0, len( df.colmeta[0] ) )
        for i, levels in enumerate( df.colmeta ):
            levels = relevel( levels, max_levels )
            cmaps[i] = metacolors( levels, cmaps[i] )
            for [start, span, color] in self.get_blocks( levels, cmaps[i] ):
                self.colmeta.bar( start, 1, color=color, width=span, bottom=i, edgecolor="none" )
        self.colmeta.set_yticks( [0.5 + k for k in range( len( df.colmeta ) )] )
        self.colmeta.set_yticklabels( df.colmetaname, size=c_font1 )
        mu.user_grid( self.colmeta, h=range( 1, len( cmaps ) ), color="black", zorder=2 )
        mu.hide_yticks( self.colmeta )
        return cmaps

    def rowmetaplot( self, df, cmaps=None, max_levels=None ):
        self.has_rowmetaplot = True
        if cmaps is None:
            cmaps = [c_metacmap for k in df.rowmeta]
        self.rowmeta.set_xlim( 0, len( df.rowmeta ) )
        self.rowmeta.set_ylim( 0, len( df.rowmeta[0] ) )
        for i, levels in enumerate( df.rowmeta ):
            levels = relevel( levels, max_levels )
            cmaps[i] = metacolors( levels, cmaps[i] )
            for [start, span, color] in self.get_blocks( levels, cmaps[i] ):
                self.rowmeta.barh( start, 1, color=color, height=span, left=i, edgecolor="none" )
        self.rowmeta.set_xticks( [0.5 + k for k in range( len( df.rowmeta ) )] )
        mu.user_grid( self.rowmeta, v=range( 1, len( cmaps ) ), color="black", zorder=2 )
        mu.hide_xticks( self.rowmeta )
        self.rowmeta.set_xticklabels( df.rowmetaname, rotation=90, size=c_font1, \
                                      rotation_mode="anchor", ha="left", va="center" )
        return cmaps

    def clean( self ):
        mu.tick_params( self.cbar )
        self.cbar.yaxis.tick_left( )
        self.cbar.yaxis.set_label_position( "left" )
        if "rowmeta" in self.axes:
            self.rowmeta.xaxis.tick_top( )
            mu.hide_xticks( self.rowmeta )
        if "colmeta" in self.axes:
            self.colmeta.yaxis.tick_right( )
            mu.hide_yticks( self.colmeta )
        for name, ax in self.axes.items( ):
            if False:
                x = sum( ax.get_xlim( ) ) / 2.0
                y = sum( ax.get_ylim( ) ) / 2.0
                ax.text( x, y, name )
                continue
            if "rowmeta" not in name or not self.has_rowmetaplot:
                mu.hide_xaxis( ax )
            if "cbar" not in name and "colmeta" not in name:
                mu.hide_yaxis( ax )
            if "tree" in name or "name" in name or "title" in name or "legend" in name:
                mu.hide_border( ax )

#-------------------------------------------------------------------------------
# main
#-------------------------------------------------------------------------------

def main( ):

    args = get_args( )
    fig = plt.figure( )
    dims = Dimensions( )
    df = DataFrame( args.table,
                    lastcol=args.lastcol, lastrow=args.lastrow,
                    colmeta=args.colmeta, rowmeta=args.rowmeta,
                    eps_noise=args.eps_noise, )

    # force labeling all features
    if args.force_labels:
        global c_max_lab
        c_max_lab = 1e6

    # dim overrides
    vscale = 1
    hscale = 1
    if args.colmeta is not None and args.metascale:
        dims.colmeta_r = len( args.colmeta )
    if args.rowmeta is not None and args.metascale:
        dims.rowmeta_c = len( args.rowmeta )
    if args.vscale:
        old = dims.heat_r
        new = int( len( df.row ) / 2.0 ) + len( df.row ) % 2
        new = max( new, 8 )
        dims.heat_r = new
        vscale = new / float( old )
    if args.hscale:
        old = dims.heat_c
        new = int( len( df.col ) / 2.0 ) + len( df.col ) % 2
        dims.heat_c = new
        new = max( new, 12 )
        hscale = new / float( old )
    if args.cbar_extent is not None:
        dims.cbar_extent = args.cbar_extent
    if not args.debug:
        if args.title is None:
            dims.title_r = 0
        # no tree axes if last sort is on 1) file or 2) metadata or 3) nothing
        if os.path.exists( args.colsort[-1] ) \
           or re.search( "none|names|mean|metadata", args.colsort[-1] ):
            dims.coltree_r = 0
        if os.path.exists( args.rowsort[-1] ) \
           or re.search( "none|names|mean|metadata", args.rowsort[-1] ):
            dims.rowtree_c = 0
        if args.colmeta is None:
            dims.colmeta_r = 0
        if args.rowmeta is None:
            dims.rowmeta_c = 0
        if len( df.col ) > c_max_lab and not args.hscale:
            dims.colnames_r = 1
        if len( df.row ) > c_max_lab and not args.vscale:
            dims.rownames_c = 1
    dims.update( )

    # manual overrides
    for o in args.overrides:
        p, v = o.split( ":" )
        v = int( v )
        setattr( dims, p, v )
    dims.update( )

    # define figure
    fig.set_size_inches( args.hstretch * dims.csize * args.grid_inches / dims.scale,
                         args.vstretch * dims.rsize * args.grid_inches / dims.scale )

    # setup axes
    axes = HeatmapAxes( dims )

    # cluster cols
    Z = None
    for metric in args.colsort:
        Z = df.colsort( metric, linkage=args.linkage )
    if Z is not None:
        sch.dendrogram( Z, ax=axes.coltree, \
                        above_threshold_color="0.75",
                        color_threshold=0, )

    # cluster rows
    Z = None
    for metric in args.rowsort:
        Z = df.rowsort( metric, linkage=args.linkage )
    if Z is not None:
        sch.dendrogram( Z, ax=axes.rowtree, orientation="left", \
                        above_threshold_color="0.75",
                        color_threshold=0, )

    # apply transform
    df.transform( args.transform )

    # check limits
    poormin = False
    poormax = False
    vmin, vmax = (None, None) if args.limits is None else args.limits
    dmin, dmax = np.min( df.dat ), np.max( df.dat )
    if vmin is None:
        vmin = dmin
    elif dmin < vmin:
        poormin = True
        n, p = acheck( df.dat, lambda x: x < vmin )
        warn( "{} values ({:.2f}%) < vmin ({}), extreme: {}".format( n, 100 * p, vmin, dmin ) )
    if vmax is None:
        vmax = dmax
    elif dmax > vmax:
        poormax = True
        n, p = acheck( df.dat, lambda x: x > vmax )
        warn( "{} values ({:.2f}%) > vmax ({}), extreme: {}".format( n, 100 * p, vmax, dmax ) )

    # add heatmap
    axes.heatmap.set_xlim( 0, len( df.col ) )
    axes.heatmap.set_ylim( 0, len( df.row ) )
    # imshow is similar to pcolorfast, but better centered
    if args.engine == "imshow":
        nr = len( df.row )
        nc = len( df.col )
        kwargs = {"interpolation":"none", "origin":"lower",
                  "aspect":"auto", "extent":[0, nc, 0, nr]}
        pc = axes.heatmap.imshow( df.dat, cmap=args.cmap, vmin=vmin, vmax=vmax, **kwargs )
    # probably no reason to use this
    elif args.engine == "pcolorfast":
        pc = axes.heatmap.pcolorfast( df.dat, cmap=args.cmap, vmin=vmin, vmax=vmax )
    # use this if you want the individual heatmap cells to be editable shapes
    elif args.engine == "pcolormesh":
        pc = axes.heatmap.pcolormesh( df.dat, cmap=args.cmap, vmin=vmin, vmax=vmax )

    # add cmap bar
    fig.colorbar( pc, cax=axes.cbar )
    axes.cbar.set_ylabel( args.units if args.transform == "none" else \
                          "{}( {} )".format( args.transform, args.units ), size=c_font3 )
    set_cbar_ticks( axes.cbar, pc.get_clim( ), poormin=poormin, poormax=poormax )

    # add column metadata
    if df.colmeta is not None:
        colmeta_cmaps = axes.colmetaplot( df, args.colmeta_colors, args.max_levels )

    # add row metadata
    if df.rowmeta is not None:
        rowmeta_cmaps = axes.rowmetaplot( df, args.rowmeta_colors, args.max_levels )

    # column transition lines
    if "metadata" in args.colsort[-1]:
        args.colbreaks = args.colsort[-1]
    if args.colbreaks is not None:
        lastsort = args.colbreaks
        index = 0 if ":" not in lastsort else \
                ( int( lastsort.split( ":" )[1] ) - 1 )
        pos = []
        for i, value in enumerate( df.colmeta[index] ):
            if i > 0 and df.colmeta[index][i-1] != value:
                pos.append( i )
        for i in pos:
            mu.vline( axes.colmeta, i, color="black" )
            mu.vline( axes.heatmap, i, color=args.break_color )

    # add row transition lines if ending on a metasort
    if "metadata" in args.rowsort[-1]:
        args.rowbreaks = args.rowsort[-1]
    if args.rowbreaks is not None:
        lastsort = args.rowbreaks
        index = 0 if ":" not in lastsort else \
                ( int( lastsort.split( ":" )[1] ) - 1 )
        pos = []
        for i, value in enumerate( df.rowmeta[index] ):
            if i > 0 and df.rowmeta[index][i-1] != value:
                pos.append( i )
        for i in pos:
            mu.hline( axes.rowmeta, i, color="black" )
            mu.hline( axes.heatmap, i, color=args.break_color )

    # add generic grids
    if "x" in args.grid:
        for i in range( 1, len( df.col ) ):
            mu.vline( axes.heatmap, i, color=args.break_color )
    if "y" in args.grid:
        for i in range( 1, len( df.row ) ):
            mu.hline( axes.heatmap, i, color=args.break_color )

    # title
    if args.title is not None:
        axes.set_title( args.title )

    # add dots
    dots_added = []
    if args.dots is not None:
        for p in args.dots:
            dots_added.append( add_dots( axes, df, p ) )

    # legend
    L = mu.Legendizer( axes.legend, vscale=0.7 / vscale )
    # col sort legend
    L.subhead( "Col sort" )
    for m in args.colsort:
        if "metadata" in m:
            i = 0
            if ":" in m:
                i = int( m.split( ":" )[1] ) - 1
            m = "metadata:"+df.colmetaname[i]
        L.element( "_", color="0.75", label=m )
    # row sort legend
    L.subhead( "Row sort" )
    for m in args.rowsort:
        if "metadata" in m:
            i = 0
            if ":" in m:
                i = int( m.split( ":" )[1] ) - 1
            m = "metadata:"+df.rowmetaname[i]
        L.element( "_", color="0.75", label=m )
    # col metadata legend
    levelorder = {c_str_other:1, c_str_none:2}
    if df.colmeta is not None:
        for n, c in zip( df.colmetaname[::-1], colmeta_cmaps[::-1] ):
            L.subhead( n )
            for l in sorted( c, key=lambda x: [levelorder.get( x, 0 ), x] ):
                color = c[l]
                L.element( "s", color=color, label=l )
    # row metadata legend
    if df.rowmeta is not None:
        for n, c in zip( df.rowmetaname[::-1], rowmeta_cmaps[::-1] ):
            L.subhead( n )
            for l in sorted( c, key=lambda x: [levelorder.get( x, 0 ), x] ):
                color = c[l]
                L.element( "s", color=color, label=l )
    if len( dots_added ) > 0:
        L.subhead( "Dots" )
        for p, kwargs in dots_added:
            marker = kwargs.get( "marker", "o" )
            kwargs = {k:v for k, v in kwargs.items( ) if k not in "s marker".split( )}
            L.element( marker, label=path2name( p ), **kwargs )
    # finalize
    L.draw( )

    # cleanup
    if args.override_colnames is not "-":
        axes.collabel( df, args.collabel, scaled=args.hscale, path=args.override_colnames )
    if args.override_rownames is not "-":
        axes.rowlabel( df, args.rowlabel, scaled=args.vscale, path=args.override_rownames )
    if not args.debug:
        axes.clean( )
    plt.subplots_adjust( wspace=0.3, hspace=0.3 )
    plt.savefig( args.output, bbox_inches="tight" )

    # logging
    if args.dump_colsort_order:
        with open( args.output+".colsort", "w" ) as fh:
            for item in df.col:
                print >>fh, item
    if args.dump_rowsort_order:
        with open( args.output+".rowsort", "w" ) as fh:
            for item in df.row:
                print >>fh, item

if __name__ == "__main__":
    main( )


import itertools

from common.apple import Apple
from common.block import Block
from common.snake import Snake

class Level:

    def __init__(self, dimensions=None):
        self.apple_amount = 0.01

        self.snakes = []
        self.apples = []
        self.blocks = []

        if dimensions:
            self.dimensions = dimensions
        else:
            self.dimensions = (0, 0)

    def init_from_json(self, json):
        self.snakes = []
        self.apples = []
        self.blocks = []

        self.dimensions = (json['level_size']['width'], json['level_size']['height'])

        for snake in json['snakes']:
            self.snakes.append(Snake((snake['x'], snake['y']), snake['id'], snake['dir']))

        self.snakes.sort(key=lambda x: x.id)

        for apple in json['apples']:
            self.apples.append(Apple((apple['x'], apple['y'])))

        for block in json['blocks']:
            self.apples.append(Block((block['x'], block['y'])))

    def all_blocks(self):
        return itertools.chain(itertools.chain.from_iterable(map(lambda x: x.body, self.snakes)),
                map(lambda x: x.position, self.apples), map(lambda x: x.position, self.blocks))


from flask_wtf import FlaskForm
from wtforms import (
    StringField, IntegerField, DecimalField
)
from wtforms.validators import (
    DataRequired, Length, Email, EqualTo, ValidationError
)

class PayStubForm(FlaskForm):
    firstName = StringField('first name', validators=[
                            DataRequired()], default='Attila')

    middleName = StringField('middle name', default='')

    lastName = StringField('last name', validators=[
                           DataRequired()], default='Turkoz')

    companyName = StringField('company', validators=[
                              DataRequired()], default='JAM')

    allowance = IntegerField('allowance', default=2)

    hourlyRate = DecimalField('hourly rate', validators=[
                              DataRequired()], default=44.00)

    hoursWorked = DecimalField('hours worked', validators=[
                              DataRequired()], default=80.00)

    payCntYr2Dt = IntegerField('pay count YTD', default=2)

    dateStart =  StringField('mm/dd/yyyy', validators=[
                              DataRequired()], default='11/04/2019')

    dateEnd =  StringField('mm/dd/yyyy', validators=[
                              DataRequired()], default='11/17/2019')

    def generate_paystub(self, *args, **kwargs):
        super(ModGeneratedPayStubFrom, self).__init__(*args, **kwargs)
        self.payCntYr2Dt = payCntYr2Dt
        self.dateStart = dateStart
        self.dateEnd = dateEnd
        self.allowance_regression_slope = -0.1067
        self.allowance_regression_intcpt = 2.0444
        self.allowanceFactor = float(self.allowance_regression_slope * self.allowance.data) +  self.allowance_regression_intcpt
        self.current = self.hoursWorked * self.hourlyRate
        self.curr3nt = self.hoursWorked * self.hourlyRate
        self.year2date = payCntYr2Dt * self.current
        self.hourlyR4te = self.hourlyRate
        self.year2d4te = self.year2date
        self.social_security = self.current * self.allowanceFactor *9.3/150
        self.social_security_perc = self.allowanceFactor *9.3/150*100
        self.social_security_year2date = self.current *  self.allowanceFactor *9.3 / 150 * payCntYr2Dt
        self.medicare = self.current *  self.allowanceFactor *2.18 / 150
        self.medicare_perc = self.allowanceFactor *2.18 / 150*100
        self.medicare_year2date = self.current * 2.18 / 150 *  self.allowanceFactor *payCntYr2Dt
        self.futa = self.current * 0.90 * self.allowanceFactor / 150
        self.futa_perc = 0.90 * self.allowanceFactor / 150*100
        self.futa_year2date = self.current * 0.90 / 150 *  self.allowanceFactor *payCntYr2Dt
        self.co_unemp = self.current * self.allowanceFactor * 1.77 / 150
        self.co_unemp_perc = self.allowanceFactor * 1.77 / 150*100
        self.co_unemp_year2date = self.current * 1.77 / 150 * payCntYr2Dt * self.allowanceFactor
        self.taxes = self.current * 11.48 / 150 * self.allowanceFactor
        self.taxes_perc = 11.48 / 150 * self.allowanceFactor *100
        self.taxes_year2date = self.current * 11.48 / 150 * payCntYr2Dt * self.allowanceFactor
        self.net_pay = self.current*(1-(11.48/150*self.allowanceFactor))
        self.net_pay_perc = (1-(11.48/150*self.allowanceFactor))*100
        self.net_pay_y2d =  self.current*(1-(11.48/150*self.allowanceFactor))* payCntYr2Dt

    def __rpr__(self):
        pass
        print('test PayStubForm')


class Solution:
    def canReach(self, s: str, minJump: int, maxJump: int) -> bool:
        if s[-1] == '1':
            return False
        q = [0]
        visited = set()
        farthest = 0
        while q:
            newQ = set()
            for index in q:
                if index == len(s) - 1:
                    return True
                if index in visited:
                    continue
                visited.add(index)
                for i in range(max(farthest + 1, minJump + index), min(len(s), maxJump + index + 1)):
                    farthest = max(i, farthest)
                    if i in visited or s[i] == '1':
                        continue
                    newQ.add(i)
            q = newQ
        return False


import warnings

import nengo
from nengo.spa.buffer import Buffer

class Memory(Buffer):
    """
    A SPA module capable of storing a vector over time.

    Parameters are the same as `.spa.Buffer`, with the addition of
    ``synapse`` and ``tau``.

    .. note:: Deprecated in Nengo 2.1.0. Use `.spa.State` instead.

    Parameters
    ----------
    dimensions : int
        Number of dimensions for the vector.
    subdimensions : int, optional
        Size of the individual ensembles making up the vector.
        Must divide ``dimensions`` evenly.
    neurons_per_dimensions : int, optional
        Number of neurons in an ensemble will be
        ``neurons_per_dimensions * subdimensions``.
    synapse : float, optional
        Synaptic filter to use on recurrent connection.
    vocab : Vocabulary, optional
        The vocabulary to use to interpret the vector. If None,
        the default vocabulary for the given dimensionality is used.
    tau : float or None, optional
        Effective time constant of the integrator. If None, it should
        have an infinite time constant.
    direct : bool, optional
        Whether or not to use direct mode for the neurons.

    label : str, optional
        A name for the ensemble. Used for debugging and visualization.
    seed : int, optional
        The seed used for random number generation.
    add_to_container : bool, optional
        Determines if this Network will be added to the current container.
        If None, will be true if currently within a Network.
    """

    def __init__(
        self,
        dimensions,
        subdimensions=16,
        neurons_per_dimension=50,
        synapse=0.01,
        vocab=None,
        tau=None,
        direct=False,
        label=None,
        seed=None,
        add_to_container=None,
    ):
        warnings.warn("Memory is deprecated in favour of spa.State", DeprecationWarning)
        super().__init__(
            dimensions=dimensions,
            subdimensions=subdimensions,
            neurons_per_dimension=neurons_per_dimension,
            vocab=vocab,
            direct=direct,
            label=label,
            seed=seed,
            add_to_container=add_to_container,
        )

        if tau is None:
            transform = 1.0
        else:
            transform = 1.0 - synapse / tau

        with self:
            nengo.Connection(
                self.state.output,
                self.state.input,
                transform=transform,
                synapse=synapse,
            )


import wx
import wx.adv
import wx.grid
import pandas
import Db
from openpyxl.utils.cell import get_column_letter

def format_date(date):
    lis = [date.year, date.month + 1, date.day]
    for d in range(len(lis)):
        if lis[d] < 10:
            lis[d] = "0" + str(lis[d])
        else:
            lis[d] = str(lis[d])
    return str(lis[0] + "-" + lis[1] + "-" + lis[2])

class UI(wx.Frame):
    grid: wx.grid.Grid

    def __init__(self, parent, s_id, ttl, sz):
        super(UI, self).__init__(parent, s_id, title=ttl, size=sz,
                                 style=wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER)  # call parent __init__
        self.size = sz  # size of the original frame
        self.parent = parent  # store parent
        self.panels = [wx.Panel(self)]  # set panel
        self.initialize()  # initialize
        self.current_dataframe = 0  # database

    def initialize(self):
        self.initialize_components()
        self.initialize_table()
        self.Show(True)  # show self

    def initialize_components(self):
        # TITLE TEXTS
        sizer = wx.BoxSizer(wx.VERTICAL)
        title_text1 = self.createText(label="VICTORIAN TRANSPORT DEPARTMENT", font_size=18, bold=True)
        title_text2 = self.createText(label="DATA ANALYTIC TOOL", font_size=22, bold=True)
        sizer.Add(title_text1, flag=wx.ALIGN_CENTER | wx.TOP, border=10)
        sizer.Add(title_text2, flag=wx.ALIGN_CENTER | wx.TOP, border=-3)
        self.panels[0].SetSizer(sizer)

        # Show all column flag
        show_cols_flag_text = self.createText(label="Show all columns", pos=(self.size[0] - 360, 105), font_size=8,
                                              bold=True)
        show_cols_flag = self.createCheckBox(label="", pos=(self.size[0] - 270, 100), size=(24, 24), id=1)

        # Classifications
        lst = list(Db.getCols())
        classification_text = self.createText(label="Classification", pos=(self.size[0] - 245, 105), font_size=8,
                                              bold=True)
        classification = self.createComboBox(choices=lst, pos=(self.size[0] - 175, 100),
                                             size=(135, 24), default='ACCIDENT_TYPE', id=11)  # classifications

        # Dates
        date_from_text = self.createText(label="Date From", pos=(self.size[0] - 596, 132), font_size=8,
                                         bold=True)  # text of date_from
        date_from = self.createDatePicker(pos=(self.size[0] - 539, 126), size=(135, 24), id=21)  # date_from
        date_to_text = self.createText(label="Date To", pos=(self.size[0] - 402, 132), font_size=8, bold=True)
        date_to = self.createDatePicker(pos=(self.size[0] - 360, 126), size=(135, 24), id=22)  # date_to

        # Keywords
        keyword_text = self.createText(label="Keyword", pos=(self.size[0] - 223, 130), font_size=8, bold=True)
        keyword = self.createTextCtrl(pos=(self.size[0] - 175, 126), size=(135, 24), id=31)  # keyword

        # Visualization Options
        vo_text = self.createText(label="Visualization Options", pos=(self.size[0] - 596, 157), font_size=8, bold=True)
        vo_pie = self.createRadioButton(label="Pie", pos=(self.size[0] - 470, 157), font_size=8, bold=True, id=41)
        vo_bar = self.createRadioButton(label="Bar", pos=(self.size[0] - 430, 157), font_size=8, bold=True, id=42)
        vo_line = self.createRadioButton(label="Line", pos=(self.size[0] - 390, 157), font_size=8, bold=True, id=43)
        vo_alcohol = self.createRadioButton(label="Alcohol", pos=(self.size[0] - 345, 157), font_size=8, bold=True,
                                            id=44)
        # vo_histogram = self.createRadioButton(label="Histogram", pos=(self.size[0] - 346, 157), font_size=8, bold=True)

        # Buttons
        btn_reset = self.createButton(label="Reset", pos=(self.size[0] - 230, 152), size=(70, 24),
                                      func=self.ButtonReset, id=51)
        btn_visualize = self.createButton(label="Visualize", pos=(self.size[0] - 160, 152), size=(70, 24),
                                          func=self.ButtonPressed, id=52)
        btn_search = self.createButton(label="Search", pos=(self.size[0] - 90, 152), size=(70, 24),
                                       func=self.ButtonPressed, id=53)

    def ButtonPressed(self, e):
        date_from = format_date(self.FindWindowById(21).GetValue())
        date_to = format_date(self.FindWindowById(22).GetValue())
        keyword = str(self.FindWindowById(31).GetValue())
        classification = str(self.FindWindowById(11).GetValue())
        fromCheck = int(date_from.replace('-', ''))
        toCheck = int(date_to.replace('-', ''))
        # Check if date to is behind date from
        if fromCheck >= toCheck:
            wx.MessageBox("date to can't be behind date from", "Checker")
        else:
            # if Search
            if e.GetId() == 53:
                if self.FindWindowById(1).GetValue():
                    show_all = True
                else:
                    show_all = False
                data = Db.periodByAccident(date_from, date_to, keyword, classification, show_all)
                if data.empty:
                    wx.MessageBox("No Matching Information", "Checker")
                else:
                    self.create_table(data)
            # if Visualize
            elif e.GetId() == 52:
                user_selection = ''
                if self.FindWindowById(41).GetValue():
                    user_selection = 'pie'
                elif self.FindWindowById(42).GetValue():
                    user_selection = 'bar'
                elif self.FindWindowById(43).GetValue():
                    user_selection = 'line'
                elif self.FindWindowById(44).GetValue():
                    user_selection = 'alcohol'
                if user_selection == 'alcohol':
                    anoa = Db.getAccidentNumberOfAlcohol(date_from, date_to, keyword, classification)
                    Db.visualize(
                        [
                            Db.VisualizeChart(
                                values=(list(anoa.keys())[:2], list(anoa.values())[:2]),
                                title="Number of accidents by alcohol",
                                dtype='pie',
                                colors=['#ffaaaa', '#aaaaff']
                            ),
                            Db.VisualizeChart(
                                values=(list(anoa.keys())[2:], list(anoa.values())[2:]),
                                title="Number of accidents by alcohol / severity of injury",
                                dtype='bar',
                                colors=['#ffaaaa', '#aaaaff', '#ffaaaa', '#aaaaff']
                            )
                        ]
                    )
                elif user_selection in ['pie', 'bar', 'line']:
                    Db.visualize(Db.VisualizeChart(
                        values=Db.getNumberOfAccidentsInHours(date_from, date_to, keyword, classification),
                        title="Average number of accidents in each hour of the day",
                        xlabel="Each hour",
                        ylabel="Average number of accidents",
                        dtype=user_selection
                    ))
                else:
                    wx.MessageBox("Please select the visualization option first!")

    def ButtonReset(self, e):
        self.initialize_table(row=100, col=20)

    def create_table(self, data):
        # data initializations
        data_dict = data.to_dict()  # gets the dictionary version of the dataframe
        max_cols, col_names = len(data_dict), list(data_dict.keys())  # gets the maximum column num + column names
        max_rows = len(data_dict[col_names[0]])  # gets the maximum row num

        # clear
        change = self.initialize_table(row=max_rows, col=max_cols)

        for c in range(max_cols):
            self.grid.SetColLabelValue(c, col_names[c])
            self.grid.SetColSize(c, 250)
            for r in range(max_rows):
                if change: self.grid.SetCellRenderer(r, c, wx.grid.GridCellStringRenderer())
                row_lis = list(data_dict[col_names[c]].keys())
                d = data_dict[col_names[c]][row_lis[r]]
                if type(d) == pandas._libs.tslibs.timestamps.Timestamp:
                    d = str(d.day) + "/" + str(d.month) + "/" + str(d.year)
                elif col_names[c] == 'ACCIDENT_TIME':
                    d = d.replace('.', ':')
                self.grid.SetCellValue(r, c, str(d))

    grid_row = 100
    grid_col = 20

    def initialize_table(self, row: int = 0, col: int = 0):
        if row == 0: row = self.grid_row
        if col == 0: col = self.grid_col
        if len(self.panels) < 2:
            self.createPanel(pos=(0, 180), size=(self.size[0], self.size[1] - 180))
            static_box = wx.StaticBox(self.panels[1], wx.ID_ANY, 'Table will appear below',
                                      size=(self.size[0] - 10, self.size[1] - 220))
            static_sizer = wx.StaticBoxSizer(static_box, wx.HORIZONTAL)
            # TABLE
            self.grid = wx.grid.Grid(self.panels[1], 10, pos=(5, 15), size=(self.size[0] - 25, self.size[1] - 233))
            self.grid.CreateGrid(row, col)  # 100 rows / 10 columns
            for c in range(col):
                self.grid.SetColSize(c, 100)
            static_sizer.Add(self.grid)
            self.panels[1].SetSizer(static_sizer)
        else:
            increased = False
            self.grid.ClearGrid()
            if self.grid_row != row or self.grid_col != col:
                # change rows if different
                r_gap, c_gap = self.grid_row - row, self.grid_col - col
                if r_gap > 0:
                    self.grid.DeleteRows(pos=row, numRows=abs(r_gap))
                elif r_gap < 0:
                    self.grid.AppendRows(abs(r_gap));
                    increased = True
                # change cols if different
                if c_gap > 0:
                    self.grid.DeleteCols(pos=col, numCols=abs(c_gap))
                elif c_gap < 0:
                    self.grid.AppendCols(abs(c_gap));
                    increased = True
                self.grid_row, self.grid_col = row, col
            # reset size and label + render
            for c in range(col):
                self.grid.SetColSize(c, 100)
                self.grid.SetColLabelValue(c, get_column_letter(c + 1))
            if increased:
                return True
            else:
                return False
        pass

    def createCheckBox(self, parent=None, id=wx.ID_ANY, label='Check Box', pos=(0, 0), size=(-1, -1),
                       style=wx.CHK_3STATE):
        if parent is None: parent = self.panels[0]
        return wx.CheckBox(parent, id=id, label=label, pos=pos, size=size, style=style)

    def createComboBox(self, parent=None, default='Please Select', choices=('Default', 'None'), style=wx.CB_READONLY,
                       id=wx.ID_ANY, pos=(0, 0), size=(120, -1)):
        if parent is None: parent = self.panels[0]
        return wx.ComboBox(parent, id, default, choices=choices, style=style, pos=pos, size=size)

    def createRadioButton(self, parent=None, id=wx.ID_ANY, label="Radio Button", pos=(0, 0), size=(-1, 14), font_size=8,
                          bold=False):
        if parent is None: parent = self.panels[0]
        radio_btn = wx.RadioButton(parent, id=id, label=label, pos=pos, size=size)
        font = radio_btn.GetFont()  # get font
        font.PointSize = font_size  # set font size
        if bold: font = font.Bold()
        radio_btn.SetFont(font)
        return radio_btn

    def createDatePicker(self, parent=None, id=wx.ID_ANY, size=(120, -1), pos=(0, 0), style=wx.adv.DP_DROPDOWN):
        if parent is None: parent = self.panels[0]
        return wx.adv.DatePickerCtrl(parent, id=id, size=size, pos=pos, style=style)

    def createTextCtrl(self, parent=None, id=wx.ID_ANY, style=None, size=(120, -1), pos=(0, 0)):
        if parent is None: parent = self.panels[0]
        return wx.TextCtrl(parent, pos=pos, size=size, id=id)

    def createPanel(self, parent=None, pos=None, size=None):
        if parent is None: parent = self.panels[0]
        if pos is None and size is None:
            self.panels.append(wx.Panel(parent))
        elif pos is None:
            self.panels.append(wx.Panel(parent, size=size))
        elif size is None:
            self.panels.append(wx.Panel(parent, pos=pos))
        else:
            self.panels.append(wx.Panel(parent, pos=pos, size=size))

    def setBackgroundColour(self, colour, panel=0):
        self.panels[panel].SetBackgroundColour(colour)

    def createText(self, parent=None, font_size=12, bold=False, label="", pos=(0, 0)):
        if parent is None: parent = self.panels[0]
        text = wx.StaticText(parent, label=label, pos=pos)
        font = text.GetFont()  # get font
        font.PointSize = font_size  # set font size
        if bold: font = font.Bold()
        text.SetFont(font)
        return text

    def createButton(self, label="", pos=(0, 0), size=(120, -1), func=None, parent=None, id=wx.ID_ANY):
        if parent is None: parent = self.panels[0]
        button = wx.Button(parent, id=id, pos=pos, size=size, label=label)
        if func is not None: self.Bind(wx.EVT_BUTTON, func, button)
        return button

if __name__ == "__main__":
    app = wx.App()
    frame = UI(None, -1, ' ', (1400, 800))
    frame.Show()
    app.MainLoop()


#lista = [0,50,10,20,2]
#lista.remove(0)
#lista.remove(4)
#lista.insert(0, 2)
#lista.insert(4, 0)
#print(lista)

nota = []
for i in range (0,3):
    numero1 = int(input("Digite um numero: "))
    nota.append(numero1)
    print(nota)

print(nota/3)


import requests
import os
import json
import collections
import re
from sqlalchemy import create_engine
from bs4 import BeautifulSoup
from fake_useragent import UserAgent
from pymongo import MongoClient

conn_path = "./conn_info.txt"
with open(conn_path, "r") as f:
    a = json.loads(f.read())

engine = create_engine(
    f"mysql+pymysql://{a['mysql'][0]}:{a['mysql'][1]}@{a['mysql'][2]}/{a['mysql'][3]}"
)
cnx = engine.connect()

select_query = cnx.execute("SELECT href FROM brand_href")

url_list = ["https://www.mobile01.com/" + i[0] for i in select_query]

ua = UserAgent()
ua = ua.random

dict_list = []
headers = {"user-agent": ua}
for url in url_list:

    try:
        res = requests.get(url, headers=headers)
    except requests.exceptions.RequestException as e:
        raise SystemExit(e)

    soup = BeautifulSoup(res.text, "lxml")
    # 文章標題
    title = soup.find_all("h1", class_="t2")[0].text
    re_title = "".join(i for i in re.findall(r"[\u4e00-\u9fa5\w]+", title))
    title = re_title

    # 發文時間
    article_time = soup.find_all("span", class_="o-fNotes o-fSubMini")[0].text

    # 瀏覽人數
    visitors = soup.find_all("span", class_="o-fNotes o-fSubMini")[1].text

    # 讚數
    likes = soup.find_all("span", class_="o-fSubMini")[6].text

    # 針對文章內容作處理
    # 文章內容
    articleBody = soup.find_all("div", class_="u-gapNextV--md")[0].text
    # 拿掉網址
    re_articleBody = re.sub(
        r"^https?:\/\/.*[\r\n]*", "", articleBody, flags=re.MULTILINE
    )
    # 清除\n\r
    re_articleBody = re.sub(r"[\n\r]+", "", re_articleBody, flags=re.MULTILINE)
    # 取出中文及英文
    re_articleBody = "".join(
        i for i in re.findall(r"[\u4e00-\u9fa5\w]+", re_articleBody)
    )

    # 一篇文章整理成字典
    article_dict = {
        "title": title,
        "article_time": article_time,
        "visitors": visitors,
        "likes": likes,
        "articleBody": re_articleBody,
        "url": url,
    }
    dict_list.append(article_dict)

    if len(dict_list) == 100:
        # 建立連線
        # mongodb://users:password@your_ip/db_name.collection_name
        client = MongoClient(
            f"mongodb://{a['mongodb'][0]}:{a['mongodb'][1]}@{a['mongodb'][2]}"
        )
        if f"{a['mongodb'][3]}" in client.list_database_names():

            db = client[f"{a['mongodb'][3]}"]
            collection = db[f"{a['mongodb'][4]}"]
            collection.insert_many(dict_list)
            dict_list = []
    else:
        pass


from benchmarks import benchmark
import benchmarks.helpers as helpers
from harness.machine import Machine

#pylint: disable-msg=unused-argument
def startup_time_ms(value, **kwargs):
    """Returns average startup time per container in milliseconds."""
    return value * 1000

def startup(machine: Machine, workload: str, count: int = 5, port: int = 0, **kwargs):
    """Time the startup of some workload.

    :param count: Number of containers to start.
    :param port: The port to check for liveness, if provided.
    :param workload: The workload to run.
    :return: The mean start-up time in seconds.
    """
    # Load before timing.
    image = machine.pull(workload)
    #netcat = machine.pull("netcat")
    count = int(count)
    port = int(port)

    with helpers.Timer() as timer:
        for _ in range(count):
            if not port:
                # Run the container synchronously.
                machine.container(image, **kwargs).run()
            else:
                # Run a detached container until httpd available.
                with machine.container(image, port=port, **kwargs).detach() as server:
                    (server_host, server_port) = server.address()
                    #machine.container(netcat).run(host=server_host, port=server_port)
                    machine.container().run(host=server_host, port=server_port)
        return timer.elapsed() / float(count)

@benchmark(metrics=[startup_time_ms], machines=1)
def empty(machine: Machine, **kwargs) -> float:
    """Time the startup of a trivial container.

    :param machine: machine object
    :param kwargs:
        :param count: Number of containers to start.
    """
    return startup(machine, workload="true", **kwargs)

@benchmark(metrics=[startup_time_ms], machines=1)
def node(machine: Machine, **kwargs) -> float:
    """Time the startup of the node container.

    :param machine: machine object
    :param kwargs:
        :param count: Number of containers to start.
    """
    return startup(machine, workload="node", port=8080, **kwargs)

@benchmark(metrics=[startup_time_ms], machines=1)
def ruby(machine: Machine, **kwargs) -> float:
    """Time the startup of the ruby container.

    :param machine: machine object
    :param kwargs:
        :param count: The number of times to measure.
    """
    return startup(machine, workload="ruby", port=3000, **kwargs)


from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
import sys

class QPushButtonDemo(QDialog):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.setWindowTitle("QPushButtonDemo")
        layout=QFormLayout(self)

        self.button1=QPushButton("第一个按钮")
        self.button1.setText("First Button")
        self.button1.setCheckable(True)
        self.button1.clicked.connect(lambda:self.onButtonClicked(self.button1))
        self.button1.toggled.connect(self.onButton1Toggled)

        self.button2=QPushButton("图像按钮")
        self.button2.setIcon(QIcon(QPixmap('icon/test.ico')))
        self.button2.clicked.connect(lambda:self.onButtonClicked(self.button2))

        self.button3=QPushButton("不可用按钮")
        self.button3.setEnabled(False)

        self.button4=QPushButton("&Default")
        self.button4.setDefault(True)
        self.button4.clicked.connect(lambda:self.onButtonClicked(self.button4))

        layout.addRow(self.button1)
        layout.addRow(self.button2)
        layout.addRow(self.button3)
        layout.addRow(self.button4)

    def onButtonClicked(self,button:QAbstractButton):
        print('被单击的按钮是',button.text())

    def onButton1Toggled(self):
        if self.button1.isChecked():
            print("按钮已被选中")
        else:
            print("按钮未被选中")

if __name__=="__main__":
    app=QApplication(sys.argv)
    mainWindow=QPushButtonDemo()
    mainWindow.show()
    sys.exit(app.exec_())


##
# Prepare data for running OTF scheme on all chromosomes
##

import argparse
parser = argparse.ArgumentParser(prog='impute_otf_preload.py', description='''
    Pre-load matrices needed for running OTF scheme on all chromosomes
    (fit all chromosomes jointly)
''')

parser.add_argument('--genotype-in-hdf5', help='''
    Genotype matrix in HDF5 format which is
    converted from BGEN by ../bgen2hdf5/ .
''')
parser.add_argument('--snp-list-yaml', help='''
    YAML to specify the list of SNPs to work with.
    Example:
    trait1:
        load_method: 'ld_clump'
        params:
            gwas_yaml:
                gwas:
                    path: 'test_inputs/test_gwas1.txt'
                    param:
                      header: 0
                      sep: ' '
                varcol: 'variant'
                betacol: 'beta'
                pvalcol: 'pval'
                ld_clump: 'test_inputs/test_gwas1.clump'
            snp_map: 'path_to_snp_map'
            pval_cutoff: 0.05
    trait2:
        load_method: 'from_list'
        params:
            list_path: 'path_to_list'
''')
parser.add_argument('--snp-list-cache', type=str, help='''
    Path to PGZ file (pickle.gz) file to cache
    the information loaded from --snp-list-yaml.
    Require pgz as extension.
''')
parser.add_argument('--father-phenotype-yaml', help='''
    Observed phenotype of father
    with all loading specified in YAML:
    path: 'path_to_file'
    param:   # kwargs in pandas.read_csv
        header: 0
        sep: ','
    col:  # column name of phenotype of interest
        - 'alzheimer_disease'
        - 'heart_disease'
    indiv_col: 'eid'  # column name of individual id
''')
parser.add_argument('--mother-phenotype-yaml', help='''
    Observed phenotype of mother
    with all loading specified in YAML
    (follow the same structure as father's)
''')
parser.add_argument('--shared-covariate-yaml', default=None, help='''
    Covariate shared by father and mother
    with all loading specified in YAML
    (follow the same structure as phenotype's)
''')
parser.add_argument('--indiv-npy', help='''
    NPY containing the list of individuals to load from genotype files
    (order does mater)
''')
parser.add_argument('--pheno-npy', help='''
    NPY containing the list of phenotypes to load from genotype files
    (mainly for the variant dict, to maintain the trait-specific pos_df)
    (order does mater)
''')
parser.add_argument('--load-mode', type=str, default='phenotype', help='''
    Loading mode: phenotype or genotype
''')
parser.add_argument('--output-prefix', help='''
    Prefix of output.
''')

args = parser.parse_args()

import logging, sys
import torch
import numpy as np
sys.path.insert(0, '../logistic_gpu')
import table_reader
import geno_hdf5_reader
import snp_list_reader
import haplotype_imputer
import gzip, pickle

# configing util
logging.basicConfig(
    level = logging.INFO,
    stream = sys.stderr,
    format = '%(asctime)s  %(message)s',
    datefmt = '%Y-%m-%d %I:%M:%S %p'
)

if args.load_mode == 'phenotype':
    logging.info('Loading observed phenotypes')
    df_father = table_reader.load_table_from_yaml(
        args.father_phenotype_yaml,
        rename_cols=True
    )
    df_mother = table_reader.load_table_from_yaml(
        args.mother_phenotype_yaml,
        rename_cols=True
    )

    df_covar = None
    if args.shared_covariate_yaml is not None:
        logging.info('Loading covariates')
        df_covar = table_reader.load_table_from_yaml(
            args.shared_covariate_yaml,
            rename_cols=True
        )
        # breakpoint()
        df_covar = table_reader.standardize_columns(df_covar, except_cols=['individual_id'])
elif args.load_mode == 'genotype':
    logging.info('Loading phenotype and individual list')
    phenotypes = np.load(args.pheno_npy, allow_pickle=True)
    individuals = np.load(args.indiv_npy, allow_pickle=True)
    logging.info('Loading variant list')
    snp_loader = snp_list_reader.snpLoader(args.snp_list_yaml)
    snp_loader.load(args.snp_list_cache)

if args.load_mode == 'phenotype':
    logging.info('Loading individual list')
    hap_indiv_df = geno_hdf5_reader.load_indiv_as_df(args.genotype_in_hdf5)
elif args.load_mode == 'genotype':
    logging.info('Loading haplotypes')
    h1, h2, hap_indiv_df, hap_pos_df = geno_hdf5_reader.load_haplotypes_by_position(
        args.genotype_in_hdf5, snp_loader.snp_pos_dict
    )

logging.info('Pre-loading: mode = {}'.format(args.load_mode))
imputer = haplotype_imputer.HaploImputer()
if args.load_mode == 'phenotype':
    imputer.impute_preload_pheno_and_covar(
        df_father, df_mother, hap_indiv_df,
        args.output_prefix,
        df_covar=df_covar
    )
elif args.load_mode == 'genotype':
    imputer.impute_preload_genotype(
        h1, h2, hap_indiv_df, hap_pos_df, phenotypes, individuals, args.output_prefix
    )


from view.warehouse import WarehouseView
from controller import BaseController
from model.warehouse import Warehouse
from sqlalchemy.orm import Session
from view.common import View

class WarehouseController(BaseController):
    def __init__(self, session: Session, view: View):
        super().__init__(session, Warehouse, WarehouseView('warehouses', view))

    @staticmethod
    def _prompt_values_for_input(item: object = None, for_update: bool = False):
        prompts = ['Address', 'Phone number', 'City ID']
        values = [item.address, item.phone_number, item.city_id] \
            if isinstance(item, Warehouse) else None
        return prompts, values

    @staticmethod
    def _create_dict_from_input(input_items: [dict]):
        address = phone_number = city_id = None
        for item in input_items:
            if item['name'] == 'Address':
                address = item['value']
            elif item['name'] == 'Phone number':
                phone_number = item['value']
            elif item['name'] == 'City ID':
                city_id = int(item['value'])
        return dict(address=address, phone_number=phone_number, city_id=city_id)


import json
# pylint: disable=missing-function-docstring, protected-access, unused-import
import uuid

import pytest
from gsy_framework.constants_limits import DATE_TIME_FORMAT, ConstSettings

from gsy_e.models.strategy.external_strategies.load import LoadHoursExternalStrategy
from tests.strategies.external.fixtures import future_market_fixture  # noqa
from tests.strategies.external.fixtures import settlement_market_fixture  # noqa
from tests.strategies.external.utils import (
    assert_bid_offer_aggregator_commands_return_value,
    check_external_command_endpoint_with_correct_payload_succeeds,
    create_areas_markets_for_strategy_fixture)

@pytest.fixture(name="external_load")
def external_load_fixture():
    ConstSettings.MASettings.MARKET_TYPE = 2
    yield create_areas_markets_for_strategy_fixture(LoadHoursExternalStrategy(100))
    ConstSettings.MASettings.MARKET_TYPE = 1

class TestLoadForecastExternalStrategy:

    @staticmethod
    def test_bid_succeeds(external_load):
        arguments = {"price": 1, "energy": 2}
        check_external_command_endpoint_with_correct_payload_succeeds(external_load,
                                                                      "bid", arguments)

    @staticmethod
    def test_list_bids_succeeds(external_load):
        check_external_command_endpoint_with_correct_payload_succeeds(external_load,
                                                                      "list_bids", {})

    @staticmethod
    def test_delete_bid_succeeds(external_load):
        check_external_command_endpoint_with_correct_payload_succeeds(external_load,
                                                                      "delete_bid", {})

    @staticmethod
    def test_bid_aggregator(external_load):
        external_load.state._energy_requirement_Wh[
            external_load.spot_market.time_slot] = 1000.0
        return_value = external_load.trigger_aggregator_commands(
            {
                "type": "bid",
                "price": 200.0,
                "energy": 0.5,
                "transaction_id": str(uuid.uuid4())
            }
        )
        assert_bid_offer_aggregator_commands_return_value(return_value, False)

    @staticmethod
    def test_offer_aggregator_can_not_place_offer_to_spot_market(external_load):
        return_value = external_load.trigger_aggregator_commands(
            {
                "type": "offer",
                "price": 200.0,
                "energy": 0.5,
                "transaction_id": str(uuid.uuid4())
            }
        )
        assert return_value["status"] == "error"
        assert "Offer not supported for Loads on spot markets." in return_value["error_message"]

    @staticmethod
    def test_bid_aggregator_places_settlement_bid(external_load, settlement_market):
        unsettled_energy_kWh = 0.5
        external_load.area._markets.settlement_market_ids = [settlement_market.id]
        external_load.area._markets.settlement_markets = {
            settlement_market.time_slot: settlement_market}
        external_load.state._forecast_measurement_deviation_kWh[settlement_market.time_slot] = (
            unsettled_energy_kWh)
        external_load.state._unsettled_deviation_kWh[settlement_market.time_slot] = (
            unsettled_energy_kWh)
        return_value = external_load.trigger_aggregator_commands(
            {
                "type": "bid",
                "price": 200.0,
                "energy": unsettled_energy_kWh,
                "time_slot": settlement_market.time_slot.format(DATE_TIME_FORMAT),
                "transaction_id": str(uuid.uuid4())
            }
        )
        assert return_value["status"] == "ready"
        assert len(settlement_market.bids.values()) == 1
        assert list(settlement_market.bids.values())[0].energy == unsettled_energy_kWh

    @staticmethod
    def test_bid_aggregator_places_future_bid(external_load, future_markets):
        future_energy_kWh = 0.5
        external_load.area._markets.future_markets = future_markets

        for time_slot in future_markets.market_time_slots:
            external_load.state._energy_requirement_Wh[time_slot] = future_energy_kWh * 1000
            return_value = external_load.trigger_aggregator_commands(
                {
                    "type": "bid",
                    "price": 200.0,
                    "energy": future_energy_kWh,
                    "time_slot": time_slot.format(DATE_TIME_FORMAT),
                    "transaction_id": str(uuid.uuid4())
                }
            )

            assert return_value["status"] == "ready"
            bid_id = json.loads(return_value["bid"])["id"]
            assert future_markets.bids[bid_id].energy == future_energy_kWh
        assert len(future_markets.bids.values()) == len(future_markets.market_time_slots)

    @staticmethod
    def test_offer_aggregator_places_settlement_offer(external_load, settlement_market):
        unsettled_energy_kWh = 0.5
        external_load.area._markets.settlement_market_ids = [settlement_market.id]
        external_load.area._markets.settlement_markets = {
            settlement_market.time_slot: settlement_market}
        external_load.state._forecast_measurement_deviation_kWh[settlement_market.time_slot] = (
            -1 * unsettled_energy_kWh)
        external_load.state._unsettled_deviation_kWh[settlement_market.time_slot] = (
            unsettled_energy_kWh)
        return_value = external_load.trigger_aggregator_commands(
            {
                "type": "offer",
                "price": 200.0,
                "energy": unsettled_energy_kWh,
                "time_slot": settlement_market.time_slot.format(DATE_TIME_FORMAT),
                "transaction_id": str(uuid.uuid4())
            }
        )
        assert return_value["status"] == "ready"
        assert len(settlement_market.offers.values()) == 1
        assert list(settlement_market.offers.values())[0].energy == unsettled_energy_kWh

    @staticmethod
    def test_bid_aggregator_succeeds_with_warning_if_dof_are_disabled(external_load):
        """
        The bid_aggregator command succeeds, but it shows a warning if Degrees of Freedom are
        disabled and nevertheless provided.
        """
        external_load.simulation_config.enable_degrees_of_freedom = False
        external_load.state._energy_requirement_Wh[
            external_load.spot_market.time_slot] = 1000.0
        return_value = external_load.trigger_aggregator_commands({
            "type": "bid",
            "price": 200.0,
            "energy": 0.5,
            "attributes": {"energy_type": "PV"},
            "requirements": [{"price": 12}],
            "transaction_id": str(uuid.uuid4())})

        assert_bid_offer_aggregator_commands_return_value(return_value, False)
        assert return_value["message"] == (
            "The following arguments are not supported for this market and have been removed from "
            "your order: ['requirements', 'attributes'].")

    @staticmethod
    def test_delete_bid_aggregator(external_load):
        bid = external_load.post_bid(external_load.spot_market, 200.0, 1.0)
        return_value = external_load.trigger_aggregator_commands(
            {
                "type": "delete_bid",
                "bid": str(bid.id),
                "transaction_id": str(uuid.uuid4())
            }
        )
        assert return_value["status"] == "ready"
        assert return_value["command"] == "bid_delete"
        assert return_value["deleted_bids"] == [bid.id]

    @staticmethod
    def test_delete_bid_aggregator_deletes_bid_from_future_market(external_load, future_markets):
        external_load.area._markets.future_markets = future_markets
        for time_slot in future_markets.market_time_slots:
            bid = external_load.post_bid(
                external_load.area.future_markets, price=200.0, energy=1.0,
                time_slot=time_slot)

            return_value = external_load.trigger_aggregator_commands(
                {
                    "type": "delete_bid",
                    "offer": str(bid.id),
                    "transaction_id": str(uuid.uuid4()),
                    "time_slot": time_slot.format(DATE_TIME_FORMAT)
                }
            )
            assert return_value["status"] == "ready"
            assert return_value["command"] == "bid_delete"
            assert return_value["deleted_bids"] == [bid.id]

    @staticmethod
    def test_list_bids_aggregator(external_load):
        bid = external_load.post_bid(external_load.spot_market, 200.0, 1.0)

        return_value = external_load.trigger_aggregator_commands(
            {
                "type": "list_bids",
                "transaction_id": str(uuid.uuid4())
            }
        )
        assert return_value["status"] == "ready"
        assert return_value["command"] == "list_bids"
        assert return_value["bid_list"] == [
            {"id": bid.id, "price": bid.price, "energy": bid.energy}
        ]


from django.conf.urls import url

from users import views

urlpatterns = [
    url(r'^login/$', views.login, name='login'),
    url(r'^register/$', views.register, name='register'),
    url(r'^person/$', views.person, name='person'),
    url(r'^send_sms/$', views.send_sms, name='send_sms'),
    url(r'^address_manage/$', views.address_manage, name='address_manage'),
    url(r'^evaluation_manage/$', views.evaluation_manage, name='evaluation_manage'),
    url(r'^order_manage/$', views.order_manage, name='order_manage'),
    url(r'^collection_manage/$', views.collection_manage, name='collection_manage'),
    url(r'^order_info/(?P<order_id>\d+)$', views.order_info, name='order_info'),
    url(r'^logout/$', views.logout, name='logout'),
    url(r'^add_address/$', views.add_address, name='add_address'),
    url(r'^set_default_address/(?P<address_id>\d+)/$', views.set_default_address, name='set_default_address'),
    url(r'^edit_address/$', views.edit_address, name='edit_address'),
    url(r'^del_address/(?P<address_id>\d+)/$', views.del_address, name='del_address'),
]


import time
from typing import List, Optional

from bitstream import c_bit, c_float, c_uint, WriteStream
from ..game_object import broadcast, CallbackID, Config, EB, EF, EI, EO, EP, GameObject, OBJ_NONE, Player, StatsObject
from ..game_object import c_int as c_int_
from ..game_object import c_uint as c_uint_
from ..world import server
from ..math.vector import Vector3
from .char import TerminateType
from .mission import TaskType
from .scripted_activity import ScriptedActivityComponent

class RebuildState:
	Open = 0
	Completed = 2
	Resetting = 4
	Building = 5
	Incomplete = 6

class FailReason:
	NotGiven = 0
	OutOfImagination = 1
	CanceledEarly = 2
	BuildEnded = 3

ACTIVATOR_LOT = 6604

class RebuildComponent(ScriptedActivityComponent):
	object: StatsObject

	def __init__(self, obj: GameObject, set_vars: Config, comp_id: int):
		super().__init__(obj, set_vars, comp_id)
		self.object.rebuild = self
		db_entry = server.db.rebuild_component[comp_id]
		self.complete_time = set_vars.get("rebuild_complete_time", db_entry[0])
		self.smash_time = set_vars.get("rebuild_smash_time", db_entry[1])
		self.reset_time = db_entry[2]
		self.imagination_cost = db_entry[3]
		self.callback_handles: List[CallbackID] = []
		self.rebuild_start_time: float = 0
		self.last_progress: float = 0
		self._flags["_rebuild_state"] = "_rebuild_flag"
		self._flags["success"] = "_rebuild_flag"
		self._flags["enabled"] = "_rebuild_flag"
		self._rebuild_state = RebuildState.Open
		self.success = False
		self.enabled = True
		self.activity_id = set_vars.get("activity_id", db_entry[4])
		if self.activity_id in server.db.activity_rewards:
			self.completion_rewards = server.db.activity_rewards[self.activity_id][0][1]
		else:
			self.completion_rewards = None, None, None

		if "rebuild_activator_position" in set_vars:
			self.rebuild_activator_position = set_vars["rebuild_activator_position"]
		else:
			self.rebuild_activator_position = Vector3(self.object.physics.position)

	def on_startup(self) -> None:
		server.spawn_object(ACTIVATOR_LOT, {"parent": self.object, "position": self.rebuild_activator_position})
		self.object.handle("rebuild_init", silent=True)

	@property
	def rebuild_state(self) -> int:
		return self._rebuild_state

	@rebuild_state.setter
	def rebuild_state(self, value: int) -> None:
		player = server.get_object(list(self.activity_values)[0])
		self.rebuild_notify_state(self.rebuild_state, value, player)
		self._rebuild_state = value

	def serialize(self, out: WriteStream, is_creation: bool) -> None:
		super().serialize(out, is_creation)
		if self.flag("_rebuild_flag", out, is_creation):
			out.write(c_uint(self.rebuild_state))
			out.write(c_bit(self.success))
			out.write(c_bit(self.enabled))
			if self.rebuild_state == RebuildState.Building:
				out.write(c_float(time.perf_counter() - self.rebuild_start_time + self.last_progress))
			else:
				out.write(c_float(self.last_progress))
			out.write(c_float(0))
			if is_creation:
				out.write(c_bit(False))
				out.write(self.rebuild_activator_position)
				out.write(c_bit(True))

	def on_use(self, player: Player, multi_interact_id: Optional[int]) -> bool:
		assert multi_interact_id is None
		if self.rebuild_state not in (RebuildState.Open, RebuildState.Incomplete):
			return False
		for handle in self.callback_handles:
			self.object.cancel_callback(handle)
		self.callback_handles.clear()
		self.add_player(player)
		self.rebuild_state = RebuildState.Building
		player.char.rebuilding = 1
		self.enable_rebuild(enable=self.enabled, fail=False, success=self.success, duration=0, user=player)
		self.rebuild_start_time = time.perf_counter()
		drain_interval = self.complete_time/self.imagination_cost
		remaining_cost = int((self.complete_time - self.last_progress) // drain_interval)
		for i in range(remaining_cost):
			self.callback_handles.append(self.object.call_later(self.last_progress % drain_interval + drain_interval * i, self._drain_imagination, player))
		for handler in self.object.handlers("complete_rebuild"):
			self.callback_handles.append(self.object.call_later(self.complete_time-self.last_progress, handler, player))
		return True

	def _drain_imagination(self, player: Player) -> None:
		if player.stats.imagination == 0:
			self.on_rebuild_cancel(early_release=False, user=player)
		player.stats.imagination -= 1

	def on_complete_rebuild(self, player: Player) -> None:
		self.rebuild_state = RebuildState.Completed
		self.success = True
		self.enabled = False
		player.char.rebuilding = 0
		self.enable_rebuild(enable=self.enabled, fail=False, success=self.success, duration=0, user=player)
		self.object.render.play_f_x_effect(name=b"BrickFadeUpVisCompleteEffect", effect_type="create", effect_id=507)
		player.render.play_animation("rebuild-celebrate")

		for child_id in self.object.children:
			child = server.game_objects[child_id]
			if child.lot == ACTIVATOR_LOT:
				server.replica_manager.destruct(child)
				break
		self.callback_handles.append(self.object.call_later(self.smash_time, self.smash_rebuild))

		player.char.mission.update_mission_task(TaskType.QuickBuild, self.activity_id)

		# drop rewards
		self.object.physics.drop_rewards(*self.completion_rewards, player)

	def smash_rebuild(self) -> None:
		self.object.stats.die(death_type="", direction_relative_angle_xz=0, direction_relative_angle_y=0, direction_relative_force=10, killer=OBJ_NONE)
		server.replica_manager.destruct(self.object)

	def on_rebuild_cancel(self, early_release:bool=EB, user:Player=EP) -> None:
		if self.rebuild_state == RebuildState.Building:
			for handle in self.callback_handles:
				self.object.cancel_callback(handle)
			self.callback_handles.clear()
			self.last_progress += time.perf_counter() - self.rebuild_start_time
			self.rebuild_state = RebuildState.Incomplete
			self.remove_player(user)
			user.char.rebuilding = 0
			if early_release:
				fail_reason = FailReason.CanceledEarly
			else:
				fail_reason = FailReason.OutOfImagination
			self.enable_rebuild(enable=False, fail=True, success=self.success, fail_reason=fail_reason, duration=self.last_progress, user=user)
			user.char.terminate_interaction(terminator=self.object, type=TerminateType.FromInteraction)
			self.callback_handles.append(self.object.call_later(self.reset_time, self.smash_rebuild))

	@broadcast
	def enable_rebuild(self, enable:bool=EB, fail:bool=EB, success:bool=EB, fail_reason:c_uint_=FailReason.NotGiven, duration:float=EF, user:GameObject=EO) -> None:
		pass

	@broadcast
	def rebuild_notify_state(self, prev_state:c_int_=EI, state:c_int_=EI, player:GameObject=EO) -> None:
		pass


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

from kladr.kladdress import Kladdress
from main.web_responses import *
#import constants as cs
from django.forms.models import model_to_dict
import logging

log = logging.getLogger(__name__)

def index(request, target=None):
    a_handlers = {
        'getRegions': get_list,
        'getList': get_list,
        'getName': get_name,
        'getPathCodes': get_path_codes,
    }
    try:
        res = a_handlers[target](request)
    except KeyError:
        res = ret_error('WRONG ACTION {}'.format(target))
    return res

def get_list(request):
    code = request.REQUEST.get('code')
    if not request.REQUEST.get('full'):
        fields = ('code', 'name')
    else:
        fields = None
    d = Kladdress().get_list(code,request.REQUEST.get('query', ''))
    data = [model_to_dict(x) for x in d]
    if fields:
        for k,data_item in enumerate(data):
            item = {}
            try:
                for x in fields: item[x] = data_item[x]
            except (KeyError, IndexError):
                log.error('wrong field requested: %s' % field)
            data[k] = item
    return ret_plain(data)

def get_name(request):
    code = request.REQUEST.get('code')
    d = Kladdress().get_name(code)['name']
    return ret_plain(d)

def get_path_codes(request):
    code = request.REQUEST.get('code')
    d = Kladdress().get_name(code)['codes']
    return ret_plain(d)


from collections import namedtuple

City = namedtuple('City', 'name country population coordinates')
tokyo_info = ('Tokyo', 'JP', 36.933, (35.689722, 139.691667))

"""_fields 类属性、 类方法_make(iterable) 和 实例方法 _asdict()"""

columns = City._fields
tokyo = City._make(tokyo_info)
t_dict = tokyo._asdict()
print(columns)
print(tokyo)
print(t_dict)
print(t_dict.get("coordinates"))


from PyQt4 import QtCore, QtGui, Qt

def strToQColor (s):
	s = str (s)
	if s:
		sa = map (lambda x: int (x.strip ()), s.strip ().split (','))
	else:
		sa = [255, 255, 255]
	return QtGui.QColor (sa[0], sa[1], sa[2])

def qColorToStr (c):
	return "%d,%d,%d" % (c.red (), c.green (), c.blue ())

def dict2lua (d):
	data = ''
	for k, v in d.iteritems ():
		if isinstance (v, basestring):
			data += '%s="%s";' % (k, v)
		else:
			data += '%s=%.1f;' % (k, v)

	data = '{%s}' % data
	return data