#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
PROCESSED FILE VERSION V1.0 built on multiPlot v1.2

multiPlot version v1.2 cleans up to make Pi and Windows use easier

multiPlot version v1.1 adds sunrise sunset times for location of lat long in first file
requires suntime library https://github.com/SatAgro/suntime

multiPlot version v1.0 plots up to 10 PSWS "rawdata" files and average value
modified from WWV_plt2.py @authors dkazdan jgibbons
expects a homepath directory with processed files in homepath or subdirs
leaves plot in Mplot directory
plots files from multiple subdir to compare node results
plot title from first file

windows version hardcoded homepath directory location
for Pi comment out windows homepath and uncomment Pi  lines

uses WWV_utility2.py
Bob Benedict, KD8CGH, 7/29/2021

create text file "Processfiles.txt" in homepath directory
  keyword ('Doppler' or 'Power')
  keyword ('Average' or 'No Average')
  subdir/filename1
  subdir/filename2
  filename3
  ...

Note - expects all data from the same beacon

if found 'Doppler' will plot Doppler shifts, else will plot Power
if found "Average" will add average plot

loads file names in list
plots first file and create axis and title info
plots rest in loop as curves on first plot
calculates average and plots
leaves plotfile in Mplot directory

uses
WWV_utility2.py
20 February 2020
WWV utility file
Routines and classes used in WWV file management and graphing
David Kazdan, AD8Y
John Gibbons, N8OBJ - mods to plot header 2/3/20

"""

#import os # uncomment for pi
from os import path
import sys
import csv
import math
#import shutil  # uncomment for pi
#from datetime import date, timedelta  # uncomment for pi
import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import filtfilt, butter
import datetime
from suntime import Sun
#import subprocess
from WWV_utility2 import time_string_to_decimals
from Beacon import readheader

'''  #uncomment for Pi
# ~ points to users home directory - usually /home/pi/
homepath = os.path.expanduser('~')

# imbed the trailing / in the home path
homepath = homepath + "/PSWS/"

#comment out windows homepath
'''

homepath = "E:\\Documents\\PSWS\\"  # set your windows path, comment out for Pi

names = open(homepath+"Processfiles.txt","r")

PlotTarget = names.readline()
PlotTarget = PlotTarget.strip('\n')
PlotAverage = names.readline()
if PlotAverage[0:7] == 'Average':
    doavg=True
else:
    doavg=False

Filenames=['a' for a in range (10)]
Filedates=['a' for a in range (10)]
#PrFilenames=['a' for a in range (10)]
Nodenum=['a' for a in range (10)]
Beaconname=['a' for a in range (10)]
beaconfreq=np.zeros(10)

nfiles = 0  # holder for number of files to plot

colors=['b','g','r','c','m','y','tab:orange','tab:gray','tab:purple','tab:brown']

while True:
    temp = names.readline()
    if  len(temp) <= 1:
        break
    Filenames[nfiles]=temp.strip("\n")
    fdate = Filenames[nfiles].find("/") # find start of filename after subdirectory
    if fdate==-1 :  # if / not found try \
        fdate = Filenames[nfiles].find("\\")
#    print(" position ",fdate)
    # if neith / nor \ found file is in homepath, fdate=-1, following assignment still works
    Filedates[nfiles]=temp[fdate+1:fdate+11]
    nfiles=nfiles + 1

#print(Filenames[0:9])
#print(Filedates[0:9])
print('number of files',nfiles)
if nfiles > 10 :
    print('10 file limit')
    sys.exit(0)

PROCESSDIR = homepath

#saved plot directrory
PlotDir = homepath + 'Mplot/'

'''
read first file
'''
PrFilenames=(PROCESSDIR + Filenames[0])

if (path.exists(PrFilenames)):
    print('File ' + PrFilenames + ' found!\nProcessing...')
else:
    print('File ' + PrFilenames + ' not available.\nExiting disappointed...')
    sys.exit(0)

with open(PrFilenames, 'r') as dataFile:
    dataReader=csv.reader(dataFile)
    data = list(dataReader)
    Header = data.pop(0)

#    print('return',readheader(0,Header))
    Nodenum[0], Beaconname[0], beaconfreq[0], Lat, Long = readheader(Header)
#    print('\n returned ', Nodenum[0], Beaconname[0], beaconfreq[0], Lat, Long, '\n')

''' ###########################################################################
'''
print('Ready to start processing records')

# Prepare data arrays
hours=[[],[],[],[],[],[],[],[],[],[]]
Doppler=[[],[],[],[],[],[],[],[],[],[]]
#Vpk=[[],[],[],[],[],[],[],[],[],[]]
Power_dB=[[],[],[],[],[],[],[],[],[],[]] # will be second data set, received power 9I20
filtDoppler=[[],[],[],[],[],[],[],[],[],[]]
filtPower=[[],[],[],[],[],[],[],[],[],[]]

LateHour=False # flag for loop going past 23:00 hours

# eliminate all metadata saved at start of file - Look for UTC (CSV headers)
#find first row of data0
FindUTC = 0

for row in data:
    if (FindUTC == 0):
        #print('looking for UTC - row[0] =',row[0])
        if (row[0] == 'UTC'):
            FindUTC = 1
#            print('UTC found =', row[0])
    else:
        #print('Processing record')
        decHours=time_string_to_decimals(row[0])
#        if (NewHdr != 'New'):
#            if (calccnt  < 101):
#                calcnt = calcnt+1
#                freqcalc = freqcalc + (float(row[1])/100)
#        if decHours > 23:
#            LateHour=True # went past 23:00 hours
        if (not LateHour) or (LateHour and (decHours>23)): # Otherwise past 23:59:59.  Omit time past midnight.
            hours[0].append(decHours) # already in float because of conversion to decimal hours.
            Doppler[0].append(float(row[1])-beaconfreq[0]) # frequency offset from col 2
#            Vpk[0].append (float(row[2])) # Get Volts peak from col 3
            Power_dB[0].append (20*math.log10(float(row[2]))) # log power from col 4

#print('nf ',0,'len hours',len(hours[0]))

###############################################################################################
# Find max and min of Power_dB for graph preparation:
min_power=np.amin(Power_dB[0]) # will use for graph axis min
max_power=np.amax(Power_dB[0]) # will use for graph axis max

min_Doppler=np.amin(Doppler[0]) # min Doppler
max_Doppler=np.amax(Doppler[0]) # max Doppler

print('\nDoppler min: ', min_Doppler, '; Doppler max: ', max_Doppler)
print('dB min: ', min_power, '; dB max: ', max_power)

#%% Create an order 3 lowpass butterworth filter.
# This is a digital filter (analog=False)
# Filtering at .01 to .004 times the Nyquist rate seems "about right."
# The filtering argument (Wn, the second argument to butter()) of.01
# represents filtering at .05 Hz, or 20 second weighted averaging.
# That corresponds with the 20 second symmetric averaging window used in the 1 October 2019
# Excel spreadsheet for the Festival of Frequency Measurement data.
#FILTERBREAK=.005 #filter breakpoint in Nyquist rates. N. rate here is 1/sec, so this is in Hz.
FILTERBREAK=0.005 #filter breakpoint in Nyquist rates. N. rate here is 1/sec, so this is in Hz.
FILTERORDER=6
b, a = butter(FILTERORDER, FILTERBREAK, analog=False, btype='low')
#print (b, a)
#%%
# Use the just-created filter coefficients for a noncausal filtering (filtfilt is forward-backward noncausal)

filtDoppler[0] = filtfilt(b, a, Doppler[0])

filtPower[0] = filtfilt(b, a, Power_dB[0])

##################################################################################################
# sunrise sunset times in UTC
sun = Sun(float(Lat), float(Long))

UTC_DT=Filedates[0]
print(UTC_DT)
SDAY=int(UTC_DT[8:10])
SMON=int(UTC_DT[5:7])
SYEAR=int(UTC_DT[0:4])
sdate = datetime.date(SYEAR, SMON, SDAY)
today_sr = sun.get_sunrise_time(sdate)
today_ss = sun.get_sunset_time(sdate)
#print(today_sr)
srh=int(format(today_sr.strftime('%H')))
srm=int(format(today_sr.strftime('%M')))
srx=srh+srm/60
ssh=int(format(today_ss.strftime('%H')))
ssm=int(format(today_ss.strftime('%M')))
ssx=ssh+ssm/60

# set up x-axis with time
fig = plt.figure(figsize=(19,10)) # inches x, y with 72 dots per inch
ax = fig.add_subplot(111)
ax.set_xlabel('UTC Hour')
ax.set_xlim(0,24) # UTC day
ax.set_xticks([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24], minor=False)

# plot first curve
if (PlotTarget == 'Doppler'):
    ax.plot([srx,srx],[-1,1],'y',label='sunrise',linestyle='dashed')
    ax.plot([ssx,ssx],[-1,1],'b',label='sunset',linestyle='dashed')
    ax.plot(hours[0], filtDoppler[0], colors[0],label=Beaconname[0] +' '+Nodenum[0]+' '+Filedates[0]) # color k for black
    ax.set_ylabel('Doppler shift, Hz '+ Filedates[0])
    ax.set_ylim([-1.0, 1.0]) # -1 to 1 Hz for Doppler shift
    plt.axhline(y=0, color="gray", lw=1) # plot a zero freq reference line for 0.000 Hz Doppler shift

else:
    ax.plot([srx,srx],[-90,0],'y',label='sunrise',linestyle='dashed')
    ax.plot([ssx,ssx],[-90,0],'b',label='sunset',linestyle='dashed')
    ax.plot(hours[0], filtPower[0], colors[0],label=Beaconname[0] +' '+ Nodenum[0]+' '+Filedates[0]) # color k for black
    ax.set_ylabel('Power, dB '+ Filedates[0])
    ax.set_ylim(-90, 0)

# add grid lines - RLB
plt.grid(axis='both')

'''
######################################################################
read and plot files loop
'''

for nf in range(1, nfiles):
# splot second curve
# read second file, skip header
    print('process file ',nf, Filenames[nf])
    PrFilenames=(PROCESSDIR + Filenames[nf])
    with open(PrFilenames, 'r') as dataFile: # read second set
        dataReader=csv.reader(dataFile)
        data = list(dataReader)
        Header = data.pop(0)
        Nodenum[nf]= Header[2]
    FindUTC = 0

    Nodenum[nf], Beaconname[nf], beaconfreq[nf], Lat, Long = readheader(Header)
#    print('\n returned ', Nodenum[nf], Beaconname[nf], beaconfreq[nf], Lat, Long, '\n')

    for row in data:
        if (FindUTC == 0):
            #print('looking for UTC - row[0] =',row[0])
            if (row[0] == 'UTC'):
                FindUTC = 1
#            print('UTC found =', row[0])
        else:
            decHours=time_string_to_decimals(row[0])
            hours[nf].append(decHours) # already in float because of conversion to decimal hours.
            Doppler[nf].append(float(row[1])-beaconfreq[nf]) # frequency offset from col 2
#            Vpk[nf].append (float(row[2])) # Get Volts peak from col 3
#            Power_dB[nf].append (float(row[4])) # log power from col 4
            Power_dB[nf].append (20*math.log10(float(row[2]))) # log power
# filter  file data
    filtDoppler[nf] = filtfilt(b, a, Doppler[nf])
    filtPower[nf] = filtfilt(b, a, Power_dB[nf])

    if (PlotTarget == 'Doppler'):
        ax.plot(hours[nf], filtDoppler[nf], colors[nf], label=Beaconname[nf] +' '+ Nodenum[nf]+' '+Filedates[nf]) # color k for black
    else:
        ax.plot(hours[nf], filtPower[nf], colors[nf], label=Beaconname[nf] +' '+ Nodenum[nf]+' '+Filedates[nf]) # color k for black

'''
#############################################################################
end for read and plot loop, start average
'''
# find shortest data set, limit average to that
if doavg :
    al=1000000
    ak=0

    for k in range(nfiles):
        templ=len(hours[k])
        if templ < al:
            al=templ
            ak=k

    avg=[]

    if (PlotTarget == 'Doppler'):
        for i in range(al):
            temp=0.0
            for j in range(nfiles):
                temp=temp+filtDoppler[j][i]
            temp=temp/nfiles
            avg.append(temp)
    else:
        for i in range(al):
            temp=0.0
            for j in range(nfiles):
                temp=temp+filtPower[j][i]
            temp=temp/nfiles
            avg.append(temp)

    #print('avg',len(avg))

    ax.plot(hours[ak], avg, 'k', label='Average') # color k for black

'''
end average
'''
ax.legend(loc="lower right",  frameon=False)

# Create Plot Title
plt.title(' Grape Data Plot')
#plt.title(beaconlabel + ' Grape Data Plot\nNode:  ' + node + '     Gridsquare:  '+ GridSqr + '\nLat= ' + Lat + '    Long= ' + Long + '    Elev= ' + Elev + ' M\n' )
# Create Plot File Nam
#GraphFile = yesterdaystr + '_' + node + '_' + RadioID + '_' + GridSqr + '_' + beacon + '_graph.png'
GraphFile = 'multi'+ PlotTarget + '.png'
PlotGraphFile = PlotDir + GraphFile

# create plot
#plt.savefig(PlotDir + yesterdaystr + '_' + node + '_' +  GridSqr + '_' +  RadioID + '_' +  beacon + '_graph.png', dpi=250, orientation='landscape')
plt.savefig(PlotDir + GraphFile, dpi=250, orientation='landscape')
# =============================================================================

print('Plot File: ' + GraphFile + '\n')  # indicate plot file name for crontab printout

#-------------------------------------------------------------------
print('Exiting python multi plot program gracefully')


import datetime as dt
import os

from engine.tool import datetool
from engine.conf import param

SINGLE_SEP_LINE = '\n' + '-'*30

cache = []

def doLog(msg):
    """

    :rtype : None
    """
    current_time = datetool.fmt2str(dt.datetime.now())
    content = "{0} : \t{1}".format(current_time, msg)
    print(content)

    global cache
    cache.append(content + '\n')

    if len(cache) >= 10:
        toDisk()

def toDisk():
    global cache
    if len(cache) > 0:
        with open(os.path.join(param.BASE_PATH, 'log.txt'), 'a') as f:
            f.writelines(cache)
            cache = []

def printProgress(i, N, p0, p1):  # p0% - p1% progress
    doLog('>> PROGRESS(%): {0}\n'.format(int((p1-p0) * i / N) + p0))


from mmdet.apis import inference_detector
from mmdet.models import build_detector
from mmcv.runner import load_state_dict
from collections import OrderedDict
import scipy
import mmcv
import os
import torch
import numpy as np
import cv2
import time
from mmdet.models.utils.efficientdet_utils import plot_one_box, get_index_label, STANDARD_COLORS, standard_to_bgr
from mmdet.models.utils.tracker.multitracker import JDETracker
from mmdet.models.utils.detect_post_process import simple_nms
from mmdet.models.utils.efficientdet_utils import _topk, tranpose_and_gather_feat, nms_torch, plot_one_box

DEVICE = 'cuda'

config_file = '/home/boden/Dev/ws/ws/BDNet_tracking/configs/bdnet/bdnet_tracking.py'
checkpoint_file = '/home/boden/Dev/ws/ws/BDNet_tracking/work_dirs/20210611/epoch_56.pth'

threshold = 0.4
iou_threshold = 0.2
obj_list = ['Sedan', 'Van', 'STruck', 'MTruck', 'LTruck', 'Bus','Traffic_Cone','Traffic_Bar','Traffic_Barrier']

color_list = standard_to_bgr(STANDARD_COLORS)
scale = torch.tensor([896/1418,384/640,896/1418,384/640],dtype=torch.float32).cuda()
config = mmcv.Config.fromfile(config_file)
height = config.height
width = config.width
# load config information
img_mean = config.img_norm_cfg['mean']
img_std = config.img_norm_cfg['std']
num_classes = len(config.classes)

# build the model from a config file and a checkpoint file
model = build_detector(config.model, test_cfg=config.test_cfg)
checkpoint = torch.load(checkpoint_file, map_location=torch.device('cuda'))

model.CLASSES = checkpoint['meta']['CLASSES']
state_dict = checkpoint['state_dict']
# strip prefix of state_dict
if list(state_dict.keys())[0].startswith('module.'):
    state_dict = {k[7:]: v for k, v in checkpoint['state_dict'].items()}
# load state_dict
if hasattr(model, 'module'):
    load_state_dict(model.module, state_dict, False, None)
else:
    load_state_dict(model, state_dict, False, None)

model.cfg = config  # save the config in the model for convenience
model.cuda()
model.eval()

def anchor_free_bbox_post_process(pred_heatmap, pred_wh, pred_off2d, scale):
    scale = torch.from_numpy(scale).cuda()
    down_ratio = 8
    batch, cat, height, width = pred_heatmap.size()
    pred_heatmap = pred_heatmap.detach().sigmoid_()
    wh = pred_wh.detach()
    off2d = pred_off2d.detach()

    # perform nms on heatmaps
    # heat = simple_nms(pred_heatmap)  # used maxpool to filter the max score
    heat = pred_heatmap
    topk = 100
    # (batch, topk)
    scores, inds, clses, ys, xs = _topk(heat, topk=topk)

    if pred_off2d is not None:
        off2d = tranpose_and_gather_feat(off2d, inds)
        off2d = off2d.view(batch, topk, 2)
        xs = (xs.view(batch, topk, 1) + off2d[:, :, 0:1]) * down_ratio
        ys = (ys.view(batch, topk, 1) + off2d[:, :, 1:2]) * down_ratio
    else:
        xs = xs.view(batch, topk, 1) * down_ratio
        ys = ys.view(batch, topk, 1) * down_ratio

    wh = tranpose_and_gather_feat(wh, inds)

    wh = wh.view(batch, topk, 2)
    wh = wh * down_ratio
    clses = clses.view(batch, topk, 1).float()
    scores = scores.view(batch, topk, 1)

    bboxes2d = torch.cat([xs - wh[..., [0]] / 2, ys - wh[..., [1]] / 2,
                          xs + wh[..., [0]] / 2, ys + wh[..., [1]] / 2], dim=2)

    result_list = []
    score_thr = 0.3
    for batch_i in range(bboxes2d.shape[0]):
        scores_per_img = scores[batch_i].squeeze()
        bboxes2d_per_img = bboxes2d[batch_i]
        labels_per_img = clses[batch_i]

        nms_idx = nms_torch(bboxes2d_per_img, scores_per_img, iou_threshold=0.5)

        bboxes2d_per_img = bboxes2d_per_img[nms_idx] / scale

        labels_per_img = labels_per_img[nms_idx]
        scores_per_img = scores_per_img[nms_idx]

        scores_keep = (scores_per_img > score_thr)

        scores_per_img = scores_per_img[scores_keep].unsqueeze(1)
        bboxes2d_per_img = bboxes2d_per_img[scores_keep]

        labels_per_img = labels_per_img[scores_keep]

        bboxes_per_img = torch.cat([bboxes2d_per_img.float(), scores_per_img.float(), labels_per_img.float()], dim=1)
        result_list.append(bboxes_per_img)
    result_list = torch.stack(result_list, dim=0)
    result_list = result_list.squeeze(0)
    result_list = result_list.cpu().numpy()
    return result_list

def anchor_based_bbox_post_process(det_list, scale):
    result_list = []
    center_list = []
    score_thr = 0.5
    for det in det_list:
        bbox, label, score = det['bbox'], det['label'], det['score']
        if score > score_thr:
            x1, y1, x2, y2 = bbox
            center_list.append(np.array([(x1+x2)/2, (y1+y2)/2]))
            x1 /= scale[0]
            y1 /= scale[1]
            x2 /= scale[0]
            y2 /= scale[1]
            result_list.append(np.array([x1, y1, x2, y2, score, label]))

    return np.array(result_list), np.array(center_list)

def anchor_base_feature_post_process(feature_heatmap, center_list):
    embedding_list = []
    if len(center_list) > 0:
        feature_heatmap = feature_heatmap.squeeze().permute(1,2,0).contiguous().cpu().numpy()
        center_list = center_list.astype(np.int)

        ct_int_x = center_list[:, 0]//8
        ct_int_y = center_list[:, 1]//8
        ct_res_x = center_list[:, 0]/8 - ct_int_x
        ct_res_y = center_list[:, 1]/8 - ct_int_y

        for x, y, res_x, res_y in zip(ct_int_x, ct_int_y, ct_res_x, ct_res_y):
            embedding = (1-res_x)*(1-res_y)*feature_heatmap[y, x] + (1-res_x)*(res_y)*feature_heatmap[y+1, x] \
                + (res_x)*(1-res_y)*feature_heatmap[y, x+1] + (res_x)*(res_y)*feature_heatmap[y+1, x+1]

            embedding_list.append(embedding)

    embedding_list = np.array(embedding_list)

    return embedding_list

def display(bbox, img, idx, imshow=False, imwrite=False,color=(0,0,0)):

    if bbox.shape[0] == 0:
        return img

    img = img.copy()

    for j in range(len(bbox)):
        x1, y1, x2, y2 = bbox[j,:4].astype(np.int)
        obj = obj_list[int(bbox[j,5])]
        score = float(bbox[j,4])
        plot_one_box(img, [x1, y1, x2, y2], label=obj,score=score,color=color)

    if imshow:
        cv2.imshow('img', img)
        cv2.waitKey(0)

    if imwrite:
        # cv2.imwrite(f'test/img_inferred_d{0}_this_repo_{i}.jpg', imgs[i])
        cv2.imwrite('/home/boden/Dev/ws/whz/BDPilot-merge/data/val/test_%d.jpg'%idx,img)

    return img

def get_color(idx):
    idx = idx * 3
    color = ((37 * idx) % 255, (17 * idx) % 255, (29 * idx) % 255)

    return color

def plot_tracking(image, tlwhs, obj_ids, scores=None, frame_id=0, fps=0., ids2=None):
    im = np.ascontiguousarray(np.copy(image))
    im_h, im_w = im.shape[:2]

    top_view = np.zeros([im_w, im_w, 3], dtype=np.uint8) + 255

    text_scale = max(1, image.shape[1] / 3200.)
    text_thickness = 1 if text_scale > 1.1 else 1
    line_thickness = max(1, int(image.shape[1] / 500.))

    radius = max(5, int(im_w/140.))
    cv2.putText(im, 'frame: %d fps: %.2f num: %d' % (frame_id, fps, len(tlwhs)),
                (0, int(15 * text_scale)), cv2.FONT_HERSHEY_PLAIN, text_scale, (0, 0, 255), thickness=2)

    for i, tlwh in enumerate(tlwhs):
        x1, y1, w, h = tlwh
        intbox = tuple(map(int, (x1, y1, x1 + w, y1 + h)))
        obj_id = int(obj_ids[i])
        id_text = '{}'.format(int(obj_id))
        if ids2 is not None:
            id_text = id_text + ', {}'.format(int(ids2[i]))
        _line_thickness = 1 if obj_id <= 0 else line_thickness
        color = get_color(abs(obj_id))
        cv2.rectangle(im, intbox[0:2], intbox[2:4], color=color, thickness=line_thickness)
        cv2.putText(im, id_text, (intbox[0], intbox[1]), cv2.FONT_HERSHEY_PLAIN, text_scale, (0, 0, 255),
                    thickness=2)
    return im

def display_bbox(bbox, img, start_index, color=(0,0,0)):
    if bbox.shape[0] == 0:
        return img

    for j in range(len(bbox)):
        x1, y1, x2, y2 = bbox[j,:4].astype(np.int)
        score = float(bbox[j,4])
        obj = obj_list[start_index + int(bbox[j,5])]
        plot_one_box(img, [x1, y1, x2, y2], label=obj,score=score,color=color)

    return img

# DEMO_DIR = '/home/boden/Dev/ws/whz/BDPilot-merge/data/validation_crop'
# DEMO_DIR = '/home/boden/Dev/ws/BDPilotDataset/Depth/save_00_calib_480'
# DEMO_DIR = '/home/boden/Dev/ws/BDPilotDataset/BDMerge/val_lane/scene_1'
DEMO_DIR = '/home/boden/Dev/ws/BDPilotDataset/BDMerge/val_lane/scene_2'
OUTPUT_PATH = '/home/boden/Dev/ws/ws/BDNet_tracking/data/output_0612_3'

IMG_LIST = os.listdir(DEMO_DIR)
IMG_LIST.sort()

tracker = JDETracker(conf_thres=0.3,mean=img_mean,std=img_std,num_classes=len(model.CLASSES))
scale = np.array([768/1418,384/640,768/1418,384/640])

for frame_id,DEMO_IMG in enumerate(IMG_LIST):
    img_name = DEMO_IMG
    DEMO_IMG = os.path.join(DEMO_DIR,DEMO_IMG)
    img = cv2.imread(DEMO_IMG)
    time1 = time.time()
    outputs = inference_detector(model, DEMO_IMG)
    dynamic_bbox_result, center_bbox_result = anchor_based_bbox_post_process(outputs['detect'], scale)
    static_bbox_result = anchor_free_bbox_post_process(outputs['static_detect']['hm'], outputs['static_detect']['wh'], outputs['static_detect']['off_2d'], scale)
    feature_bbox_result = anchor_base_feature_post_process(outputs['track']['embedding'], center_bbox_result)

    online_targets = tracker.update(dynamic_bbox_result, feature_bbox_result)
    online_tlwhs = []
    online_ids = []
    for t in online_targets:
        tlwh = t.tlwh
        tid = t.track_id
        online_tlwhs.append(tlwh)
        online_ids.append(tid)
    img = plot_tracking(img, online_tlwhs, online_ids, frame_id=frame_id, fps=1/(time.time()-time1))

    img = display_bbox(static_bbox_result, img, 6, color=(18,87,220))

    # for bbox in dynamic_bbox_result:
    #     cv2.rectangle(img, (int(bbox[0]), int(bbox[1])), (int(bbox[2]), int(bbox[3])), (255, 0, 0), thickness=2)

    cv2.imwrite(os.path.join(OUTPUT_PATH, img_name), img)


import os
from collections import namedtuple
from typing import Iterable
from unittest import TestCase, mock

from parameterized import parameterized

from model_garden.services.s3 import (
  DELETE_REQUEST_LIMIT, DeleteError, S3Client, image_ext_filter,
)

class TestS3Client(TestCase):
  def setUp(self):
    self.bucket_name = 'bucket-name'
    self.resource_patcher = mock.patch('model_garden.services.s3.resource')
    self.resource_mock = self.resource_patcher.start()
    self.s3_mock = self.resource_mock.return_value
    self.bucket_mock = self.s3_mock.Bucket.return_value
    self.client = S3Client(bucket_name=self.bucket_name)

  def tearDown(self):
    self.resource_patcher.stop()

  def test_list_bucket(self):
    object_mock = mock.Mock()
    self.bucket_mock.objects.all.return_value = [object_mock]

    result = self.client.list_bucket()

    self.assertEqual(result, [object_mock])

  def test_list_keys_without_filter(self):
    object_mock = mock.Mock()
    self.bucket_mock.objects.filter.return_value = [object_mock]

    result = self.client.list_keys('foo')

    self.assertIsInstance(result, Iterable)
    self.assertEqual(list(result), [object_mock])

  def test_list_keys_with_filter(self):
    object_mock = mock.Mock()
    self.bucket_mock.objects.filter.return_value = [object_mock, mock.Mock()]

    result = self.client.list_keys('foo', filter_by=lambda o: o is object_mock)

    self.assertIsInstance(result, Iterable)
    self.assertEqual(list(result), [object_mock])

  def test_download_file(self):
    self.client.download_file(key='key', filename='filename')

    self.bucket_mock.meta.client.download_file.assert_called_once_with(
      self.bucket_name, 'key', 'filename',
    )

  def test_upload_file(self):
    self.client.upload_file(filename='filename', key='key')

    self.bucket_mock.meta.client.upload_file.assert_called_once_with(
      'filename', self.bucket_name, 'key',
    )

  def test_upload_file_obj(self):
    file_obj_mock = mock.Mock()

    self.client.upload_file_obj(file_obj=file_obj_mock, bucket=self.bucket_name, key='key')

    self.bucket_mock.meta.client.upload_fileobj.assert_called_once_with(
      file_obj_mock, self.bucket_name, 'key',
    )

  def test_upload_files(self):
    file_obj_mock = mock.Mock()

    self.client.upload_files(
      files_to_upload=[
        (file_obj_mock, 'test1.txt'),
        (file_obj_mock, 'test2.txt'),
      ],
      bucket=self.bucket_name,
    )

    self.bucket_mock.meta.client.upload_fileobj.assert_has_calls([
      mock.call(file_obj_mock, self.bucket_name, 'test1.txt'),
      mock.call(file_obj_mock, self.bucket_name, 'test2.txt'),
    ])

  def test_delete_files_when_empty_call(self):
    self.bucket_mock.delete_objects.return_value = {}

    result = self.client.delete_files()

    self.bucket_mock.delete_objects.assert_not_called()
    self.assertListEqual(result, [])

  def test_delete_files_with_pagination(self):
    self.bucket_mock.delete_objects.return_value = {}

    keys_count = int(DELETE_REQUEST_LIMIT * 1.5)
    result = self.client.delete_files(*[str(i) for i in range(keys_count)])

    self.assertEqual(self.bucket_mock.delete_objects.call_count, 2)

    keys_sent = 0
    for i in range(2):
      keys_sent += len(self.bucket_mock.delete_objects.call_args_list[i][1]['Delete']['Objects'])
    self.assertEqual(keys_sent, keys_count)

    self.assertListEqual(result, [])

  def test_delete_files_with_error(self):
    self.bucket_mock.delete_objects.return_value = {
      'Errors': [
        {
          'Key': 'foo',
          'VersionId': 'string2',
          'Code': 'string3',
          'Message': 'string4',
        },
      ],
    }

    result = self.client.delete_files('foo')

    self.bucket_mock.delete_objects.assert_called_once()
    self.assertEqual(len(result), 1)
    self.assertEqual(
      result[0],
      DeleteError(
        key='foo',
        code='string3',
        message='string4',
        version_id='string2',
      ),
    )

  def test_delete_files_cuncurrent_when_tasks_more_than_executor_pool(self):
    default_threads_count = os.cpu_count() + 4
    keys_count = int(DELETE_REQUEST_LIMIT * default_threads_count * 1.5)

    with mock.patch.object(S3Client, 'delete_files') as delete_mock:
      delete_mock.return_value = []

      result = self.client.delete_files_concurrent(
        *[str(i) for i in range(keys_count)],
      )

      keys_sent = 0
      for call in delete_mock.call_args_list:
        keys_sent += len(call[0])
      self.assertEqual(keys_sent, keys_count)

    self.assertListEqual(result, [])

  def test_delete_files_cuncurrent_when_erros_raised(self):
    expected_exception = Exception('foo')

    keys_count = int(DELETE_REQUEST_LIMIT * 1.5)

    with mock.patch.object(S3Client, 'delete_files') as delete_mock:
      delete_mock.side_effect = expected_exception

      result = self.client.delete_files_concurrent(
        *[str(i) for i in range(keys_count)],
      )

    self.assertEqual(len(result), keys_count)
    for each in result:
      self.assertIsInstance(each, DeleteError)
      self.assertEqual(each.message, str(expected_exception))

class TestImageExtFilter(TestCase):

  @parameterized.expand([
    ('', False),
    ('foo', False),
    ('foo/bar', False),
    ('.png', False),
    ('foo.bar', False),
    ('foo/bar/baz.bmp', True),
    ('foo.jpg', True),
  ])
  def test_image_ext_filter(self, key, expected):
    ObjectSummary = namedtuple('ObjectSummary', 'key')

    self.assertIs(image_ext_filter(ObjectSummary(key=key)), expected)

  def test_when_empty_input(self):
    self.assertFalse(image_ext_filter(None))


''' Image Processing Library'''
import numpy as np
import matplotlib.pyplot as plt
from skimage import io
from skimage.segmentation import random_walker

class Cursor(object):
  def __init__(self, fig, ax1, ax2, ax3, im, im_markers, im_labels, r):
    self.fig = fig
    self.ax1 = ax1
    self.ax2 = ax2
    self.ax3 = ax3
    self.im = im
    self.im_markers = im_markers
    self.im_labels = im_labels
    self.r = r
    self.button = 0
    self.xs = self.im.shape[0]
    self.ys = self.im.shape[1]
    self.xr = np.linspace(0, self.xs-1, self.xs)
    self.yr = np.linspace(0, self.ys-1, self.ys)
    self.yy, self.xx = np.meshgrid(self.yr, self.xr)

    self.ax1.imshow(self.im, cmap='gray', interpolation='nearest')
    self.ax1.axis('off')
    self.ax1.set_title('Image')
    self.ax2.imshow(self.im_markers, cmap='magma', interpolation='nearest')
    self.ax2.axis('off')
    self.ax2.set_title('Markers')
    self.ax3.imshow(self.im_labels, cmap='gray', interpolation='nearest')
    self.ax3.axis('off')
    self.ax3.set_title('Segmentation')
    self.fig.tight_layout()

  def draw(self, event):
    x, y = event.xdata, event.ydata
    x, y = int(x), int(y)
    # print('x=%1.2f, y=%1.2f' % (x, y))
    imd = np.sqrt((self.xx-y)**2 + (self.yy-x)**2) <= self.r

    if event.button == 1:
      self.im_markers[imd] = 1
    elif event.button == 3:
      self.im_markers[imd] = 2
    elif event.button == 2:
      self.im_labels = random_walker(self.im, self.im_markers, beta=10, mode='cg_mg') # 'bf'
      self.ax3.imshow(self.im_labels, cmap='gray', interpolation='nearest')
    self.ax2.imshow(self.im_markers, cmap='magma', interpolation='nearest')
    plt.draw()

  def mouse_move(self, event):
    if not event.inaxes:
      return

    if self.button == 1:
      self.draw(event)

  def button_press(self, event):
    if not event.inaxes:
      return

    self.button = 1
    self.draw(event)

  def button_release(self, event):
    if not event.inaxes:
      return
    self.button = 0

if __name__ == '__main__':

  # load image
  filename = './im/cell2d.png'
  im = io.imread(filename)

  # manual semi-supervised image clustering
  im_markers = np.zeros(im.shape, dtype=np.uint8)
  im_labels = np.zeros(im.shape, dtype=np.bool)
  fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(8, 3.2),
                                      sharex=False, sharey=False)
  cursor = Cursor(fig, ax1, ax2, ax3, im, im_markers, im_labels, 10)
  plt.connect('motion_notify_event', cursor.mouse_move)
  plt.connect('button_press_event', cursor.button_press)
  plt.show()


from manpac.entity_type import EntityType
from manpac.entity import Entity
from manpac.map import Map
from manpac.direction import Direction
from manpac.cell import Cell

import numpy as np
import pytest

def test_get_set():
    map = Map((10, 10))
    # Assert start empty
    cnt = 0
    for row in map[:, :]:
        for x in row:
            if x == Cell.EMPTY:
                cnt += 1
    assert cnt == 100

    # Test basic indexing
    map[0, 0] = Cell.WALL
    assert map[0, 0] == Cell.WALL

    # Test with numpy arrays
    pos = np.array([4, 5])
    map[pos] = Cell.WALL
    assert map[pos] == Cell.WALL

    cnt = 0
    for row in map[:, :]:
        for x in row:
            if x == Cell.WALL:
                cnt += 1
    assert cnt == 2

def test_move():
    map = Map((10, 10))
    ent = Entity(EntityType.GHOST)
    ent.alive = True
    ent.moving = True
    ent.face(Direction.RIGHT)

    # Move 0 ticks
    old_pos = ent.pos.copy()
    map.move(ent, 0)
    np.testing.assert_allclose(ent.pos, old_pos)
    # Move for n ticks
    ticks = 7.5
    old_pos = ent.pos.copy() + ent.direction.vector * ent.speed * ticks
    map.move(ent, ticks)
    np.testing.assert_allclose(ent.pos, old_pos)

def test_closest_walkable():
    map = Map((10, 10))

    assert (map.closest_walkable(np.array([-1, 0])) == np.array([0, 0])).all()
    assert (map.closest_walkable(np.array([0, -1])) == np.array([0, 0])).all()
    assert (map.closest_walkable(np.array([10, 9])) == np.array([9, 9])).all()
    assert (map.closest_walkable(np.array([9, 10])) == np.array([9, 9])).all()

    pos = [4, 5]

    for i in range(10):
        n = np.random.random(1)[0]
        assert (map.closest_walkable(np.array([-n, 0])) == np.array([0, 0])).all()
        assert (map.closest_walkable(np.array([0, -n])) == np.array([0, 0])).all()
        assert (map.closest_walkable(np.array([9 + n, 9])) == np.array([9, 9])).all()
        assert (map.closest_walkable(np.array([9, 9 + n])) == np.array([9, 9])).all()
        n = n / 2
        assert (map.closest_walkable(np.array([4-n, 5])) == pos).all()
        assert (map.closest_walkable(np.array([4, 5-n])) == pos).all()
        assert (map.closest_walkable(np.array([4 + n, 5])) == pos).all()
        assert (map.closest_walkable(np.array([4, 5 + n])) == pos).all()

    map[pos] = Cell.WALL
    for i in range(10):
        n = np.random.random(1)[0]
        n = n / 2
        assert not (map.closest_walkable(np.array([4-n, 5])) == pos).all()
        assert not (map.closest_walkable(np.array([4, 5-n])) == pos).all()
        assert not (map.closest_walkable(np.array([4 + n, 5])) == pos).all()
        assert not (map.closest_walkable(np.array([4, 5 + n])) == pos).all()

@pytest.mark.timeout(5)
def test_move_bounds():
    size = 10
    map = Map((size, size))
    ent = Entity(EntityType.GHOST)
    ent.alive = True
    ent.moving = True
    ticks = 7785888.5

    for direction in Direction:
        for i in range(10):
            ent.face(direction)
            p = np.clip(np.random.random_sample(2) * size, ent.size, size - ent.size)
            ent.teleport(p)

            # Move for n ticks
            old_pos = ent.pos.copy() + ent.direction.vector * ent.speed * ticks
            old_pos = np.clip(old_pos, ent.size, size - ent.size)
            map.move(ent, ticks)
            np.testing.assert_allclose(ent.pos, old_pos)

            #  Move for n ticks
            ent.face(-ent.direction)
            old_pos = ent.pos.copy() + ent.direction.vector * ent.speed * ticks
            old_pos = np.clip(old_pos, ent.size, size - ent.size)
            map.move(ent, ticks)
            np.testing.assert_allclose(ent.pos, old_pos)

@pytest.mark.timeout(5)
def test_move_walls():
    size = 10
    map = Map((size, size))
    ent = Entity(EntityType.GHOST)
    ent.alive = True
    ent.moving = True
    ticks = 7785888.5

    map[:, 7:] = Cell.WALL
    map[8:, :] = Cell.WALL
    map[:1, :] = Cell.WALL
    map[:, :2] = Cell.WALL
    max_bounds = np.array([8, 7]) - ent.size
    min_bounds = np.array([1, 2]) + ent.size

    for direction in Direction:
        for i in range(10):
            ent.face(direction)
            p = np.clip(np.random.random_sample(2) * (size - 1), min_bounds, max_bounds)
            ent.teleport(p)

            map.print()

            # Move for n ticks
            old_pos = ent.pos.copy() + ent.direction.vector * ent.speed * ticks
            old_pos = np.clip(old_pos, min_bounds, max_bounds)
            map.move(ent, ticks)
            np.testing.assert_allclose(ent.pos, old_pos)

            #  Move for n ticks
            ent.face(-ent.direction)
            old_pos = ent.pos.copy() + ent.direction.vector * ent.speed * ticks
            old_pos = np.clip(old_pos, min_bounds, max_bounds)
            map.move(ent, ticks)
            np.testing.assert_allclose(ent.pos, old_pos)

def test_pickup_boost():
    map = Map((10, 10))
    ghost = Entity(EntityType.GHOST)
    ghost.alive = True
    ghost.moving = True
    ghost.face(Direction.RIGHT)
    ghost.teleport(np.array([.5, .5]))

    pacman = Entity(EntityType.PACMAN)
    pacman.alive = True
    pacman.moving = True
    pacman.face(Direction.RIGHT)
    pacman.teleport(np.array([.5, .5]))

    map.ghost_boosts = [[Direction.RIGHT.vector * 2.5, 9999], [Direction.DOWN.vector * 3.5, 9999]]

    # Pick up nothing
    map.move(pacman, 1)
    map.move(ghost, 1)
    assert len(map.ghost_boosts) == 2
    assert len(map.pacman_boosts) == 0

    # Pick up ghost boost
    ticks = 4 / ghost.speed
    map.move(pacman, ticks)
    map.move(ghost, ticks)
    assert len(map.ghost_boosts) == 1
    assert len(map.pacman_boosts) == 1

    # Pick up pacman boost
    ghost.face(-ghost.direction)
    pacman.face(-pacman.direction)
    map.move(ghost, ticks)
    map.move(pacman, ticks)
    assert len(map.ghost_boosts) == 1
    assert len(map.pacman_boosts) == 0


import sys
from collections import deque

input = sys.stdin.readline

N, M = map(int, input().split(" "))
board = []
for _ in range(N):
    board.append(list(map(int, list(input())[:-1])))

q = deque()
q.append([0,0])
dist = [[0] * M for _ in range(N)]
dist[0][0] = 1
while q:
    node = q.popleft()
    if node == [N-1, M-1]:
        break
    for next in [[node[0]-1, node[1]],[node[0], node[1]-1],[node[0]+1, node[1]],[node[0], node[1]+1]]:
        if next[0] >= N or next[0] < 0:
            continue
        if next[1] >= M or next[1] < 0:
            continue
        if not board[next[0]][next[1]]:
            continue
        if dist[next[0]][next[1]]:
            continue
        q.append(next)
        dist[next[0]][next[1]] = dist[node[0]][node[1]] + 1
print(dist[N-1][M-1])


import json
from types import MappingProxyType

import discord
from discord.ext import commands

# Here's a link to the original source https://gist.github.com/StudioMFTechnologies/ad41bfd32b2379ccffe90b0e34128b8b. This has been eddited

class Help(commands.Cog, name="Help"):
    """The help command!"""

    def __init__(self, bot):
        self.bot = bot

    @commands.command(pass_context=True)
    async def help(self, ctx, *, command=None):
        """Gets all category and commands of mine."""
        prefix = self.bot.command_prefix  # If you are using a bot with customizable prefixes, change the prefix here.
        try:
            if command is None:
                """Command listing.  What more?"""
                halp = discord.Embed(color=discord.Color.dark_blue())
                halp.set_author(name="All commands", icon_url=self.bot.user.avatar_url)
                mp = MappingProxyType(self.bot.cogs)
                for x in self.bot.cogs:
                    if x.lower() == "help":
                        continue
                    cog_info = mp[x]
                    all_commands = []
                    for y in cog_info.walk_commands():
                        all_commands.append(f"`{y.name}`")
                    halp.add_field(name=x, value=", ".join(all_commands), inline=False)
                halp.set_footer(text=f"To find out more about a command please do: {prefix}help <command name>")
                await ctx.send(embed=halp)
            else:
                """Command listing within a category."""
                found = False
                for x in self.bot.walk_commands():
                    if x.name.lower() == command.lower():
                        params = []
                        paramsDict = list(x.clean_params.items())
                        for i in range(len(x.clean_params)):
                            if str(paramsDict[i][1])[-5:] == "=None":
                                params.append(f"[{str(paramsDict[i][0])}]")
                            else:
                                params.append(f"<{str(paramsDict[i][0])}>")
                        aliases = []
                        for alias in x.aliases:
                            aliases.append(f"`{alias}`")
                        halp = discord.Embed(color=discord.Color.dark_blue())
                        halp.set_author(name=f"{prefix}{x.name} info", icon_url=self.bot.user.avatar_url)
                        halp.add_field(name="Description:", value=x.help, inline=False)
                        halp.add_field(name="Usage:", value=f"`{prefix}{x.name} {' '.join(params)}`", inline=False)
                        if aliases:
                            halp.add_field(name="Aliases", value=', '.join(aliases), inline=False)
                        await ctx.send(embed=halp)
                        return
                if not found:
                    """Reminds you if that category doesn't exist."""
                    halp = discord.Embed(title='Error!', description=f'Command `{command}` was not found.',
                                         color=discord.Color.red())
                    await ctx.send(embed=halp)
                else:
                    # await ctx.message.add_reaction(emoji='✔')
                    pass
        except ValueError:
            await ctx.send("Excuse me, I can't send embeds.")

def setup(bot):
    bot.add_cog(Help(bot))


#
#
# File: eto.py
#
#

from eto_py3.wunderground_personal_weather_station_py3 import Wunder_Personal
from eto_py3.messo_handlers_py3 import Messo_ETO
from eto_py3.messo_handlers_py3 import Messo_Precp
from eto_py3.cimis_spatial_py3 import CIMIS_SPATIAL
from eto_py3.cimis_handlers_py3 import CIMIS_ETO
from eto_py3.eto_init_py3 import Initialize_ETO_Accumulation_Table
from redis_support_py3.construct_data_handlers_py3 import Generate_Handlers

ONE_DAY = 24 * 3600

class Eto_Management(object):
    def __init__(self,  eto_sources, package,site_data,qs,initial_accumulation_tables ):

        self.eto_sources = eto_sources
        self.package  = package
        self.site_data = site_data
        self.qs = qs

        self.generate_redis_handlers()
        self.eto_hash_table =  self.ds_handlers["ETO_ACCUMULATION_TABLE"]
        self.initialize_values()
        self.generate_calculators()
        initial_accumulation_tables.initialize_eto_tables(self.eto_hash_table)

    def generate_redis_handlers(self):
        self.handlers = {}
        data_structures = self.package["data_structures"]
        generate_handlers = Generate_Handlers(self.package,self.qs)
        self.ds_handlers = {}
        self.ds_handlers["EXCEPTION_VALUES"] = generate_handlers.construct_hash(data_structures["EXCEPTION_VALUES"])
        self.ds_handlers["ETO_VALUES"] = generate_handlers.construct_hash(data_structures["ETO_VALUES"])
        self.ds_handlers["RAIN_VALUES"] = generate_handlers.construct_hash(data_structures["RAIN_VALUES"])
        self.ds_handlers["ETO_CONTROL"] = generate_handlers.construct_hash(data_structures["ETO_CONTROL"])
        self.ds_handlers["ETO_HISTORY"] = generate_handlers.construct_stream_writer(data_structures["ETO_HISTORY"])
        self.ds_handlers["RAIN_HISTORY"] = generate_handlers.construct_stream_writer(data_structures["RAIN_HISTORY"] )
        self.ds_handlers["EXCEPTION_LOG"] = generate_handlers.construct_stream_writer(data_structures["EXCEPTION_LOG"] )
        self.ds_handlers["ETO_ACCUMULATION_TABLE"] = generate_handlers.construct_hash(data_structures["ETO_ACCUMULATION_TABLE"])

    def initialize_values(self):
         if self.ds_handlers["ETO_CONTROL"].hget("ETO_UPDATE_FLAG") == None:
             self.ds_handlers["ETO_CONTROL"].hset("ETO_UPDATE_FLAG",0)
         if self.ds_handlers["ETO_CONTROL"].hget("ETO_LOG_FLAG") == None:
             self.ds_handlers["ETO_CONTROL"].hset("ETO_LOG_FLAG",0)

    def generate_calculators(self):
        for data in self.eto_sources:
            print(data["type"])
            if data["type"] == "WUNDERGROUND":
               data["calculator"] = Wunder_Personal(data,self.ds_handlers["ETO_VALUES"],self.ds_handlers["RAIN_VALUES"])
               continue
            if data["type"] == "CIMIS_SAT":
               data["calculator"] = CIMIS_SPATIAL(data, self.ds_handlers["ETO_VALUES"],self.ds_handlers["RAIN_VALUES"])
               continue
            if data["type"] == "CIMIS":
               data["calculator"] = CIMIS_ETO(data,self.ds_handlers["ETO_VALUES"],self.ds_handlers["RAIN_VALUES"])
               continue
            if data["type"] == "MESSO_ETO":
               data["calculator"] = Messo_ETO(data,self.ds_handlers["ETO_VALUES"],self.ds_handlers["RAIN_VALUES"])
               continue
            if data["type"] == "MESSO_RAIN":
               data["calculator"] = Messo_Precp(data,self.ds_handlers["ETO_VALUES"],self.ds_handlers["RAIN_VALUES"])
               continue
            assert 0,"data type is not recognized "+data["type"]

    def new_day_rollover( self, *parameters ):

         self.ds_handlers["EXCEPTION_VALUES"].delete_all()

         self.ds_handlers["ETO_VALUES"].delete_all()
         self.ds_handlers["RAIN_VALUES"].delete_all()

         self.ds_handlers["ETO_CONTROL"].hset("ETO_UPDATE_FLAG",0)
         self.ds_handlers["ETO_CONTROL"].hset("ETO_LOG_FLAG",0)
         return "DISABLE"

    def make_measurement(self, *parameters):

        for source in self.eto_sources:
            print("source",source)
            if "calculator" in source:
                try:
                    source["calculator"].compute_previous_day()
                except Exception as tst:

                    print("exception",source["name"],tst)
                    self.ds_handlers["EXCEPTION_VALUES"].hset(source["name"],str(tst))
        print("calculator done")

    def update_eto_bins(self, *parameters):
        print(int(self.ds_handlers["ETO_CONTROL"].hget("ETO_UPDATE_FLAG")))
        if int(self.ds_handlers["ETO_CONTROL"].hget("ETO_UPDATE_FLAG")) == 1:
            return True
        self.ds_handlers["ETO_CONTROL"].hset("ETO_UPDATE_FLAG",1)
        # find eto with lowest priority
        eto = self.find_eto()
        if eto ==  None:
           return False
        self.reference_eto = eto
        rain = self.find_rain()
        self.reference_rain = self.find_rain()

        for i in self.eto_hash_table.hkeys():

           new_value = float(self.eto_hash_table.hget(i)) + float(eto)
           print("eto_update",i,new_value)
           self.eto_hash_table.hset(i,new_value)
        print("logging sprinkler_data")
        self.log_sprinkler_data()
        return True

    def log_sprinkler_data(self,*parameters):
       if int(self.ds_handlers["ETO_CONTROL"].hget("ETO_LOG_FLAG")) == 1:
            return
       eto_data = self.assemble_data("eto",self.ds_handlers["ETO_VALUES"])
       if len(eto_data.keys()) == 0:
          return

       self.ds_handlers["ETO_CONTROL"].hset("ETO_LOG_FLAG",1)

       print("logging eto data")
       self.ds_handlers["ETO_HISTORY"].push(data = eto_data)
       rain_data = self.assemble_data("rain",self.ds_handlers["RAIN_VALUES"])
       if len(rain_data.keys()) > 0:
           print("loging rain data")
           self.ds_handlers["RAIN_HISTORY"].push(data = rain_data)
       exception_data = self.ds_handlers["EXCEPTION_VALUES"].hgetall()
       print("exception data",exception_data)
       if len(eto_data.keys()) > 0:
            self.ds_handlers["EXCEPTION_LOG"].push(data=exception_data)

    def find_eto(self):
       eto_data = self.ds_handlers["ETO_VALUES"].hgetall()

       ref_priority = 1000000 # large starting number
       eto_value = None
       for i ,data in eto_data.items():
           print("################## i data @@@@@@@@@@@@@@@@@@@@@",i,data)
           if data["priority"] < ref_priority:
               ref_priority = int(data["priority"])
               eto_value = float(data["eto"])

       return eto_value

    def find_rain(self):
       rain_data = self.ds_handlers["RAIN_VALUES"].hgetall()

       ref_priority = 1000000 # large starting number
       for i ,data in rain_data.items():

           if data["priority"] < ref_priority:
               ref_priority = int(data["priority"])
               rain_data = float(data["rain"])

       return rain_data

    def assemble_data(self,field_key,hash_handler):
       data = hash_handler.hgetall()
       return_value = {}
       for key , item in data.items():

          return_value[key] = item[field_key]
       return return_value

def replace_keys( redis_site_data,elements ):
   redis_handle = redis.StrictRedis(redis_site["host"], redis_site["port"], db=redis_site["redis_password_db"], decode_responses=True)
   for i in elements:

       temp = i["access_key"]
       api_key = redis_handle.hget("eto",temp)

       i["access_key"] = api_key

def construct_eto_instance(qs, site_data ):

    #
    #
    # find nodes associated with WEATHER_STATIONS
    #
    #

    #
    #  Find "WS_STATION" nodes
    #
    #
    query_list = []
    query_list = qs.add_match_relationship( query_list,relationship="SITE",label=site_data["site"] )
    query_list = qs.add_match_terminal( query_list,
                                        relationship = "WS_STATION" )

    eto_sets, eto_sources = qs.match_list(query_list)

    query_list = []
    query_list = qs.add_match_relationship( query_list,relationship="SITE",label=site_data["site"] )

    query_list = qs.add_match_terminal( query_list,
                                        relationship = "PACKAGE", property_mask={"name":"WEATHER_STATION_DATA"} )

    package_sets, package_sources = qs.match_list(query_list)

    #
    # Replace symbolic keys with actual api keys
    #
    replace_keys(site_data, eto_sources)

    initial_accumulation_tables = Initialize_ETO_Accumulation_Table(qs,site_data)

    eto = Eto_Management(eto_sources, package_sources[0],site_data,qs,initial_accumulation_tables )

    return eto

def add_eto_chains(eto, cf):

    cf.define_chain("test_generator",False)
    cf.insert.log("send Day Tick")
    cf.insert.send_event("DAY_TICK")
    cf.insert.terminate()

    cf.insert.wait_tod_le( hour =  1 )
    cf.insert.send_event("DAY_TICK")
    cf.insert.wait_tod_ge( hour =  2 )
    cf.insert.reset()

    cf.define_chain("eto_time_window", True)
    cf.insert.log("Waiting for day tick")
    cf.insert.wait_event_count( event = "DAY_TICK" )
    cf.insert.log("Got Day Tick")
    cf.insert.one_step(eto.new_day_rollover)
    cf.insert.reset()

    cf.define_chain("enable_measurement", True)
    cf.insert.log("starting enable_measurement")
    cf.insert.wait_tod_ge( hour =  8 )
    cf.insert.enable_chains(["eto_make_measurements"])
    cf.insert.log("enabling making_measurement")
    cf.insert.wait_tod_ge(hour=11)
    cf.insert.enable_chains(["update_eto_bins"])
    cf.insert.log("enable_update_eto_bins")

    cf.insert.wait_tod_ge( hour =  23 )
    cf.insert.disable_chains(["eto_make_measurements","update_eto_bins"])

    cf.insert.wait_event_count( event = "DAY_TICK" )
    cf.insert.reset()

    cf.define_chain("update_eto_bins", False)
    cf.insert.wait_event_count( event = "MINUTE_TICK",count = 8)
    cf.insert.log("updating eto bins")
    cf.insert.wait_function( eto.update_eto_bins )
    cf.insert.disable_chains(["eto_make_measurements"])
    cf.insert.terminate()

    cf.define_chain("eto_make_measurements", False)
    cf.insert.log("starting make measurement")

    cf.insert.one_step( eto.make_measurement )

    cf.insert.wait_event_count( event = "MINUTE_TICK",count = 1)
    cf.insert.log("Receiving minute tick")

    cf.insert.reset()

if __name__ == "__main__":

    import datetime
    import time
    import string
    import urllib.request
    import math
    import redis
    import base64
    import json

    import os
    import copy
    #import load_files_py3
    from redis_support_py3.graph_query_support_py3 import  Query_Support
    import datetime

    from py_cf_new_py3.chain_flow_py3 import CF_Base_Interpreter

    #
    #
    # Read Boot File
    # expand json file
    #
    file_handle = open("system_data_files/redis_server.json",'r')
    data = file_handle.read()
    file_handle.close()
    redis_site = json.loads(data)

    #
    # Setup handle
    # open data stores instance

    qs = Query_Support( redis_site )

    eto = construct_eto_instance( qs, redis_site)

    #
    # Adding chains
    #

    cf = CF_Base_Interpreter()
    add_eto_chains(eto, cf)
    #
    # Executing chains
    #

    cf.execute()

else:
  pass


"""
Metrics

Built-in metrics:

- MSE, MeanSquaredError
- RMSE, RootMeanSquaredError
- R2, RSquared
"""

from __future__ import annotations

import logging
from functools import partial
from inspect import isclass
from typing import Callable, Optional

import ax.utils.measurement.synthetic_functions
import botorch.test_functions.synthetic
import numpy as np
import pandas as pd
import sklearn.metrics
from ax import Metric
from ax.core.base_trial import BaseTrial
from ax.core.data import Data
from ax.core.types import TParameterization
from ax.metrics.noisy_function import NoisyFunctionMetric
from ax.utils.measurement.synthetic_functions import FromBotorch, from_botorch

import boa.metrics.synthethic_funcs
from boa.metaclasses import MetricRegister, MetricToEvalRegister
from boa.metrics.metric_funcs import metric_from_json, metric_from_yaml
from boa.metrics.metric_funcs import (
    normalized_root_mean_squared_error as normalized_root_mean_squared_error_,
    regress_slope as regress_slope_,
)
from boa.utils import get_dictionary_from_callable, serialize_init_args
from boa.wrapper import BaseWrapper

logger = logging.getLogger(__name__)

def get_metric_from_config(config, instantiate=True, **kwargs):
    if config.get("metric"):
        config = config["metric"]
    if config.get("boa_metric"):
        kwargs["metric_name"] = config["boa_metric"]
        metric = get_metric_by_class_name(instantiate=instantiate, **config, **kwargs)
    elif config.get("sklearn_metric"):
        kwargs["metric_name"] = config["sklearn_metric"]
        kwargs["sklearn_"] = True
        metric = get_metric_by_class_name(instantiate=instantiate, **config, **kwargs)
    elif config.get("synthetic_metric"):
        metric = setup_synthetic_metric(instantiate=instantiate, **config, **kwargs)
    else:
        # TODO link to docs for configuration when it exists
        raise KeyError("No valid configuration for metric found.")
    return metric

def get_metric_by_class_name(metric_name, instantiate=True, sklearn_=False, **kwargs):
    if sklearn_:
        return setup_sklearn_metric(metric_name, instantiate=True, **kwargs)
    return globals()[metric_name](**kwargs) if instantiate else globals()[metric_name]

def get_sklearn_func(metric_to_eval):
    if metric_to_eval in sklearn.metrics.__all__:
        metric = getattr(sklearn.metrics, metric_to_eval)
    else:
        raise AttributeError(f"Sklearn metric: {metric_to_eval} not found!")
    return metric

def setup_sklearn_metric(metric_to_eval, instantiate=True, **kw):
    metric = get_sklearn_func(metric_to_eval)

    def modular_sklearn_metric(**kwargs):
        return ModularMetric(**{**kw, **kwargs, "metric_to_eval": metric})

    return modular_sklearn_metric(**kw) if instantiate else modular_sklearn_metric

def get_synth_func(synthetic_metric):
    synthetic_funcs_modules = [
        boa.metrics.synthethic_funcs,
        ax.utils.measurement.synthetic_functions,
        botorch.test_functions.synthetic,
    ]
    for module in synthetic_funcs_modules:
        try:
            return getattr(module, synthetic_metric)
        except AttributeError:
            continue
    # If we don't find the class by the end of the modules, raise attribute error
    raise AttributeError(
        f"boa synthetic function: {synthetic_metric}"
        f" not found in modules: {synthetic_funcs_modules}!"
    )

def setup_synthetic_metric(synthetic_metric, instantiate=True, **kw):
    metric = get_synth_func(synthetic_metric)

    if isclass(metric) and issubclass(metric, ax.utils.measurement.synthetic_functions):
        metric = metric()  # if they pass a ax synthetic metric class, not instance
    elif isclass(metric) and issubclass(
        metric, botorch.test_functions.synthetic.SyntheticTestFunction
    ):
        # botorch synthetic functions need to be converted
        metric = from_botorch(botorch_synthetic_function=metric())

    def modular_synthetic_metric(**kwargs):
        return ModularMetric(**{**kw, **kwargs, "metric_to_eval": metric})

    return modular_synthetic_metric(**kw) if instantiate else modular_synthetic_metric

def _get_name(obj):
    if hasattr(obj, "__name__"):
        return obj.__name__
    elif isinstance(obj, FromBotorch):
        # Using metrics that are FromBotorch(botorch synthetic_funcs) leaves us
        # with having to rely on a private attribute to get to the funcs __name__
        # watch for breaking someday
        obj = obj._botorch_function
    elif isinstance(obj, partial):
        obj = obj.func
    else:
        obj = obj.__class__
    return _get_name(obj)

class MetricToEval(metaclass=MetricToEvalRegister):
    def __init__(
        self, *, func: Callable | str, func_kwargs: Optional[dict] = None, type_: str = None
    ):
        if isinstance(func, str):
            func = self.func_from_str(func, type_)
        self.func = func
        self.func_kwargs = func_kwargs or {}
        self.name = _get_name(func)
        self.type_ = type_

    def __call__(self, *args, **kwargs):
        return self.func(
            *args, **get_dictionary_from_callable(self.func, {**self.func_kwargs, **kwargs})
        )

    def to_dict(self):
        return {
            "__type": self.__class__.__name__,
            "func": self.name,
            "func_kwargs": self.func_kwargs,
            "type_": self.type_,
        }

    @classmethod
    def func_from_str(cls, name: str, type_: str = None):
        if type_ == "sklearn_metric":
            func = get_sklearn_func(name)
        elif type_ == "synthetic_metric":
            func = get_synth_func(name)
        elif type_ == "boa_metric" or type_ is None:
            func = globals()[name]
            try:
                func = func()
            except Exception as e:
                logger.debug(
                    "func: %s not callable because of: %r", getattr(func, "__name__", func), e
                )
            if isinstance(func, ModularMetric):
                func = func.metric_to_eval.func
            elif isinstance(func, MetricToEval):
                func = func.func
            # else func is just func
        else:
            raise ValueError(f"{cls.__name__} type_: {type_} invalid!")
        return func

class ModularMetric(NoisyFunctionMetric, metaclass=MetricRegister):
    def __init__(
        self,
        metric_to_eval: Callable,
        param_names: list[str] = None,
        noise_sd: Optional[float] = 0.0,
        metric_func_kwargs: Optional[dict] = None,
        wrapper: Optional[BaseWrapper] = None,
        properties: Optional[dict[str]] = None,
        type_: Optional[str] = None,
        **kwargs,
    ):

        if kwargs.get("name") is None:
            kwargs["name"] = _get_name(metric_to_eval)
        param_names = param_names if param_names is not None else []
        self.metric_func_kwargs = metric_func_kwargs or {}
        self.metric_to_eval = MetricToEval(
            func=metric_to_eval, func_kwargs=metric_func_kwargs, type_=type_
        )
        self.wrapper = wrapper or BaseWrapper()
        super().__init__(
            param_names=param_names,
            noise_sd=noise_sd,
            **get_dictionary_from_callable(NoisyFunctionMetric.__init__, kwargs),
        )
        self.properties = properties or {}

    @classmethod
    def is_available_while_running(cls) -> bool:
        return False

    def fetch_trial_data(self, trial: BaseTrial, *args, **kwargs):
        wrapper_kwargs = (
            self.wrapper.fetch_trial_data(
                trial=trial,
                metric_properties=self.properties,
                metric_name=self.name,
                *args,
                **kwargs,
            )
            if self.wrapper
            else {}
        )
        wrapper_kwargs = wrapper_kwargs or {}
        safe_kwargs = {"trial": trial, **kwargs, **wrapper_kwargs}
        if isinstance(self.metric_to_eval.func, Metric):
            return self.metric_to_eval.func.fetch_trial_data(
                *args,
                **get_dictionary_from_callable(
                    self.metric_to_eval.func.fetch_trial_data, safe_kwargs
                ),
            )
        else:
            return self._fetch_trial_data_of_func(*args, **safe_kwargs)

    def _fetch_trial_data_of_func(self, trial: BaseTrial, noisy: bool = True, **kwargs) -> Data:
        noise_sd = self.noise_sd if noisy else 0.0
        arm_names = []
        mean = []
        for name, arm in trial.arms_by_name.items():
            arm_names.append(name)
            val = self._evaluate(params=arm.parameters, **kwargs)
            if noise_sd:
                val = val + noise_sd * np.random.randn()
            mean.append(val)
        # indicate unknown noise level in data
        if noise_sd is None:
            noise_sd = float("nan")
        df = pd.DataFrame(
            {
                "arm_name": arm_names,
                "metric_name": self.name,
                "mean": mean,
                "sem": noise_sd,
                "trial_index": trial.index,
            }
        )
        return Data(df=df)

    def _evaluate(self, params: TParameterization, **kwargs) -> float:
        kwargs["x"] = np.array([params[p] for p in self.param_names if p in params])
        return self.f(**get_dictionary_from_callable(self.metric_to_eval, kwargs))

    def f(self, *args, **kwargs):
        return self.metric_to_eval(*args, **kwargs)

    def clone(self) -> "Metric":
        """Create a copy of this Metric."""
        cls = type(self)
        return cls(
            **serialize_init_args(self, parents=[NoisyFunctionMetric], match_private=True),
        )

    def to_dict(self) -> dict:
        """Convert Ax experiment to a dictionary."""
        parents = self.__class__.mro()[1:]  # index 0 is the class itself

        # We don't want to match init args for Metric class and back, because
        # NoisyFunctionMetric changes the init parameters22
        try:
            index_of_metric = parents.index(Metric)
        except ValueError:
            index_of_metric = None
        p_b4_metric = parents[:index_of_metric]

        wrapper_state = serialize_init_args(
            self, parents=p_b4_metric, match_private=True, exclude_fields=["wrapper"]
        )

        # wrapper_state = convert_type(wrapper_state, {Path: str})
        return {"__type": self.__class__.__name__, **wrapper_state}

    def __repr__(self) -> str:
        init_dict = serialize_init_args(self, parents=[NoisyFunctionMetric], match_private=True)
        init_dict = {k: v for k, v in init_dict.items() if v}

        if isinstance(init_dict["metric_to_eval"], partial):
            init_dict["metric_to_eval"] = init_dict["metric_to_eval"].func

        arg_str = " ".join(f"{k}={v}" for k, v in init_dict.items())
        return f"{self.__class__.__name__}({arg_str})"

MSE = setup_sklearn_metric("mean_squared_error", lower_is_better=True, instantiate=False)
MeanSquaredError = MSE
mean_squared_error = MSE

RMSE = setup_sklearn_metric(
    "mean_squared_error",
    name="root_mean_squared_error",
    lower_is_better=True,
    metric_func_kwargs={"squared": False},
    instantiate=False,
)
RootMeanSquaredError = RMSE
root_mean_squared_error = RMSE

R2 = setup_sklearn_metric("r2_score", instantiate=False)
RSquared = R2
Mean = partial(ModularMetric, metric_to_eval=np.mean, lower_is_better=True)

MetricFromJSON = partial(ModularMetric, metric_to_eval=metric_from_json)
MetricFromYAML = partial(ModularMetric, metric_to_eval=metric_from_yaml)

NRMSE = partial(
    ModularMetric, metric_to_eval=normalized_root_mean_squared_error_, lower_is_better=True
)
NormalizedRootMeanSquaredError = NRMSE
normalized_root_mean_squared_error = NRMSE

RegSlp = partial(
    ModularMetric, metric_to_eval=regress_slope_, lower_is_better=True
)
LinearRegressionSlope = RegSlp
regress_slope = RegSlp


import re

# pySMART module imports
from .device import Device
from .smartctl import Smartctl, SMARTCTL
from typing import List

class DeviceList(object):
    """
    Represents a list of all the storage devices connected to this computer.
    """

    def __init__(self, init: bool = True, smartctl=SMARTCTL, catch_errors: bool = False):
        """Instantiates and optionally initializes the `DeviceList`.

        Args:
            init (bool, optional): By default, `pySMART.device_list.DeviceList.devices`
                is populated with `Device` objects during instantiation. Setting init
                to False will skip initialization and create an empty
                `pySMART.device_list.DeviceList` object instead. Defaults to True.
            smartctl ([type], optional): This stablish the smartctl wrapper.
                Defaults the global `SMARTCTL` object and should be only
                overwritten on tests.
            catch_errors (bool, optional): If True, individual device-parsing errors will be caught
        """

        self.devices: List[Device] = []
        """
        **(list of `Device`):** Contains all storage devices detected during
        instantiation, as `Device` objects.
        """
        self.smartctl: Smartctl = smartctl
        """The smartctl wrapper
        """
        if init:
            self.initialize(catch_errors)

    def __repr__(self):
        """Define a basic representation of the class object."""
        rep = "<DeviceList contents:\n"
        for device in self.devices:
            rep += str(device) + '\n'
        return rep + '>'
        # return "<DeviceList contents:%r>" % (self.devices)

    def _cleanup(self):
        """
        Removes duplicate ATA devices that correspond to an existing CSMI
        device. Also removes any device with no capacity value, as this
        indicates removable storage, ie: CD/DVD-ROM, ZIP, etc.
        """
        # We can't operate directly on the list while we're iterating
        # over it, so we collect indeces to delete and remove them later
        to_delete = []
        # Enumerate the list to get tuples containing indeces and values
        for index, device in enumerate(self.devices):
            if device.interface == 'csmi':
                for otherindex, otherdevice in enumerate(self.devices):
                    if (otherdevice.interface == 'ata' or
                            otherdevice.interface == 'sata'):
                        if device.serial == otherdevice.serial:
                            to_delete.append(otherindex)
                            device._sd_name = otherdevice.name
            if device.capacity is None and index not in to_delete:
                to_delete.append(index)
        # Recreate the self.devices list without the marked indeces
        self.devices[:] = [v for i, v in enumerate(self.devices)
                           if i not in to_delete]

    def initialize(self, catch_errors: bool = False):
        """
        Scans system busses for attached devices and add them to the
        `DeviceList` as `Device` objects.
        If device list is already populated, it will be cleared first.

        Args:
            catch_errors (bool, optional): If True, individual device-parsing errors will be caught
        """

        # Clear the list if it's already populated
        if len(self.devices):
            self.devices = []

        # Scan for devices
        for line in self.smartctl.scan():
            if not ('failed:' in line or line == ''):
                groups = re.compile(
                    r'^(\S+)\s+-d\s+(\S+)').match(line).groups()
                name = groups[0]
                interface = groups[1]

                try:
                    # Add the device to the list
                    self.devices.append(
                        Device(name, interface=interface, smartctl=self.smartctl))

                except Exception as e:
                    if catch_errors:
                        # Print the exception
                        import logging

                        logging.exception(f"Error parsing device {name}")

                    else:
                        # Reraise the exception
                        raise e

        # Remove duplicates and unwanted devices (optical, etc.) from the list
        self._cleanup()
        # Sort the list alphabetically by device name
        self.devices.sort(key=lambda device: device.name)

    def __getitem__(self, index: int) -> Device:
        """Returns an element from self.devices

        Args:
            index (int): An index of self.devices

        Returns:
            Device: Returns a Device that is located on the asked index
        """
        return self.devices[index]

__all__ = ['DeviceList']


import netCDF4
import matplotlib.pyplot as plt
from scipy.signal import welch
import numpy as np

d = netCDF4.Dataset('vibration_5_2V.nc')

for bolos in d.variables:
    if '0136.1.1' in bolos:
        plt.figure()
        ff, psd = welch(d[bolos][5000:], fs=152.5, nperseg=256)
        asd = np.sqrt(psd)
        plt.semilogy(ff, asd)
        plt.savefig('bolo_figures/{}_psd.png'.format(bolos))
        plt.close()

        plt.figure()
        plt.plot(d[bolos][5000:])
        plt.savefig('bolo_figures/{}_tod.png'.format(bolos))
        plt.close()


from yt_to_audio import yt_to_audio,trim_audio
from speech_to_text import audio_to_txt
from text_analysis import txt_sentiment,sentiment_analysis,df_sentiment
import pandas as pd
# Download a youtube video and extract the audio file
url = 'https://www.youtube.com/watch?v=yYUIt6FtIB4' #Fed Chair Powell speaks at The Brookings Institute on economic outlook — 11/30/22

#yt_to_audio(url)

file_name = 'audio.mp3'
minutes_start = 2
minutes_end = 17.1
out_put_file_name ='trimed_audio.mp3'
# trim audio file
#trim_audio(file_name,out_put_file_name,minutes_start=minutes_start,minutes_end=minutes_end)

# Get the text of the audio file
output = audio_to_txt(out_put_file_name)
output_text = output['text']
segments = output['segments']
df = pd.DataFrame(segments)
df = df[['start','end','text']]

## Checkpoint
# Open the file for writing
# with open('output_text.txt', 'w') as file:
#     # Write the string to the file
#     file.write(output_text)

# # Load txt file into the variable
# output_text = open("output_text.txt", "r")
# output_text = output_text.read()

# Perform text sentiment analysis
sentiments = txt_sentiment(output_text)
df = df_sentiment(df)
df.to_csv('sentiment.csv')
sentiment_analysis(list(df['sentiment']))
#sentiment_analysis(sentiments)

import matplotlib.pyplot as plt
plt.xlabel('Sentences')
plt.show()


import tkinter as tk
from tkinter import filedialog
from tkinter import messagebox
from tkinter import ttk
from tkinterdnd2 import DND_FILES, TkinterDnD

def remove_duplicates():
    file_path = file_path_var.get()
    if file_path == "":
        messagebox.showwarning("Предупреждение", "Выберите файл")
        return

    with open(file_path, 'r') as file:
        trackers = file.readlines()

    unique_trackers = []
    for tracker in trackers:
        trimmed_tracker = tracker.strip()
        if remove_checkbox_var.get():
            unique_trackers.append(trimmed_tracker)
            if trimmed_tracker:
                unique_trackers.append('')
        elif trimmed_tracker and trimmed_tracker not in unique_trackers:
            unique_trackers.append(trimmed_tracker)

    num_duplicates = len(trackers) - len(unique_trackers)

    with open(file_path, 'w') as file:
        file.writelines([tracker + '\n' for tracker in unique_trackers])

    messagebox.showinfo("Готово", f"Удалено: {num_duplicates} дубликатов")

def browse_file():
    file_path = filedialog.askopenfilename(filetypes=[("Text Files", "*.txt")])
    file_path_var.set(file_path)

def on_drop(event):
    file_path = event.data
    file_path_var.set(file_path)

# Создание главного окна с поддержкой перетаскивания файлов
root = TkinterDnD.Tk()
root.title("Удаление дубликатов трекеров")
root.geometry('300x250')

# Установка стилей для элементов
style = ttk.Style()
style.configure("TButton",
                font=("Arial", 12),
                foreground="black",  # Черный цвет текста
                background="#4CAF50",
                padding=10)
style.configure("TLabel",
                font=("Arial", 14),
                foreground="black",
                background="#F0F0F0")
style.configure("TEntry",
                font=("Arial", 12),
                foreground="black",
                background="white",
                padding=5)

# Переменные для хранения пути к файлу и состояния Checkbox
file_path_var = tk.StringVar()
remove_checkbox_var = tk.BooleanVar()

# Создание метки и поле для отображения пути к файлу
file_label = ttk.Label(root, text="Выберите файл:")
file_label.pack(pady=10)

file_entry = ttk.Entry(root, textvariable=file_path_var, width=40)
file_entry.pack(pady=5)

# Привязка события перетаскивания к полю ввода
file_entry.drop_target_register(DND_FILES)
file_entry.dnd_bind('<<Drop>>', on_drop)

# Создание кнопки для выбора файла
browse_button = ttk.Button(root, text="Обзор", command=browse_file, style="TButton")
browse_button.pack(pady=5)

# Создание Checkbox для включения/отключения функции удаления дубликатов
remove_checkbox = ttk.Checkbutton(root, text="Разделять строки пустотой", variable=remove_checkbox_var)
remove_checkbox.pack(pady=5)

# Создание кнопки "Удалить дубликаты"
remove_duplicates_button = ttk.Button(root, text="Удалить дубликаты", command=remove_duplicates, style="TButton")
remove_duplicates_button.pack(pady=10)

# Запуск главного цикла
root.mainloop()


from fastapi import FastAPI, WebSocket
import websockets
from typing import List

app = FastAPI()

@app.get("/")
async def root():
    return {"message": "Hello World"}

@app.get("/hello/{name}")
async def say_hello(name: str):
    return {"message": f"Hello {name}"}

# 웹소켓용 인스턴스, 하나씩 만들어도 되지만 이렇게 하는 이유는, 채팅방이 다수 필요할 때 사용하기 위함
class WSCon:
    def __init__(self):
        self.connections: List[WebSocket] = []

    async def connect(self, websocket: WebSocket):
        await websocket.accept()
        self.connections.append(websocket)
        await websocket.send_text(f'{websocket.client}')

    async def receive(self, data):
        for connection in self.connections:
            await connection.send_text(data)

ws = WSCon()

# ws서버 생성용 코드
@app.websocket("/")
async def wss(websocket: WebSocket):
    await ws.connect(websocket)

    while True:
        data = await websocket.receive_text()
        await ws.receive(f'{data}')


from json import load
import tensorflow as tf
import numpy as np
import cv2 as cv
from keras.models import load_model
import argparse
import matplotlib.pyplot as plt
from tensorflow.python.keras.utils.generic_utils import default
import imutils
from tensorflow.keras.preprocessing.image import img_to_array

parser = argparse.ArgumentParser()
# parser.add_argument('-c', '--cascade', help= 'Path to cascade', default= 'data/haarcascades/haarcascade_frontalface_alt.xml')
parser.add_argument('-m', '--model', help= 'Path to pre-trained gender detector',default= 'TrainedModels_Serialized\gender_classifier_celeba.h5' )
parser.add_argument('-v', '--video', help= 'Path to video file(optional)')
args = vars(parser.parse_args())

model = load_model(args['model'])
face_cascade = cv.CascadeClassifier(cv.data.haarcascades + 'haarcascade_frontalface_default.xml')

if not args.get('video', False):
    camera = cv.VideoCapture(0)

else:
    camera = cv.VideoCapture(args['video'])

if not camera.isOpened():
    print("Cannot open camera")
    exit()

while True:

    (ret, frame) = camera.read()

    if args.get('video') and not ret:
        break

    frame = imutils.resize(frame, width= 300)
    frameClone = frame.copy()

    rects = face_cascade.detectMultiScale(frame, scaleFactor= 1.1, minNeighbors= 5, minSize= (30, 30), flags= cv.CASCADE_SCALE_IMAGE)

    for(fx, fy, fw, fh) in rects:

        roi = frame[fy - 20: fy + fh , fx - 20: fx + fw]
        roi= cv.resize(frame, (64, 64))
        roi = roi.astype('float')/255.0
        roi = img_to_array(roi)
        roi = np.expand_dims(roi, axis=0)

        pred_logits = model.predict(roi)
        male = tf.sigmoid(pred_logits)
        label = 'Male' if male>0.5 else 'Female'

        cv.putText(frameClone, label, (fx, fy - 10), cv.FONT_HERSHEY_SIMPLEX, 0.45, (0, 255, 0), 2)
        cv.rectangle(frameClone, (fx , fy), (fx + fw, fy + fh), (0, 255, 0), 2)
        cv.imshow('Face', frameClone)

        if(cv.waitKey(1) & 0xFF == ord('q')):
            break

camera.release()
cv.distroyAllWindows()


'''
K-Folding script
author: obanmarcos
'''
import os
import os, sys
from config import *

sys.path.append(where_am_i())

import pytorch_lightning as pl
import argparse
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from utilities import dataloading_utilities as dlutils
from utilities.folders import *

from training import train_utilities as trutils

from models.models_system import MoDLReconstructor
import torch

from pytorch_lightning.callbacks import ModelCheckpoint
from pytorch_lightning.loggers import WandbLogger

from torchvision import transforms as T
from pytorch_msssim import SSIM
# from torchmetrics import StructuralSimilarityIndexMeasure as SSIM
from torchmetrics import MultiScaleStructuralSimilarityIndexMeasure as MSSSIM

# Options for folding menu
use_default_model_dict = True
use_default_dataloader_dict = True
use_default_trainer_dict = True

profiler = None

def runs(testing_options):
# Model dictionary
    if use_default_model_dict == True:
        #U-Net model
        unet_dict = {'n_channels': 1,
                     'n_classes':1,
                     'bilinear': True,
                     'batch_norm': True,
                     'batch_norm_inconv':True,
                     'residual':True,
                     'up_conv': False}

        # Training parameters
        loss_dict = {'loss_name': 'psnr',
                    'psnr_loss': torch.nn.MSELoss(reduction = 'mean'),
                    'ssim_loss': SSIM(data_range=1, size_average=True, channel=1),
                    'msssim_loss': MSSSIM(kernel_size = 1)}

        # Optimizer parameters
        optimizer_dict = {'optimizer_name': 'Adam+Tanh',
                        'lr': 1e-4}

        # System parameters
        model_system_dict = {'optimizer_dict': optimizer_dict,
                            'method':'unet',
                            'kw_dictionary_unet': unet_dict,
                            'loss_dict': loss_dict,
                            'track_train': True,
                            'track_val': True,
                            'track_test': True}

    # PL Trainer and W&B logger dictionaries
    if use_default_trainer_dict == True:

        logger_dict = {'project':'deepopt',
                        'entity': 'omarcos',
                        'log_model': True}

        lightning_trainer_dict = {'max_epochs': 40,
                                  'log_every_n_steps': 10,
                                  'check_val_every_n_epoch': 1,
                                  'gradient_clip_val' : 0.5,
                                  'accelerator' : 'gpu',
                                  'devices' : 1,
                                  'fast_dev_run' : False,
                                  'default_root_dir': model_folder}

        trainer_dict = {'lightning_trainer_dict': lightning_trainer_dict,
                        'use_k_folding': True,
                        'track_checkpoints': True,
                        'epoch_number_checkpoint': 10,
                        'use_swa' : False,
                        'use_accumulate_batches': False,
                        'k_fold_number_datasets': 2,
                        'use_logger' : True,
                        'resume':'allow',
                        'logger_dict': logger_dict,
                        'track_default_checkpoints'  : False,
                        'use_auto_lr_find': False,
                        'batch_accumulate_number': 3,
                        'use_mixed_precision': False,
                        'batch_accumulation_start_epoch': 0,
                        'profiler': profiler,
                        'restore_fold': False,
                        'fold_number_restore': 2,
                        'acc_factor_restore': 22}

    # Dataloader dictionary
    if use_default_dataloader_dict == True:

        # data_transform = T.Compose([T.ToTensor()])
        data_transform = None

        dataloader_dict = {'datasets_folder': datasets_folder,
                           'number_volumes' : 0,
                           'experiment_name': 'Bassi',
                           'img_resize': 100,
                           'load_shifts': True,
                           'save_shifts':False,
                           'number_projections_total': 720,
                           'number_projections_undersampled': 720//20,
                           'acceleration_factor':20,
                           'train_factor' : 0.8,
                           'val_factor' : 0.2,
                           'test_factor' : 0.2,
                           'batch_size' : 8,
                           'sampling_method' : 'equispaced-linear',
                           'shuffle_data' : True,
                           'data_transform' : data_transform,
                           'num_workers' : 8}

    # Create Custom trainer
    if 'train_ssim' in testing_options:

        with torch.autograd.set_detect_anomaly(True):

            model_system_dict['loss_dict']['loss_name'] = 'ssim'

            trainer = trutils.TrainerSystem(trainer_dict, dataloader_dict, model_system_dict)
            trainer.k_folding()

    if 'train_psnr' in testing_options:

        model_system_dict['loss_dict']['loss_name'] = 'psnr'

        trainer = trutils.TrainerSystem(trainer_dict, dataloader_dict, model_system_dict)
        trainer.k_folding()

if __name__ == '__main__':

    train_options = []

    parser = argparse.ArgumentParser(description='Do K-folding with different networks')

    parser.add_argument('--train_psnr', help = 'Train w/PSNR loss with optimal hyperparameters', action="store_true")
    parser.add_argument('--train_ssim', help = 'Train w/SSIM loss with optimal hyperparameters', action="store_true")

    args = parser.parse_args()

    if args.train_psnr:

        print('Training UNET with PSNR loss...')
        train_options.append('train_psnr')

    if args.train_ssim:

        print('Training UNET with SSIM loss...')
        train_options.append('train_ssim')

    runs(train_options)


from flask import Flask, request
import json
import threading
import cli_session_mgmt
import vnc_mgmt
import auth_cli
import traceback
import sqlite3
import client_mgmt
import os
import socket

app = Flask(__name__)
client_sys = client_mgmt.ClientManagement()
auth = auth_cli.AuthenticationManagement()
vnc_sys = vnc_mgmt.VNCManagement(auth, client_sys)

class SocketThreadExchange:
    def __init__(self, socket, conn):
        self.socket = socket
        self.conn = conn

@app.route('/add/<string:hostname>')
def add(hostname):
    return client_sys.add_client(hostname, request.remote_addr)

@app.route('/vnc_data')
def vnc_data():
    return json.dumps(vnc_sys.get_vnc_data())

@app.route('/list_clients')
def list_clients():
    clients = json.dumps(client_sys.client_list)
    return clients

@app.route('/auth', methods=['POST'])
def authenticate():
    auth_key = dict(request.form)['auth'].split(':')
    return str(auth.auth(auth_key[0], auth_key[1]))

def manage_cli_session(conn, ste):
    invalid_credentials = True
    run_cli = True
    while invalid_credentials:
        try:
            authentication = conn.recv(1024).decode('utf-8').split(':')
        except ConnectionResetError:
            print('Connection to client lost, closing thread')
        else:
            if not authentication == '':
                if not auth.auth(authentication[0], authentication[1]) == False:
                    conn.send(b'auth')
                    invalid_credentials = False
                else:
                    conn.send(b'noauth')
            else:
                conn.close()
                run_cli = False
    if run_cli:
        session = cli_session_mgmt.CLISessionManagement(authentication[0], authentication[1], vnc_sys, client_sys, ste=ste)
        while True:
            try:
                cmd = conn.recv(1024).decode('utf-8')
                if cmd == 'exit':
                    conn.close()
                    break
                else:
                    try:
                        resp = session.execute(cmd)
                    except:
                        conn.send(b'Error, check logs for more details')
                        traceback.print_exc()
                    else:
                        conn.send(resp.encode())
            except ConnectionResetError:
                print('Connection to client lost, closing thread')
                break

def start_cli_mgmt():
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    s.bind(('0.0.0.0', 4582))
    s.listen()
    while True:
        print('Listening for CLI connections')
        conn, addr = s.accept()
        ste = SocketThreadExchange(s, conn)
        threading.Thread(target=manage_cli_session, args=[conn, ste]).start()

if __name__ == '__main__':
    threading.Thread(target=start_cli_mgmt).start()
    app.run('0.0.0.0', port=4583)


import tensorflow as tf
import os
import helper
from buildCNN import model
from get_images import train_generator, validation_generator, test_generator, batch_size

EPOCHS = 100
num_samples = len(train_generator.classes)
path = helper.path

config = tf.compat.v1.ConfigProto()
config.gpu_options.allow_growth = True
session = tf.compat.v1.InteractiveSession(config=config)

model.summary()
os.makedirs("models", exist_ok=True)

# Create ModelCheckpoint object
checkpointer = tf.keras.callbacks.ModelCheckpoint(monitor='val_accuracy', mode = 'max',
                               filepath=path / r"models\best model2.h5",
                               verbose=1, save_best_only=True)
# Create EarlyStopping object
early_stopping_monitor = tf.keras.callbacks.EarlyStopping(monitor='val_accuracy', patience = 20)
callbacks_list = [checkpointer, early_stopping_monitor]

hist = model.fit(train_generator, epochs=EPOCHS, validation_data=validation_generator, steps_per_epoch=num_samples//batch_size, callbacks = callbacks_list)

score = model.evaluate(test_generator, verbose=1)
print("Model performance on test data: ")
print('Test loss:', score[0])
print('Test accuracy:', score[1])

import matplotlib.pyplot as plt
print("Accuracy Plot: ")
plt.plot(hist.history['accuracy'])
plt.plot(hist.history['val_accuracy'])
plt.title('Model Accuracy')
plt.ylabel('Accuracy')
plt.xlabel('Epoch')
plt.legend(['train', 'val'], loc='upper left')
plt.show()


"""This module reproduces the content of the course in
streamlit, section 2"""
import streamlit as st
import pandas as pd
import numpy as np

# You can display almost anything just by passing it to
# st.write()

st.write("Hello world")
st.write("Welcome to Streamlit App APIs")
st.write(1234)
df=pd.DataFrame({
    "first_column":[1,2,3,4,5],
    "second_column":["a","b","c","d","e"],
    "third_column":[12.1,12.34,12.33,15.1, 66]
}
)
st.write(df)
st.write(np.array([1,2,3,4]))

## --------- MAGIC ---------------#
st.write("Magic commands")
df1=pd.DataFrame({'col1':[1,2,3]})

df1

x=10

x

st.button("Rerun")


from django.db import models
from exploreuser.models import ExUser
from django.template.defaultfilters import slugify
from datetime import datetime, timezone

# Create your models here.
class Post(models.Model):
	user = models.ForeignKey(ExUser, on_delete=models.CASCADE)
	title = models.CharField(max_length=50)
	describtion = models.TextField()
	timestamp = models.DateTimeField(auto_now=True)

def get_image_path(instance, filename):
	user = instance.post.user
	title = instance.post.title
	slug = slugify(title)

	return "post_images/%s/%s-%s"%(user, slug, filename)

class PostImages(models.Model):
	post = models.ForeignKey(Post, on_delete=models.CASCADE, default=None)
	image = models.ImageField(upload_to=get_image_path, verbose_name='Image')

class Hashtags(models.Model):
	tag = models.CharField(max_length=32, unique=True)
	post = models.ManyToManyField(Post)

class Comments(models.Model):
	user = models.ForeignKey(ExUser, on_delete=models.CASCADE)
	text = models.CharField(max_length=200)
	on_post = models.ForeignKey(Post, on_delete=models.CASCADE)
	added_time = models.DateTimeField(auto_now_add=True)

	class Meta:
		ordering = ['added_time']

	def diff_time(self):
		now = datetime.now(timezone.utc)
		diff = now - self.added_time
		diff_in_sec = diff.total_seconds()

		if diff_in_sec < 60:
			td = 'Just now'
		elif diff_in_sec >= 60 and diff_in_sec < 3600:
			minute = divmod(diff_in_sec, 60)[0]

			if minute > 1:
				td = '%d minutes ago'%(minute)
			else:
				td = '1 minute ago'

		elif diff_in_sec >= 3600 and diff_in_sec < 86400:
			hours = divmod(diff_in_sec, 3600)[0]

			if hours > 1:
				td = '%d hours ago'%(hours)
			else:
				td = '1 hour ago'

		elif diff_in_sec >= 86400 and diff_in_sec < 604800:
			days = divmod(diff_in_sec, 86400)[0]

			if days > 1:
				td = '%d days ago'%(days)
			else:
				td = '1 day ago'

		else:
			td = self.added_time.strftime('%d %b, %Y')

		return td

class PostRating(models.Model):
	post = models.ForeignKey(Post, on_delete=models.CASCADE)
	user = models.ForeignKey(ExUser, on_delete=models.CASCADE)
	rating = models.IntegerField(null=True)

class PostHit(models.Model):
	max_permitted_hit = 20
	post = models.ForeignKey(Post, on_delete=models.CASCADE)
	hits = models.IntegerField(default=0)
	user = models.ForeignKey(ExUser, on_delete=models.CASCADE)
	last_viewed = models.DateTimeField(auto_now=True)


#https://www.codechef.com/JULY18B/problems/NMNMX

from functools import reduce
import operator as op

#efficient factorial = PRECOMPUTE FACTORIALS ;)
#Ref https://stackoverflow.com/questions/4941753/is-there-a-math-ncr-function-in-python
#AC in PyPy

fact={}

fact[0]=1

for i in range(1,5001):
	fact[i]=fact[i-1]*i

def ncr(n, r):
	if(r>n):
		return 0
	return fact[n] // fact[n-r] // fact[r]

def expoGivenI(n,k,i,precomputed):
	#returns the number of combinations in which element is not the global minimum
	#total no of combos in which a particular element is always present - noOfWaysInWhichThatElementIsMin- noOfWaysInWhichThatElementIsMax
	e= precomputed- ncr(n-i-1,k-1)-ncr(i,k-1)
	return e

t=int(raw_input())

while(t!=0):
	t-=1
	n,k=[int(x) for x in raw_input().split()]
	a=[int(x) for x in raw_input().split()]
	a=sorted(a)
	middle_eles=[]
	for i in range(1,n-1):
		middle_eles.append(a[i])

	exponents=[ncr(n-2,k-2)]  #n-2Ck-2 is the expo of the second number
	mid=n//2
	precomputed=ncr(n-1,k-1) #total no of combos in which a particular element is always present
	for index in range(2,mid):
		exponents.append(expoGivenI(n,k,index,precomputed))

	mirror=exponents[::-1]

	if(n%2!=0):
		#n happens to be odd
		#calculate middle element
		exponents.append(expoGivenI(n,k,mid,precomputed))

	exponents+=mirror

	products=[]
	for i in range(n-2):
		p=pow(middle_eles[i],exponents[i],10**9+7) #mid[i] ^ expo
		products.append(p)

	ans=reduce(op.mul,products,1)

	print(pow(ans,1,10**9+7))


import os
import pdfplumber
import re
import math
import openpyxl
import json
import io
from config import *
import numpy as np

import random

def get_filePath_fileName_fileExt(fileUrl):
    """
    获取文件路径， 文件名， 后缀名
    :param fileUrl:
    :return:
    """
    filepath, tmpfilename = os.path.split(fileUrl)
    shotname, extension = os.path.splitext(tmpfilename)
    return filepath, shotname, extension

def read_pdf(path):

    with pdfplumber.open(path) as pdf:
        for page in pdf.pages:
            txt = page.extract_text()
            # print(txt)
            # ss = page.bbox
            # tables = page.find_tables()

            name = re.compile('编号(.*?)\n',re.S).findall(txt)[0]
            name = name.replace(' ','')

            content = re.compile('4.工作任务\n(.*?)\n5.计划工作时间',re.S).findall(txt)[0]

            print(content)

            # for area_name in AREA_LIST:
            #     arr = content.split(area_name)
            #     if len(arr)>1:

            #         dict[area_name]

            result = []
            arr = content.split('\n')
            for a in arr:
                if '工作地点及设备双重名称' in a:
                    arr.remove(a)
                    continue

                device = ''
                # desc = ''

                a_arr = a.split('：')
                if len(a_arr)>1:
                    area = a_arr[0]
                    a_n_arr = a_arr[1].split(' ')
                    device =a_n_arr[0]
                    # if len(a_n_arr)>1:
                    #     desc = a_n_arr[1]

                    result.append({
                        'area': area,
                        'device':device
                    })
                else:
                    device_last = a_arr[0]
                    item = result.pop()
                    item['device'] = item['device'] + device_last
                    result.append(item)

            # 每页打印一分页分隔
            print('---------- ---------- ----------')
            break

        elec_contents_str = ''
        elec_contents = []
        for page in pdf.pages:
            txt = page.extract_text()
            elec_content = re.compile('工作地点保留带电部分或注意事项.*?由工作票签发人填写(.*?)工作票签发人签名',re.S).findall(txt)

            if len(elec_content)==0:
                continue
            elec_contents_str = elec_content[0].replace(') （由工作许可人填写)','')
            elec_contents_str = elec_contents_str.replace('\n','')

            arr =elec_contents_str.split('； ')

            for a in arr:
                if '安全距离' in a:
                    continue
                if '工作中应做好相关协调配合工作' in a :
                    continue

                a_i =  re.split('[，、]', a)
                for a_ii in a_i:
                    elec_contents.append(a_ii)

            break

        print(result)
        return name,result,elec_content

# https://cloud.tencent.com/developer/ask/sof/78178
# https://www.jianshu.com/p/2381639ac6ef

def latlonhtoxyzwgs84(lat,lon,h):

    a=6378137.0             #radius a of earth in meters cfr WGS84
    b=6356752.3             #radius b of earth in meters cfr WGS84
    e2=1-(b**2/a**2)
    latr=lat/90*0.5*math.pi      #latitude in radians
    lonr=lon/180*math.pi         #longituede in radians
    Nphi=a/math.sqrt(1-e2*math.sin(latr)**2)
    x=(Nphi+h)*math.cos(latr)*math.cos(lonr)
    y=(Nphi+h)*math.cos(latr)*math.sin(lonr)
    z=(b**2/a**2*Nphi+h)*math.sin(latr)
    return x,y,z

def latlontoxyz(lat,lng,alt):
    phi = (90-lat)*(math.pi/180)
    theta = (lng+180)*(math.pi/180)
    radius = alt+200
    x = -(radius * math.sin(phi) * math.cos(theta))
    z = (radius * math.sin(phi) * math.sin(theta))
    y = (radius * math.cos(phi))
    x_ext= -713.349609375
    y_ext= 149.6861572265625
    z_ext= 166.3239288330078
    x = x + x_ext
    y = y + y_ext
    z = z + z_ext
    return x,y,z

def get_distince(x1,y1,z1,x2,y2,z2):
    # dis = np.sqrt(np.abs(x1-x2)* np.abs(x1-x2) + np.abs(y1-y2)* np.abs(y1-y2) + np.abs(z1-z2)* np.abs(z1-z2))
    dis = np.sqrt((x1-x2)* (x1-x2) + (y1-y2)* (y1-y2))
    return dis

# excel表格转json文件 https://www.jianshu.com/p/57a735ac021e
def excel_to_json(excel_file, json_file_name):
    # 加载工作薄
    book = openpyxl.load_workbook(excel_file)
    # 获取sheet页
    sheet = book["Sheet1"]
    # 行数
    max_row = sheet.max_row
    # 列数
    max_column = sheet.max_column
    print("max_row: %d, max_column: %d" % (max_row, max_column))
    # 结果，数组存储
    result = []
    heads = []
    max_column = 13
    # 解析表头
    for column in range(max_column):
        # 读取的话行列是从（1，1）开始
        heads.append(sheet.cell(1, column + 1).value)
    # 遍历每一行
    for row in range(max_row):
        if row == 0:
            continue
        one_line = {}
        for column in range(max_column):
            # 读取第二行开始每一个数据
            k = heads[column]
            cell = sheet.cell(row + 1, column + 1)
            value = cell.value
            if value == None:
                value =''
            if column ==3:
                value = value.replace('交流','')
            one_line[k] = value

        safe = get_safe(one_line['dianya'])
        if safe:
            one_line['person_safe'] = safe['person']
            one_line['car_safe'] = safe['car']
        else:
            one_line['person_safe'] = 0
            one_line['car_safe'] = 0

        print(one_line)
        result.append(one_line)
    book.close()
    # 将json保存为文件
    save_json_file(result, json_file_name)

# 将json保存为文件
def save_json_file(jd, json_file_name):
    file = io.open(json_file_name, 'w', encoding='utf-8')
    # 把对象转化为json对象
    # indent: 参数根据数据格式缩进显示，读起来更加清晰
    # ensure_ascii = True：默认输出ASCII码，如果把这个该成False, 就可以输出中文。
    txt = json.dumps(jd, indent=2, ensure_ascii=False)
    file.write(txt)
    file.close()

def generate_random_gps(base_log=None, base_lat=None, radius=None):
    radius_in_degrees = radius / 111300
    u = float(random.uniform(0.0, 1.0))
    v = float(random.uniform(0.0, 1.0))
    w = radius_in_degrees * math.sqrt(u)
    t = 2 * math.pi * v
    x = w * math.cos(t)
    y = w * math.sin(t)
    longitude = y + base_log
    latitude = x + base_lat
    # 这里是想保留6位小数点
    loga = '%.8f' % longitude
    lata = '%.8f' % latitude
    return float(loga), float(lata)

# log1, lat1 = generate_random_gps(base_log=120.7, base_lat=30, radius=1000000)

def load_json(path):
    with open(path,"r") as f:
        data = json.load(f)
        return data

if '__main__' == __name__:

    BASE_DIR = os.path.dirname(os.path.abspath(__file__))

    path = os.path.join(BASE_DIR,'piao','1000kV邢台站一次设备台账（2021.09.05）.xlsx')
    json_path = os.path.join(BASE_DIR,'pcd','tai.json')

    excel_to_json(path, json_path)

    # file_path = os.path.join(rundir,'piao','201909001.pdf')
    # file_path2 = os.path.join(BASE_DIR,'piao','202104002.pdf')
    # # result = read_pdf(file_path)
    # result2 = read_pdf(file_path2)
    # print(result2)