from django.shortcuts import render_to_response
from django.template import RequestContext
from PsirtPageAnalyzer.models import BusinessUnit

# Create your views here.

def index(request):
    alphaTbl = "abcdefghijklmnopqrstuvwxyz"
    bus = BusinessUnit.objects.all()
    bu_list = [bu.to_json() for bu in bus]
    for index in range(len(bu_list)):
        bu_list[index]["radioname"] = "radionname-" +alphaTbl[index] # this is werid process only for UI displaying

    return render_to_response('PsirtPageAnalyzer/index.html',
                              {"bsus":bu_list},
                              context_instance=RequestContext(request))


import gradio as gr
import numpy as np
from ultralytics import YOLO
import cv2
import matplotlib.pyplot as plt
from omegaconf import OmegaConf
import torch
import os

import sys
sys.path.append('lama-with-refiner')
from saicinpainting.evaluation.refinement import refine_predict
from saicinpainting.training.trainers import load_checkpoint

def get_inpaint_model():
    predict_config = OmegaConf.load('lama-with-refiner/configs/prediction/default.yaml')
    predict_config.model.path = 'big-lama'
    predict_config.refiner.gpu_ids = '0'

    device = torch.device(predict_config.device)
    train_config_path = os.path.join(predict_config.model.path, 'config.yaml')

    train_config = OmegaConf.load(train_config_path)
    train_config.training_model.predict_only = True
    train_config.visualizer.kind = 'noop'

    checkpoint_path = os.path.join(predict_config.model.path,
                                   'models',
                                   predict_config.model.checkpoint)

    model = load_checkpoint(train_config, checkpoint_path, strict=False, map_location='cpu')
    model.freeze()
    model.to(device)
    return model,predict_config

model = YOLO("yolov8x-seg.pt")
inpaint_model,predict_config = get_inpaint_model()

import gradio as gr
import numpy as np
from ultralytics import YOLO
import cv2
import matplotlib.pyplot as plt
from omegaconf import OmegaConf
import torch
import os
from scipy.ndimage import gaussian_filter

import sys
sys.path.append('lama-with-refiner')
from saicinpainting.evaluation.refinement import refine_predict
from saicinpainting.training.trainers import load_checkpoint

id2objects = {}
segment_masks = None

def process_classes(results):
    global segment_masks
    global id2objects
    segment_masks = None
    segment_masks = results[0].masks.data.cpu().numpy()
    classes = results[0].boxes.cls.cpu().numpy()
    conf = results[0].boxes.conf.cpu().numpy()
    dec = results[0].names
    id2objects = {}

    for i in range(len(classes)):
        id2objects[i] = dec[classes[i]], round(conf[i], 2)
    s = ""
    for k, v in id2objects.items():
        s += f"{k}: {v[0]} {str(v[1])}\n"
    return s

def get_mask(img):
    img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
    cv2.imwrite("test_img.jpg", img)

    results = model.predict(img)

    img = results[0].plot({'line_width': False, 'boxes': False, 'conf': True, 'labels': True})
    return img, process_classes(results)

def ceil_modulo(x, mod):
    if x % mod == 0:
        return x
    return (x // mod + 1) * mod

def pad_img_to_modulo(img, mod):
    channels, height, width = img.shape

    out_height = ceil_modulo(height, mod)
    out_width = ceil_modulo(width, mod)
    return np.pad(img, ((0, 0), (0, out_height - height), (0, out_width - width)), mode='symmetric')

def image_resize(image, width = None, height = None, inter = cv2.INTER_AREA):
    # initialize the dimensions of the image to be resized and
    # grab the image size
    dim = None
    (h, w) = image.shape[:2]

    # if both the width and height are None, then return the
    # original image
    if width is None and height is None:
        return image

    # check to see if the width is None
    if width is None:
        # calculate the ratio of the height and construct the
        # dimensions
        r = height / float(h)
        dim = (int(w * r), height)

    # otherwise, the height is None
    else:
        # calculate the ratio of the width and construct the
        # dimensions
        r = width / float(w)
        dim = (width, int(h * r))

    # resize the image
    resized = cv2.resize(image, dim, interpolation = inter)

    # return the resized image
    return resized

def remove(img, s):
    with torch.no_grad():
        ids = [int(x) for x in s.split(",") if x]

        img = image_resize(img, height = 720)
        img = img.astype('float32') / 255
        img = np.transpose(img, (2, 0, 1))

        print(np.unique(segment_masks))
        temp_masks = segment_masks[ids]
        print(temp_masks.shape)
        masks = np.zeros((img.shape[1], img.shape[2]), dtype = bool)
        for mask in temp_masks:
            print(mask.shape)
            mask = cv2.resize(mask, (img.shape[2], img.shape[1]), interpolation = cv2.INTER_NEAREST).astype(bool)
            masks = masks | mask

        kernel = np.ones((7, 7), np.uint8)
        masks = masks.astype(np.uint8) * 255
        masks = cv2.GaussianBlur(masks, (7,7), 0)
        masks = cv2.dilate(masks, kernel, iterations = 3)

        batch = dict(image=img, mask=masks[None, ...])

        batch['unpad_to_size'] = [torch.tensor([batch['image'].shape[1]]),torch.tensor([batch['image'].shape[2]])]
        batch['image'] = torch.tensor(pad_img_to_modulo(batch['image'], predict_config.dataset.pad_out_to_modulo))[None].to(predict_config.device)
        batch['mask'] = torch.tensor(pad_img_to_modulo(batch['mask'], predict_config.dataset.pad_out_to_modulo))[None].float().to(predict_config.device)

        cur_res = refine_predict(batch, inpaint_model, **predict_config.refiner)
        cur_res = cur_res[0].permute(1,2,0).detach().cpu().numpy()

        cur_res = np.clip(cur_res * 255, 0, 255).astype('uint8')

    return cur_res, masks

if __name__ == "__main__":
    app = gr.Blocks()
    with app:
        with gr.Row():
            with gr.Column():
                input_img = gr.Image(label="input image")
                run_btn = gr.Button(variant = "primary")
            output_mask = gr.Image(label="masks", image_mode = "RGB")
        with gr.Row():
            with gr.Column():
                list_of_objects = gr.Textbox(label="Objects id")
                objects_to_remove = gr.Textbox(label="Objects id to remove")
                remove_button = gr.Button("remove")
            with gr.Column():
                output_img = gr.Image(label = "result")
                black_white = gr.Image(label = "segment mask")
        run_btn.click(get_mask, [input_img], [output_mask, list_of_objects])
        remove_button.click(remove, [input_img,objects_to_remove], [output_img, black_white])
    print("sdfdsf")
    app.launch(share=True)


import uvicorn
from fastapi import FastAPI, Request
from keywords_extractor import *

app = FastAPI()

@app.post("/extract")
async def extract_keywords(request: Request):
    data = await request.json()
    keywords = pipeline(data)
    return {"keywords": keywords}

if __name__ == "__main__":
    uvicorn.run(app, host="127.0.0.1", port=9004)


from napari_intensity_step_detection.base.plots import colors, Histogram, HistogramMultiAxes
from qtpy.QtWidgets import QWidget, QGridLayout, QScrollArea, QVBoxLayout
from typing import Optional

class HistogramGrid(QWidget):
    def __init__(
        self,
        parent: Optional[QWidget] = None,
    ):
        super().__init__(parent=parent)
        self.setLayout(QVBoxLayout())

        self.scrollArea = QScrollArea()
        self.scrollArea.setWidgetResizable(True)

        self.centralWidget = QWidget()
        self.centralWidget.setLayout(QGridLayout())

        self.layout().addWidget(self.scrollArea)
        self.col = 2

    def draw(self) -> None:
        n_colors = len(colors)
        # print(len(self.axes))
        row_count = 0
        for i, (key, val) in enumerate(self.data.items()):
            row = int(i / self.col)
            col = int(i % self.col)
            if key == "tile_histogram":
                if col > 0:
                    row_count += 1
                # print(f"MultiHistogramWidgets draw tile {row_count}")
                grid_size = len(val)
                _milti_axes = HistogramMultiAxes(count=grid_size)
                _milti_axes.setData(data=val, title="Step length")
                _milti_axes.setMinimumWidth(400*2)
                _milti_axes.setMinimumHeight(400 * grid_size)
                _milti_axes.draw()
                self.centralWidget.layout().addWidget(_milti_axes, row_count, 0, grid_size, self.col)
            else:
                # print(f"MultiHistogramWidgets draw {row}, {col}, {key}")
                _histogram = Histogram()
                _histogram.setMinimumWidth(400)
                _histogram.setMinimumHeight(400)
                _histogram.setData(val, key)
                _histogram.setColor(colors[int(i % n_colors)])
                _histogram.draw()
                self.centralWidget.layout().addWidget(_histogram, row, col)
            row_count += 1
            self.scrollArea.setWidget(self.centralWidget)

    def setData(self, data):
        self.data = data
        self.draw()

def main():
    from qtpy.QtWidgets import QApplication
    import sys
    import numpy as np
    app = QApplication(sys.argv)
    d1 = np.linspace(10, 20, 100)
    d2 = np.linspace(100, 200, 50)
    d3 = np.linspace(1000, 2000, 500)
    data = {
        "d1": d1,
        "d2": d2,
        "d3": d3
    }
    gh = HistogramGrid()
    gh.setData(data=data)
    gh.show()
    sys.exit(app.exec())

if __name__ == "__main__":
    main()


from datetime import datetime
import pandas as pd
import numpy as np
import geopandas as gpd
import folium
import os
import shutil
import tarfile
from tqdm import tqdm
from contextlib import closing
from homura import download
import requests
from bs4 import BeautifulSoup
from subprocess import Popen, PIPE

def visualize_intersects_region(footprint, intersections):
    xy = np.asarray(footprint.centroid[0].xy).squeeze()
    center = list(xy[::-1])

    # Create a map to visualize the paths and rows that intersects.
    # Select a zoom
    zoom = 6
    # Create the most basic OSM folium map
    m = folium.Map(location=center, zoom_start=zoom, control_scale=True)

    # Add the bounds GeoDataFrame in red
    m.add_child(folium.GeoJson(bounds.__geo_interface__, name='Area of Study',
                               style_function=lambda x: {'color': 'red', 'alpha': 0}))

    # Iterate through each Polygon of paths and rows intersecting the area
    for i, row in intersections.iterrows():
        # Create a string for the name containing the path and row of this Polygon
        name = 'path: %03d, row: %03d' % (row.PATH, row.ROW)
        # Create the folium geometry of this Polygon
        g = folium.GeoJson(row.geometry.__geo_interface__, name=name)
        # Add a folium Popup object with the name string
        g.add_child(folium.Popup(name))
        # Add the object to the map
        g.add_to(m)

    folium.LayerControl().add_to(m)
    m.save('./wrs.html')

def AWS_download(products, save_dir='.'):
    # For each row
    for i, row in products.iterrows():

        # Print some the product ID
        print('\n', 'EntityId:', row.productId, '\n')
        print(' Checking content: ', '\n')

        # Request the html text of the download_url from the amazon server.
        # download_url example: https://landsat-pds.s3.amazonaws.com/c1/L8/139/045/LC08_L1TP_139045_20170304_20170316_01_T1/index.html
        # download_url = f'https://landsat-pds.s3.amazonaws.com/c1/L8/{row.entityId[3:6]}/{row.entityId[6:9]}/{row.productId}/index.html'
        # headers = {
        #     'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36',
        #     'Host': 'landsat-pds.s3.amazonaws.com'
        # }

        download_url = row.download_url
        # headers = {
        #     'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36',
        #     'Host': 's3-us-west-2.amazonaws.com'
        # }
        response = requests.get(download_url)

        # If the response status code is fine (200)
        if response.status_code == 200:

            # Import the html to beautiful soup
            html = BeautifulSoup(response.content, 'html.parser')

            # Create the dir where we will put this image files.
            entity_dir = os.path.join(save_dir, row.productId)
            os.makedirs(entity_dir, exist_ok=True)

            # Second loop: for each band of this image that we find using the html <li> tag
            file_list = []
            for li in html.find_all('li'):

                # Get the href tag
                file = li.find_next('a').get('href')
                if file.endswith('.IMD') or file.endswith('.ovr'):
                    continue
                else:
                    file_list.append(file)

            for f in file_list:
                # Download the files
                # code from: https://stackoverflow.com/a/18043472/5361345
                url = row.download_url.replace('index.html', f)
                status = requests.head(url).status_code
                if status != 200:
                    raise ValueError
                download(url, os.path.join(entity_dir, f))

        source_dir = entity_dir
        output_filename = '{}.tar.gz'.format(row.productId)
        out_location = os.path.join(save_dir, output_filename)
        with tarfile.open(out_location, "w:gz") as tar:
            tar.add(source_dir, arcname=os.path.basename(source_dir))
        shutil.rmtree(source_dir)
        print('Successfully download: {}'.format(row.productId))

# TODO: incomplete, complete it when needed
def GCS_download(products, save_dir='.'):
    # For each row
    for i, row in products.iterrows():

        # Print some the product ID
        print('\n', 'EntityId:', row.productId, '\n')
        print(' Checking content: ', '\n')

        # Request the html text of the download_url from the amazon server.
        # example url: 'https://storage.googleapis.com/gcp-public-data-landsat/LC08/01/037/029/LC08_L1TP_037029_20130602_20170310_01_T1/LC08_L1TP_037029_20130602_20170310_01_T1_B2.TIF'
        download_url = f'http://storage.googleapis.com/gcp-public-data-landsat/LC08/01/{row.SCENE_ID[3:6]}/{row.SCENE_ID[6:9]}/{row.PRODUCT_ID}'

# TODO: incomplete, complete it when needed
def GCS_download_with_gsutil(products, save_dir='.'):
    # example url: gs://gcp-public-data-landsat/LC08/01/044/034/LC08_L1GT_044034_20130330_20170310_01_T2/
    url = ''
    p = Popen('gsutil -m cp -r '+url+' ./data', stdout=PIPE, stderr=PIPE, shell=True)
    stdout = p.stdout.read()
    stderr = p.stderr.read()
    if stderr:
        raise NotImplementedError(stderr)
    if stdout:
        print(stdout)

def GCS_filter(wrs_intersection, start_date, end_date, cloud_cover=20, ):
    paths, rows = wrs_intersection['PATH'].values, wrs_intersection['ROW'].values
    # google_scenes, 'https://storage.googleapis.com/gcp-public-data-landsat/index.csv.gz'
    scenes = pd.read_csv('./index.csv.gz', compression='gzip')

    scenes.dropna(subset=['PRODUCT_ID'], inplace=True, axis=0)
    scenes = scenes[
        (scenes.SPACECRAFT_ID == 'LANDSAT_8') &
        (scenes.PRODUCT_ID.str.endswith('_T1')) &
        (scenes.DATA_TYPE == 'L1TP') &
        (scenes.COLLECTION_NUMBER == '01')
        ]
    # Empty list to add the images
    bulk_list = []

    # Iterate through paths and rows
    for path, row in zip(paths, rows):

        print('Path:', path, 'Row:', row)

        # Filter the Google cloud storage table for images matching path, row, cloud cover and processing state.
        tem_scenes = scenes[
            (scenes.WRS_PATH == path) &
            (scenes.WRS_ROW == row) &
            (scenes.CLOUD_COVER <= cloud_cover) &
            (scenes.DATE_ACQUIRED > datetime.strptime(start_date, '%Y%m%d').strftime('%Y-%m-%d')) &
            (scenes.DATE_ACQUIRED < datetime.strptime(end_date, '%Y%m%d').strftime('%Y-%m-%d'))
            ]

        print(' Found {} images\n'.format(len(tem_scenes)))

        # If any scenes exists, select the one that have the minimum cloudCover.
        if len(tem_scenes):
            scene = tem_scenes.sort_values('CLOUD_COVER').iloc[0]
            # Add the selected scene to the bulk download list.
            bulk_list.append(scene)

    bulk_frame = pd.concat(bulk_list, 1).T
    return bulk_frame

def AWS_filter(wrs_intersection, start_date, end_date, cloud_cover=20):
    paths, rows = wrs_intersection['PATH'].values, wrs_intersection['ROW'].values
    # wrs_intersection_night = wrs_night[wrs_night.intersects(bounds.geometry[0])]
    # paths_night, rows_night = wrs_intersection_night['PATH'].values, wrs_intersection_night['ROW'].values

    # Checking Available Images on Amazon S3
    # 'http://landsat-pds.s3.amazonaws.com/c1/L8/scene_list.gz'
    s3_scenes = pd.read_csv('./aws_scene_list.gz', compression='gzip')
    s3_scenes = s3_scenes[
                       s3_scenes.productId.str.endswith('_T1')
                       ]
    # Empty list to add the images
    bulk_list = []

    # Iterate through paths and rows
    for path, row in zip(paths, rows):

        print('Path:', path, 'Row:', row)

        # Filter the Landsat Amazon S3 table for images matching path, row, cloud cover and processing state.
        scenes = s3_scenes[(s3_scenes.path == path) & (s3_scenes.row == row) &
                           (s3_scenes.cloudCover <= cloud_cover) &
                           (s3_scenes.productId.str.endswith('_T1')) &
                           (s3_scenes.acquisitionDate > datetime.strptime(start_date, '%Y%m%d').strftime('%Y-%m-%d %H:%M:%S.%f')) &
                           (s3_scenes.acquisitionDate < datetime.strptime(end_date, '%Y%m%d').strftime('%Y-%m-%d %H:%M:%S.%f'))
                           ]

        print(' Found {} images\n'.format(len(scenes)))

        # If any scenes exists, select the one that have the minimum cloudCover.
        if len(scenes):
            scene = scenes.sort_values('cloudCover').iloc[0]
            # Add the selected scene to the bulk download list.
            bulk_list.append(scene)

    bulk_frame = pd.concat(bulk_list, 1).T
    return bulk_frame

if __name__ == '__main__':
    # the .geojson file can be created from http://geojson.io
    bounds = gpd.read_file('./geojson_files/moutain.geojson')
    start_date = '20190701'
    end_date = '20190901'
    save_dir = r'./'
    # download from: https://www.usgs.gov/land-resources/nli/landsat/landsat-shapefiles-and-kml-files
    wrs_day = gpd.GeoDataFrame.from_file('./WRS2_descending/WRS2_descending.shp')
    # wrs_night = gpd.GeoDataFrame.from_file('./WRS2_ascending_nighttime_data/WRS2_acsending.shp')

    wrs_intersection = wrs_day[wrs_day.intersects(bounds.geometry[0])]

    # visualize the ROI
    # visualize_intersects_region(bounds, wrs_intersection)

    # # AWS download
    bulk_list = AWS_filter(wrs_intersection, start_date, end_date)
    AWS_download(bulk_list, save_dir)
    # ====================================================
    # GCS download
    # bulk_list = GCS_filter(wrs_intersection, start_date, end_date)


########################################### IMPORTS ####################################################
from pyspark import SparkConf, SparkContext
from pyspark.sql import SQLContext
conf = SparkConf().setAppName("building a warehouse")
sc = SparkContext(conf=conf)
sqlContext = SQLContext(sc)

################################## STATISTICS ON FINAL RESULTS FOR MAPS ################################
############## ALL RESULTS ARE SAVED INTO PARQUET FILES AND USED IN visualization.ipynb ################

# Download the results of localization for each insta
final_sites = sqlContext.read.parquet("hdfs:///user/prado/final_localization.parquet")

# How many instagrams do we have by cantons ?
canton_map = final_sites.groupBy('canton').count()
canton_map.write.save("hdfs:///user/prado/insta_by_canton.parquet", mode = 'overwrite', format="parquet")

# MARKERS
# For each sentiment :
for i in [0,1,2]:

    # Cross tab: number of instagram by canton and by month
    per_canton_month = final_sites.filter(final_sites['label']==i).crosstab('canton', 'date_found')
    per_canton_month.write.save("hdfs:///user/prado/per_canton_month_"+str(i)+".parquet",mode = 'overwrite', format="parquet")

#CHOROPLETH MAP
# number of happy insta & total insta by canton
nb_hapinsta = final_sites.filter(final_sites["label"]==0).groupBy('canton').count().withColumnRenamed('count', 'happy')
nb_neutrinsta = final_sites.filter(final_sites["label"]==1).groupBy('canton').count().withColumnRenamed('count', 'neutral')
nb_insta = final_sites.groupBy('canton').count().withColumnRenamed('count', 'total')
finalinsta = nb_hapinsta.join(nb_insta, on = 'canton')
FINALINSTA = finalinsta.join(nb_neutrinsta, on = 'canton')
FINALINSTA.write.save("hdfs:///user/prado/insta_map_scores.parquet", mode = 'overwrite', format="parquet")

# CHOROPLETH MAP:
# Number of instagram per cities
city_map = final_sites.groupBy('city').count()
city_map.write.save("hdfs:///user/prado/insta_density.parquet", mode = 'overwrite', format="parquet")


import torch
import torch.nn as nn
import torch.nn.functional as F
from torchvision import datasets, transforms
from tqdm.notebook import tqdm, trange

# Set GPU device
cuda0 = torch.device('cuda:0')

# Model class
class CNN(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(1, 32, kernel_size=5, padding=2).cuda(0)
        self.conv2 = nn.Conv2d(32, 64, kernel_size=5, padding=2).cuda(0)
        self.pl1 = nn.Linear(7*7*64, 256).cuda(0)
        self.pl2 = nn.Linear(256, 10).cuda(0)

    def forward(self, x):
        x = self.conv1(x)
        x = F.relu(x)
        x = F.max_pool2d(x, kernel_size=2)

        x = self.conv2(x)
        x = F.relu(x)
        x = F.max_pool2d(x, kernel_size=2)

        x = x.view(-1, 7*7*64)
        x = self.pl1(x)
        x = F.relu(x)

        x = self.pl2(x)
        return x

# Load data
train = datasets.MNIST(root='./datasets', train=True, transform=transforms.ToTensor(), download=True)
test = datasets.MNIST(root='./datasets', train=False, transform=transforms.ToTensor(), download=True)
train_loader = torch.utils.data.DataLoader(train, shuffle=True)
test_loader = torch.utils.data.DataLoader(test, shuffle=False)

model = CNN()

criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)

# Train
with torch.cuda.device(0):
    for epoch in trange(3):
        for images, labels in tqdm(train_loader):

            optimizer.zero_grad()

            x = images.cuda(0)
            y = model(x)
            loss = criterion(y, labels.cuda(0))
            loss.backward()
            optimizer.step()

# Test
correct = 0
total = len(test)

with torch.cuda.device(0):
    with torch.no_grad():
        for images, labels in tqdm(test_loader):
            x = images.cuda(0)
            y = model(x)

            prediction = torch.argmax(y, dim=1)
            correct += torch.sum((prediction == labels.cuda(0)).float())

print(f'{correct} of {total}')


import numpy as np
from scipy import interpolate

def z(j, k):
    """Calculates equivalence scale. z(2,1) is the equivalence scale for a household with two adults and one child

    Parameters
    ----------
    j : float
        the number of adults in the household.
    k : float
        the number of children (under 18 years old).

    Returns
    -------
    type
        float

    """
    return (j + 0.7* k)**0.75

def create_consumption_preference_array(e_lvl):
    """Calculates n_et for given age.

    Parameters
    ----------
    j_et : float
        the average number of adults in the household by age and education group.
    k_et : float
        the average number of children in the household by age and education group.

    Returns
    -------
    type
        float

    """

    k_et = create_avg_children(e_lvl)
    j_et = create_avg_adults(e_lvl)

    return z(j_et,k_et) / z(2,1)

def create_avg_children(e_lvl):
    '''Data from https://www.census.gov/data/tables/2016/demo/families/cps-2016.html'''

    age = [25,30,35,40,45,50,55,60,65, 90]
    col = [0.70, 1.20, 1.45, 1.29, 0.90, 0.47, 0.23, 0.13, 0.09, 0.05]
    hs = [val * 1.00 for val in col]
    lhs = [val * 1.40 for val in col] # Notice the multiplying factor

    names = {
        '<HS': lhs,
        'HS': hs,
        'College': col
    }

    assert e_lvl in names.keys()
    f = interpolate.interp1d(age, names[e_lvl], kind='linear', fill_value = "extrapolate")

    output = np.array([float(f(_age)) for _age in range(0, 90 + 1)])
    output[0:25] = 0 # For t<25 set size to 0, else there will be problems in the z function
    return output

def create_avg_adults(e_lvl):
    '''Data from https://www.census.gov/data/tables/2016/demo/families/cps-2016.html'''

    age = [25,30,35,40,45,50,55,60,65, 90]
    col = [1.84, 1.82, 1.92, 2.04, 2.21, 2.19, 2.10, 1.94, 1.83, 1.60]
    hs = [val * 1.00 for val in col]
    lhs = [val * 1.00 for val in col]

    names = {
        '<HS': lhs,
        'HS': hs,
        'College': col
    }

    assert e_lvl in names.keys()
    f = interpolate.interp1d(age, names[e_lvl], kind='linear', fill_value = "extrapolate")

    output = np.array([float(f(_age)) for _age in range(0, 90 + 1)])
    output[0:25] = 0 # For t<25 set size to 0, else there will be problems in the z function
    return output


#from asyncio import subprocess
import os
from tkinter import *
from tkinter.ttk import *
from tkinter import messagebox
import subprocess
import shutil
import sounddevice
import pandas
import datetime
import psutil

MainWindow = Tk()
MainWindow.title("Sobotify App")

project_path_default     = os.path.join(os.path.expanduser("~"),".sobotify","projects") # 'path to movement/speech data')

DEFAULT_ROBOT_IP="192.168.0.141"
DEFAULT_ROBOT_NAMES=("stickman","pepper","nao","cozmo","mykeepon")
DEFAULT_PROJECT="quiz_english"
DEFAULT_NEW_PROJECT_NAME=("MyProject")

if os.path.isfile(os.path.join(os.path.expanduser("~"),"miniconda3","condabin","conda.bat")):
	conda_exe=os.path.join(os.path.expanduser("~"),"miniconda3","condabin","conda.bat")
elif os.path.isfile(os.path.join(os.path.expanduser("~"),"AppData","Local","miniconda3","condabin","conda.bat")):
	conda_exe=os.path.join(os.path.expanduser("~"),"AppData","Local","miniconda3","condabin","conda.bat")
else :
	print ("Cannot find Conda executable path. Abort")
	exit()

class sound_devices(object):

	def __init__(self):
		self.device_dict={}

	def read_device_list(self):
		self.device_dict.clear()
		for index,device in enumerate(sounddevice.query_devices()):
			if device["max_input_channels"]>0:
				#print (f"index:{index}, name:{device['name']}")
				self.device_dict[device['name']]=index
		#print (self.device_dict)

	def get_list(self):
		self.read_device_list()
		device_list=list(self.device_dict.keys())
		return device_list

	def get_device_id(self,device_name):
		#print (self.device_dict[device_name])
		return self.device_dict[device_name]

def get_projects() :
	projects=[]
	project_files = os.listdir(project_path_default)
	for project in project_files:
		projectname ,ext = os.path.splitext(project)
		if ext==".xlsx":
			projects.append(projectname)
	return projects

def get_project_file_name(project_name):
	return os.path.join(project_path_default,str(project_name)+".xlsx")

def get_deleted_project_file_name(project_name):
	return os.path.join(project_path_default,"trash",str(project_name)+".xlsx")

def get_project_info(project_name) :
	data=pandas.read_excel(get_project_file_name(project_name))
	app=str(data.iloc[0,4]).strip()
	language=str(data.iloc[2,4]).strip()
	#print(app)
	#print(language)
	return app,language

class SobotifyAppGui(object):

	def __init__(self):
		self.project_proc=None

		self.robot_IP=StringVar()
		self.robot_IP.set(DEFAULT_ROBOT_IP)
		self.robot_IP.trace_add("write",self.check_IP)

		self.sound_devs=sound_devices()
		self.selected_sound_device=StringVar()
		self.sound_devices=self.sound_devs.get_list()
		self.selected_sound_device.set(self.sound_devices[0])

		self.robots=(DEFAULT_ROBOT_NAMES)
		self.selected_robot=StringVar()
		self.selected_robot.set(self.robots[0])

		self.selected_delete_project=StringVar()
		self.selected_curr_project=StringVar()
		self.selected_base_project=StringVar()
		self.new_project=StringVar()

		self.projects=get_projects()
		if len(self.projects)==0:
			self.selected_curr_project.set("")
			self.selected_base_project.set("")
		if DEFAULT_PROJECT in self.projects :
			self.selected_curr_project.set(DEFAULT_PROJECT)
			self.selected_base_project.set(DEFAULT_PROJECT)
		else:
			self.selected_curr_project.set(self.projects[0])
			self.selected_base_project.set(self.projects[0])
		self.new_project.set(DEFAULT_NEW_PROJECT_NAME)
		self.selected_delete_project.set("")

		self.app,self.language=get_project_info(self.selected_curr_project.get())

		# column 1
		col=1
		padx=5
		Label(MainWindow, text="________________________ settings ________________________").grid(row=1, column=col,padx=padx,pady=5,columnspan=2)

		Label(MainWindow, text="").grid(row=1, column=col,padx=padx,pady=5)
		Label(MainWindow, text="robot name   ",justify=RIGHT,anchor="e").grid(row=2, column=col,padx=padx,pady=5,sticky=E)
		Label(MainWindow, text="robot IP/port",justify=RIGHT,anchor="e").grid(row=3, column=col,padx=padx,pady=5,sticky=E)
		Label(MainWindow, text="sound device ",justify=RIGHT,anchor="e").grid(row=4, column=col,padx=padx,pady=5,sticky=E)

		# column 2
		col=2
		self.combobox_robot_sel=Combobox(MainWindow,textvariable=self.selected_robot)
		self.combobox_robot_sel.grid(sticky="W",row=2, column=col,padx=padx,pady=5)
		self.combobox_robot_sel['values']=self.robots
		self.combobox_robot_sel['width']=30
		self.combobox_robot_sel['state']='readonly'

		Entry(MainWindow, text="IP", textvariable=self.robot_IP, width=15).grid(row=3, column=col,padx=0,pady=20)

		self.combobox_sound_dev_sel=Combobox(MainWindow,textvariable=self.selected_sound_device)
		self.combobox_sound_dev_sel.grid(sticky="W",row=4, column=col,padx=padx,pady=5)
		self.combobox_sound_dev_sel['values']=self.sound_devices
		self.combobox_sound_dev_sel['width']=30
		self.combobox_sound_dev_sel['state']='readonly'

		# column 3-4
		col=3
		Label(MainWindow, text="________________ project ________________").grid(row=1, column=col,padx=20,pady=5,columnspan=2)

		self.combobox_curr_project_sel=Combobox(MainWindow,textvariable=self.selected_curr_project)
		self.combobox_curr_project_sel.grid(sticky="W",row=2, column=col,padx=20,pady=5,columnspan=2)
		self.combobox_curr_project_sel['values']=self.projects
		self.combobox_curr_project_sel['width']=30
		self.combobox_curr_project_sel['state']='readonly'

		Button(MainWindow, text="start", command=self.start_project).grid(row=3, column=col,padx=20,pady=5)
		Button(MainWindow, text="edit", command=self.edit_project).grid(row=4, column=col,padx=20,pady=5)

		col=4
		Button(MainWindow, text="stop", command=self.stop_project).grid(row=3, column=col,padx=20,pady=5)
		Button(MainWindow, text="new/delete...", command=self.new_delete_project).grid(row=4, column=col,padx=20,pady=5)

	def check_IP(self,*args):
		IP_parts=self.robot_IP.get().split(".")
		for IP_part in IP_parts:
			if IP_part.isnumeric():
				if int(IP_part) in range(0,255):
					#print(f"IP {IP_part} is ok")
					pass
				else:
					#print(f"IP {IP_part} is out of range")
					return False
			else:
				#print(f"IP {IP_part} is not a number")
				return False
		return True

	def check_port(self,*args):
		if "COM" in self.robot_IP.get():
			return True
		return False

	def update_project_list(self, deleted_project_name="") :
			self.projects=get_projects()
			self.combobox_delete_project['values']=self.projects
			self.combobox_base_project['values']=self.projects
			self.combobox_curr_project_sel['values']=self.projects
			self.combobox_delete_project.set("")
			if deleted_project_name==self.selected_curr_project.get() :
				if len(self.projects)==0:
					self.selected_curr_project.set("")
				else:
					self.selected_curr_project.set(self.projects[0])
			if deleted_project_name==self.selected_base_project.get() :
				if len(self.projects)==0:
					self.selected_base_project.set("")
				else:
					self.selected_base_project.set(self.projects[0])

	def start_project(self) :
		self.app,self.language=get_project_info(self.selected_curr_project.get())
		self.stop_project()
		if self.check_IP()==False and self.check_port()==False:
			messagebox.showerror("Robot IP Address Error",f"Invalid robot IP address:\n{self.robot_IP.get()}\nCorrect format is\n4 numbers in range 0..255,\nseparated by dots, for example\n192.168.0.141")
			return
		sobotify_path=os.path.dirname(os.path.abspath(__file__))
		script_path=os.path.join(sobotify_path,'apps',self.app,self.app+'.py')
		conda_env = "sobotify"
		arguments=[conda_exe]
		arguments.append("run")
		arguments.extend(('-n',conda_env))
		arguments.append("--no-capture-output")
		arguments.append("python")
		arguments.append(script_path)
		arguments.extend(('--robot_name',self.selected_robot.get()))
		arguments.extend(('--robot_ip',self.robot_IP.get()))
		arguments.extend(('--language',self.language))
		arguments.extend(('--sound_device',str(self.sound_devs.get_device_id(self.selected_sound_device.get()))))
		arguments.extend(('--project_file',get_project_file_name(self.selected_curr_project.get())))

		#if debug==True:
		print (*arguments)
		self.project_proc=subprocess.Popen(arguments,creationflags=subprocess.CREATE_NEW_CONSOLE)
		#self.project_proc=subprocess.Popen(arguments)
		print ('started project app, pid=',self.project_proc.pid)

	def stop_project(self):
		if not self.project_proc==None:
			try:
				project_process=psutil.Process(self.project_proc.pid)
				project_children=project_process.children(recursive=True)
				print(project_children)
				for child in project_children:
					try:
						#print(f"kill process {child.name} with pid: {child.pid}")
						child.kill()
					except:
						#print(f"process {child.name} with pid: {child.pid} already finished")
						pass
				try:
					#print(f"kill process with pid: {self.project_proc.pid}")
					self.project_proc.kill()
				except:
					#print(f"process with pid: {self.project_proc.pid} already finished")
					pass
			except:
				#print(f"process with pid: {self.project_proc.pid} does not exist (anymore)")
				pass
		else:
			#print("no process to kill")
			pass
		self.project_proc=None

	def edit_project(self):
		project_editor_proc=os.startfile(get_project_file_name(self.combobox_curr_project_sel.get()))

	def create_project(self):
		src=get_project_file_name(self.selected_base_project.get())
		dest=get_project_file_name(self.new_project.get())
		if os.path.isfile(dest):
			messagebox.showerror('File exists',f'Project {self.new_project.get()} already exists. Choose a different name')
		else:
			if messagebox.askokcancel('Create Project Copy',f'Project file\n{src}\nwill be copied to\n{dest}\nDo you want to proceed?') == True :
				shutil.copyfile(src,dest)
		self.update_project_list()

	def delete_project(self):
		src=get_project_file_name(self.selected_delete_project.get())
		dest=get_deleted_project_file_name(self.selected_delete_project.get())
		if os.path.isfile(dest):
			if messagebox.askokcancel('File exists',f'Old project file {dest} already exists and will be overwritten.\nDo you want to proceed?') == True :
				shutil.move(src,dest)
		else:
			if messagebox.askokcancel('Move file', f'Project file\n{src}\nwill be moved to\n{dest}\nDo you want to proceed?') == True :
				shutil.move(src,dest)
		self.update_project_list(self.selected_delete_project.get())

	def new_delete_project(self) :
		now=datetime.datetime.now()
		date_time_string=now.strftime("%y%m%d_%H%M%S")
		self.new_project.set(DEFAULT_NEW_PROJECT_NAME+"_"+date_time_string)
		ProjectWindow = Toplevel(MainWindow)
		ProjectWindow.grab_set()
		ProjectWindow.title("Create or delete a project")

		col=1
		Label(ProjectWindow, text="name of new project:").grid(row=1, column=col,padx=20,pady=5,)
		Entry(ProjectWindow, text="Entry", textvariable=self.new_project, width=50).grid(row=2, column=col,padx=20,pady=5)
		self.combobox_base_project=Combobox(ProjectWindow,textvariable=self.selected_base_project)
		Label(ProjectWindow, text="name of project to be deleted:",justify=RIGHT,anchor="e").grid(row=3, column=col,padx=20,pady=5,sticky=E)

		col=2
		Label(ProjectWindow, text="based on project:").grid(row=1, column=col,padx=20,pady=5,)
		self.combobox_base_project.grid(sticky="W",row=2, column=col,padx=20,pady=5)
		self.combobox_base_project['values']=self.projects
		self.combobox_base_project['state']='readonly'
		self.combobox_delete_project=Combobox(ProjectWindow,textvariable=self.selected_delete_project)
		self.combobox_delete_project.grid(sticky="W",row=3, column=col,padx=20,pady=20)
		self.combobox_delete_project['values']=self.projects
		self.combobox_delete_project['state']='readonly'

		col=3
		Button(ProjectWindow, text="create new project", command=self.create_project).grid(row=2, column=col,padx=5,pady=5)
		Button(ProjectWindow, text="delete project", command=self.delete_project).grid(row=3, column=col,padx=5,pady=20)

sobot_gui=SobotifyAppGui()

MainWindow.mainloop()


"""Add birthdays table

Revision ID: 16be16a7b5b7
Revises: 1e981ab7bc29
Create Date: 2023-03-06 14:55:10.159495

"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql

# revision identifiers, used by Alembic.
revision = "16be16a7b5b7"
down_revision = "1e981ab7bc29"
branch_labels = None
depends_on = None

def upgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.create_table(
        "birthdays",
        sa.Column("id", sa.Integer(), nullable=False),
        sa.Column("date", sa.DateTime(), nullable=False),
        sa.Column("user_id", sa.String(length=300), nullable=False),
        sa.Column("guild_id", sa.String(length=300), nullable=False),
        sa.Column("is_anonymous", sa.Boolean(), nullable=True),
        sa.Column("created_at", sa.DateTime(), nullable=True),
        sa.Column("updated_at", sa.DateTime(), nullable=True),
        sa.PrimaryKeyConstraint("id", name=op.f("pk_birthdays")),
    )
    # ### end Alembic commands ###

def downgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.drop_table("birthdays")
    # ### end Alembic commands ###


from .base_type import BaseType
from .base_metric import BaseMetric
from .metric_helper import MetricHelper
from wallarm_api import WallarmAPI
from collections import Counter

class HintsMetric(BaseType):
    HINT_TYPES = [("Attack rechecker rewrite (avaliable)", 7, "attack_rechecker_rewrite"),
                  ("Attack by regex (avaliable)", 8, "regex"),
                  ("Sensitive data (avaliable)", 9, "sensitive_data"),
                  ("Vpatch (avaliable)", 10, "vpatch"),
                  ("Wallarm mode (avaliable)", 11, "wallarm_mode"),
                  ("Disable regex (avaliable)", 12, "disable_regex"),
                  ("Experimental regex (avaliable)", 13, "experimental_regex"),
                  ("Brute counter (avaliable)", 14, "brute_counter"),
                  ("Dirbust counter (avaliable)", 15, "dirbust_counter"),
                  ("Attack rechecker (avaliable)", 16, "attack_rechecker"),
                  ("Binary data (avaliable)", 17, "binary_data"),
                  ("Disable attack type (avaliable)", 18, "disable_attack_type"),
                  ("Parser state (avaliable)", 19, "parser_state"),
                  ("Set response header (avaliable)", 20, "set_response_header"),
                  ("Uploads (avaliable)", 21, "uploads"),
                  ("Tag (internal)", 22, "tag"),
                  ("Disable ld context (internal)", 23, "disable_ld_context"),
                  ("Overlimit (internal)", 24, "overlimit_res"),
                  ("Variative values (internal)", 25, "variative_values"),
                  ("Variative keys (internal)", 26, "variative_keys"),
                  ("Variative by regex (internal)", 27, "variative_by_regex"),
                  ("Max serialize data size (internal)",
                   28, "max_serialize_data_size"),
                  ("Middleware (internal)", 29, "middleware"),
                  ("Experimental stamp (internal)", 30, "experimental_stamp"),
                  ("Disable stamp (internal)", 31, "disable_stamp"),
                  ("Disable response stamp (internal)",
                   32, "disable_response_stamp"),
                  ("Experimental parser (internal)", 33, "experimental_parser"),
                  ]

    PARSER_TYPES = [("Disable parser base_64", 41, "base64")]

    HINT_TYPES_BY_USER = [("[USER] Attack rechecker rewrite", 101, "attack_rechecker_rewrite"),
                          ("[USER] Attack by regex", 102, "regex"),
                          ("[USER] Sensitive data", 103, "sensitive_data"),
                          ("[USER] Vpatch", 104, "vpatch"),
                          ("[USER] Wallarm mode", 105, "wallarm_mode"),
                          ("[USER] Disable regex", 106, "disable_regex"),
                          ("[USER] Experimental regex", 107, "experimental_regex"),
                          ("[USER] Brute counter", 108, "brute_counter"),
                          ("[USER] Dirbust counter", 109, "dirbust_counter"),
                          ("[USER] Attack rechecker", 110, "attack_rechecker"),
                          ("[USER] Binary data", 111, "binary_data"),
                          ("[USER] Disable attack type", 112, "disable_attack_type"),
                          ("[USER] Parser state", 113, "parser_state"),
                          ("[USER] Set response header", 114, "set_response_header"),
                          ("[USER] Uploads", 115, "uploads")]

    def get_hints(self):
        all_hints = []
        real_clients_id = [client.id for client in MetricHelper().real_clients]
        i = 0
        while True:
            hints = WallarmAPI().hints_api.get_hint_details(
                clientid=real_clients_id, limit=100, offset=i*100)
            all_hints += hints
            i += 1
            if len(hints) < 100:
                break

        return all_hints

    def get_hints_types(self, hints):
        types = [i.type for i in hints]
        return dict(Counter(types))

    def hints_uri_conditions(self, hints):
        uri_condition = []
        for hint in hints:
            for condition in hint.action:
                if "uri" in condition["point"]:
                    uri_condition.append(hint.id)

        return len(uri_condition)

    def get_hints_created_by_user(self):
        user_hints = []
        userids = MetricHelper().non_superadmin_users
        real_clients_id = [client.id for client in MetricHelper().real_clients]
        i = 0
        while True:
            hints = WallarmAPI().hints_api.get_hint_details(
                clientid=real_clients_id, create_userid=userids, limit=100, offset=i*100)
            user_hints += hints
            i += 1
            if len(hints) < 100:
                break

        return user_hints

    class CountHintsByType(BaseMetric):
        def __init__(self, types, name, row, hint_type) -> None:
            super().__init__(name, row)
            self.types = types
            self.hint_type = hint_type

        def value(self):
            if self.hint_type in self.types:
                return self.types[self.hint_type]
            else:
                return 0

    class CountParserStateByParser(BaseMetric):
        def __init__(self, name, row, parser_type) -> None:
            super().__init__(name, row)
            self.parser_type = parser_type

        def value(self):
            count_hints = 0

            for client in MetricHelper().real_clients:
                i = 0
                while True:
                    hints = WallarmAPI().hints_api.get_hint_details(
                        type=["parser_state"], clientid=client.id, limit=100, offset=i*100)
                    for hint in hints:
                        if hint.parser == self.parser_type:
                            count_hints += 1
                    i += 1
                    if len(hints) < 100:
                        break

            return count_hints

    class CountHintsCreatedByClient(BaseMetric):
        def __init__(self, types, name, row, hint_type) -> None:
            super().__init__(name, row)
            self.hint_type = hint_type
            self.types = types

        def value(self):
            if self.hint_type in self.types:
                return self.types[self.hint_type]
            else:
                return 0

    def collect_metrics(self):
        all_hints = self.get_hints()
        #hints_uri_condition = self.hints_uri_conditions(all_hints)
        hint_types = self.get_hints_types(all_hints)
        hints_by_user = self.get_hints_created_by_user()
        hints_by_user_types = self.get_hints_types(hints_by_user)

        metrics = [self.CountHintsCreatedByClient(hints_by_user_types, *t) for t in self.HINT_TYPES_BY_USER] + [
            self.CountHintsByType(hint_types, *t) for t in self.HINT_TYPES] + [
            self.CountParserStateByParser(*t) for t in self.PARSER_TYPES]
        return metrics


import tkinter as tk
from tkinter import *
from tkinter import filedialog
from PIL import Image, ImageTk
from PIL import ImageFont
from PIL import ImageDraw

window = Tk()
window.title("Watermarking")
window.config(padx=10, pady=10)
window.minsize(width=800, height=600)
l1 = tk.Label(window, text='Add Student Data with Photo', width=30, font=('times', 18, 'bold'))
l1.grid(row=1, column=1)
b1 = tk.Button(window, text='Upload File',
    width=20, command=lambda:upload())
b1.grid(row=2, column=1)

def upload():
        global img
        f_types = [('Jpg Files', '*.jpg'),  ("all files", "*.*")]
        filename = filedialog.askopenfilename(filetypes=f_types)
        img = Image.open(filename)
        img_resized = img.resize((400, 200)) # new width & height
        draw = ImageDraw.Draw(img)

        # Creating text and font object
        text = "HolyPython.com"
        font = ImageFont.truetype('arial.ttf', 82)

        # Positioning Text
        textwidth, textheight = draw.textsize(text, font)
        width, height = img.size
        x = width / 2 - textwidth / 2
        y = height - textheight - 300

        # Applying text on image via draw object
        draw.text((x, y), text, font=font)

        # Saving the new image
        img.save('watermarked.png')

window.mainloop()


from functools import wraps

class CachedProperty(property):
    """Subclass used to signal cached properties."""
    pass

def cache(method):
    """Decorator to cache selected property values.

    Can use del obj.property to clear the cache."""
    name = '_' + method.__name__

    @CachedProperty
    @wraps(method)
    def f(self):
        if hasattr(self, name):
            res = getattr(self, name)
        else:
            res = method(self)
            object.__setattr__(self, name, res)

        return res

    @f.deleter
    def f(self):
        if hasattr(self, name):
            delattr(self, name)

    return f

def cache_only_in_eval(cls):
    """Decorator for torch.nn.Module to make any `CachedProperty`
    clear its cache whenever the Module is in training mode.
    The result of the property will be cached only in eval mode.
    """

    # Identify all cached properties
    cached_properties = [
        name
        for name in dir(cls)
        if isinstance(getattr(cls, name), CachedProperty)
    ]

    # Decorate all cached properties again so that, if they're in training,
    # the cached value disappears after access
    def dec(method):

        @wraps(method)
        def f(self):
            res = method(self)

            if self.training:
                delattr(self, method.__name__)

            return res

        return f

    for name in cached_properties:
        p = getattr(cls, name)
        setattr(cls, name, wraps(p.fget)(CachedProperty(dec(p.fget), fdel=p.fdel)))

    # Also, edit the train method so that when coming from eval,
    # we also destroy the cached values
    def train(self, train=True):
        # Delete all caches
        for name in cached_properties:
            delattr(self, name)

        return super(cls, self).train(train)

    cls.train = train
    return cls


from functools import cache
from random import random
import time
from generalizedYShapeAnalysis import YLattice
from newNodeNetwork import NodeNetwork, Node
import numpy as np
import cv2
import math
import argparse

#Set up argparser to allow for input image
parser = argparse.ArgumentParser(description='MFM image analysis')
parser.add_argument('image', metavar='image', type=str, nargs='+',help='Path of image')
parser.add_argument('-s', "--spacing",  help="how dense the islands are packed small=denser (default=0.25)", type=float, default=0.25)
parser.add_argument("-t", "--trim", help="Set if the offset row is shorter than the non-offset rows",action="store_true", default=False)
parser.add_argument("-a", "--reference_image", help="image of the height(to help line up the sample points)", type=str)
args=parser.parse_args()

WINDOWSIZE=800

#read image and reference image
try:
    phase_image = cv2.imread(args.image[0])
    phase_image=cv2.resize(phase_image,(WINDOWSIZE,WINDOWSIZE))
except:
    raise Exception("File not found")

if args.reference_image is not None:
    try:
        height_image = cv2.imread(args.reference_image)
        height_image = cv2.resize(height_image, (WINDOWSIZE,WINDOWSIZE))
    except:
        raise Exception("File not found")
else:
    height_image=np.zeros((WINDOWSIZE,WINDOWSIZE,3), np.uint8)

def getBWImage(image):
        pointSampleWidth=1
        avg_color_per_row = np.average(image, axis=0)
        avg_color = np.average(avg_color_per_row, axis=0)
        avg=np.average(avg_color,axis=0)

        print("Average color:",avg)
        blur = cv2.GaussianBlur(image,(pointSampleWidth,pointSampleWidth),15)

        blurredImage=blur
        blur=cv2.cvtColor(blur,cv2.COLOR_RGB2GRAY)
        BWImage=cv2.adaptiveThreshold(blur, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11,0)
        #BWImage=cv2.cvtColor(BWImage,cv2.COLOR_GRAY2RGB)

        return BWImage

global lastMouse

def degToRad(ang):
    return ang*np.pi/180
def cosDeg(ang):
    return np.cos(degToRad(ang))
def sinDeg(ang):
    return np.sin(degToRad(ang))

class RowCol:
    def __init__(self,row,col):
        self.row=row
        self.col=col
    def __str__(self) -> str:
        return f"r{self.row}c{self.col}"
    def __hash__(self):
        return hash(str(self))

class YIsland():
    def __init__(self,row,col,leg1Angle,radius):
        self.leg1Angle=leg1Angle
        self.row=row
        self.col=col
        self.radius=radius

    def getPoints(self):

        center=np.array([self.col,self.row])
        points=[center]
        for angle in [self.leg1Angle, self.leg1Angle+120, self.leg1Angle+240]:
            points.append(center+self.radius*np.array([cosDeg(angle),sinDeg(angle)]))

        return [RowCol(point[1],point[0]) for point in points]

    def hasError(colorPattern):
        return sum(colorPattern)!=0

class Pattern:
    def __init__(self,repeatRow,repeatCol):
        self.repeatRow=repeatRow
        self.repeatCol=repeatCol
        self.islands=[]

        self.colOffset=0
        self.rowOffset=0

        self.colEndOffset=0
        self.rowEndOffset=0

    def addIsland(self,island):
        self.islands.append(island)

    def invalidateCache(self):
        self.getSamplePoints.cache_clear()

    @cache
    def getSamplePoints(self,maxRow,maxCol):
        if self.colOffset>0:self.colOffset-=self.repeatCol
        if self.colOffset<-self.repeatCol: self.colOffset+=self.repeatCol
        if self.rowOffset>0:self.rowOffset-=self.repeatRow
        if self.rowOffset<-self.repeatRow: self.rowOffset+=self.repeatRow
        if self.colEndOffset>0:self.colEndOffset=0
        if self.rowEndOffset>0:self.rowEndOffset=0

        legAngles=[]
        points=[]
        for island in self.islands:
            islePoints=island.getPoints()
            for point in islePoints:
                point.row-=2*self.rowOffset
                point.col-=2*self.colOffset
            points.append(islePoints)
            legAngles.append(island.leg1Angle)

        newPoints=[]
        for i in range(math.floor(self.rowOffset),math.ceil(maxRow/self.repeatRow)):
            for island,legAngle in zip(points,legAngles):
                pointGroup=[]
                for point in island:
                    pointGroup.append(RowCol(point.row+i*self.repeatRow,point.col))
                newPoints.append(pointGroup)
                legAngles.append(legAngle)
        points+=newPoints

        newPoints=[]
        for i in range(math.floor(self.colOffset),math.ceil(maxCol/self.repeatCol)):
            for island,legAngle in zip(points,legAngles):
                pointGroup=[]
                for point in island:
                    pointGroup.append(RowCol(point.row,point.col+i*self.repeatCol))
                newPoints.append(pointGroup)
                legAngles.append(legAngle)
        points+=newPoints

        validPoints=[]
        validLegAngles=[]
        for island,legAngle in zip(points,legAngles):
            valid=True
            for point in island:
                if point.row<0 or point.col<0 or point.row>=maxRow+self.rowEndOffset or point.col>=maxCol+self.colEndOffset:
                    valid=False
                    break

            if valid:
                validPoints.append(island)
                validLegAngles.append(legAngle)
        points=validPoints
        legAngles=validLegAngles

        #remove duplicates
        seenHashes=[]
        validPoints=[]
        validLegAngles=[]
        for island,legAngle in zip(points,legAngles):
            thisHash=hash(",".join([str(point) for point in island]))
            if thisHash not in seenHashes:
                validPoints.append(island)
                validLegAngles.append(legAngle)
                seenHashes.append(thisHash)

        assert len(validPoints)==len(validLegAngles)

        return validPoints, validLegAngles

    def incrementYRadius(self):
        for island in self.islands:
            island.radius*=1.01
        self.invalidateCache()
    def decrementYRadius(self):
        for island in self.islands:
            island.radius*=0.99
        self.invalidateCache()

latticeType="bethe"

if latticeType=="normal":
    yLattice=Pattern(math.sqrt(3),2)
    yLattice.addIsland(YIsland(0,0.5,90,0.1))
    yLattice.addIsland(YIsland(0,1.5,90,0.1))
    yLattice.addIsland(YIsland(math.sqrt(3)/2,1,90,0.1))
    yLattice.addIsland(YIsland(math.sqrt(3)/2,2,90,0.1))
elif latticeType=="YOnKag":
    yLattice=Pattern(math.sqrt(3),2)
    yLattice.addIsland(YIsland(0,0,90,0.1))
    yLattice.addIsland(YIsland(0,1,90,0.1))
    yLattice.addIsland(YIsland(math.sqrt(3)/2,0.5,90,0.1))
elif latticeType=="YOnHex":
    yLattice=Pattern(math.sqrt(3),3)
    yLattice.addIsland(YIsland(0,0,90,0.1))
    yLattice.addIsland(YIsland(0,1,90,0.1))
    yLattice.addIsland(YIsland(math.sqrt(3)/2,1.5,90,0.1))
    yLattice.addIsland(YIsland(math.sqrt(3)/2,2.5,90,0.1))
elif latticeType=="hex":
    yLattice=Pattern(math.sqrt(3),3)
    yLattice.addIsland(YIsland(0,0,0,0.1))
    yLattice.addIsland(YIsland(0,1,60,0.1))
    yLattice.addIsland(YIsland(math.sqrt(3)/2,1.5,0,0.1))
    yLattice.addIsland(YIsland(math.sqrt(3)/2,2.5,60,0.1))
elif latticeType=="snowflake":
    r3o2=math.sqrt(3)/2

    yLattice=Pattern((math.sqrt(5)/2+4/8),1)
    yLattice.addIsland(YIsland(1/8,0,30,0.1))
    yLattice.addIsland(YIsland(-1/8,0.5,90,0.1))
    yLattice.addIsland(YIsland(math.sqrt(5)/4+1/8,0,90,0.1))
    yLattice.addIsland(YIsland(math.sqrt(5)/4+3/8,0.5,30,0.1))
    #yLattice.addIsland(YIsland(0,,90,0.1))
    #yLattice.addIsland(YIsland(0,1.5,30,0.1))
elif latticeType=="chiral":
    angle=15
    print(f"chiral angle: {angle} degrees")

    yLattice=Pattern(math.sqrt(3),2)
    yLattice.addIsland(YIsland(0,0.5,90-angle,0.1))
    yLattice.addIsland(YIsland(0,1.5,90-angle,0.1))
    yLattice.addIsland(YIsland(math.sqrt(3)/2,1,90-angle,0.1))
    yLattice.addIsland(YIsland(math.sqrt(3)/2,2,90-angle,0.1))
elif latticeType=="bethe":
    yLattice=Pattern(10,10)
    n=2
    gamma=0
    r3o2=math.sqrt(3)/2

    def addBetheIslands(yLattice,x,y,n,vectorAngle,islandSpacing,radius,gamma):
        if n==0:
            return

        if vectorAngle is None:
            angle=-90
            nextAngles=[90,210,330]
        else:
            angle=vectorAngle
            print(vectorAngle)
            nextAngles=[vectorAngle+60,vectorAngle-60]
        yLattice.addIsland(YIsland(y,x,-angle,radius))

        islandSpacing=islandSpacing*((1-gamma))
        for angle in nextAngles:
            addBetheIslands(yLattice,x+islandSpacing*cosDeg(angle),y+islandSpacing*sinDeg(angle),n-1,angle,islandSpacing,radius*(1-gamma),gamma)

    addBetheIslands(yLattice,1,1,n,None,2,0.5,gamma)

    # if N>1:
    #     dist=(1-gamma)+(1-2*gamma)
    #     yLattice.addIsland(YIsland(1/2*dist,-r3o2*dist,90,1-gamma))
    #     yLattice.addIsland(YIsland(0,dist,90,1-gamma))
    #     yLattice.addIsland(YIsland(-1/2*dist,-r3o2*dist,90,1-gamma))

BWImage=getBWImage(phase_image)

imageShown="phase"

def show():
    image=[]
    if imageShown=="phase":
        image=phase_image.copy()
    elif imageShown=="height":
        image=height_image.copy()
    elif imageShown=="bw":
        image=cv2.cvtColor(BWImage.copy(),cv2.COLOR_GRAY2RGB)

    n.draw(image,showGrid=False)

    if not n.dragging:
        points,_=yLattice.getSamplePoints(n.rows-1,n.cols-1)
        for island in points:
            colorPattern=[]
            for point in island:
                coord=n.getXY(point.row,point.col)
                bwColor=BWImage[coord[1]][coord[0]]
                if bwColor==0:
                    color=(255,0,0)
                    colorPattern.append(-1)
                elif bwColor==255:
                    color=(0,0,255)
                    colorPattern.append(1)
                else:
                    color=(0,255,0)
                    colorPattern.append(0)
                cv2.circle(image,coord,2,color,-1)

            if YIsland.hasError(colorPattern):
                cv2.circle(image,n.getXY(island[0].row,island[0].col),5,(0,255,0),3)

    cv2.imshow("window",image)

def cycleArea(x,y):
    type=BWImage[y][x]
    blankSquare=np.zeros((4,4))
    if type==255:
        blankSquare[::]=0
    elif type==0:
        blankSquare[::]=127
    elif(type==127):
        blankSquare[::]=255

    BWImage[(y-2):(y+2),(x-2):(x+2)]=blankSquare

def countTotalErrors():
    total=0
    points,_=yLattice.getSamplePoints(n.rows-1,n.cols-1)
    for island in points:
        colorPattern=[]
        for point in island:
            coord=n.getXY(point.row,point.col)
            bwColor=BWImage[coord[1]][coord[0]]
            if bwColor==0:
                colorPattern.append(-1)
            elif bwColor==255:
                colorPattern.append(1)
            else:
                colorPattern.append(0)

        if YIsland.hasError(colorPattern):
            total+=1
    return total

def jiggle(x,y):
    fixedPoint=n.getNearestFixedPoint(x,y)

    errorsBefore=countTotalErrors()

    node=fixedPoint["node"]
    originalNode=node.copy()

    radius=5

    node.x+=random()*2*radius-radius
    node.y+=random()*2*radius-radius
    n.invalidateCache()

    if(errorsBefore<countTotalErrors()):
        fixedPoint["node"]=originalNode

    n.invalidateCache()

def dataAsString():
    string="row,col,leg 1 angle,leg 1 color,leg 2 color,leg 3 color,center color\n"
    points,legAngles=yLattice.getSamplePoints(n.rows-1,n.cols-1)
    for island,legAngle in zip(points,legAngles):
        colorPattern=[]
        for point in island:
            coord=n.getXY(point.row,point.col)
            bwColor=BWImage[coord[1]][coord[0]]
            if bwColor==0:
                colorPattern.append(-1)
            elif bwColor==255:
                colorPattern.append(1)
            else:
                colorPattern.append(0)
        colorCode=colorPattern
        string+=f"{island[0].row},{island[0].col},{legAngle},{colorCode[1]},{colorCode[2]},{colorCode[3]},{colorCode[0]}\n"

    return string

def mouse_event(event, x, y,flags, param):
    global lastMouse
    if event == cv2.EVENT_RBUTTONDOWN:
        n.splitAtClosestPoint(x,y)
    elif event ==cv2.EVENT_LBUTTONDOWN:
        n.selectNearestFixedPoint(x,y)
        n.dragging=True
    elif event==cv2.EVENT_MOUSEMOVE:
        n.updateDragging(x,y)
    elif event==cv2.EVENT_LBUTTONUP:
        n.stopDragging()
    elif event == cv2.EVENT_RBUTTONDOWN:
        pass

    lastMouse=(x,y)

    show()

n=NodeNetwork(Node(10,10),Node(600,10),Node(10,600),Node(600,600),15,15)

show()
cv2.setMouseCallback('window', mouse_event)

while(True):
    show()

    key=cv2.waitKey(0)
    if(key==ord("\r")):
        break;
    elif(key==ord("r")):
        n.addRow()
    elif(key==ord("e")):
        n.removeRow()
    elif(key==ord("c")):
        n.addCol()
    elif(key==ord("x")):
        n.removeCol()
    elif(key==ord("q")):
        if imageShown=="phase":imageShown="height"
        elif imageShown=="height":imageShown="bw"
        elif imageShown=="bw":imageShown="phase"
    elif(key==ord("+")):
        yLattice.incrementYRadius()
    elif(key==ord("-")):
        yLattice.decrementYRadius()
    elif(key==ord("g")):
        yLattice.rowOffset-=0.01
        yLattice.invalidateCache()
    elif(key==ord("h")):
        yLattice.colOffset-=0.01
        yLattice.invalidateCache()
    elif(key==ord("a")):
        cycleArea(*lastMouse)
    elif(key==ord("j")):
        start=time.time()
        while(time.time()-start<0.25):
            jiggle(*lastMouse)
        print(countTotalErrors())
    elif(key==ord("b")):
        yLattice.colEndOffset-=0.25
        yLattice.invalidateCache()
    elif(key==ord("n")):
        yLattice.colEndOffset+=.25
        yLattice.invalidateCache()
    elif(key==ord("k")):
        yLattice.rowEndOffset-=0.25
        yLattice.invalidateCache()
    elif(key==ord("l")):
        yLattice.rowEndOffset+=0.25
        yLattice.invalidateCache()

outputname=args.image[0].split("/")[-1].split(".")[0]
print(outputname)

with open(outputname+".csv", 'w') as file:
    file.write(dataAsString())

outputImage=np.zeros((1000,1000,3), np.uint8)
outputImage[:,:]=(127,127,127)

cv2.imwrite("output.jpg", np.float32(outputImage));

cv2.destroyAllWindows()


import pandas as pd
import numpy as np
import scipy
import sklearn
from sklearn import linear_model
from sklearn import preprocessing
from sklearn.preprocessing import OneHotEncoder
import matplotlib.pyplot as plt
from datetime import *
from lib.massager import *

massage = massager()
filePath = "~/Documents/Loyola/Research/Shriner/data/CP_HAM.csv"

#Read in relevant columns, convert categorical variables to binary.
df = pd.read_csv(filePath)
dfcat = df.iloc[:, [1,3,4,5,9]].copy()
catnames = list(dfcat)
dmDF = pd.get_dummies(df, columns= catnames)
dmDF = dmDF.drop(['Comment'], axis=1)
dmDF = dmDF.dropna()
#print(dmDF['TestDate'].head())
#Get unique patient ids
patients = dmDF.DeIdentifyNumber.unique()

#print(patients)

#running average gaussian smoothing
#break down by surgery
#y axis should be gdi difference from day of surgery
#so gdi of date of record - gdi day of preop

sx = {}
for p in patients:
    x = dmDF.loc[dmDF['DeIdentifyNumber'] == p]
    x = x[x['StudyType_Pre-op'] != 0]
    sxDate = x['TestDate'].unique()
    sx[p] = sxDate

patientGDI = {}

for p in patients:
    pFrame = dmDF.loc[dmDF['DeIdentifyNumber'] == p]
    pFrame = pFrame[pFrame['StudyType_Pre-op'] != 0]
    if(pFrame.shape[0] > 0):
        pFrame = pFrame[pFrame['Procedures.Side_L'] == pFrame['MotionParams.Side_Left']]
        gdiList = pFrame['GDI'].tolist()
        avgGdi = sum(gdiList)/len(gdiList)
        patientGDI[p] = avgGdi

# print(len(sx))
# print(len(patientGDI))

for i, row in dmDF.iterrows():
    row['Gdi Differential'] = row['GDI'] - row['DeIdentifyNumber']

def diff(row):
    if(row['DeIdentifyNumber'] in patientGDI):
        x = row['GDI'] - patientGDI[row['DeIdentifyNumber']]
        return x
    else:
        return 'n/a'

def sd (row):
    if (sx[row['DeIdentifyNumber']].shape[0] > 0):
        x = pd.to_datetime(row['TestDate']) - pd.to_datetime(sx[row['DeIdentifyNumber']][0])
        return x.days
    else:
        return 'n/a'

# def movingaverage(interval, window_size):
#     window= np.ones(int(window_size))/float(window_size)
#     return np.convolve(interval, window, 'same')
#
# def runningMeanFast(x, N):
#     return np.convolve(x, np.ones((N,))/N)[(N-1):]
#
# def running_mean(x, n):
#     # cumsum = np.cumsum(np.insert(x, 0, 0))
#     # return (cumsum[N:] - cumsum[:-N]) / N
#     ret = np.cumsum(x)
#     ret[n:] = ret[n:] - ret[:-n]
#     return ret[n - 1:] / n

def getYearAvg(df):
    unique_vals = df['Time From Surgery'].unique()
    unique_vals.sort()
    for x in unique_vals:
        print(x)

def myround(x, base=5):
    f = int(base * round(float(x) / base))
    if f == 0:
        f += 5
    else:
        f = f
    return f

def cumMovAvg(df):
    """
    This will be used to figure out
    the days that we have had and the averages
    that exist therein them, so that we can connect them
    and stitch them together.
    """

    # Calculate Step Length via binning process
    df_time = df['Time From Surgery'].sort_values(ascending=True)
    # print(df_time)
    least_time = df_time.iloc[0]
    most_time = df_time.iloc[len(df) - 1]
    print(least_time, most_time)

    # Use Max - Min Averaging to Figure out N values; the more reccurent they are the smoother they will be
    N = (least_time + most_time) / len(df_time)
    print(N)
    N = myround(N)
    print('New N:', N)

    # Now that N is set, divide the dataframe into the 'N' Values. then, we will go
    # Ahead and figure out how many rows are left at the end, which will be averaged
    # In an ungraceful way

    last_set = len(df) % N
    how_many_extra = len(df) / N
    print('Extra set of rows', how_many_extra)
    print('Last set of rows:', last_set)

    # Write a 'For' loop to split data into 'N' sizes,
    # Then average the columns for that 'N' data,
    # And write to a new df containing the averages and
    # the x and y values.

    i = 0
    row_start = 0
    while i < len(df) - last_set:
        tmp_df = df.iloc[row_start:N]
        row_start = row_start + N
        N += N
        i = i + N
        # print(tmp_df)

def calculate_running_mean_list(window_size, dict_of_data, original_df, col_to_search, col_to_sum):

    print(dict_of_data)
    patient_dates = []
    average_values = []
    for k,v in dict_of_data.items():
        tmp_list = []
        tmp_list.append(v)
        patient_dates.append(k)
        for item in tmp_list:
            tmp_add_array = []
            for item in item:
                rows = original_df.loc[original_df[col_to_search] == item]
                print('======================')
                print(rows[col_to_sum])
                print(item)
                print(rows[col_to_sum].mean())
                print('======================')
                tmp_add_array.append(rows[col_to_sum].mean())
            average_values.append(np.sum(tmp_add_array))
    a = np.array(average_values)
    b = np.empty(len(average_values))

    b.fill(window_size)
    divided_array = np.divide(a, b)
    scaled_divided_array = np.multiply(divided_array, 10)

    try:
        len(dict_of_data) == len(average_values)

    except:
        print("Something is messed up with the data. Please re-check.")

    print(scaled_divided_array)
    print(patient_dates)

    scaled_df_avg = pd.DataFrame({'Time From Surgery': patient_dates, 'Running_Mean_Avg': scaled_divided_array})
    return scaled_df_avg

def movingDateAvg(df, N):
    """
    :param df: The dataframe that we want to run a cumulative mean on
    :param N: The size of the window (in one direction, so make this the TOTAL length of the window)
    :return: Dataframe that will be graphed ontop of the graphs that are generated.
    """
    # Get the total window size Needed for the dataset "Moving Average" by calculating lower
    # and upper bounds
    print('Window Size =', N)
    window_size = int(N / 2)
    lower_bound = window_size * -1
    upper_bound = window_size
    print('Upper Bound:', upper_bound, '\n', 'Lower Bound', lower_bound)

    # Check that the lower and upper bounds are valid
    try:
        lower_bound < upper_bound
    except:
        print("Your boundary conditions are incorrect.")

    # Create a massager object and use the method to clean the
    # Values by making everything within it a DateTime Object
    # df = massage.typeCastToDateTime(df, 'Time From Surgery')
    unique_dates = df['Time From Surgery'].unique()

    # Create a dataframe to store the dateranges and values needed
    columns = ['Time From Surgery', 'UpperDate', 'LowerDate']
    df_of_ranges = pd.DataFrame(columns=columns)
    for every_date in unique_dates:
        lower_date = every_date + lower_bound
        upper_date = every_date + upper_bound
        df_of_ranges = df_of_ranges.append({'Time From Surgery': every_date,'UpperDate': upper_date, 'LowerDate' : lower_date}, ignore_index=True)

    print(list(df_of_ranges))
    print(df_of_ranges.index)

    # for index, row in df_of_ranges.iteritems():
    #     print(row['TestDate'])
    total_frame = []
    for ix in df_of_ranges.index:
        df2 = []
        upper_bound_date = df_of_ranges.loc[ix]['UpperDate']
        lower_bound_date = df_of_ranges.loc[ix]['LowerDate']

        for date in unique_dates:
            if lower_bound_date < date < upper_bound_date:
                df2.append(date)

        total_frame.append(df2)
    # print(df_of_ranges.loc[1]['UpperDate'], df_of_ranges.loc[1]['LowerDate'])
    # print(total_frame[1])

    # Create a Dict that has the key set to date, and the value set to the date ranges
    dict_data = {}
    i = 0
    while i < len(total_frame):
        dict_data.update({df_of_ranges['Time From Surgery'].iloc[i] : total_frame[i]})
        i += 1

    """
    Now that we have that the "range" of the value for each date, let's use the dict to locate the
    values that are needed to do the computation for each point, returning a set of the data points and
    averaging those values.
    N : Window Size
    """

    avg_mean_df = calculate_running_mean_list(N, dict_data, df, 'Time From Surgery', 'GDI Differential')
    return avg_mean_df

dmDF['Time From Surgery'] = dmDF.apply(lambda row: sd(row),axis=1)
dmDF['GDI Differential'] = dmDF.apply(lambda row: diff(row), axis=1)

dmDF = dmDF[dmDF['Time From Surgery'] != 'n/a']
dmDF = dmDF[dmDF['GDI Differential'] != 'n/a']

sxBTXHams = dmDF.loc[dmDF['SxCode_BTX-Hams'] == 1]
sxHamsRelease = dmDF.loc[dmDF['SxCode_Ham-Release'] == 1]
sxHamsM = dmDF.loc[dmDF['SxCode_Hams-M'] == 1]
sxHamsML = dmDF.loc[dmDF['SxCode_Hams-ML'] == 1]

avg_sxBTXHams = movingDateAvg(sxBTXHams, 20)
avg_sxBTXHams = avg_sxBTXHams.sort_values(by= 'Time From Surgery', ascending=True)

# cumMovAvg(sxBTXHams)

# getYearAvg(sxBTXHams)
# columns = ['GDI', 'newIndex']
sxBTXHams_Vector = pd.DataFrame()
sxBTXHams_Vector = sxBTXHams_Vector.append(sxBTXHams['Time From Surgery'])
sxBTXHams_Vector = sxBTXHams_Vector.append(sxBTXHams['GDI Differential'])
sxBTXHams_Vector = sxBTXHams_Vector.transpose()
sxBTXHams_Vector = sxBTXHams_Vector.set_index(sxBTXHams_Vector['Time From Surgery'])

# print(sxBTXHams_Vector)

plt.figure(1)

# plt.plot([1,2,3])
# plt.subplot(221)
plt.scatter(sxBTXHams['Time From Surgery'], sxBTXHams['GDI Differential'])
plt.scatter(avg_sxBTXHams['Time From Surgery'], avg_sxBTXHams['Running_Mean_Avg'])
plt.plot(avg_sxBTXHams['Time From Surgery'], avg_sxBTXHams['Running_Mean_Avg'], marker='o', color='r')
plt.title("Time since Surgery (BTX-Hams)")
plt.xlabel("Days from Surgery")
plt.ylabel("GDI Differential")
plt.axhline()

# plt.subplot(222)
# plt.scatter(sxHamsRelease['Time From Surgery'], sxHamsRelease['GDI Differential'])
# plt.plot(pd.rolling_mean(sxHamsRelease['GDI Differential'], window=2, center=False), "r")
# plt.title("Time from First Surgery (Hams Release)")
# plt.xlabel("Days from Surgery")
# plt.ylabel("GDI Differential")
# plt.axhline()
#
# plt.subplot(223)
# plt.scatter(sxHamsM['Time From Surgery'], sxHamsM['GDI Differential'])
# plt.plot(pd.rolling_mean(sxHamsM['GDI Differential'], window=2), "r")
# plt.title("Time from First Surgery (Hams M")
# plt.xlabel("Days from Surgery")
# plt.ylabel("GDI Differential")
# plt.axhline()
#
# plt.subplot(224)
# plt.scatter(sxHamsML['Time From Surgery'], sxHamsML['GDI Differential'])
# plt.plot(pd.rolling_mean(sxHamsML['GDI Differential'], window=5), "r")
# plt.title("Time from First Surgery (Hams ML")
# plt.xlabel("Days from Surgery")
# plt.ylabel("GDI Differential")
# plt.axhline()
plt.show()


import re

import setuptools

requires = [
    'isort',
    'flake8>=3.0.0',
]

with open('README.rst') as fh:
    long_description = re.sub(
        '^.. start-no-pypi.*^.. end-no-pypi', '', fh.read(), flags=re.M | re.S)

setuptools.setup(
    name="flake8_imports",
    license="MIT",
    version="0.1.1",
    description="isort extension flake8",
    long_description=long_description,
    author="Michael van Tellingen",
    author_email="michaelvantellingen@gmail.com",
    url="https://gitlab.com/mvantellingen/flake8-imports",
    install_requires=requires,
    package_dir={'': 'src'},
    py_modules=['flake8_imports'],
    entry_points={
        'flake8.extension': [
            'I0 = flake8_imports:ImportsPlugin',
        ],
    },
    classifiers=[
        "Framework :: Flake8",
        "Environment :: Console",
        "Intended Audience :: Developers",
        "License :: OSI Approved :: MIT License",
        "Programming Language :: Python",
        "Programming Language :: Python :: 2",
        "Programming Language :: Python :: 3",
        "Topic :: Software Development :: Libraries :: Python Modules",
        "Topic :: Software Development :: Quality Assurance",
    ],
)


"""

Citation:
@inproceedings{ bitsnlp2021dravidian,
 title={Sentiment Analysis of Dravidian Code Mixed Data},
 author={Mandalam, Asrita Venkata and Sharma, Yashvardhan},
 booktitle={ 15th Conference of the European Chapter of the Association for Computational Linguistics 2021 (EACL 2021) },
 year={2021}
}

"""

import numpy as np
import pandas as pd
import re
from keras.layers import LSTM, Dense, Embedding, Input
from keras.preprocessing.text import Tokenizer
from keras.preprocessing.sequence import pad_sequences
import keras

from tqdm import tqdm
tqdm.pandas(desc="progress-bar")
from gensim.models.word2vec import Word2Vec
from gensim.models.doc2vec import TaggedDocument
import multiprocessing
from sklearn import utils
from keras.models import Model
from keras.layers import BatchNormalization, Activation

def token(sentence):
    tokens = []
    for t in re.findall("[a-zA-Z]+",sentence):
         if len(t)>=1:
             tokens.append(t)
    return tokens

def emoji_ch (words):
    if words == 'ЁЯШД' :
      words='good'
    elif words == 'ЁЯШЖ' :
      words='good'
    elif words == 'ЁЯШК' :
      words='good'
    elif words == 'ЁЯШГ' :
      words='good'
    elif words == 'ЁЯдм' :
      words='bad'
    elif words == 'ЁЯШП' :
      words='good'
    elif words == 'ЁЯШН' :
      words='good'
    elif words == 'ЁЯШШ' :
      words='good'
    elif words == 'ЁЯШЪ' :
      words='good'
    elif words == 'ЁЯШ│' :
      words='flushed'
    elif words == 'ЁЯШМ' :
      words='bad'
    elif words == 'ЁЯШЖ' :
      words='good'
    elif words == 'ЁЯШВ' :
      words='good'
    elif words == 'ЁЯШО' :
      words='good'
    elif words == 'ЁЯдп' :
      words='blow_mind'
    elif words == 'тЬМя╕П' :
      words='vhand'
    elif words == 'ЁЯдШ' :
      words='metal'
    elif words == 'ЁЯдж' :
      words='bad'
    elif words == 'ЁЯдй':
      words='good'
    elif words == 'ЁЯе░':
      words='good'
    elif words == 'ЁЯдФ':
      words='thinking'
    elif words == 'ЁЯдг':
      words='good'
    elif words == 'ЁЯдЧ':
      words = 'good'
    else :
      return None
    return words+" "

def tamilchar(ch):
    if ch == u'\u0B85' or ch== u'роЕ':
        ch="A"
    elif ch == u'\u0B86' or ch== u'роЖ':
        ch="AA"
    elif ch == u'\u0B87' or ch== u'роЗ':
        ch="I"
    elif ch == u'\u0B88' or ch== u'роИ':
        ch="II"
    elif ch == u'\u0B89' or ch== u'роЙ':
        ch="U"
    elif ch == u'\u0B8A' or ch== u'роК':
        ch="UU"
    elif ch == u'\u0B8E' or ch== u'роО':
        ch="E"
    elif ch == u'\u0B8F' or ch== u'роП':
        ch="EE"
    elif ch == u'\u0B90' or ch== u'роР':
        ch="AI"
    elif ch == u'\u0B92' or ch== u'роТ':
        ch="O"
    elif ch == u'\u0B93' or ch== u'роУ':
        ch="OO"
    elif ch == u'\u0B94' or ch== u'роФ':
        ch="AU"
    elif ch ==u'\u0B95'or ch==u'роХ':
        ch="KA"
    elif ch ==u'\u0B99'or ch==u'роЩ':
        ch="NGA"
    elif ch ==u'\u0B9A'or ch==u'роЪ':
        ch="SA"
    elif ch ==u'\u0B9C' or ch==u'роЬ':
        ch="JA"
    elif ch ==u'\u0B9E'or ch==u'роЮ':
        ch=u"NYA"
    elif ch ==u'\u0B9F'or ch==u'роЯ':
        ch="DA"
    elif ch ==u'\u0BA3'or ch==u'рог':
        ch="NNA"
    elif ch ==u'\u0BA4'or ch==u'род':
        ch="THA"
    elif ch ==u'\u0BA8'or ch==u'рои':
        ch="NA"
    elif ch ==u'\u0BA9' or ch==u'рой':
        ch="NA"
    elif ch ==u'\u0BAA'or ch==u'рок':
        ch="PA"
    elif ch ==u'\u0BAE'or ch==u'роо':
        ch="MA"
    elif ch ==u'\u0BAF' or ch==u'роп':
        ch="YA"
    elif ch ==u'\u0BB0' or ch==u'ро░':
        ch="RA"
    elif ch ==u'\u0BB1'or ch==u'ро▒':
        ch="RRA"
    elif ch ==u'\u0BB2' or ch==u'ро▓':
        ch="LA"
    elif ch ==u'\u0BB3'or ch==u'ро│':
        ch="LLA"
    elif ch ==u'\u0BB4'or ch ==u'ро┤':
        ch=="LLLA"
    elif ch ==u'\u0BB5'or ch==u'ро╡':
        ch="VA"
    elif ch ==u'\u0BB6'or ch==u'ро╢':
        ch="SHA"
    elif ch ==u'\u0BB7'or ch==u'ро╖':
        ch="SSA"
    elif ch ==u'\u0BB8'or ch==u'ро╕':
        ch="SA"
    elif ch ==u'\u0BB9'or ch==u'ро╣':
        ch="HA"
    elif ch ==u'\u0BBE'or ch==u'$ро╛':
        ch="AA"
    elif ch ==u'\u0BBF'or ch==u'$ро┐':
        ch="I"
    elif ch ==u'\u0BC0'or ch==u'$рпА':
        ch="II"
    elif ch ==u'\u0BC1'or ch==u'$рпБ':
        ch="U"
    elif ch ==u'\u0BC2'or ch==u'рпВ$':
        ch="UU"
    elif ch ==u'\u0BC6'or ch==u'$рпЖ':
        ch="E"
    elif ch ==u'\u0BC7'or ch==u'$рпЗ':
        ch="EE"
    elif ch ==u'\u0BC8'or ch==u'$рпИ':
        ch="AI"
    elif ch ==u'\u0BCA'or ch==u'$рпК':
        ch="O"
    elif ch ==u'\u0BCB'or ch==u'$рпЛ':
        ch="OO"
    elif ch ==u'\u0BCC'or ch==u'$рпМ':
        ch="AU"
    elif ch ==u'\u0BCD'or ch==u'$рпН':
        ch="PULLI"
    elif ch ==u'\u0BD0'or ch==u'рпР':
        ch="OM"
    elif ch ==u'\u0BD7'or ch==u'$рпЧ':
        ch="AU"
    else:
        return None
    return ch

def preprocess(word):
  word=re.sub(r'([a-z])\1+', r'\1',word)
  return word

def tamilword(word):
    fla=0
    string=""
    for ch in word:
        if(tamilchar(ch) is not None):
            ch=tamilchar(ch)
            fla=1
        if(emoji_ch(ch) is not None):
            ch=emoji_ch(ch)
            fla=1
        string=string+str(ch)
    if(fla==1):
        return string
    else:
        return None

def malchar(ch):
    if ch == u'р┤Е':
        ch="A"
    elif ch == u'р┤Ж':
        ch="AA"
    elif ch == u'р┤З':
        ch="I"
    elif ch == u'р┤И':
        ch="II"
    elif ch == u'р┤Й':
        ch="U"
    elif ch == u'р┤К':
        ch="UU"
    elif ch == u'р┤О':
        ch="E"
    elif ch == u'р┤П':
        ch="EE"
    elif ch == u'р┤Р':
        ch="AI"
    elif ch == u'р┤Т':
        ch="O"
    elif ch == u'р┤У':
        ch="OO"
    elif ch == u'р┤Ф':
        ch="AU"
    elif ch ==u'р┤Х'or ch==u'р┤Ц':
        ch="KA"
    elif ch ==u'р┤Ч'or ch==u'р┤Ш':
        ch="GA"
    elif ch ==u'р┤Щ':
        ch="NGA"
    elif ch ==u'р┤Ъ'or ch==u'р┤Ы':
        ch="CH"
    elif ch ==u'р┤Ъ'or ch==u'р┤Ы':
        ch="CH"
    elif ch ==u'р┤╢'or ch==u'р┤╖':
        ch="SH"
    elif ch ==u'р┤╕':
        ch="S"
    elif ch ==u'р┤Ь' or ch==u'р┤Э':
        ch="JA"
    elif ch ==u'р┤б'or ch==u'р┤ж':
        ch="DA"
    elif ch ==u'р┤е'or ch==u'р┤д':
        ch="THA"
    elif ch ==u'р┤г'or ch==u'р┤и':
        ch="NA"
    elif ch ==u'р┤к':
        ch="PA"
    elif ch ==u'р┤о':
        ch="MA"
    elif ch ==u'р┤п':
        ch="YA"
    elif ch ==u'р┤░':
        ch="RA"
    elif ch ==u'р┤│':
        ch="LA"
    elif ch ==u'р┤╡':
        ch="VA"
    elif ch ==u'р┤╣':
        ch="HA"
    elif ch ==u'р┤н'or ch==u'р┤м':
        ch="BA"
    elif ch ==u'р┤в'or ch==u'р┤з':
        ch="DH"
    elif ch ==u'р┤а':
        ch="DT"
    elif ch ==u'р┤Я':
        ch="T"
    elif ch ==u'р┤Ю':
        ch="NJ"
    elif ch ==u'р┤л':
        ch="PH"
    elif ch ==u'р┤┤':
        ch="ZH"
    elif ch ==u'р┤▒':
        ch="RA"
    else:
        return None
    return ch

def malword(word):
    fla=0
    string=""
    for ch in word:
        if(malchar(ch) is not None):
            ch=malchar(ch)
            fla=1
        string=string+str(ch)
    if(fla==1):
        return string
    else:
        return None

colnames=['text','label']
df = pd.read_csv(r'/content/drive/My Drive/Dravidian/EACL/tamil_train.tsv',names=colnames, delimiter='\t', error_bad_lines=False, header=None,
                      usecols=['text','label'], na_values=" NaN",skiprows=[0])

df_val = pd.read_csv(r'/content/drive/My Drive/Dravidian/EACL/tamil_dev.tsv',names=colnames, delimiter='\t', error_bad_lines=False, header=None,
                      usecols=['text','label'], na_values=" NaN",skiprows=[0])

colnames=['index','text','label']
df_test = pd.read_csv(r'/content/drive/My Drive/Dravidian/EACL/tamil_test.tsv',names=colnames, delimiter='\t', error_bad_lines=False, header=None,
                      usecols=['text','label'], na_values=" NaN",skiprows=[0])

# colnames=['text','label']
# df = pd.read_csv(r'/content/drive/MyDrive/Dravidian/EACL/malayalam_train.tsv',names=colnames, delimiter='\t', error_bad_lines=False, header=None,
#                       usecols=['text','label'], na_values=" NaN",skiprows=[0])

# df_val = pd.read_csv(r'/content/drive/MyDrive/Dravidian/EACL/malayalam_dev.tsv',names=colnames, delimiter='\t', error_bad_lines=False, header=None,
#                       usecols=['text','label'], na_values=" NaN",skiprows=[0])

# colnames=['index','text','label']
# df_test = pd.read_csv(r'/content/drive/MyDrive/Dravidian/EACL/malayalam_test.tsv',names=colnames, delimiter='\t', error_bad_lines=False, header=None,
#                       usecols=['text','label'], na_values=" NaN",skiprows=[0])

labels = ['Mixed_feelings ','Negative ','Positive ','not-Tamil ','unknown_state ']

for index, line in df.iterrows():
  if line['label'].lower() == labels[0].lower():
        line['label'] = 0
  elif line['label'].lower() == labels[1].lower():
        line['label'] = 1
  elif line['label'].lower() == labels[2].lower():
        line['label'] = 2
  elif line['label'].lower() == labels[3].lower():
        line['label'] = 3
  elif line['label'].lower() == labels[4].lower():
        line['label'] = 4
  i=line[0].split()
  for word in range(len(i)):
      for ch in range(len(i[word])):
          checker=emoji_ch(i[word][ch])
          if(checker is not None):
              i[word]+=checker

      checker=tamilword(i[word])
      if(checker is not None):
          i[word]=checker
      i[word]=preprocess(i[word])
  line[0]=' '.join(i)

for index, line in df_val.iterrows():
  if line['label'].lower() == labels[0].lower():
        line['label'] = 0
  elif line['label'].lower() == labels[1].lower():
        line['label'] = 1
  elif line['label'].lower() == labels[2].lower():
        line['label'] = 2
  elif line['label'].lower() == labels[3].lower():
        line['label'] = 3
  elif line['label'].lower() == labels[4].lower():
        line['label'] = 4
  i=line[0].split()
  for word in range(len(i)):
      for ch in range(len(i[word])):
          checker=emoji_ch(i[word][ch])
          if(checker is not None):
              i[word]+=checker

      checker=tamilword(i[word])
      if(checker is not None):
          i[word]=checker
      i[word]=preprocess(i[word])
  line[0]=' '.join(i)

labels = ['Mixed_feelings','Negative','Positive','not-Tamil','unknown_state']
for index, line in df_test.iterrows():
  if line['label'].lower() == labels[0].lower():
        line['label'] = 0
  elif line['label'].lower() == labels[1].lower():
        line['label'] = 1
  elif line['label'].lower() == labels[2].lower():
        line['label'] = 2
  elif line['label'].lower() == labels[3].lower():
        line['label'] = 3
  elif line['label'].lower() == labels[4].lower():
        line['label'] = 4
  i=line[0].split()
  for word in range(len(i)):
      for ch in range(len(i[word])):
          checker=emoji_ch(i[word][ch])
          if(checker is not None):
              i[word]+=checker
      i[word]=preprocess(i[word])

      checker=tamilword(i[word])
      if(checker is not None):
          i[word]=checker
      i[word]=preprocess(i[word])

  line[0]=' '.join(i)

print(df.head())
print(df_val.head())
print(df_test.head())

x_train = df['text']
y_train = df['label']
x_dev = df_val['text']
y_dev = df_val['label']
x_test = df_test['text']
y_test = df_test['label']

from collections import Counter
unique = Counter()
df['text'].str.lower().str.split().apply(unique.update)
avl=[]
for a in df['text']:
  avl.append(len(a))

import math
cbowsize=100
sgsize=100
totalsize=cbowsize+sgsize
maxlen=math.ceil(sum(avl)/len(avl))
tokmaxwords=len(unique)
batch_size=128

def LabelComments(tweets,label):
    result = []
    prefix = label
    for i, t in zip(tweets.index, tweets):
        result.append(TaggedDocument(t.split(), [prefix + '_%s' % i]))
    return result

trainTotal = x_train
trainTotalAll = LabelComments(trainTotal, 'all')

cores = multiprocessing.cpu_count()
CBOW_Model = Word2Vec(sg=0, size=cbowsize, negative=10, window=15, min_count=2, workers=cores, alpha=0.1, min_alpha=0.001)
CBOW_Model.build_vocab([x.words for x in tqdm(trainTotalAll)])
for epoch in range(10):
    CBOW_Model.train(utils.shuffle([x.words for x in tqdm(trainTotalAll)]), total_examples=len(trainTotalAll), epochs=1)

from gensim.models import FastText
FASTTEXT_Model = FastText([x.words for x in tqdm(trainTotalAll)], size=sgsize, window=15, workers=4,sg=1,negative=10,iter=10)

embeddings_index = {}
for w in CBOW_Model.wv.vocab.keys():
  if(w in FASTTEXT_Model.wv.vocab.keys()):
    embeddings_index[w] = np.append(CBOW_Model.wv[w],FASTTEXT_Model.wv[w])

tokenizer = Tokenizer(num_words=tokmaxwords)
tokenizer.fit_on_texts(x_train)
sequences = tokenizer.texts_to_sequences(x_train)
x_train_sequences = pad_sequences(sequences, maxlen=maxlen)

sequences_val = tokenizer.texts_to_sequences(x_dev)
x_val_sequences= pad_sequences(sequences_val, maxlen=maxlen)

sequences_test = tokenizer.texts_to_sequences(x_test)
x_test_sequences = pad_sequences(sequences_test, maxlen=maxlen)

num_words = tokmaxwords
embedding_matrix = np.zeros((num_words, totalsize))
for word, i in tokenizer.word_index.items():
    if i >= num_words:
        continue
    embedding_vector = embeddings_index.get(word)
    if embedding_vector is not None:
        embedding_matrix[i] = embedding_vector

def LSTM_model(max_sequence_length, max_words_fn, embedding_dim, numberOfClasses):
    embedding_layer = Embedding(max_words_fn,embedding_dim,input_length=max_sequence_length,trainable=False,weights=[embedding_matrix])
    sequence_input = Input(shape=(max_sequence_length,), dtype='float32')
    embedded_sequences = embedding_layer(sequence_input)
    layer1 = LSTM(64, return_sequences=True, dropout = 0.3, recurrent_dropout=0.2)(embedded_sequences)
    layer2 = LSTM(32, dropout = 0.3, recurrent_dropout =0.2)(layer1)
    layer3 = Dense(numberOfClasses)(layer2)
    layer4 = BatchNormalization()(layer3)
    preds = Activation('softmax')(layer4)
    model = Model(sequence_input, preds)
    model.compile(loss='sparse_categorical_crossentropy',optimizer='adam',metrics=['acc'])
    model.summary()
    return model

max_words = tokmaxwords
maxlen = maxlen
embedding_dims = totalsize
model = LSTM_model(maxlen, max_words, embedding_dims, 5)
num_epochs = 500

y_train2 = np.asarray(y_train).astype('float32').reshape((-1,1))
y_val2 = np.asarray(y_dev).astype('float32').reshape((-1,1))

es_callback = keras.callbacks.EarlyStopping(monitor='val_loss', patience=5)
history = model.fit(x_train_sequences, y_train2, batch_size=batch_size,
                  callbacks=[es_callback], epochs=num_epochs, validation_data=(x_val_sequences, y_val2), shuffle=True,verbose=1)

from keras.utils import np_utils
from sklearn.metrics import classification_report
y_test3 = np_utils.to_categorical(y_test, 5)
predictions = model.predict(x_test_sequences)
prediction = (predictions>0.20)
print(classification_report(y_test3, prediction))


import os

import zeep

def test_hello_world():
    path = os.path.join(
        os.path.dirname(os.path.realpath(__file__)), "hello_world_recursive.wsdl"
    )
    client = zeep.Client(path)
    client.wsdl.dump()


import tkinter as tk
import sqlite3
import csv
import json
from tkinter import ttk, messagebox, filedialog

class PhoneBook(tk.Tk):
    def __init__(self, db_name):
        super().__init__()
        self.title('Телефонный справочник')
        self.phones_table = ttk.Treeview(self, selectmode='browse', show='headings',
            columns=('#1', '#2', '#3', '#4', '#5'))
        self.phones_table.heading('#1', text='#')
        self.phones_table.heading('#2', text='Фамилия')
        self.phones_table.heading('#3', text='Имя')
        self.phones_table.heading('#4', text='Телефон')
        self.phones_table.heading('#5', text='Описание')
        self.first_name_entry = ttk.Entry()
        self.last_name_entry = ttk.Entry()
        self.phone_number_entry = ttk.Entry()
        self.description_entry = ttk.Entry()
        self.import_button = ttk.Button(self, text="Импорт", command=self.import_file)
        self.export_button = ttk.Button(self, text="Экспорт", command=self.export_file)
        self.clear_button = ttk.Button(self, text="Очистить", command=self.clear_table)
        self.delete_button = ttk.Button(self, text="Удалить", command=self.delete_row)
        self.insert_button = ttk.Button(self, text="Вставить", command=self.insert_row)
        self.import_button.grid(row=0, column=0)
        self.export_button.grid(row=0, column=1)
        self.clear_button.grid(row=0, column=6)
        self.phones_table.grid(row=1, column=0, columnspan=7)
        self.last_name_entry.grid(row=2, column=0)
        self.first_name_entry.grid(row=2, column=1)
        self.phone_number_entry.grid(row=2, column=2)
        self.description_entry.grid(row=2, column=3)
        self.insert_button.grid(row=2, column=4)
        self.delete_button.grid(row=2, column=6)
        self.conn = sqlite3.connect(db_name)
        self.prepare_db()
        self.phones_table.bind("<<TreeviewSelect>>", self.item_selected)
    def item_selected(self, event):
        for selected_item in self.phones_table.selection():
            item = self.phones_table.item(selected_item)
            person = item['values']
            return person[0]
    def import_file(self):
        file_name = filedialog.askopenfilename()
        c = self.conn.cursor()
        if file_name.endswith('.csv'):
            with open(file_name, 'r') as csvfile:
                reader = csv.reader(csvfile)
                for row in reader:
                    c.execute('INSERT INTO book VALUES (null, ?, ?, ?, ?)', row)
        elif file_name.endswith('.json'):
            with open(file_name, 'r') as jsonfile:
                reader = json.load(jsonfile)
                data = []
                for row in reader['data']:
                    c.execute('INSERT INTO book VALUES (null, ?, ?, ?, ?)',
                        (row['last_name'], row['first_name'], row['phone_number'], row['description'])
                    )
        self.conn.commit()
        self.update_table()
    def export_file(self):
        c = self.conn.cursor()
        with open('C:\python\sem8\export.maf', 'w') as export_file:
            for row in c.execute('SELECT * FROM book'):
                export_file.write(row[1] + '\n')
                export_file.write(row[2] + '\n')
                export_file.write(row[3] + '\n')
                export_file.write(row[4] + '\n')
                export_file.write('\n')
    def prepare_db(self):
        c = self.conn.cursor()
        c.execute('''
            CREATE TABLE IF NOT EXISTS book
            (
                [id] INTEGER PRIMARY KEY AUTOINCREMENT,
                [last_name] TEXT,
                [first_name] TEXT,
                [phone_number] TEXT,
                [description] TEXT
            )
            ''')
        self.conn.commit()
    def clear_table(self):
        if not messagebox.askyesno(title='Очистить', message='Удалить ВСЕ записи?'):
            return
        self.phones_table.delete(*self.phones_table.get_children())
        c = self.conn.cursor()
        c.execute('DELETE FROM book')
        self.conn.commit()
        self.update_table()
    def insert_row(self):
        row = (
            self.first_name_entry.get(),
            self.last_name_entry.get(),
            self.phone_number_entry.get(),
            self.description_entry.get())
        c = self.conn.cursor()
        c.execute('INSERT INTO book VALUES (null, ?, ?, ?, ?)', row)
        self.conn.commit()
        self.update_table()
    def delete_row(self):
        c = self.conn.cursor()
        c.execute('DELETE FROM book WHERE id = ?', (self.item_selected('<<TreeviewSelect>>'),))
        self.conn.commit()
        self.phones_table.delete(self.phones_table.selection())
    def update_table(self):
        self.phones_table.delete(*self.phones_table.get_children())
        c = self.conn.cursor()
        for row in c.execute('SELECT * FROM book'):
            self.phones_table.insert('', tk.END, values=row)

if __name__ == '__main__':
    phone_book = PhoneBook('C:\python\sem8\phonebook.db')
    phone_book.update_table()
    phone_book.mainloop()