import numpy as np
import datetime
import random

class DataSet():
    def __init__(self, filename):
        self.filename = filename
        self.sentences = []
        self.tags = []
        sentence = []
        tag = []
        word_num = 0
        file = open(filename, encoding='utf-8')
        while True:
            line = file.readline()
            if not line:
                break
            if line == '\n':
                self.sentences.append(sentence)  # [[word1,word2,...],[word1...],[...]]
                self.tags.append(tag)  # [[tag1,tag2,...],[tag1...],[...]]
                sentence = []
                tag = []
            else:
                sentence.append(line.split()[1])  # [word1,word2,...]
                tag.append(line.split()[3])  # [tag1,tag2,...]
                word_num += 1
        self.sentences_num = len(self.sentences)  # 统计句子个数
        self.word_num = word_num  # 统计词语个数

        print('{}:共{}个句子,共{}个词。'.format(filename, self.sentences_num, self.word_num))
        file.close()

    def split(self):
        data = []
        temp_list = []
        for i in range(len(self.sentences)):
            for j in range(len(self.sentences[i])):  # j为词在句子中的序号
                temp_list.append((self.sentences[i][j], self.tags[i][j]))  # [(句子1,1,词性),(句子1,2,词性)...]
            data.append(temp_list)
            temp_list = []
        return data

class global_liner_model(object):
    def __init__(self, train_file, dev_file, test_file):
        self.train_data = DataSet(train_file)  # 处理训练集文件
        self.dev_data = DataSet(dev_file)  # 处理开发集文件
        self.test_data = DataSet(test_file) # 处理测试集文件
        self.features = {}  # 存放所有特征及其对应编号的字典
        self.tag_to_index = {}  # 存放所有词性及其对应编号的字典
        self.index_to_tag = {}
        self.tag_list = []  # 存放所有词性的列表
        self.weights = []  # 特征权重矩阵
        self.v = []
        self.BOS = 'BOS'

    def create_bigram_feature(self, pre_tag):
        return ['01:' + pre_tag]

    def create_unigram_feature(self, sentence, position):
        template = []
        cur_word = sentence[position]
        cur_word_first_char = cur_word[0]
        cur_word_last_char = cur_word[-1]
        if position == 0:
            last_word = '##'
            last_word_last_char = '#'
        else:
            last_word = sentence[position - 1]
            last_word_last_char = sentence[position - 1][-1]

        if position == len(sentence) - 1:
            next_word = '$$'
            next_word_first_char = '$'
        else:
            next_word = sentence[position + 1]
            next_word_first_char = sentence[position + 1][0]

        template.append('02:' + cur_word)
        template.append('03:' + last_word)
        template.append('04:' + next_word)
        template.append('05:' + cur_word + '*' + last_word_last_char)
        template.append('06:' + cur_word + '*' + next_word_first_char)
        template.append('07:' + cur_word_first_char)
        template.append('08:' + cur_word_last_char)

        for i in range(1, len(sentence[position]) - 1):
            template.append('09:' + sentence[position][i])
            template.append('10:' + sentence[position][0] + '*' + sentence[position][i])
            template.append('11:' + sentence[position][-1] + '*' + sentence[position][i])
            if sentence[position][i] == sentence[position][i + 1]:
                template.append('13:' + sentence[position][i] + '*' + 'consecutive')

        if len(sentence[position]) > 1 and sentence[position][0] == sentence[position][1]:
            template.append('13:' + sentence[position][0] + '*' + 'consecutive')

        if len(sentence[position]) == 1:
            template.append('12:' + cur_word + '*' + last_word_last_char + '*' + next_word_first_char)

        for i in range(0, 4):
            if i > len(sentence[position]) - 1:
                break
            template.append('14:' + sentence[position][0:i + 1])
            template.append('15:' + sentence[position][-(i + 1)::])
        return template

    def create_feature_template(self, sentence, position, pre_tag):
        template = []
        template.extend(self.create_bigram_feature(pre_tag))
        template.extend(self.create_unigram_feature(sentence, position))
        return template

    def create_feature_space(self):
        for i in range(len(self.train_data.sentences)):
            sentence = self.train_data.sentences[i]
            tags = self.train_data.tags[i]
            for j in range(len(sentence)):
                if j == 0:
                    pre_tag = self.BOS
                else:
                    pre_tag = tags[j - 1]
                template = self.create_feature_template(sentence, j, pre_tag)
                for f in template:
                    if f not in self.features:
                        self.features[f] = len(self.features)
                for tag in tags:
                    if tag not in self.tag_list:
                        self.tag_list.append(tag)
        self.tag_list = sorted(self.tag_list)
        self.tag_to_index = {t: i for i, t in enumerate(self.tag_list)}
        self.index_to_tag = {i: t for i, t in enumerate(self.tag_list)}
        self.weights = np.zeros((len(self.features), len(self.tag_list)))
        self.v = np.zeros((len(self.features), len(self.tag_list)))
        self.update_times = np.zeros((len(self.features), len(self.tag_list)))
        self.bigram_features = [self.create_bigram_feature(prev_tag) for prev_tag in self.tag_list]
        print("特征的总数是：{}".format(len(self.features)))

    def get_score(self, feature, averaged=False):
        if averaged:
            scores = [self.v[self.features[f]] for f in feature if f in self.features]
        else:
            scores = [self.weights[self.features[f]] for f in feature if f in self.features]
        return np.sum(scores, axis=0)

    def predict(self, sentence, averaged):
        length = len(sentence)
        delta = np.zeros((length, len(self.tag_list)))
        path = np.zeros((length, len(self.tag_list)), dtype=int)
        feature_first = self.create_feature_template(sentence, 0, self.BOS)
        delta[0] = self.get_score(feature_first, averaged)
        path[0] = -1
        bigram_scores = np.array([self.get_score(bigram_feature, averaged) for bigram_feature in self.bigram_features])
        # 对于每一个bigram_feature其实就是对于每一个pre_tag
        for i in range(1, length):
            unigram_features = self.create_unigram_feature(sentence, i)
            unigram_scores = self.get_score(unigram_features, averaged)
            scores = np.transpose(bigram_scores + unigram_scores) + delta[i - 1]
            path[i] = np.argmax(scores, axis=1)
            delta[i] = np.max(scores, axis=1)
        predict_tag_list = []
        tag_index = np.argmax(delta[length - 1])
        predict_tag_list.append(self.index_to_tag[tag_index])
        for i in range(length - 1):
            tag_index = path[length - 1 - i][tag_index]
            predict_tag_list.insert(0, self.index_to_tag[tag_index])
        return predict_tag_list

    def update_v(self, findex, tindex, update_time, last_w_value):
        last_update_time = self.update_times[findex][tindex]  # 上一次更新所在的次数
        current_update_time = update_time  # 本次更新所在的次数
        self.update_times[findex][tindex] = update_time
        self.v[findex][tindex] += (current_update_time - last_update_time - 1) * last_w_value + self.weights[findex][
            tindex]

    def evaluate(self, data, averaged):
        total_num = 0
        correct_num = 0
        for i in range(len(data.sentences)):
            sentence = data.sentences[i]
            tags = data.tags[i]
            total_num += len(tags)
            predict = self.predict(sentence, averaged)
            for j in range(len(tags)):
                if tags[j] == predict[j]:
                    correct_num += 1
        return correct_num, total_num, correct_num / total_num

    def perceptron_online_training(self, iterator, stop_iterator, shuffle, averaged):
        max_dev_precision = 0
        counter = 0
        update_time = 0
        max_iterator = -1
        data = self.train_data.split()
        if averaged:
            print("使用累加特征权重：")
        else:
            print("不使用累加特征权重：")
        for iter in range(iterator):
            print('iterator: {}'.format(iter))
            start_time = datetime.datetime.now()
            if shuffle:
                print('\t正在打乱训练数据...')
                random.shuffle(data)
                print("\t数据已打乱，正在进行预测...")
            bigram_features = [self.create_bigram_feature(pre_tag) for pre_tag in self.tag_list]
            for i in range(len(self.train_data.sentences)):
                sentence = self.train_data.sentences[i]
                tags = self.train_data.tags[i]
                predict = self.predict(sentence, averaged)
                if predict != tags:
                    update_time += 1
                    for j in range(len(sentence)):
                        unigram_feature = self.create_unigram_feature(sentence, j)
                        if j == 0:
                            gold_bigram_feature = self.create_bigram_feature(self.BOS)
                            predict_bigram_feature = self.create_bigram_feature(self.BOS)
                        else:
                            gold_pre_tag = tags[j - 1]
                            predict_pre_tag = predict[j - 1]
                            gold_bigram_feature = bigram_features[self.tag_to_index[gold_pre_tag]]
                            predict_bigram_feature = bigram_features[self.tag_to_index[predict_pre_tag]]

                        for f in unigram_feature:
                            if f in self.features:
                                findex = self.features[f]
                                tindex = self.tag_to_index[tags[j]]
                                last_w_value = self.weights[findex][tindex]
                                self.weights[findex][tindex] += 1
                                self.update_v(findex, tindex, update_time, last_w_value)

                                findex = self.features[f]
                                tindex = self.tag_to_index[predict[j]]
                                last_w_value = self.weights[findex][tindex]
                                self.weights[findex][tindex] -= 1
                                self.update_v(findex, tindex, update_time, last_w_value)

                        for f in gold_bigram_feature:
                            if f in self.features:
                                findex = self.features[f]
                                tindex = self.tag_to_index[tags[j]]
                                last_w_value = self.weights[findex][tindex]
                                self.weights[findex][tindex] += 1
                                self.update_v(findex, tindex, update_time, last_w_value)
                                # self.weights[self.features[f]][self.tag2id[tags[j]]] += 1

                        for f in predict_bigram_feature:
                            if f in self.features:
                                findex = self.features[f]
                                tindex = self.tag_to_index[predict[j]]
                                last_w_value = self.weights[findex][tindex]
                                self.weights[findex][tindex] -= 1
                                self.update_v(findex, tindex, update_time, last_w_value)
            # 本次迭代完成
            current_update_times = update_time  # 本次更新所在的次数
            for i in range(len(self.v)):
                for j in range(len(self.v[i])):
                    last_w_value = self.weights[i][j]
                    last_update_times = self.update_times[i][j]  # 上一次更新所在的次数
                    if current_update_times != last_update_times:
                        self.update_times[i][j] = current_update_times
                        self.v[i][j] += (current_update_times - last_update_times - 1) * last_w_value + self.weights[i][j]

            train_correct_num, total_num, train_precision = self.evaluate(self.train_data, averaged)
            print('\t' + 'train准确率：{} / {} = {}'.format(train_correct_num, total_num, train_precision))
            test_correct_num, test_num, test_precision = self.evaluate(self.test_data, averaged)
            print('\t' + 'test准确率：{} / {} = {}'.format(test_correct_num, test_num, test_precision))
            dev_correct_num, dev_num, dev_precision = self.evaluate(self.dev_data, averaged)
            print('\t' + 'dev准确率：{} / {} = {}'.format(dev_correct_num, dev_num, dev_precision))

            if dev_precision > max_dev_precision:
                max_dev_precision = dev_precision
                max_iterator = iter
                counter = 0
            else:
                counter += 1
            end_time = datetime.datetime.now()
            print("\t迭代执行时间为：" + str((end_time - start_time).seconds) + " s")
            if counter >= stop_iterator:
                break
        print('最优迭代轮次 = {} , 开发集准确率 = {}'.format(max_iterator, max_dev_precision))

if __name__ == '__main__':
    train_data_file = 'data/train.conll'  # 训练集文件
    dev_data_file = 'data/dev.conll'  # 开发集文件
    test_data_file = 'data/test.conll'  # 测试集文件
    iterator = 100  # 最大迭代次数
    stop_iterator = 10  # 连续多少次迭代没有提升效果就退出
    shuffle = True  # 每次迭代是否打乱数据
    averaged = False  # 是否使用averaged percetron

    total_start_time = datetime.datetime.now()
    lm = global_liner_model(train_data_file, dev_data_file, test_data_file)
    lm.create_feature_space()
    lm.perceptron_online_training(iterator, stop_iterator, shuffle, averaged)
    total_end_time = datetime.datetime.now()
    print("总执行时间为：" + str((total_end_time - total_start_time).seconds) + " s")


import os, sys, stat
from pathlib import Path
from os.path import realpath
import json
import numpy as np
from osgeo import  osr, gdal, ogr
import matplotlib as mpl
import rtree
from pyearth.visual.scatter.scatter_plot_data import scatter_plot_data
from pyearth.toolbox.reader.text_reader_string import text_reader_string
from pyearth.visual.scatter.scatter_plot_multiple_data import scatter_plot_multiple_data
from pyflowline.external.pyearth.gis.gdal.gdal_functions  import meter_to_degree, degree_to_meter
from pyearth.visual.color.create_diverge_rgb_color_hex import create_diverge_rgb_color_hex
from pyhexwatershed.pyhexwatershed_read_model_configuration_file import pyhexwatershed_read_model_configuration_file
from pyflowline.formats.read_flowline import read_flowline_geojson
from pyflowline.mesh.dggrid.create_dggrid_mesh import dggrid_find_resolution_by_index
from pyflowline.external.pyearth.gis.gdal.gdal_functions import gdal_read_geotiff_file, reproject_coordinates
sPath_parent = str(Path(__file__).parents[2]) # data is located two dir's up
print(sPath_parent)
sPath_data = realpath( sPath_parent +  '/data/amazon' )
sWorkspace_input =  str(Path(sPath_data)  /  'input')
sWorkspace_output = '/compyfs/liao313/04model/pyhexwatershed/amazon'
aResolution_index = [10, 11, 12, 13]
nCase = len(aResolution_index)
aCase_index = aResolution_index
sDate='20230801'
sMesh_type = 'dggrid'
sFilename_configuration_in = realpath( sPath_parent +  '/examples/amazon/pyhexwatershed_amazon_dggrid.json' )

# we define a dictionnary with months that we'll use later
case_dict = dict()

for i in range(1, nCase +1):
    case_dict[i] = 'Case ' +  "{:0d}".format(i)

print(case_dict)

aDistance_niws =list()
aData_x=list()
aData_y  =list()
aLabel_legend =list()

#read the point location using gdal
pSrs = osr.SpatialReference()
pSrs.ImportFromEPSG(4326)    # WGS84 lat/lon
sFilename_confluence = '/qfs/people/liao313/data/hexwatershed/amazon/vector/amztrbmth.geojson'
pDriver = ogr.GetDriverByName('GeoJSON')
pDataSource = pDriver.Open(sFilename_confluence, 0)
pLayer = pDataSource.GetLayer()
nPoint = pLayer.GetFeatureCount()
aLongitude = np.full(nPoint, None, dtype=float)
aLatitude = np.full(nPoint, None, dtype=float)
for i in range(nPoint):
    pFeature = pLayer.GetFeature(i)
    pGeometry = pFeature.GetGeometryRef()
    #get x and y of the point
    dLongitude = pGeometry.GetX()
    dLatitude = pGeometry.GetY()
    aLongitude[i] = dLongitude
    aLatitude[i] = dLatitude

pDataSource = None

#the flow accumenation is in the same order as the point

sFilename_flow_accumulation = '/compyfs/liao313/00raw/hydrology/amazon/CD06_CAMREX_1086/data/amzfloacc.tif'
pRaster = gdal.Open(sFilename_flow_accumulation)
aFlow_accumulation_in, dPixelWidth, dOriginX, dOriginY, \
            nrow, ncolumn,dMissing_value, pGeotransform, pProjection,  pSpatialRef_target = gdal_read_geotiff_file(sFilename_flow_accumulation)

dResolution_degree_in= 0.005
dLatitude_mean = np.mean(aLatitude)
dResolution_flow_accumulation = degree_to_meter( dLatitude_mean ,dResolution_degree_in)

dX_left=dOriginX
dX_right = dOriginX + ncolumn * dPixelWidth
dY_top = dOriginY
dY_bot = dOriginY - nrow * dPixelWidth
aFlow_accumulation = np.full(nPoint, None, dtype=float)
for i in range(nPoint):
    x1 = aLongitude[i]
    y1 = aLatitude[i]
    dX_out,dY_out = reproject_coordinates(x1,y1, pSrs,pSpatialRef_target)
    dDummy1 = (dX_out - dX_left) / dPixelWidth
    lColumn_index = int(dDummy1)
    dDummy2 = (dY_top - dY_out) / dPixelWidth
    lRow_index = int(dDummy2)
    if lColumn_index >= ncolumn or lColumn_index < 0 \
        or lRow_index >= nrow or lRow_index < 0:
        #this pixel is out of bound
        continue
    else:
        dFlow_accumulation = aFlow_accumulation_in[lRow_index, lColumn_index]
        aFlow_accumulation[i] = dFlow_accumulation * dResolution_flow_accumulation * dResolution_flow_accumulation / 1.0E6

#read the model resolution
sDggrid_type = 'ISEA3H'
aDrainage_area = np.full(( nCase,nPoint), None, dtype=float)
for iCase in range(0, nCase ):
    #read
    iCase_index = aCase_index[iCase]
    iResolution_index = aResolution_index[iCase]
    dResolution = dggrid_find_resolution_by_index(sDggrid_type, iResolution_index)
    print(dResolution)

    oPyhexwatershed = pyhexwatershed_read_model_configuration_file(sFilename_configuration_in,
                    iCase_index_in=iCase_index,
                    sDate_in= sDate, sMesh_type_in= sMesh_type)

    #read the variable polygon
    sFilename_polygon = oPyhexwatershed.aBasin[0].sFilename_variable_polygon
    pDataSource = pDriver.Open(sFilename_polygon, 0)
    pLayer_base = pDataSource.GetLayer()
    nFeature_base = pLayer_base.GetFeatureCount()
    index_base = rtree.index.Index()

    for i in range(nFeature_base):
        lID = i
        pFeature_base = pLayer_base.GetFeature(i)
        pGeometry_base = pFeature_base.GetGeometryRef()
        left, right, bottom, top= pGeometry_base.GetEnvelope()
        pBound= (left, bottom, right, top)
        index_base.insert(lID, pBound)  #

    #find the confluence point
    for i in range(nPoint):
        #convert meter to degree
        dLatitude_mean=     aLatitude[i]
        dResolution_degree = meter_to_degree(dResolution, dLatitude_mean) * 2
        pBound= (aLongitude[i] - dResolution_degree,
                 aLatitude[i] - dResolution_degree,
                 aLongitude[i] + dResolution_degree,
                 aLatitude[i] + dResolution_degree)
        aIntersect = list(index_base.intersection(pBound))
        aDummy = list()
        for k in aIntersect:
            pFeature_base = pLayer_base.GetFeature(k)
            dDrainage_base = pFeature_base.GetField("drainage_area")
            aDummy.append(dDrainage_base/ 1.0E6)

        #find the closese to the observation
        dFlow_accumulation = aFlow_accumulation[i]
        #calculate the difference
        aDummy = np.asarray(aDummy)
        aDummy0 = np.abs(aDummy - dFlow_accumulation)
        #find th minimum and its index
        iIndex = np.argmin(aDummy0)
        aDrainage_area[iCase, i] = aDummy[iIndex]

    #close the file
    pDataSource = None

sFilename_out = sPath_parent + '/' + 'figures' + '/' + 'scatterplot_drainage_area_multiple.png'

#5 cases + 1 obs

aColor = np.full(nCase, None, dtype=object)
aMarker= np.full(nCase, None, dtype=object)
aSize = np.full(nCase, mpl.rcParams['lines.markersize'] ** 2 , dtype=object)

nmesh=nCase
aColor= create_diverge_rgb_color_hex(nmesh)
aMarker = [ '.','o','+','x','^']

aFlow_accumulation = np.array(aFlow_accumulation)
aData_x = list()
aData_y = list()

for i in range(nCase):
    iCase_index = aCase_index[i]
    aLabel_legend.append(   'ISEA3H Level ' +  "{:0d}".format(iCase_index)   )
    aDatax0 = list()
    aDatay0 = list()
    for j in range(nPoint):
        aDatax0.append(aFlow_accumulation[j])
        aDatay0.append(aDrainage_area[i,j])

    aDatax0 = np.asarray(aDatax0)
    aDatay0 = np.asarray(aDatay0)
    aData_x.append(aDatax0)
    aData_y.append(aDatay0)

scatter_plot_multiple_data(aData_x,
                      aData_y,
                      sFilename_out,
                      iFlag_scientific_notation_x_in=1,
                      iFlag_scientific_notation_y_in=1,
                      iSize_x_in = None,
                      iSize_y_in = None,
                      iDPI_in = None ,
                      iFlag_log_x_in = None,
                      iFlag_log_y_in = None,
                      dMin_x_in = 0,
                      dMax_x_in = np.max(aFlow_accumulation),
                      dMin_y_in = 0,
                      dMax_y_in = np.max(aFlow_accumulation),
                      dSpace_x_in = None,
                      dSpace_y_in = None,
                      sFormat_x_in =None,
                      sFormat_y_in =None,
                      sLabel_x_in ='LBA-ECO data, $km^{2}$',
                      sLabel_y_in = 'HexWatershed, $km^{2}$)' ,
                      aColor_in=aColor,
                      aMarker_in=aMarker,
                      aSize_in = aSize,
                      aLabel_legend_in = aLabel_legend,
                      sTitle_in = 'Drainage area')

print('finished')


from dataclasses import dataclass,field

## TvShowTorrent is based on the record returned form 1337x
## It will parse the the record returned from 1337x API and
## Have utilities to standardize the actions on that return data

class TvTorrentParsingError(Exception):
    def __init__(self):
        self.msg = 'There was an error parsing the torrent API data'
        super().__init__(self.msg)

@dataclass
class TvShowTorrent():
    _name:str=field(init=False)
    _torrent_id:str=field(init=False)
    _link:str=field(init=False)
    _seeders:int=field(init=False)
    _leechers:str=field(init=False)
    _size:str=field(init=False)
    _upload_date:str=field(init=False)
    _uploader:str=field(init=False)
    _uploader_link:str=field(init=False)
    _adjusted_size:float=field(init=False)
    def __lt__(self, other):
        return self._adjusted_size < other.score

    def parse_data(self, torrent_record)->None:
        try:
            self._name=torrent_record['name']
            self._torrent_id=torrent_record['torrentId']
            self._link=torrent_record['link']
            self._seeders=int(torrent_record['seeders'] )
            self._leechers=torrent_record['leechers']
            self._size=torrent_record['size']
            self._upload_date=torrent_record['time']
            self._uploader=torrent_record['uploader']
            self._uploader_link=torrent_record['uploaderLink']
            self._adjusted_size=self.startard_sizes()
        except:
           raise TvTorrentParsingError()

    ## The size of the torrent files are on Mb and Gb but as strings and
    ## This will standardize them as Gb as a float
    def startard_sizes(self):
        size=float(self._size[0:len(self._size)-3])
        if self._size.upper().find('MB')!=-1:
            size=size/1000
        return size

    ## Takes a string of a show name, season and episode and returns
    ## True or False if it matches
    def matches(self,name:str,season:int,episode:int):
        ## Make it upper to match easier
        upper_show=self._name.upper().replace(' ','.')

        ## Make it upper to match easier
        search_show='{show}.S{season:02d}E{episode:02d}'.format(\
            show=name.upper(),season=season,episode=episode)

        if upper_show.find(search_show.upper().replace(' ','.'))==0:
            return True
        else:
            return False


from test_framework import generic_test
from collections import Counter

"""

Constructible if
    for each char in letter:
        count of char in letter <= count of char in magazine

Brute force:
For each char in letter
    Count occurrences of char in mag, and compare
O(nm)

Hash table:
Get counts of chars in letter (O(n))
Get counts of chars in magazine (O(m))
Compare counts (O(k) for k unique chars), basically O(26) = O(1))
O(n + m)

"""

def is_letter_constructible_from_magazine(letter_text: str,
                                          magazine_text: str) -> bool:
    letter_counts = Counter(letter_text)
    mag_counts = Counter(magazine_text)
    mag_counts.subtract(letter_counts)
    for k, v in mag_counts.items():
        if v < 0: # higher count in letter
            return False
    return True

if __name__ == '__main__':
    exit(
        generic_test.generic_test_main(
            'is_anonymous_letter_constructible.py',
            'is_anonymous_letter_constructible.tsv',
            is_letter_constructible_from_magazine))


import csv
import logging

from openlp.core.common import translate
from openlp.plugins.songs.lib.importers.songimport import SongImport

log = logging.getLogger(__name__)

# Used to strip control chars (except 10=LF, 13=CR)
CONTROL_CHARS_MAP = dict.fromkeys(list(range(10)) + [11, 12] + list(range(14, 32)) + [127])

class ZionWorxImport(SongImport):
    """
    The :class:`ZionWorxImport` class provides the ability to import songs
    from ZionWorx, via a dump of the ZionWorx database to a CSV file.

    ZionWorx song database fields:

    * ``SongNum`` Song ID. (Discarded by importer)
    * ``Title1`` Main Title.
    * ``Title2`` Alternate Title.
    * ``Lyrics`` Song verses, separated by blank lines.
    * ``Writer`` Song author(s).
    * ``Copyright`` Copyright information
    * ``Keywords`` (Discarded by importer)
    * ``DefaultStyle`` (Discarded by importer)

    ZionWorx has no native export function; it uses the proprietary TurboDB
    database engine. The TurboDB vendor, dataWeb, provides tools which can
    export TurboDB tables to other formats, such as freeware console tool
    TurboDB Data Exchange which is available for Windows and Linux. This command
    exports the ZionWorx songs table to a CSV file:

    ``tdbdatax MainTable.dat songstable.csv -fsdf -s, -qd``

    * -f  Table format: ``sdf`` denotes text file.
    * -s  Separator character between fields.
    * -q  Quote character surrounding fields. ``d`` denotes double-quote.

    CSV format expected by importer:

    * Field separator character is comma ``,``
    * Fields surrounded by double-quotes ``"``. This enables fields (such as
      Lyrics) to include new-lines and commas. Double-quotes within a field
      are denoted by two double-quotes ``""``
    * Note: This is the default format of the Python ``csv`` module.

    """
    def do_import(self):
        """
        Receive a CSV file (from a ZionWorx database dump) to import.
        """
        with open(self.import_source, 'rb') as songs_file:
            field_names = ['SongNum', 'Title1', 'Title2', 'Lyrics', 'Writer', 'Copyright', 'Keywords',
                           'DefaultStyle']
            songs_reader = csv.DictReader(songs_file, field_names)
            try:
                records = list(songs_reader)
            except csv.Error as e:
                self.log_error(translate('SongsPlugin.ZionWorxImport', 'Error reading CSV file.'),
                               translate('SongsPlugin.ZionWorxImport', 'Line %d: %s') % (songs_reader.line_num, e))
                return
            num_records = len(records)
            log.info('%s records found in CSV file' % num_records)
            self.import_wizard.progress_bar.setMaximum(num_records)
            for index, record in enumerate(records, 1):
                if self.stop_import_flag:
                    return
                self.set_defaults()
                try:
                    self.title = self._decode(record['Title1'])
                    if record['Title2']:
                        self.alternate_title = self._decode(record['Title2'])
                    self.parse_author(self._decode(record['Writer']))
                    self.add_copyright(self._decode(record['Copyright']))
                    lyrics = self._decode(record['Lyrics'])
                except UnicodeDecodeError as e:
                    self.log_error(translate('SongsPlugin.ZionWorxImport', 'Record %d' % index),
                                   translate('SongsPlugin.ZionWorxImport', 'Decoding error: %s') % e)
                    continue
                except TypeError as e:
                    self.log_error(translate(
                        'SongsPlugin.ZionWorxImport', 'File not valid ZionWorx CSV format.'), 'TypeError: %s' % e)
                    return
                verse = ''
                for line in lyrics.splitlines():
                    if line and not line.isspace():
                        verse += line + '\n'
                    elif verse:
                        self.add_verse(verse)
                        verse = ''
                if verse:
                    self.add_verse(verse)
                title = self.title
                if not self.finish():
                    self.log_error(translate('SongsPlugin.ZionWorxImport', 'Record %d') % index +
                                   (': "' + title + '"' if title else ''))

    def _decode(self, str):
        """
        Decodes CSV input to unicode, stripping all control characters (except new lines).
        """
        # This encoding choice seems OK. ZionWorx has no option for setting the
        # encoding for its songs, so we assume encoding is always the same.
        return str(str, 'cp1252').translate(CONTROL_CHARS_MAP)


import os
import torch
import numpy as np
from osgeo import gdal, ogr
import geopandas as gpd
from shapely.geometry import Point
from tqdm import tqdm
from matplotlib import pyplot as plt
import affine
import rasterio
import rasterio.features
import random

def list_paths_in_dir(root_dir, file_endings=None):
    """
    Get a list of paths to files within a directory and subdirectories

    :param root_dir: directory to search
    :param file_endings: list of file endings to consider. Default is all
    """
    files = []
    for dirpath, _, filenames in os.walk(root_dir):
        if file_endings:
            filenames = [f for f in filenames if f.endswith(file_endings)]
        for filename in filenames:
            files.append(os.path.join(dirpath, filename))
    return files

def build_padded_vrt(sources, padding=1000):
    """ Creates an inmemory gdal VRT from a list of sources with additional padding
    :param sources: list of paths to raster files
    :param padding: amount of padding in meters around the vrt to avoid read errors
    :returns: a gdal vrt object
    """
    vrt = gdal.BuildVRT('', sources)
    extent = get_raster_extent(vrt)
    extent = extent[0] - padding, extent[3] - padding, extent[2] + padding, extent[1] + padding
    vrt = gdal.BuildVRT('', sources, options=gdal.BuildVRTOptions(outputBounds=extent, resolution='highest'))
    return vrt

def get_all_bands_as_numpy(raster, offset=(0, 0), res=None, bands=None, means=None, stds=None):
    """
    Fetches bands from a raster, stacks them and returns normalised numpy array.
    A list of means and standard deviations the same length as the number of bands can be passed to standardise each
    one individually. To standardise all bands with the same mean and std pass a list of length 1

    :param raster: gdal raster object
    :param offset: offset tuple (x,y) in pixels from top left corner
    :param res: output size in pixels (crops input). Default is to use the whole raster.
    :param bands: list of bands to extract. Default is all.
    :param means: list of means for each band to standardise
    :param stds: list of standard deviations for each band to standardise
    :return: standardised numpy array
     """

    if res is None:
        res = (raster.RasterXSize, raster.RasterYSize)
    else:
        res = (res, res)

    if bands is None:
        bands = range(1, raster.RasterCount + 1)

    # standardise all bands the same if only one value is given
    if means and len(means) == 1:
        means = raster.RasterCount * means
    if stds and len(stds) == 1:
        stds = raster.RasterCount * stds

    band_list = []
    i = 0
    for band in bands:
        rb = raster.GetRasterBand(band)
        rb.SetNoDataValue(means[i] if means else 0)
        arr = rb.ReadAsArray(offset[0], offset[1], res[0], res[1], buf_type=gdal.GDT_Float32)

        # Standardise
        if means:
            arr -= means[i]
        if stds:
            arr /= stds[i]

        band_list.append(arr)
        arr = None
        rb = None
        i += 1

    image = np.stack(band_list, axis=2)

    return image

def redistribute_satellite_data(image):
    """ Redistributes the input data to spread it more evenly.

    The input data was found to bi bimodal with a large spike on the negative side of the standardised data
    from the shadows. Multiplying negative values by 3 as well as by themselves was found to result in a better spread
    of data.
    """
    image[image < 0] = -3 * image[image < 0] ** 2
    return image

def undo_redistribute_satellite_data(image):
    """ Reverses effects of redistribute_satellite_data for visualisation"""
    image[image < 0] = -torch.sqrt(-image[image < 0]/3)
    return image

def get_numpy_from_ogr_shapefile(shapefile, ref_raster, offset=(0, 0), res=None):
    """
    Rasterises shapefile and return numpy array. The shapefile should be opened with ogr.

    :param shapefile: shapefile openened with ogr
    :param ref_raster: reference raster which shapefile will be projected on.
    :param offset: offset (x,y) in pixels from the top left corner.
    :param res: output size (x, y) in pixels. Output will be cropped to this. Default is size of reference raster.
    :return: numpy array of shapefile at specified window
    """

    if res is None:
        res = (ref_raster.RasterXSize, ref_raster.RasterYSize)

    # get spatial information from reference raster
    geo_transform = ref_raster.GetGeoTransform()
    pixel_w = geo_transform[1]  # pixel width eg. 1 pixel => 1.5m
    x_min = geo_transform[0]
    y_max = geo_transform[3]
    y_min = y_max + geo_transform[5] * ref_raster.RasterYSize
    y_res = ref_raster.RasterYSize

    # prepare raster
    shape_raster = gdal.GetDriverByName('MEM').Create('', res[0], res[1], 1, gdal.GDT_Byte)
    shape_raster.SetGeoTransform(
        (x_min + offset[0] * pixel_w, pixel_w, 0, y_min + (y_res - offset[1]) * pixel_w, 0, -pixel_w))

    # rasterise
    shape_l = shapefile.GetLayer()
    err = gdal.RasterizeLayer(shape_raster, [1], shape_l, burn_values=[1])
    if err != 0:
        print('Rasterising error: ', err)

    return shape_raster.ReadAsArray()

def rasterise_geopandas(dataset, tile_size, offset, burn_val=1, res=1.5, individual=False):
    """
    Rasterise geopandas dataset and return numpy array

    :param dataset: geopandas dataset to be rasterised
    :param tile_size: size of the output patch
    :param offset: position of top left corner. Make sure this is in the correct CRS
    :param burn_val: value to write where there is a shape. Background is zero. If string, it is interpreted as an attribute
    :param res: resolution of raster (meters per pixel)
    :param individual: whether to rasterise each avalanche into a separate channel
    """
    transform = affine.Affine(res, 0, offset[0], 0, -res, offset[1])

    # first get subset of avalanches intersecting patch before rasterising them
    subset = dataset.cx[offset[0]: offset[0] + res * tile_size[0], offset[1] + -res * tile_size[1]: offset[1]:]
    if len(subset) == 0:
        return np.zeros(tile_size)

    if isinstance(burn_val, str):
        shapes = ((sample.geometry, sample[burn_val]) for _, sample in subset.iterrows())
    else:
        shapes = ((geom, value) for geom, value in zip(subset.geometry, len(subset) * [burn_val]))

    raster = []
    if individual:
        for shape in shapes:
            raster.append(rasterio.features.rasterize([shape], tile_size, transform=transform, dtype=np.single))
        raster = np.stack(raster, axis=2)
    else:
        raster = rasterio.features.rasterize(shapes, tile_size, transform=transform, dtype=np.single)
    return raster

def get_raster_extent(raster):
    """
    Get the spatial extent of the raster in its coordinate frame
    :param raster: gdal raster object
    :return: ulx, uly, lrx, lry whereby ul is upper left and lr is lower right in meters
    """
    ulx, xres, xskew, uly, yskew, yres = raster.GetGeoTransform()
    lrx = ulx + (raster.RasterXSize * xres)
    lry = uly + (raster.RasterYSize * yres)
    return ulx, uly, lrx, lry

def labels_to_mask(labels):
    """ Convert image labels to mask of zeros and ones. Returns binary mask of avalanches ignoring their certainty"""
    return (labels != 0).float()

def get_avalanches_in_region(avalanches, region):
    """
    Return geoseries of all avalanches within the region
    """
    selection = avalanches.intersects(region.geometry.loc[0])
    for i in range(1, len(region)):
        selection |= avalanches.intersects(region.geometry.loc[i])

    return avalanches[selection]

def generate_point_grid(region, tile_size, pixel_w ,overlap=0):
    """
    Generate a geopandas Geoseries object of coordinates within a region
    corresponding to the top left corner of the corrsponding patch.

    The region is expanded before checking whether points are within it such that
    it is completely covered by the points.

    :param region: shapefile opened with geopandas
    :param tile_size: size that patches will be in meters
    :param overlap: overlap of tiles in meters
    :return: geopandas geoseries of coordinates as Points
    """

    spacing = tile_size*pixel_w - overlap

    # generate uniform grid over the entire extent

    minx, miny, maxx, maxy = region.buffer(tile_size, join_style=2).total_bounds
    #minx, miny, maxx, maxy = region.total_bounds
    X, Y = np.mgrid[minx:maxx + spacing:spacing, miny:maxy + spacing:spacing]
    X, Y = X.ravel(), Y.ravel()
    points = gpd.GeoSeries(map(Point, zip(X, Y)))

    # slightly expand regions and filter out points outside of polygons
    expanded_region = region.buffer(tile_size*pixel_w/2, join_style=2)
    mask = points.within(expanded_region.loc[0])
    for i in range(1, len(expanded_region)):
        mask |= points.within(expanded_region.loc[i])
    points = points.loc[mask]

    # shift coordinates such that they are in the top left of each patch
    points = points.translate(xoff=-tile_size*pixel_w*1/2, yoff=tile_size*pixel_w*1/2)

    return points

def generate_sample_points(avalanches, region, tile_size, no_aval_ratio=0.05, n=200):
    """ Intelligently choose samples such that there is no overlap but large avalanches are covered
        Also add samples with no avalanche present

        :param avalanches: geopandas geoseries of avalanche polygons
        :param region: region in which samples are contained as geoseries
        :param tile_size: size of one sample
        :param no_aval_ratio: ratio of samples to add with no avalanche [0-1]
        :param n: number of neighbour avalanches (in geoseries order) to consider when checking distance
        :returns: geoseries of sample Points
    """
    sample_points = gpd.GeoSeries()

    # add point for each avalanche, multiple points for large avalanches
    for i in tqdm(range(0, len(avalanches)), desc="Generating Points in avalanches"):
        aval = avalanches.iloc[i]
        diff = aval.geometry
        while not diff.is_empty:
            # get point inside avalanche - not random but not centroid either
            p = diff.representative_point()

            # get difference of avalanche and square around sample point
            diff = diff.difference(p.buffer(tile_size, cap_style=3))

            # only add point if it is not too close to another (could be too close to another avalanche)
            if not (sample_points.iloc[-n:].distance(p) < tile_size).any():
                sample_points = sample_points.append(gpd.GeoSeries(p))

    # add points with no avalanche
    for i in tqdm(range(0, int(no_aval_ratio * len(avalanches))), desc='Generating points with no avalanches'):
        for j in range(0, 100): # max 100 tries
            p = get_random_point_in_region(region)

            # only add point if far enough from all avalanches
            if not (sample_points.distance(p) < tile_size).any():
                sample_points = sample_points.append(gpd.GeoSeries(p))
                break

    return sample_points

def get_random_point_in_region(region):
    """ Sample a random point within a region
        :param region: geoseries with one or multiple polygons
        :returns: random point within region
    """
    minx, miny, maxx, maxy = region.total_bounds
    while True:
        p = Point(random.uniform(minx, maxx), random.uniform(miny, maxy))
        if region.contains(p).any():
            return p


from __future__ import absolute_import, division, print_function

__metaclass__ = type

from ansible_collections.community.isva.plugins.module_utils.isva_utils import parse_fail_message, identical_files
from ansible_collections.community.isva.plugins.module_utils.common import ISVAModuleError
from ansible.module_utils.connection import Connection

import json
import logging
import os
import base64
import shutil

uri = '/isam/downloads'

logger = logging.getLogger(__name__)

MAP_API_ATTRIBUTES = {}

def from_api(source):
    data = {}
    for _, value in MAP_API_ATTRIBUTES.items():
        if value in source and source[value] is not None:
            data = source[value]

    return data

def fetch_file_downloads(module, path=None, recursive=True):
    """ This function fetch the file downloads from the appliance for a given path

    Returns:
        _type_: _description_
    """
    if path:
        target_uri = '{}/{}?recursive={}'.format(uri, path, recursive)
    else:
        target_uri = '{}?recursive={}'.format(uri, recursive)

    connection = Connection(module._socket_path)
    response = connection.send_request(path=target_uri)

    if response['code'] != 200:
        raise ISVAModuleError(parse_fail_message(response['code'], response['contents']))

    return response['contents']

def download_file_downloads(module, path, dest, remote_files={}):
    """This function will download the requested shared volume file.

    """
    target_uri = '{}/{}'.format(uri, path)
    file_path = path.split('/')

    curr_d = remote_files
    for d in file_path[1:]:  # Starting at 1 to avoid the first empty string
        curr_d = curr_d.get(d)
        if not curr_d:
            raise ISVAModuleError('The requested file does not exist {}'.format(path))

    tmp_dest = '{}{}'.format(module.tmpdir, file_path[-1])
    # Downloading file, we've no way to find out remotely if they are identical, so adding it at a temporary location.
    connection = Connection(module._socket_path)
    response = connection.download_file(path=target_uri, dest=tmp_dest)

    if not response:
        raise ISVAModuleError('Couldn\'t download the file {}/{}'.format(volume, path))

    if identical_files(module, tmp_dest, dest):  # No change to report
        return False

    shutil.copyfile(tmp_dest, dest)

    return True


import abc
import json
import logging
import math
from copy import deepcopy

# TODO: Merge code from jqGrid and this together?
from library.pandas_utils import df_nan_to_none

class DataFrameJqGrid:
    fields = []
    allow_empty = True

    pager_id = '#pager'
    url = None
    caption = None
    colmodel_overrides = {}

    @abc.abstractmethod
    def get_dataframe(self):
        pass

    def __init__(self):
        self.extra_config = {}
        self._overrides = deepcopy(self.colmodel_overrides)

    def get_override(self, field_name):
        return self._overrides.get(field_name, {})

    def get_items(self, request):
        df = self.get_dataframe()
        df = df_nan_to_none(df)  # JSON can't handle NaN
        df = self.sort_dataframe(request, df)
        (df_slice, page_number, num_pages, num_records) = self.paginate_df(request, df)
        items = self.get_dataframe_rows(df_slice)
        return page_number, num_pages, items, num_records

    def sort_dataframe(self, request, df):
        sidx = request.GET.get('sidx')
        if sidx is not None:
            ascending = not request.GET.get('sord') == 'desc'
            if sidx == 'ID':
                df = df.sort_index(ascending=ascending)
            elif sidx in df.columns:
                df = df.sort_values(sidx, ascending=ascending)
            else:
                logging.error("Request: %s asked for grid sort index (sidx) of '%s' which is not in DF!", request.GET, sidx)
        return df

    def get_paginate_by(self, request):
        rows = request.GET.get('rows', self.get_config(False)['rowNum'])
        try:
            paginate_by = int(rows)
        except ValueError:
            paginate_by = 10
        return paginate_by

    def paginate_df(self, request, df):
        paginate_by = self.get_paginate_by(request)
        if not paginate_by:
            return df, None, None, None

        page_number = int(request.GET.get('page', 1))
        num_records = len(df)
        num_pages = int(math.ceil(num_records / paginate_by))

        start = (page_number - 1) * paginate_by
        end = start + paginate_by + 1
        df_slice = df[start:end]
        return df_slice, page_number, num_pages, num_records

    def get_dataframe_rows(self, df):
        items = []
        for i, row in df.iterrows():
            data = dict(iter(row.items()))
            data['ID'] = i
            items.append(data)
        return items

    def get_json(self, request):
        page_number, num_pages, items, num_records = self.get_items(request)
        data = {
            'page': int(page_number),
            'total': int(num_pages),
            'rows': items,
            'records': int(num_records),
        }
        return json.dumps(data)

    def get_default_config(self):
        config = {
            'datatype': 'json',
            'autowidth': True,
            'forcefit': True,
            'shrinkToFit': True,
            'jsonReader': {'repeatitems': False},
            'rowNum': 10,
            'rowList': [10, 15, 20, 25, 50],
            'sortname': 'ID',
            'viewrecords': True,
            'sortorder': "asc",
            'pager': self.pager_id,
            'altRows': True,
            'gridview': True,
            'height': 'auto',
        }
        return config

    def get_url(self):
        return str(self.url)

    def get_caption(self):
        return self.caption or ''

    def get_config(self, as_json=True):
        config = self.get_default_config()
        config.update(self.extra_config)
        config.update({'url': self.get_url(),
                       'caption': self.get_caption(),
                       'colModel': self.get_colmodels()})
        if as_json:
            config = json.dumps(config)
        return config

    def add_overrides(self, colmodel, column_name):
        override = self.get_override(column_name)
        if override:
            colmodel.update(override)
        return colmodel

    def get_colmodels(self, *args, **kwargs):
        colmodels = []
        df = self.get_dataframe()
        index_colmodel = self.get_index()
        self.add_overrides(index_colmodel, index_colmodel["index"])
        colmodels.append(index_colmodel)
        for column_name in df.columns:
            column = df[column_name]
            colmodel = self.column_to_colmodel(column, column_name)
            self.add_overrides(colmodel, column_name)
            colmodels.append(colmodel)
        return colmodels

    @staticmethod
    def get_index():
        return {
            'name': 'ID',
            'index': 'ID',
            'label': 'ID',
            'editable': False
        }

    @staticmethod
    def column_to_colmodel(column, column_name):
        colmodel = {
            'name': column_name,
            'index': column_name,
            'label': column_name,
            # TODO: dtype?
            'editable': True
        }
        return colmodel


from django.db import models

# Create your models here.

class Colaborador (models.Model):
    rutColaborador= models.IntegerField(primary_key=True, verbose_name='Rut colaborador')
    imagen= models.ImageField(upload_to='img/', null=True, blank=True)
    nomColaborador= models.CharField(max_length=60, verbose_name='Nombre colaborador')
    fonoColaborador= models.IntegerField( verbose_name='Telefono colaborador')
    dirColaborador= models.CharField(max_length=60, verbose_name= 'Dirección colaborador')
    emailColaborador= models.EmailField(verbose_name='E-mail colaborador')
    paisColaborador= models.CharField(max_length=60, verbose_name='País colaborador')
    contrasenaColaborador= models.CharField(max_length=20, verbose_name='Contraseña')

    def __str__(self):
        return self.nomColaborador


from flask import Flask, request, render_template, redirect, url_for, flash
from config import Config
from flask_wtf import FlaskForm, RecaptchaField
from wtforms import SubmitField
from werkzeug.utils import secure_filename
from skimage import io
from PIL import Image
import matplotlib

matplotlib.use('Agg')
import matplotlib.pyplot as plt
import os
from pathlib import Path

class SignupForm(FlaskForm):
    recaptcha = RecaptchaField()
    submit = SubmitField(label="Submit")

ALLOWED_EXTENSIONS = set(['png', 'jpg', 'jpeg'])
UPLOAD_FOLDER = 'static/uploads/'
app = Flask(__name__)
app.config.from_object(Config)
app.config['TEMPLATES_AUTO_RELOAD'] = True
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024
my_site_key = app.config['RECAPTCHA_PUBLIC_KEY'] = '6LdSXSMgAAAAAHQgMIIoeoXxbEYRuip_zpRnLK0a'
my_private_key = app.config['RECAPTCHA_PRIVATE_KEY'] = '6LdSXSMgAAAAAP8GPoEby3vYKmEbbHInhv2eG0y3'
height, width = 400, 400

def allowed_file(filename):
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

def image_histogram(image, flag: int):
    filepath = str(Path('uploads').absolute())
    _ = plt.hist(image.ravel(), bins=256, color='orange', )
    _ = plt.hist(image[:, :, 0].ravel(), bins=256, color='red', alpha=0.5)
    _ = plt.hist(image[:, :, 1].ravel(), bins=256, color='Green', alpha=0.5)
    _ = plt.hist(image[:, :, 2].ravel(), bins=256, color='Blue', alpha=0.5)
    _ = plt.xlabel('Intensity Value')
    _ = plt.ylabel('Count')
    _ = plt.legend(['Total', 'Red_Channel', 'Green_Channel', 'Blue_Channel'])
    if flag == 0:
        plt.savefig(os.path.join(app.config['UPLOAD_FOLDER'], 'temporary.png'))
    if flag == 1:
        plt.savefig(os.path.join(app.config['UPLOAD_FOLDER'], 'temporary_resized.png'))

@app.route('/')
@app.route('/upload', methods=['GET', 'POST'])
def upload_form():
    global form
    form = SignupForm()
    return render_template('download image.html', form=form)

@app.route('/wh', methods=['POST'])
def get_values():
    global height, width
    if request.method == 'POST':
        height = int(request.form.get('height'))
        width = int(request.form.get('width'))
    print(height, width)
    return render_template('download image.html', height=height, width=width)

@app.route('/', methods=['POST'])
def upload_image():
    if form.is_submitted():
        if 'file' not in request.files:
            flash('No file part')
            return redirect(request.url)
        file = request.files['file']
        if file.filename == '':
            flash('Картинка не загружена')
            return redirect(request.url)
        if file and allowed_file(file.filename):
            filename = secure_filename(file.filename)
            file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
            image = Image.open(os.path.join(app.config['UPLOAD_FOLDER'], filename))
            print(width, height)
            image = image.resize((width, height))
            image.save(os.path.join(app.config['UPLOAD_FOLDER'], 'resized' + filename))
            file_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
            file_path_resize = os.path.join(app.config['UPLOAD_FOLDER'], 'resized' + filename)
            image_histogram(io.imread(file_path), 0)
            image_histogram(io.imread(file_path_resize), 1)
            mat_filename = 'temporary.png'
            mat_filename_resized = 'temporary_resized.png'
            # print('upload_image filename: ' + filename)
            flash('Картинка загружена и отображена ниже')
            print(height, width)
            return render_template('download image.html', filename='resized' + filename, mat_filename=mat_filename,
                                   mat_filename_resized=mat_filename_resized, height=height,
                                   width=width, my_site_key=my_site_key, form=form)
        else:
            flash('Доступны форматы jpg, jpeg, png')
            return redirect(request.url)
    else:
        return redirect(request.url)

@app.route('/display/<filename>')
def display_image(filename):
    # print('display_image filename: ' + filename)
    return redirect(url_for('static', filename='uploads/' + filename), code=301)

@app.route('/display/<mat_filename>')
def display_imagemap():
    return redirect(url_for('static', mat_filename='uploads/temporary.png'), code=301)

@app.route('/display/<mat_filename_resized>')
def display_imagemap_resized():
    return redirect(url_for('static', mat_filename='uploads/temporary_resized.png'), code=301)

if __name__ == "__main__":
    app.run(host='127.0.0.1', port=5000)


import numpy as np
import cv2
import imutils
import tkinter as tk
import tkinter.messagebox
import matplotlib.pyplot as plt
from PIL import Image, ImageTk  # Python Imaging Library
import time
import kalman
import SerialandAngle
from math import *

# 支持中文
plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号

# 初始化，平衡平板
SerialandAngle.Angle2SerPort(0.4, -0.4)

# vs = cv2.VideoCapture('BlueBal.avi')
vs = cv2.VideoCapture(1, cv2.CAP_DSHOW)
vs.set(3, 640)
vs.set(4, 480)
print("Open camera succeed.")

getPixelColor = False  # flag to get the pixel color of the ball when needed
camHeight = 640
camWidth = 480
H, S, V = 0, 0, 0  # the color properties of the Pixel to track
mouseX, mouseY = 0, 0  # declare variables to capture mouse position for color tracking

# 展示了系统控制面板
controllerWindow = tk.Tk()  # initializes this tk interpreter and creates the root window
controllerWindow.title("Ball Plate Control Window ")  # define title of the root window
controllerWindow.geometry("800x640")  # define size of the root window
controllerWindow["bg"] = "lightgrey"  # define the background color of the root window
controllerWindow.resizable(0, 0)  # define if the root window is resizable or not for Vertical and horizontal，不可以拉伸

# 主控制面板背景图片
canvas = tk.Canvas(controllerWindow, width=380, height=92, bd=0, highlightthickness=0)
image_file = tk.PhotoImage(file='C:\\Users\\50578\\working\\Ball-Tracking\\background-en.gif')
image = canvas.create_image(0, 0, anchor='nw', image=image_file)  # 放置着张图片
canvas.place(x=410, y=10)

# 展示了实时画面的控制面板
videoWindow = tk.Toplevel(controllerWindow)  # a new window derived from the root window "controllerwindow"
videoWindow.title("Live Camera")  # define title of videowindow
videoWindow.resizable(0, 0)  # Cannot resize the window
lmain = tk.Label(videoWindow)  # create an empty label widget in the videoWindow
lmain.pack()  # adjust the size of the videowindow to fit the label lmain
videoWindow.withdraw()  # hide the window

# 展示PID控制下输入输出的跟踪情况
graphWindow = tk.Toplevel(controllerWindow)  # a new window derived from the root window "graphwindow"
graphWindow.title("Position in function of time")  # define window title
graphWindow.resizable(0, 0)  # define if resizable or not
graphCanvas = tk.Canvas(graphWindow, width=500 + 200, height=515)  # create a canvas widget in graphwindow
graphCanvas.pack()  # pack the canvas widget
graphWindow.withdraw()  # hide the graphwindow

# 声明一些滑条将用到的变量
sliderHDefault = 0
sliderSDefault = 0
sliderVDefault = 0
sliderCoefPDefault = 0.028
sliderCoefIDefault = 0
sliderCoefDDefault = 0.022
sliderRadiusDefault = 20
sliderSpeedDefault = 10
sliderRefXDefault = 190
sliderRefYDefault = 190

pointsListCircle = []  # create an empty list to put points refinates that describes a circle patern

def createPointsListCircle():  # create an array of 360 points to describe a whole circle with the argument as radius
    global pointsListCircle
    pointsListCircle = []
    for angle in range(0, 360):
        angle = angle - 90
        pointsListCircle.append(
            [sliderRadius.get() * cos(radians(angle)) + 170, sliderRadius.get() * sin(radians(angle)) + 180])
    # print(pointsListCircle)

drawCircleBool = False  # flag to draw Circle

def startDrawCircle():
    # function triggered by Circle pattern Button as a Toggle
    createPointsListCircle()
    global drawCircleBool, drawEightBool, refX, refY
    if drawCircleBool == False:
        drawCircleBool = True
        BballDrawCircle["text"] = "Disable Circle Trajectory"
    else:
        drawCircleBool = False
        refX, refY = 170, 180
        # sliderCoefP.set(sliderCoefPDefault)
        BballDrawCircle["text"] = "Enable Circle Trajectory"
    resetPID()

# 球的运动轨迹是圆还是椭圆，一共分为三步
# 第一步：创建圆与椭圆的运动点列表
# 第二步：编写按键控制的bool逻辑
# 第三步：判断bool逻辑，是否要进入圆与椭圆运行状态。
pointCounter = 0  # a counter that will cover the whole 360 points in case of draw circle or eight

def drawWithBall():  # function triggered after the startDrawCircle or startDrawEight
    global pointCounter, refX, refY, pointsListCircle
    if drawCircleBool == True:
        if pointCounter >= len(pointsListCircle):
            pointCounter = 0
        point = pointsListCircle[pointCounter]
        refX, refY = point[0], point[1]
        pointCounter += sliderSpeed.get()

useKalmanBool = False

def UseKalmanJudge():  # function to judge weather use kalman filter or not.
    global useKalmanBool
    if useKalmanBool == False:
        useKalmanBool = True
        Bkalman["text"] = "Kalman Filter ON"
    else:
        useKalmanBool = False
        Bkalman["text"] = "Kalman Filter OFF"

# 验证小球运动的轨道
showCalqueCalibrationBool = False

def showCalqueCalibration():
    global showCalqueCalibrationBool
    showCalqueCalibrationBool = not showCalqueCalibrationBool

def setRefWithButton():  # set refX and refY based on the mousePosition, mousePosition is the realtime position of the mouse not a saved variable
    global refX, refY
    refX, refY = sliderRefX.get(), sliderRefY.get()
    resetPID()

# 取色笔，可以获得像素点的HSV的值
def getMouseClickPosition(mousePosition):  # get mouse click position
    global mouseX, mouseY
    global getPixelColor
    mouseX, mouseY = mousePosition.x, mousePosition.y
    getPixelColor = True

# 用鼠标设定小球的运动位置，为其设定参考点
refX = 160  # reference refinate X
refY = 180  # reference refinate Y

def setRefWithMouse(mousePosition):
    global refX, refY
    if mousePosition.y > 10:
        refreshGraph()
        refX, refY = mousePosition.x, mousePosition.y

# 左上角，实时视频窗口，控制是不是要显示
showVideoWindow = False

def showCameraFrameWindow():  # function to toggle the showVideoWindow and change the label text of the button
    global showVideoWindow, showGraph
    global BShowVideoTxt
    if showVideoWindow == False:
        # if showGraph == True:
        #    graphWindow.withdraw()
        #    showGraph = False
        #    BShowGraph["text"] = "Show Plot"
        videoWindow.deiconify()
        showVideoWindow = True
        BShowVideo["text"] = "Hide Live CAM"
    else:
        videoWindow.withdraw()
        showVideoWindow = False
        BShowVideo["text"] = "Show Live CAM"

# 控制是否显示建模图。建模图显示了给定与输入输出之间的实时关系。
showGraph = False  # bool for Graph window

def showGraphWindow():  # function that toggles the Graph window and update the show graph button
    global showGraph, showVideoWindow
    global BShowGraph

    if showGraph == False:
        # if showVideoWindow == True:
        #    videoWindow.withdraw()
        #    showVideoWindow = False
        #    BShowVideo["text"] = "Show Live CAM feed"
        showGraph = True
        BShowGraph["text"] = "Hide Plot"
    else:
        showGraph = False
        BShowGraph["text"] = "Show Plot"

t = 500  # time variable for the plotting and initialize at 480 for a good visualization
Ts = 0

def paintGraph():  # function to plot in realtime the graphWindow
    global t, refX, refY, x, y, prevX, Ts, prevY, alpha, prevAlpha
    global showGraphPositionX, showGraphPositionY, showGraphAlpha
    if showGraph == True:
        t += Ts * 100
        graphWindow.deiconify()  # 显示画面
        if showGraphPositionX.get() == 1:
            graphCanvas.create_line(t - Ts * 100, prevX, t, x, fill="#b20000", width=2)
            graphCanvas.create_line(t - Ts * 100, prevRefX, t, refX, fill="#ff7777", width=2)

        if showGraphPositionY.get() == 1:
            graphCanvas.create_line(t - Ts * 100, prevY, t, y, fill="#0069b5", width=2)
            graphCanvas.create_line(t - Ts * 100, prevRefY, t, refY, fill="#6f91f7", width=2)
        if showGraphAlpha.get() == 1:
            graphCanvas.create_line(t - Ts * 100, 240 - prevAlpha * 3, t, 240 - alpha * 3, fill="#8f0caf", width=2)
        if t >= 500:
            t = 0
            graphCanvas.delete("all")

            for i in range(4):
                graphCanvas.create_line(0, 120 * (i + 1), 500, 120 * (i + 1), fill="black", width=1)
                graphCanvas.create_line(100 * (i + 1), 0, 100 * (i + 1), 480, fill="black", width=1)

            graphCanvas.create_line(3, 3, 500, 3, fill="black", width=3)
            graphCanvas.create_line(3, 500, 500, 500, fill="black", width=3)
            graphCanvas.create_line(3, 3, 3, 500, fill="black", width=3)
            graphCanvas.create_line(500, 3, 500, 500, fill="black", width=3)
            graphCanvas.create_line(550, 32, 740, 32, fill="#b20000", width=5)
            graphCanvas.create_line(550, 53, 740, 53, fill="#0069b5", width=5)
            graphCanvas.create_line(550, 73, 740, 73, fill="#8f0caf", width=5)

    else:
        graphWindow.withdraw()

def refreshGraph():  # function that reset the time variable to 480 if the graph is full
    global t
    t = 480

# 更新圆形的路线
def radiusUpdate(self):
    createPointsListCircle()

def resetPID():  # function that compact the plate
    global totalErrorX, totalErrorY, prevErrorX, prevErrorY, prevIntegX, prevIntegY, prevDerivX, prevDerivY
    totalErrorX = 0
    totalErrorY = 0
    prevErrorX = 0
    prevErrorY = 0
    prevIntegX = 0
    prevIntegY = 0
    prevDerivX = 0
    prevDerivY = 0

# PID控制程序
totalErrorX = 0
totalErrorY = 0

alpha, beta, prevAlpha, prevBeta = 0, 0, 0, 0

prevDerivX = 0  # previous derivative
prevDerivY = 0  # previous derivative
prevIntegX = 0
prevIntegY = 0
prevErrorX = 0
prevErrorY = 0

prevBallPosX = 0
prevBallPosY = 0

delivery_time = 0

Ix, Iy = 0, 0
vec_lastx = 0
vec_lasty = 0
ballx = []
bally = []
vecxlist = []
vecylist = []
vecxFilterlist = []
vecyFilterlist = []
timelist = []
refxdraw = []

def PIDcontrol(ballPosX, ballPosY, refX, refY):
    global totalErrorX, totalErrorY
    global alpha, beta, prevAlpha, prevBeta
    global Ts, delivery_time
    global prevDerivX, prevDerivY, prevIntegX, prevIntegY
    global prevErrorX, prevErrorY, Ix, Iy, prevY, prevX, vec_lastx, vec_lasty
    global vecxlist, vecylist, timelist, vecxFilterlist, vecyFilterlist
    global ballx, bally, refxdraw

    Kp = sliderCoefP.get()
    Ki = sliderCoefI.get()
    Kd = sliderCoefD.get()

    Ts = time.time() - delivery_time  # sampling time
    delivery_time = time.time()

    errorX = refX - ballPosX
    errorY = refY - ballPosY
    # print('curPosx:', ballPosX, 'curPosy:',ballPosY)

    # 使用PD控制器，I这一项完全为零
    Cix = Ki * totalErrorX  # prevIntegX + errorX*Ki*Ts                    #Ki * totalErrorX
    Ciy = Ki * totalErrorY  # prevIntegY + errorY*Ki*Ts                    #Ki * totalErrorX

    Cdx = Kd * (0.25 * vec_lastx + 0.75 * ((prevX - ballPosX) / Ts))
    Cdy = Kd * (0.25 * vec_lasty + 0.75 * ((prevY - ballPosY) / Ts))

    # 绘制速度曲线
    print(time.time())
    timelist.append(time.time())
    # vecxlist.append(((prevX - ballPosX) / Ts))
    # vecylist.append(((prevY - ballPosY) / Ts))
    # vecxFilterlist.append((0.25 * vec_lastx + 0.75 * ((prevX - ballPosX) / Ts)))
    # vecyFilterlist.append((0.25 * vec_lasty + 0.75 * ((prevY - ballPosY) / Ts)))

    # 绘制小球运动路线轨迹
    ballx.append(ballPosX)
    bally.append(ballPosY)
    refxdraw.append(refX)

    vec_lastx = (prevX - ballPosX) / Ts
    vec_lasty = (prevY - ballPosY) / Ts

    # print('vec:', ((prevX - ballPosX) / Ts), ((prevY - ballPosY) / Ts))

    Ix = Kp * errorX + Cix + Cdx
    Iy = Kp * errorY + Ciy + Cdy
    # print('errorX:', errorX,'X:', 'P:', Kp * errorX, 'I:', Cix, 'D:', Cdx, 'outputX:', Ix)
    # print('errorY:', errorY,'Y:', 'P:', Kp * errorY, 'I:', Ciy, 'D:', Cdy, 'outputY:', Iy,'\n')

    if (Ix < 0 and Iy < 0) or (Ix > 0 and Iy > 0):
        SerialandAngle.Angle2SerPort(-Ix + 0.4, -Iy - 0.4)
    else:
        SerialandAngle.Angle2SerPort(Ix + 0.4, Iy - 0.4)

    prevDerivX = Cdx
    prevDerivY = Cdy
    prevIntegX = Cix
    prevIntegY = Ciy
    prevErrorX = errorX
    prevErrorY = errorY

    prevX = ballPosX
    prevY = ballPosY

    return Ix, Iy

def drawVecPlot():
    global vecxlist, vecylist, timelist, vecxFilterlist, vecyFilterlist
    global ballx, bally, refxdraw

    plt.xlabel("x/像素点")  # x轴上的名字
    plt.ylabel("y/像素点")  # y轴上的名字

    # plt.plot(timelist, vecxlist,linestyle='--',label='没有滤波的速度曲线')
    # plt.plot(timelist, vecxFilterlist,label='加入滤波算法后的速度曲线')

    plt.plot(ballx, bally,label='小球运动轨迹')

    # plt.plot(timelist, ballx, linestyle='--', label='随时间变化x轴运动轨迹')
    # plt.plot(timelist, refxdraw, label='参考轨迹曲线')

    plt.legend()
    plt.show()

# 退出interface
def endProgam():
    drawVecPlot()
    SerialandAngle.ser.close()
    controllerWindow.destroy()

# function that does nothing, may be used for delay
def donothing():
    pass

prevX, prevY = 0, 0
prevRefX, prevRefY = 0, 0

def main():
    global H, S, V
    global getPixelColor
    global refX, refY, totalErrorX, totalErrorY
    global x, y, alpha, beta, Ix, Iy
    global prevX, prevY, prevAlpha, prevBeta, prevRefX, prevRefY
    global camWidth, camHeight

    _, frame = vs.read()
    frame = frame[70:420, 160:480]

    # print(camHeight,((camWidth - camHeight) / 2),(camWidth - ((camWidth - camHeight) / 2)))
    blurred = cv2.GaussianBlur(frame, (11, 11), 0)
    hsv = cv2.cvtColor(blurred, cv2.COLOR_BGR2HSV)

    # 相当于取色笔
    if getPixelColor == True and mouseY > 0 and mouseY < 720 and mouseX < 720:
        pixelColorOnClick = frame[mouseY, mouseX]
        pixelColorOnClick = np.uint8([[pixelColorOnClick]])
        pixelColorOnClick = cv2.cvtColor(pixelColorOnClick, cv2.COLOR_BGR2HSV)
        H = pixelColorOnClick[0, 0, 0]
        S = pixelColorOnClick[0, 0, 1]
        V = pixelColorOnClick[0, 0, 2]
        print(mouseX, mouseY)
        # print(H, S, V)
        getPixelColor = False

    # 银质绿面小球
    greenLower = (43 - sliderLH.get(), 30 - sliderLS.get(), 140 - sliderLV.get())
    greenUpper = (105 + sliderUH.get(), 160 + sliderUS.get(), 255 + sliderUV.get())

    mask_before = cv2.inRange(hsv, greenLower, greenUpper)
    mask_erode = cv2.erode(mask_before, None, iterations=2)
    mask = cv2.dilate(mask_erode, None, iterations=2)
    # cv2.imshow('mask_before', mask_before)
    # cv2.imshow('mask_erode', mask_erode)
    # cv2.imshow('mask', mask)

    cnts = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    cnts = imutils.grab_contours(cnts)
    center = None

    cv2.circle(frame, (int(refX), int(refY)), int(4), (255, 0, 0), 2)
    if showCalqueCalibrationBool == True:
        cv2.circle(frame, (240, 240), 220, (255, 0, 0), 2)
        cv2.circle(frame, (240, 240), 160, (255, 0, 0), 2)
        cv2.line(frame, (240, 240), (240, 240 + 160), (255, 0, 0), 2)
        cv2.line(frame, (240, 240), (240 + 138, 240 - 80), (255, 0, 0), 2)
        cv2.line(frame, (240, 240), (240 - 138, 240 - 80), (255, 0, 0), 2)

    if len(cnts) > 0:
        c = max(cnts, key=cv2.contourArea)
        ((x, y), radius) = cv2.minEnclosingCircle(c)
        M = cv2.moments(c)
        center = (int(M["m10"] / M["m00"]), int(M["m01"] / M["m00"]))
        center_float = (M["m10"] / M["m00"], M["m01"] / M["m00"])
        # 添加一步滤波，因为当接收到的数据，在1~2个像素点的误差内剧烈抖动时，会对系统的控制输出造成很大的影响。
        a = x
        d = y
        if radius > 10:
            cv2.putText(frame, str(int(x)) + ";" + str(int(y)).format(0, 0), (int(x) - 50, int(y) - 50),
                        cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2)
            cv2.circle(frame, (int(x), int(y)), int(radius), (0, 255, 255), 2)
            cv2.circle(frame, center, 5, (0, 0, 255), -1)
            # if useKalmanBool == False:
            # 这里其实是kalman的两种算法
            #     a, b, c, d = kalman_new.kalman(np.mat(center_float[0]))
            #     d, e, f, g = kalman_new.kalman(np.mat(center_float[1]))
            #     a, b = kalman.updatePisiton(x, Ix)
            #     d, e = kalman.updatePisiton(y, Iy)

            # PIDcontrol(int(a), int(d), refX, refY)
        else:
            totalErrorX, totalErrorY = 0, 0
    else:
        SerialandAngle.Angle2SerPort(0.4, -0.4)

    if showVideoWindow == True:
        frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)  # 转换颜色从BGR到RGB
        frame = Image.fromarray(frame)  # 将图像转换成Image对象
        imgtk = ImageTk.PhotoImage(image=frame)
        lmain.imgtk = imgtk
        lmain.configure(image=imgtk)

    # 延迟20ms之后，进入主程序，从而形成循环。
    lmain.after(20, main)
    # 查询是否要画圆和椭圆
    drawWithBall()
    paintGraph()

    prevRefX, prevRefY = refX, refY
    prevAlpha = alpha
    prevBeta = beta

'''
可以控制并改变HSV的上下值范围。
*************
here  **
      **
*************
      **
      **
*************
'''
FrameVideoControl = tk.LabelFrame(controllerWindow, text="Identify Control Panel")
FrameVideoControl.place(x=10, y=10, width=390, height=550)
EmptyLabel = tk.Label(FrameVideoControl)
EmptyLabel.pack()
BShowVideo = tk.Button(FrameVideoControl, text="Show Live CAM", command=showCameraFrameWindow)
BShowVideo.place(x=120, y=0)
BPositionCalibration = tk.Button(FrameVideoControl, text="Toggle Calibration View", command=showCalqueCalibration)
BPositionCalibration.place(x=230, y=0)

sliderUH = tk.Scale(FrameVideoControl, from_=-50, to=50, orient="horizontal", label="upper H", length=350,
                    tickinterval=10)
sliderUH.set(sliderHDefault)
sliderUH.place(x=15, y=30)
sliderUS = tk.Scale(FrameVideoControl, from_=-50, to=50, orient="horizontal", label="upper S", length=350,
                    tickinterval=10)
sliderUS.set(sliderSDefault)
sliderUS.place(x=15, y=107)
sliderUV = tk.Scale(FrameVideoControl, from_=-50, to=50, orient="horizontal", label="upper V", length=350,
                    tickinterval=10)
sliderUV.set(sliderVDefault)
sliderUV.place(x=15, y=184)

sliderLH = tk.Scale(FrameVideoControl, from_=-50, to=50, orient="horizontal", label="lower H", length=350,
                    tickinterval=10)
sliderLH.set(sliderHDefault)
sliderLH.place(x=15, y=261)
sliderLS = tk.Scale(FrameVideoControl, from_=-50, to=50, orient="horizontal", label="lower S", length=350,
                    tickinterval=10)
sliderLS.set(sliderSDefault)
sliderLS.place(x=15, y=338)
sliderLV = tk.Scale(FrameVideoControl, from_=-50, to=50, orient="horizontal", label="lower V", length=350,
                    tickinterval=10)
sliderLV.set(sliderVDefault)
sliderLV.place(x=15, y=415)
'''
系统控制，实现退出，连接等功能。
*************
      **
      **
*************
 here **
      **
*************
'''
FrameServosControl = tk.LabelFrame(controllerWindow, text="System Control")
FrameServosControl.place(x=10, y=570, width=390, height=63)
BQuit = tk.Button(FrameServosControl, text="Program Quit", command=endProgam)
BQuit.place(x=75, y=5)
# BQuit.pack()
Bkalman = tk.Button(FrameServosControl, text="Kalman Filter On", command=UseKalmanJudge)
Bkalman.place(x=185, y=5)

'''
控制PID参数
*************
      ** here
      **
*************
      **
      **
*************
'''

FramePIDCoef = tk.LabelFrame(controllerWindow, text="PID coefficients")
FramePIDCoef.place(x=410, y=112, width=380, height=310)
BShowGraph = tk.Button(FramePIDCoef, text="Plot on Graph", command=showGraphWindow)
BShowGraph.pack()
sliderCoefP = tk.Scale(FramePIDCoef, from_=0, to=0.1, orient="horizontal", label="P", length=350, tickinterval=0.01,
                       resolution=0.001)
sliderCoefP.set(sliderCoefPDefault)
sliderCoefP.pack()
sliderCoefI = tk.Scale(FramePIDCoef, from_=0, to=0.1, orient="horizontal", label="I", length=350, tickinterval=0.01,
                       resolution=0.001)
sliderCoefI.set(sliderCoefIDefault)
sliderCoefI.pack()
sliderCoefD = tk.Scale(FramePIDCoef, from_=0, to=0.1, orient="horizontal", label="D", length=350, tickinterval=0.01,
                       resolution=0.001)
sliderCoefD.set(sliderCoefDDefault)
sliderCoefD.pack()
'''
这一块是小球轨迹的控制程序，可以实现小球稳定在球面中心，画圆形，画8字型
*************
      **
      **
*************
      ** here
      **
*************
'''
FrameBallControl = tk.LabelFrame(controllerWindow, text="Ball Control")
FrameBallControl.place(x=410, y=432, width=380, height=200)

sliderRadius = tk.Scale(FrameBallControl, from_=0, to=300, orient="horizontal", label="Radius", length=350,
                        tickinterval=50, resolution=1, command=radiusUpdate)
sliderRadius.set(sliderRadiusDefault)
sliderRadius.pack()
sliderSpeed = tk.Scale(FrameBallControl, from_=0, to=20, orient="horizontal", label="Speed", length=350, tickinterval=1,
                       resolution=1)
sliderSpeed.set(sliderSpeedDefault)
sliderSpeed.pack()
BballDrawCircle = tk.Button(FrameBallControl, text="Enable Circle Trajectory", command=startDrawCircle)
BballDrawCircle.place(x=215, y=0)

showGraphPositionX = tk.IntVar()
showGraphPositionX.set(1)
CheckbuttonPositionX = tk.Checkbutton(graphWindow, text="X Position", variable=showGraphPositionX, command=refreshGraph)
CheckbuttonPositionX.place(x=520, y=20)
showGraphPositionY = tk.IntVar()
showGraphPositionY.set(1)
CheckbuttonPositionY = tk.Checkbutton(graphWindow, text="Y Position", variable=showGraphPositionY, command=refreshGraph)
CheckbuttonPositionY.place(x=520, y=40)
showGraphAlpha = tk.IntVar()
CheckbuttonAlpha = tk.Checkbutton(graphWindow, text="Plate Inclination", variable=showGraphAlpha, command=refreshGraph)
CheckbuttonAlpha.place(x=520, y=60)
sliderRefX = tk.Scale(graphWindow, from_=0, to=480, orient="horizontal", label="RefX", length=150,
                      tickinterval=100)
sliderRefX.set(sliderRefXDefault)
sliderRefX.place(x=520, y=100)
sliderRefY = tk.Scale(graphWindow, from_=0, to=480, orient="horizontal", label="RefY", length=150,
                      tickinterval=100)
sliderRefY.set(sliderRefYDefault)
sliderRefY.place(x=520, y=200)
BsetReference = tk.Button(graphWindow, text="Set Ref", command=setRefWithButton)
BsetReference.place(x=520, y=350)
# Blog = tk.Button(graphWindow, text="Write Log", command=startLog)
# Blog.place(x=520, y=370)

# 获取鼠标的位置，转换成像素值。
# https://www.cnblogs.com/progor/p/8505599.html
videoWindow.protocol("WM_DELETE_WINDOW", donothing)
videoWindow.bind("<Button-3>", getMouseClickPosition)
videoWindow.bind("<Button-1>", setRefWithMouse)  # mouse click to set reference position

main()
tk.mainloop()


from django.shortcuts import render, redirect, get_object_or_404
from django.http import HttpResponseNotAllowed
from django.utils.timezone import make_naive

from webapp.models import Shop
from .forms import ShopForm

def index_view(request):
    data = Shop.objects.all()
    return render(request, 'index.html', context={
        'articles': data
    })

def shop_view(request, pk):
    shop = get_object_or_404(Shop, pk=pk)

    context = {'shop': shop}
    return render(request, 'shop_view.html', context)

def shop_create_view(request):
    if request.method == "GET":
        form = ShopForm()
        return render(request, 'shop_create.html', context={
            'form': form
        })
    elif request.method == 'POST':
        form = ShopForm(data=request.POST)
        if form.is_valid():
            shop = Shop.objects.create(
                name=form.cleaned_data['name'],
                description=form.cleaned_data['description'],
                category=form.cleaned_data['category'],
                amount=form.cleaned_data['amount'],
                price=form.cleaned_data['price']
            )
            return redirect('shop_view', pk=shop.pk)
        else:
            return render(request, 'shop_create.html', context={
                'form': form
            })
    else:
        return HttpResponseNotAllowed(permitted_methods=['GET', 'POST'])

def shop_update_view(request, pk):
    shop = get_object_or_404(Shop, pk=pk)
    if request.method == "GET":
        form = ShopForm(initial={
            'name': shop.name,
            'description': shop.description,
            'category': shop.category,
            'amount': shop.amount,
            # форматирование перед выводом для DateTime.
            'price': make_naive(shop.price)\
                .strftime(BROWSER_DATETIME_FORMAT)
            # для дат выглядит просто как:
            # 'price': shop.price
        })
        return render(request, 'shop_update.html', context={
            'form': form,
            'shop': shop
        })
    elif request.method == 'POST':
        form = ShopForm(data=request.POST)
        if form.is_valid():
            # Shop.objects.filter(pk=pk).update(**form.cleaned_data)
            shop.name = form.cleaned_data['name']
            shop.description = form.cleaned_data['description']
            shop.category = form.cleaned_data['category']
            shop.amount = form.cleaned_data['amount']
            shop.price = form.cleaned_data['price']
            shop.save()
            return redirect('shop_view', pk=shop.pk)
        else:
            return render(request, 'shop_update.html', context={
                'shop': shop,
                'form': form
            })
    else:
        return HttpResponseNotAllowed(permitted_methods=['GET', 'POST'])

def shop_delete_view(request, pk):
    shop = get_object_or_404(Shop, pk=pk)
    if request.method == 'GET':
        return render(request, 'shop_delete.html', context={'shop': shop})
    elif request.method == 'POST':
        shop.delete()
        return redirect('index')
    else:
        return HttpResponseNotAllowed(permitted_methods=['GET', 'POST'])


import pymongo
import sys

def main():
	connection = pymongo.MongoClient("mongodb://localhost",safe=True)
	db = connection.m101
	people = db.people

	person = {"name":"Joe Biden", "role":"Vice President", "address":{"address1":"The White House","street":"1600 Pennsylvania Avenue","state":"DC","city":"Washington"}, "interests":["government","baseball","debates"]}
	people.insert(person)

main()


"""
A widget showing the current week day and date.
"""

import widgets as wd
from datetime import datetime, timedelta

BACKGROUND = wd.Color.rgb(255/255, 250/255, 227/255)
FOREGROUND = wd.Color.rgb(75/255, 72/255, 55/255)

class DateProvider(wd.TimelineProvider):

    def timeline(self):
        today = datetime.today()
        today = datetime.combine(today, datetime.min.time())

        dates = []
        for i in range(30):
            date = today + timedelta(days=i)
            dates.append(date)

        return dates

    def widget(self, date):
        widget = wd.Widget()
        layout = widget.medium_layout

        date_text = wd.DynamicDate(
            date=date,
            font=wd.Font("AmericanTypewriter", 18),
            color=FOREGROUND,
            padding=wd.PADDING_ALL)

        layout.add_vertical_spacer()
        layout.add_row([date_text])
        layout.set_background_color(BACKGROUND)
        layout.set_link(date.ctime())

        return widget

if wd.link is not None:
    print(wd.link)
else:
    wd.provide_timeline(DateProvider())


from __future__ import print_function, division
from keras.datasets import mnist
from keras.layers.advanced_activations import LeakyReLU
from keras.layers.convolutional import UpSampling2D, Conv2D
from keras.models import Sequential, Model
from keras.optimizers import Adam
import matplotlib.pyplot as plt
import numpy as np

from keras.layers import Input, Dense, Reshape, Flatten, Dropout, multiply, GaussianNoise
from keras.layers import BatchNormalization, Activation, Embedding, ZeroPadding2D
from keras.layers import MaxPooling2D, concatenate
from keras import losses
from keras.utils import to_categorical
import keras.backend as K

import tensorflow as tf
import os
# 최신 Windows Laptop에서만 사용할것.CPU Version이 높을때 사용.
# AVX를 지원하는 CPU는 Giuthub: How to compile tensorflow using SSE4.1, SSE4.2, and AVX.
# Ubuntu와 MacOS는 지원하지만 Windows는 없었음. 2018-09-29
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'

# Compuntational Graph Initialization
from tensorflow.python.framework import ops
ops.reset_default_graph()

# 13.	(option) Model Save path define and Initialization
LOG_DIR_Model = "/tmp/ML/13_Generative_Adversarial_Network/BidirectionalGAN/Model"
LOG_DIR_Graph = "/tmp/ML/13_Generative_Adversarial_Network/BidirectionalGAN/Graph"

Print_Cycle = 20

class BIGAN():
    def __init__(self):
        self.img_rows = 28
        self.img_cols = 28
        self.channels = 1
        self.img_shape = (self.img_rows, self.img_cols, self.channels)
        self.latent_dim = 100

        optimizer = Adam(0.0002, 0.5)

        # Build and compile the discriminator
        self.discriminator = self.build_discriminator()
        self.discriminator.compile(loss=['binary_crossentropy'],
            optimizer=optimizer,
            metrics=['accuracy'])

        # Build the generator
        self.generator = self.build_generator()

        # Build the encoder
        self.encoder = self.build_encoder()

        # The part of the bigan that trains the discriminator and encoder
        self.discriminator.trainable = False

        # Generate image from sampled noise
        z = Input(shape=(self.latent_dim, ))
        img_ = self.generator(z)

        # Encode image
        img = Input(shape=self.img_shape)
        z_ = self.encoder(img)

        # Latent -> img is fake, and img -> latent is valid
        fake = self.discriminator([z, img_])
        valid = self.discriminator([z_, img])

        # Set up and compile the combined model
        # Trains generator to fool the discriminator
        self.bigan_generator = Model([z, img], [fake, valid])
        self.bigan_generator.compile(loss=['binary_crossentropy', 'binary_crossentropy'],
            optimizer=optimizer)

    def build_encoder(self):
        model = Sequential()

        model.add(Flatten(input_shape=self.img_shape))
        model.add(Dense(512))
        model.add(LeakyReLU(alpha=0.2))
        model.add(BatchNormalization(momentum=0.8))
        model.add(Dense(512))
        model.add(LeakyReLU(alpha=0.2))
        model.add(BatchNormalization(momentum=0.8))
        model.add(Dense(self.latent_dim))

        model.summary()

        img = Input(shape=self.img_shape)
        z = model(img)

        return Model(img, z)

    def build_generator(self):
        model = Sequential()

        model.add(Dense(512, input_dim=self.latent_dim))
        model.add(LeakyReLU(alpha=0.2))
        model.add(BatchNormalization(momentum=0.8))
        model.add(Dense(512))
        model.add(LeakyReLU(alpha=0.2))
        model.add(BatchNormalization(momentum=0.8))
        model.add(Dense(np.prod(self.img_shape), activation='tanh'))
        model.add(Reshape(self.img_shape))

        model.summary()

        z = Input(shape=(self.latent_dim,))
        gen_img = model(z)

        return Model(z, gen_img)

    def build_discriminator(self):

        z = Input(shape=(self.latent_dim, ))
        img = Input(shape=self.img_shape)
        d_in = concatenate([z, Flatten()(img)])

        model = Dense(1024)(d_in)
        model = LeakyReLU(alpha=0.2)(model)
        model = Dropout(0.5)(model)
        model = Dense(1024)(model)
        model = LeakyReLU(alpha=0.2)(model)
        model = Dropout(0.5)(model)
        model = Dense(1024)(model)
        model = LeakyReLU(alpha=0.2)(model)
        model = Dropout(0.5)(model)
        validity = Dense(1, activation="sigmoid")(model)

        return Model([z, img], validity)

    def train(self, N_EPISODES, batch_size=128, sample_interval=50):

        # Load the dataset
        (X_train, _), (_, _) = mnist.load_data()

        # Rescale -1 to 1
        X_train = (X_train.astype(np.float32) - 127.5) / 127.5
        X_train = np.expand_dims(X_train, axis=3)

        # Adversarial ground truths
        valid = np.ones((batch_size, 1))
        fake = np.zeros((batch_size, 1))

        for episode in range(N_EPISODES):

            # ---------------------
            #  Train Discriminator
            # ---------------------

            # Sample noise and generate img
            z = np.random.normal(size=(batch_size, self.latent_dim))
            imgs_ = self.generator.predict(z)

            # Select a random batch of images and encode
            idx = np.random.randint(0, X_train.shape[0], batch_size)
            imgs = X_train[idx]
            z_ = self.encoder.predict(imgs)

            # Train the discriminator (img -> z is valid, z -> img is fake)
            d_loss_real = self.discriminator.train_on_batch([z_, imgs], valid)
            d_loss_fake = self.discriminator.train_on_batch([z, imgs_], fake)
            d_loss = 0.5 * np.add(d_loss_real, d_loss_fake)

            # ---------------------
            #  Train Generator
            # ---------------------

            # Train the generator (z -> img is valid and img -> z is is invalid)
            g_loss = self.bigan_generator.train_on_batch([z, imgs], [valid, fake])

            # Plot the progress
            if (episode+1) % Print_Cycle == 0:
                print ("[Episodes: %6d] [D loss: %3.6f, acc.: %.2f%%] [G loss: %3.6f]" % (episode+1, d_loss[0], 100*d_loss[1], g_loss[0]))

            # If at save interval => save generated image samples
            if (episode+1) % sample_interval == 0:
                self.save_model()
                self.sample_interval(episode)

    def sample_interval(self, episode):
        _row, _column = 5, 5
        z = np.random.normal(size=(25, self.latent_dim))
        gen_imgs = self.generator.predict(z)
        # Rescale images 0 - 1
        gen_imgs = 0.5 * gen_imgs + 0.5

        fig, axs = plt.subplots(_row, _column)
        _count = 0
        for i in range(_row):
            for j in range(_column):
                axs[i,j].imshow(gen_imgs[_count,:,:,0], cmap='gray')
                axs[i,j].axis('off')
                _count += 1
        fig.savefig(LOG_DIR_Graph + "/%d.png" % (episode+1))
        plt.close()

    def save_model(self):

        def save(model, model_name):
            model_path = LOG_DIR_Model + "/%s.json" % model_name
            weights_path = LOG_DIR_Model + "/%s_weights.hdf5" % model_name
            options = {"file_arch": model_path,
                        "file_weight": weights_path}
            json_string = model.to_json()
            open(options['file_arch'], 'w').write(json_string)
            model.save_weights(options['file_weight'])

        save(self.generator, "generator")
        save(self.discriminator, "discriminator")

if __name__ == '__main__':

    if not os.path.exists(LOG_DIR_Model):
        os.makedirs(LOG_DIR_Model)
    if not os.path.exists(LOG_DIR_Graph):
        os.makedirs(LOG_DIR_Graph)

    bigan = BIGAN()
    bigan.train(N_EPISODES=5000, batch_size=32, sample_interval=200)


import pkgutil
import koebe.graphics.js.js
from IPython.display import display
from IPython.core.magics.display import Javascript

# For sending data to the JavaScript part
import json #json.dumps(obj)

### STYLE HANDLING

def makeStyle(stroke = None, strokeWeight = 1, fill = None):
    return {"stroke":       stroke,
            "strokeWeight": strokeWeight,
            "fill":         fill}

class DefaultStyles:

    RED_STROKE = makeStyle(stroke = "#ff0000", strokeWeight = 1)
    GREEN_STROKE = makeStyle(stroke = "#00ff00", strokeWeight = 1)
    BLUE_STROKE = makeStyle(stroke = "#0000ff", strokeWeight = 1)

    RED_FILL = makeStyle(fill = "#ff0000")
    GREEN_FILL = makeStyle(fill = "#00ff00")
    BLUE_FILL = makeStyle(fill = "#0000ff")

class VertexColoredTriangle:
    def __init__(self, p1, p2, p3, color1, color2, color3):
        self.p1 = p1
        self.p2 = p2
        self.p3 = p3
        self.color1 = color1
        self.color2 = color2
        self.color3 = color3
    def to_dict(self):
        return {"type": "VertexColoredTriangle",
                "p1":   tuple(self.p1),
                "p2":   tuple(self.p2),
                "p3":   tuple(self.p3),
                "color1": self.color1,
                "color2": self.color2,
                "color3": self.color3}

class Viewer:

    def __init__(self, width, height, scale, jsSketchFile, SketchClass, obj_json_convert_func):
        viewer_code = pkgutil.get_data("koebe.graphics.js.js", jsSketchFile).decode("utf8")
        display(Javascript(viewer_code))
        self._sketch = SketchClass(width=width, height=height, scale=scale)
        self._objs   = []
        self._anim   = []
        self._styles = {}
        self.obj_json_convert_func = obj_json_convert_func

    def _updateJson(self):
        self._sketch.objects = self._toJson()
        self._sketch.objectsDirty = True

    def update(self):
        self._updateJson()

    def setStyle(self, obj, style):
        self._styles[id(obj)] = style

    def setStyles(self, objs, style):
        for obj in objs:
            self.setStyle(obj, style)

    def getStyle(self, obj):
        if id(obj) in self._styles:
            return self._styles[id(obj)]
        else:
            return None

    def show(self):
        self._updateJson()
        display(self._sketch)

    def add(self, obj, style = None):
        self._objs.append(obj)
        if (style != None):
            self.setStyle(obj, style)

    def addAll(self, objs):
        for obj in objs:
            if isinstance(obj, tuple):
                self._objs.append(obj[0])
                self.setStyle(obj[0], obj[1])
            else:
                self._objs.append(obj)

    def pushAnimFrame(self):
        self._anim.append(self._objs)
        self._objs = []

    def _toJson(self):
        frames = self._anim + [self._objs]
        return json.dumps(
            [[d for d in [self.obj_json_convert_func(o, self.getStyle(o)) for o in frame] if not d == None]
             for frame in frames]
        )


import torch

def count_parameters(model, trainable_only=True):

    if trainable_only:
        if len(list(model.parameters())) > 0:
            params = sum(p.numel() for p in model.parameters() if p.requires_grad)
        else:
            params = 0
    else:
        if len(list(model.parameters())) > 0:
            params = sum(p.numel() for p in model.parameters())
        else:
            params = 0

    return params

def center_crop(x: torch.Tensor, length: int):
    start = (x.shape[-1] - length) // 2
    stop = start + length
    return x[..., start:stop]

def causal_crop(x: torch.Tensor, length: int):
    stop = x.shape[-1] - 1
    start = stop - length
    return x[..., start:stop]

def restore_from_0to1(x: torch.Tensor, min_val: float, max_val: float):
    """Restore tensor back to the original range assuming they have been normalized on (0,1)

    Args:
        x (torch.Tensor): Tensor with normalized values on (0,1).
        min_val (float): Minimum value in the original range.
        max_val (float): Maximum value in the original range.

    Returns:
        y (torch.Tensor): Tensor with denormalized values on (min_val, max_val).
    """
    return (x * (max_val - min_val)) + min_val

def scale_to_0to1(x: torch.Tensor, min_val: float, max_val: float):
    """Scale tensor to 0 to 1 given the supplied min-max range.

    Args:
        x (torch.Tensor): Tensor with normalized values on (0,1).
        min_val (float): Minimum value in the original range.
        max_val (float): Maximum value in the original range.

    Returns:
        y (torch.Tensor): Tensor with normalized values on (0, 1).
    """
    return (x - min_val) / (max_val - min_val)


from selenium import webdriver
from selenium.webdriver.common.by import By
from webdriver_manager.firefox import GeckoDriverManager
from selenium.webdriver.common.keys import Keys
import time
import json

players_url = []
driver = webdriver.Firefox(executable_path=GeckoDriverManager().install())
driver.get("https://www.premierleague.com/players")
driver.maximize_window()
time.sleep(10)

try:
    driver.find_element(By.CSS_SELECTOR,"#onetrust-accept-btn-handler").click()
    time.sleep(10)
    driver.find_element(By.CSS_SELECTOR,"#advertClose").click()

except:
    print("Element does not exist")

for nu in range(1,21):
    try:
        driver.find_element(By.CSS_SELECTOR,"#onetrust-accept-btn-handler").click()
    except:
        print("Element does not exist")

    driver.find_element(By.CSS_SELECTOR, ".mobile > .current").click()
    driver.find_element(By.CSS_SELECTOR, ".mobile li:nth-child({})".format(nu)).click()
    print("clicked")
    time.sleep(5)

    SCROLL_PAUSE_TIME = 0.5

    # Get scroll height
    last_height = driver.execute_script("return document.body.scrollHeight")

    while True:
        # Scroll down to bottom
        driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")

        # Wait to load page
        time.sleep(SCROLL_PAUSE_TIME)

        # Calculate new scroll height and compare with last scroll height
        new_height = driver.execute_script("return document.body.scrollHeight")
        if new_height == last_height:
            break
        last_height = new_height

    # playerElements = driver.find_elements(By.CSS_SELECTOR,".dataContainer .playerName")
    playerElements = driver.find_elements(By.CSS_SELECTOR, 'a.playerName')

    print(len(playerElements))
    for elem in playerElements:
        try:
            print(elem.get_attribute('href'))
            players_url.append(elem.get_attribute('href'))
        except:
            print("no url")
    time.sleep(5)

mydict={}
for index, i in enumerate(players_url):
    mydict[index]=f"{i}"

with open('players.json', 'w') as fp:
    json.dump(mydict, fp)

print(players_url)
print(len(players_url))
driver.quit()