import os
import cv2
import pickle as pkl
import natsort
from scipy.io import loadmat
import numpy as np
import imageio
import optparse
from moviepy.video.io.ffmpeg_reader import FFMPEG_VideoReader
import moviepy.editor as moviepyeditor
import paramiko

from core import image_utils

def read_frame_pathes(video_name, max_n_frames):
    video_path = '/home/nour/Documents/Datasets/YouTube2Text/YouTubeClips/all_frames/'
    folder_path = video_path + video_name
    frame_names = natsort.natsorted(os.walk(folder_path).next()[2])
    n_frames = len(frame_names)

    if n_frames > max_n_frames:
        frame_names = np.array(np.linspace(0, n_frames - 1, num=max_n_frames), dtype=int)
        frame_pathes = [folder_path + '/' + str(name) + '.jpeg' for name in frame_names]
    else:
        frame_pathes = [folder_path + '/' + name for name in frame_names]

    return frame_pathes

def read_frames_from_desk(video_name, max_n_frames):
    frame_pathes = read_frame_pathes(video_name, max_n_frames)
    frames = [cv2.imread(frame_path) for frame_path in frame_pathes]
    return frames

def video_to_frames(event_name):
    """
    Extract places classes and scores (accumulate scores) from time-samples n frames of the videos
    :return:
    """

    # frames of videos
    videos_root_path = '/home/nour/Documents/Datasets/TRECVID_MED/Events/' + event_name + '/video/'
    frames_root_path = '/home/nour/Documents/Datasets/TRECVID_MED/Events/' + event_name + '/all-frames/'
    video_names = natsort.natsorted(os.walk(videos_root_path).next()[2])
    video_pathes = [videos_root_path + name for name in video_names]

    # read only the first 500 videos, we only want to compare qualitatively the
    # places extracted from key-frames vs. the ones extracted from the sampled-frames
    count = 0

    for video_path, video_name in zip(video_pathes, video_names):

        video_name_no_extn = video_name[:-4]
        frames_save_dir = frames_root_path + video_name_no_extn + '/'

        count += 1
        print(video_name_no_extn)
        print(count)

        # if no folder with video name, create it
        if not os.path.exists(frames_save_dir):
            os.mkdir(frames_save_dir)

        try:
            read_frames_imageio(video_path, frames_save_dir)
        except:
            read_frames_opencv(video_path, frames_save_dir)

def read_frames_opencv(video_fullpath, frames_save_dir):
    '''
    opencv ugly and sluggish way to get frames
    :param video:
    :return:
    '''
    cap = cv2.VideoCapture(video_fullpath)
    i = 0
    while cap.isOpened():
        ret, frame = cap.read()

        frame_file_name = frames_save_dir + str(i) + '.jpeg'
        cv2.imwrite(frame_file_name, frame)
        i += 1

        if not ret:
            break

def read_frames_imageio(video_fullpath, frames_save_dir):
    '''
     much better/faster way to read video frames
    :param video_fullpath:
    :return:
    '''
    vid = imageio.get_reader(video_fullpath, 'ffmpeg')
    for i, frame in enumerate(vid):
        frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)

        frame_file_name = frames_save_dir + str(i) + '.jpeg'
        cv2.imwrite(frame_file_name, frame)

def video_uniform_sampling(spf, video_path, resize_type, is_local, verbose=False):
    assert resize_type in ['resize', 'resize_crop', 'resize_crop_scaled']

    resize_function = None
    if resize_type == 'resize':
        resize_function = image_utils.resize_frame
    elif resize_type == 'resize_crop':
        resize_function = image_utils.resize_crop
    elif resize_type == 'resize_crop_scaled':
        resize_function = image_utils.resize_crop_scaled

    cap = FFMPEG_VideoReader(video_path, False)
    cap.initialize()
    fps = cap.fps
    n_frames = cap.nframes
    duration = cap.duration
    n_samples = int(duration / float(spf))

    # check if no samples because the video duration is less than spf
    # then at least, get 1 frame of the video
    if n_samples == 0:
        n_samples = 1

    frame_size = 224
    frames = np.zeros(shape=(n_samples, frame_size, frame_size, 3), dtype='float32')
    for i in range(n_samples):
        num = i + 1
        if num % 100 == 0 and verbose:
            print(' ... reading frame %d/%d' % (num, n_samples))
        time_sec = i * spf
        frame = cap.get_frame(time_sec)
        # resize frame to fit in the array, it's going to be used by caffe anyway
        frame = resize_function(frame)
        # frame encoded as uint and values are from 0-255
        # but caffe needs float32 and values from 0-1
        frame = frame.astype('float32') / float(255)
        frames[i] = frame

    # very important, or we'd have memory leakage
    cap.__del__()

    return frames, fps, n_frames, duration

def video_uniform_sample_and_save_old(spf, video_path, frames_path, image_name_format, resize_type, verbose=False):
    if resize_type is not None:
        assert resize_type in ['resize', 'resize_crop', 'resize_crop_scaled']

    resize_function = None
    if resize_type == 'resize':
        resize_function = image_utils.resize_frame
    elif resize_type == 'resize_crop':
        resize_function = image_utils.resize_crop
    elif resize_type == 'resize_crop_scaled':
        resize_function = image_utils.resize_crop_scaled

    cap = FFMPEG_VideoReader(video_path, False)
    cap.initialize()
    fps = cap.fps
    n_frames = cap.nframes
    duration = cap.duration
    n_samples = int(duration / float(spf))

    # check if no samples because the video duration is less than spf
    # then at least, get 1 frame of the video
    if n_samples == 0:
        n_samples = 1

    for i in range(n_samples):
        num = i + 1
        if verbose:
            print(' ... reading frame %d/%d' % (num, n_samples))
        time_sec = i * spf
        frame = cap.get_frame(time_sec)

        if resize_type is not None:
            # resize frame to fit in the array, it's going to be used by caffe anyway
            frame = resize_function(frame)

        frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
        frame_path = image_name_format % (frames_path, num)
        cv2.imwrite(frame_path, frame)

    # very important, or we'd have memory leakage
    cap.close()

    return fps, n_frames, duration

def video_uniform_sample_and_save(spf, video_path, frames_path, image_name_format, resize_type, verbose=False):
    if resize_type is not None:
        assert resize_type in ['resize', 'resize_crop', 'resize_crop_scaled']

    resize_function = None
    if resize_type == 'resize':
        resize_function = image_utils.resize_frame
    elif resize_type == 'resize_crop':
        resize_function = image_utils.resize_crop
    elif resize_type == 'resize_crop_scaled':
        resize_function = image_utils.resize_crop_scaled

    cap = moviepyeditor.VideoFileClip(video_path)
    fps = cap.fps
    duration = cap.duration
    n_frames = int(fps * duration)
    n_samples = int(duration / float(spf))

    # check if no samples because the video duration is less than spf
    # then at least, get 1 frame of the video
    if n_samples == 0:
        n_samples = 1

    for i in range(n_samples):
        num = i + 1
        if verbose:
            print(' ... reading frame %d/%d' % (num, n_samples))
        time_sec = i * spf
        frame = cap.get_frame(time_sec)

        if resize_type is not None:
            # resize frame to fit in the array, it's going to be used by caffe anyway
            frame = resize_function(frame)

        frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
        frame_path = image_name_format % (frames_path, num)
        cv2.imwrite(frame_path, frame)

    # very important, or we'd have memory leakage
    cap.close()

    return fps, n_frames, duration

def video_uniform_sample_and_save_i3d(spf, video_path, frames_path, resize_type, verbose=False):
    if resize_type is not None:
        assert resize_type in ['resize', 'resize_crop', 'resize_crop_scaled']

    resize_function = None
    if resize_type == 'resize':
        resize_function = image_utils.resize_frame
    elif resize_type == 'resize_crop':
        resize_function = image_utils.resize_crop
    elif resize_type == 'resize_crop_scaled':
        resize_function = image_utils.resize_crop_scaled

    cap = moviepyeditor.VideoFileClip(video_path)
    fps = cap.fps
    duration = cap.duration
    n_frames = int(fps * duration)
    n_samples = int(duration / float(spf))
    n_frames_per_segment = 8
    fps_float = float(fps)

    # check if no samples because the video duration is less than spf
    # then at least, get 1 frame of the video
    if n_samples == 0:
        n_samples = 1

    for i in range(n_samples):
        num = i + 1
        if verbose:
            print(' ... reading frame %d/%d' % (num, n_samples))
        time_sec = i * spf

        t_stop = time_sec + n_frames_per_segment - 1
        if t_stop > duration:
            return

        # get 8 successive frames for i3d
        for j in range(n_frames_per_segment):
            t = time_sec + (j / fps_float)
            frame = cap.get_frame(t)

            # resize frame to fit in the array, it's going to be used by caffe anyway
            if resize_type is not None:
                frame = resize_function(frame)

            frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
            frame_path = '%s/%06d_%d.jpg' % (frames_path, num, j + 1)
            cv2.imwrite(frame_path, frame)

    # very important, or we'd have memory leakage
    cap.close()

    return fps, n_frames, duration

def video_uniform_sample_n_frames_old(video_path, n_samples, max_dim):
    """
    Sample only n frames from the video.
    """

    raise Exception('Needs to add argument about resizing type')

    cap = FFMPEG_VideoReader(video_path, False)
    cap.initialize()
    fps = cap.fps
    n_frames = cap.nframes
    duration = cap.duration
    step = duration / (n_samples)

    frames = []
    for i in range(n_samples):
        time_sec = i * step
        frame = cap.get_frame(time_sec)
        # resize frame to fit in the array, it's going to be used by caffe anyway
        frame = image_utils.resize_keep_aspect_ratio_max_dim(frame, max_dim)
        # frame encoded as uint and values are from 0-255
        # but caffe needs float32 and values from 0-1
        frame = frame.astype('float32') / float(255)
        frames.append(frame)

    # very important, or we'd have memory leakage
    cap.__del__()

    return frames

def video_uniform_sample_n_frames_and_save(n_samples, video_path, frames_path, image_name_format, resize_type, verbose=False):
    if resize_type is not None:
        assert resize_type in ['resize', 'resize_crop', 'resize_crop_scaled']

    resize_function = None
    if resize_type == 'resize':
        resize_function = image_utils.resize_frame
    elif resize_type == 'resize_crop':
        resize_function = image_utils.resize_crop
    elif resize_type == 'resize_crop_scaled':
        resize_function = image_utils.resize_crop_scaled

    cap = moviepyeditor.VideoFileClip(video_path)
    fps = cap.fps
    duration = cap.duration
    step = duration / (n_samples)

    for i in range(n_samples):
        num = i + 1
        if verbose:
            print(' ... reading frame %d/%d' % (num, n_samples))

        time_sec = i * step
        frame = cap.get_frame(time_sec)

        if resize_type is not None:
            # resize frame to fit in the array, it's going to be used by caffe anyway
            frame = resize_function(frame)

        frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
        frame_path = image_name_format % (frames_path, num)
        cv2.imwrite(frame_path, frame)

    # very important, or we'd have memory leakage
    cap.reader.close()
    cap.close()
    del cap.reader
    del cap

    return fps, n_samples, duration

def video_save_frames(video_path, frames_path, image_name_format, resize_type=None, verbose=False):
    if resize_type is not None:
        assert resize_type in ['resize', 'resize_crop', 'resize_crop_scaled']

    resize_function = None
    if resize_type == 'resize':
        resize_function = image_utils.resize_frame
    elif resize_type == 'resize_crop':
        resize_function = image_utils.resize_crop
    elif resize_type == 'resize_crop_scaled':
        resize_function = image_utils.resize_crop_scaled

    cap = moviepyeditor.VideoFileClip(video_path)
    fps = float(cap.fps)
    duration_sec = cap.duration
    n_frames = int(fps * duration_sec)

    index = 0
    while True:
        time_sec = index / fps
        frame = cap.get_frame(time_sec)

        # resize frame to fit in the array, it's going to be used by caffe anyway
        if resize_type is not None:
            frame = resize_function(frame)

        index += 1
        if index > n_frames:
            break

        if verbose and index % 100 == 0:
            print(' ... reading frame %d/%d' % (index, n_frames))
        frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
        frame_path = image_name_format % (frames_path, index)
        cv2.imwrite(frame_path, frame)

    # very important, or we'd have memory leakage
    cap.reader.close()
    cap.close()
    del cap.reader
    del cap

    return fps, n_frames, duration_sec

def video_save_frames_specific_duration(action_num, video_num, video_path, frames_root_pathes, start_stop_sec, image_name_format, verbose=False):
    assert len(frames_root_pathes) == len(start_stop_sec)

    cap = FFMPEG_VideoReader(video_path, False)
    cap.initialize()
    fps = float(cap.fps)
    duration_sec = cap.duration
    img_dim = 224

    start_stop_sec = np.array(start_stop_sec)

    for i, s_s_sec in enumerate(start_stop_sec):
        start_sec, stop_sec = s_s_sec
        frame_root_path = frames_root_pathes[i]

        # offset of starting/stopping the action
        sec_offset = 0.25

        start_idx = int((start_sec + sec_offset) * fps)
        stop_idx = int((stop_sec + sec_offset) * fps) + 1

        if verbose:
            print('action, video: %d, %d' % (action_num, video_num))
            print('%d/%d' % (start_sec, stop_sec))
            print('%d/%d' % (start_idx, stop_idx))

        for idx_frame in range(start_idx, stop_idx):
            time_sec = idx_frame / fps
            if verbose and idx_frame % 100 == 0:
                print('... time_sec, frame: %d/%d' % (time_sec, idx_frame))

            frame = cap.get_frame(time_sec)
            frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
            frame = resize_crop(frame, target_width=img_dim, target_height=img_dim)
            frame_path = image_name_format % (frame_root_path, idx_frame)
            cv2.imwrite(frame_path, frame)

    # very important, or we'd have memory leakage
    cap.__del__()

def get_video_info(video_path):
    # video_fps, video_n_frames, video_duration = video_utils.

    cap = FFMPEG_VideoReader(video_path, False)
    cap.initialize()
    fps = cap.fps
    n_frames = cap.nframes
    duration = cap.duration
    cap.close()
    del cap

    return fps, n_frames, duration

def get_regions(video_path, annot, resize_type, verbose=False):
    """
    Get the frames whose numbers are given in the "annot" dictionary.. Then, for each frame get the regions as specificed in the "annot" dictionary.
    Finally, return these regions.
    """

    assert resize_type in ['resize', 'resize_crop', 'resize_crop_scaled']

    resize_function = None
    if resize_type == 'resize':
        resize_function = image_utils.resize_frame
    elif resize_type == 'resize_crop':
        resize_function = image_utils.resize_crop
    elif resize_type == 'resize_crop_scaled':
        resize_function = image_utils.resize_crop_scaled

    cap = FFMPEG_VideoReader(video_path, False)
    cap.initialize()
    fps = float(cap.fps)
    n_frames = cap.nframes
    duration = cap.duration
    n_regions = sum([len(v) for k, v in annot.iteritems()])

    frame_size = 224
    bbox_resize_factor = 2
    regions = np.zeros(shape=(n_regions, frame_size, frame_size, 3), dtype='float32')
    region_idx = -1

    frame_nums = annot.keys()
    for frame_num in frame_nums:

        if (region_idx + 1) % 100 == 0 and verbose:
            print(' ... reading region %d/%d' % (region_idx + 1, n_regions))

        # get the frame
        i = frame_num - 1
        time_sec = i / fps
        frame = cap.get_frame(time_sec)

        # get the regions (resized) from the frame
        regions_info = annot[frame_num]
        for region_info in regions_info:
            region_idx += 1
            bbox = region_info[1:5]
            bbox = np.multiply(bbox, bbox_resize_factor).astype(np.int)
            x1, y1, x2, y2 = bbox
            region = frame[y1:y2, x1:x2]
            # resize frame to fit in the array, it's going to be used by caffe anyway
            region = resize_function(region)
            # frame encoded as uint and values are from 0-255, but caffe needs float32 and values from 0-1
            region = region.astype('float32') / float(255)
            regions[region_idx] = region

    # very important, or we'd have memory leakage
    cap.__del__()

    return regions


from collections import deque

N = int(input())
queue = deque()
for _ in range(N):
    row = input().split()
    if len(row) > 1:
        q, name = row
        queue.append(name)
    else:
        q = int(row[0])
        if q == 2:
            print(queue[0])
        else:
            queue.popleft()


"""
    监控模型、资料的程式，通常是排程执行，或者资料流入执行。
    云端服务常见 composer, cloud function 触发.py档案执行。
    以此次范例来说，可以用 serving server 去纪录资料笔数，
    当累积达一定再呼叫此 server 之API来计算。

    ---

    以公司来说，可能是呼叫 BQ API 来做运算。

    以云端服务来说，是 cloud function / Google App Engine / Composer 的替代。
"""
import numpy as np
import requests
from joblib import load, dump
from flask import Flask, request, jsonify
from module.db import get_json
from module.monitoring import notify, get_model_performance, get_monotoring_data
from module.monitoring import check_model_performance
from module.model_training import retrain
from module.model_evaluation import is_evaluation

# app
app = Flask(__name__)
app.config['JSON_AS_ASCII'] = False     # 解决json中文问题

# config
config = get_json('./data/config.json')
model_name = './models/2022-11-29-11_29_08_483980rf.joblib'
model = load(model_name)

@app.route('/monitoring/cancer/', methods=['GET'])
def monitoring_cancer():
    """
        提供一个 monitoring 的 API，serving server 会呼叫此API，进行效能、资料监控。

        1. serving server 呼叫此 API，
        2. 此 server 计算目前模型的效能，
        3. 若异常呼叫retraining，若正常则不做事情。
    """
    global model
    x, y = get_monotoring_data(config['db_name_monitoring'], config['db_query_monitoring'], config['table_name_monitoring'])
    print(x.shape, y.shape)
    acc = get_model_performance(model, x, y)
    is_monitor = check_model_performance(acc, config['monitoring_threshold'])

    if is_monitor:
        message = '\n模型效能不佳，呼叫重新训练 API'
        notify('line-notify', config['line-notify'], message)
        url = config['retraining_url']
        resp = requests.get(url)
        return jsonify({'state': f'模型效能异常: {acc}，以触发重新训练。'})
    else:
        message = '\n'
        notify('line-notify', config['line-notify'], message)
        return jsonify({'state': f'模型效能正常: {acc}，不须处理。'})

if __name__ == '__main__':
    app.run(debug=False, port=8002)


import pytest
from unittest.mock import patch
import deadletter_watcher.datadog as datadog
import datetime

@patch('requests.get')
def test_validate(patched_get):
    # Arrange
    patched_get.return_value.status_code = 200
    secrets = {
        "DL-WATCHER": {
            "DD_API_KEY" : "0121-DO-1"
        }
    }

    # Act
    response = datadog.validate(secrets)

    # Assert
    assert patched_get.called is True
    assert response.status_code == 200

@patch('deadletter_watcher.datadog.__datadog_request_tenant_id')
@patch('deadletter_watcher.datadog.__datadog_request_emails')
def test_datadog_log_query_successful_request(patched_emails, patched_tenant):
    # Arrange
    message_id = "12345678-1234-1234-1234-12345678901234"
    secrets = {
        "DL-WATCHER": {
            "DD_API_KEY" : "0121-DO-1"
        }
    }
    now = datetime.datetime.now()

    # Arrange Mock
    patched_emails.return_value = {
        'statusCode': 200,
        'logs': [
            {
                "content": {
                    "attributes" : {
                        "sender_email": "sender@unittest.com",
                        "recipient_email": "recipient@unittest.com"
                    }
                }
            }
        ]
    }
    patched_tenant.return_value = {
        'statusCode': 200,
        'logs': [
            {
                "content": {
                    "timestamp": "unittest_time",
                    "attributes" : {
                        "tenant_name": "unittest_tenant"
                    }
                }
            }
        ]
    }

    # Act
    deadletter_details = datadog.datadog_log_query(message_id, now, secrets)

    # Assert
    assert patched_emails.called is True
    assert patched_tenant.called is True
    assert deadletter_details['timestamp'] == "unittest_time" and \
            deadletter_details['tenant_name'] == "unittest_tenant" and \
            deadletter_details['sender_email'] == "sender@unittest.com" and \
            deadletter_details['recipient_email'] == "recipient@unittest.com"

@patch('deadletter_watcher.datadog.__datadog_request_tenant_id')
@patch('deadletter_watcher.datadog.__datadog_request_emails')
def test_datadog_log_query_email_details_not_found_in_logs(patched_emails, patched_tenant):
    # Arrange
    message_id = "12345678-1234-1234-1234-12345678901234"
    secrets = {
        "DL-WATCHER": {
            "DD_API_KEY" : "0121-DO-1"
        }
    }
    now = datetime.datetime.now()

    patched_emails.return_value = {
        # Empty logs
        'statusCode': 200,
        'logs': [],
    }

    # Act
    deadletter_details = datadog.datadog_log_query(message_id, now, secrets)

    error_message = "Cannot Find in DataDog Log"

    # Assert
    assert patched_emails.called is True
    assert patched_tenant.called is False
    assert deadletter_details['tenant_name'] == error_message
    assert deadletter_details['sender_email'] == error_message
    assert deadletter_details['recipient_email'] == error_message


# -*- coding: utf-8 -*-

"""
	Venom
"""

import threading

from resources.lib.modules import control
from resources.lib.modules import log_utils
from resources.lib.modules import trakt

# check on adding while loop here with xbmc.Monitor().abortRequested() vs. inside the service function
control.execute('RunPlugin(plugin://%s)' % control.get_plugin_url({'action': 'service'}))

traktCredentials = trakt.getTraktCredentialsInfo()

try:
	AddonVersion = control.addon('plugin.video.venom').getAddonInfo('version')
	RepoVersion = control.addon('repository.venom').getAddonInfo('version')
	log_utils.log('###################   Venom   ##################', log_utils.LOGNOTICE)
	log_utils.log('#####   CURRENT Venom VERSIONS REPORT   #####', log_utils.LOGNOTICE)
	log_utils.log('########   Venom PLUGIN VERSION: %s   ########' % str(AddonVersion), log_utils.LOGNOTICE)
	log_utils.log('#####   Venom REPOSITORY VERSION: %s   #######' % str(RepoVersion), log_utils.LOGNOTICE)
	log_utils.log('############################################', log_utils.LOGNOTICE)

except:
	log_utils.log('############################# Venom ############################', log_utils.LOGNOTICE)
	log_utils.log('################# CURRENT Venom VERSIONS REPORT ################', log_utils.LOGNOTICE)
	log_utils.log('# ERROR GETTING Venom VERSION - Missing Repo of failed Install #', log_utils.LOGNOTICE)
	log_utils.log('################################################################', log_utils.LOGNOTICE)

def syncTraktLibrary():
	control.execute('RunPlugin(plugin://%s)' % 'plugin.video.venom/?action=tvshowsToLibrarySilent&url=traktcollection')
	control.execute('RunPlugin(plugin://%s)' % 'plugin.video.venom/?action=moviesToLibrarySilent&url=traktcollection')

def syncTraktWatched():
	control.execute('RunPlugin(plugin://%s)' % 'plugin.video.venom/?action=cachesyncTVShows')
	control.execute('RunPlugin(plugin://%s)' % 'plugin.video.venom/?action=cachesyncMovies')
	# if control.setting('trakt.general.notifications') == 'true':
		# control.notification(title = 'default', message = 'Trakt Watched Status Sync Complete', icon='default', time=1, sound=False)

def check_for_addon_update():
	try:
		if control.setting('general.checkAddonUpdates') == 'false':
			return
		import re
		import requests
		repo_xml = requests.get('https://raw.githubusercontent.com/123Venom/zips/master/addons.xml')
		if not repo_xml.status_code == 200:
			log_utils.log('Could not connect to repo XML, status: %s' % repo_xml.status_code, log_utils.LOGNOTICE)
			return
		repo_version = re.findall(r'<addon id=\"plugin.video.venom\" version=\"(\d*.\d*.\d*)\"', repo_xml.text)[0]
		local_version = control.getVenomVersion()

		if control.check_version_numbers(local_version, repo_version):
			while control.condVisibility('Library.IsScanningVideo'):
				control.sleep(10000)
			log_utils.log('A newer version of Venom is available. Installed Version: v%s, Repo Version: v%s' % (local_version, repo_version), log_utils.LOGNOTICE)
			control.notification(title = 'default', message = control.lang(35523) % repo_version, icon = 'default', time=5000, sound=False)
	except:
		pass

if traktCredentials is True:
	syncTraktWatched()

if control.setting('autoTraktOnStart') == 'true':
	syncTraktLibrary()

if control.setting('general.checkAddonUpdates') == 'true':
	check_for_addon_update()

if int(control.setting('schedTraktTime')) > 0:
	log_utils.log('###############################################################', log_utils.LOGNOTICE)
	log_utils.log('#################### STARTING TRAKT SCHEDULING ################', log_utils.LOGNOTICE)
	log_utils.log('#################### SCHEDULED TIME FRAME '+ control.setting('schedTraktTime')  + ' HOURS ###############', log_utils.LOGNOTICE)
	timeout = 3600 * int(control.setting('schedTraktTime'))
	schedTrakt = threading.Timer(timeout, syncTraktLibrary)
	schedTrakt.start()


# -*- coding: utf-8 -*-
import importlib
import os

import sys

from gos.exceptions import GOSIOException

class Loader(object):
    @staticmethod
    def import_custom_python_file(file_path):
        if not os.path.exists(file_path):
            raise GOSIOException("Specified file does not exists")
        if os.path.isdir(file_path):
            raise GOSIOException("Specified path corresponds to a directory, not a file")
        module_path, file_name = os.path.split(file_path)
        if not file_name.endswith((".py", ".pyc")):
            raise GOSIOException("Specified path does not correspond to python file ")
        if module_path not in sys.path:
            sys.path.insert(0, module_path)
        module_name = file_name[:file_name.rfind(".")]
        module = importlib.import_module(module_name)
        objects = [getattr(module, attr_name) for attr_name in dir(module)]
        return file_name, module_path, objects


import torch.nn as nn
import torch.nn.functional as F
import torch
from unet_block import *

def weights_init_normal(m):
    classname = m.__class__.__name__
    if classname.find('Conv') != -1:
        torch.nn.init.normal_(m.weight.data, 0.0, 0.02)
    elif classname.find('BatchNorm2d') != -1:
        torch.nn.init.normal_(m.weight.data, 1.0, 0.02)
        torch.nn.init.constant_(m.bias.data, 0.0)

# build U-Net using blocks
class GeneratorUNet(nn.Module):
    def __init__(self, in_channels=3, out_channels=3):
        super(GeneratorUNet, self).__init__()

        self.downsample1 = UNetDown(in_channels, 64, normalize=False)
        self.downsample2 = UNetDown(64, 128)
        self.downsample3 = UNetDown(128, 256)
        self.downsample4 = UNetDown(256, 512)
        self.downsample5 = UNetDown(512, 512)
        self.downsample6 = UNetDown(512, 512)
        self.downsample7 = UNetDown(512, 512)
        self.downsample8 = UNetDown(512, 512, normalize=False)

        self.upsample1 = UNetUp(512, 512, dropout=0.5)
        self.upsample2 = UNetUp(1024, 512, dropout=0.5)
        self.upsample3 = UNetUp(1024, 512, dropout=0.5)
        self.upsample4 = UNetUp(1024, 512, dropout=0.5)
        self.upsample5 = UNetUp(1024, 256)
        self.upsample6 = UNetUp(512, 128)
        self.upsample7 = UNetUp(256, 64)

        self.final = nn.Sequential(
            nn.Upsample(scale_factor=2),
            # nn.UpsamplingBilinear2d(scale_factor=2),
            nn.ZeroPad2d((1, 0, 1, 0)),
            nn.Conv2d(128, out_channels, 4, padding=1),
            nn.Tanh()
        )

    def forward(self, x):
        down1 = self.downsample1(x)
        down2 = self.downsample2(down1)
        down3 = self.downsample3(down2)
        down4 = self.downsample4(down3)
        down5 = self.downsample5(down4)
        down6 = self.downsample6(down5)
        down7 = self.downsample7(down6)
        down8 = self.downsample8(down7)
        up1 = self.upsample1(down8, down7)
        up2 = self.upsample2(up1, down6)
        up3 = self.upsample3(up2, down5)
        up4 = self.upsample4(up3, down4)
        up5 = self.upsample5(up4, down3)
        up6 = self.upsample6(up5, down2)
        up7 = self.upsample7(up6, down1)

        return self.final(up7)

#Discriminator

class Discriminator(nn.Module):
    def __init__(self, in_channels=3):
        super(Discriminator, self).__init__()

        def discriminator_block(in_filters, out_filters, normalization=True):
            """Returns downsampling layers of each discriminator block"""
            layers = [nn.Conv2d(in_filters, out_filters, 4, stride=2, padding=1)]
            if normalization:
                layers.append(nn.InstanceNorm2d(out_filters))
            layers.append(nn.LeakyReLU(0.2, inplace=True))
            return layers

        self.model = nn.Sequential(
            *discriminator_block(in_channels*2, 64, normalization=False),
            *discriminator_block(64, 128),
            *discriminator_block(128, 256),
            *discriminator_block(256, 512),
            nn.ZeroPad2d((1, 0, 1, 0)),
            nn.Conv2d(512, 1, 4, padding=1, bias=False)
        )

    def forward(self, img_A, img_B):
        img_input = torch.cat((img_A, img_B), 1)
        return self.model(img_input)


from django.forms import modelform_factory
from django.shortcuts import render, get_object_or_404, redirect

# Create your views here.
from personas.forms import PersonaForm
from personas.models import Persona

def detallePersona(request, id):
    # persona = Persona.objects.get(pk=id)
    persona = get_object_or_404(Persona, pk=id)
    return render(request, 'personas/detalle.html', {'persona': persona})

# PersonaForm = modelform_factory(Persona, exclude=[])

def nuevaPersona(request):
    if request.method == 'POST':
        formatPersona = PersonaForm(request.POST)
        if formatPersona.is_valid():
            formatPersona.save()
            return redirect('index')
    else:
        formatPersona = PersonaForm()
    return render(request, 'personas/nueva.html', {'formatPersona': formatPersona})

def editarPersona(request, id):
    persona = get_object_or_404(Persona, pk=id)
    if request.method == 'POST':
        formatPersona = PersonaForm(request.POST, instance=persona)
        if formatPersona.is_valid():
            formatPersona.save()
            return redirect('index')
    else:
        formatPersona = PersonaForm(instance=persona)
    return render(request, 'personas/editar.html', {'formatPersona': formatPersona})

def eliminarPersona(request, id):
    persona = get_object_or_404(Persona, pk=id)
    if persona:
        persona.delete()
    return redirect('index')


import socket
import struct
import enum
import datetime
import dataclasses

import os
import json
import zmq
import time

INTERFACE = "0.0.0.0"
PORT = 40868

#bus_endpoint = "tcp://192.168.1.223:7777"
bus_endpoint = os.environ["ITS_GBUS_BSCP_ENDPOINT"]

def generate_logfile_name():
    now = datetime.datetime.utcnow().replace(microsecond=0)
    isostring = now.isoformat()  # строка вида 2021-04-27T23:17:31
    isostring = isostring.replace("-", "")  # Строка вида 20210427T23:17:31
    isostring = isostring.replace(":", "")  # Строка вида 20210427T231731, то что надо
    return "sdr-lora-log-" + isostring + ".bin"

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind((INTERFACE, PORT,))

ctx = zmq.Context()
socket = ctx.socket(zmq.PUB)
print("connecting to %s" % bus_endpoint)
socket.connect(bus_endpoint)

log_file = generate_logfile_name()
log_stream = open(log_file, mode="wb")

cookie = 1

while True:
    data, port = sock.recvfrom(4096)
    log_stream.write(struct.pack("<L", len(data)) + data)
    log_stream.flush()

    lora_tap_len = 13 # 13 байт на непонятные нули
    lora_mac_len = 5  # пять байт на что-то, что постоянно меняется
    crc_len = 2 # 2 байта, на что-то типо контрольной суммы?

    tap_bytes = data[:lora_tap_len]
    rssi_bytes = data[lora_tap_len:][:lora_mac_len]
    payload = data[lora_tap_len + lora_mac_len:][:-crc_len]
    crc_bytes = data[-crc_len:]
    print(
        "tap: %s, mac: %s, payload: %s, crc: %s"
        % (tap_bytes.hex(), rssi_bytes.hex(), payload.hex(), crc_bytes.hex())
    )

    frame_no = payload[:2]
    frame_no, = struct.unpack("<H", frame_no)
    payload = payload[2:]

    now = time.time()
    packet = {
        'time_s': int(now),
        'time_us': int((now - int(now)) * 1000_0000),
        'cookie': cookie,
        'snr' : rssi_bytes[0],
        'frame_no': frame_no,

        'tap_bytes': tap_bytes.hex(),
        'rssi_bytes': rssi_bytes.hex(),
        'crc_bytes': crc_bytes.hex(),
    }

    parts = [
        b"sdr.downlink_frame",
        json.dumps(packet).encode("utf-8"),
        payload
    ]

    socket.send_multipart(parts)
    cookie += 1
    cookie &= 0xFFFF_FFFF_FFFF_FFFF
    if cookie == 0:
        cookie = 1


from django.contrib.auth.mixins import LoginRequiredMixin
from django.db.models import Count,Q
from django.shortcuts import render
from learning.models import (
    Problem,
    Tutorial,
    Score,
    Submission
)
from django.contrib.auth.models import User
from django.urls import reverse_lazy
from django.shortcuts import get_object_or_404
from django.views.generic import (
    DetailView,
    ListView,
    CreateView
)
from learning.forms import SubmissionForm

class MainPageView(LoginRequiredMixin,ListView):

    template_name = 'learning/main_page.html'

    def get_queryset(self):
        return Problem.objects.all()

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context.update({
            'blog_nav': 'active',
            'tutorials': Tutorial.objects.all(),
            'current_user': Score.objects.filter(learner=self.request.user),
            'dashboard_learning_tab': 'active',
            'dashboard_Tuto_tab': 'active'
        })
        return context

class ProblemListView(LoginRequiredMixin,ListView):
    model = Problem
    context_object_name = 'problems'
    template_name = 'learning/problems_list.html'

    def get_queryset(self):

        current_user = self.request.user if self.request.user.is_authenticated else None
        return Problem.objects.annotate(
            solve_count=Count(
                'submissions__user',
                filter=Q(submissions__status='AC'),
                distinct=True
            ),
            is_solved=Count(
                'submissions__user',
                filter=Q(submissions__status='AC', submissions__user=current_user)
            )
        ).order_by('-solve_count')

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context.update({
            'dashboard_learning_tab': 'active',
            'dashboard_Prob_tab': 'active',
            'current_user': Score.objects.filter(learner=self.request.user)
        })
        return context

class ProblemDetailView(LoginRequiredMixin,DetailView):
    model = Problem
    template_name = 'learning/problem_details.html'
    context_object_name = 'problem'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context.update({
            'dashboard_learning_tab': 'active',
            'dashboard_Prob_tab': 'active',
            'submission_form': SubmissionForm(),
            'testcases': self.get_object().testcases.filter(is_sample=True)
        })
        return context

class SubmissionCreateView(LoginRequiredMixin,CreateView):
    model = Submission
    form_class = SubmissionForm
    success_url = reverse_lazy('learning:submission-list')

    def form_valid(self, form):
        form.instance.user = self.request.user
        form.instance.problem = get_object_or_404(Problem, pk=self.kwargs.get('problem_id'))
        return super().form_valid(form)

class SubmissionListView(LoginRequiredMixin,ListView):
    model = Submission
    paginate_by = 10
    context_object_name = 'submissions'
    template_name = 'learning/submission_list.html'

    def get_queryset(self):
        return Submission.objects.filter(user = self.request.user).order_by('-created_at')

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context.update({
            'dashboard_learning_tab': 'active',
            'dashboard_Sub_tab': 'active'
        })
        return context


import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('lenna.png', 1)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
plt.figure()
plt.hist(gray.ravel(), 256)
# hist = cv2.calcHist([gray], [0], None, [256], [0, 256])
# plt.plot(hist)
plt.title("Grayscale Histogram")
plt.xlabel("Bins")
plt.ylabel("Number of Pixels")
plt.xlim([0, 270])
plt.ylim([0, 4000])
plt.show()


import os
import sys

from SCons.Script import ARGUMENTS  # pylint: disable=import-error
from SCons.Script import COMMAND_LINE_TARGETS  # pylint: disable=import-error
from SCons.Script import DefaultEnvironment  # pylint: disable=import-error

from platformio import fs, util
from platformio.compat import IS_MACOS, IS_WINDOWS
from platformio.package.meta import PackageItem
from platformio.package.version import get_original_version
from platformio.platform.exception import UnknownBoard
from platformio.platform.factory import PlatformFactory
from platformio.project.config import ProjectOptions

# pylint: disable=too-many-branches, too-many-locals

@util.memoized()
def _PioPlatform():
    env = DefaultEnvironment()
    return PlatformFactory.from_env(env["PIOENV"], targets=COMMAND_LINE_TARGETS)

def PioPlatform(_):
    return _PioPlatform()

def BoardConfig(env, board=None):
    with fs.cd(env.subst("$PROJECT_DIR")):
        try:
            p = env.PioPlatform()
            board = board or env.get("BOARD")
            assert board, "BoardConfig: Board is not defined"
            return p.board_config(board)
        except (AssertionError, UnknownBoard) as exc:
            sys.stderr.write("Error: %s\n" % str(exc))
            env.Exit(1)
    return None

def GetFrameworkScript(env, framework):
    p = env.PioPlatform()
    assert p.frameworks and framework in p.frameworks
    script_path = env.subst(p.frameworks[framework]["script"])
    if not os.path.isfile(script_path):
        script_path = os.path.join(p.get_dir(), script_path)
    return script_path

def LoadPioPlatform(env):
    p = env.PioPlatform()

    # Ensure real platform name
    env["PIOPLATFORM"] = p.name

    # Add toolchains and uploaders to $PATH and $*_LIBRARY_PATH
    for pkg in p.get_installed_packages():
        type_ = p.get_package_type(pkg.metadata.name)
        if type_ not in ("toolchain", "uploader", "debugger"):
            continue
        env.PrependENVPath(
            "PATH",
            os.path.join(pkg.path, "bin")
            if os.path.isdir(os.path.join(pkg.path, "bin"))
            else pkg.path,
        )
        if (
            not IS_WINDOWS
            and os.path.isdir(os.path.join(pkg.path, "lib"))
            and type_ != "toolchain"
        ):
            env.PrependENVPath(
                "DYLD_LIBRARY_PATH" if IS_MACOS else "LD_LIBRARY_PATH",
                os.path.join(pkg.path, "lib"),
            )

    # Platform specific LD Scripts
    if os.path.isdir(os.path.join(p.get_dir(), "ldscripts")):
        env.Prepend(LIBPATH=[os.path.join(p.get_dir(), "ldscripts")])

    if "BOARD" not in env:
        return

    # update board manifest with overridden data from INI config
    board_config = env.BoardConfig()
    for option, value in env.GetProjectOptions():
        if not option.startswith("board_"):
            continue
        option = option.lower()[6:]
        try:
            if isinstance(board_config.get(option), bool):
                value = str(value).lower() in ("1", "yes", "true")
            elif isinstance(board_config.get(option), int):
                value = int(value)
        except KeyError:
            pass
        board_config.update(option, value)

    # load default variables from board config
    for option_meta in ProjectOptions.values():
        if not option_meta.buildenvvar or option_meta.buildenvvar in env:
            continue
        data_path = (
            option_meta.name[6:]
            if option_meta.name.startswith("board_")
            else option_meta.name.replace("_", ".")
        )
        try:
            env[option_meta.buildenvvar] = board_config.get(data_path)
        except KeyError:
            pass

    if "build.ldscript" in board_config:
        env.Replace(LDSCRIPT_PATH=board_config.get("build.ldscript"))

def PrintConfiguration(env):  # pylint: disable=too-many-statements
    platform = env.PioPlatform()
    pkg_metadata = PackageItem(platform.get_dir()).metadata
    board_config = env.BoardConfig() if "BOARD" in env else None

    def _get_configuration_data():
        return (
            None
            if not board_config
            else [
                "CONFIGURATION:",
                "https://docs.platformio.org/page/boards/%s/%s.html"
                % (platform.name, board_config.id),
            ]
        )

    def _get_plaform_data():
        data = [
            "PLATFORM: %s (%s)"
            % (
                platform.title,
                pkg_metadata.version if pkg_metadata else platform.version,
            )
        ]
        if (
            int(ARGUMENTS.get("PIOVERBOSE", 0))
            and pkg_metadata
            and pkg_metadata.spec.external
        ):
            data.append("(%s)" % pkg_metadata.spec.uri)
        if board_config:
            data.extend([">", board_config.get("name")])
        return data

    def _get_hardware_data():
        data = ["HARDWARE:"]
        mcu = env.subst("$BOARD_MCU")
        f_cpu = env.subst("$BOARD_F_CPU")
        if mcu:
            data.append(mcu.upper())
        if f_cpu:
            f_cpu = int("".join([c for c in str(f_cpu) if c.isdigit()]))
            data.append("%dMHz," % (f_cpu / 1000000))
        if not board_config:
            return data
        ram = board_config.get("upload", {}).get("maximum_ram_size")
        flash = board_config.get("upload", {}).get("maximum_size")
        data.append(
            "%s RAM, %s Flash"
            % (fs.humanize_file_size(ram), fs.humanize_file_size(flash))
        )
        return data

    def _get_debug_data():
        debug_tools = (
            board_config.get("debug", {}).get("tools") if board_config else None
        )
        if not debug_tools:
            return None
        data = [
            "DEBUG:",
            "Current",
            "(%s)"
            % board_config.get_debug_tool_name(env.GetProjectOption("debug_tool")),
        ]
        onboard = []
        external = []
        for key, value in debug_tools.items():
            if value.get("onboard"):
                onboard.append(key)
            else:
                external.append(key)
        if onboard:
            data.extend(["On-board", "(%s)" % ", ".join(sorted(onboard))])
        if external:
            data.extend(["External", "(%s)" % ", ".join(sorted(external))])
        return data

    def _get_packages_data():
        data = []
        for item in platform.dump_used_packages():
            original_version = get_original_version(item["version"])
            info = "%s @ %s" % (item["name"], item["version"])
            extra = []
            if original_version:
                extra.append(original_version)
            if "src_url" in item and int(ARGUMENTS.get("PIOVERBOSE", 0)):
                extra.append(item["src_url"])
            if extra:
                info += " (%s)" % ", ".join(extra)
            data.append(info)
        if not data:
            return None
        return ["PACKAGES:"] + ["\n - %s" % d for d in sorted(data)]

    for data in (
        _get_configuration_data(),
        _get_plaform_data(),
        _get_hardware_data(),
        _get_debug_data(),
        _get_packages_data(),
    ):
        if data and len(data) > 1:
            print(" ".join(data))

def exists(_):
    return True

def generate(env):
    env.AddMethod(PioPlatform)
    env.AddMethod(BoardConfig)
    env.AddMethod(GetFrameworkScript)
    env.AddMethod(LoadPioPlatform)
    env.AddMethod(PrintConfiguration)
    return env


"""
demo14_vc.py　视频捕捉
"""
import cv2 as cv

# 报错，因为没有摄像头
# 获取视频捕捉设备
vc = cv.VideoCapture(0)
while True:
    # 读取一帧
    frame = vc.read()[1]
    cv.imshow('VideoCapture', frame)
    # 每个33毫秒，会截图，并且即使不摁键盘方法也会自动退出，
    # 退出键esc的值27，当cv.waitKey()的返回值为27时退出white循环
    if cv.waitKey(33) == 27:
        break
# 释放视频捕捉设备
vc.release()
# 销毁cv的所有窗口
cv.destroyAllWindows()


from pathlib import Path
import pandas as pd

def load_data(path = './data', datasets = ['seasons', 'constructors', 'drivers', 'races', 'circuits', 'lap_times', 'results', 'status']):
    data_dir = Path(path).absolute()
    d = {k: pd.read_csv((data_dir/k).with_suffix('.csv')) for k in datasets}
    r = races = d['races']
    r = r.merge(d['results'], on='raceId')
    r = r.merge(d['constructors'], on='constructorId')
    r = r.merge(d['status'], on='statusId')
    r = r.merge(d['drivers'], on='driverId')
    r.drop(columns=[])
    r = r[r.year > 2010]
    races = races[races.year > 2010]
    return r

data = load_data()


# import sys
# import pytesseract
# from difflib import SequenceMatcher as SQ

# try:
#     from PIL import Image
# except ImportError:
#     import Image

# raw_string = pytesseract.image_to_string("/Users/zeraphim/Desktop/aaa.png", lang="eng", config='--psm 7')  # eng or example_model

# print(raw_string)

import os

os.environ["GOOGLE_APPLICATION_CREDENTIALS"]= r"gvision_auth.json"

def detect_document(path):
    """Detects document features in an image."""
    from google.cloud import vision

    client = vision.ImageAnnotatorClient()

    with open(path, "rb") as image_file:
        content = image_file.read()

    image = vision.Image(content=content)

    response = client.document_text_detection(image=image)

    for page in response.full_text_annotation.pages:
        for block in page.blocks:
            print(f"\nBlock confidence: {block.confidence}\n")

            for paragraph in block.paragraphs:
                print("Paragraph confidence: {}".format(paragraph.confidence))

                for word in paragraph.words:
                    word_text = "".join([symbol.text for symbol in word.symbols])
                    print(
                        "Word text: {} (confidence: {})".format(
                            word_text, word.confidence
                        )
                    )

                    for symbol in word.symbols:
                        print(
                            "\tSymbol: {} (confidence: {})".format(
                                symbol.text, symbol.confidence
                            )
                        )

    if response.error.message:
        raise Exception(
            "{}\nFor more info on error messages, check: "
            "https://cloud.google.com/apis/design/errors".format(response.error.message)
        )

# def detect_document(path):
#     """Detects document features in an image."""
#     from google.cloud import vision

#     client = vision.ImageAnnotatorClient()

#     with open(path, "rb") as image_file:
#         content = image_file.read()

#     image = vision.Image(content=content)

#     response = client.document_text_detection(image=image)

#     for page in response.full_text_annotation.pages:
#         for block in page.blocks:
#             for paragraph in block.paragraphs:
#                 for word in paragraph.words:
#                     word_text = "".join([symbol.text for symbol in word.symbols])
#                     print(word_text, end=' ')
#     print()  # Print a newline at the end

img_path = "/Users/zeraphim/Desktop/MKR-Thesis/demo_images/s1.png"

detect_document(img_path)


import logging

import pygsheets
from fastapi import APIRouter, Depends, Body, Security

from configs import settings
from core.authen import get_api_key
from models.base_model import CarInsuranceModel
from models.base_response import BaseResponseData, BaseErrorResponse
from utils import create_aliased_response

router = APIRouter()
GC_SHEET_SRV = None
telegram_logger = logging.getLogger("critical")

def get_gg_sheet_inst():
    global GC_SHEET_SRV
    if GC_SHEET_SRV:
        return GC_SHEET_SRV
    else:
        gc = pygsheets.authorize(service_file="insurance.json")
        sh = gc.open(settings.SHEET_NAME)
        GC_SHEET_SRV = sh[0]
        GC_SHEET_SRV.insert_rows(
            3,
            number=1,
            values=[
                "Tên",
                "SĐT",
                "Email",
                "Hãng xe",
                "Dòng xe",
                "Năm SX",
                "Tỉnh thành",
                "Ngày ĐK đầu tiên",
                "Ngày hiệu lực BH",
                "Xe Đk KD",
                "Thời gian tạo",
            ],
        )
        return GC_SHEET_SRV

@router.get(
    "/healthcheck",
    response_model=BaseResponseData,
    tags=["Wrapper API"],
)
async def health_check():
    """Add multiple task to task-pipeline"""
    return create_aliased_response(
        BaseResponseData(
            code=0,
            message="success",
            result={"health_check": "Oke"},
        )
    )

@router.post(
    "/car-insurance/new-insurance",
    response_model=BaseResponseData,
    tags=["Wrapper API"],
    dependencies=[Security(get_api_key)],
)
async def new_car_insurance(
    *,
    body: CarInsuranceModel = Body(
        ...,
    ),
    gg_sh=Depends(get_gg_sheet_inst)
):
    """Add multiple task to task-pipeline"""

    try:
        gg_sh.insert_rows(
            5,
            number=1,
            values=[
                body.name,
                body.phone,
                body.email or "#",
                body.car_brand,
                body.car_model,
                body.car_year,
                body.province,
                body.date_registry,
                body.date_insurance_atv,
                body.is_ecom,
                body.date_submit,
            ],
            inherit=True,
        )
        telegram_logger.info("New data insert", body.dict())
        return create_aliased_response(
            BaseResponseData(
                code=0,
                message="success",
                result={},
            )
        )
    except Exception as ex:
        telegram_logger.error("New data update error", body.dict())
        return (
            create_aliased_response(
                BaseErrorResponse(code=1, message="servce  error", detail=str(ex)),
            ),
            400,
        )


from datetime import datetime
from decimal import Decimal

import csv
import sys
import os

wd = os.getcwd()
sys.path.append(wd)

from cryptocoins.models.forex_pairs_history import ForexPairsHistory
from cryptocoins.utils import setup_logging

if len(sys.argv) < 3:
    raise ValueError('Usage: import file_name symbol')

file_path = sys.argv[1]
to_symbol = sys.argv[2]

logger = setup_logging()

if __name__ == "__main__":
    logger.info(f"IMPORTING FROM {file_path}, SYMBOL {to_symbol}")
    data = []
    with open(file_path, 'r') as csv_file:
        reader = csv.reader(csv_file)
        for i in range(5):
            next(reader)
        for row in reader:
            if len(row) < 2:
                continue
            if not row[1]:
                continue
            timestamp_epoc = datetime.strptime(row[0], '%d/%m/%y').timestamp()
            price_dollars = Decimal(row[1].replace(',', ''))
            model_params = {'from_symbol': 'USD',
                            'to_symbol': to_symbol,
                            'price': Decimal(1.0) / price_dollars,
                            'timestamp_epoc': timestamp_epoc}
            data.append(model_params)
    ForexPairsHistory.create_from_model_params(data)


# -*- coding: utf-8 -*-
"""
Decision Sypport Systems
6.5.1 - 6.5.2

Kasper Kronborg Larsen
"""

import pandas as pd
import itertools
import time
import statsmodels.api as sm
import matplotlib.pyplot as plt

data = pd.read_csv('C:/Users/Kasper/Desktop/datasets/Hitters.csv')
data.head()

print("Number of null values:", data["Salary"].isnull().sum())

# Print the dimensions of the original Hitters data (322 rows x 20 columns)
print("Dimensions of original data:", data.shape)

# Drop any rows the contain missing values, along with the player names
data_drop = data.dropna().drop('Unnamed: 0', axis=1)

# Print the dimensions of the modified Hitters data (263 rows x 20 columns)
print("Dimensions of modified data:", data_drop.shape)

# One last check: should return 0
print("Number of null values:", data_drop["Salary"].isnull().sum())

dummies = pd.get_dummies(data_drop[['League', 'Division', 'NewLeague']])
y = data_drop.Salary

# Drop the column with the independent variable (Salary), and columns for which we created dummy variables
X_ = data_drop.drop(['Salary', 'League', 'Division', 'NewLeague'], axis=1).astype('float64')

# Define the feature set X.
X = pd.concat([X_, dummies[['League_N', 'Division_W', 'NewLeague_N']]], axis=1)

dummies = pd.get_dummies(data_drop[['League', 'Division', 'NewLeague']])
y = data_drop.Salary

# Drop the column with the independent variable (Salary), and columns for which we created dummy variables
X_ = data_drop.drop(['Salary', 'League', 'Division', 'NewLeague'], axis=1).astype('float64')

# Define the feature set X.
X = pd.concat([X_, dummies[['League_N', 'Division_W', 'NewLeague_N']]], axis=1)

def processSubset(feature_set):
    # Fit model on feature_set and calculate RSS
    model = sm.OLS(y,X[list(feature_set)])
    regr = model.fit()
    RSS = ((regr.predict(X[list(feature_set)]) - y) ** 2).sum()
    return {"model":regr, "RSS":RSS}

def getBest(k):

    tic = time.time()

    results = []

    for combo in itertools.combinations(X.columns, k):
        results.append(processSubset(combo))

    # Wrap everything up in a nice dataframe
    models = pd.DataFrame(results)

    # Choose the model with the highest RSS
    best_model = models.loc[models['RSS'].argmin()]

    toc = time.time()
    print("Processed", models.shape[0], "models on", k, "predictors in", (toc-tic), "seconds.")

    # Return the best model, along with some other useful information about the model
    return best_model

# Could take quite awhile to complete...

models_best = pd.DataFrame(columns=["RSS", "model"])

tic = time.time()
for i in range(1,8):
    models_best.loc[i] = getBest(i)

toc = time.time()
print("Total elapsed time:", (toc-tic), "seconds.")

models_best
print(models_best.loc[2, "model"].summary())

# Show the best 19-variable model (there's actually only one)
print(getBest(19)["model"].summary())

models_best.loc[2, "model"].rsquared

# Gets the second element from each row ('model') and pulls out its rsquared attribute
models_best.apply(lambda row: row[1].rsquared, axis=1)

plt.figure(figsize=(20,10))
plt.rcParams.update({'font.size': 18, 'lines.markersize': 10})

# Set up a 2x2 grid so we can look at 4 plots at once
plt.subplot(2, 2, 1)

# We will now plot a red dot to indicate the model with the largest adjusted R^2 statistic.
# The argmax() function can be used to identify the location of the maximum point of a vector
plt.plot(models_best["RSS"])
plt.xlabel('# Predictors')
plt.ylabel('RSS')

# We will now plot a red dot to indicate the model with the largest adjusted R^2 statistic.
# The argmax() function can be used to identify the location of the maximum point of a vector

rsquared_adj = models_best.apply(lambda row: row[1].rsquared_adj, axis=1)

plt.subplot(2, 2, 2)
plt.plot(rsquared_adj)
plt.plot(rsquared_adj.argmax(), rsquared_adj.max(), "or")
plt.xlabel('# Predictors')
plt.ylabel('adjusted rsquared')

# We'll do the same for AIC and BIC, this time looking for the models with the SMALLEST statistic
aic = models_best.apply(lambda row: row[1].aic, axis=1)

plt.subplot(2, 2, 3)
plt.plot(aic)
plt.plot(aic.argmin(), aic.min(), "or")
plt.xlabel('# Predictors')
plt.ylabel('AIC')

bic = models_best.apply(lambda row: row[1].bic, axis=1)

plt.subplot(2, 2, 4)
plt.plot(bic)
plt.plot(bic.argmin(), bic.min(), "or")
plt.xlabel('# Predictors')
plt.ylabel('BIC')

def forward(predictors):

    # Pull out predictors we still need to process
    remaining_predictors = [p for p in X.columns if p not in predictors]

    tic = time.time()

    results = []

    for p in remaining_predictors:
        results.append(processSubset(predictors+[p]))

    # Wrap everything up in a nice dataframe
    models = pd.DataFrame(results)

    # Choose the model with the highest RSS
    best_model = models.loc[models['RSS'].argmin()]

    toc = time.time()
    print("Processed ", models.shape[0], "models on", len(predictors)+1, "predictors in", (toc-tic), "seconds.")

    # Return the best model, along with some other useful information about the model
    return best_model

models_fwd = pd.DataFrame(columns=["RSS", "model"])

tic = time.time()
predictors = []

for i in range(1,len(X.columns)+1):
    models_fwd.loc[i] = forward(predictors)
    predictors = models_fwd.loc[i]["model"].model.exog_names

toc = time.time()
print("Total elapsed time:", (toc-tic), "seconds.")

print(models_fwd.loc[1, "model"].summary())
print(models_fwd.loc[2, "model"].summary())

print(models_best.loc[6, "model"].summary())
print(models_fwd.loc[6, "model"].summary())

def backward(predictors):

    tic = time.time()

    results = []

    for combo in itertools.combinations(predictors, len(predictors)-1):
        results.append(processSubset(combo))

    # Wrap everything up in a nice dataframe
    models = pd.DataFrame(results)

    # Choose the model with the highest RSS
    best_model = models.loc[models['RSS'].argmin()]

    toc = time.time()
    print("Processed ", models.shape[0], "models on", len(predictors)-1, "predictors in", (toc-tic), "seconds.")

    # Return the best model, along with some other useful information about the model
    return best_model

models_bwd = pd.DataFrame(columns=["RSS", "model"], index = range(1,len(X.columns)))

tic = time.time()
predictors = X.columns

while(len(predictors) > 1):
    models_bwd.loc[len(predictors)-1] = backward(predictors)
    predictors = models_bwd.loc[len(predictors)-1]["model"].model.exog_names

toc = time.time()
print("Total elapsed time:", (toc-tic), "seconds.")

print("------------")
print("Best Subset:")
print("------------")
print(models_best.loc[7, "model"].params)
print("-----------------")
print("Foward Selection:")
print("-----------------")
print(models_fwd.loc[7, "model"].params)
print("-------------------")
print("Backward Selection:")
print("-------------------")
print(models_bwd.loc[7, "model"].params)


from django.shortcuts import render, redirect
from django.contrib import messages
from models import User
from ..posts.models import *

def index(request):
    if 'logged_id' not in request.session:
        return render(request, 'users/index.html')
    else:
        return redirect('/users/' + str(request.session['logged_id']))

def login(request):
    if 'logged_id' not in request.session:
        return render(request, 'users/login.html')
    else:
        return redirect('/users/' + str(request.session['logged_id']))

def register(request):
    if 'logged_id' not in request.session:
        return render(request, 'users/register.html')
    else:
        return redirect('/users/' + str(request.session['logged_id']))

def process_login(request):
    if request.method == 'POST':
        errors = User.objects.log_validator(request)
        if len(errors):
            for error in errors:
                messages.error(request, error)
                return redirect('/login')
        else:
            return redirect('/users/' + str(request.session['logged_id']))

def process_register(request):
    if request.method == 'POST':
        errors = User.objects.reg_validator(request)
        if len(errors):
            for error in errors:
                messages.error(request, error)
            return redirect('/register')
        else:
            User.objects.reg_user(request)
            request.session['logged_id'] = User.objects.last().id
            return redirect ('/users/' + str(request.session['logged_id']))

def users(request, id):
    context = {
        'user': User.objects.get(id = id),
        'posts': Post.objects.filter(user_id = id),
        'comments': Comment.objects.all(),
    }
    return render(request, 'users/users.html', context)

def community(request):
    context = {
        'users': User.objects.all().order_by('handle')
    }
    return render(request, 'users/community.html', context)

def settings(request, id):
    context = {
        'user': User.objects.get(id = id)
    }
    return render(request, 'users/settings.html', context)

def update_email(request):
    if request.method == 'POST':
        errors = User.objects.update_email_validator(request)
        if len(errors):
            for error in errors:
                messages.error(request, error)
            return redirect('/users/' + str(request.session['logged_id']) + '/settings')
        else:
            User.objects.update_email(request)
            messages.success(request, 'Email successfully updated!')
            return redirect('/users/' + str(request.session['logged_id']) + '/settings')

def update_password(request):
    if request.method == 'POST':
        errors = User.objects.update_password_validator(request)
        if len(errors):
            for error in errors:
                messages.error(request, error)
            return redirect('/users/' + str(request.session['logged_id']) + '/settings')
        else:
            User.objects.update_password(request)
            messages.success(request, 'Password successfully updated!')
            return redirect('/users/' + str(request.session['logged_id']) + '/settings')

def logout(request):
    request.session.clear()
    return redirect('/')


from pymongo import MongoClient

from kobject import KObject

class KTimer(KObject):
    def __init__(self, name, char, onetime, start_time,
                 callback, duration, *args):
        KObject.__init__(self, _id=None)

        self.name = name
        self.args = args
        self.onetime = onetime
        self.callback = callback
        self.start_time = start_time
        self.duration = duration
        self.char = char
        self._id = self.state_save()

    def die(self):
        self.callback(self)

    def state_save(self):
        client = MongoClient('mongodb://192.168.0.107:27017/')
        db = client.kmud
        collection = db.timers

        timer = {'char': self.char._id,
                 'duration': self.duration,
                 'start': self.start_time,
                 'onetime': self.onetime,
                 'args': self.args}

        return collection.insert_one(timer).inserted_id


import numpy as np
import pandas as pd
import streamlit as st
#from pathlib import Path
from datetime import datetime
import plotly.express as px

from PIL import Image
#import plotly.graph_objects as go
#import plotly.io as pio

realBonds = ['R197', 'I2025', 'R210', 'I2029', 'I2031', 'I2033', 'R202', 'I2038', 'I2046', 'I2050']

nomBonds = ['R186', 'R2030', 'R213', 'R2032', 'R2035', 'R209', 'R2037', 'R2040', 'R214', 'R2044', 'R2048', 'R2053']

#file = "BondDetails.csv"
file = "BondDetailsv1.csv"
fileprev = 'BondDetailsv0.csv'

@st.cache_data
def data(file):
    #df = pd.read_csv(file, delimiter=";", index_col="Date", parse_dates=True, infer_datetime_format=True)
    #df = pd.read_csv(file, delimiter=";")
    df = pd.read_csv(file, delimiter=",")
    return df

df = data(file)
dfprev =data(fileprev)

#bondData = df[['Bond Code', 'Date', 'ISSUER', 'ISSUER_INDUSTRY', 'PAYMENT_RANK', 'Coupon', 'Companion Bond',
#               'BP Spread', 'MTM', 'Last MTM Change Date', 'DAYS_TO_NEXT_COUPON', 'NXT_CPN_DT', 'Modified Duration']]

bondData = df[['Bond Code', 'Maturity', 'ISSUER', 'ISSUER_INDUSTRY', 'PAYMENT_RANK', 'Coupon', 'Companion Bond',
               'BP Spread', 'MTM', 'Last MTM Change Date', 'DAYS_TO_NEXT_COUPON', 'NXT_CPN_DT', 'Modified Duration']]

change0 = df[['Bond Code', 'ISSUER', 'ISSUER_INDUSTRY', 'PAYMENT_RANK', 'Companion Bond', 'BP Spread']]
change1 = dfprev[['Bond Code', 'ISSUER', 'ISSUER_INDUSTRY', 'PAYMENT_RANK', 'Companion Bond', 'BP Spread']]

#change0['BP Spread'] = change0['BP Spread'].astype(float)
#change1['BP Spread'] = change1['BP Spread'].astype(float)

change = pd.merge(change0, change1, on='Bond Code', how='left')

change = change.drop(['ISSUER_y'], axis=1)
change = change.drop(['ISSUER_INDUSTRY_y'], axis=1)
change = change.drop(['PAYMENT_RANK_y'], axis=1)
change = change.drop(['Companion Bond_y'], axis=1)

#change0['BP Spread'] = change0['BP Spread'].astype(float)
#change1['BP Spread'] = change1['BP Spread'].astype(float)

change['Move'] = change['BP Spread_x'] - change['BP Spread_y']

change = change.dropna()

change = change[(change['Move'] != 0)]

change = change.rename({'ISSUER_x': 'Issuer',
                        'ISSUER_INDUSTRY_x': 'Industry',
                        'PAYMENT_RANK_x': 'Rank',
                        'Companion Bond_x': 'Companion',
                        'BP Spread_x': 'Current Spread',
                        'BP Spread_y': 'Previous Spread',
            }, axis=1)

change = change[['Bond Code', 'Issuer', 'Industry', 'Rank', 'Companion', 'Previous Spread', 'Current Spread', 'Move']]

#st.dataframe(change)

#st.dataframe(bondData)

#bondData = bondData.dropna()
#bondaData = bondData.dropna(subset = ['DAYS_TO_NEXT_COUPON'])
#bondaData = bondaData.loc[bondaData['DAYS_TO_NEXT_COUPON'] != ' #N/A N/A ']

#st.dataframe(bondData)
##bondaData['DAYS_TO_NEXT_COUPON'] = bondaData['DAYS_TO_NEXT_COUPON'].replace(' -  ', 0)
#bondaData = bondData.dropna(subset = ['Date'])

#bondaData = bondData.dropna(subset = ['NXT_CPN_DT'])
#bondaData = bondData.dropna(subset = ['DAYS_TO_NEXT_COUPON'])

today = datetime.today().date()

#bondData['Maturity'] = bondData.apply(lambda x: datetime.strptime(x['Date'], "%Y/%m/%d").date(), axis=1)
bondData['Maturity'] = bondData.apply(lambda x: datetime.strptime(x['Maturity'], "%d-%b-%y").date(), axis=1)
bondData['Last_MTM_Change'] = bondData.apply(lambda x: datetime.strptime(x['Last MTM Change Date'], "%d-%b-%y").date(), axis=1)

#bondData['NXT_CPN_DT'] = bondData.apply(lambda x: datetime.strptime(x['NXT_CPN_DT'], "%Y/%m/%d").date(), axis=1)

bondData['Term'] = bondData.apply(lambda x: ((x['Maturity'] - today).days)/365, axis=1)

#bondData['MD'] = bondData.apply(lambda x: ((x['DAYS_TO_NEXT_COUPON'] - today).days)/365, axis=1)
bondData['MD'] = bondData.apply(lambda x: (float(x['DAYS_TO_NEXT_COUPON']))/365 if (x['Companion Bond'] == 'JIBAR') else x['Modified Duration'] , axis=1)

#bondData = bondData.drop(['Date'], axis=1)
bondData = bondData.drop(['Last MTM Change Date'], axis=1)

bondData = bondData.sort_values(by='Maturity')

issuerData = bondData['ISSUER'].unique()

industryData = bondData['ISSUER_INDUSTRY'].unique()

rankData = bondData['PAYMENT_RANK'].unique()

benchmarkData = bondData['Companion Bond'].unique()

codes = bondData['Bond Code'].unique()

options = ['Issuer', 'Industry', 'Rank']

issuers = sorted(issuerData)

industry = sorted(industryData)

rank = sorted(rankData)

benchmark = benchmarkData

####benchmark = sorted(benchmarkData)#####

@st.cache_data
def MTMRegression(data):

    fig = px.scatter(data, x='Term', y='Companion_Spread', text='Bond Code', trendline='ols', trendline_color_override='red')

    fig.update_traces(textposition='top center')

    results = px.get_trendline_results(fig)
    results0 = results.iloc[0]["px_fit_results"].summary()
    results1 = results.iloc[0]["px_fit_results"].params

    r_squared = px.get_trendline_results(fig).px_fit_results.iloc[0].rsquared

    return fig, results0, results1, r_squared

@st.cache_data
def MTMRegressionJIBAR(data):

    fig = px.scatter(data, x='Term', y='JIBAR_Spread', text='Bond Code', trendline='ols', trendline_color_override='red')

    fig.update_traces(textposition='top center')

    results = px.get_trendline_results(fig)
    results0 = results.iloc[0]["px_fit_results"].summary()
    results1 = results.iloc[0]["px_fit_results"].params

    r_squared = px.get_trendline_results(fig).px_fit_results.iloc[0].rsquared

    return fig, results0, results1, r_squared

@st.cache_data
def MTMHistogram(data, metric, attribute):

    fig = px.histogram(data, x=metric, color=attribute, text_auto = True)

    fig.update_layout(legend=dict(
    orientation="h",
    yanchor="bottom",
    y=-0.3,
    xanchor="left",
    x=0.0
))

    return fig

#st.markdown("
Credit Analysis
", unsafe_allow_html=True)

st.header('Credit Analysis')

st.markdown(" ")
banner2 = Image.open('background1.jpg')
st.image(banner2)
st.markdown(" ")

#st.header('Spread Moves')

#st.dataframe(change)

st.sidebar.header('Pricing Inputs')

st.markdown(" ")
banner1 = Image.open('sidebarBackground2.jpg')
st.sidebar.image(banner1)
st.markdown(" ")

refRate = st.sidebar.number_input('3M JIBAR', value=8.492)

inflation = st.sidebar.number_input('12M YOY CPI', value=6.300)

####Need to fix this, include or incorporate inflation#############
####Also need to think about spread - it should be spread over Companion not JIBAR?########

#bondData['YTM'] = bondData.apply(lambda x: 200*((1+((refRate + (x['BP Spread'])/100))/400)**(2)-1) if (x['Companion Bond'] == 'JIBAR') else x['MTM'], axis =1)

#bondData['Spread'] = bondData.apply(lambda x: round(100*((400*(((1+((x['YTM'])/200))**(0.5))-1))-refRate),2), axis =1)

@st.cache_data
def ytm(data):

    lenth = data.shape[0]

    yieldToMaturity = []

    for i in range(0,lenth):

        #if (data['Companion Bond'].iloc[i].isin(realBonds)):
        if(data['Companion Bond'].iloc[i] == 'R197'):
            ytm =  data['MTM'].iloc[i] + (inflation)
            yieldToMaturity.append(ytm)

        elif(data['Companion Bond'].iloc[i] == 'I2025'):
            ytm =  data['MTM'].iloc[i] + (inflation)
            yieldToMaturity.append(ytm)

        elif(data['Companion Bond'].iloc[i] == 'R210'):
            ytm =  data['MTM'].iloc[i] + (inflation)
            yieldToMaturity.append(ytm)

        elif(data['Companion Bond'].iloc[i] == 'I2029'):
            ytm =  data['MTM'].iloc[i] + (inflation)
            yieldToMaturity.append(ytm)

        elif(data['Companion Bond'].iloc[i] == 'I2029'):
            ytm =  data['MTM'].iloc[i] + (inflation)
            yieldToMaturity.append(ytm)

        elif(data['Companion Bond'].iloc[i] == 'R2031'):
            ytm =  data['MTM'].iloc[i] + (inflation)
            yieldToMaturity.append(ytm)

        elif(data['Companion Bond'].iloc[i] == 'R2033'):
            ytm =  data['MTM'].iloc[i] + (inflation)
            yieldToMaturity.append(ytm)

        elif(data['Companion Bond'].iloc[i] == 'R202'):
            ytm =  data['MTM'].iloc[i] + (inflation)
            yieldToMaturity.append(ytm)

        elif(data['Companion Bond'].iloc[i] == 'I2038'):
            ytm =  data['MTM'].iloc[i] + (inflation)
            yieldToMaturity.append(ytm)

        elif(data['Companion Bond'].iloc[i] == 'I2046'):
            ytm =  data['MTM'].iloc[i] + (inflation)
            yieldToMaturity.append(ytm)

        elif(data['Companion Bond'].iloc[i] == 'I2050'):
            ytm =  data['MTM'].iloc[i] + (inflation)
            yieldToMaturity.append(ytm)

        elif(data['Companion Bond'].iloc[i] == 'JIBAR'):
            ytm = (data['BP Spread'].iloc[i]/100) + refRate
            yieldToMaturity.append(ytm)

        else:
            ytm = data['MTM'].iloc[i]

            yieldToMaturity.append(ytm)

    return yieldToMaturity

@st.cache_data
def jibarSpread(data):

    lenth = data.shape[0]

    jibarSpread = []

    for i in range(0,lenth):

        if(data['Companion Bond'].iloc[i] == 'JIBAR'):
            spread = round((data['YTM'].iloc[i] - refRate)*100,2)
            jibarSpread.append(spread)

        else:
            spread = round((((((1+((data['YTM'].iloc[i])/200))**(2/4)) - 1)*400) - refRate)*100,2)
            jibarSpread.append(spread)

    return jibarSpread

#bondData['Spread'] = bondData['BP Spread']

#bondData['YTM'] = bondData.apply(lambda x: x['MTM'] if (x['MTM'] > 0) else ((x['Spread']/100) + refRate), axis=1)

bondData['YTM'] = ytm(bondData)

bondData['Companion_Spread'] = bondData['BP Spread']

#bondData['JIBAR_Spread'] = (bondData['YTM'] - refRate)*100

bondData['JIBAR_Spread'] = jibarSpread(bondData)

#########
#########

#bondData['MD'] = bondData.apply(lambda x: (float(x['DAYS_TO_NEXT_COUPON'])/365) if (x['Companion Bond'] == 'JIBAR') else x['Modified Duration'], axis =1)

bondData = bondData.drop(['BP Spread'], axis=1)
bondData = bondData.drop(['MTM'], axis=1)
bondData = bondData.drop(['DAYS_TO_NEXT_COUPON'], axis=1)
bondData = bondData.drop(['NXT_CPN_DT'], axis=1)
bondData = bondData.drop(['Modified Duration'], axis=1)

st.header('BESA MTM')

st.write('', unsafe_allow_html=True)

showDF = st.radio("Details",("Spread Change", "All Bonds"))

if (showDF == 'Spread Change'):
    st.dataframe(change)
else:
    st.dataframe(bondData)

selection = st.sidebar.selectbox('Criteria', options, index=0)

###################################################################################################################################################
################################### Code within if statements based on selection ##################################################################

st.markdown(" ")
st.markdown(" ")
st.header('Filtered Bond')

if (selection == 'Issuer'):

    issuer1 = st.multiselect('Issuers', issuers, default = 'ABSA BANK LTD')

    emptyDf = []

    for issuer in issuer1:
        container = bondData.loc[(bondData['ISSUER'] == issuer)]
        emptyDf.append(container)

    issuerFilter = pd.concat(emptyDf)

    issuerIndustry = st.sidebar.checkbox("Industry")
    if issuerIndustry:
        industryIssuer = st.sidebar.selectbox('Industry', industry, index=0)
        issuerFilter = issuerFilter.loc[(issuerFilter['ISSUER_INDUSTRY'] == industryIssuer)]

    issuerRank = st.sidebar.checkbox("Rank")
    if issuerRank:
        rankIssuer = st.sidebar.selectbox('Rank', rank, index=0)
        issuerFilter = issuerFilter.loc[(issuerFilter['PAYMENT_RANK'] == rankIssuer)]

    issuerBenchmark = st.sidebar.checkbox("Benchmark")
    if issuerBenchmark:
        benchmarkIssuer = st.sidebar.selectbox('Rank', benchmark, index=0)
        issuerFilter = issuerFilter.loc[(issuerFilter['Companion Bond'] == benchmarkIssuer)]

    issuerDate = st.sidebar.checkbox("Date")
    if issuerDate:
        dateIssuer1 = st.sidebar.date_input("Start Date")
        dateIssuer2 = st.sidebar.date_input("End Date")

        issuerFilter = issuerFilter.loc[(issuerFilter['Maturity'] >= dateIssuer1) & (issuerFilter['Maturity'] <= dateIssuer2)]

    st.write('', unsafe_allow_html=True)

    bondCode = st.radio("Filter on Bond Code",("No", "Yes"))

    #bondCode = st.checkbox("Filter on Bond Code")

    if(bondCode == "Yes"):

        identifier = issuerFilter['Bond Code'].unique()

        codeBonds = st.multiselect('Bond Codes', identifier)

        issuerFilter = issuerFilter[issuerFilter['Bond Code'].isin(codeBonds)]
    else:
        pass

    #st.header('Filtered Bond')
    st.dataframe(issuerFilter, use_container_width=True)

#############
    #showMoves = st.checkbox("Show Spread Changes")

    #if showMoves:
    #    st.header('Spread Moves')

    #    st.dataframe(change)

#############
    showStats = st.checkbox("Show Statistics")

    if showStats:

        #descriptiveDF = issuerFilter[['Spread', 'Term']]
        descriptiveDF = issuerFilter[['Companion_Spread', 'JIBAR_Spread']]

        df1, df2, df3= st.columns([0.6,1,1])

        df1.header('Statistics')
        df1.markdown(' ')
        df1.markdown(' ')
        df1.markdown(' ')
        df1.markdown(' ')
        df1.dataframe(descriptiveDF.describe())

        histSpOJ = MTMHistogram(issuerFilter, 'Companion_Spread', 'ISSUER')
        df2.header('Companion_Spread Histogram')
        df2.plotly_chart(histSpOJ, use_container_width=True)

        #histTerm = MTMHistogram(issuerFilter, 'Term', 'ISSUER')
        #df3.header('Term Histogram')
        #df3.plotly_chart(histTerm, use_container_width=True)

        histJIBARSpread = MTMHistogram(issuerFilter, 'JIBAR_Spread', 'ISSUER')
        df3.header('JIBAR_Spread Histogram')
        df3.plotly_chart(histJIBARSpread, use_container_width=True)

    showGraph = st.checkbox("Spread Over Companion Bond Regression")

    if showGraph:

        yieldGraph, summary, param, rSquared = MTMRegression(issuerFilter)

        graphCol, summaryCol = st.columns([1.1,0.9])

        graphCol.header('OLS Comapanion Bond Spread')

        graphCol.plotly_chart(yieldGraph)

        summaryCol.header('Companion Bond Model Based Spread')

        constant = round(param[0],5)
        gradient = round(param[1],5)

        summaryCol.markdown(' ')
        summaryCol.markdown(' ')
        summaryCol.markdown(' ')
        summaryCol.markdown(' ')

        summaryCol.markdown('Spread over Companion Bond = '+str(round(param[0],2))+' + ' + str(round(param[1],2)) + ' x Term')

        summaryCol.markdown('R-Squared = '+str(round(rSquared,2)))

        inputTerm = summaryCol.number_input('Term', value=1.00)

        Spread = round(constant + gradient*inputTerm,2)

        averageCompanionYield = round(issuerFilter['YTM'].mean() - (issuerFilter['Companion_Spread'].mean())/100,2)

        YTM = round(averageCompanionYield + (Spread/100), 2)

        YTMQuarterly = round(400*(((1+(YTM/200))**(2/4))-1),2)

        #YTM = round(((200*(((1+(((Spread/100)+refRate)/400))**(2))-1))),2)

        summaryCol.markdown('Ref: Average Companion Bond Yield = '+str(averageCompanionYield))

        summaryCol.markdown('Spread over Companion Bond = '+str(Spread))
        summaryCol.markdown('Quarterly YTM = ' + str(YTMQuarterly))
        summaryCol.markdown('Semi-Annual YTM = ' + str(YTM))

        #showSummary= st.checkbox("Companion Bond Regression Results")
        #if showSummary:
        #
        #    st.header('OLS Results Summary')
        #    summary

    showGraph = st.checkbox("Spread Over JIBAR Regression")

    if showGraph:

        yieldGraph, summary, param, rSquaredJibar = MTMRegressionJIBAR(issuerFilter)

        graphCol, summaryCol = st.columns([1.1,0.9])

        graphCol.header('OLS JIBAR Spread')

        graphCol.plotly_chart(yieldGraph)

        summaryCol.header('JIBAR Model Based Spread')

        constant = round(param[0],5)
        gradient = round(param[1],5)

        summaryCol.markdown(' ')
        summaryCol.markdown(' ')
        summaryCol.markdown(' ')
        summaryCol.markdown(' ')

        summaryCol.markdown('Spread Over 3M JIBAR = '+str(round(param[0],2))+' + ' + str(round(param[1],2)) + ' x Term')
        summaryCol.markdown('R-Squared = '+str(round(rSquaredJibar,2)))

        inputTerm = summaryCol.number_input('Tenor', value=1.00)

        Spread = round(constant + gradient*inputTerm,2)

        #YTM = round(((200*(((1+(((Spread/100)+refRate)/400))**(2))-1))),2)

        YTM = round((Spread/100) + refRate,2)

        YTMSemi = round(200*(((1+(YTM/400))**(2))-1),2)

        summaryCol.markdown('Ref: 3M JIBAR = '+str(refRate))

        summaryCol.markdown('Spread over 3M JIBAR = '+str(Spread))
        summaryCol.markdown('Quarterly YTM = ' + str(YTM))
        summaryCol.markdown('Semi-Annual YTM = ' + str(YTMSemi))

        #showSummary= st.checkbox("JIBAR Spread Regression Results")
        #if showSummary:
        #
        #    st.header('OLS Results Summary')
        #    summary
######

elif(selection == 'Industry'):

    industry1 = st.multiselect('Industries', industry, default = 'BANK')

    emptyDf = []

    for industry in industry1:
        container = bondData.loc[(bondData['ISSUER_INDUSTRY'] == industry)]
        emptyDf.append(container)

    industryFilter = pd.concat(emptyDf)

    industryIssuer = st.sidebar.checkbox("Issuer")
    if industryIssuer:
        issuerIndustry = st.sidebar.selectbox('Issuer', issuers, index=0)
        industryFilter = industryFilter.loc[(industryFilter['ISSUER'] == issuerIndustry)]

    rankIndustry = st.sidebar.checkbox("Rank")
    if rankIndustry:
        industryRank = st.sidebar.selectbox('Rank', rank, index=0)
        industryFilter = industryFilter.loc[(industryFilter['PAYMENT_RANK'] == industryRank)]

    industryBenchmark = st.sidebar.checkbox("Benchmark")
    if industryBenchmark:
        benchmarkIndustry = st.sidebar.selectbox('Rank', benchmark, index=0)
        industryFilter = industryFilter.loc[(industryFilter['Companion Bond'] == benchmarkIndustry)]

    industryDate = st.sidebar.checkbox("Date")
    if industryDate:
        dateIssuer1 = st.sidebar.date_input("Start Date")
        dateIssuer2 = st.sidebar.date_input("End Date")

        industryFilter = industryFilter.loc[(industryFilter['Maturity'] >= dateIssuer1) & (industryFilter['Maturity'] <= dateIssuer2)]

    bondCode = st.checkbox("Filter on Bond Code")

    if bondCode:

        identifier = industryFilter['Bond Code'].unique()

        codeBonds = st.multiselect('Bond Codes', identifier)

        industryFilter = industryFilter[industryFilter['Bond Code'].isin(codeBonds)]

    st.dataframe(industryFilter)

#############
    showStats = st.checkbox("Show Statistics")

    if showStats:

        #descriptiveDF = industryFilter[['Spread', 'Term']]
        descriptiveDF = industryFilter[['Companion_Spread', 'JIBAR_Spread']]

        df1, df2, df3= st.columns([0.6,1,1])

        df1.header('Statistics')
        df1.markdown(' ')
        df1.markdown(' ')
        df1.markdown(' ')
        df1.markdown(' ')
        df1.dataframe(descriptiveDF.describe())

        histSpOJ = MTMHistogram(industryFilter, 'Companion_Spread', 'ISSUER')
        df2.header('Companion_Spread Histogram')
        df2.plotly_chart(histSpOJ, use_container_width=True)

        #histTerm = MTMHistogram(industryFilter, 'Term', 'ISSUER')
        #df3.header('Term Histogram')
        #df3.plotly_chart(histTerm, use_container_width=True)

        histJIBARSpread = MTMHistogram(industryFilter, 'JIBAR_Spread', 'ISSUER')
        df3.header('JIBAR_Spread Histogram')
        df3.plotly_chart(histJIBARSpread, use_container_width=True)

    showGraph = st.checkbox("Spread Over Companion Bond Regression")

    if showGraph:

        yieldGraph, summary, param = MTMRegression(industryFilter)

        graphCol, summaryCol = st.columns([1.1,0.9])

        graphCol.header('OLS Comapanion Bond Spread')

        graphCol.plotly_chart(yieldGraph)

        summaryCol.header('Companion Bond Model Based Spread')

        constant = round(param[0],5)
        gradient = round(param[1],5)

        summaryCol.markdown(' ')
        summaryCol.markdown(' ')
        summaryCol.markdown(' ')
        summaryCol.markdown(' ')

        summaryCol.markdown('Spread over Companion Bond= '+str(round(param[0],2))+' + ' + str(round(param[1],2)) + ' x Term')

        inputTerm = summaryCol.number_input('Term', value=1.00)

        Spread = round(constant + gradient*inputTerm,2)

        averageCompanionYield = round(industryFilter['YTM'].mean() - (industryFilter['Companion_Spread'].mean())/100,2)

        YTM = round(averageCompanionYield + (Spread/100), 2)

        YTMQuarterly = round(400*(((1+(YTM/200))**(2/4))-1),2)

        #YTM = round(((200*(((1+(((Spread/100)+refRate)/400))**(2))-1))),2)

        summaryCol.markdown('Ref: Average Companion Bond Yield = '+str(averageCompanionYield))

        summaryCol.markdown('Spread over Companion Bond = '+str(Spread))
        summaryCol.markdown('Quarterly YTM = ' + str(YTMQuarterly))
        summaryCol.markdown('Semi-Annual YTM = ' + str(YTM))

        showSummary= st.checkbox("Companion Bond Regression Results")
        if showSummary:

            st.header('OLS Results Summary')

            summary

    showGraph = st.checkbox("Spread Over JIBAR Regression")

    if showGraph:

        yieldGraph, summary, param = MTMRegressionJIBAR(industryFilter)

        graphCol, summaryCol = st.columns([1.1,0.9])

        graphCol.header('OLS JIBAR Spread')

        graphCol.plotly_chart(yieldGraph)

        summaryCol.header('JIBAR Model Based Spread')

        constant = round(param[0],5)
        gradient = round(param[1],5)

        summaryCol.markdown(' ')
        summaryCol.markdown(' ')
        summaryCol.markdown(' ')
        summaryCol.markdown(' ')

        summaryCol.markdown('Spread Over 3M JIBAR = '+str(round(param[0],2))+' + ' + str(round(param[1],2)) + ' x Term')

        inputTerm = summaryCol.number_input('Tenor', value=1.00)

        Spread = round(constant + gradient*inputTerm,2)

        #YTM = round(((200*(((1+(((Spread/100)+refRate)/400))**(2))-1))),2)

        YTM = round((Spread/100) + refRate,2)

        YTMSemi = round(200*(((1+(YTM/400))**(2))-1),2)

        summaryCol.markdown('Ref: 3M JIBAR = '+str(refRate))

        summaryCol.markdown('Spread over 3M JIBAR = '+str(Spread))
        summaryCol.markdown('Quarterly YTM = ' + str(YTM))
        summaryCol.markdown('Semi-Annual YTM = ' + str(YTMSemi))

        showSummary= st.checkbox("JIBAR Spread Regression Results")
        if showSummary:

            st.header('OLS Results Summary')

            summary
######

elif (selection == 'Rank'):

    rank1 = st.multiselect('Rank', rank, default = 'Sr Unsecured')

    emptyDf = []

    for rank in rank1:
        container = bondData.loc[(bondData['PAYMENT_RANK'] == rank)]
        emptyDf.append(container)

    rankFilter = pd.concat(emptyDf)

    rankIssuer = st.sidebar.checkbox("Issuer")
    if rankIssuer:
        issuerRank = st.sidebar.selectbox('Issuer', issuers, index=0)
        rankFilter = rankFilter.loc[(rankFilter['ISSUER'] == issuerRank)]

    rankIndustry = st.sidebar.checkbox("Industry")
    if rankIndustry:
        industryRank = st.sidebar.selectbox('Industry', industry, index=0)
        rankFilter = rankFilter.loc[(rankFilter['ISSUER_INDUSTRY'] == industryRank)]

    rankBenchmark = st.sidebar.checkbox("Benchmark")
    if rankBenchmark:
        benchmarkRank = st.sidebar.selectbox('Rank', benchmark, index=0)
        rankFilter = rankFilter.loc[(rankFilter['Companion Bond'] == benchmarkRank)]

    industryDate = st.sidebar.checkbox("Date")
    if industryDate:
        dateIssuer1 = st.sidebar.date_input("Start Date")
        dateIssuer2 = st.sidebar.date_input("End Date")

        rankFilter = rankFilter.loc[(rankFilter['Maturity'] >= dateIssuer1) & (rankFilter['Maturity'] <= dateIssuer2)]

    bondCode = st.checkbox("Filter on Bond Code")

    if bondCode:

        identifier = rankFilter['Bond Code'].unique()

        codeBonds = st.multiselect('Bond Codes', identifier)

        rankFilter = rankFilter[rankFilter['Bond Code'].isin(codeBonds)]

    st.dataframe(rankFilter)

#############
    showStats = st.checkbox("Show Statistics")

    if showStats:

        #descriptiveDF = rankFilter[['Spread', 'Term']]
        descriptiveDF = rankFilter[['Companion_Spread', 'JIBAR_Spread']]

        df1, df2, df3= st.columns([0.6,1,1])

        df1.header('Statistics')
        df1.markdown(' ')
        df1.markdown(' ')
        df1.markdown(' ')
        df1.markdown(' ')
        df1.dataframe(descriptiveDF.describe())

        histSpOJ = MTMHistogram(rankFilter, 'Companion_Spread', 'ISSUER')
        df2.header('Companion_Spread Histogram')
        df2.plotly_chart(histSpOJ, use_container_width=True)

        #histTerm = MTMHistogram(rankFilter, 'Term', 'ISSUER')
        #df3.header('Term Histogram')
        #df3.plotly_chart(histTerm, use_container_width=True)

        histJIBARSpread = MTMHistogram(rankFilter, 'JIBAR_Spread', 'ISSUER')
        df3.header('JIBAR_Spread Histogram')
        df3.plotly_chart(histJIBARSpread, use_container_width=True)

    showGraph = st.checkbox("Spread Over Companion Bond Regression")

    if showGraph:

        yieldGraph, summary, param = MTMRegression(rankFilter)

        graphCol, summaryCol = st.columns([1.1,0.9])

        graphCol.header('OLS Comapanion Bond Spread')

        graphCol.plotly_chart(yieldGraph)

        summaryCol.header('Companion Bond Model Based Spread')

        constant = round(param[0],5)
        gradient = round(param[1],5)

        summaryCol.markdown(' ')
        summaryCol.markdown(' ')
        summaryCol.markdown(' ')
        summaryCol.markdown(' ')

        summaryCol.markdown('Spread over Companion Bond= '+str(round(param[0],2))+' + ' + str(round(param[1],2)) + ' x Term')

        inputTerm = summaryCol.number_input('Term', value=1.00)

        Spread = round(constant + gradient*inputTerm,2)

        averageCompanionYield = round(rankFilter['YTM'].mean() - (rankFilter['Companion_Spread'].mean())/100,2)

        YTM = round(averageCompanionYield + (Spread/100), 2)

        YTMQuarterly = round(400*(((1+(YTM/200))**(2/4))-1),2)

        #YTM = round(((200*(((1+(((Spread/100)+refRate)/400))**(2))-1))),2)

        summaryCol.markdown('Ref: Average Companion Bond Yield = '+str(averageCompanionYield))

        summaryCol.markdown('Spread over Companion Bond = '+str(Spread))
        summaryCol.markdown('Quarterly YTM = ' + str(YTMQuarterly))
        summaryCol.markdown('Semi-Annual YTM = ' + str(YTM))

        showSummary= st.checkbox("Companion Bond Regression Results")
        if showSummary:

            st.header('OLS Results Summary')

            summary

    showGraph = st.checkbox("Spread Over JIBAR Regression")

    if showGraph:

        yieldGraph, summary, param = MTMRegressionJIBAR(rankFilter)

        graphCol, summaryCol = st.columns([1.1,0.9])

        graphCol.header('OLS JIBAR Spread')

        graphCol.plotly_chart(yieldGraph)

        summaryCol.header('JIBAR Model Based Spread')

        constant = round(param[0],5)
        gradient = round(param[1],5)

        summaryCol.markdown(' ')
        summaryCol.markdown(' ')
        summaryCol.markdown(' ')
        summaryCol.markdown(' ')

        summaryCol.markdown('Spread Over 3M JIBAR = '+str(round(param[0],2))+' + ' + str(round(param[1],2)) + ' x Term')

        inputTerm = summaryCol.number_input('Tenor', value=1.00)

        Spread = round(constant + gradient*inputTerm,2)

        #YTM = round(((200*(((1+(((Spread/100)+refRate)/400))**(2))-1))),2)

        YTM = round((Spread/100) + refRate,2)

        YTMSemi = round(200*(((1+(YTM/400))**(2))-1),2)

        summaryCol.markdown('Ref: 3M JIBAR = '+str(refRate))

        summaryCol.markdown('Spread over 3M JIBAR = '+str(Spread))
        summaryCol.markdown('Quarterly YTM = ' + str(YTM))
        summaryCol.markdown('Semi-Annual YTM = ' + str(YTMSemi))

        showSummary= st.checkbox("JIBAR Spread Regression Results")
        if showSummary:

            st.header('OLS Results Summary')

            summary

################################################################################
################################################################################


import random
from matplotlib import pyplot as plt
import numpy as np

def determine_if_mandelbrot(iterations, imaginary_number):
    z = imaginary_number
    iteration = 0
    while abs(z.real) < 2 and abs(z.imag) < 2 and iteration < iterations:
        z = z**2 + imaginary_number
        iteration += 1
    if iteration == iterations:
        boolean = 'T'
    else:
        boolean = 'F'
    return [imaginary_number, iteration, boolean]

realRange = [-2, 2]
imagRange = [-2, 2]
n = 800000
iterations = 1000

realGrid = np.arange(realRange[0], realRange[1], (realRange[1]-realRange[0])*1.0/n)
if len(realGrid) == n:
	realGrid = np.append(realGrid, realRange[1])
imagGrid = np.arange(imagRange[0], imagRange[1], (imagRange[1]-imagRange[0])*1.0/n)
if len(imagGrid) == n:
	imagGrid = np.append(imagGrid, imagRange[1])

realOrder = random.sample(np.arange(n), n)
imagOrder = random.sample(np.arange(n), n)

all_points = []
max = -2
for i in range(n):

	point = random.uniform(realGrid[realOrder[i]], realGrid[realOrder[i] + 1]) + 1j* random.uniform(imagGrid[imagOrder[i]], imagGrid[imagOrder[i]+1])
	all_points.append(determine_if_mandelbrot(iterations, point))

hit = 0
x = []
y = []
color = []

for result in all_points:
	if result[2] == 'T':
		hit += 1
	x.append(result[0].real)
	y.append(result[0].imag)
	color.append(result[1])

plt.scatter(x,y, s=1, c=color)
plt.ylim(-2,2)
plt.xlim(-2,2)
print(hit*1.0/n * 16.0)
plt.show()


from locust import HttpLocust, TaskSet, task

class UserBehavior(TaskSet):
    # runs one time for each user
    def on_start(self):
        self.client.get("/")

    @task(2)  # chance to run 2/3
    def posts(self):
        self.client.get("/posts")

    @task(1)  # chance to run 1/3
    def comment(self):
        data = {
            "postId": 1,
            "name": "my comment",
            "email": "test@user.test",
            "body": "Author is cool. Some text. Hello world!"
        }
        self.client.post("/comments", data)

class WebsiteUser(HttpLocust):
    task_set = UserBehavior
    min_wait = 1000
    max_wait = 2000


import datetime

from aiogram import Router, Bot, F
from aiogram.filters import Command, Text
from aiogram.types import CallbackQuery, Message, ChatInviteLink, \
    InlineKeyboardButton

from aiogram.fsm.context import FSMContext
from aiogram.utils.deep_linking import create_start_link, decode_payload
from aiogram.utils.keyboard import InlineKeyboardBuilder

from config_data.conf import LOGGING_CONFIG, conf, tz
import logging.config

from keyboards.keyboards import start_kb, custom_kb
from lexicon.lexicon import LEXICON_RU
from services.db_func import create_user, check_user, get_channels, \
    get_user_subscribe_text, update_subscribe
from services.referal import add_referal_count

logging.config.dictConfig(LOGGING_CONFIG)
logger = logging.getLogger('bot_logger')
err_log = logging.getLogger('errors_logger')

router: Router = Router()

@router.message(Command(commands=["start"]))
async def process_start_command(message: Message, state: FSMContext, bot: Bot):
    await state.clear()
    referal = message.text[7:]
    new_user = create_user(message.from_user, referal)
    if new_user:
        reference = str(decode_payload(referal))
        if reference and reference != new_user.tg_id:
            add_referal_count(reference)
        await message.answer(LEXICON_RU['start_text'], reply_markup=start_kb)
    else:
        await message.answer(LEXICON_RU['start_text'], reply_markup=start_kb)

@router.callback_query(Text(text='demo'))
async def get_demo_info(callback: CallbackQuery, state: FSMContext, bot: Bot):
    text = LEXICON_RU['demo_text']
    await callback.message.answer(text, reply_markup=custom_kb(1, {'Получить пробный доступ': 'get_demo'}))
    await callback.message.delete()

@router.callback_query(Text(text='get_demo'))
async def get_demo(callback: CallbackQuery, state: FSMContext, bot: Bot):
    user = check_user(callback.from_user.id)
    if user.demo_used:
        await callback.message.answer('Вы уже использовали демо-доступ')
    else:
        user.set('demo_used', 1)
        channels = get_channels()
        for channel in channels:
            link: ChatInviteLink = await bot.create_chat_invite_link(
                chat_id=channel.channel_id,
                creates_join_request=False,
                expire_date=(datetime.datetime.now(tz=conf.tg_bot.TIMEZONE) + datetime.timedelta(hours=24)),
                member_limit=1)
            text = LEXICON_RU['get_demo'].format(channel.title)
            url_button_1 = InlineKeyboardButton(
                text=f'Перейти на {channel.title}',
                url=f'{link.invite_link}')
            kb_builder: InlineKeyboardBuilder = InlineKeyboardBuilder()
            kb_builder.row(url_button_1)
            keyboard = kb_builder.as_markup()
            await callback.message.answer(text, reply_markup=keyboard)
            await bot.unban_chat_member(chat_id=channel.channel_id,
                                        user_id=callback.from_user.id,
                                        only_if_banned=True)
            # user.set('demo_expire', link.expire_date)
            update_subscribe(user, channel.id, 1)

    await callback.message.delete()

@router.callback_query(Text(text='check_expire'))
async def check_expire(callback: CallbackQuery, state: FSMContext, bot: Bot):
    subscribes_text = get_user_subscribe_text(callback.from_user.id)
    await callback.message.answer(subscribes_text)

@router.callback_query(Text(text='support'))
async def support(callback: CallbackQuery, state: FSMContext, bot: Bot):
    text = LEXICON_RU['support_text']
    await callback.message.answer(text, reply_markup=start_kb)
    await callback.message.delete()