import os
import numpy as np
from scipy.optimize import curve_fit
import pandas as pd
import matplotlib.pyplot as plt
from model import simulate, load_models
from eods import plot_eod_interval_hist
from baseline import interval_statistics, serial_correlations, vector_strength, cyclic_rate
import plottools.plottools as pt

def plot_style():
    """ Settings and styles for the plots.

    Returns
    -------
    s: namespace
        Plotting styles (dictionaries with colors, line poperties, ...).
    """
    class s:
        colors = pt.palettes['muted']
        data_color = colors['blue']
        model_color = colors['red']
        onset_color = colors['green']
        ss_color = colors['red']
        base_color = colors['lightblue']
        error_color = colors['red']
        poscontrast_color = colors['magenta']
        negcontrast_color = colors['purple']

        lw = 1.5
        ms = 4

        lsGrid = dict(color='gray', ls=':', lw=0.5)
        lsData = dict(color=data_color, lw=lw)
        lsModel = dict(color=model_color, lw=lw)
        lpsData = dict(color=data_color, ls='-', lw=lw, marker='o', ms=ms, clip_on=False)
        lpsModel = dict(color=model_color, ls='-', lw=lw, marker='o', ms=ms, clip_on=False)
        fsData = dict(color=data_color, alpha=0.5)
        fsModel = dict(color=model_color, alpha=0.5)
        psOnset = dict(ls='none', color=onset_color, marker='o', ms=ms, clip_on=False)
        psSS = dict(ls='none', color=ss_color, marker='o', ms=ms, clip_on=False)
        lsOnset = dict(ls='-', color=onset_color, lw=lw)
        lsSS = dict(ls='-', color=ss_color, lw=lw)
        lsBase = dict(ls='-', color=base_color, lw=lw)
        lsDataLine = dict(color='black', lw=lw, zorder=-10)
        lsModelLine = dict(color='gray', lw=lw, zorder=-10)

        lsPosContrast = dict(ls='-', color=poscontrast_color, lw=lw)
        lsNegContrast = dict(ls='-', color=negcontrast_color, lw=lw)
        fsError = dict(color=error_color, alpha=1)
    pt.axes_params(0, 0, 0, 'none')
    pt.figure_params(format='pdf')
    pt.spines_params('lb')
    pt.legend_params(fontsize='small', frameon=False,
                     handlelength=1.2, borderpad=0)
    return s

def instantaneous_rate(spikes, time):
    """Firing rate as the inverse of the interspike intervals.

    Parameter
    ---------
    spikes: ndarrays of floats
        Spike times of a single trial.
    time: ndarray of floats
        Times on which instantaneous rate is computed.

    Returns
    -------
    rate: ndarray of floats
        Instantaneous firing rate corresponding to `spikes`.
    """
    isis = np.diff(spikes)                        # well, the ISIs
    inst_rate = 1 / isis                          # rate as inverse ISIs
    # indices (int!) of spike times in time array:
    dt = time[1] - time[0]
    spike_indices = np.asarray(np.round((spikes-time[0])/dt), int)
    spike_indices = spike_indices[(spike_indices >= 0) &
                                  (spike_indices < len(time))]
    rate = np.zeros(len(time))
    for i in range(len(spike_indices)-1): # for all spikes and ISIs, except the last
        # set the full ISI to the instantaneous rate of that ISI:
        rate[spike_indices[i]:spike_indices[i+1]] = inst_rate[i]
    return rate

def plot_comparison(ax, s, title, error):
    ax.show_spines('r')
    ax.tick_params(axis='both', which='major', labelsize='x-small')
    ax.text(0, 1.1, title, transform=ax.transAxes, ha='left', fontsize='small')
    if error < 0.02:
        error = 0.02
    ax.bar(0, 100*np.abs(error), width=1, **s.fsError)
    ax.set_xlim(-0.8, 0.8)
    ax.set_ylim(0.0, 30)
    ax.set_yticks_fixed([0, 20], ['0%', '20%'])
    plt.setp(ax.get_yticklabels(), rotation=90, va='center')

def baseline_data(data_path, cell):
    """ Load baseline spike and EOD events measured in a cell.

    Parameters
    ----------
    data_path: str
         Base path with the cell data folders.
    cell: str
         Name of the cell its data folder.

    Returns
    -------
    spikes: ndarray of floats
        Times of spikes.
    eods: ndarray of floats
        Times of EOD cacles.
    """
    spikes = np.load(os.path.join(data_path, cell, 'baseline_spikes_trial_1.npy'))
    eods = np.load(os.path.join(data_path, cell, 'baseline_eods_trial_1.npy'))
    return spikes, eods

def baseline_model(EODf, model_params, tmax=10):
    """ Simulate baseline activity.

    Parameters
    ----------
    EODf: float
        EOD frequency in Hertz
    model_params: dict
        Model parameters.
    tmax: float
        Time to simulate baseline activity.
    """
    deltat = model_params["deltat"]
    time = np.arange(0, tmax, deltat)
    # baseline EOD with amplitude 1:
    stimulus = np.sin(2*np.pi*EODf*time)
    # integrate the model:
    spikes = simulate(stimulus, **model_params)
    return spikes

def analyse_baseline(EODf, data_spikes, data_eods, model_spikes,
                     data={}, model={}, max_eods=15.5, max_lag=15):
    """ Compute and plot baseline statistics for data and model spikes. """
    eod_period = 1/EODf
    # analyse data:
    data_isi, data_kde, data_rate, data_cv = \
        interval_statistics(data_spikes, sigma=0.05*eod_period, maxisi=max_eods*eod_period)
    data_lags, data_corrs, data_low, data_high = serial_correlations(data_spikes, max_lag=max_lag)
    data_vs = vector_strength(data_spikes, data_eods)
    data_cphase, data_crate = cyclic_rate(data_spikes, data_eods, sigma=0.02)
    # analyse model:
    model_isi, model_kde, model_rate, model_cv = \
        interval_statistics(model_spikes, sigma=0.05*eod_period, maxisi=max_eods*eod_period)
    model_lags, model_corrs, model_low, model_high = serial_correlations(model_spikes, max_lag=max_lag)
    model_vs = vector_strength(model_spikes, eod_period)
    model_cphase, model_crate = cyclic_rate(model_spikes, eod_period, sigma=0.02)
    data['isis'] = data_isi
    data['hist'] = data_kde
    data['rate'] = data_rate
    data['CV'] = data_cv
    data['lags'] = data_lags
    data['corrs'] = data_corrs
    data['corrs_low'] = data_low
    data['corrs_high'] = data_high
    data['vectorstrength'] = data_vs
    data['cyclic_phases'] = data_cphase
    data['cyclic_rates'] = data_crate
    model['isis'] = model_isi
    model['hist'] = model_kde
    model['rate'] = model_rate
    model['CV'] = model_cv
    model['lags'] = model_lags
    model['corrs'] = model_corrs
    model['corrs_low'] = model_low
    model['corrs_high'] = model_high
    model['vectorstrength'] = model_vs
    model['cyclic_phases'] = model_cphase
    model['cyclic_rates'] = model_crate
    return data, model

def plot_baseline(axi, axc, axv, axb, s, EODf, data, model):
    """ Compute and plot baseline statistics for data and model spikes. """
    eod_period = 1/EODf
    # plot isih statistics:
    for eod in np.arange(1, int(data['isis'][-1]/eod_period), 1):
        axi.axvline(1000*eod*eod_period, **s.lsGrid)
    axi.fill_between(1000*data['isis'], data['hist']/1000, **s.fsData)
    axi.fill_between(1000*model['isis'], model['hist']/1000, **s.fsModel)
    axi.plot(1000*data['isis'], data['hist']/1000, **s.lsData)
    axi.plot(1000*model['isis'], model['hist']/1000, **s.lsModel)
    axi.text(1, 0.95, f'$r={data["rate"]:.0f}$Hz',
            transform=axi.transAxes, ha='right')
    axi.text(1, 0.83, f'$CV^{{(d)}}={data["CV"]:.2f}$',
            transform=axi.transAxes, ha='right')
    axi.text(1, 0.71, f'$CV^{{(m)}}={model["CV"]:.2f}$',
            transform=axi.transAxes, ha='right')
    axi.set_xlabel('ISI', 'ms')
    axi.set_ylabel('pdf', '1/ms')
    axi.set_xticks_delta(10)
    # plot serial correlations:
    axc.axhspan(data['corrs_low'], data['corrs_high'], **s.fsData)
    axc.axhline(0, **s.lsGrid)
    axc.plot(data['lags'], data['corrs'], label='data', **s.lpsData)
    axc.plot(model['lags'], model['corrs'], label='model', **s.lpsModel)
    axc.text(1, 0.95, f'$\\rho^{{(d)}}_1={data["corrs"][1]:.2f}$',
            transform=axc.transAxes, ha='right')
    axc.text(1, 0.83, f'$\\rho^{{(m)}}_1={model["corrs"][1]:.2f}$',
            transform=axc.transAxes, ha='right')
    axc.set_ylim(-1, 1)
    axc.set_xlabel('Lag $k$')
    axc.set_ylabel('Correlation $\\rho_k$')
    axc.set_xticks_delta(5)
    axc.legend(loc='lower right', markerfirst=False)
    # plot vector strength:
    axv.fill_between(data['cyclic_phases'], data['cyclic_rates'], **s.fsData)
    axv.fill_between(model['cyclic_phases'], model['cyclic_rates'], **s.fsModel)
    axv.plot(data['cyclic_phases'], data['cyclic_rates'], **s.lsData)
    axv.plot(model['cyclic_phases'], model['cyclic_rates'], **s.lsModel)
    axc.text(1.9, 0.95, f'$VS^{{(d)}}={data["vectorstrength"]:.2f}$',
            transform=axc.transAxes, ha='right')
    axc.text(1.9, 0.83, f'$VS^{{(m)}}={model["vectorstrength"]:.2f}$',
            transform=axc.transAxes, ha='right')
    axv.set_rlim(0, 0.5)
    axv.set_rorigin(-0.2)
    axv.set_xticks_pifracs(4)
    axv.set_yticks_blank()
    # comparison:
    plot_comparison(axb[0], s, '$CV$', np.abs(data['CV'] - model['CV']))
    axb[0].set_visible(False)
    plot_comparison(axb[1], s, '$CV$', np.abs(data['CV'] - model['CV']))
    plot_comparison(axb[2], s, '$\\rho_1$', np.abs(data['corrs'][1] - model['corrs'][1]))
    plot_comparison(axb[3], s, '$VS$', np.abs(data["vectorstrength"] - model["vectorstrength"]))

def ficurve_data(data_path, cell):
    """ Load fI curve data measured in a cell.

    Parameters
    ----------
    data_path: str
         Base path with the cell data folders.
    cell: str
         Name of the cell its data folder.

    Returns
    -------
    contrasts: ndarray of floats
        Contrasts of step stimuli.
    fonset: ndarray of floats
        Onset spike frequency in Hertz.
    fss: ndarray of floats
        Steady-state spike frequncy in Hertz.
    """
    file_path = os.path.join(data_path, cell, 'fi_curve_info.csv')
    data = pd.read_csv(file_path, index_col=0, comment='#')
    contrasts = data.contrast.to_numpy()
    fonset = data.f_zero.to_numpy()
    fss = data.f_inf.to_numpy()
    return contrasts, fonset, fss

def firate_model(EODf, model_params, contrasts, t0=-0.4, t1=0.2):
    """ Simulate spike frequencies in response to step stimuli.

    Parameters
    ----------
    EODf: float
        EOD frequency in Hertz
    model_params: dict
        Model parameters.
    contrasts: ndarray of floats
        Contrasts for which responses are simulated.
    t0: float
        Start of simulation before the step in seconds (negative).
    t1: float
        End of simulation after the step in seconds.
    """
    deltat = model_params["deltat"]
    time = np.arange(t0, t1, deltat)
    rates = [None] * len(contrasts)
    for i, contrast in enumerate(contrasts):
        # generate EOD stimulus with an amplitude step:
        stimulus = np.sin(2*np.pi*EODf*time)
        stimulus[np.argmin(np.abs(time)):] *= (1.0+contrast)
        # integrate the model:
        n = 20
        rate = np.zeros(len(time))
        for k in range(n):
            model_params['v_zero'] = np.random.rand()
            model_params['a_zero'] += 0.02*model_params['a_zero']*np.random.randn()
            spikes = simulate(stimulus, **model_params)
            spikes += time[0]
            trial_rate = instantaneous_rate(spikes, time)
            rate += trial_rate/n
        rates[i] = rate
    return time, rates

def ficurves(time, rates, ton=0.05, tss0=0.1, tss1=0.05, tbase=0.1):
    """ Extract onset and steady-state firing rates from step responses.

    The step stimuli start at time 0 and extend to the end of `time`.

    Parameters
    ----------
    time: ndarray of floats
        Time points of firing rate estimates in `rates`.
        Can be less than the arrays in `rates`.
    rates: list of ndarrays of floats
        Firing rate estimates to be analysed.
    ton: float
        Time interval right after stimulus onset in which to look
        for the onset rate.
    tss0: float
        Start time before stimulus end for estimating steady-state response.
    tss1: float
        End time before stimulus end for estimating steady-state response.
    tbase: float
        Time interval right before stimulus onset for estimating baseline rate.

    Returns
    -------
    fonset: ndarray of floats
        For each response in `rates`, the maximum deviation from
        the baseline rate after stimulus onset.
    fss: ndarray of floats
        For each response in `rates`, the steady-state firing rate
        during the end of the step stimulus, between `tss0` and `tss1`
        before stimulus end.
    baseline: ndarray of floats
        For each response in `rates`, the firing rate during `tbase`
        before the step stimulus.
    """
    baseline = np.zeros(len(rates))
    fonset = np.zeros(len(rates))
    fss = np.zeros(len(rates))
    for i in range(len(rates)):
        rate = rates[i][:len(time)]
        baseline[i] = np.mean(rate[(time > -tbase) & (time < 0)])
        fss[i] = np.mean(rate[(time > time[-1] - tss0) & (time < time[-1] - tss1)])
        fmax = np.max(rate[(time > 0) & (time < ton)])
        fmin = np.min(rate[(time > 0) & (time < ton)])
        fonset[i] = fmax if np.abs(fmax - baseline[i]) > np.abs(fmin - baseline[i]) else fmin
    return fonset, fss, baseline

def sigmoid(x, x0, k, ymax):
    return ymax/(1 + np.exp(-k*(x - x0)))

def fit_ficurves(EODf, contrasts, fonset, fss, data={}):
    fon_contrasts = np.linspace(np.min(contrasts), np.max(contrasts), 200)
    # onset slopes:
    popt = [0.05, 0.03*EODf, EODf]
    try:
        popt, _ = curve_fit(sigmoid, contrasts, fonset, popt)
        fon_slope = popt[2]*popt[1]/4
        fon_line = sigmoid(fon_contrasts, *popt)
    except RuntimeError:
        fon_slope, fon_b = np.polyfit(contrasts, fonset, deg=1)
        fon_line = fon_slope*fon_contrasts + fon_b
    # ss slopes:
    min_contr = -0.2
    max_contr = +0.2
    sel = (contrasts >= min_contr) & (contrasts < max_contr)
    fss_slope, fss_b = np.polyfit(contrasts[sel], fss[sel], deg=1)
    fss_contrasts = np.linspace(min_contr, max_contr, 200)
    fss_line = fss_slope*fss_contrasts + fss_b
    data['fon_slope'] = fon_slope
    data['fon_contrasts'] = fon_contrasts
    data['fon_line'] = fon_line
    data['fss_slope'] = fss_slope
    data['fss_contrasts'] = fss_contrasts
    data['fss_line'] = fss_line
    return data

def plot_ficurves(ax, axc, s, EODf, data_contrasts, data_fonset, data_fss,
                  model_contrasts, model_fonset, model_fss, data, model):
    """ Plot fI curves. """
    ax.axvline(0, **s.lsGrid)
    ax.axhline(EODf, **s.lsGrid)
    ax.axhline(data['rate'], **s.lsBase)
    ax.plot(100*model_contrasts, model_fss, label='$f_{\infty}(I)$', **s.lsSS)
    ax.plot(100*model_contrasts, model_fonset, label='$f_0(I)$', **s.lsOnset)
    sel = (data_contrasts >= model_contrasts[0]) & (data_contrasts <= model_contrasts[-1])
    ax.plot(100*data_contrasts[sel], data_fss[sel], **s.psSS)
    ax.plot(100*data_contrasts[sel], data_fonset[sel], **s.psOnset)
    ax.set_xlim(100*model_contrasts[0], 100*model_contrasts[-1])
    ax.set_ylim(0, 1200)
    ax.set_xticks_delta(15)
    ax.set_xlabel('Contrast', '%')
    ax.set_ylabel('Spike frequency', 'Hz')
    # comparison onset slopes:
    ax.plot(100*data['fon_contrasts'], data['fon_line'], **s.lsDataLine)
    ax.plot(100*model['fon_contrasts'], model['fon_line'], **s.lsModelLine)
    plot_comparison(axc[0], s, '$s$', np.abs(model['fon_slope'] - data['fon_slope'])/data['fon_slope'])
    # comparison ss slopes:
    ax.plot(100*data['fss_contrasts'], data['fss_line'], **s.lsDataLine)
    ax.plot(100*model['fss_contrasts'], model['fss_line'], **s.lsModelLine)
    ax.legend(loc='upper left')
    plot_comparison(axc[2], s, '$s$', np.abs(model['fss_slope'] - data['fss_slope'])/data['fss_slope'])
    # comparison chi squared:
    model_idxs = [np.argmin(np.abs(model_contrasts - data_contrasts[i]))
                  for i in range(len(data_contrasts))]
    chifon = np.sum((data_fonset - model_fonset[model_idxs])**2)
    chifss = np.sum((data_fss - model_fss[model_idxs])**2)
    normfon = len(data_contrasts)*(EODf/4)**2
    normfss = len(data_contrasts)*(data['rate']/2)**2
    plot_comparison(axc[1], s, '$\chi^2 f_{on}$', chifon/normfon)
    plot_comparison(axc[3], s, '$\chi^2 f_{ss}$', chifss/normfss)

def plot_firates(ax, axc, s, contrasts, time, rates):
    """ Plot a few selected firng rates in response to step stimuli. """
    for contrast, rate, color in zip(contrasts, rates, s.rate_colors):
        ax.plot(1000*time, rate, label=f'${100*contrast:+.0f}$%', **color)
    ax.legend(ncol=3, loc='upper right', bbox_to_anchor=(1, 1.1))
    ax.set_xlim(-20, 50)
    ax.set_ylim(0, 1200)
    ax.set_xlabel('Time', 'ms')
    ax.set_ylabel('Spike frequency', 'Hz')
    #plot_comparison(axc, s, '$\chi^2$', 0.1)

def check_baseeod(data_path, cell):
    """
    bad EODs (clipped EOD trace!)
    2012-06-27-ah-invivo-1

    bad EODs (big chirps!!!):
    2014-06-06-ac-invivo-1         CV=0.188
    2014-06-06-ag-invivo-1         CV=0.195
    2018-06-25-ad-invivo-1         many small chirps
    2018-06-26-ah-invivo-1         CV=0.203   many big chirps
    """
    data_eods = np.load(os.path.join(data_path, cell, 'baseline_eods_trial_1.npy'))
    fig, ax = plt.subplots()
    ax.set_title(cell)
    rate = 1/np.diff(data_eods)
    ax.plot(data_eods[:-1], rate)
    #plot_eod_interval_hist(ax, data_eods, max_iei=5)
    plt.show()

def main():
    s = plot_style()

    data_path = 'celldata'
    plot_path = 'plots'
    if not os.path.isdir(plot_path):
        os.mkdir(plot_path)

    baseline_tmax = 15 # seconds
    model_contrasts = np.arange(-0.3, 0.31, 0.01)
    rate_contrasts = [-0.2, +0.05, -0.1, +0.1, -0.05, +0.2]
    s.rate_colors = [s.lsNegContrast,
                     pt.lighter(s.lsPosContrast, 0.4),
                     pt.lighter(s.lsNegContrast, 0.7),
                     pt.lighter(s.lsPosContrast, 0.7),
                     pt.lighter(s.lsNegContrast, 0.4),
                     s.lsPosContrast]
    data_dicts = []
    model_dicts = []

    # load model parameter:
    parameters = load_models("models.csv")

    # loop over model cells:
    for cell_idx in range(len(parameters)):
    #for cell_idx in [58]:
        model_params = parameters[cell_idx]
        cell = model_params.pop('cell')
        EODf = model_params.pop('EODf')
        print(f'cell {cell_idx:3d}: {cell}')
        data = dict(cell=cell)
        model = dict(cell=cell)
        #check_baseeod(data_path, cell)
        #continue

        # setup figure:
        fig, axg = plt.subplots(1, 2, cmsize=(16, 11), width_ratios=[42, 2])
        fig.subplots_adjust(leftm=8, rightm=3, bottomm=3.5, topm=3, wspace=0.07)
        fig.text(0.03, 0.96, cell, ha='left')
        fig.text(0.97, 0.96, f'EOD$f$={EODf:.0f}Hz', ha='right')
        axs = axg[0].subplots(2, 3, wspace=0.8, hspace=0.4)
        axs[0, 2] = axs[0, 2].make_polar(-0.02, -0.05)
        axr = fig.merge(axs[1,1:3])
        axc = axg[1].subplots(4, 2, hspace=0.6, wspace=0.2)

        # baseline:
        data_spikes, data_eods = baseline_data(data_path, cell)
        model_spikes = baseline_model(EODf, model_params, baseline_tmax)
        data, model = analyse_baseline(EODf, data_spikes, data_eods, model_spikes,
                                       data=data, model=model,
                                       max_eods=15.5, max_lag=15)
        plot_baseline(axs[0, 0], axs[0, 1], axs[0, 2], axc[0:2,:].ravel(), s,
                      EODf, data, model)

        # fi curves:
        data_contrasts, data_fonset, data_fss = ficurve_data(data_path, cell)
        time, rates = firate_model(EODf, model_params, model_contrasts)
        model_fonset, model_fss, baseline = ficurves(time, rates)
        data = fit_ficurves(EODf, data_contrasts, data_fonset, data_fss, data)
        model = fit_ficurves(EODf, model_contrasts, model_fonset, model_fss, model)
        plot_ficurves(axs[1, 0], axc[2:4,:].ravel(), s, EODf,
                      data_contrasts, data_fonset, data_fss,
                      model_contrasts, model_fonset, model_fss, data, model)

        # fi rates:
        time, rates = firate_model(EODf, model_params, rate_contrasts)
        plot_firates(axr, None, s, rate_contrasts, time, rates)

        fig.common_yspines(axc)
        fig.savefig(os.path.join(plot_path, cell))
        plt.close(fig)
        #plt.show()

        data_dicts.append(data)
        model_dicts.append(model)

        #break

    data = pd.DataFrame(data_dicts)
    model = pd.DataFrame(model_dicts)
    data = data.drop(columns=['isis', 'hist', 'lags', 'cyclic_phases', 'cyclic_rates', 'fon_contrasts', 'fon_line', 'fss_contrasts', 'fss_line'])
    data.corrs = [c[1] for c in data.corrs]
    model = model.drop(columns=['isis', 'hist', 'lags', 'cyclic_phases', 'cyclic_rates', 'fon_contrasts', 'fon_line', 'fss_contrasts', 'fss_line'])
    model.corrs = [c[1] for c in model.corrs]
    data.to_csv('punitdata.csv')
    model.to_csv('modeldata.csv')

if __name__ == '__main__':
    main()


from selenium import webdriver
from selenium.webdriver.chrome.options import Options

import time

#url = 'https://www.youtube.com/watch?v=k2eEyOZmi2c&ab_channel=CanalemDia'
options = Options()
options.add_experimental_option=True

webBrowser = webdriver.Chrome(options=options)
url = 'https://www.youtube.com/watch?v=k2eEyOZmi2c&ab_channel=CanalemDia'

def open_new_tab(url, tab_number):
    webBrowser.execute_script("window.open('about:blank', "+ str(tab_number) +");")
    webBrowser.switch_to.window(str(tab_number) )
    webBrowser.get(url)

while True:
    for i in range(10):
        open_new_tab(url, i)

    time.sleep(90)


#!/usr/bin/env python3
"""move (rename) files

"""
from sys import exit
from pathlib import PurePosixPath
from argparse import ArgumentParser

from client_backend.fs_db_io import FSDatabase
from client_backend.fs_db_file import File, Directory
from client_backend.fs_db_file import IncorrectFileTypeError, MissingFileError

def parse_args():
    global ARGV, SHELL
    parser = ArgumentParser(description='move (rename) files')
    parser.add_argument('source',
                        help='file(s) that should be renamed/moved',
                        nargs='+')
    parser.add_argument('destination',
                        help='New filename or directory to move the file to')

    return parser.parse_args(ARGV)

# See FSDatabase._resolve_relative_path
def to_abs_path(path):
    global SHELL
    ctx_path = PurePosixPath("/")
    path = PurePosixPath(path)
    if path.parts and path.parts[0] == "~":
        ctx_path = PurePosixPath(SHELL.HOME)
    else:
        ctx_path = PurePosixPath(SHELL.PWD)

    assert ctx_path.anchor
    # if path starts with /, will ignore ctx_path automatically
    return ctx_path.joinpath(path)

def move_to(src_path, dst_path):
    global FS
    try:
        File.resolve_to(FS, dst_path, Directory)
    except (MissingFileError, IncorrectFileTypeError):
        print(f"mv: target '{str(dst_path)}' is not a directory")
        return 1

    return not rename_to(src_path, dst_path)

def rename_to(src_path, dst_path):
    global FS

    try:
        # Either exists or does not. If does not exist, generic error is fine
        # If wrong type then should've been deleted
        src_file = File(FS, src_path)
        src_path = PurePosixPath(src_file.full_name)
        dst_path = to_abs_path(dst_path)
        try:
            resolved_dir = File.resolve_to(FS, dst_path, Directory)
            dst_path = PurePosixPath(resolved_dir.full_name).joinpath(src_path.name)
        except IncorrectFileTypeError:
            File(FS, dst_path).remove()
        except MissingFileError:
            pass
        dst_dir = Directory(FS, dst_path.parent)
        if src_path.parent != dst_path.parent:
            src_file.move(dst_dir)
        src_file.name = dst_path.name

    except (MissingFileError, IncorrectFileTypeError):
        print(f"cannot move '{str(src_path)}' to '{str(dst_path)}': No such file or directory")
        return 1

def main(args):
    global FS
    if len(args.source) > 1:
        for source in args.source:
            if not move_to(source, args.destination):
                return 1
    else:
        return rename_to(args.source[0], args.destination)

if __name__ == "__main__":
    import sys
    from client_backend import shell_context
    FS = FSDatabase('.fs_db_rdbsh')
    ARGV = sys.argv[1:]
    SHELL = shell_context
    exit(main(parse_args()))

if __name__ == "__rdbsh__":
    exit(main(parse_args()))


#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Purpose.

This program analyses the news database for most popular
articles, most popular authors, and the days in which
the percentage of requests that return 404 error is more than one.

"""

import psycopg2

DBNAME = "news"

title_one = "\nThe three most popular articles of all time"
title_two = "\nThe three most popular authors of all time"
title_three = "\nThe days with more than one percent of" \
              " requests that leads to an error"

query_one = "SELECT title, COUNT(*) as views FROM articles a," \
            "log l WHERE a.slug=substring(l.path, 10) GROUP BY " \
            "title ORDER BY views desc limit 3"
query_two = "SELECT name, SUM(views) FROM title_views_author" \
            " GROUP BY name ORDER BY sum desc limit 3"
query_three = "SELECT * FROM error_view WHERE percentage_error > 1"

def get_query_result(query):
    """Get query results from database."""
    db = psycopg2.connect(database=DBNAME)
    c = db.cursor()
    c.execute(query)
    results = c.fetchall()
    db.close()
    return results

def print_query_result(query_result):
    """Print query result from first and second queries."""
    print(query_result[1])
    for results in (query_result[0]):
        print(str(results[0]) + ' - ' + str(results[1]) + ' views')

def print_error_result(error_result):
    """Print query result for third query."""
    print(error_result[1])
    for results in error_result[0]:
        print(str(results[0]) + ' - ' + str(results[1]) + '%')

if __name__ == '__main__':
    most_popular_articles = get_query_result(query_one), title_one
    most_popular_authors = get_query_result(query_two), title_two
    highest_error_days = get_query_result(query_three), title_three

    print_query_result(most_popular_articles)
    print_query_result(most_popular_authors)
    print_error_result(highest_error_days)


class Node:
    def __init__(self,dataval=None):
        self.dataval=dataval
        self.nextval=None

class SlinkedList:
    def __init__(self):
        self.headval=None

    def printLinkedList(self):
        printlist=self.headval
        while printlist is not None:
            print(printlist.dataval)
            printlist=printlist.nextval

    def Atbeginning(self,newdata):
        newNode=Node(newdata)
        newNode.nextval=self.headval
        self.headval=newNode

Head=SlinkedList()
Head.headval=Node("Mon")
Node1=Node("Tue")
Head.headval.nextval=Node1
Node2=Node("Wed")
Node1.nextval=Node2
Node3=Node("Thurs")
Node2.nextval=Node3
Head.Atbeginning("Sun")
print(Head.headval.dataval)


import numpy as np
import pylab as pyl
import matplotlib.pyplot as plt
import bcolz
from random import sample
from sklearn.cluster import MiniBatchKMeans
from sklearn.metrics.pairwise import pairwise_distances_argmin
from scipy.spatial.distance import cdist,pdist

def save_array(fname, arr):
    carr=bcolz.carray(arr, rootdir=fname, mode='w'); carr.flush()

def load_array(fname):
    return bcolz.open(fname)[:]

def plot_image(imname):
    pyl.imshow(imname)
    pyl.show()

def plot_cluster(image_list, labels, c_id, n_images=20, cols=4):
    """
    helper to plot shoes/images within a cluster

    Params:
    --------
    image_list: list with all the images
    labels    : cluster labels
    c_id      : id of the cluster to plot
    n_images  : number of images in the plot
    cols      : columns of the plot
    """

    idx = np.where(labels == c_id)[0]
    idx = sample(idx, n_images)
    imgs = [image_list[i] for i in idx]

    nrow = len(idx) / cols
    ncol = cols

    if ((ncol * nrow) != len(idx)): nrow = nrow + 1

    plt.figure()
    for i,img in enumerate(imgs):
        plt.subplot(nrow,ncol,i+1)
        plt.imshow(img)
        plt.axis('off')
    plt.show()

def avg_within_ss(X, k):
    """
    Compute the average within-cluster sum of squares. The code here can be
    found "almost" anywhere online

    Params:
    --------
    X: numpy array with observations and features to be clustered
    k: number of clusters

    Returns:
    --------
    avgwithinss: average within-cluster sum of squares
    """

    model = MiniBatchKMeans(init='k-means++', n_clusters=k, batch_size=50,
                          n_init=3, max_no_improvement=10, verbose=0)
    model.fit(X)

    centroids = model.cluster_centers_
    dist_c = cdist(X, centroids, 'euclidean')
    dist   = np.min(dist_c, axis=1)
    avgwithinss = sum(dist**2)/X.shape[0]

    return avgwithinss

def perc_var_explained(X,k):
    """
    Compute the percentage of variance explained defined as between sum of squares
    divided but the total sum of squares.
    WARNING: It will take a while.
    The code here can be found "almost" anywhere online.

    Params:
    --------
    X: numpy array with observations and features to be clustered
    k: number of clusters

    Returns:
    --------
    pve: percentage of variance explained
    """

    model = MiniBatchKMeans(init='k-means++', n_clusters=k, batch_size=50,
                          n_init=3, max_no_improvement=10, verbose=0)
    model.fit(X)

    centroids = model.cluster_centers_
    dist_c = cdist(X, centroids, 'euclidean')
    dist   = np.min(dist_c, axis=1)
    tot_withinss = sum(dist**2)
    totss = sum(pdist(X)**2)/X.shape[0]
    betweenss = totss - tot_withinss
    pve = (betweenss/totss  *100)

    return pve

def bic(X, k):
    """
    Compute the BIC score.
    Implementarion from here:
    http://www.aladdin.cs.cmu.edu/papers/pdfs/y2000/xmeans.pdf
    with corrections from here:
    https://stats.stackexchange.com/questions/90769/using-bic-to-estimate-the-number-of-k-in-kmeans

    Params:
    --------
    X: numpy array with observations and features to be clustered
    k: number of clusters

    Returns:
    --------
    BIC: bic score
    """

    model = MiniBatchKMeans(init='k-means++', n_clusters=k, batch_size=50,
                          n_init=3, max_no_improvement=10, verbose=0)
    model.fit(X)

    centers = model.cluster_centers_
    centers = np.expand_dims(centers, axis=1)
    labels  = model.labels_
    N_C = np.bincount(labels)
    R, M = X.shape

    wcss = sum([sum(cdist(X[np.where(labels == c)], centers[c], 'euclidean')**2) for c in range(k)])
    var = (1.0/(R-k)/M) * wcss
    const_term = 0.5 * k * np.log(R) * (M+1)

    BIC = np.sum([ ( Rn * np.log(Rn) ) -
                   ( Rn * np.log(R) ) -
                   ( ((Rn * M) / 2) * np.log(2*np.pi*var) )  -
                   ( (Rn - 1) * M/ 2 )
                   for Rn in N_C]) - const_term

    return BIC


import collections
import numpy as np
import tensorflow as tf
import tensorflow.contrib.seq2seq as seq2seq
from tensorflow.contrib.seq2seq.python.ops import helper as helper_py

from tensorflow.python.framework import dtypes
from tensorflow.python.framework import ops
from tensorflow.python.layers import core as layer_core
from tensorflow.python.layers import base as layers_base
from tensorflow.python.ops import array_ops
from tensorflow.python.ops import control_flow_ops
from tensorflow.python.ops import embedding_ops
from tensorflow.python.ops import math_ops
from tensorflow.python.ops import rnn_cell_impl
from tensorflow.python.ops.distributions import categorical
from tensorflow.python.util import nest
from tensorflow.python.framework import tensor_shape

class BasicVectorDecoderOutput(
    collections.namedtuple("BasicVectorDecoderOutput",
                           ("rnn_output", "stop_vector", "stop_id"))):
  pass

class BasicVectorDecoder(seq2seq.BasicDecoder):
    """Basic sampling decoder with vector input / output."""

    def __init__(self, cell, helper, initial_state, output_layer=None):
        """Initialize BasicVectorDecoder.

        Args:
            cell: An `RNNCell` instance.
            helper: A `Helper` instance.
            initial_state: A (possibly nested tuple of...) tensors and TensorArrays.
                The initial state of the RNNCell.
            output_layer:An instance of `tf.layers.Layer`, i.e., `tf.layers.Dense`.
                If not provided, use 1 fc layer.

        Raises:
            TypeError: if `cell`, `helper` or `output_layer` have an incorrect type.
        """
        if not rnn_cell_impl._like_rnncell(cell):  # pylint: disable=protected-access
            raise TypeError("cell must be an RNNCell, received: %s" % type(cell))
        if not isinstance(helper, helper_py.Helper):
            raise TypeError("helper must be a Helper, received: %s" % type(helper))
        if (output_layer is not None and not isinstance(output_layer, layers_base.Layer)):
            raise TypeError(
                "output_layer must be a Layer, received: %s" % type(output_layer))
        self._cell = cell
        self._helper = helper
        self._initial_state = initial_state
        if output_layer is None:
            self._output_layer = layer_core.Dense(2, use_bias=True,
                                                  name="stop_predictor")
        else:
            self._output_layer = output_layer

    def _rnn_output_size(self):
        return self._cell.output_size

    @property
    def output_size(self):
        # Return the cell output and the id
        return BasicVectorDecoderOutput(
            rnn_output=self._rnn_output_size(),
            # stop_vector=tensor_shape.TensorShape([self.batch_size, 2]),
            stop_vector=2,
            stop_id=tensor_shape.TensorShape([]))

    @property
    def output_dtype(self):
        # Assume the dtype of the cell is the output_size structure
        # containing the input_state's first component's dtype.
        # Return that structure and int32 (the id)
        dtype = nest.flatten(self._initial_state)[0].dtype
        return BasicVectorDecoderOutput(
            nest.map_structure(lambda _: dtype, self._rnn_output_size()),
            dtype, dtypes.int32)

    def step(self, time, inputs, state, name=None):
        """Perform a decoding step.

        Args:
            time: scalar `int32` tensor.
            inputs: A (structure of) input tensors.
            state: A (structure of) state tensors and TensorArrays.
            name: Name scope for any created operations.

        Returns:
            `(outputs, next_state, next_inputs, finished)`.
        """
        with ops.name_scope(name, "BasicVectorDecoderStep", (time, inputs, state)):
            cell_outputs, cell_state = self._cell(inputs, state)
            stop_vector = self._output_layer(cell_outputs)
            stop_id = self._helper.sample(
                time=time, stop_vector=stop_vector, state=cell_state)
            (finished, next_inputs, next_state) = self._helper.next_inputs(
                time=time,
                outputs=cell_outputs,
                state=cell_state,
                stop_id=stop_id)
        outputs = BasicVectorDecoderOutput(cell_outputs,
                                           stop_vector,
                                           stop_id)
        return (outputs, next_state, next_inputs, finished)

class VectorTrainingHelper(seq2seq.TrainingHelper):
    """A helper for use during training. Only reads inputs.

    Contrary to TrainingHelper, this reads vector inputs.
    stop_id is sampled in a greedy fashion.
    """
    def sample(self, time, stop_vector, state, name=None):
        """sample stop signal."""
        del time, state  # unused by sample_fn
        stop_id = math_ops.cast(
            math_ops.argmax(stop_vector, axis=-1), dtypes.int32)
        return stop_id

class VectorGreedyEmbeddingHelper(seq2seq.GreedyEmbeddingHelper):
    """A helper for use during inference.

    Pass output vectors as inputs to following sequences.
    Stop signal is predicted by additional layer.
    """

    def __init__(self, start_inputs):
        """Initializer.

        Args:
            start_inputs: inputs for the initial state.
        """
        self._batch_size = start_inputs.get_shape().as_list()[0]
        self._start_inputs = start_inputs

    @property
    def batch_size(self):
        return self._batch_size

    def initialize(self, name=None):
        finished = array_ops.tile([False], [self._batch_size])
        return (finished, self._start_inputs)

    def sample(self, time, stop_vector, state, name=None):
        """sample stop signal."""
        del time, state  # unused by sample_fn
        stop_id = math_ops.cast(
            math_ops.argmax(stop_vector, axis=-1), dtypes.int32)
        return stop_id

    def next_inputs(self, time, outputs, state, stop_id, name=None):
        """next_inputs_fn for GreedyEmbeddingHelper."""
        del time  # unused by next_inputs_fn
        finished = math_ops.equal(stop_id, 1)  # 1 is stop signal
        all_finished = math_ops.reduce_all(finished)
        next_inputs = control_flow_ops.cond(
            all_finished,
            # If we're finished, the next_inputs value doesn't matter
            lambda: self._start_inputs,
            lambda: outputs)
        return (finished, next_inputs, state)

class SyntacticGreedyEmbeddingHelper(seq2seq.Helper):
    """A helper for use during inference.

    Perform the argmax over the grammatically correct output candidates.
    Outputs are passes through an embedding layer to get the next input.
    """

    def __init__(self, dsl_syntax, max_program_len, embedding, start_tokens, end_token):
        """Initializer.

        Args:
            dsl_syntax: Syntax checker for generating next possible tokens.
            max_program_len: maximum program length
            embedding: A callable that takes a vector tensor of `ids` (argmax ids),
                or the `params` argument for `embedding_lookup`. The returned tensor
                will be passed to the decoder input.
            start_tokens: `int32` vector shaped `[batch_size]`, the start tokens
            end_token: `int32` scalar, the token that marks end of decoding.

        Raises:
            ValueError: if `start_tokens` is not a 1D tensor or `end_token` is not a
                scalar.
        """
        self.dsl_syntax = dsl_syntax
        self.max_program_len = max_program_len
        self.previous_tokens = []
        self.previous_probs = []
        self.previous_masks = []

        if callable(embedding):
            self._embedding_fn = embedding
        else:
            self._embedding_fn = (
                lambda ids: embedding_ops.embedding_lookup(embedding, ids))

        self._start_tokens = ops.convert_to_tensor(
            start_tokens, dtype=dtypes.int32, name="start_tokens")
        self._end_token = ops.convert_to_tensor(
            end_token, dtype=dtypes.int32, name="end_token")
        if self._start_tokens.get_shape().ndims != 1:
            raise ValueError("start_tokens must be a vector")
        self._batch_size = array_ops.size(start_tokens)
        if self._end_token.get_shape().ndims != 0:
            raise ValueError("end_token must be a scalar")
        self._start_inputs = self._embedding_fn(self._start_tokens)

    @property
    def batch_size(self):
        return self._batch_size

    def initialize(self, name=None):
        finished = array_ops.tile([False], [self._batch_size])

        def init_prev_tokens(finished):
            self.previous_tokens = []
            self.previous_probs = []
            self.previous_masks = []
            return finished
        new_finished = tf.py_func(init_prev_tokens, [finished], tf.bool)
        new_finished.set_shape(finished.get_shape())
        return (new_finished, self._start_inputs)

    def sample(self, time, outputs, state, name=None):
        """sample for SyntacticGreedyEmbeddingHelper."""
        del time, state  # unused by sample_fn
        # Outputs are logits, use argmax to get the most probable id
        if not isinstance(outputs, ops.Tensor):
            raise TypeError("Expected outputs to be a single Tensor, got: %s" %
                            type(outputs))

        # Mask outputs to reduce candidates to syntatically correct ones.
        def mask_output(outputs, end_token):
            if len(self.previous_tokens) == 0:  # when there is no previous token, skip masking.
                mask = np.zeros(outputs.shape, dtype=outputs.dtype)
                mask[:, self.dsl_syntax.token2int['DEF']] = 1
                return mask
            tokens = np.stack(self.previous_tokens, axis=1)
            masks = []
            for i in range(outputs.shape[0]):
                if tokens[i][-1] == end_token:
                    next_tokens = [end_token]
                else:
                    try:
                        p_str = self.dsl_syntax.intseq2str(tokens[i])
                        next_tokens_with_counts = self.dsl_syntax.get_next_candidates(p_str)
                        next_tokens = [t[0] for t in next_tokens_with_counts
                                       if t[1] <= self.max_program_len - len(tokens[i])]
                    except:
                        # TODO: this code rarely cause syntax error, which
                        # should not happen. We should fix this in the future.
                        next_tokens = [t for t in range(len(self.dsl_syntax.int2token))]
                    else:
                        next_tokens = [self.dsl_syntax.token2int[t] for t in next_tokens]
                mask = np.zeros([outputs.shape[1]], dtype=outputs.dtype)
                for t in next_tokens:
                    mask[t] = 1
                masks.append(mask)
            return np.stack(masks, axis=0)
        masks = tf.py_func(mask_output, [outputs, self._end_token], tf.float32)
        masks.set_shape(outputs.get_shape())
        masked_outputs = tf.exp(outputs) * masks
        sample_ids = math_ops.cast(
            math_ops.argmax(masked_outputs, axis=-1), dtypes.int32)

        def add_sample_ids(sample_ids):
            self.previous_tokens.append(sample_ids)
            return sample_ids
        new_sample_ids = tf.py_func(add_sample_ids, [sample_ids], tf.int32)
        new_sample_ids.set_shape(sample_ids.get_shape())
        return new_sample_ids

    def next_inputs(self, time, outputs, state, sample_ids, name=None):
        """next_inputs_fn for GreedyEmbeddingHelper."""
        del time, outputs  # unused by next_inputs_fn
        finished = math_ops.equal(sample_ids, self._end_token)
        all_finished = math_ops.reduce_all(finished)
        next_inputs = control_flow_ops.cond(
            all_finished,
            # If we're finished, the next_inputs value doesn't matter
            lambda: self._start_inputs,
            lambda: self._embedding_fn(sample_ids))
        return (finished, next_inputs, state)

class SyntacticSampleEmbeddingHelper(SyntacticGreedyEmbeddingHelper):
    """A helper for use during inference.

    Uses sampling (from a distribution) instead of argmax and passes the
    result through an embedding layer to get the next input.
    """

    def __init__(self, dsl_syntax, max_program_len, embedding, start_tokens, end_token, seed=None):
        """Initializer.

        Args:
            dsl_syntax: Syntax checker for generating next possible tokens.
            max_program_len: maximum program length
            embedding: A callable that takes a vector tensor of `ids` (argmax ids),
                or the `params` argument for `embedding_lookup`. The returned tensor
                will be passed to the decoder input.
            start_tokens: `int32` vector shaped `[batch_size]`, the start tokens.
            end_token: `int32` scalar, the token that marks end of decoding.
            seed: The sampling seed.

        Raises:
            ValueError: if `start_tokens` is not a 1D tensor or `end_token` is not a
                scalar.
        """
        super(SyntacticSampleEmbeddingHelper, self).__init__(
            dsl_syntax, max_program_len, embedding, start_tokens, end_token)
        self._seed = seed

    def sample(self, time, outputs, state, name=None):
        """sample for SyntacticGreedyEmbeddingHelper."""
        del time, state  # unused by sample_fn
        # Outputs are logits, use argmax to get the most probable id
        if not isinstance(outputs, ops.Tensor):
            raise TypeError("Expected outputs to be a single Tensor, got: %s" %
                            type(outputs))

        # Mask outputs to reduce candidates to syntatically correct ones.
        def mask_output(outputs, end_token):
            if len(self.previous_tokens) == 0:  # when there is no previous token, skip masking.
                mask = np.zeros(outputs.shape, dtype=outputs.dtype)
                mask[:, self.dsl_syntax.token2int['DEF']] = 1
                return mask
            tokens = np.stack(self.previous_tokens, axis=1)
            masks = []
            for i in range(outputs.shape[0]):
                if tokens[i][-1] == end_token:
                    next_tokens = [end_token]
                else:
                    try:
                        p_str = self.dsl_syntax.intseq2str(tokens[i])
                        next_tokens_with_counts = self.dsl_syntax.get_next_candidates(
                            '{}'.format(p_str))
                        next_tokens = [t[0] for t in next_tokens_with_counts
                                       if t[1] <= self.max_program_len - len(tokens[i])]
                    except:
                        # TODO: this code rarely cause syntax error, which
                        # should not happen. We should fix this in the future.
                        next_tokens = [t for t in range(len(self.dsl_syntax.int2token))]
                    else:
                        next_tokens = [self.dsl_syntax.token2int[t] for t in next_tokens]
                mask = np.zeros([outputs.shape[1]], dtype=outputs.dtype)
                for t in next_tokens:
                    mask[t] = 1
                masks.append(mask)
            return np.stack(masks, axis=0)
        masks = tf.py_func(mask_output, [outputs, self._end_token], tf.float32)
        masks.set_shape(outputs.get_shape())
        masked_outputs = tf.exp(outputs) * masks
        masked_probs = masked_outputs / \
            tf.reduce_sum(masked_outputs, axis=1, keep_dims=True)
        sample_id_sampler = categorical.Categorical(probs=masked_probs)
        sample_ids = sample_id_sampler.sample(seed=self._seed)

        def add_sample_ids(sample_ids, masked_probs, masks):
            self.previous_tokens.append(sample_ids)
            self.previous_probs.append(masked_probs)
            self.previous_masks.append(masks)

            return sample_ids
        new_sample_ids = tf.py_func(add_sample_ids, [sample_ids, masked_probs, masks], tf.int32)
        new_sample_ids.set_shape(sample_ids.get_shape())
        return new_sample_ids


import logging, os, io, base64, requests, sys
import praw
import pyimgur
import numpy as np
import urllib.request
from PIL import Image
import atexit
from dotenv import load_dotenv, find_dotenv

load_dotenv(dotenv_path=find_dotenv())

segment_url = os.getenv("SEGMENT_URL")
censor_url = os.getenv("CENSOR_URL")
web_app_url = os.getenv("WEB_APP_URL")

# Create the reddit instance
class reddit_bot:
    def __init__(self):
        self.reddit = praw.Reddit("reddit-bot")
        self.comments = self.reddit.inbox.unread(limit=None)
        self.info = "\n\n\nPhotoSense is a set of online tools that give people the ability to protect their privacy. " \
                    "The Reddit social media bot can be utilized by anyone who wants to spread this movement " \
                    "by using the appropriate hashtags (u/PhotoSenseBot) and flag commands. Enter 'u/PhotoSenseBot cmds' " \
                    "to retrieve a list of flag commands."

    #As of right now this only serves to return the image_urls and flags for the webapp to process
    def send_to_webapp(self, image_urls, flags):
        return image_urls, flags

    #As of right now, this only serves to return an app_url from the webapp for a session with the image
    def send_from_webapp(self, app_url):
        return app_url

    #Parses the body of the comment for any flags
    def parse_flags(self, text):
        flags_found = []
        flag_messages = ""

        flags = {
            'cmds': 'view bot commands',
            'rmv': 'remove parent comment with censored image',
            'px': 'apply the pixel sorting algorithm',
            'sb': 'apply the simple blurring algorithm (gaussian blur)',
            'pz': 'apply the pixelization algorithm',
            'bb': 'apply the black bar censoring algorithm',
            'fi': 'apply the fill in censoring algorithm',
        }

        if "cmds" in text:
            flag_descriptions = flags.values()
            flags_found.append('cmds')

            # instantiate a message response for displaying all commands
            flag_messages += "\n\nAll Image Censoring Commands\n\n"
            for flag in flags.keys():
                description = flags.get(flag)
                flag_messages += "\n(" + flag +")" + " " + description + "\n"

            flag_messages += "\nThe following example invokes the bot to return a censored image using " \
                "the pixel sorting algorithm: u/PhotoSenseBot px \n"
            flag_messages += "\nMultiple censoring algorithms can be used as well. " \
                "The following example invokes the bot to return a censored image using multiple commands: u/PhotoSenseBot px sb pz"
        else:
            arr = text.split()
            if('u/PhotoSenseBot' in arr):
                arr.remove('u/PhotoSenseBot')

            for i in range(len(arr)):
                arr[i] = arr[i].lower()

            if 'px' in arr:
                flags_found.append("pixel_sort")
            if 'pz' in arr:
                flags_found.append("pixelization")
            if 'sb' in arr:
                flags_found.append("gaussian_blur")
            if 'bb' in arr:
                flags_found.append("black_bar")
            if 'fi' in arr:
                flags_found.append("fill_in")
            if 'rmv' in arr:
                flags_found.append("remove")

            if(len(flags_found) == 0):
                flag_messages += "\n" + self.info

        return flag_messages, flags_found

    '''
    Checks the mention and parses through to find the image in the parent post. All image url's are extracted, and
    the body is parsed for flags. Also does the main assessment for what the reply text will be.
    '''
    def checkout_mention(self, mention):
        parent_id = mention.parent()
        parent = self.reddit.submission(id=parent_id)
        message = ""
        images = []

        try:
            keys = ['.jpg', '.jpeg', '.png', '.jfif', 'gallery']
            text_only_post = parent.is_self
            # determine the reddit post type: text, image/video, url
            if text_only_post:
                selftext = parent.selftext
                # check if an image was posted in the text
                if any (key in selftext for key in keys):
                    num_images = parent.selftext.count("https://") # check how many links we have total in the text
                    for i in range(num_images):
                        unstripped_URL = selftext.split("https://")[i+1]  # for each link, take the split section with the actual part of the link (caption removed)
                        image_URL = unstripped_URL.split(')')[0]  # strip the closing' ) ' and the rest of remaining selftext
                        if '.jpg' or '.jpeg' or '.png' or ".jfif" in image_URL:  # use this to confirm it's a link to an image, and not to another site
                            images.append("https://"+image_URL)  # add it to our list of links to print
            else:
                # check if an image was posted in the url
                if any (key in parent.url for key in keys):
                    # if user enters multiple images aka 'gallery' in reddit
                    if('gallery' in parent.url):
                        gallery_data = parent.media_metadata
                        images = self.get_images_from_gallery(gallery_data)
                    # if user enters a single image
                    else:
                        images.append(parent.url)

        except Exception as e:
            # print('throwing exception')

            # print(e.__traceback__)
            self.delete_post(mention)
            return "", mention.id, [], []
            # return "This bot does not reply links in comments! Only to initial image posts! :)"+ "\n\n\n"+self.info, parent_id,

        if(len(images) == 0):
            print("no image was found")
            message += "\n\nNo image was found\n\n"
            mention.reply(message)
            return "", mention.id, [], []

        else:
            comment_body = str(mention.body)
            flag_msg, flags = self.parse_flags(comment_body)

            if "remove" in flags:
                print("Deleting post: ", mention.id)
                # self.delete_post(mention)
                return "", mention.id, [], flags
            else:
                message += flag_msg
                return message, parent_id, images, flags

    def get_images_from_gallery(self, data):
        images = []
        if(len(data) > 0):
            for media_id in data:
                image_data = data[media_id]
                if image_data['e'] == 'Image':
                    image_url = image_data['p'][-1]['u'] # Get most high quality image url (last one that appears in the link list)
                    images.append(image_url)

        return images

    # Sends a reply through reddit
    def reply(self, mention, message, images, flags):
        # respond with all commands
        if('cmds' in flags or len(flags) == 0):
            print(message)
            mention.reply(message)
        else:
            imgur_links = []
            temp_censored_images = []
            temp_images = []
            temp_segmented_images = []

            temp_censor_url = censor_url
            total_flags = len(flags)
            # instantiate temp censor url according to flags set by user
            for i in range(total_flags):
                if(i == total_flags - 1):
                    temp_censor_url += flags[i] + "]"
                else:
                    temp_censor_url += flags[i] + ", "

            for i in range(len(images)):
                temp_image = 'temp' + str(i) + '.jpg'
                temp_mask_image = 'mask' + str(i) + '.jpg'
                temp_censored_image = 'censored' + str(i) + '.jpg'

                # Call Segmentation API for each image
                with urllib.request.urlopen(images[i]) as url:
                    with open(temp_image, 'wb') as f:
                        f.write(url.read())
                files = {'image': open(temp_image, 'rb')}
                res = requests.post(segment_url, files=files).json()
                print('completed segmentation request')
                # add a temp image to be used later in case user wants to edit segmentations via web app
                temp_images.append(temp_image)

                # Convert each segmentation to an image file
                mask_to_image(res["predictions"]).save(temp_mask_image)

                with open(temp_image, 'rb') as image, open(temp_mask_image, 'rb') as masked_image:
                    files = {'image': image, 'mask': masked_image}
                    # add a temp masked image so it can be removed locally later on
                    temp_segmented_images.append(temp_mask_image)

                    # Call the censorship api
                    res = requests.post(temp_censor_url, files=files)
                    print('completed censoring request')

                    # Convert base64 response file
                    if res.status_code == 200:
                        fn = temp_censored_image
                        img_bytes = res.json()['ImageBytes'].encode()
                        with open(fn, 'wb') as f:
                            f.write(base64.decodebytes(img_bytes))
                        i += 1
                        temp_censored_images.append(fn)
                    else:
                        print('response status was not equal to 200')

            if(len(temp_censored_images) > 0):
                # Upload image to imgur
                imgur_links = upload_to_imgur(temp_censored_images)
                original_image_links = upload_to_imgur(temp_images)

                re_edit_images_links = []
                for original_image in original_image_links:
                    re_edit_images_links.append(web_app_url + original_image)

                message += '\n\nHere are your censored images\n\n'
                message += str(imgur_links) + '\n'
                message += '\nIf you are unsatisfied with an image segmentation(s), copy and paste one of the links'
                message += '\nbelow in your browser to edit an image segmentation using the PhotoSense web app\n\n'
                message += str(re_edit_images_links) + '\n'
                print(message)
                mention.reply(message)
            else:
                print('\n\nError in processing requests')
                message += '\n\nError in processing requests'
                mention.reply(message)

            # delete all locally saved images
            self.remove_local_image(temp_segmented_images)
            self.remove_local_image(temp_censored_images)
            self.remove_local_image(temp_images)

    def remove_local_image(self, local_images):
        for local_image in local_images:
            os.remove(local_image)

            if os.path.exists(local_image) is False:
                print('image removed locally')
            else:
                print('file still exists')

    #deletes a post if
    def delete_post(self,mention):
        print("===Deleting response===")
        sub = mention.submission #returns the submission object
        sub_auth = sub.author #submission author
        comm_to_del = mention.parent() #delete the parent of the mentioner
        init_mentioner = comm_to_del.parent() #will be used to check if the mentioner wants to delete their own bot response

        if((mention.author == sub_auth) or (mention.author == init_mentioner)) and (comm_to_del.author == "PhotoSenseBot"):
            comm_to_del.delete() # will be comm_to_del.delete()
            print("Successfully removed!")
        else:
            print("Unsuccessful removal!")

    #deletes all unread comments waiting in the unread stream
    def mark_r(self):
        #create new stream object so it doesn't interfere with the class one
        comms = self.reddit.inbox.unread(limit=None)
        read_comments = []
        for comment in comms:
            if comment and isinstance(comment, praw.models.reddit.comment.Comment):
                read_comments.append(comment)
        if(len(read_comments)>0):
            self.reddit.inbox.mark_read(read_comments)
            print("Marked comments read: ", read_comments)

    def run(self):
        print("Bot running...")
        found_images = []
        flags = []

        self.mark_r() #prevents responding to comments that were made while bot was asleep

        while(True):
            self.comments = self.reddit.inbox.unread(limit=None)
            #must reinstantiate the unread stream or else it won't enter loop below
            for comment in self.comments:
                if comment and isinstance(comment,praw.models.reddit.comment.Comment) and ("u/PhotoSenseBot" in comment.body):
                    msg,_,found_images,flags = self.checkout_mention(comment)
                    if(len(found_images) > 0):
                        self.reply(comment, msg, found_images, flags)
                    self.reddit.inbox.mark_read([comment])
                break

def upload_to_imgur(images):
    print('uploading images to imgur: \n')
    print(images)

    imgur_links = []
    client_id = os.getenv('IMGUR_CLIENT_ID')
    i = 0

    for image in images:
        path = images[i]
        im = pyimgur.Imgur(client_id)
        uploaded_image = im.upload_image(path, title="Uploaded with PyImgur")
        imgur_links.append(uploaded_image.link)
        i += 1

    return imgur_links

def mask_to_image(pixels):
    arr = np.zeros([len(pixels), len(pixels[0]), 3], dtype=np.uint8)
    for i in range(len(pixels)):
        for j in range(len(pixels[0])):
            if pixels[i][j] == 0:
                arr[i, j] = [0, 0, 0]
            else:
                arr[i, j] = [255, 255, 255]
    return Image.fromarray(arr)

def restartProcess():
    os.system('nohup python reddit_bot.py')

def main():
    bot = reddit_bot()
    bot.run()
    atexit.register(restartProcess)

if __name__ == "__main__":
    main()


import json
import shutil
from pathlib import Path
from dataclasses import dataclass
import configparser
from enum import StrEnum

import openpyxl
from openpyxl.drawing.image import Image

from qrcode_base64 import generate_qrcode

HERE = Path(__file__).resolve().parent

config = configparser.ConfigParser()
config.read(HERE / 'congfig_printed_file.ini')

class PrintedExcelType(StrEnum):
    certificate = 'certificate'
    inspection = 'inspection'
    congifuration = 'congifuration'

@dataclass
class FileTypeError(Exception):
    pass

@dataclass
class JsonFileTypeError(Exception):
    pass

def get_qrcode_img()->Image:
    qrcode_img_stream = generate_qrcode('http://tsgz.zjamr.zj.gov.cn/ecode/300200033110103932023Z1803')
    return Image(qrcode_img_stream)

# 读入json格式的文件
def read_json(path:Path)->dict:
    """读入一个Json格式文件"""
    with open(path, 'r') as f:
        data = json.load(f)
    return data

def generate_new_name(file_path:Path, prefix:str)->str:
    """给文件名添加前缀"""
    return f"{prefix}_{file_path.name}"

def copy_template_files(prefix:str = "")->list[Path]:
    """将template中的文件依次拷贝到输出的文件夹，返回新拷贝的文件路径列表"""
    source_dir = HERE / config.get('paths', 'source_directory')
    target_dir = HERE / config.get('paths', 'target_directory')

    target_dir.mkdir(exist_ok=True)
    excel_files = [file for file in source_dir.glob('*')
                   if file.is_file()
                      and file.suffix.lower() in ['.xls', '.xlsx']
                      and not file.name.startswith('~')]
    target_files = []
    for excel_file in excel_files:
        new_file_name = generate_new_name(file_path=excel_file,
                                          prefix=prefix)
        target_file = target_dir/new_file_name
        shutil.copy(excel_file, target_file)

        target_files.append(target_file)
    return target_files

def write_data_into_excelfile(file:Path,
                              cert_data:dict = None,
                              config_data:dict = None)->Path:
    """将json_data数据写入到excel文件file中"""
    wb = openpyxl.load_workbook(file)
    ws = wb.active
    is_write = False
    if PrintedExcelType.certificate in file.name:
        section_name = PrintedExcelType.certificate.value
        json_data = cert_data
    elif PrintedExcelType.inspection in file.name:
        section_name = PrintedExcelType.inspection.value
        json_data = cert_data
    elif PrintedExcelType.congifuration in file.name:
        section_name = PrintedExcelType.congifuration.value
        json_data = config_data
    else:
        raise FileTypeError()

    if json_data is None:
        json_data = {}

    for index, location in config.items(section_name):
        # 在excel中添加数据
        if index in json_data:
            data = json_data[index]
            if (section_name == PrintedExcelType.certificate.value
                or section_name == PrintedExcelType.inspection.value):# excel文件是合格证文件
                if isinstance(data, list):
                    data = "/".join(str(n) for n in data)
                ws[location] = data
            else: # excel文件是配置文件
                locs = location.split(',')
                for loc, d in zip(locs, data):
                    ws[loc] = d
            is_write = True
        # 在excel中添加二维码图
        if index == "qrcode_img":
            img = get_qrcode_img()
            ws.add_image(img, location)
    if is_write:
        wb.save(file)
        return file
    else:
        return None

def export_printed_files(cert_data:dict, config_data:dict = None)->list[Path]:
    """将json格式的数据写入到excel模版文件，返回成功写入数据的文件名"""
    newfiles = []
    if 'contact_num' in cert_data and 'product_num' in cert_data:
        files_prefix = cert_data['contact_num']+'_'+ cert_data['product_num']
    else:
        raise JsonFileTypeError("合格证Json文件格式不正确")

    files = copy_template_files(prefix=files_prefix)
    for file in files:
        newfile = write_data_into_excelfile(file=file,
                                            cert_data=cert_data,
                                            config_data=config_data)
        if newfile is None:
            # 数据写入不成功，就删除原文件
            file.unlink()
        else:
            newfiles.append(newfile)

    return newfiles


# -*- coding: utf-8 -*-
# All the Dictionaries

import numpy as np
import Functions as fn                # file with most of the functions

##########################################################################################
                                    # lDict

def make_lDict(data=None, **kw):
    ''' making a dictionary with all the angle l values as the x-axis
        Startpoint: either filename str or data list
        data list must be a list or tuple. will be taken as [int(x) for x in data]
        if no inputs other than startpoint is given, then comes w/ some prepopulated values
    '''

    # data List
    if isinstance(data, str):
        dataList = np.array([int(x) for x in fn.extractData(data, 0)])
    elif isinstance(data, (list, np.ndarray, tuple)):
        dataList = np.array([int(x) for x in data])
    else:  # if no dataList is given in any recognizable format
        print('Error: need a filename or dataList')
        return

    # ---- Base ----
    # base steps
    if 'baseStep' in kw:
        baseStep = kw.get('baseStep')
    else:
        baseStep = dataList[1]-dataList[0]  # fix this
    # data file's minimum l value
    if 'dataMin' in kw:
        dataMin = kw.get('dataMin')
    else:
        dataMin = dataList[0]
    # data file's maximum l value
    if 'dataMax' in kw:
        dataMax = kw.get('dataMax')
    else:
        dataMax = dataList[-1]

    # l-step for binning
    if 'lStep' in kw:
        lStep = kw.get('lStep')
    else:
        lStep = 20*baseStep
    # min l value used
    if 'lMin' in kw:
        lMin = kw.get('lMin')
    else:
        lMin = 50
    # floor of lMin, incase lMin is not an integer
    if 'refMin' in kw:
        refMin = kw.get('refMin')
    else:
        refMin = lMin-dataMin
    # max l value used (including)
    if 'lMax' in kw:
        lMax = kw.get('lMax')
    else:
        lMax = 500
    # floor of lMax, incase lMax is not an integer
    if 'refMax' in kw:
        refMax = kw.get('refMax')
    else:
        refMax = lMax-dataMin

    # x-axis for everything
    if 'lList' in kw:
        lList = np.array(kw.get('lList'))
    else:
        lList = np.array(dataList[refMin:refMax])

    # # reference list of bins
    # if 'refBins' in kw:
    #     refBins = np.array(kw.get('refBins'))
    # else:
    #     refBins = fn.makeList(refMin, refMax+lStep, lStep)
    # # list of bins
    # if 'lBins' in kw:
    #     lBins = np.array(kw.get('lBins'))
    # else:
    #     lBins = fn.makeList(lMin, lMax+lStep, lStep)

    # # reference bin centers
    # if 'refBinCent' in kw:
    #     refBinCent = np.array(kw.get('refBinCent'))
    # else:
    #     refBinCent = fn.binCenter(refBins)
    # # l bin centers
    # if 'lBinCent' in kw:
    #     lBinCent = np.array(kw.get('lBinCent'))
    # else:
    #     lBinCent = fn.binCenter(lBins)

    lDict = {
             # steps
             'baseStep': baseStep,
             'lStep': [lStep],  # *** NEED List for binning
             # minimums
             'dataMin': dataMin,
             'lMin': lMin,
             'refMin': refMin,
             # maximums
             'lMax': lMax,
             'dataMax': dataMax,
             'refMax': refMax,
             # list
             'dataList': dataList,
             'lList': lList,
             # binned list
             # 'refBins': refBins,
             # 'lBins': lBins,
             # # centers of binned list
             # 'refBinCent': refBinCent,
             # 'lBinCent': lBinCent
            }
    return lDict

##########################################################################################
                                    # Constants

def make_Const(**kw):
    ''' Reference dictionary of constants
        If no inputs given, comes prepopulated with standard values
    '''
    # if 'nu1' in kw:
    #     nu1 = np.float64(kw.get('nu1'))
    # else:
    #     nu1 = np.float64(90.0*(10**9))
    # if 'nu2' in kw:
    #     nu2 = np.float64(kw.get('nu2'))
    # else:
    #     nu2 = np.float64(150.0*(10**9))
    if 'nu0' in kw:
        nu0 = np.float64(kw.get('nu0'))
    else:
        nu0 = np.float64(220.)
    if 'h' in kw:
        h = np.float64(kw.get('h'))
    else:
        h = np.float64(6.62606957*(10**-34))
    if 'c' in kw:
        c = np.float64(kw.get('c'))
    else:
        c = np.float64(299792458.)
    if 'k' in kw:
        k = np.float64(kw.get('k'))
    else:
        k = np.float64(1.3806488*(10**-23))
    if 'Tcmb' in kw:
        Tcmb = np.float64(kw.get('Tcmb'))
    else:
        Tcmb = np.float64(2.7)
    if 'TDust' in kw:
        TDust = np.float64(kw.get('TDust'))
    else:
        TDust = np.float64(19.6)

    constants = {
             # 'nu1': nu1,      # frequency 1
             # 'nu2': nu2,      # frequency 2
             'nu0': nu0,      # reference frequency
             'h': h,          # Planck's constant
             'c': c,          # speed of light
             'k': k,          # Boltzmann constant
             'Tcmb': Tcmb,    # vacuum temp
             'TDust': TDust,  # dust temp
             'List': [h, c, k, Tcmb, TDust]
            }
    return constants

##########################################################################################
                                    # Frequencies
def make_frequencies(*args, **kw):
    ''' Reference dictionary of constants
        If no inputs given, comes prepopulated with standard values
    '''
    freqs_Dict = {}
    freqs = []
    for index, value in enumerate(args):
        freqs_Dict['nu{}'.format(index+1)] = value
        freqs.append(value)
    for value, key in enumerate(kw):
        freqs_Dict[key] = value
        freqs.append(value)
    return freqs_Dict, freqs


from __future__ import annotations

import math
import random
import re
from abc import ABC, abstractmethod
from dataclasses import dataclass
import cv2 as cv
import sys

import numpy as np
import pytesseract
import requests

@dataclass
class ChainParam:
    src: np
    copySrc: np = None
    pre: np = None
    dst: np = None
    vehicle_no: str = ''

class Handler(ABC):
    @abstractmethod
    def set_next(self, handler: Handler) -> Handler:
        pass

    @abstractmethod
    def handle(self, param: ChainParam):
        pass

class AbstractHandler(Handler):
    _next_handler: Handler = None

    def set_next(self, handler: Handler) -> Handler:
        self._next_handler = handler

        return handler

    def handle(self, param: ChainParam):
        if self._next_handler:
            return self._next_handler.handle(param)

        return None

class PreProcess(AbstractHandler):
    def handle(self, param: ChainParam):
        gray = cv.cvtColor(param.src, cv.COLOR_BGR2GRAY)
        src_bin = cv.GaussianBlur(gray, (0, 0), 2, sigmaY=0, borderType=cv.BORDER_DEFAULT)
        src_bin = cv.adaptiveThreshold(src_bin, 255, cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY_INV, 19, 4)
        param.pre = src_bin

        return super().handle(param)

class CutVehicleRegion(AbstractHandler):
    # src = None
    # pre = None

    def handle(self, param: ChainParam):
        min_pts = None
        min_area: int = sys.maxsize
        contours, _ = cv.findContours(param.pre, cv.RETR_LIST, cv.CHAIN_APPROX_NONE)
        for pts in contours:
            # 외곽선 근사화
            approx = cv.approxPolyDP(pts, cv.arcLength(pts, True) * 0.02, True)

            # 컨벡스가 아니고, 사각형이 아니면 무시
            # if not cv.isContourConvex(approx):
            #     continue
            # if len(approx) != 4:
            #     continue

            x, y, w, h = cv.boundingRect(pts)
            cv.rectangle(param.copySrc, (x, y), (x + w, y + h), (0, 0, 255), thickness=3)
            if h / w > 0.5:
                continue
            area = cv.contourArea(pts)
            if area < 80 * 80:
                continue
            # cv.drawContours(param.src, [approx], 0, (0, 0, 255), 3)
            # cv.rectangle(param.copySrc, (x, y), (x + w, y + h), (0, 0, 255), thickness=3)
            # cv.polylines(param.src, [approx], True, (0, 0, 255), 2, cv.LINE_AA)
            count = self.get_connected_components((x, y, w, h), param)
            if count < 4 or count > 20:
                continue

            if w * h < min_area:
                min_area = w * h
                min_pts = pts

        if min_pts is not None:
            x, y, w, h = cv.boundingRect(min_pts)
            param.dst = param.src[y:y + h, x + 20:x + w - 20]
            param.src = param.src[y:y + h, x + 20:x + w - 20]
            param.copySrc = param.src.copy()
            cv.rectangle(param.copySrc, (x, y), (x + w, y + h), (0, 0, 255), thickness=3)

        return super().handle(param)

    def get_connected_components(self, rect, param: ChainParam) -> int:
        component_count = 0
        x, y, w, h = rect
        mat = param.pre[y:y + h, x:x + w]
        contours, _ = cv.findContours(mat, cv.RETR_LIST, cv.CHAIN_APPROX_NONE)
        if len(contours) == 0:
            return 0
        for pts in contours:
            if cv.contourArea(pts) < 200:
                continue
            if not self.guess_vehicle_no(pts):
                continue

            similar_count = self.similar_contour(contours, pts)
            if similar_count < 3:
                continue

            component_count = component_count + 1

        return component_count

    @staticmethod
    def guess_vehicle_no(pts) -> bool:
        x, y, w, h = cv.boundingRect(pts)
        ratio = h / w
        if ratio < 1.0 or ratio > 4.0:
            return False
        return True

    @staticmethod
    def similar_contour(contours, pts) -> int:
        similar_count = 0
        x1, y1, w1, h1 = cv.boundingRect(pts)
        diagonal_length = math.sqrt(w1 * w1 + h1 * h1)
        for pts in contours:
            x2, y2, w2, h2 = cv.boundingRect(pts)
            area_diff: float = abs(w1 * h1 - w2 * h2) / (w1 * h1)
            width_diff: float = abs(w1 - w2) / w1
            height_diff: float = abs(h1 - h2) / h1

            if area_diff > 0.6 or width_diff > 0.8 or height_diff > 0.2:
                continue

            distance = math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2)
            if distance > diagonal_length * 5:
                continue

            angle_diff = 0
            dx = abs(x1 - x2)
            dy = abs(y1 - y2)
            if dx == 0:
                angle_diff = 90
            else:
                angle_diff = math.atan(dy / dx) * (180 / math.pi)
            if angle_diff > 20.0:
                continue

            similar_count = similar_count + 1
        return similar_count

class GetVehicleNo(AbstractHandler):
    def handle(self, param: ChainParam):
        if param.dst is None:
            return super().handle(param)

        p = re.compile('[0-9]{2,3}[가-힣]{1}[0-9]{4}|[가-힣]{2}[0-9]{2}[가-힣]{1}[0-9]{4}')
        gray = cv.cvtColor(param.dst, cv.COLOR_BGR2GRAY)
        src_bin = cv.GaussianBlur(gray, (0, 0), 1, sigmaY=4, borderType=cv.BORDER_DEFAULT)
        thres, _ = cv.threshold(src_bin, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU, dst=src_bin)

        src_bin = cv.erode(src_bin, None, iterations=2)

        src_bin = cv.copyMakeBorder(src_bin, 10, 10, 10, 10, cv.BORDER_CONSTANT, value=(0, 0, 0))
        vehicle_no = self.get_text_from_image(src_bin)
        if vehicle_no != '':
            m = p.match(vehicle_no)
            if m is not None:
                param.vehicle_no = m.group()
                return super().handle(param)

        cv.imshow('src_bin', src_bin)
        # cv.waitKey()
        vehicle_no = self.retry_vehicle_no(gray, thres, p)
        param.vehicle_no = vehicle_no
        print(vehicle_no)
        if vehicle_no == '' or len(vehicle_no) == 4:
            v = self.retry_vehicle_no(gray, thres, p, make_border=True)
            print(v)
            if vehicle_no == '' or len(v) >= 4:
                param.vehicle_no = v

        return super().handle(param)

    def retry_vehicle_no(self, gray, thres, p, iterations=10, make_border=False) -> str:
        for i in range(iterations):
            thres = thres + 10
            src_bin = cv.GaussianBlur(gray, (0, 0), 1, sigmaY=4, borderType=cv.BORDER_DEFAULT)
            thres, _ = cv.threshold(src_bin, thres, 255, cv.THRESH_BINARY, dst=src_bin)

            src_bin = cv.erode(src_bin, None, iterations=2)

            if make_border:
                src_bin = cv.copyMakeBorder(src_bin, 10, 10, 10, 10, cv.BORDER_CONSTANT, value=(0, 0, 0))
            vehicle_no = self.get_text_from_image(src_bin)
            if vehicle_no != '':
                m = p.match(vehicle_no)
                if m is not None:
                    return m.group()
                elif len(vehicle_no) > 4:
                    v = vehicle_no[-4:]
                    if v.isdigit():
                        return v

        return ''

    @staticmethod
    def get_text_from_image(src_bin) -> str:
        result: str = ''
        vehicle_no = pytesseract.image_to_string(src_bin, lang='kor', config='--oem 3 --psm 7')
        for i in range(len(vehicle_no)):
            v = vehicle_no[i]
            print(v)
            if ('가' <= v <= '힣') or v.isdigit():
                result = result + v

        return result

if __name__ == "__main__":
    # url = 'https://parkingcone.s3.ap-northeast-2.amazonaws.com/real/user_vehicle/2023/04/eaee1dfc75754d44046cfb9177c59c8b/1682679738_FVBUUC/f9c2755a3aa4cc06404b8e64f030c'
    # url = 'https://parkingcone.s3.ap-northeast-2.amazonaws.com/real/user_vehicle/2023/05/eaee1dfc75754d44046cfb9177c59c8b/1682679738_FVBUUC/7cccd183e821468e65b81b734'
    # url = 'https://parkingcone.s3.ap-northeast-2.amazonaws.com/real/user_vehicle/2023/04/eaee1dfc75754d44046cfb9177c59c8b/1682679738_FVBUUC/2cbdb867245618e515a61776b26dcd'
    url = 'https://parkingcone.s3.ap-northeast-2.amazonaws.com/real/user_vehicle/2023/05/bc8e73ed52dc49fe9bf95149b00a9f31/1683169300_DGSPYV/66d64a516a3950a1686ce524453b9d81'
    image_array = np.asarray(bytearray(requests.get(url).content), dtype=np.uint8)
    src = cv.imdecode(image_array, cv.IMREAD_COLOR)
    # src = cv.imread('../imgs/vehicle18.jpeg')
    if src is None:
        print('image read fail!!')
        sys.exit()

    chainParam = ChainParam(src)
    chainParam.copySrc = src.copy()

    pre = PreProcess()
    pre.set_next(CutVehicleRegion()).set_next(PreProcess()).set_next(CutVehicleRegion()).set_next(GetVehicleNo())
    pre.handle(chainParam)

    cv.imshow('pre', chainParam.pre)
    if chainParam.dst is not None:
        cv.imshow('dst', chainParam.dst)
    cv.imshow('src', chainParam.copySrc)
    print(chainParam.vehicle_no)

    cv.waitKey()
    cv.destroyAllWindows()


import sys
sys.stdin = open("test_input.txt")
input = sys.stdin.readline

T = int(input())
for tc in range(1,T+1):
    N, K = map(int,input().split())
    N_info = list(range(1,N+1))
    info = list(map(int, input().split()))

    print("#{}".format(tc),end=" ")
    for i in N_info:
        if i not in info:
            print(i,end=" ")
    print()
    # print("#{} {}".format(tc, rst))


import cycle
import rx

def log(msg):
  print(msg)

def main(responses):
  responses["dumbDriver"].subscribe(on_next=log)
  obs = rx.Observable.interval(1000)

  return {
    "dumbDriver": obs
  }

def dumbDriver():

  def driver(responses):
    responses.subscribe(on_next=log)
    obs = rx.Observable.interval(200).map(lambda x: x*x)
    return obs

  return driver

drivers = {
  "dumbDriver": dumbDriver()
}

cycle.run(main, drivers)


import os
from datetime import datetime

APP_NAME = "Kotar"
APP_DATA = 'APPDATA'
# TODO: set the telegram bot token and the chat id
# TELEGRAM Connection based on
# https://pythoncircle.com/post/265/how-to-create-completely-automated-telegram-channel-with-python/
TELEGRAM_TOKEN = None
TELEGRAM_CHAT_ID = None

NEW_DRIVER_DATE = datetime.strptime('2019-12-09', '%Y-%m-%d').date()

def create_temp_folder(notify: bool):
    app_data = os.getenv(APP_DATA)
    if app_data is not None:
        app_data = os.path.join(app_data, APP_NAME)
        os.makedirs(app_data, exist_ok=True)

    if notify:
        print("App temp directory: {}".format(app_data))
    return app_data

def rreplace(s: str, old: str, new: str, occurences):
    li = s.rsplit(old, occurences)
    return new.join(li)

def change_file_name(filepath, to):
    path, ext = os.path.splitext(filepath)
    filename = os.path.split(path)[-1]
    new_path = rreplace(filepath, filename, to, -1)
    return new_path

def str_to_bool(value: str) -> bool:
    return value.lower() in ["true", "t", "1", "yes""y"]

def try_parse_int(value):
    """
    Attempts to parse the given value to int and return its value, if fails returns original value
    :param value: the value to parse to int
    :return: int representation for value or value
    """
    try:
        return int(value)
    except ValueError:
        return value

class Config(object):
    """
    A class that should handle all app configurations
    """
    ENV = "environment"
    DB_URL = "DB_URL"

    def __init__(self, **kwargs):
        import configparser
        self.read_ok = False
        self.config = configparser.ConfigParser()
        config_path = kwargs.get("config_path", None)
        if config_path is not None:
            self.read(config_path)

    def get(self, section, option, default):
        if not self.read_ok:
            print("No config file found, working with defaults")
            self.read_ok = True
        return try_parse_int(self.config.get(section, option)) if self.config.has_option(section, option) else default

    def read(self, config_file):
        self.read_ok = len(self.config.read(config_file)) > 0
        print("Reading config file: '{}'".format(config_file))

    def expose_env(self):
        if self.config.has_section(Config.ENV):
            exposed_db_url = False
            for var_name in self.config.options(Config.ENV):
                var_name = var_name.upper()
                var_value = self.config.get(Config.ENV, var_name).replace('"', "").replace("'", '')

                if var_name == Config.DB_URL:
                    if not os.path.isabs(var_value):
                        var_value = os.path.abspath(var_value)
                    exposed_db_url = True

                print("Exposing {} - {}: {}".format(Config.ENV, var_name, var_value))

                os.environ[var_name] = var_value

            if not exposed_db_url:
                print("WARNING! DB_URL is not defined")
        else:
            os.environ["DB_URL"] = os.path.abspath("database.db")
            print("Exposing {} - {}: {}".format(Config.ENV, "DB_URL", os.path.abspath("database.db")))

class Singleton(type):
    _instances = {}

    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
        return cls._instances[cls]

class AppDir(object, metaclass=Singleton):
    def __init__(self):
        self.app_directory = self.create_app_dir(True)

    def create_app_dir(self, notify: bool):
        app_dir = os.getenv(APP_DATA)
        if app_dir is not None:
            app_dir = os.path.join(app_dir, APP_NAME)
            try:
                os.makedirs(app_dir)
            except:
                pass

        if notify:
            print("App temp directory: {}".format(app_dir))
        return app_dir


import imp
from fastapi import FastAPI,Header,Depends
from fastapi.security import oauth2
from fastapi.middleware.cors import CORSMiddleware
from fastapi_pagination import add_pagination
from sqladmin import Admin
from main.db import engine,asyncengine
from main.utils import OAuth2AppBearer
from user.approutes import auth
from store.approutes import store_app
from user.admin import UserAdmin,RoleAdmin,ContentTypesAdmin
from user.models import User
def create_dev_app():

    app=FastAPI(title="Development User Admin App",debug=False)
    origins = [ "*"]
    app.add_middleware(
            CORSMiddleware,
            allow_origins=origins,
            allow_credentials=True,
            allow_methods=["*"],
            allow_headers=["*"],
            )
    tok_bear=OAuth2AppBearer(tokenUrl="/auth/login")
    app.include_router(auth,prefix="/auth")
    app.include_router(store_app,prefix="/store")
    admin=Admin(app,asyncengine,title="Store Admin Dashboard")
    @app.get("/")
    def index(current_user : str=Depends(tok_bear)):
        return {"Message":current_user}
    add_pagination(app)
    admin.add_view(UserAdmin)
    admin.add_view(RoleAdmin)
    admin.add_view(ContentTypesAdmin)

    return app

def create_testing_app():
    app=FastAPI()
    origins = [ "*"]
    app.add_middleware(
            CORSMiddleware,
            allow_origins=origins,
            allow_credentials=True,
            allow_methods=["*"],
            allow_headers=["*"],
            )

    @app.get("/")
    def index():
        return {"Message":"You should make your own index page"}
    return app


import sys

a_list = list()
b_list = list()
for t in range(3):
    a, b = map(int, sys.stdin.readline().split())
    if a in a_list: a_list.remove(a)
    else: a_list.append(a)
    if b in b_list: b_list.remove(b)
    else: b_list.append(b)
print(a_list[0], b_list[0])


import customtkinter
import tkinter
import tksheet
import getperf
import SM3
from tkinter import filedialog

customtkinter.set_default_color_theme("dark-blue")
customtkinter.set_appearance_mode("light")

path = ""

def tk_center():
    screen_width = app.winfo_screenwidth()
    screen_height = app.winfo_screenheight()
    width = 400
    height = 300
    x = int(screen_width / 2 - width / 2)
    y = int(screen_height / 2 - height / 2)
    size = '{}x{}+{}+{}'.format(width, height, x, y)
    return size

class AboutWindow(customtkinter.CTkToplevel):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.geometry(tk_center())
        self.title("关于")
        self.label = customtkinter.CTkLabel(self, text="ToplevelWindow")
        self.label.pack(padx=20, pady=20)
        self.wm_attributes('-topmost',1)

class FileFrame(customtkinter.CTkFrame):
    def __init__(self, master, **kwargs):
        super().__init__(master, **kwargs)

        self.grid_columnconfigure(1, weight=1)
        self.grid_columnconfigure(0, weight=1)
        self.filepath = customtkinter.CTkTextbox(self, height=20)
        self.filepath.grid(row=0, column=0, padx=20, pady=10, sticky="ew")
        self.selectbutton = customtkinter.CTkButton(self, text="选择文件", command=self.FileSelect)
        self.selectbutton.grid(row=0, column=1, padx=20, pady=20, sticky="e")

    def FileSelect(self):
        global path
        path = filedialog.askopenfilename()
        self.filepath.delete(1.0, tkinter.END)
        self.filepath.insert(tkinter.END, path)

class inputFrame(customtkinter.CTkFrame):
    def __init__(self, input_name, master, **kwargs):
        super().__init__(master, **kwargs)

        self.grid_rowconfigure(0, weight=1)
        self.grid_rowconfigure(1, weight=1)
        self.grid_columnconfigure(0, weight=1)

        self.label = customtkinter.CTkLabel(self, text=input_name, height=20)
        self.label.grid(row=0, column=0, padx=20, pady=10, sticky="n")

        self.input_box = customtkinter.CTkTextbox(self)
        self.input_box.grid(row=1, column=0, padx=20, pady=20, sticky="nsew")

class SideFrame(customtkinter.CTkFrame):
    def __init__(self, master, **kwargs):
        super().__init__(master, **kwargs)

        self.about_window = None
        self.label1 = customtkinter.CTkLabel(self, text="工具箱")
        self.label1.grid(row=0, column=0, padx=20, pady=20)
        self.button1 = customtkinter.CTkButton(self, text="性能提取", command=master.ShowPerf)
        self.button1.grid(row=1, column=0, padx=20, pady=5)
        self.button2 = customtkinter.CTkButton(self, text="随机数检测", command=master.randomtest)
        self.button2.grid(row=2, column=0, padx=20, pady=5)
        self.button3 = customtkinter.CTkButton(self, text="SM3算法", command=master.SM3Hash)
        self.button3.grid(row=3, column=0, padx=20, pady=5)
        self.button4 = customtkinter.CTkButton(self, text="文本处理", command=master.SM3Hash)
        self.button4.grid(row=4, column=0, padx=20, pady=5)
        self.aboutbutton = customtkinter.CTkButton(self, text="关于", command=self.open_about)
        self.aboutbutton.grid(row=8, column=0, padx=20, pady=20, sticky="s")

    def open_about(self):
        if self.about_window is None or not self.about_window.winfo_exists():
            self.about_window = AboutWindow(self)

class PerfFrame(customtkinter.CTkFrame):
    def __init__(self, master, **kwargs):
        super().__init__(master, **kwargs)

        self.sheet = None
        self.grid_columnconfigure(0, weight=1)
        self.grid_rowconfigure(0, weight=1)

        self.files = FileFrame(self, height=60)
        self.files.grid(row=1, column=0, padx=20, sticky="sew")

        self.start = customtkinter.CTkButton(self, text="开始", command=self.getres)
        self.start.grid(row=0, pady=20, padx=40, sticky="se")

    def getres(self):
        global path
        res = getperf.get_perf(path)
        self.sheet = tksheet.Sheet(self, headers=["测试项", "源数据", "结果"], height=750, width=648,
                                   show_x_scrollbar=False,
                                   vertical_grid_to_end_of_window=True,
                                   horizontal_grid_to_end_of_window=True)
        self.sheet.enable_bindings()
        self.sheet.font(("Times New Roman", 16, "normal"))
        self.sheet.header_font(("Times New Roman", 16, "bold"))
        self.sheet.grid(row=0, column=0, padx=40, pady=40, sticky="nsw")
        for i in range(3):
            self.sheet.column_width(column=i, width=200)
            self.sheet.set_column_data(i, values=res[i], add_rows=True, redraw=False)

class RandomFrame(customtkinter.CTkFrame):
    def __init__(self, master, **kwargs):
        super().__init__(master, **kwargs)

        print("random")

class SM3Frame(customtkinter.CTkFrame):
    def __init__(self, master, **kwargs):
        super().__init__(master, **kwargs)

        self.grid_columnconfigure((0, 1), weight=1)
        self.grid_rowconfigure((0, 1), weight=1)
        self.message_input = inputFrame("消息原文", master=self)
        self.message_input.grid(row = 0, column=0, sticky = "nsew")
        self.key_input = inputFrame("HMAC密钥", master=self)
        self.key_input.grid(row=0, column=1, sticky = "nsew")
        self.hash_output = inputFrame("HASH结果", master=self)
        self.hash_output.grid(row=1, column=0, sticky = "nsew")
        self.hash_output = inputFrame("HMAC结果", master=self)
        self.hash_output.grid(row=1, column=1, sticky = "nsew")

        print("sm3")

class App(customtkinter.CTk):
    def __init__(self):
        super().__init__()

        self.sm3 = None
        self.random = None
        self.func = None
        self.title('MuTools')
        self.minsize(960, 720)
        self.grid_rowconfigure(0, weight=1)
        self.grid_columnconfigure(0, weight=0)
        self.grid_columnconfigure(1, weight=1)

        self.side = SideFrame(master=self)
        self.side.grid_rowconfigure(8, weight=1)
        self.side.grid(row=0, column=0, sticky="nsew")

    def ShowPerf(self):
        self.func = PerfFrame(master=self)
        self.func.grid(row=0, column=1, sticky="nsew")

    def randomtest(self):
        self.random = RandomFrame(master=self)
        self.random.grid(row=0, column=1, sticky="nsew")

    def SM3Hash(self):
        self.sm3 = SM3Frame(master=self, corner_radius=0)
        self.sm3.grid(row=0, column=1, sticky="nsew")

if __name__ == "__main__":
    app = App()
    app.mainloop()


"""Module for visualizing the first convolution layer filter images"""
import torch
import network
import torchvision.transforms as transforms
from PIL import Image
import torchvision.models as models
import matplotlib.pyplot as plt
import numpy as np

OUT_PATH = "../filter_images/"

def generate_filters(model_path, out_file_name):
	"""Generate the first layer filters"""
	net = network.SimClRNet(num_classes=12)
	net.load_state_dict(torch.load(model_path))
	model_children = list(net.backbone.children())
	print(model_children[0], type(model_children[0]), model_children[0].weight.shape)
	convlayer1 = model_children[0]

	# visualize the first conv layer filters
	plt.figure(figsize=(20, 17), tight_layout=True)
	for i, fltr in enumerate(model_children[0].weight):
		plt.subplot(8, 8, i+1)  # (8, 8) because in conv0 we have 7x7 filters and total of 64 (see printed shapes)
		fltr = fltr.detach().numpy()
		fltr = fltr - fltr.min()
		fltr = fltr / fltr.max()
		fltr = np.transpose(fltr, (1, 2, 0))
		plt.imshow(fltr)
		plt.axis('off')
		plt.savefig(OUT_PATH + out_file_name)
	# plt.show()

generate_filters("../simclr_models/simclr_toybox_self_final_1_supervised.pt", "self_1.png")
generate_filters("../simclr_models/simclr_toybox_self_final_2_supervised.pt", "self_2.png")
generate_filters("../simclr_models/simclr_toybox_transform_final_1_supervised.pt", "transform_1.png")
generate_filters("../simclr_models/simclr_toybox_transform_final_2_supervised.pt", "transform_2.png")
generate_filters("../simclr_models/simclr_toybox_object_final_1_supervised.pt", "object_1.png")
generate_filters("../simclr_models/simclr_toybox_object_final_2_supervised.pt", "object_2.png")
generate_filters("../simclr_models/toybox_class_final_supervised.pt", "class_1.png")
generate_filters("../simclr_models/toybox_class_final_2_supervised.pt", "class_2.png")


import re
from operator import add

from mrjob.job import MRJob

class MRSparkWordcount(MRJob):

    def spark(self, input_path, output_path):
        # Spark may not be available where script is launched
        from pyspark import SparkContext

        sc = SparkContext(appName='mrjob Spark image ount script')

        lines = sc.textFile(input_path)

        counts = (
            lines.flatMap(self.get_words)
            .map(lambda word: (word, 1))
            .reduceByKey(add))

        counts.saveAsTextFile(output_path)

        sc.stop()

    def get_words(self, line):
        words = re.split(",", line)
        return words[0].lower().strip()

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


import scrapy
import pickle
import os
import ast
from urllib import parse
from scrapy.selector import Selector

class AnhuiSpider(scrapy.Spider):
    name = "Anhui"
    if not os.path.exists('../../data/HTML_pk/%s' % name):
        os.makedirs('../../data/HTML_pk/%s' % name)
    if not os.path.exists('../../data/text/%s' % name):
        os.makedirs('../../data/text/%s' % name)
    def start_requests(self):
        total_page = 448
        # total_page = 3
        url_base = 'http://www.ah.gov.cn/site/label/8888?IsAjax=1&dataType=html&_=0.42568734060518776&siteId=6781961&pageSize=16&pageIndex={0}&action=list&isDate=true&dateFormat=yyyy-MM-dd&length=46&organId=1681&type=4&catId=&cId=&result=%E6%9A%82%E6%97%A0%E7%9B%B8%E5%85%B3%E4%BF%A1%E6%81%AF&searchType=&keyWords=&specialCatIds=6708451%2C6708461%2C6708471&catIdExplainType=6711101tp_explain%2C6711111xwfbh_explain%2C6711121sp_explain%2C6711131ft_explain&labelName=publicInfoList&file=%2Fahxxgk%2FpublicInfoList-an-new'
        for i in range(total_page):
            yield scrapy.Request(url=url_base.format(i+1), callback=self.parse)

    def parse(self,response):
        detail_page_links = []
        for div in response.css('div.xxgk_navli'):
            url = response.urljoin(div.css('a::attr(href)').get())
            UID = url.split('/')[-1][:-5]
            detail_page_links.append(url)
            yield {
                'UID': UID,
                'title': div.css('a::attr(title)').get(),
                'date': div.css('span.date::text').get(),
                'FileNumber':None,
                'url': url,
                'crawl state':'half'
            }
        yield from response.follow_all(detail_page_links, callback = self.parse_content)

    def parse_content(self, response):
        UID = response.url.split('/')[-1][:-5]
        with open('../../data/HTML_pk/%s/%s.pkl' % (self.name,UID), 'wb') as f:
            pickle.dump(response.text,f)
        doc_info_dict = {}
        td_list = response.css('tbody')[0].css('td')
        th_list = response.css('tbody')[0].css('th')
        for i in range(len(th_list)):
            key = ''.join(th_list[i].css('::text').getall())
            value = ''.join(td_list[i].css('::text').getall())
            doc_info_dict[key] = value
        File_num = None
        if '文号：' in doc_info_dict.keys():
            File_num = doc_info_dict['文号：']
        paragraph_list =  response.css('div.wzcon p *::text').getall()
        with open('../../data/text/%s/%s.txt' % (self.name,UID), 'w') as f:
            f.write('\n'.join(paragraph_list))
        return {
            'UID': UID,
            'FileNumber':File_num,
            'mainText': paragraph_list,
            'doc_info_dict':doc_info_dict,
            'crawl state':'full',
        }


import os
def ensure_dir(file_path):
    directory = os.path.dirname(file_path)
    if not os.path.exists(directory):
        os.makedirs(directory)
        print("新建文件夹'%s'成功"%file_path)
    else:
        print("'%s'已经存在"%file_path)
if __name__ == "__main__":

    f="./jpstest/"
    ensure_dir(f)