from tables import *
import numpy as np
import matplotlib.pyplot as plt
import matplotlib
import time
import redpy.cluster
import os
import glob
from obspy import UTCDateTime
from bokeh.plotting import figure, output_file, save, gridplot
from bokeh.models import HoverTool, ColumnDataSource, OpenURL, TapTool, Range1d

def createPlots(rtable, ftable, ttable, opt):

    """
    Creates all output plots (core images, family plots, and two bokeh .html plots)

    rtable: Repeater table
    ftable: Families table
    opt: Options object describing station/run parameters

    """

    if len(rtable)>1:
        plotTimelines(rtable, ftable, ttable, opt)
        if np.sum(ftable.cols.printme[:]):
            printCatalog(rtable, ftable, opt)
            plotCores(rtable, ftable, opt)
            plotFamilies(rtable, ftable, opt)
            ftable.cols.printme[:] = np.zeros((len(ftable),))
            ftable.cols.lastprint[:] = np.arange(len(ftable))
    else:
        print('Nothing to plot!')

    # Rename any .tmp files
    tmplist = glob.glob('./{0}/clusters/*.tmp'.format(opt.groupName))
    for tmp in tmplist:
        os.rename(tmp,tmp[0:-4])

def plotTimelines(rtable, ftable, ttable, opt):

    """
    Creates the primary .html Bokeh timelines

    rtable: Repeater table
    ftable: Families table
    opt: Options object describing station/run parameters

    """

    dt = rtable.cols.startTimeMPL[:]
    fi = np.nanmean(rtable.cols.FI[:], axis=1)
    longevity = ftable.cols.longevity[:]
    famstarts = ftable.cols.startTime[:]
    alltrigs = ttable.cols.startTimeMPL[:]

    # Create histogram of events/dybin
    histT, hT = np.histogram(alltrigs, bins=np.arange(min(alltrigs),
        max(alltrigs+opt.dybin), opt.dybin))
    histR, hR = np.histogram(dt, bins=np.arange(min(alltrigs),
        max(alltrigs+opt.dybin), opt.dybin))

    # Create histogram of events/hrbin
    histTr, hTr = np.histogram(alltrigs, bins=np.arange(max(alltrigs)-opt.recplot,
        max(alltrigs+opt.hrbin/24), opt.hrbin/24))
    histRr, hRr = np.histogram(dt, bins=np.arange(max(alltrigs)-opt.recplot,
        max(alltrigs+opt.hrbin/24), opt.hrbin/24))

    oTOOLS = ['pan,box_zoom,reset,resize,save,tap']

    o0 = figure(tools=oTOOLS, plot_width=1250, plot_height=250, x_axis_type='datetime')
    if opt.dybin>=1:
        o0.title = 'Repeaters vs. Orphans by {:.1f} Day Bin'.format(opt.dybin)
    else:
        o0.title = 'Repeaters vs. Orphans by {:.1f} Hour Bin'.format(opt.dybin*24)
    o0.grid.grid_line_alpha = 0.3
    o0.xaxis.axis_label = 'Date'
    o0.yaxis.axis_label = 'Events'

    o0.line(matplotlib.dates.num2date(hT[0:-1]+opt.dybin/2), histT-histR, color='black',
        legend='Orphans')
    o0.line(matplotlib.dates.num2date(hR[0:-1]+opt.dybin/2), histR, color='red',
        legend='Repeaters')
    o0.legend.orientation = "top_left"

    o0r = figure(tools=oTOOLS, plot_width=1250, plot_height=250, x_axis_type='datetime')
    if opt.hrbin<24:
        o0r.title = 'Last {0} Days: Repeaters vs. Orphans by {1:.1f} Hour Bin'.format(
            opt.recplot, opt.hrbin)
    else:
        o0r.title = 'Last {0} Days: Repeaters vs. Orphans by {1:.1f} Day Bin'.format(
            opt.recplot, opt.hrbin/24)
    o0r.grid.grid_line_alpha = 0.3
    o0r.xaxis.axis_label = 'Date'
    o0r.yaxis.axis_label = 'Events'

    o0r.line(matplotlib.dates.num2date(hTr[0:-1]+opt.hrbin/48), histTr-histRr,
        color='black', legend='Orphans')
    o0r.line(matplotlib.dates.num2date(hRr[0:-1]+opt.hrbin/48), histRr, color='red',
        legend='Repeaters')
    o0r.legend.orientation = "top_left"

    o1 = figure(plot_width=1250, plot_height=250, x_axis_type='datetime',
        x_range=o0.x_range)
    o1.title = 'Frequency Index'
    o1.grid.grid_line_alpha = 0.3
    o1.xaxis.axis_label = 'Date'
    o1.yaxis.axis_label = 'FI'
    o1.circle(matplotlib.dates.num2date(dt), fi, color='red', line_alpha=0,
        size=3, fill_alpha=0.5)

    o1r = figure(plot_width=1250, plot_height=250, x_axis_type='datetime',
        x_range=o0r.x_range)
    o1r.title = 'Frequency Index'
    o1r.grid.grid_line_alpha = 0.3
    o1r.xaxis.axis_label = 'Dater'
    o1r.yaxis.axis_label = 'FI'
    # Put invisible points in for case that there are no events
    o1r.circle(matplotlib.dates.num2date(hTr[0:2]), [1, 1], line_alpha=0, fill_alpha=0)
    o1r.circle(matplotlib.dates.num2date(dt[dt>(max(alltrigs)-opt.recplot)]),
        fi[dt>(max(alltrigs)-opt.recplot)], color='red', line_alpha=0,
        size=3, fill_alpha=0.5)

    o2 = figure(tools=oTOOLS, plot_width=1250, plot_height=250, x_axis_type='datetime',
        x_range=o0.x_range, y_axis_type='log', y_range=[0.1, alltrigs[-1]-alltrigs[0]])
    o2.title = 'Cluster Longevity'
    o2.grid.grid_line_alpha = 0.3
    o2.xaxis.axis_label = 'Date'
    o2.yaxis.axis_label = 'Days'
    for n in range(len(famstarts)):
        o2.line((matplotlib.dates.num2date(famstarts[n]), matplotlib.dates.num2date(
            famstarts[n]+longevity[n])), (longevity[n], longevity[n]), color='red',
            line_alpha=0.5)

    o2r = figure(tools=oTOOLS, plot_width=1250, plot_height=250, x_axis_type='datetime',
        x_range=o0r.x_range, y_axis_type='log', y_range=[0.1, alltrigs[-1]-alltrigs[0]])
    o2r.title = 'Cluster Longevity'
    o2r.grid.grid_line_alpha = 0.3
    o2r.xaxis.axis_label = 'Date'
    o2r.yaxis.axis_label = 'Days'
    # Put invisible points in for case that there are no events
    o2r.circle(matplotlib.dates.num2date(hTr[0:2]), [1, 1], line_alpha=0, fill_alpha=0)
    for n in range(len(famstarts)):
        if (max(alltrigs)-opt.recplot)<=famstarts[n]:
            o2r.line((matplotlib.dates.num2date(famstarts[n]), matplotlib.dates.num2date(
                famstarts[n]+longevity[n])), (longevity[n], longevity[n]), color='red',
                line_alpha=0.5)
        elif (max(alltrigs)-opt.recplot)<=famstarts[n]+longevity[n]:
            o2r.line((matplotlib.dates.num2date(hTr[0]), matplotlib.dates.num2date(
                famstarts[n]+longevity[n])), (longevity[n], longevity[n]), color='red',
                line_alpha=0.5)
            o2r.text(time.mktime(matplotlib.dates.num2date(
                    hTr[0]).timetuple())*1000 - 28799000, longevity[n], text=['<'],
                    text_font_size='9pt', text_baseline='middle', text_color='red',
                    text_alpha=0.5)

    # Build hover to show an image of the cluster core
    hover = HoverTool(
        tooltips="""

            Cluster ID:
            @famnum

        """, names=["patch"])

    TOOLS = [hover,'pan,box_zoom,reset,resize,save,tap']

    # Build hover to show an image of the cluster core
    hoverr = HoverTool(
        tooltips="""

            Cluster ID:
            @famnum

        """, names=["patchr"])

    TOOLSrec = [hoverr,'pan,box_zoom,reset,resize,save,tap']

    p1 = figure(tools=TOOLS, plot_width=1250, plot_height=500, x_axis_type='datetime',
        x_range=o0.x_range)
    p1.title = 'Occurrence Timeline (Color by Events per Hour)'
    p1.grid.grid_line_alpha = 0.3
    p1.xaxis.axis_label = 'Date'
    p1.yaxis.axis_label = 'Cluster by Date ({}+ Members)'.format(opt.minplot)

    r1 = figure(tools=TOOLSrec, plot_width=1250, plot_height=500, x_axis_type='datetime',
        x_range=o0r.x_range)
    r1.title = 'Occurrence Timeline (Color by Events per Hour)'
    r1.grid.grid_line_alpha = 0.3
    r1.xaxis.axis_label = 'Date'
    r1.yaxis.axis_label = 'Cluster by Date'

    # Steal YlOrRd (len=256) colormap from matplotlib
    colormap = matplotlib.cm.get_cmap('YlOrRd')
    bokehpalette = [matplotlib.colors.rgb2hex(m) for m in colormap(
        np.arange(colormap.N)[::-1])]

    # Build the lists and dictionaries
    n = 0
    m = 0
    for clustNum in range(ftable.attrs.nClust):

        members = np.fromstring(ftable[clustNum]['members'], dtype=int, sep=' ')

        # Create histogram of events/hour
        hist, h = np.histogram(dt[members], bins=np.arange(min(dt[members]),
            max(dt[members]+1.0/24), 1.0/24))
        d1 = matplotlib.dates.num2date(h[hist>0])
        d2 = matplotlib.dates.num2date(h[hist>0]+1.0/24)
        histlog = np.log10(hist[hist>0])
        ind = [int(min(255,255*(i/2))) for i in histlog]
        colors = [bokehpalette[i] for i in ind]

        if len(dt[members]) >= opt.minplot:

            # Date is required as datenum
            p1.line((matplotlib.dates.num2date(min(dt[members])),
                matplotlib.dates.num2date(max(dt[members]))), (n, n),
                color='black')

            p1.quad(top=n+0.3, bottom=n-0.3, left=d1, right=d2,
                color=colors)

            # Text doesn't understand datetimes, need to convert to a number and subtract
            # about 8 hours
            p1.text(time.mktime(matplotlib.dates.num2date(
                 max(dt[members])).timetuple())*1000 - 28799000, n,
                 text=['   {}'.format(len(dt[members]))], text_font_size='9pt',
                 text_baseline='middle')

            # Build source for hover patches
            fnum = clustNum
            if n == 0:
                xs=[[matplotlib.dates.num2date(min(dt[members])-1),
                    matplotlib.dates.num2date(min(dt[members])-1),
                    matplotlib.dates.num2date(max(dt[members])+1),
                    matplotlib.dates.num2date(max(dt[members])+1)]]
                ys=[[n-0.5, n+0.5, n+0.5, n-0.5]]
                famnum=[fnum]
            else:
                xs.append([matplotlib.dates.num2date(min(dt[members])-1),
                           matplotlib.dates.num2date(min(dt[members])-1),
                           matplotlib.dates.num2date(max(dt[members])+1),
                           matplotlib.dates.num2date(max(dt[members])+1)])
                ys.append([n-0.5, n+0.5, n+0.5, n-0.5])
                famnum.append([fnum])

            n = n+1

        if max(dt[members])>hRr[0]:

            if min(dt[members])<hRr[0]:
                r1.line((matplotlib.dates.num2date(hRr[0]-opt.hrbin/6),
                matplotlib.dates.num2date(max(dt[members]))), (m, m),
                    color='black')
                r1.text(time.mktime(matplotlib.dates.num2date(
                    hRr[0]-opt.hrbin/6).timetuple())*1000 - 28799000, m, text=['<'],
                    text_font_size='9pt', text_baseline='middle')

                idx = np.where(h[hist>0]>hRr[0])[0]

            else:
                r1.line((matplotlib.dates.num2date(min(dt[members])),
                    matplotlib.dates.num2date(max(dt[members]))), (m, m),
                    color='black')
                idx = np.arange(len(d1))

            r1.quad(top=m+0.3, bottom=m-0.3, left=np.array(d1)[idx],
                right=np.array(d2)[idx], color=np.array(colors)[idx])

            # Text doesn't understand datetimes, need to convert to a number and subtract
            # about 8 hours
            r1.text(time.mktime(matplotlib.dates.num2date(
                max(dt[members])).timetuple())*1000 - 28799000, m,
                text=['   {}'.format(len(dt[members]))], text_font_size='9pt',
                text_baseline='middle')

            # Build source for hover patches
            fnumr = clustNum
            if m == 0:
                xsr=[[matplotlib.dates.num2date(max(min(dt[members]),hRr[0])-1),
                    matplotlib.dates.num2date(max(min(dt[members]),hRr[0])-1),
                    matplotlib.dates.num2date(max(dt[members])+1),
                    matplotlib.dates.num2date(max(dt[members])+1)]]
                ysr=[[m-0.5, m+0.5, m+0.5, m-0.5]]
                famnumr=[fnumr]
            else:
                xsr.append([matplotlib.dates.num2date(max(min(dt[members]),hRr[0])-1),
                           matplotlib.dates.num2date(max(min(dt[members]),hRr[0])-1),
                           matplotlib.dates.num2date(max(dt[members])+1),
                           matplotlib.dates.num2date(max(dt[members])+1)])
                ysr.append([m-0.5, m+0.5, m+0.5, m-0.5])
                famnumr.append([fnumr])
            m = m+1

    if n > 0:
        # Patches allow hovering for image of core and cluster number
        source = ColumnDataSource(data=dict(xs=xs, ys=ys, famnum=famnum))
        p1.patches(xs=xs, ys=ys, source=source, name="patch", alpha=0)

        # Tapping on one of the patches will open a window to a file with more information
        # on the cluster in question.
        url = "./clusters/@famnum.html"
        renderer = p1.select(name="patch")[0]
        renderer.nonselection_glyph=renderer.glyph.clone()
        taptool = p1.select(dict(type=TapTool))[0]
        taptool.names.append("patch")
        taptool.callback = OpenURL(url=url)

        if n > 30:
            p1.set(plot_height=n*15, y_range=Range1d(-1, n))

    else:
        p1.circle(matplotlib.dates.num2date(hTr[0:2]), [0, 0], line_alpha=0, fill_alpha=0)

    if m > 0:
        sourcer = ColumnDataSource(data=dict(xs=xsr, ys=ysr, famnum=famnumr))
        r1.patches(xs=xsr, ys=ysr, source=sourcer, name="patchr", alpha=0)

        url = "./clusters/@famnum.html"
        renderer = r1.select(name="patchr")[0]
        renderer.nonselection_glyph=renderer.glyph.clone()
        taptool = r1.select(dict(type=TapTool))[0]
        taptool.names.append("patchr")
        taptool.callback = OpenURL(url=url)

        if m > 30:
            r1.set(plot_height=m*15, y_range=Range1d(-1, m))

    else:
        r1.circle(matplotlib.dates.num2date(hTr[0:2]), [0, 0], line_alpha=0, fill_alpha=0)

    o = gridplot([[o0],[o1],[p1],[o2]])
    o_recent = gridplot([[o0r],[o1r],[r1],[o2r]])

    output_file('{}/overview.html'.format(opt.groupName),
        title='{} Overview'.format(opt.title))
    save(o)

    output_file('{}/overview_recent.html'.format(opt.groupName),
            title='{0} Overview - Last {1:.1f} Days'.format(opt.title,opt.recplot))
    save(o_recent)

def plotCores(rtable, ftable, opt):

    """
    Plots core waveforms as .gif for hovering in timeline

    rtable: Repeater table
    ftable: Families table
    opt: Options object describing station/run parameters

    """

    for n in range(len(ftable))[::-1]:
        if ftable.cols.lastprint[n] != n and ftable.cols.printme[n] == 0:
            os.rename('{0}/clusters/{1}.gif'.format(opt.groupName,
                ftable.cols.lastprint[n]), '{0}/clusters/{1}.gif.tmp'.format(
                opt.groupName, n))
            os.rename('{0}/clusters/fam{1}.png'.format(opt.groupName,
                ftable.cols.lastprint[n]), '{0}/clusters/fam{1}.png.tmp'.format(
                opt.groupName, n))

    cores = rtable[ftable.cols.core[:]]
    n = -1
    for r in cores:
        n = n+1
        if ftable.cols.printme[n] == 1:
            fig = plt.figure(figsize=(5, 1))
            ax = plt.Axes(fig, [0., 0., 1., 1.])
            ax.set_axis_off()
            fig.add_axes(ax)

            waveform = r['waveform'][opt.printsta*opt.wshape:(opt.printsta+1)*opt.wshape]
            tmp = waveform[max(0, r['windowStart']-int(
                opt.ptrig*opt.samprate)):min(opt.wshape,
                r['windowStart']+int(opt.atrig*opt.samprate))]
            dat = tmp[int(opt.ptrig*opt.samprate - opt.winlen*0.5):int(
                opt.ptrig*opt.samprate + opt.winlen*1.5)]/r['windowAmp'][opt.printsta]
            dat[dat>1] = 1
            dat[dat<-1] = -1

            ax.plot(dat,'k',linewidth=0.25)
            plt.autoscale(tight=True)
            plt.savefig('{0}/clusters/{1}.gif'.format(opt.groupName,n),
                dpi=100)
            plt.close(fig)

def plotFamilies(rtable, ftable, opt):

    """
    Creates a multi-paneled family plot.

    rtable: Repeater table
    ftable: Families table
    opt: Options object describing station/run parameters

    Top row: Ordered waveforms
    Middle row: Timeline of amplitude
    Bottom row: Timeline of event spacing
    """

    # Adjust the font face
    matplotlib.rcParams['font.family'] = 'sans-serif'
    matplotlib.rcParams['font.sans-serif'] = ['Arial']
    matplotlib.rcParams['font.size'] = 8.0

    # Load into memory
    startTimeMPL = rtable.cols.startTimeMPL[:]
    startTime = rtable.cols.startTime[:]
    windowAmp = rtable.cols.windowAmp[:][:,opt.printsta]
    windowStart = rtable.cols.windowStart[:]
    fi = rtable.cols.FI[:]

    for cnum in range(ftable.attrs.nClust):

        fam = np.fromstring(ftable[cnum]['members'], dtype=int, sep=' ')
        core = ftable[cnum]['core']

        # Prep catalog
        catalogind = np.argsort(startTimeMPL[fam])
        catalog = startTimeMPL[fam][catalogind]
        longevity = ftable[cnum]['longevity']
        spacing = np.diff(catalog)*24
        minind = fam[catalogind[0]]
        maxind = fam[catalogind[-1]]

        if ftable.cols.printme[cnum] != 0:

            fig = plt.figure(figsize=(10, 11))

            # Plot waveforms
            ax1 = fig.add_subplot(3, 3, (1,2))

            # If only one station, plot all aligned waveforms
            if opt.nsta==1:

                famtable = rtable[fam]
                n=-1
                data = np.zeros((len(fam), int(opt.winlen*2)))
                for r in famtable:
                    n = n+1
                    waveform = r['waveform'][0:opt.wshape]
                    tmp = waveform[max(0, windowStart[fam[n]]-int(
                        opt.ptrig*opt.samprate)):min(opt.wshape,
                        windowStart[fam[n]]+int(opt.atrig*opt.samprate))]
                    data[n, :] = tmp[int(opt.ptrig*opt.samprate - opt.winlen*0.5):int(
                        opt.ptrig*opt.samprate + opt.winlen*1.5)]/windowAmp[fam[n]]
                if len(fam) > 12:
                    ax1.imshow(data, aspect='auto', vmin=-1, vmax=1, cmap='RdBu',
                        interpolation='nearest', extent=[-1*opt.winlen*0.5/opt.samprate,
                        opt.winlen*1.5/opt.samprate, n + 0.5, -0.5])
                else:
                    tvec = np.arange(
                        -opt.winlen*0.5/opt.samprate,opt.winlen*1.5/opt.samprate,
                        1/opt.samprate)
                    for o in range(len(fam)):
                        dat=data[o,:]
                        dat[dat>1] = 1
                        dat[dat<-1] = -1
                        ax1.plot(tvec,dat/2-o,'k',linewidth=0.25)

            # Otherwise, plot cores and stacks from all stations
            else:

                r = rtable[core]
                famtable = rtable[fam]
                tvec = np.arange(-opt.winlen*0.5/opt.samprate,opt.winlen*1.5/opt.samprate,
                    1/opt.samprate)
                for s in range(opt.nsta):

                    dats = np.zeros((int(opt.winlen*2),))
                    waveform = famtable['waveform'][:,s*opt.wshape:(s+1)*opt.wshape]
                    for n in range(len(fam)):
                        tmps = waveform[n, max(0, windowStart[fam[n]]-int(
                            opt.ptrig*opt.samprate)):min(opt.wshape,
                            windowStart[fam[n]]+int(
                            opt.atrig*opt.samprate))]/(famtable['windowAmp'][
                            n,s]+1.0/1000)
                        tmps[tmps>1] = 1
                        tmps[tmps<-1] = -1
                        dats = dats + tmps[int(opt.ptrig*opt.samprate -
                            opt.winlen*0.5):int(opt.ptrig*opt.samprate + opt.winlen*1.5)]
                    dats = dats/(max(dats)+1.0/1000)
                    dats[dats>1] = 1
                    dats[dats<-1] = -1
                    ax1.plot(tvec,dats-1.75*s,'r',linewidth=1)

                    waveformc = r['waveform'][s*opt.wshape:(s+1)*opt.wshape]
                    tmpc = waveformc[max(0, r['windowStart']-int(
                        opt.ptrig*opt.samprate)):min(opt.wshape,
                        r['windowStart']+int(opt.atrig*opt.samprate))]
                    datc = tmpc[int(opt.ptrig*opt.samprate - opt.winlen*0.5):int(
                        opt.ptrig*opt.samprate + opt.winlen*1.5)]/(
                        r['windowAmp'][s]+1.0/1000)
                    datc[datc>1] = 1
                    datc[datc<-1] = -1
                    ax1.plot(tvec,datc-1.75*s,'k',linewidth=0.25)

            ax1.axvline(x=-0.1*opt.winlen/opt.samprate, color='k', ls='dotted')
            ax1.axvline(x=0.9*opt.winlen/opt.samprate, color='k', ls='dotted')
            ax1.get_yaxis().set_visible(False)
            ax1.autoscale(tight=True)
            ax1.set_xlabel('Time Relative to Trigger (sec)')

            # Plot mean FFT
            ax2 = fig.add_subplot(3, 3, 3)
            ax2.set_xlabel('Frequency (Hz)')
            ax2.get_yaxis().set_visible(False)
            r = rtable[core]
            famtable = rtable[fam]
            freq = np.linspace(0,opt.samprate/2,opt.winlen/2)
            fftc = np.zeros((opt.winlen/2,))
            fftm = np.zeros((opt.winlen/2,))
            for s in range(opt.nsta):
                fft = np.abs(np.real(r['windowFFT'][s*opt.winlen:s*opt.winlen+opt.winlen/2]))
                fft = fft/(np.amax(fft)+1.0/1000)
                fftc = fftc+fft
                ffts = np.mean(np.abs(np.real(
                    famtable['windowFFT'][:,s*opt.winlen:s*opt.winlen+opt.winlen/2])),
                    axis=0)
                fftm = fftm + ffts/(np.amax(ffts)+1.0/1000)
            ax2.plot(freq,fftm,'r', linewidth=1)
            ax2.plot(freq,fftc,'k', linewidth=0.25)
            ax2.set_xlim(0,opt.fmax*1.5)

            # Plot amplitude timeline
            ax3 = fig.add_subplot(3, 3, (4,6))
            ax3.plot_date(startTimeMPL[fam], windowAmp[fam],
                    'ro', alpha=0.5, markeredgecolor='r', markeredgewidth=0.5)
            myFmt = matplotlib.dates.DateFormatter('%Y-%m-%d\n%H:%M')
            ax3.xaxis.set_major_formatter(myFmt)
            ax3.set_ylim(1, max(rtable.cols.windowAmp[:][:,opt.printsta])+500)
            ax3.margins(0.05)
            ax3.set_ylabel('Amplitude (Counts)')
            ax3.set_yscale('log')

            # Plot spacing timeline
            ax4 = fig.add_subplot(3, 3, (7,9))
            ax4.plot_date(catalog[1:], spacing, 'ro', alpha=0.5, markeredgecolor='r',
                markeredgewidth=0.5)
            myFmt = matplotlib.dates.DateFormatter('%Y-%m-%d\n%H:%M')
            ax4.xaxis.set_major_formatter(myFmt)
            ax4.set_xlim(ax3.get_xlim())
            ax4.set_ylim(1e-3, max(spacing)*2)
            ax4.margins(0.05)
            ax4.set_ylabel('Time since previous event (hours)')
            ax4.set_xlabel('Date')
            ax4.set_yscale('log')

            plt.tight_layout()
            plt.savefig('{0}/clusters/fam{1}.png'.format(opt.groupName,
                cnum), dpi=100)
            plt.close(fig)

        if ftable.cols.printme[cnum] != 0 or ftable.cols.lastprint[cnum] != cnum:
            if cnum>0:
                prev = "< Cluster {0}".format(cnum-1)
            else:
                prev = " "
            if cnum<len(ftable)-1:
                next = "Cluster {0} >".format(cnum+1)
            else:
                next = " "
            # Now write a simple HTML file to show image and catalog
            with open('{0}/clusters/{1}.html'.format(opt.groupName, cnum), 'w') as f:
                f.write("""
                <title>{1} - Cluster {0}</title>

                {10}   |   {11}

                    Cluster {0}

                    Number of events: {2}

                    Longevity: {5:.2f} days

                    Mean event spacing: {7:.2f} hours

                    Median event spacing: {8:.2f} hours

                    Mean Frequency Index: {9:.2f}

                    First event: {3}

                    Core event: {6}

                    Last event: {4}

                """.format(cnum, opt.title, len(fam), (UTCDateTime(
                    startTime[minind]) + windowStart[minind]/opt.samprate).isoformat(),
                    (UTCDateTime(startTime[maxind]) + windowStart[
                    maxind]/opt.samprate).isoformat(), longevity, (UTCDateTime(
                    startTime[core]) + windowStart[core]/opt.samprate).isoformat(),
                    np.mean(spacing), np.median(spacing), np.mean(np.nanmean(fi[fam],
                    axis=1)),prev,next))

                f.write("""

                """)

def printCatalog(rtable, ftable, opt):
    """
    Prints flat catalog to text file

    rtable: Repeater table
    ftable: Families table
    opt: Options object describing station/run parameters

    Note: Time in text file corresponds to current trigger time by alignment
    """

    with open('{}/catalog.txt'.format(opt.groupName), 'w') as f:

        startTimes = rtable.cols.startTime[:]
        windowStarts = rtable.cols.windowStart[:]

        for cnum in range(ftable.attrs.nClust):
            fam = np.fromstring(ftable[cnum]['members'], dtype=int, sep=' ')
            for i in np.argsort(startTimes[fam]):
                f.write("{0} {1}\n".format(cnum,(UTCDateTime(startTimes[fam][i]) +
                    windowStarts[fam][i]/opt.samprate).isoformat()))


#-*- coding: UTF-8 -*-
#!/usr/bin/env python
#
import os
import sys
import optparse
from replay_kinect_bone_data import draw
from matlab_cp2tform import get_similarity_transform_for_cv2
import cv2
import numpy as np
#from builtins import input
try:
   input = raw_input
except NameError:
   pass

JointType_SpineBase = 0
JointType_SpineMid = 1
JointType_Neck = 2
JointType_Head = 3
JointType_ShoulderLeft = 4
JointType_ElbowLeft = 5
JointType_WristLeft = 6
JointType_HandLeft = 7
JointType_ShoulderRight = 8
JointType_ElbowRight = 9
JointType_WristRight = 10
JointType_HandRight = 11
JointType_HipLeft = 12
JointType_KneeLeft = 13
JointType_AnkleLeft=14
JointType_FootLeft = 15
JointType_HipRight = 16
JointType_KneeRight = 17
JointType_AnkleRight=18
JointType_FootRight = 19
JointType_SpineShoulder = 20
JointType_HandTipLeft = 21
JointType_ThumbLeft = 22
JointType_HandTipRight = 23
JointType_ThumbRight = 24
Frame_Num=25

skeletons = []
skeletons_lines = []
value_threshold = 0.09
line_threshold = 6
skeleton_threshold = 6
candidates=[]
op_flag = False
def alignment(src_img, src_pts):
    # ref_pts = [[30.2946, 51.6963], [65.5318, 51.5014],
    #            [48.0252, 71.7366], [33.5493, 92.3655], [62.7299, 92.2041]]
    ref_pts = [[48.0252, 20.6963],[38,30],[48.0252, 60.7366]]

    crop_size = (96, 112)
    src_pts = np.array(src_pts).reshape(3, 2)

    s = np.array(src_pts).astype(np.float32)
    r = np.array(ref_pts).astype(np.float32)

    tfm = get_similarity_transform_for_cv2(s, r)
    bone_img = cv2.warpAffine(src_img, tfm, crop_size)
    return bone_img
def save_skeleton_video(video_path, start=0, end=10**10, subject_lines=[],num=0):
    write=True
    avi = os.path.join(video_path, "bgr.avi")
    txt = os.path.join(video_path, "kinect color.txt")
    f = open(txt, encoding='utf-8')  # ,encoding='utf-8'
    lines = f.readlines()
    dict = {}
    line_num = 0
    for i in range(len(lines)):
        line_num = line_num + 1
        line = lines[i].split(' ')[0:-1]
        # use color frame as the key in the dict
        if (int(line[1]) not in dict):
            dict[int(line[1])] = []
        values = []
        pre_i = 0
        # there are two frame numbers in a line
        for i in line[2:]:
            try:
                i = float(i)
                values.append(i)
                pre_i = i
            except:
                values.append(pre_i)
        values.append(int(line[0]))
        values.append(line_num)
        dict[int(line[1])].append(values)

    cap = cv2.VideoCapture(avi)
    fg=0#fg是当前帧数
    while 1:
        fg+=1
        ret, copy = cap.read()

        if(fg<start):
            continue
        if(fg>end):
            break
        if (not copy is None):
            if (fg in dict):
                tmp = len(dict[fg])
                skeletons = []
                for j in range(tmp):
                    if (dict[fg][j][Frame_Num * 2] == dict[fg][0][Frame_Num * 2]):
                        jointArr = [[0, 0] for _ in range(26)]
                        for k in range(26):
                            for l in range(2):
                                if l == 0:
                                    jointArr[k][0] = dict[fg][j][k * 2 + l]
                                else:
                                    jointArr[k][1] = dict[fg][j][k * 2 + l]
                        skeletons.append(jointArr)

                if len(skeletons) > 0:
                    bones=[]
                    for jointArr in skeletons:
                        x = []
                        y = []
                        for point in jointArr:
                            x.append(int(point[0]))
                            y.append(int(point[1]))
                        x = sorted(x)
                        y = sorted(y)

                        if jointArr[25][1] in subject_lines:
                            if(x[1]-20<0):
                                x[1]=5
                            if(x[-2]+20>960):
                                x[-2]=954
                            if(y[1]-50<0):
                                y[1]=30
                            if(y[-2]+50>540):
                                y[-2]=509
                            bones.append(jointArr[JointType_Head])
                            bones.append(jointArr[JointType_ShoulderLeft])
                            bones.append(jointArr[JointType_SpineBase])
                            try:
                                copy[:, 0:x[1] - 20] = 0
                                copy[:, x[-2] + 20:960] = 0
                                copy[0:y[1] - 50, :] = 0
                                copy[y[-2] + 50:540, :] = 0
                                res=alignment(copy,bones)
                                res=cv2.flip(res,1)
                                cv2.imshow("replay", res)
                                if write:
                                    dir_name=dest_dir+'/ali_img/'
                                    if not os.path.exists(dir_name):
                                        os.mkdir(dir_name)
                                    dir_name=dir_name+'/'+str(num)
                                    if not os.path.exists(dir_name):
                                        os.mkdir(dir_name)
                                    cv2.imwrite(dir_name+"/"+str(fg)+".jpg",res)
                                    print(dir_name+"/"+str(fg)+".jpg",res)
                            except:
                                continue
            if cv2.waitKey(50) & 0xFF == ord('e'):
                break
    cap.release()
    cv2.destroyAllWindows()

def generate_dest_file_name(src_file):
    path_list = src_file.split(os.sep)
    return "%s_%s" % (path_list[-2], "bone")

def create_destination_dir(dir):
    if not dir:
        print(("The output directory doesn't exist: %s" % dir))
        dir = os.path.join(os.path.dirname(src_file),"cleaned")
        print(("Use the source directory as destination directory: %s" % dir))
    if not os.path.isdir(dir):
        os.makedirs(dir)
    return dir

def get_patient_dir(filepath):
    path_list = filepath.split(os.sep)
    patient_dir = ""
    try:
        patient_dir = path_list[-4]
    except IndexError:
        pass
    return patient_dir

def load_and_clean_kinect_bone_data(src_file):
    if not os.path.exists(src_file):
        raise SystemExit("The source file doesn't exist : %s" % src_file)
    # read data from file line by line
    line_num = 1
    with open(src_file, "r") as sf:
        for line in sf:
            append_line_to_skeletons(line.strip(), line_num)
            line_num = line_num + 1
    print(("total lines: %d" % line_num))

def append_line_to_skeletons(line, line_num):
    print(("processing the line %d" % line_num))
    values = line.split(' ')
    try:
        v1 = int(values[0])
    except ValueError:
        v1 = float(values[0])
    try:
        v2 = int(values[1])
    except ValueError:
        v2 = float(values[1])

    if not skeletons:
        # the raw data doesn't have frame number
        if not isinstance(v1, int) or v1 == 0:
            values.insert(0, line_num)
        if not isinstance(v2, int) or v2 == 0:
            values.insert(1, line_num)
        print(("insert the line %d to the empty skeletons" % line_num))
        skeletons.append([values])
        skeletons_lines.append([line_num])
    else:
        # the raw data has frame number (After P29)
        if isinstance(v1, int) and v1 != 0:
            # the raw data has 2 frame number (After P40)
            if isinstance(v2, int) and v2 != 0:
                pass
            # the raw data has 1 frame number (P30 to P40)
            else:
                values.insert(1, v1)
        # the raw data doesn't have frame number (P1 to P29)
        else:
            values.insert(0, line_num)
            values.insert(1, line_num)

        processed = False
        for i in range (1, skeleton_threshold + 1):
            try:
                diff_frames = abs(int(skeletons[-i][-1][0]) - int(values[0]))
                if ( diff_frames >=1 and diff_frames <=6 ) and ( abs(float(skeletons[-i][-1][2]) - float(values[2])) <= value_threshold ) :
                    print(("insert the line %d to the skeleton[%d]" % (line_num, len(skeletons)-i+1)))
                    skeletons[-i].append(values)
                    skeletons_lines[-i].append(line_num)
                    processed = True
                    break
            except IndexError as ie:
                print(("the line %d does not match to the last 6 skeletons" % line_num))

        if not processed:
            print(("insert the line %d as a new skeleton" % line_num))
            skeletons.append([values])
            skeletons_lines.append([line_num])
            processed = True

def print_out_skeletons():
    print(("There are %d skeletons in this file" % len(skeletons)))
    i = 0
    global candidates
    for skeleton in skeletons:
        i = i + 1
        if len(skeleton) < 20 or len(skeleton) > 250:
            continue
        candidates.append(i)
        print("===========================================")
        print(("The %d skeleton \n Start from %d to %d, total %d frames(lines)" % (i, int(skeleton[0][0]), int(skeleton[-1][0]), len(skeleton))))
        print((skeleton[0]))
        print("......")
        print((skeleton[-1]))
        print("===========================================")

op_flg = False
def showAvi(dict):
    global candidates
    src=os.path.dirname(src_file)
    num=''
    print(("Skeletons Candidate Set:", candidates))
    if(len(candidates)==0):
        print("Set is Empty.")
        print("## All process completely, Exit")
        exit(0)
    else:
        while(num==''):
            if op_flg:
                num = candidates[0]
            else:
                num = input("Input Skeleton num / e To exit:")
    if (num == "e"):
        exit(0)

    if num != '':
        try:
            num = int(num)
            start = int(skeletons[num - 1][0][1])
            end = int(skeletons[num - 1][-1][1])
            draw(src, start, end, skeletons_lines[num-1],dict)
            confirm = input("Save %d? ((y-->save)/(n-->don't save)/(e-->exit)/(enter or others-->pass)):" % num)
            if confirm == 'y':
                save_skeleton_to_file(num)
                # save_skeleton_video(src,start, end, skeletons_lines[num-1],num)
                candidates.remove(num)
            if confirm=='n':
                candidates.remove(num)
            if confirm == 'e':
                exit(0)
        except ValueError as ve:
           print(("Unknow options [%s] please check your input" % num))
        showAvi(dict)

def print_options_to_user():
    print("Please input the options: (no [])")
    print("     Input [numbers] to save the skeletons: e.g. 1 for the skeleton 1 or 1,2,3 for the skeletons of 1, 2, 3")
    print("     Input [skeletons] or [s] to show the skeletons information: e.g. skeletons or s")
    print("     Input [avi] or [a] to watch movie with bone:e.g. avi or a")
    print("     Input [help] or [h] to show this message again: e.g. help or h")
    print("     Input [exit] or [q] to exit the program: e.g. exit or q")

def handle_user_input(input):
    if input == "skeletons" or input == "s":
        print_out_skeletons()
    elif input == "help" or input == "h":
        print_options_to_user()
    elif input == "e" or input == "q":
        pass
    elif input=="avi" or input=="a":
        showAvi()
    else:
        numbers_str = input.strip().split(',')
        numbers = []
        try:
            for num_str in numbers_str:
                if num_str:
                    numbers.append(int(num_str))
        except ValueError:
            print(("Unknow options [%s] please check your input" % input))
            return

        if len(numbers) > 0:
            for num in numbers:
                save_skeleton_to_file(num)

def save_skeleton_to_file(num):
    try:
        #src_file_name = os.path.splitext(os.path.basename(src_file))[0]
        skeleton_file_name = "%s_%d.txt" % (dest_file_name, num)
        skeleton_file = os.path.join(dest_dir, skeleton_file_name)
        skeletons[num-1]
        with open(skeleton_file, "w") as sf:
            for item in skeletons[num-1]:
                sf.write("%s\n" % " ".join(map(str,item)))
        print(("saved skeleton %d to file: %s" % (num, skeleton_file)))
    except IndexError as ie:
        print(("Failed: %d is not found in skeletons" % num))

#---------------
# Main Script
#---------------
def main():
    usage = "Usage: %prog [options] args"
    parser = optparse.OptionParser(usage)
    parser.add_option("-s", "--source", dest="source", default="", help="The source directory of raw data")
    parser.add_option("-d", "--destination", dest="destination", default="", help="The output directory for cleaned data")
    (opts, extra) = parser.parse_args()

    # Verify the arguments
    if len(sys.argv) == 1:
        parser.error("No argument has been provided. \nTry --help to get more details.")

    if not os.path.exists(opts.source):
        raise SystemExit("The given source file doesn't exist : %s" % opts.source)

    kinect_bone_file = os.path.join(opts.source, "kinect bone.txt")
    kinect_bgr_file = os.path.join(opts.source, "bgr.avi")

    if not os.path.isfile(kinect_bone_file):
        raise SystemExit("The file 'kinect bone.txt' doesn't exist in : %s" % opts.source)
    if not os.path.isfile(kinect_bgr_file):
        raise SystemExit("The file 'bgr.avi' doesn't exist in : %s" % opts.source)

    global src_file
    src_file = kinect_bone_file
    global dest_file_name
    dest_file_name = generate_dest_file_name(src_file)
    global dest_dir
    dest_dir = create_destination_dir(opts.destination)

    load_and_clean_kinect_bone_data(kinect_bone_file) # save cleaned to skeletons

    print_out_skeletons()

    inputs = ""
    print_options_to_user()
    # 直接进入符合骨架条件的视频

    '''
    copy from replay
    '''
    video_path = os.path.dirname(src_file)
    if not os.path.exists(video_path):
        raise SystemExit("The video path doesn't exist : %s" % video_path)
    avi = os.path.join(video_path, "bgr.avi")
    txt = os.path.join(video_path, "kinect color.txt")
    f=open(txt, encoding='utf-8') #,encoding='utf-8'
    lines=f.readlines()
    dict={}
    line_num = 0
    for i in range(len(lines)):
        line_num = line_num + 1
        line=lines[i].split(' ')[0:-1]
        # use color frame as the key in the dict
        if(int(line[1]) not in dict):
            dict[int(line[1])]=[]
        values = []
        pre_i = 0
        # there are two frame numbers in a line
        for i in line[2:]:
            try:
                i = float(i)
                values.append(i)
                pre_i = i
            except:
                values.append(pre_i)
        values.append(int(line[0]))
        values.append(line_num)
        dict[int(line[1])].append(values)
    '''
    end
    '''

    showAvi(dict)
    while inputs != "exit" and inputs != "q":
        inputs = input("Enter your option: ")
        if inputs:
            handle_user_input(inputs)
        else:
            print("Nothing has been input")

    print("Exit the program.")

if __name__ == '__main__':
    main()


"""
created by Nagaj at 13/05/2021
"""
import random
import time
from actors import Wizard, Creature, SmallAnimal, Dragon
from app7_wizard_battle.constants import (
    EXIT,
    GOOD_BYE,
    ATTACK,
    RUN,
    LOOK,
    ACTIVE_CREATURE,
    KILL,
    RECOVER,
    RETURNS,
    WAIT,
    SEES,
    LIST,
    RUNAWAY,
    TIMES
)
from validations import validated_cmd
from art import print_header

def wizard_recovering():
    print(RECOVER.format(WAIT))
    time.sleep(WAIT)
    print(RETURNS)

def wizard_look(hero, creatures):
    print(SEES.format(hero.name))
    for counter, creature in enumerate(creatures, start=1):
        print(LIST.format(counter=counter, creaturename=creature.name, creaturelevel=creature.level))
    print("#" * TIMES)

def game_loop():
    creatures = [
        SmallAnimal("Toad", 1),
        Creature("Tiger", 12),
        SmallAnimal("Bat", 3),
        Dragon("Dragon", 50, scaliness=20, breaths_fire=False),
        # Wizard("Evil Wizard", 1000),
    ]
    hero = Wizard("GandOlf", 75)
    while True:
        if not creatures:
            print(KILL)
            break
        active_creature = random.choice(creatures)
        print(
            ACTIVE_CREATURE.format(
                name=active_creature.name, level=active_creature.level
            )
        )
        cmd = validated_cmd()
        if cmd == ATTACK:
            if hero.attack(active_creature) and len(creatures) > 0:
                creatures.remove(active_creature)
            else:
                wizard_recovering()
        elif cmd == RUN:
            print(RUNAWAY)

        elif cmd == LOOK:
            wizard_look(hero, creatures)

        elif cmd == EXIT:
            print(GOOD_BYE)
            break

def main():
    print_header()
    game_loop()

if __name__ == "__main__":
    main()


"""
Created by Philippenko, 6th March 2020.

In this python file is provided tools to implement any local update scheme. This is the part which is perfomed on local
devices in federated learning.
"""
import random

import torch
import numpy as np

from src.models.CostModel import ACostModel
from src.machinery.Parameters import Parameters
from src.models.QuantizationModel import s_quantization

from abc import ABC, abstractmethod

class AbstractLocalUpdate(ABC):

    def __init__(self, parameters: Parameters, cost_model: ACostModel) -> None:
        super().__init__()
        self.parameters = parameters
        self.cost_model = cost_model

        self.g_i = torch.zeros(parameters.n_dimensions, dtype=np.float)
        self.v = torch.zeros(parameters.n_dimensions, dtype=np.float)

        # Initialization of model's parameter.
        # self.model_param = torch.zeros(self.parameters.n_dimensions).to(dtype=torch.float64)
        self.model_param = torch.FloatTensor(
            [(-1 ** i) / (2 * self.parameters.n_dimensions) for i in range(self.parameters.n_dimensions)]) \
            .to(dtype=torch.float64)

    def set_initial_v(self, v):
        self.v = v

    @abstractmethod
    def send_global_informations_and_update_local_param(self, tensor_sent: torch.FloatTensor, step: float):
        pass

    def compute_local_gradient(self, j: int):
        # if len(self.cost_model.X) <= j:
        #     self.g_i = None
        #     return
        if self.parameters.stochastic:
            idx = random.choice(range(len(self.cost_model.X)))
            x = torch.stack([self.cost_model.X[idx]])
            y = torch.stack([self.cost_model.Y[idx]])
            self.g_i = self.cost_model.grad_i(self.model_param, x, y)
        else:
            self.g_i = self.cost_model.grad(self.model_param)

    @abstractmethod
    def compute_locally(self, j: int):
        pass

class LocalGradientVanillaUpdate(AbstractLocalUpdate):

    def __init__(self, parameters: Parameters, cost_model: ACostModel) -> None:
        super().__init__(parameters, cost_model)

    def compute_locally(self, j: int):
        self.compute_local_gradient(j)
        return self.g_i

    def send_global_informations_and_update_local_param(self, tensor_sent: torch.FloatTensor, step: float):
        self.v = self.parameters.momentum * self.v + tensor_sent
        self.model_param = self.model_param - step * self.v

class LocalDianaUpdate(AbstractLocalUpdate):

    def __init__(self, parameters: Parameters, cost_model: ACostModel) -> None:
        super().__init__(parameters, cost_model)
        self.h_i = torch.zeros(parameters.n_dimensions, dtype=np.float)
        self.delta_i = torch.zeros(parameters.n_dimensions, dtype=np.float)

    def send_global_informations_and_update_local_param(self, tensor_sent: torch.FloatTensor, step: float):
        self.v = self.parameters.momentum * self.v + tensor_sent
        self.model_param = self.model_param - step * self.v

    def compute_locally(self, j: int):
        self.compute_local_gradient(j)
        if self.g_i is None:
            return None

        self.delta_i = self.g_i - self.h_i
        quantized_delta_i = s_quantization(self.delta_i, self.parameters.quantization_param)
        self.h_i += self.parameters.learning_rate * quantized_delta_i
        return quantized_delta_i

class LocalArtemisUpdate(AbstractLocalUpdate):
    """This class carry out the local update of the Artemis algorithm."""

    def __init__(self, parameters: Parameters, cost_model: ACostModel) -> None:
        super().__init__(parameters, cost_model)
        self.h_i = torch.zeros(parameters.n_dimensions, dtype=np.float)
        self.delta_i = torch.zeros(parameters.n_dimensions, dtype=np.float)

        # For bidirectional compression :
        self.l_i = torch.zeros(parameters.n_dimensions, dtype=np.float)

    def send_global_informations_and_update_local_param(self, tensor_sent: torch.FloatTensor, step: float):
        learning_rate_down = self.parameters.learning_rate

        # l_i must be update with true omega, not with it "unzip" version which corresponds to compress model param.
        # As we override model_param, we need to update l_i in the same operation,
        # to benefit from the true model_param.
        if self.parameters.double_use_memory:
            decompressed_value, self.l_i = tensor_sent + self.l_i, self.l_i + learning_rate_down * tensor_sent
        else:
            decompressed_value = tensor_sent

        # Updating the model with the new gradients.
        self.v = self.parameters.momentum * self.v + decompressed_value
        self.model_param = self.model_param - step * self.v

    def compute_locally(self, j: int):
        self.compute_local_gradient(j)
        if self.g_i is None:
            return None

        self.delta_i = self.g_i - self.h_i
        quantized_delta_i = s_quantization(self.delta_i, self.parameters.quantization_param)
        self.h_i += self.parameters.learning_rate * quantized_delta_i
        return quantized_delta_i


#!/usr/bin/env python
# coding=utf-8

"""
根域名处理
"""

from suffixs import SUFFIXS

class Domain:

    @classmethod
    def url_format(cls, url):
        """
        return http(s)://www.example.com
        """
        if not url.startswith(("http://", "https://")):
            url = "http://" + url
        if url.endswith("/"):
            url = url[:-1]
        return url

    @classmethod
    def get_domain(cls, url):
        url = url.replace("https://", "")
        url = url.replace("http://", "")
        domain = url[:url.index("/")+1] if "/" in url else url
        return domain

    @classmethod
    def get_root_domain(cls, url):
        domain = cls.get_domain(url)
        domain_blocks = domain.split(".")
        index = -2
        suffix = ".".join(domain_blocks[index:])
        if_match = False
        if suffix in SUFFIXS:
            index -= 1
            if_match = True
        else:
            index += 1
            suffix = ".".join(domain_blocks[index:])
            if suffix in SUFFIXS:
                index -= 1
                if_match = True
        root_domain = ""
        if if_match:
            root_domain = ".".join(domain_blocks[index:])
        return root_domain


from __future__ import absolute_import

import logging

from django.utils.timezone import now

from celery_app.background_email_constants import (BODY_REMINDER, BODY_FEEDBACK, SUBJECT_REMINDER, SUBJECT_FEEDBACK,
                                                   BD_TZ, time_format)
from celery_app.celery import app
from celery_app.models import TaskList
from common.utils import send_mail
from event.models import Registration, Event, EventEmail

logger = logging.getLogger(__name__)

def send_mail_async(subject, body_email, to_email):
    # This is just a helper function to send email async.
    # See the output in the worker process console
    return send_mail.delay(subject, body_email, to_email)

@app.task
def send_reminder_email(event_id, is_feedback_email):
    """
    :param event_id:
    :param is_feedback_email:
    :return:
    """
    # Change and update the body_email make it more customized

    event = Event.objects.get(id=int(event_id))
    registered_user_list = Registration.objects.filter(event=event)

    for reg_user in registered_user_list:
        to_email = [reg_user.attendee.email, ]

        if is_feedback_email:
            subject = SUBJECT_FEEDBACK
            body_email = BODY_FEEDBACK.format(reg_user.attendee.first_name, event.title)
        else:
            event_start_time = event.start_time.astimezone(BD_TZ).strftime(time_format)
            subject = SUBJECT_REMINDER.format(event.title)
            body_email = BODY_REMINDER.format(reg_user.attendee.first_name, event.title,
                                              event_start_time, event.duration)

        send_mail(subject, body_email, to_email)

def delete_previous_tasks(event):
    """
    :param parent_task_name:
    :return:
    """
    task_list = TaskList.objects.filter(parent_task_name=event.name_task)
    if task_list:
        for task in task_list:
            app.control.revoke(task.celery_task_id)
            task.delete()
            logger.info("Deleted task {0} of parent task{1}".format(task.celery_task_id, event.name_task))

def schedule_background_email(event, start_timedelta, expire_timedelta, is_feedback_email):
    """
    :param event:
    :param start_timedelta:
    :param expire_timedelta:
    :param is_feedback_email:
    :return:
    """
    reminder_start_time = event.end_time + start_timedelta if is_feedback_email else event.start_time - start_timedelta

    # if the scheduled time is already in past, does n't make sense to schedule it
    if reminder_start_time < now():
        return

    reminder_expire_time = reminder_start_time + expire_timedelta

    reminder_task_id = send_reminder_email.apply_async((event.id, is_feedback_email), eta=reminder_start_time,
                                                       expires=reminder_expire_time)
    # Creating tasking so that can revoke it later
    TaskList.objects.create(parent_task_name=event.name_task, celery_task_id=reminder_task_id.task_id)

    return True

@app.task
def skype_event_group_email(event_email_id):
    """
    :param event_email_id:
    :return:
    """
    event_email = EventEmail.objects.get(id=event_email_id)
    registered_user_list = Registration.objects.filter(event=event_email.event)
    for reg_user in registered_user_list:
        logger.info("\n\n group email for loop\n")
        to_email = [reg_user.attendee.email, ]
        subject = event_email.email_subject
        body_email = event_email.email_body
        send_mail(subject, body_email, to_email)


#############################################################################
#
# Bista Solutions Pvt. Ltd
# Copyright (C) 2020 (https://www.bistasolutions.com)
#
#############################################################################
from odoo import api, fields, models
import odoo.addons.decimal_precision as dp

class SaleOrder(models.Model):
    _inherit = "sale.order"

    @api.depends('order_line.price_total')
    def _compute_amount_undiscounted(self):
        for order in self:
            total = 0.0
            for line in order.order_line:
                total += line.price_subtotal + line.price_unit * ((line.discount or 0.0) / 100.0) * line.product_uom_qty  # why is there a discount in a field named amount_undiscounted ??
            order.amount_undiscounted = total

    @api.depends('order_line.discount')
    def _order_percent(self):
        """
        Compute the total discount of the SO.
        """
        for order in self:
        	if order.amount_undiscounted:
        		order.discount_rate = ((order.amount_undiscounted - order.amount_untaxed) / order.amount_undiscounted) * 100
        	else:
        		order.discount_rate = 0.0

    discount_type = fields.Selection([('percent', 'Percentage'), ('amount', 'Amount')], string='Discount type',
                                     readonly=True,
                                     default='percent')
    discount_rate = fields.Float('Order Discount %',
                                 readonly=True,store=True, compute='_order_percent',
                                     track_visibility='always')


import pandas as pd
import numpy as np
import traceback

class Wiki:
    '''
    MAIN CLASS TO store all revisions for a wiki along with editors and timestamp.
    '''
    def __init__(self,id,title, revs, all_tokens=[]):
        self.id = id
        self.title = title
        self.revisions = revs
        self.add_all_token(all_tokens)

#     def init_revisions(self, revisions):
#           self.revisions = pd.Series( {revision["id"] :
#                                        Revision(revision["id"],revision["timestamp"], revision["editor"]) for revision in revisions} )

    def add_all_token(self, all_tokens):
        for token in all_tokens:
            self.revisions.loc[token["o_rev_id"]].added.add(token["token_id"])
            for in_revision in token["in"]:
                self.revisions.loc[in_revision].added.add(token["token_id"])
            for out_revision in token["out"]:
                self.revisions.loc[out_revision].removed.add(token["token_id"])

    def create_change(self, from_rev_id, to_rev_id, to_rev_content, epsilon_size):
        try:
            from_rev = self.revisions[from_rev_id]
            to_rev = self.revisions[to_rev_id]
            from_rev.deleted(to_rev)
            to_rev.content = to_rev_content
            to_rev.inserted_continuous_pos()
            to_rev.inserted_neighbours()
            from_rev.create_change_object(to_rev)
            from_rev.append_neighbour_vec(to_rev, epsilon_size)
        except:
            print("exception occurred in calculating change object",traceback.format_exc())
            print("problem in ", to_rev_content.keys() )

class Revision:
    def __init__(self, id, timestamp,editor):
        self.id = id
        self.timestamp = timestamp
        self.editor = editor
        self.added = set()
        self.removed = set()

    def deleted(self, to_rev):
        self.content["removed"] = pd.Series(np.isin( self.content["token_id"].values, list(to_rev.removed), assume_unique= True ))
        end_pos = np.argwhere(np.ediff1d(np.pad(self.content["removed"].astype(np.int), (1,1), mode="constant", constant_values=0)) == -1) -1
        start_pos = np.argwhere(np.ediff1d(np.pad(self.content["removed"].astype(np.int), (1,1), mode="constant", constant_values=0)) == 1)
        start_neighbour = start_pos - 1
        end_neighbour = end_pos + 1
        self.deleted_object = pd.DataFrame(np.c_[ start_pos, end_pos, start_neighbour, end_neighbour ],
                                       columns=[ "del_start_pos", "del_end_pos", "left_neigh", "right_neigh",])

    def inserted_continuous_pos(self):
        self.content["added"] = pd.Series(np.isin( self.content["token_id"].values, list(self.added), assume_unique= True))
        end_pos = np.argwhere(np.ediff1d(np.pad(self.content["added"].astype(np.int), (1,1), mode="constant", constant_values=0)) == -1) -1
        start_pos = np.argwhere(np.ediff1d(np.pad(self.content["added"].astype(np.int), (1,1), mode="constant", constant_values=0)) == 1)
        self.added_pos = np.c_[start_pos, end_pos]

    def inserted_neighbours(self):
        start_token_pos = self.added_pos[:,0] - 1
        end_token_pos = self.added_pos[:,1] + 1
        self.start_token_id = self.content["token_id"].values[start_token_pos]
        self.end_token_id = self.content["token_id"].values[end_token_pos]

    def create_change_object(self, to_rev):
        self.ins_left = np.argwhere(np.isin(self.content.token_id.values, to_rev.start_token_id, assume_unique= True))
        self.ins_right = np.argwhere(np.isin(self.content.token_id.values, to_rev.end_token_id, assume_unique= True))
        self.inserted_object = pd.DataFrame(np.concatenate([to_rev.added_pos, self.ins_left, self.ins_right], axis=1),
                                       columns=["ins_start_pos", "ins_end_pos", "left_neigh", "right_neigh", ])

        self.change = pd.merge(self.inserted_object, self.deleted_object,how="outer", on=["left_neigh", "right_neigh"])
        self.change.fillna(-1, inplace=True)

    def append_neighbour_vec(self, to_rev, epsilon_size):
        self.wiki_who_tokens = self.content.token_id.values
        del self.content
        neighbour_df = self.change.apply(find_tokens, axis=1, args=(self,to_rev, epsilon_size))
        neighbour_df.columns= ["ins_tokens", "del_tokens", "left_neigh", "right_neigh", "left_token", "right_token"]
        self.neighbour = neighbour_df
        self.change_df = pd.concat([self.change, neighbour_df], sort=False, axis=1)

def find_tokens(change, revision, to_rev, epsilon_size):
    start_left = (int(change["left_neigh"]) - epsilon_size)
    if start_left <0:
        start_left = 0
    left_neigh = slice( start_left, int(change["left_neigh"]) + 1)

    end_right = (int(change["right_neigh"]) + epsilon_size+1)
    if end_right >= revision.wiki_who_tokens.size:
        end_right = revision.wiki_who_tokens.size - 1
    right_neigh = slice(int(change["right_neigh"]), end_right )
    if(change["ins_start_pos"]==-1):
        ins_tokens = []
    else:
        ins_slice = slice(int(change["ins_start_pos"]), int(change["ins_end_pos"]+1) )
        ins_tokens = to_rev.content.str.values[ins_slice]
    if(change["del_start_pos"] == -1):
        del_tokens = []
    else:
        del_slice = slice(int(change["del_start_pos"]), int(change["del_end_pos"]+1) )
        del_tokens = revision.wiki_who_tokens[del_slice]
    left_token = revision.wiki_who_tokens[left_neigh]
    right_token = revision.wiki_who_tokens[right_neigh]
    return pd.Series([tuple(ins_tokens), tuple(del_tokens), left_neigh, right_neigh, tuple(left_token), tuple(right_token)])


''' This plotter expects 3-tuples
(median, firstQuantile, thirdQuantile) as input.
The output is the default Boxerrorbar plot
from gnuplot.
'''

import os
import sys
import subprocess

separator = '|'

def _writePlotHeaderData(gnuplotFile, outputFileName, config, additionalCommands=None):

    # For details see the gnuplot manual.
    # See https://stackoverflow.com/questions/62848395/horizontal-bar-chart-in-gnuplot

    print("set terminal pdfcairo enhanced color size 7cm, 7cm", file=gnuplotFile)
    print(f'set output "{outputFileName}"', file=gnuplotFile)
    print(f'set datafile separator "{separator}"', file=gnuplotFile)

    print('set style fill solid', file=gnuplotFile)
    print('unset key', file=gnuplotFile)
    #print('set pointsize 0', file=gnuplotFile)
    #print(f'set xlabel "{config["plotYAxisLabel"]}"', file=gnuplotFile)
    print('set boxwidth 0.4 relative', file=gnuplotFile)
    print(f'set title "{config["plotTitle"]}"', file=gnuplotFile)

    #print('myBoxWidth = 0.8', file=gnuplotFile)
    #print('set offsets 0,0,0.5-myBoxWidth/2.,0.5', file=gnuplotFile)

    if additionalCommands:
        print(additionalCommands, file=gnuplotFile)

def plot(valuesOfSequences, outputPath, experimentId, config):

    # initializations
    gnuplotFileName = experimentId + '.txt'
    dataFileName = f'{experimentId}.dat'
    colors = config.get('plotSequenceColors', {})

    # Create simple CSV file that can be referenced in gnuplot.
    with open(os.path.join(outputPath, dataFileName), 'w') as dataFile:

        # find the correct order of the sequences to plot
        orderSequences = None
        if 'plotArrangementSequences' in config:
            orderSequences = config.get('plotArrangementSequences')
        else:
            orderSequences = valuesOfSequences.keys()

        # write data according to the order
        for sequenceId in orderSequences:
            if sequenceId in valuesOfSequences.keys():
                sequence = valuesOfSequences[sequenceId]
                parameter, value = sequence[0]
                #dataFile.write(config['plotSequenceNames'][sequenceId] + separator + str(value[0]) + separator +
                #               str(value[1]) + separator + str(value[2]) + separator + str(colors.get(sequenceId, 1)) + '\n')
                dataFile.write(config['plotSequenceNames'][sequenceId] + separator + str(value[0]) + separator +
                               str(value[1]) + separator + str(value[2]) + separator + str(colors.get(sequenceId, 1)) + '\n')

    # create file for gnuplot and execute gnuplot
    gnuPlotFilePath = os.path.join(outputPath, gnuplotFileName)
    with open(gnuPlotFilePath, 'w') as gnuPlotFile:
        _writePlotHeaderData(
            gnuplotFile = gnuPlotFile,
            outputFileName = gnuplotFileName.replace('.txt', '.pdf'),
            config = config,
            additionalCommands = config.get('plotAdditionalGnuplotHeaderCommands') )
        plot_commands = []
        #plot_commands.append(f'"{dataFileName}" using ($0):2:3:4:xticlabels(1) with boxes linecolor variable')
        #plot_commands.append(f'"{dataFileName}" using ($0):2:5:xticlabels(1) with boxes linecolor variable, "" using ($0):2:3:4 with yerrorbars linecolor 0')
        plot_commands.append(f'"{dataFileName}" using ($0):2:5:xticlabels(1) with boxes linecolor variable, "" using ($0):2:3:4 with yerrorbars linecolor 0')

        print("plot " + ",\\\n".join(plot_commands), file=gnuPlotFile)
    try:
        subprocess.run(args=['gnuplot', gnuplotFileName], cwd=outputPath)
    except Exception as e:
        print('Warning: Failed to run "gnuplot", run it manually.', file=sys.stderr)
        print(e, file=sys.stderr)


import public_fun
import sqlite3
import os
import traceback
from bs4 import BeautifulSoup
import re
import time

def init_sqlite_db(dbPath):
    '''
    返回一个sqlite数据库的实例
    '''
    conn = sqlite3.connect(dbPath)
    return conn

def file_list(filepath):
    '''
    遍历文件夹中的文件
    '''
    for root, dirs, files in os.walk(filepath):
        for file in files:
            yield os.path.join(root, file)

def get_title(pTagList):
    '''
    获取文献标题(中英文)
    '''
    aTag = pTagList[0].find('a')
    titleOne = aTag.string
    aTag = pTagList[1].find('a')
    titleTwo = aTag.string
    if titleTwo is None:
        return titleOne, ''
    regepx = re.compile(r'[\u4e00-\u9fa5]')
    match = regepx.search(titleOne)
    if match:
        title_c = titleOne
        title_e = titleTwo
    else:
        title_c = titleTwo
        title_e = titleOne

    return title_c, title_e

def get_creator(pTagList):
    '''
    获取文章作者
    '''
    creators_c = []
    creators_e = []
    aTagList = pTagList[2].find_all('a')
    for aTag in aTagList:
        creator = ''.join(aTag.stripped_strings)
        regepx = re.compile(r'\(')
        match = re.findall(regepx, creator)
        if len(match) > 0:
            tmp = creator.split('(')
            creators_c.append(tmp[0])
            creators_e.append(tmp[1][:-1])
        else:
            creators_c.append(creator)
    return ';'.join(creators_c), ';'.join(creators_e)

def get_institution_date_page(pTagList):
    """
    获取单位，发表日期，还有文章所在的页码
    """
    publisher_date_issues_page = (
        ''.join((pTagList[3].string).split())).split('；')
    creator_institution = publisher_date_issues_page[0][:-4]
    date_issue_page = publisher_date_issues_page[1].split('，')
    page = date_issue_page[1]
    date_issue = date_issue_page[0].split('(')
    date_created = ''.join((date_issue[1][:-1]).split('/'))
    return creator_institution, date_created, page

def get_lang_doi(pTagList):
    """
    获取语言与doi
    """
    lang_doi = list()
    for string in pTagList[4].stripped_strings:
        lang_doi.append(string)
    regepx = re.compile(r'(中文)')
    match = re.findall(regepx, lang_doi[0])
    if match:
        lang = "ZH"
    else:
        lang = "EN"
    try:
        doi = lang_doi[2]
    except IndexError:
        doi = ''
    return lang, doi

def get_keyword(pTagList):
    '''
    获取文献关键字
    '''
    subject = list()
    subject_en = list()
    aTagL = pTagList[5].find_all('a')
    for aTag in aTagL:
        keyword = ''.join(aTag.stripped_strings)
        if re.search(r'[\u4e00-\u9fa5]', keyword):
            subject.append(keyword)
        else:
            subject_en.append(keyword)
    return ';'.join(subject), ';'.join(subject_en)

def get_summy(soup):
    '''
    获取文献的摘要（中英）
    '''
    summy_e = soup.select('.TextArea2')
    # print(xxxx[0].string)
    summy_c = soup.select('.TextArea1')
    # print(xxx[0].string)
    return summy_c[0].string, summy_e[0].string

def get_university(rawid):
    uid = rawid.split('-')[0]
    conn = public_fun.init_db()
    cursor = conn.cursor()
    cursor.execute(
        'select university from universities where FirstID=%s', [uid])
    university = cursor.fetchone()
    cursor.close()
    conn.close()
    return university

def ProcOneFile(file):
    rawid = (file.split('\\')[1])[:-5]
    html = public_fun.read_html(file)
    soup = BeautifulSoup(html, 'lxml')
    pTagList = soup.select('.booksInformation > .detail > p')
    language, identifier_doi = get_lang_doi(pTagList)
    subject, subject_en = get_keyword(pTagList)
    lngid = 'AIRITILIBRARY_BS_' + rawid
    creator_discipline, date_created, page = get_institution_date_page(
        pTagList)
    title, title_alternative = get_title(pTagList)
    description, description_en = get_summy(soup)
    country = "CN"
    provider = 'airitithesis'
    provider_url = provider + \
        '@http://www.airitilibrary.cn/Publication/alDetailedMesh?DocID=' + rawid
    provider_id = provider + '@' + rawid
    university = get_university(rawid)
    creator, creator_en = get_creator(pTagList)
    tup = (
        lngid,
        rawid,
        identifier_doi,
        title,
        title_alternative,
        creator,
        creator_en,
        university[0],  # 论文发表者所在大学
        creator_discipline[len(university[0]):],  # 论文发表者的专业
        # creator_degree,  # 论文发表者的学位
        # contributor,  # 指导老师
        university[0],  # 所在单位
        page,
        description,
        description_en,
        subject,
        subject_en,
        date_created[:4],
        date_created,
        language,
        country,
        provider,
        provider_url,
        provider_id,
        4,
        2,
        time.strftime('%Y%m%d', time.localtime(time.time())) + '00'
    )
    return tup

if __name__ == "__main__":
    filePath = './down_by_doc_id/'
    conn = init_sqlite_db('./sqlite.db3')
    cursor = conn.cursor()
    sql = '''insert OR IGNORE into modify_title_info_zt
    (lngid,rawid,identifier_doi,title,title_alternative,creator,creator_en,creator_institution,creator_discipline,source_institution,page,
    description,description_en,subject,subject_en,date,date_created,
    language,country,provider,provider_url,provider_id,type,medium,batch) values(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)'''

    sqlList = list()
    for file in file_list(filePath):
        try:
            tup = ProcOneFile(file)
            sqlList.append(tup)
        except:
            exMsg = 'err file:' + file + '\n'
            exMsg += traceback.format_exc()
            print(exMsg)
            with open('./bug.log', 'a') as fp:
                fp.write(file)
                fp.write('\n')
                fp.write(exMsg)
                fp.write('\n')
            # sys.exit(-1)

        if len(sqlList) > 10:
            cursor.executemany(sql, sqlList)
            conn.commit()
            sqlList.clear()
        print('Parser ' + file + ' Successfully!!!')
    if len(sqlList) > 0:
        cursor.executemany(sql, sqlList)
        conn.commit()
        sqlList.clear()

    cursor.close()
    conn.close()
    print('Done!!!')


import pandas as pd

inflationEU_data = pd.read_csv("GDP per capita EU.csv")
rates_data = pd.read_csv("EUR_GBP Historical Data.csv")

# new_inflationEU_data = []
# for i in range(len(inflationEU_data)):
#     date = inflationEU_data.at[i, "Date"]
#     date = date.strip()
#     date = date.split(' ')
#     if date[0] == "Jan." or date[0] == "January":
#         date[0] = "Jan"
#     elif date[0] == "Feb." or date[0] == "February":
#         date[0] = "Feb"
#     elif date[0] == "Mar." or date[0] == "March":
#         date[0] = "Mar"
#     elif date[0] == "Apr." or date[0] == "April":
#         date[0] = "Apr"
#     elif date[0] == "May." or date[0] == "May":
#         date[0] = "May"
#     elif date[0] == "Jun." or date[0] == "June":
#         date[0] = "Jun"
#     elif date[0] == "Jan." or date[0] == "January":
#         date[0] = "Jan"
#     elif date[0] == "Jul." or date[0] == "July":
#         date[0] = "Jul"
#     elif date[0] == "Aug." or date[0] == "August":
#         date[0] = "Aug"
#     elif date[0] == "Sept." or date[0] == "September":
#         date[0] = "Sep"
#     elif date[0] == "Oct." or date[0] == "October":
#         date[0] = "Oct"
#     elif date[0] == "Nov." or date[0] == "November":
#         date[0] = "Nov"
#     elif date[0] == "Dec." or date[0] == "December":
#         date[0] = "Dec"
#     if date[1] == '1,' or date[1] == '2,' or date[1] == '3,' or date[1] == '4,' or date[1] == '5,' or date[1] == '6,' or date[1] == '7,' or date[1] == '8,' or date[1] == '9,':
#         date[1] = '0' + date[1]
#     new_date = date[0] + ' ' + date[1] + ' ' + date[2]
#     new_inflationEU_data.append([new_date, inflationEU_data.at[i, "Price"]])

new_inflationEU_data = []
for i in range(len(inflationEU_data)):
    inflation_date = inflationEU_data.at[i, "Date"]
    inflation_date = inflation_date.strip()
    inflation_date = inflation_date.split(' ')

    for j in range(len(rates_data)):
        rate_date = rates_data.at[j, "Date"]
        rate_date = rate_date.strip()
        rate_date = rate_date.split(' ')

        if inflation_date[0] == rate_date[0] and inflation_date[2] == rate_date[2]:
            new_date = rate_date[0] + ' ' + rate_date[1] + ' ' + rate_date[2]
            new_inflationEU_data.append([new_date, inflationEU_data.at[i, "Price"]])

for i in new_inflationEU_data:
    print(i)

inflationEU_rates = pd.DataFrame(new_inflationEU_data, columns=['Date', 'Price'])
inflationEU_rates.to_csv('GDP per capita EU.csv', index=False)


# -*- coding: utf-8 -*-
# チップ: ADXL345
# 型番など: 秋月電子通商(M-06724)
#
# 接続: I2Cデバイス - Raspberry Pi
# VDD - 3.3V
# GND - GND
# Vs - 3.3V
# Cs - 3.3V
# SCL - I2C SCL
# SDA - I2C SDA
# SDO - 3.3V
# 残りのピンは使用せず
#
# x方向加速度、y方向加速度、z方向加速度
# x方向傾き、y方向傾き
# が表示される
#
import smbus
from time import sleep
from math import atan2
from math import pi

def setup_adxl345():
    # full range
    bus.write_byte_data(address_adxl345, 0x31, 0x08)
    sleep(0.01)

    # start measure
    bus.write_byte_data(address_adxl345, 0x2d, 0x08)
    sleep(0.01)

def read_adxl345(register):
    data_l =  bus.read_byte_data(address_adxl345, register)
    data_h =  bus.read_byte_data(address_adxl345, register+1)

    data = (data_h<<8) | data_l

    if data & 0x8000 == 0:  # 正または0の場合
        data = data
    else: # 負の場合、 絶対値を取ってからマイナスをかける
        data = ( (~data&0xffff) + 1)*-1

    return acc_coef*data

def calc_angle(x, y):

    return atan2(x, y)*180/pi

bus = smbus.SMBus(1)
address_adxl345 = 0x1d
acc_coef = 4*9.81/1000 # 4mg

setup_adxl345()

try:
    while True:
        acc_x = read_adxl345(0x32)
        acc_y = read_adxl345(0x34)
        acc_z = read_adxl345(0x36)

        angle_x = calc_angle(acc_x, acc_z)
        angle_y = calc_angle(acc_y, acc_z)

        print("{0:.02f}, {1:.02f}, {2:.02f}".format(acc_x, acc_y, acc_z))
        print("angle_x={0:.02f}, angle_y={1:.02f}".format(angle_x, angle_y))

        sleep(0.2)

except KeyboardInterrupt:
    pass


# -*- coding: utf-8 -*-
"""
Created on Tue Jun 21 17:55:15 2016

@author: cliffk
"""

from optima import loadobj
from glob import glob
from os.path import sep

# Define things
projpath = '/home/cliffk/unsw/applications/global/nigeria/' # MAY WANT TO CHANGE THIS
debug = True # MAY WANT TO SET TO TRUE

ext = '.prj'
worked = []
failed = []
allorigfiles = glob(projpath+sep+'*'+ext)

for f,origfile in enumerate(allorigfiles):
    print('Working on file %i of %i' % (f+1, len(allorigfiles)))
    try:
        # Figure out the paths and load the files
        spreadsheetfile = origfile[:-len(ext)]+'.xlsx'
        print('Loading data...')
        P = loadobj(origfile)
        P.loadspreadsheet(spreadsheetfile, dorun=False)
        for parset in P.parsets.values():
            parset.pars[0]['birth'] = P.parsets['default'].pars[0]['birth'] # Copy default parset

        # Save project
        P.save(filename=origfile)
        worked.append(origfile)
    except Exception as E:
        failed.append(origfile+' | '+str(E))
        if debug: raise E

print('\n\n')
if len(worked):
    print('The following projects converted successfully:')
    print('\n'.join(worked))
print('\n\n')
if len(failed):
    print('The following projects FAILED MISERABLY:')
    print('\n'.join(failed))


""" Compiled: 2020-09-18 10:38:56 """

#__src_file__ = "extensions/MarkitSecuritiesFinance/etc/FMarkitSecuritiesFinanceInstall.py"

"""-------------------------------------------------------------------------------------------------------
MODULE
    FMarkitSecuritiesFinanceInstall - Installation script for Makit data Upload

    (c) Copyright 2012 SunGard FRONT ARENA. All rights reserved.

DESCRIPTION

    This module install Party, Choice List and Instrument alias type for Markit data upload.

-------------------------------------------------------------------------------------------------------"""

import acm

def create_alias_type():
    alias = acm.FInstrAliasType['CUSIP']
    if not alias:
        alias = acm.FInstrAliasType()
        alias.Name('CUSIP')
        alias.Commit()
    alias = acm.FInstrAliasType['SEDOL']
    if not alias:
        alias = acm.FInstrAliasType()
        alias.Name('SEDOL')
        alias.Commit()

def create_choice_list(list_name):
    ChoiceList = acm.FChoiceList[list_name]
    ChoiceList = acm.FChoiceList.Select('name='+list_name)
    if not ChoiceList:
        ChoiceList = acm.FChoiceList()
        ChoiceList.List(acm.FChoiceList["Product Type"])
        ChoiceList.Name(list_name)
        ChoiceList.Commit()
        return 1
    return 0

def SourceCreator(names=['Markit']):
    acm.BeginTransaction()
    try:
        for name in names:
            if not acm.FMarketPlace[name]:
                p = acm.FMarketPlace()
                p.Name(name)
                p.Commit()
        acm.CommitTransaction()
    except Exception:
        acm.AbortTransaction()
        print('Error inserting market places {}:{}'.format(names, traceback.format_exc()))

def Install(eii):
    SourceCreator()
    create_choice_list('Master Security Loan')
    create_alias_type()
    print('Sucesfully installed Markit data')


import time
import datetime
import os

import re
from threading import Thread, Lock

import pandas as pd
from openpyxl import load_workbook

def lock_process(func):
    lock = Lock()

    def wrapper(self, *args):
        lock.acquire()
        result = func(self, *args)
        lock.release()
        return result
    return wrapper

def debug(func):
    def wrapper(self, *args):  # 指定一毛一样的参数
        print("[DEBUG]: enter {}()".format(func.__name__))
        return func(self, *args)
    return wrapper  # 返回包装过函数

def get_star_count(morning_star_url):
    import numpy as np
    import requests
    from PIL import Image
    module_path = os.getcwd() + '/src'
    temp_star_url = module_path + '/assets/star/tmp.gif'
    r = requests.get(morning_star_url)
    with open(temp_star_url, "wb") as f:
        f.write(r.content)
    f.close()
    path = module_path + '/assets/star/star'

    # path = './assets/star/star'
    try:
        for i in range(6):
            p1 = np.array(Image.open(path + str(i) + '.gif'))
            p2 = np.array(Image.open(temp_star_url))
            if (p1 == p2).all():
                return i
    except:
        print('morning_star_url', morning_star_url)

def parse_csv(datafile):
    data = []
    with open(datafile, "r") as f:
        header = f.readline().split(",")  # 获取表头
        counter = 0
        for line in f:
            if counter == 10:
                break
            fields = line.split(",")
            entry = {}
            for i, value in enumerate(fields):
                entry[header[i].strip()] = value.strip()  # 用strip方法去除空白
            data.append(entry)
            counter += 1

    return data

def get_quarter_index(input_date):
    year = time.strftime("%Y", time.localtime())
    boundary_date_list = ['03-31', '06-30', '09-30', '12-31']

    input_date_strptime = datetime.datetime.strptime(
        year + '-' + input_date, '%Y-%m-%d')
    index = 1
    for idx in range(len(boundary_date_list)):
        join_date = year + '-' + boundary_date_list[idx]
        season_date_strptime = datetime.datetime.strptime(
            join_date, '%Y-%m-%d')
        if input_date_strptime <= season_date_strptime:
            index = idx + 1
            break
    return index

def get_last_quarter_str(last_index=1):
    last_quarter_time = time.localtime(
        time.time() - last_index * 3 * 30 * 24 * 3600)
    year = time.strftime("%Y", last_quarter_time)
    date = time.strftime("%m-%d", last_quarter_time)
    index = get_quarter_index(date)
    quarter_index_str = year + '-Q' + str(index)
    return quarter_index_str

def get_quarter_date(quarter_index_str):
    year = quarter_index_str.split('-')[0]
    boundary_date_list = ['03-31', '06-30', '09-30', '12-31']
    quarter_index = quarter_index_str.split('-')[1][1:]
    return year + '-' + boundary_date_list[int(quarter_index) - 1]

def fisrt_match_condition_from_list(list, code):
    for item in list:
        stock_code = item.split('-', 1)[0]
        is_exist = code == stock_code
        if is_exist:
            return item

def dict_list_to_list_list(dict_list, key_sort_list):
    tuple_list = []
    for item in dict_list:
        temp_list = []
        for key in key_sort_list:
            temp_list.append(item.get(key))
        tuple_list.append(temp_list)
    return tuple_list

def find_from_list_of_dict(dict_list, match_key, value):
    res = None
    for sub in dict_list:
        if sub[match_key] == value:
            res = sub
            break
    return res

def get_stock_market(stock_code):
    if bool(re.search("^\d{5}$", stock_code)):
        return '港股'
    elif bool(re.search("^\d{6}$", stock_code)) and bool(re.search(
            "^(00(0|1|2|3)\d{3})|(30(0|1)\d{3})|(60(0|1|2|3|5)\d{3})|68(8|9)\d{3}$", stock_code)):
        return 'A股'
    else:
        return '其他'

def update_xlsx_file(path, df_data, sheet_name):
    if os.path.exists(path):
        writer = pd.ExcelWriter(path, engine='openpyxl')
        book = load_workbook(path)
        # 表名重复，删掉，重写
        if sheet_name in book.sheetnames:
            del book[sheet_name]
        if len(book.sheetnames) == 0:
            df_data.to_excel(
                path, sheet_name=sheet_name)
            return
        else:
            writer.book = book
            df_data.to_excel(
                writer, sheet_name=sheet_name)
        writer.save()
        writer.close()
    else:
        df_data.to_excel(
            path, sheet_name=sheet_name)

def bootstrap_thread(target_fn, total, thread_count=2):
    threaders = []
    start_time = time.time()
    # 如果少于10个，只开一个线程
    if total < 10:
        thread_count = 1
    step_num = total / thread_count
    for i in range(thread_count):
        # start = steps[i]['start']
        # end = steps[i]['end']
        start = i * step_num
        end = (i + 1) * step_num
        t = Thread(target=target_fn, args=(int(start), int(end)))
        t.setDaemon(True)
        threaders.append(t)
        t.start()
    for threader in threaders:
        threader.join()
    end_time = time.time()
    print(total, 'run time is %s' % (end_time - start_time))


import pandas as pd

from PIL import Image
from pathlib import Path

from fastprogress import master_bar, progress_bar

from src.constants import HEIGHT, WIDTH

if __name__ == "__main__":
    data_dir = Path("input/bengaliai-cv19")

    mb = master_bar(["train", "test"])
    for data_type in mb:
        output_dir = data_dir / f"{data_type}_images"
        output_dir.mkdir(parents=True, exist_ok=True)

        for i in progress_bar(range(4), parent=mb, leave=False):
            df = pd.read_parquet(
                data_dir / f"{data_type}_image_data_{i}.parquet")
            images = df.iloc[:, 1:].values.reshape(-1, HEIGHT, WIDTH)

            for im in range(len(images)):
                image = Image.fromarray(images[im])
                image_id = df.loc[im, "image_id"]
                image.save(output_dir / f"{image_id}.png")


#!/usr/bin/env python3
import os
import rospy

import cv2
import time
import copy
import pickle
import traceback
import numpy as np

import tensorflow
from object_detection.utils import label_map_util
from object_detection.utils import visualization_utils as viz_utils

from dynamic_reconfigure.server import Server
from db_tensorflow.cfg import DetectConfig

import message_filters
from sensor_msgs.msg import Image, CameraInfo

from image_geometry import PinholeCameraModel

from geometry_msgs.msg import PoseStamped
from geometry_msgs.msg import PoseWithCovariance
from geometry_msgs.msg import Vector3

from vision_msgs.msg import Detection2D
from vision_msgs.msg import Detection2DArray
from vision_msgs.msg import ObjectHypothesisWithPose

from visualization_msgs.msg import MarkerArray
from visualization_msgs.msg import Marker

from std_msgs.msg import ColorRGBA

import tf2_ros
import tf2_geometry_msgs

import ctypes
# a thread gets killed improperly within CvBridge without this causing segfaults
libgcc_s = ctypes.CDLL('libgcc_s.so.1')

from cv_bridge import CvBridge, CvBridgeError

class RollingAvgRateLogger:
    def __init__(self, rolling_avg_window):
        self.rolling_avg_window = rolling_avg_window
        self.data = np.zeros(self.rolling_avg_window)
        self.index = 0

    def append(self, value):
        self.data[self.index] = value
        self.index += 1
        if self.index >= len(self.data):
            self.index = 0

    def rate(self):
        rate = 1.0 / np.mean(self.data)
        return rate

    def avg(self):
        return np.mean(self.data)

class BoxDescription:
    def __init__(self):
        self.class_index = 0
        self.class_name = ""
        self.score = 0.0
        self.box = (0.0, 0.0, 0.0, 0.0)
        self.xcenter = 0.0
        self.ycenter = 0.0
        self.xsize = 0.0
        self.ysize = 0.0
        self.obj_radius = 0.0
        self.detect_radius = 0.0

        self.pose_stamped = PoseStamped()
        self.xedge = 0.0
        self.yedge = 0.0
        self.zedge = 0.0

class DodobotTensorflow:
    def __init__(self):
        self.node_name = "db_tensorflow"
        rospy.init_node(
            self.node_name
            # disable_signals=True
            # log_level=rospy.DEBUG
        )
        # rospy.on_shutdown(self.shutdown)

        self.image_topic_name = rospy.get_param("~image_topic", "color/image_raw")
        self.depth_topic_name = rospy.get_param("~depth_topic", "depth/image_raw")
        self.info_topic_name = rospy.get_param("~camera_info_topic", "color/camera_info")

        self.labels_path = rospy.get_param("~labels_path", "annotations/label_map.pbtxt")
        self.model_path = rospy.get_param("~model_path", "models/dodobot_objects_ssd_resnet50_v1_fpn")

        self.min_score_threshold = rospy.get_param("~min_score_threshold", 0.3)
        self.max_boxes_to_draw = rospy.get_param("~max_boxes_to_draw", 20)
        self.bounding_box_border_px = rospy.get_param("~bounding_box_border_px", 30)
        self.z_size_estimations = rospy.get_param("~z_size_estimations", None)
        marker_colors = rospy.get_param("~marker_colors", None)
        self.publish_in_robot_frame = rospy.get_param("~publish_in_robot_frame", True)
        self.robot_frame = rospy.get_param("~robot_frame", "base_link")
        self.marker_persistance = rospy.get_param("~marker_persistance_s", 0.5)
        self.default_z_size = rospy.get_param("~default_z_size", 0.05)
        self.min_valid_z = rospy.get_param("~min_valid_z", 0.03)
        self.max_valid_z = rospy.get_param("~max_valid_z", 3.0)

        self.marker_persistance = rospy.Duration(self.marker_persistance)
        self.marker_colors = {name: ColorRGBA(*args) for name, args in marker_colors.items()}

        self.image_sub = message_filters.Subscriber(self.image_topic_name, Image)
        self.depth_sub = message_filters.Subscriber(self.depth_topic_name, Image)

        self.detect_fn = None
        self.category_index = None

        self.dyn_server = Server(DetectConfig, self.dyn_callback)

        self.time_sync_sub = message_filters.TimeSynchronizer([self.image_sub, self.depth_sub], 1)
        # self.time_sync_sub = message_filters.ApproximateTimeSynchronizer([self.image_sub, self.depth_sub], 10, 0.005)

        self.visualization_image_pub = rospy.Publisher("detect_overlay", Image, queue_size=1)

        self.detect_pub = rospy.Publisher("detections", Detection2DArray, queue_size=10)
        self.marker_pub = rospy.Publisher("obj_markers", MarkerArray, queue_size=25)

        self.bridge = CvBridge()
        self.camera_model = PinholeCameraModel()

        self.detect_rate_logger = RollingAvgRateLogger(10)
        self.update_rate_logger = RollingAvgRateLogger(10)
        self.camera_rate_logger = RollingAvgRateLogger(10)
        self.depth_rate_logger = RollingAvgRateLogger(10)

        self.tf_buffer = tf2_ros.Buffer()
        self.tf_listener = tf2_ros.TransformListener(self.tf_buffer)

        # with open("/home/ben/detection.pkl", 'rb') as file:
        #     self.dummy_detections = pickle.load(file)

        self.generate_detect_fn()

        self.time_sync_sub.registerCallback(self.rgbd_callback)
        self.info_sub = rospy.Subscriber(self.info_topic_name, CameraInfo, self.camera_info_callback, queue_size=5)

        rospy.loginfo("%s init done" % self.node_name)

    def generate_detect_fn(self):
        if not os.path.isfile(self.labels_path):
            raise FileNotFoundError("Labels path doesn't exist: %s" % self.labels_path)

        if not os.path.isdir(self.model_path):
            raise FileNotFoundError("Model path doesn't exist: %s" % self.model_path)

        category_index = label_map_util.create_category_index_from_labelmap(self.labels_path, use_display_name=True)

        rospy.loginfo("Loading model...")
        start_time = time.time()
        # Load saved model and build the detection function
        detect_fn = tensorflow.saved_model.load(self.model_path)
        # detect_fn = None

        end_time = time.time()
        elapsed_time = end_time - start_time
        rospy.loginfo("Model took %0.2f seconds to load" % (elapsed_time))

        self.detect_fn = detect_fn
        self.category_index = category_index

        rospy.loginfo("Priming the pump...")
        color_image_np = np.zeros((540, 960, 3), dtype=np.uint8)
        start_time = time.time()
        self.run_detection(color_image_np)
        end_time = time.time()
        elapsed_time = end_time - start_time

        rospy.loginfo("Priming took %0.2f seconds" % (elapsed_time))

    def rgbd_callback(self, color_image, depth_image):
        t0 = rospy.Time.now()
        detections = self.detection_pipeline(color_image)

        detect_array_msg = Detection2DArray()
        markers_msg = MarkerArray()

        for index in range(detections["num_detections"]):
            score = detections["detection_scores"][index]
            if score < self.min_score_threshold:
                continue
            box = detections["detection_boxes"][index]
            class_index = detections["detection_classes"][index]
            desc = self.depth_pipeline(box, score, class_index, depth_image)

            if desc.pose_stamped is None or not (self.min_valid_z <= desc.pose_stamped.pose.position.z <= self.max_valid_z):
                continue

            detect_msg = self.get_detect_msg(desc)

            if self.publish_in_robot_frame:
                new_pose = self.object_to_robot_frame(desc.pose_stamped, color_image.header)
                if new_pose is None:
                    continue
                else:
                    desc.pose_stamped = new_pose

            detection_pose = PoseWithCovariance()
            detection_pose.pose = desc.pose_stamped.pose
            detect_msg.results[0].pose = detection_pose
            detect_msg.header = desc.pose_stamped.header

            markers = self.make_markers(desc)

            detect_array_msg.detections.append(detect_msg)
            markers_msg.markers.extend(markers)

        detect_array_msg.header.stamp = color_image.header.stamp

        self.detect_pub.publish(detect_array_msg)
        self.marker_pub.publish(markers_msg)

        t1 = rospy.Time.now()
        self.update_rate_logger.append((t1 - t0).to_sec())
        self.camera_rate_logger.append((t0 - color_image.header.stamp).to_sec())
        rospy.loginfo_throttle(10, "Detection rate avg: %0.3f Hz" % self.update_rate_logger.rate())
        rospy.loginfo_throttle(10, "Camera delay avg: %0.3fs" % self.camera_rate_logger.avg())

    def camera_info_callback(self, camera_info):
        self.camera_model.fromCameraInfo(camera_info)

    def run_detection(self, color_image_np):
        input_tensor = tensorflow.convert_to_tensor(color_image_np)
        input_tensor = input_tensor[tensorflow.newaxis, ...]

        t0 = rospy.Time.now()
        # if self.detect_fn is None:
        #     detections = copy.deepcopy(self.dummy_detections)
        # else:
        detections = self.detect_fn(input_tensor)
            # with open("/home/ben/detection.pkl", 'wb') as file:
            #     pickle.dump(detections, file)
        t1 = rospy.Time.now()
        self.detect_rate_logger.append((t1 - t0).to_sec())

        rospy.loginfo_throttle(10, "Detection rate avg: %0.3f Hz" % self.detect_rate_logger.rate())

        return detections

    def detection_pipeline(self, color_image):
        try:
            # Convert ROS Image message to numpy array
            color_image_np = self.bridge.imgmsg_to_cv2(color_image, "rgb8")
        except CvBridgeError as e:
            rospy.logerr(e)
            return

        detections = self.run_detection(color_image_np)

        num_detections = int(detections.pop("num_detections"))
        detections = {key: value[0, :num_detections].numpy() for key, value in detections.items()}
        detections["num_detections"] = num_detections

        # detection_classes should be ints.
        detections["detection_classes"] = detections["detection_classes"].astype(np.int64)

        image_with_detections = color_image_np.copy()

        self.publish_visualization(detections, image_with_detections)

        return detections

    def depth_pipeline(self, box, score, class_index, depth_image):
        t0 = time.time()
        class_name = self.category_index[class_index]["name"]
        ymin, xmin, ymax, xmax = box

        # depth image dimensions should be the same as the color image because
        # the depth image has been registered/shifted to be overlaid on top of the color image
        ymin *= depth_image.height
        ymax *= depth_image.height
        xmin *= depth_image.width
        xmax *= depth_image.width

        xcenter = (xmax + xmin) / 2.0
        ycenter = (ymax + ymin) / 2.0
        xsize = xmax - xmin
        ysize = ymax - ymin
        obj_radius = min(xsize, ysize) / 2.0
        detect_radius = max(obj_radius - self.bounding_box_border_px, 1)

        desc = BoxDescription()
        desc.class_index = class_index
        desc.class_name = class_name
        desc.score = score
        desc.box = (ymin, xmin, ymax, xmax)
        desc.xcenter = xcenter
        desc.ycenter = ycenter
        desc.xsize = xsize
        desc.ysize = ysize
        desc.obj_radius = obj_radius
        desc.detect_radius = detect_radius

        if self.z_size_estimations is not None:
            zsize = self.z_size_estimations.get(class_name, self.default_z_size)
        else:
            zsize = self.default_z_size
        z_depth = self.z_depth_from_image(depth_image, desc)
        if z_depth is None:
            return None
        z_depth += zsize / 2.0  # move to the rough center of the object
        ray = self.camera_model.projectPixelTo3dRay((desc.xcenter, desc.ycenter))

        x_pos = ray[0] * z_depth
        y_pos = ray[1] * z_depth

        pose = PoseStamped()
        pose.header.frame_id = self.camera_model.tfFrame()
        pose.header.stamp = depth_image.header.stamp
        pose.pose.position.x = x_pos
        pose.pose.position.y = y_pos
        pose.pose.position.z = z_depth
        pose.pose.orientation.x = 0.0
        pose.pose.orientation.y = 0.0
        pose.pose.orientation.z = 0.0
        pose.pose.orientation.w = 1.0

        edge_point_x = desc.xcenter - xsize / 2.0
        edge_point_y = desc.ycenter - ysize / 2.0
        ray = self.camera_model.projectPixelTo3dRay((edge_point_x, edge_point_y))

        desc.pose_stamped = pose
        desc.xedge = abs(ray[0] * z_depth - x_pos) * 2.0
        desc.yedge = abs(ray[1] * z_depth - y_pos) * 2.0
        desc.zedge = zsize

        t1 = time.time()
        self.depth_rate_logger.append(t1 - t0)
        rospy.loginfo_throttle(10, "Depth pipeline rate avg: %0.3f Hz" % self.depth_rate_logger.rate())

        return desc

    def z_depth_from_image(self, depth_image, desc: BoxDescription):
        try:
            # Convert ROS Image message to numpy array
            depth_image_np = self.bridge.imgmsg_to_cv2(depth_image, desired_encoding="passthrough")
        except CvBridgeError as e:
            rospy.logerr(e)
            return None
        depth_image_np = depth_image_np.astype(np.float32)
        circle_mask = np.zeros(depth_image_np.shape, np.uint8)
        cv2.circle(circle_mask, (int(desc.xcenter), int(desc.ycenter)), int(desc.detect_radius), (255, 255, 255), cv2.FILLED)
        nonzero_mask = (depth_image_np > 0.0).astype(np.uint8)
        target_mask = cv2.bitwise_and(circle_mask, nonzero_mask)
        z_depth = cv2.mean(depth_image_np, target_mask)[0]
        z_depth /= 1000.0
        return z_depth

    def publish_visualization(self, detections, image_with_detections):
        if self.visualization_image_pub.get_num_connections() == 0:
            return
        viz_utils.visualize_boxes_and_labels_on_image_array(
            image_with_detections,
            detections["detection_boxes"],
            detections["detection_classes"],
            detections["detection_scores"],
            self.category_index,
            use_normalized_coordinates=True,
            max_boxes_to_draw=self.max_boxes_to_draw,
            min_score_thresh=self.min_score_threshold,
            agnostic_mode=False
        )

        try:
            visualize_image_msg = self.bridge.cv2_to_imgmsg(image_with_detections, "rgb8")
        except CvBridgeError as e:
            rospy.logerr(e)
            return
        self.visualization_image_pub.publish(visualize_image_msg)

    def get_detect_msg(self, desc: BoxDescription):
        detect_msg = Detection2D()
        detect_msg.bbox.size_x = desc.xsize
        detect_msg.bbox.size_y = desc.ysize
        detect_msg.bbox.center.x = desc.xcenter
        detect_msg.bbox.center.y = desc.ycenter
        hyp = ObjectHypothesisWithPose()

        hyp.id = desc.class_index
        hyp.score = desc.score
        detect_msg.results.append(hyp)
        return detect_msg

    def object_to_robot_frame(self, pose_stamped, image_header):
        try:
            transform = self.tf_buffer.lookup_transform(
                self.robot_frame,
                image_header.frame_id,
                image_header.stamp,
                rospy.Duration(1.0)
            )
        except (tf2_ros.LookupException, tf2_ros.ConnectivityException, tf2_ros.ExtrapolationException) as e:
            rospy.logwarn("Failed to look up %s to %s. %s" % (self.robot_frame, image_header.frame_id, e))
            return None
        pose_robot_frame = tf2_geometry_msgs.do_transform_pose(pose_stamped, transform)
        return pose_robot_frame

    def dyn_callback(self, config, level):
        rospy.loginfo("Reconfigure Request: %s. Level: %s" % (str(config), level))
        if level >= 0:
            rospy.loginfo("Reconfiguring")
            self.min_score_threshold = config["min_score_threshold"]
            self.max_boxes_to_draw = config["max_boxes_to_draw"]
            self.bounding_box_border_px = config["bounding_box_border_px"]
            self.min_valid_z = config["min_valid_z"]
            self.max_valid_z = config["max_valid_z"]
        return config

    def make_markers(self, desc: BoxDescription):
        sphere_marker = self.make_marker_base(desc)
        text_marker = self.make_marker_base(desc)

        sphere_marker.type = Marker.SPHERE
        sphere_marker.ns = "sphere_" + sphere_marker.ns

        text_marker.type = Marker.TEXT_VIEW_FACING
        text_marker.ns = "text_" + text_marker.ns
        text_marker.text = desc.class_name + "_" + str(desc.class_index)
        text_marker.scale.x = 0.0
        text_marker.scale.y = 0.0

        return [sphere_marker, text_marker]

    def make_marker_base(self, desc: BoxDescription):
        marker = Marker()
        marker.action = Marker.ADD
        marker.pose = desc.pose_stamped.pose
        marker.header = desc.pose_stamped.header
        marker.lifetime = self.marker_persistance
        marker.ns = desc.class_name
        marker.id = desc.class_index

        scale_vector = Vector3()
        scale_vector.x = desc.xedge
        scale_vector.y = desc.yedge
        scale_vector.z = desc.zedge
        marker.scale = scale_vector
        if self.marker_colors is not None and desc.class_name in self.marker_colors:
            marker.color = self.marker_colors[desc.class_name]
        else:
            marker.color = ColorRGBA(1.0, 1.0, 1.0, 1.0)

        return marker

    def run(self):
        rospy.spin()

if __name__ == "__main__":
    try:
        node = DodobotTensorflow()
        node.run()
    except rospy.ROSInterruptException:
        pass
    except BaseException as e:
        rospy.logerr("%s: %s\n%s" % (e.__class__.__name__, str(e), traceback.format_exc()))
    finally:
        rospy.loginfo("Exiting db_tensorflow node")