import pyglet
from src import Constants, CommonHelpers, Snake
from src.ui import AbstractUI

class NiceUI(AbstractUI.AbstractUI):
    def __init__(self, x, y, width, height, square_size):
        super().__init__(x, y, width, height, square_size, 2)
        self.draw_loading_screen()
        self.game_width = self.square_size * self.num_squares_width
        self.game_height = self.square_size * self.num_squares_height
        self.load_images()
        self.prepare_cover_squares()
        # enable transparency
        pyglet.gl.glEnable(pyglet.gl.GL_BLEND)
        pyglet.gl.glBlendFunc(pyglet.gl.GL_SRC_ALPHA, pyglet.gl.GL_ONE_MINUS_SRC_ALPHA)

    def draw_loading_screen(self):
        CommonHelpers.draw_colored_rectangle(self.screen_x, self.screen_y, self.width, self.height, 65, 51, 101)
        pyglet.text.Label(text="Loading...",
                          x=(self.screen_x + self.width / 2), y=(self.screen_y + self.height / 2),
                          anchor_x="center", anchor_y="center",
                          font_name="Bangers", font_size=60).draw()
        pyglet.gl.glFlush()

    """ IMAGE LOADING """

    def load_images(self):
        self.load_grass()
        self.load_score_background()
        self.load_snake()
        self.load_bush()
        self.load_apple()

    def load_grass(self):
        grass_image = pyglet.resource.image("NiceUI/grass.jpg")
        CommonHelpers.scale_image(grass_image, self.width - 2,
                                  self.height - 2)  # minus few pixels so the boundary is visible
        CommonHelpers.center_image(grass_image)
        self.grass = pyglet.sprite.Sprite(img=grass_image,
                                          x=self.screen_x + (self.width / 2), y=self.screen_y + (self.height / 2))

    def load_score_background(self):
        score_background_image = pyglet.resource.image("NiceUI/score_background.png")
        CommonHelpers.scale_image(score_background_image, self.game_width, self.square_size * self.score_squares)
        CommonHelpers.center_image(score_background_image)
        self.score_background = pyglet.sprite.Sprite(img=score_background_image,
                                                     x=self.game_x + self.game_width / 2,
                                                     y=self.game_y + self.game_height + (score_background_image.height / 2))

    def load_snake(self):
        snake_head_image = pyglet.resource.image("NiceUI/snake_head.png")
        snake_body_image = pyglet.resource.image("NiceUI/snake_body.png")
        snake_corner_image = pyglet.resource.image("NiceUI/snake_corner.png")
        snake_tail_image = pyglet.resource.image("NiceUI/snake_tail.png")
        snake_head_dead_image = pyglet.resource.image("NiceUI/snake_head_dead.png")

        CommonHelpers.scale_image(snake_head_image, self.square_size, self.square_size)
        CommonHelpers.scale_image(snake_body_image, self.square_size, self.square_size)
        CommonHelpers.scale_image(snake_corner_image, self.square_size, self.square_size)
        CommonHelpers.scale_image(snake_tail_image, self.square_size, self.square_size)
        CommonHelpers.scale_image(snake_head_dead_image, self.square_size, self.square_size)

        CommonHelpers.center_image(snake_head_image)
        CommonHelpers.center_image(snake_body_image)
        CommonHelpers.center_image(snake_corner_image)
        CommonHelpers.center_image(snake_tail_image)
        CommonHelpers.center_image(snake_head_dead_image)

        self.snake_head = pyglet.sprite.Sprite(img=snake_head_image)
        self.snake_body = pyglet.sprite.Sprite(img=snake_body_image)
        self.snake_corner = pyglet.sprite.Sprite(img=snake_corner_image)
        self.snake_tail = pyglet.sprite.Sprite(img=snake_tail_image)
        self.snake_head_dead = pyglet.sprite.Sprite(img=snake_head_dead_image)

    def load_bush(self):
        bush_image = pyglet.resource.image("NiceUI/bush2.png")
        CommonHelpers.scale_image(bush_image, self.square_size, self.square_size)
        CommonHelpers.center_image(bush_image)
        self.bush = pyglet.sprite.Sprite(img=bush_image)

    def load_apple(self):
        apple_image = pyglet.resource.image("NiceUI/apple.png")
        CommonHelpers.scale_image(apple_image, self.square_size, self.square_size)
        CommonHelpers.center_image(apple_image)
        self.apple = pyglet.sprite.Sprite(img=apple_image)

    """ OTHER PREPARATIONS """

    def prepare_cover_squares(self):
        grass = pyglet.resource.image("NiceUI/grass.png")
        self.cover_squares = []
        for i in range(self.num_squares_height):
            row = []
            for j in range(self.num_squares_width):
                square = grass.get_region(x=(self.game_x + j * self.square_size),
                                          y=(self.game_y + i * self.square_size),
                                          width=self.square_size, height=self.square_size)
                row.append(pyglet.sprite.Sprite(square,
                                                x=(self.game_x + j * self.square_size),
                                                y=(self.game_y + i * self.square_size)))
            self.cover_squares.append(row)

    """ GETTERS """

    def get_num_squares_height(self):
        return self.num_squares_height

    def get_num_squares_width(self):
        return self.num_squares_width

    """ DRAWING """

    def prepare_game(self, snake):
        self.draw_background()
        self.draw_score(0)
        self.draw_game_field()
        self.draw_boundary()
        self.draw_snake(snake)
        pyglet.gl.glFlush()

    def draw_snake_eat(self, snake: Snake.Snake):
        self.draw_square(snake.head.next_n.x, snake.head.next_n.y)
        self.draw_snake_head(snake.head)
        self.draw_snake_part(snake.head.next_n)
        pyglet.gl.glFlush()

    def draw_snake_move(self, snake: Snake.Snake, prev_tail):
        self.draw_square(prev_tail[0], prev_tail[1])
        self.draw_square(snake.tail.x, snake.tail.y)
        self.draw_square(snake.head.next_n.x, snake.head.next_n.y)
        self.draw_snake_head(snake.head)
        self.draw_snake_part(snake.head.next_n)
        self.draw_snake_tail(snake.tail)
        pyglet.gl.glFlush()

    def draw_apple(self, x, y):
        self.apple.x = self.game_x + x * self.square_size + self.square_size / 2
        self.apple.y = self.game_y + y * self.square_size + self.square_size / 2
        self.apple.draw()
        pyglet.gl.glFlush()

    def draw_snake(self, snake: Snake.Snake):
        for part in snake:
            self.draw_snake_part(part)
        pyglet.gl.glFlush()

    def draw_snake_dead(self, snake: Snake.Snake):
        self.draw_snake_head_dead(snake.head)
        pyglet.gl.glFlush()

    def draw_snake_part(self, part: Snake.ListNode):
        if Snake.is_head(part):
            self.draw_snake_head(part)
        elif Snake.is_tail(part):
            self.draw_snake_tail(part)
        elif Snake.is_body(part):
            self.draw_snake_body(part)
        elif Snake.is_corner(part):
            self.draw_snake_corner(part)
        pyglet.gl.glFlush()

    def draw_snake_head(self, part: Snake.ListNode):
        self.snake_head.x = self.game_x + (part.x * self.square_size) + (self.square_size / 2)
        self.snake_head.y = self.game_y + (part.y * self.square_size) + (self.square_size / 2)
        direction = Snake.heads_direction(part)
        if direction is Constants.UP:
            self.snake_head.rotation = 0
        elif direction is Constants.RIGHT:
            self.snake_head.rotation = 90
        elif direction is Constants.DOWN:
            self.snake_head.rotation = 180
        elif direction is Constants.LEFT:
            self.snake_head.rotation = 270
        self.snake_head.draw()
        pyglet.gl.glFlush()

    def draw_snake_head_dead(self, part: Snake.ListNode):
        self.snake_head_dead.x = self.game_x + (part.x * self.square_size) + (self.square_size / 2)
        self.snake_head_dead.y = self.game_y + (part.y * self.square_size) + (self.square_size / 2)
        direction = Snake.heads_direction(part)
        if direction is Constants.UP:
            self.snake_head_dead.rotation = 0
        elif direction is Constants.RIGHT:
            self.snake_head_dead.rotation = 90
        elif direction is Constants.DOWN:
            self.snake_head_dead.rotation = 180
        elif direction is Constants.LEFT:
            self.snake_head_dead.rotation = 270
        self.snake_head_dead.draw()
        pyglet.gl.glFlush()

    def draw_snake_tail(self, part: Snake.ListNode):
        self.snake_tail.x = self.game_x + (part.x * self.square_size) + (self.square_size / 2)
        self.snake_tail.y = self.game_y + (part.y * self.square_size) + (self.square_size / 2)
        direction = Snake.rest_direction(part)
        if direction is Constants.UP:
            self.snake_tail.rotation = 0
        elif direction is Constants.RIGHT:
            self.snake_tail.rotation = 90
        elif direction is Constants.DOWN:
            self.snake_tail.rotation = 180
        elif direction is Constants.LEFT:
            self.snake_tail.rotation = 270
        self.snake_tail.draw()
        pyglet.gl.glFlush()

    def draw_snake_body(self, part: Snake.ListNode):
        self.snake_body.x = self.game_x + (part.x * self.square_size) + (self.square_size / 2)
        self.snake_body.y = self.game_y + (part.y * self.square_size) + (self.square_size / 2)
        direction = Snake.heads_direction(part)
        if direction is Constants.UP or direction is Constants.DOWN:
            self.snake_body.rotation = 0
        elif direction is Constants.LEFT or direction is Constants.RIGHT:
            self.snake_body.rotation = 90
        self.snake_body.draw()
        pyglet.gl.glFlush()

    def draw_snake_corner(self, part: Snake.ListNode):
        self.snake_corner.x = self.game_x + (part.x * self.square_size) + (self.square_size / 2)
        self.snake_corner.y = self.game_y + (part.y * self.square_size) + (self.square_size / 2)
        direction = Snake.corner_type(part)
        if direction[0] is Constants.UP and direction[1] is Constants.RIGHT:
            self.snake_corner.rotation = 270
        elif direction[0] is Constants.UP and direction[1] is Constants.LEFT:
            self.snake_corner.rotation = 180
        elif direction[0] is Constants.DOWN and direction[1] is Constants.RIGHT:
            self.snake_corner.rotation = 0
        elif direction[0] is Constants.DOWN and direction[1] is Constants.LEFT:
            self.snake_corner.rotation = 90
        self.snake_corner.draw()
        pyglet.gl.glFlush()

    def draw_game_field(self):
        for i in range(1, self.num_squares_height - 1):
            for j in range(1, self.num_squares_width - 1):
                self.draw_square(j, i)
        self.draw_bushes()
        pyglet.gl.glFlush()

    def draw_square(self, x, y):
        self.cover_squares[y][x].draw()
        x1 = self.game_x + (x * self.square_size)
        y1 = self.game_y + (y * self.square_size)
        x2 = x1
        y2 = y1 + self.square_size
        x3 = x1 + self.square_size
        y3 = y1 + self.square_size
        x4 = x1 + self.square_size
        y4 = y1
        if y % 2:
            if x % 2:
                pyglet.graphics.draw(4, pyglet.gl.GL_QUADS,
                                     ("v2f", (x1, y1, x2, y2, x3, y3, x4, y4)),
                                     ("c4B", ((11, 102, 35, 110) * 4)))
            else:
                pyglet.graphics.draw(4, pyglet.gl.GL_QUADS,
                                     ("v2f", (x1, y1, x2, y2, x3, y3, x4, y4)),
                                     ("c4B", ((137, 173, 111, 80) * 4)))
        else:
            if x % 2:
                pyglet.graphics.draw(4, pyglet.gl.GL_QUADS,
                                     ("v2f", (x1, y1, x2, y2, x3, y3, x4, y4)),
                                     ("c4B", ((137, 173, 111, 80) * 4)))
            else:
                pyglet.graphics.draw(4, pyglet.gl.GL_QUADS,
                                     ("v2f", (x1, y1, x2, y2, x3, y3, x4, y4)),
                                     ("c4B", ((11, 102, 35, 110) * 4)))
        pyglet.gl.glFlush()

    def draw_bushes(self):
        for i in range(self.num_squares_width):
            self.bush.x = self.game_x + i * self.square_size + self.square_size / 2
            self.bush.y = self.game_y + self.square_size / 2
            self.bush.draw()
            self.bush.y = self.game_y + (self.num_squares_height - 1) * self.square_size + self.square_size / 2
            self.bush.draw()
        for i in range(self.num_squares_height):
            self.bush.x = self.game_x + self.square_size / 2
            self.bush.y = self.game_y + i * self.square_size + self.square_size / 2
            self.bush.draw()
            self.bush.x = self.game_x + (self.num_squares_width - 1) * self.square_size + self.square_size / 2
            self.bush.draw()
        pyglet.gl.glFlush()

    def draw_score(self, score):
        self.score_background.draw()
        pyglet.text.Label(text=f"Score: {score}", x=self.score_background.x, y=self.score_background.y,
                          anchor_x="center", anchor_y="center",
                          font_name="Bangers", font_size=self.score_background.height // 3
                          ).draw()
        pyglet.gl.glFlush()

    def draw_background(self):
        self.grass.draw()
        pyglet.gl.glFlush()

    """ DRAW GAME STATES """

    def redraw(self, snake: Snake.Snake, score, identification, num_runs, apple):
        self.draw_snake(snake)
        self.draw_score(score)
        self.draw_apple(apple[0], apple[1])

    def draw_game_over(self):
        pyglet.text.Label(text="GAME OVER",
                          x=(self.game_x + self.game_width / 2),
                          y=(self.game_y + ((self.game_height / 3) * 2)),
                          anchor_x="center", anchor_y="center",
                          font_name="Bangers", font_size=self.game_height // 10).draw()
        pyglet.text.Label(text="[click to go back to menu]",
                          x=(self.game_x + self.game_width / 2),
                          y=(self.game_y + self.game_height / 3),
                          anchor_x="center", anchor_y="center",
                          font_name="Bangers", font_size=self.game_height // 20).draw()
        pyglet.gl.glFlush()

    def draw_game_won(self):
        pyglet.text.Label(text="YOU WIN! CONGRATULATION!",
                          x=(self.game_x + self.game_width / 2),
                          y=(self.game_y + ((self.game_height / 3) * 2)),
                          anchor_x="center", anchor_y="center",
                          font_name="Bangers", font_size=self.game_height // 10).draw()
        pyglet.text.Label(text="[click to go back to menu]",
                          x=(self.game_x + self.game_width / 2),
                          y=(self.game_y + self.game_height / 3),
                          anchor_x="center", anchor_y="center",
                          font_name="Bangers", font_size=self.game_height // 20).draw()
        pyglet.gl.glFlush()

    def draw_boundary(self):
        pyglet.graphics.draw(8, pyglet.gl.GL_LINES,
                             ("v2f", (self.screen_x, self.screen_y,
                                      self.screen_x, self.screen_y + self.height,
                                      self.screen_x, self.screen_y + self.height,
                                      self.screen_x + self.width, self.screen_y + self.height,
                                      self.screen_x + self.width, self.screen_y + self.height,
                                      self.screen_x + self.width, self.screen_y,
                                      self.screen_x + self.width, self.screen_y,
                                      self.screen_x, self.screen_y)))


from __future__ import absolute_import
import sys
sys.path.append('./')

import time
import itertools
import numpy as np
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
from PIL import Image
import cv2

import torch
from unittest import TestCase

from tps_spatial_transformer import TPSSpatialTransformer

class TestTPSSpatialTransformer(TestCase):

  control_points_per_side = 6

  def test_forward(self):

    # specify the input control points with the shape [3, 6, 2]
    test_input_ctrl_pts = np.array([
      [
        [-0.1, 0.4], [0.5, 0.1], [0.9, 0.4],
        [-0.1, 0.9], [0.5, 0.6], [0.9, 0.9]
      ],
      [
        [0.1, 0.1], [0.5, 0.4], [0.9, 0.1],
        [0.1, 0.6], [0.5, 0.9], [0.9, 0.6]
      ],
      [
        [0.1, 0.1], [0.5, 0.1], [0.9, 0.1],
        [0.1, 0.9], [0.5, 0.9], [0.9, 0.9],
      ]
    ], dtype=np.float32)
    source_control_points = torch.from_numpy(test_input_ctrl_pts)

    # preprocess the input image to match the pytorch's format.
    test_im = Image.open('./test_image.jpg').resize((128, 128))
    test_image_array = np.array(test_im).astype('float32')
    test_image_array = np.array([test_image_array, test_image_array, test_image_array])
    test_images = torch.from_numpy(test_image_array)
    test_images = test_images.permute((0,3,1,2))

    target_height, target_width = 32, 100
    margin = 0.05

    print('initialize module')
    beg_time = time.time()
    tps = TPSSpatialTransformer(
      output_image_size=(target_height, target_width),
      num_control_points=6,
      margins=(margin, margin))
    past_time = time.time() - beg_time
    print('initialization takes %.02fs' % past_time)

    target_control_points = tps.target_control_points
    target_control_points_array = target_control_points.numpy()
    target_image, source_coordinate = tps(test_images, source_control_points)
    source_coordinate_array = source_coordinate.numpy()
    grid = source_coordinate.view(-1, target_height, target_width, 2)
    target_image = target_image.permute((0,2,3,1)).numpy()

    if True:
      plt.figure()
      plt.subplot(3,4,1)
      plt.scatter(test_input_ctrl_pts[0,:,0], test_input_ctrl_pts[0,:,1])
      plt.subplot(3,4,2)
      plt.scatter(target_control_points_array[:,0], target_control_points_array[:,1])
      plt.subplot(3,4,3)
      plt.scatter(source_coordinate_array[0,:,0], source_coordinate_array[0,:,1], marker='+')
      plt.subplot(3,4,4)
      plt.imshow(target_image[0].astype(np.uint8))

      plt.subplot(3,4,5)
      plt.scatter(test_input_ctrl_pts[1,:,0], test_input_ctrl_pts[1,:,1])
      plt.subplot(3,4,6)
      plt.scatter(target_control_points_array[:,0], target_control_points_array[:,1])
      plt.subplot(3,4,7)
      plt.scatter(source_coordinate_array[1,:,0], source_coordinate_array[1,:,1], marker='+')
      plt.subplot(3,4,8)
      plt.imshow(target_image[1].astype(np.uint8))

      plt.subplot(3,4,9)
      plt.scatter(test_input_ctrl_pts[2,:,0], test_input_ctrl_pts[2,:,1])
      plt.subplot(3,4,10)
      plt.scatter(target_control_points_array[:,0], target_control_points_array[:,1])
      plt.subplot(3,4,11)
      plt.scatter(source_coordinate_array[2,:,0], source_coordinate_array[2,:,1], marker='+')
      plt.subplot(3,4,12)
      plt.imshow(target_image[2].astype(np.uint8))

      plt.show()
      plt.savefig('plot.png')

if __name__ == '__main__':
  test_tps = TestTPSSpatialTransformer()
  test_tps.test_forward()


import asyncio
from src.peer import PeerConnection, PeerState

class PeersManager:
    def __init__(self, queue, info_hash, peer_id, piece_manager,
                 on_block_cb=None,
                 max_download_peers=35, max_upload_peers=35):
        self.max_download_peers = max_download_peers
        self.max_upload_peers = max_upload_peers
        self.download_peers = []
        self.upload_peers = []
        self.peer_id = peer_id
        self.peers = queue
        self.info_hash = info_hash
        self.piece_manager = piece_manager
        self.on_block_cb = on_block_cb

    async def start_download(self):
        await self.update_download()

    async def start_upload(self):
        server = await asyncio.start_server(self.new_connection_handle,
                                            '0.0.0.0', 6889)
        addr = server.sockets[0].getsockname()
        async with server:
            await server.serve_forever()

    async def new_connection_handle(self, reader, writer):
        peer = PeerConnection(reader, writer, self.info_hash, self.peer_id,
                              self.piece_manager, self.on_block_cb,
                              self.update_upload)
        my_state = [PeerState.Interested, PeerState.Choke]
        peer_state = [PeerState.Choke]
        peer_future = asyncio.ensure_future(peer.start(my_state, peer_state))
        self.upload_peers.append(peer)

    async def update_download(self):
        for i, peer in enumerate(self.download_peers):
            if PeerState.Stopped in peer.my_state:
                del self.download_peers[i]

        while len(self.download_peers) < self.max_download_peers:
            ip, port = await self.peers.get()
            reader, writer = await asyncio.wait_for(
                asyncio.open_connection(ip, port), 30)
            peer = PeerConnection(reader, writer, self.info_hash, self.peer_id,
                                  self.piece_manager, self.on_block_cb,
                                  self.update_download)
            my_state = [PeerState.Interested, PeerState.Choke]
            peer_state = [PeerState.Choke]
            peer_future = asyncio.ensure_future(
                peer.start(my_state, peer_state))
            self.download_peers.append(peer)

    async def update_upload(self):
        for i, peer in enumerate(self.upload_peers):
            if PeerState.Stopped in peer.my_state:
                del self.upload_peers[i]


class Solution:
    def maxProduct(self, nums: List[int]) -> int:
        res = max(nums) # if we take 0/1 and all nums are negative => so we are taking max of nums
        currMin = 1
        currMax = 1

        for n in nums:
            if n == 0:
                currMin = 1
                currMax = 1
            else:
                prevMin = currMin
                prevMax = currMax
                currMin = min(n*prevMin, n*prevMax, n)
                currMax = max(n*prevMin, n*prevMax, n)
                res = max(res, currMax)

        return res


import requests
from bs4 import BeautifulSoup
import pandas as pd
import re
import nltk
from nltk.sentiment import SentimentIntensityAnalyzer
from nltk.corpus import stopwords
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.decomposition import LatentDirichletAllocation
import matplotlib.pyplot as plt
import seaborn as sns
from wordcloud import WordCloud
import warnings

class HealthcareDataExtractorAnalyzer:
    def __init__(self):
        self.healthcare_data = pd.DataFrame(columns=['title', 'content'])

    def web_scraping(self, url):
        response = requests.get(url)
        soup = BeautifulSoup(response.content, 'html.parser')
        data = self.extract_data_from_html(soup)
        self.healthcare_data = self.healthcare_data.append(
            data, ignore_index=True)

    def extract_data_from_html(self, soup):
        title = soup.find('h1').text.strip()
        content = soup.find('div', class_='article-content').text.strip()
        return {'title': title, 'content': content}

    def data_collection(self):
        urls = ['https://example.com/healthcare-data',
                'https://example.com/clinical-trials']
        for url in urls:
            self.web_scraping(url)
        self.healthcare_data.drop_duplicates(inplace=True)

    def data_cleaning_processing(self):
        self.healthcare_data.dropna(inplace=True)
        self.healthcare_data['content'] = self.healthcare_data['content'].apply(
            self.clean_text)

    def clean_text(self, text):
        text = re.sub(r'[^\w\s]', '', text.lower())
        stop_words = set(stopwords.words('english'))
        tokens = nltk.word_tokenize(text)
        filtered_text = [word for word in tokens if word not in stop_words]
        return ' '.join(filtered_text)

    def nlp_analysis(self):
        pass

    def sentiment_analysis(self):
        sid = SentimentIntensityAnalyzer()
        self.healthcare_data['sentiment_score'] = self.healthcare_data['content'].apply(
            lambda x: sid.polarity_scores(x)['compound'])

    def topic_modeling(self):
        vectorizer = TfidfVectorizer()
        tfidf_matrix = vectorizer.fit_transform(
            self.healthcare_data['content'])
        lda = LatentDirichletAllocation(n_components=10, random_state=42)
        lda.fit(tfidf_matrix)
        topics = lda.transform(tfidf_matrix)
        self.healthcare_data['topic'] = topics.argmax(axis=1)

    def data_visualization(self):
        wordcloud = WordCloud(width=800, height=400).generate(
            ' '.join(self.healthcare_data['content']))
        plt.figure(figsize=(12, 8))
        plt.imshow(wordcloud, interpolation='bilinear')
        plt.axis('off')
        plt.show()
        plt.figure(figsize=(12, 6))
        sns.barplot(
            x=self.healthcare_data['sentiment_score'], y=self.healthcare_data['title'])
        plt.xlabel('Sentiment Score')
        plt.ylabel('Article Title')
        plt.title('Sentiment Analysis')
        plt.show()

    def generate_insights(self):
        pass

    def automate_extraction_analysis(self):
        pass

if __name__ == "__main__":
    warnings.filterwarnings("ignore")
    analyzer = HealthcareDataExtractorAnalyzer()
    analyzer.data_collection()
    analyzer.data_cleaning_processing()
    analyzer.nlp_analysis()
    analyzer.sentiment_analysis()
    analyzer.topic_modeling()
    analyzer.data_visualization()
    analyzer.generate_insights()
    analyzer.automate_extraction_analysis()


class lcs(object):
	def lcs(self,s1,s2):
	    res = ""
	    l1=len(s1)
	    l2=len(s2)
	    for i in range(l1):
	        for j in range(l2):
	            point=0
	            res1=''
	            while ((i+point < l1) and (j+point<l2) and s1[i+point] == s2[j+point]):
	                res1=res1+s2[j+point]
	                #print(res1)
	                point=point+1
	            if (len(res1) > len(res)):
	                res = res1

	    return res
#taking file from the path
filelist = []
import os
for file in os.listdir():
	if file.endswith(".txt"):
		y = os.path.join(file)
		filelist.append(y)
print(filelist)
#file reading
#remove special characters and convert string to words in  list.
import re
lst=[]
for i in range(len(filelist)):
	file = open(filelist[i], 'r')
	text = file.read()
	file.close()
	text = re.sub('[^a-z\ \']+', " ", text)
	text = text.replace(" ","")
	words = list(text.split())
	lst.append(words)
Matrixlist= []
for i in range(len(lst)):
	arr2 =[]
	for j in range(len(lst)):
#object creation
		obj=lcs()
		print(lst)
#convert list to string and passed to lcs function
		result= obj.lcs(" ".join(str(x) for x in lst[i])," ".join(str(x) for x in lst[j]))
		str1 = " ".join(str(x) for x in lst[i])
		len1 = len(str1)
		str2 = " ".join(str(x) for x in lst[j])
		len2 = len(str2)
		totallength = len1 + len2
		print(result)
		print(len(result))
		finalresult = ((len(result) * 2) / totallength) * 100
		print(finalresult)
		arr2.append(finalresult)
	Matrixlist.append(arr2)
#printing matrix
for i in range(len(Matrixlist)):
	print(Matrixlist[i])


import torch
import numpy as np

from model_utils.decoders import FPNDecoder
from model_utils.decoders import UNetDecoder
from model_utils.segmentation import EncoderDecoder
from model_utils.segmentation.backbones import ResNetBackbone

def segmentation(models, stack, device, indexes, class_amount, window):

    with torch.no_grad():
        window.progressBar.show()
        progress = 0
        average_preds = torch.zeros((stack.shape[0], class_amount, stack.shape[1], stack.shape[2])).to(device)
        stack = stack / 256.
        stack -= stack.mean()
        stack /= stack.std()
        stack = stack / 255

        model_name = str(models[0])
        model = init_segmentation_model(model_name, class_amount, device=device)

        for model_index, model_weights in enumerate(models):
            model.load_state_dict(torch.load(model_weights, map_location=device)["model"])
            model = model.to(device)
            model.eval()
            for i in range(stack.shape[0]):
                if i not in indexes and indexes != []:
                    progress += 1
                    continue
                progress += 1
                window.progressBar.setValue(int(progress / (len(models)*stack.shape[0])*100))
                image = stack[i, :, :]
                image = np.expand_dims(image, axis=(0, 1))
                image = torch.from_numpy(image).to(device).float()
                out = model(image)
                th = 0.3
                preds = out.gt(th)
                average_preds[i, :, :, :] += preds[0, :, :, :]

        tensor_pred = average_preds / len(models)
        tensor_pred = tensor_pred.gt(0.5)
        if class_amount == 1:
            numpy_pred = tensor_pred[:, 0, :, :].cpu().detach().numpy()
        else:
            numpy_pred = tensor_pred.cpu().detach().numpy()
        torch.cuda.empty_cache()
        return numpy_pred

def init_segmentation_model(model_name, n_classes, device='cuda'):

    if "resnet18" in model_name.lower():
        resnet_num = "resnet18"
    elif "resnet34" in model_name.lower():
        resnet_num = "resnet34"
    elif "resnet50" in model_name.lower():
        resnet_num = "resnet50"
    else:
        raise NotImplementedError

    resnet_backbone = ResNetBackbone(n_classes, resnet_num)
    if 'unet' in model_name.lower():
        mdl = EncoderDecoder(2, resnet_backbone, UNetDecoder(resnet_backbone.shape_dict[resnet_num], final_channels=n_classes))
    elif 'fpn' in model_name.lower():
        mdl = EncoderDecoder(2, resnet_backbone, FPNDecoder(resnet_backbone.shape_dict[resnet_num], final_channels=n_classes))
    else:
        raise NotImplementedError

    mdl = mdl.to(device)

    return mdl


#!/usr/bin/env python

import angr
import claripy

success_addr = 0x101ab3
failure_addr = 0x101ac1
base_addr = 0x100000

project = angr.Project("./cave", main_opts = {"base_addr" : base_addr})

state = project.factory.entry_state()
simgr = project.factory.simulation_manager(state)

simgr.explore(find=success_addr, avoid=failure_addr)

if len(simgr.found) > 0:
    for found in simgr.found:
        print(found.posix.dumps(0))


import json
import os
import unittest

from transactions_api.main import app

class TestTransaction(unittest.TestCase):

    def setUp(self):
        self.app = app.test_client()

    def test_insert_transaction(self):
        title_number = os.environ['TEST_TITLE']
        application_referenece = os.environ['TEST_APPLICATION']
        data = {"appn_trans_code": "C", "appn_trans_value": 123,
                "fee_categ_code": "2", "lr_appn_ref": application_referenece, "title_no": title_number,
                "trans_proc_curr": "Y"}
        post_response = self.app.post('/insert-transaction', data=json.dumps(data),
                                      headers={'Content-Type': 'application/json', 'Accept': 'application/json'})
        self.assertEqual(post_response.status_code, 200)


from django.contrib import admin
from config_app.models import SiteConfig

# Register your models here.
@admin.register(SiteConfig)
class SiteConfig(admin.ModelAdmin):
    MAX_OBJECTS = 1

    def has_add_permission(self, request):
        if self.model.objects.count() >= self.MAX_OBJECTS:
            return False
        return super().has_add_permission(request)


#
# @lc app=leetcode id=215 lang=python3
#
# [215] Kth Largest Element in an Array
#

# @lc code=start
from heapq import heapify, heappop
from typing import List

class Solution:
    '''
    - nums is not sorted.
    - goal: find kth largest element in the sorted array.

    do it without sorting.
    approach: using a min heap to pop out the minimum number n - k times.

    so that the final pop will be our answer.
    '''

    def findKthLargest(self, nums: List[int], k: int) -> int:
        # time: O(k + k log n)
        # space: o(n)
        n = len(nums)
        minHeap = nums[:]
        heapify(minHeap)
        for _ in range(n - k):
            heappop(minHeap)
        return heappop(minHeap)

# @lc code=end

nums = [3, 2, 1, 5, 6, 4]
k = 2
nums = [3, 2, 3, 1, 2, 4, 5, 5, 6]
k = 4
nums = [2, 1]
k = 1
sol = Solution()
ans = sol.findKthLargest(nums, k)
print(f'ans: {ans}')


from django.db.models import fields
from authApp.models.nomina import Nomina,ESTADOS_CHOICES
from authApp.models.empleado import Empleado
from authApp.models.novedad import Novedad
from authApp.models.tiponovedad import Tiponovedad
from authApp.serializers.empleadoSerializer import EmpleadoSerializer
from rest_framework import serializers

class NominaSerializer(serializers.ModelSerializer):
    estado_nom=serializers.ChoiceField(choices=ESTADOS_CHOICES)
    class Meta:
        model = Nomina
        fields = ['codigo_nom','codigo_emp','estado_nom','fechainicio_nom','fechafin_nom','salariobase_nom','salariodevengo_nom','salariodeduccion_nom','salariototal_emp']

    def create(self,validated_data):
        nominaInstancia=  Nomina.objects.create(**validated_data)
        return nominaInstancia

    def update(self,instance,validate_data):
        instance.estado_nom = validate_data.get("estado_nom",instance.estado_nom)
        instance.fechainicio_nom = validate_data.get("fechainicio_nom",instance.fechainicio_nom)
        instance.fechafin_nom = validate_data.get("fechafin_nom",instance.fechafin_nom)
        instance.salariobase_nom = validate_data.get("salariobase_nom",instance.salariobase_nom)
        instance.salariodevengo_nom = validate_data.get("salariodevengo_nom",instance.salariodevengo_nom)
        instance.salariodeduccion_nom = validate_data.get("salariodeduccion_nom",instance.salariodeduccion_nom)
        instance.save()
        return instance

    def to_representation(self, obj):
        nomina = Nomina.objects.get(codigo_nom=obj.codigo_nom)
        empleado =Empleado.objects.get(codigo_emp=obj.codigo_emp)
        novedad =Novedad.objects.get(codigo_nom=obj.codigo_nom,codigo_emp=obj.codigo_emp)
        tiponovedad=Tiponovedad.objects.get(codigo_tipnov=obj.codigo_tipnov)
        return {
                    'codigo_nom' : nomina.codigo_nom,
                    'empleado':{ 'codigo_emp' : empleado.codigo_emp,
                                 'nombre_emp' : empleado.nombre_emp
                               },
                    'estado':   nomina.estado_nom,
                    'fechainicio_nom' : nomina.fechainicio_nom,
                    'fechafin_nom':  nomina.fechafin_nom,

                    'novedad':{ 'codigo_nov' : novedad.codigo_nov,
                                'nombre_tipnov':tiponovedad.nombre_tipnov,
                                'valor_nov' : novedad.valor_nov
                               },
                    'salariobase_nom' :  nomina.salariobase_nom,
                    'salariodevengo_nom' :  nomina.salariodevengo_nom,
                    'salariodeduccion_nom' :  nomina.salariodeduccion_nom,
                    'salariototal_emp':  nomina.salariototal_emp

               }


from typing import List

# 两边扫描，暴力求解
class Solution_1:
    def twoSum(self, nums: List[int], target: int) -> List[int]:

        lens = len(nums)
        # flag = False

        for r1 in range(0, lens):
            for r2 in range(r1+1, lens):
                if nums[r1] + nums[r2] == target:
                    # flag = True
                    return [r1, r2]


print('python - Chapter 13 - if statements nested')
print('==============================================')
print('April 2022')
print()

x = "a"
y = "b"
a = "c"
b = "d"
c = "e"
e = "f"
d = "g"
h = "h"
f = "e"
g = 'I'
if (x == y or a == b) and c == d:
    g = h
else:
    e = f
print(f"If ({x} = {y} or {a} = {b}) and {c} = {d}, then {g} is equal to {h}")
print("Another way to write this is using nesting")
if c == d:
    if x == y:
        g = h
    elif a == b:
        g = h
    else:
        e = f
else:
    e = f
print()
print('When you use nesting, instead of using "and", you just create a new if or elif statement.')
# If the first line if is true, the next 6 lines execute.
# If the first line is false, the next 6 lines are skipped.

# python - Chapter 13 - if statements nested
# ==============================================
# April 2022

# If (a = b or c = d) and e = g, then I is equal to h
# Another way to write this is using nesting

# When you use nesting, instead of using "and", you just create a new if or elif statement.


import threading

import tcp_server, handler

def on_hi(connection_id, data):
  handler.send_message(connection_id, {'return': 'ok'})
  print("From connection: %s  Got data: %s" % (connection_id, data))

if __name__ == "__main__":
  server = tcp_server.Server(('127.0.0.1', 13373))
  handler = handler.JSON_EventMap(server.dispatch_message)
  server.set_handler(handler)
  handler.set_msg_map({ 'hi': on_hi })

  handler_thread = handler.start_thread()
  server_thread = server.start_thread()

  server_thread.join()


import MemePy
from typing import Dict, Any
import json
import io

TEMPLATES = {}

def get_templates() -> Dict[str, int]:
    '''
        Возвращает список возможных шаблонов для мемов
    '''
    result = {}
    memes = MemePy.MemeLibJsonDecoder.generate_standard_meme_dict()

    for meme in memes.keys():
        result[meme] = memes[meme].count_non_optional()

    return result

def generate(template, *params) -> Any:
    params = list(params)

    for i in range(len(params)):
        while '_' in params[i]:
            params[i] = params[i].replace('_', ' ')

    meme_pill = MemePy.MemeGenerator.get_meme_image(template, params)
    output = io.BytesIO()
    meme_pill.save(output, format='png')

    return output.getvalue()

TEMPLATES = get_templates()


import pandas
from sklearn import model_selection
from sklearn.metrics import classification_report
from sklearn.metrics import confusion_matrix
from sklearn.metrics import accuracy_score
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
from sklearn.naive_bayes import GaussianNB
from sklearn.svm import SVC

url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/iris.csv"
names = ['sepal-length', 'sepal-width', 'petal-length', 'petal-width', 'class']
dataset = pandas.read_csv(url, names=names)

print(dataset.shape)
print(dataset.head(20))
print(dataset.describe())
print(dataset.groupby('class').size())

models = [
    ('LR', LogisticRegression(solver='liblinear', multi_class='ovr')),
    ('LDA', LinearDiscriminantAnalysis()),
    ('KNN', KNeighborsClassifier()),
    ('CART', DecisionTreeClassifier()),
    ('NB', GaussianNB()),
    ('SVM', SVC(gamma='auto'))
]

# Split-out validation dataset
array = dataset.values
X = array[:, 0:4]
Y = array[:, 4]
validation_size = 0.20
seed = 7

X_train, X_validation, Y_train, Y_validation = model_selection.train_test_split(
    X, Y, test_size=validation_size, random_state=seed
)

# evaluate each model in turn
results = []
names = []
for name, model in models:
    kfold = model_selection.KFold(n_splits=10, random_state=seed)
    cv_results = model_selection.cross_val_score(model, X_train, Y_train, cv=kfold, scoring='accuracy')
    results.append(cv_results)
    names.append(name)
    msg = "%s: %f (%f)" % (name, cv_results.mean(), cv_results.std())
    print(msg)

# knn = KNeighborsClassifier()
# knn.fit(X_train, Y_train)
# predictions = knn.predict(X_validation)
# print(accuracy_score(Y_validation, predictions))
# print(confusion_matrix(Y_validation, predictions))
# print(classification_report(Y_validation, predictions))


class GnrCustomWebPage(object):
    py_requires = 'public:Public,foundation/dialogs'

    def main(self, rootBC, **kwargs):
        pane = rootBC.contentPane(margin='5px')
        pane.button('open 1', action='SET framepage_test ="/showcase/catalog/component/res/test1"; FIRE #myframe.open;')
        pane.button('open 2', action='SET framepage_test ="/showcase/catalog/component/res/test2"; FIRE #myframe.open;')

        self.iframeDialog(pane, title='test iframe', dlgId='myframe', height='300px',
                          width='400px', src='=framepage_test', datapath='test')


import os
import logging
import re
import pinecone
from slack_bolt.async_app import AsyncApp
from slack_bolt.adapter.asgi.async_handler import AsyncSlackRequestHandler
from slack_sdk.oauth.installation_store import FileInstallationStore
from slack_bolt.oauth import OAuthFlow
from slack_bolt.oauth.oauth_settings import OAuthSettings

from conversation import create_conversation

PINECONE_API_KEY = os.environ.get("PINECONE_API_KEY")
PINECONE_INDEX_NAME = os.environ.get("PINECONE_INDEX_NAME", '')
PINECONE_ENVIRONMENT = os.environ.get("PINECONE_ENVIRONMENT", '')

# SLACK_CLIENT_ID = os.environ.get("SLACK_CLIENT_ID")
# SLACK_CLIENT_SECRET = os.environ.get("SLACK_CLIENT_SECRET")
SLACK_INSTALLATION_BASE = os.environ.get("SLACK_INSTALLATION_BASE", '/data')

# if not SLACK_CLIENT_ID:
#     raise ValueError("SLACK_CLIENT_ID environment variable not set.")
# if not SLACK_CLIENT_SECRET:
#     raise ValueError("SLACK_CLIENT_SECRET environment variable not set.")

# OAuth redirect: slack/oauth_redirect
# Ref: https://slack.dev/bolt-python/concepts#authenticating-oauth
app = AsyncApp(
    # oauth_flow=OAuthFlow(
    #     settings=OAuthSettings(
    #         scopes=["channels:history", "users:read", "app_mentions:read", "chat:write"],
    #         installation_store=FileInstallationStore(base_dir=SLACK_INSTALLATION_BASE),  # A simple File based installation store
    #     )
    # )
)

@app.event("app_mention")
async def handle_mention(body, say, logger):
    logger.info(body)

    evt = body.get('event', {})

    channel_id = evt.get('channel')
    thread_ts = evt.get('thread_ts') if 'thread_ts' in evt else evt.get('ts')

    replies = await get_replies(channel_id, thread_ts)
    text = replies[-1].get('text')
    replies = replies[:-1]  # the last one is the one we just received
    resp = await get_ai_response(replies=replies, question=text)

    await say(resp, thread_ts=thread_ts)

async def convert_ids_to_usernames(text):
    user_ids = re.findall('<@(U.*?)>', text)
    for user_id in user_ids:
        username = await get_user_name(user_id)
        text = text.replace(f'<@{user_id}>', f'@{username}')
    return text

async def get_replies(channel_id, thread_ts):
    conversation_replies = await app.client.conversations_replies(channel=channel_id, ts=thread_ts)
    replies = conversation_replies.get('messages', [])
    replies = [
        {
            'user': await get_user_name(r.get('user')),
            'text': await convert_ids_to_usernames(r.get('text')),
        } for r in replies]
    return replies

async def get_user_name(user_id):
    user_info = await app.client.users_info(user=user_id)
    user_name = user_info.get('user', {}).get('name')
    return user_name

async def get_ai_response(replies, question):
    pinecone.init(
        api_key=PINECONE_API_KEY,
        environment=PINECONE_ENVIRONMENT,
    )
    system_prompt_str = None
    # FIXME: how to pass the path?
    with open('system_prompt.txt', 'r', encoding='utf-8') as f:
        system_prompt_str = f.read()

    chat_history = []
    for reply in replies:
        chat_history.append((reply['user'], reply['text']))

    conversation = create_conversation(
        system_prompt_str=system_prompt_str,
        chat_history=chat_history
        )
    return conversation(question)

api = AsyncSlackRequestHandler(app)

def start_server(port=9000):
    app.start(port=port, path='/slack')

if __name__ == "__main__":
    logging.basicConfig(level=logging.INFO)
    start_server()


import cv2
import numpy as np
import math

def compute_hsv_white_yellow_binary(img):
    """
    Returns a binary thresholded image produced retaining only white and yellow elements on the picture
    The provided image should be in RGB format
    """
    rgb_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    hsv_img = cv2.cvtColor(rgb_img, cv2.COLOR_RGB2HSV)

    # Compute a binary thresholded image where yellow is isolated from HLS components
    img_hls_yellow_bin = np.zeros_like(hsv_img[:, :, 0])
    img_hls_yellow_bin[((hsv_img[:, :, 0] >= 40 / 360 * 255) & (hsv_img[:, :, 0] <= 50 / 360 * 255))
                       & ((hsv_img[:, :, 1] >= 80 / 100 * 255) & (hsv_img[:, :, 1] <= 255))
                       & ((hsv_img[:, :, 2] >= 90 / 100 * 255) & (hsv_img[:, :, 2] <= 255))
                       ] = 1

    # Compute a binary thresholded image where white is isolated from HLS components
    img_hls_white_bin = np.zeros_like(hsv_img[:, :, 0])
    img_hls_white_bin[((hsv_img[:, :, 0] >= 0) & (hsv_img[:, :, 0] <= 255))
                      & ((hsv_img[:, :, 1] >= 0) & (hsv_img[:, :, 1] <= 25 / 100 * 255))
                      & ((hsv_img[:, :, 2] >= 90 / 100 * 255) & (hsv_img[:, :, 2] <= 255))
                      ] = 1

    # Now combine both
    img_hls_white_yellow_bin = np.zeros_like(hsv_img[:, :, 0])
    img_hls_white_yellow_bin[(img_hls_yellow_bin == 1) | (img_hls_white_bin == 1)] = 1
    img_hls_white_yellow_bin = cv2.normalize(src=img_hls_white_yellow_bin, dst=None, alpha=0, beta=255,
                                             norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8UC1)
    return img_hls_white_yellow_bin

def compute_hsv_white_binary(img):
    """
    Returns a binary thresholded image produced retaining only white and yellow elements on the picture
    The provided image should be in RGB format
    """
    rgb_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    hsv_img = cv2.cvtColor(rgb_img, cv2.COLOR_RGB2HSV)

    # Compute a binary thresholded image where white is isolated from HLS components
    img_hls_white_bin = np.zeros_like(hsv_img[:, :, 0])
    img_hls_white_bin[((hsv_img[:, :, 0] >= 0) & (hsv_img[:, :, 0] <= 255))
                      & ((hsv_img[:, :, 1] >= 0) & (hsv_img[:, :, 1] <= 10 / 100 * 255))
                      & ((hsv_img[:, :, 2] >= 50 / 100 * 255) & (hsv_img[:, :, 2] <= 255))
                      ] = 1

    img_hls_white_bin = cv2.normalize(src=img_hls_white_bin, dst=None, alpha=0, beta=255,
                                      norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8UC1)
    return img_hls_white_bin

def apply_mask(img, partition):
    h, w = img.shape[:2]
    mask = np.zeros(img.shape)
    mask[int(h * partition):, :] = 1
    masked = mask * img / 255
    masked = cv2.normalize(src=masked, dst=None, alpha=0, beta=255, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8UC1)
    return masked

def line_groups(lines):
    lines2 = []
    for line in lines:
        for rho, theta in line:
            lines2.append(tuple((rho, theta)))
    lines2.sort()

    sorted_lines = [[]]
    group = 0
    hor_deg_thresh = 20
    ver_deg_thresh = 20
    group_thresh = 100

    can_continue = False
    lines = lines2
    i = 0
    while not can_continue:
        if (np.deg2rad(90 + hor_deg_thresh) < lines[i][1] < np.deg2rad(180 + ver_deg_thresh)) or (np.deg2rad(ver_deg_thresh) < lines[i][1] < np.deg2rad(90 - hor_deg_thresh)):
            sorted_lines[group].append([lines[i]])
            can_continue = True
            prev_line = lines[i]
        i += 1
        if i == len(lines):
            return sorted_lines

    for line in lines[i+1:]:
        if (np.deg2rad(90 + hor_deg_thresh) < line[1] < np.deg2rad(180 + ver_deg_thresh)) or (
                np.deg2rad(ver_deg_thresh) < line[1] < np.deg2rad(90 - hor_deg_thresh)):
            if np.abs(line[0] - prev_line[0]) < group_thresh:
                sorted_lines[group].append([line])
            else:
                group += 1
                sorted_lines.append([])
                sorted_lines[group].append([line])
            prev_line = line

    # if lines[0, 0, 1] > np.deg2rad(90 + deg_thresh) or lines[0, 0, 1] < np.deg2rad(90 - deg_thresh):
    #     sorted_lines[group].append([lines[0, 0]])
    #
    # if lines.shape[0] > 1:
    #     for i in range(1, lines.shape[0]):
    #         if lines[i, 0, 1] > np.deg2rad(90 + deg_thresh) or lines[i, 0, 1] < np.deg2rad(90 - deg_thresh):
    #             if np.abs(lines[i, 0, 0] - lines[i - 1, 0, 0]) < group_thresh:
    #                 sorted_lines[group].append([lines[i, 0]])
    #             else:
    #                 group += 1
    #                 sorted_lines.append([])
    #                 sorted_lines[group].append([lines[i, 0]])
    return sorted_lines

def best_two_avg_lines(avg_lines):
    if len(avg_lines[0]) < 2:
        best_two = [[300,0], [300,0]]
    else:
        min_diff1 = 100
        min_diff2 = 200
        best_line1 = avg_lines[0][0]
        best_line2 = avg_lines[0][0]
        for line in avg_lines[0]:
            theta_diff_from_vertical = min(line[1], np.pi - line[1])
            if theta_diff_from_vertical < min_diff1:
                min_diff1 = theta_diff_from_vertical
                best_line1 = line
            elif theta_diff_from_vertical < min_diff2:
                min_diff2 = theta_diff_from_vertical
                best_line2 = line
        best_two = [best_line1, best_line2]
        best_two.sort(key=lambda x:x[0])
    return best_two

def avg_of_line_groups(lines):
    sorted_lines = line_groups(lines)
    avg_lines = [[]]
    for line_group in sorted_lines:
        if len(line_group) != 0:
            rho_sum = 0
            theta_sin_sum = 0
            theta_cos_sum = 0
            theta_sum = 0
            for line in line_group:
                rho_sum += line[0][0]
                theta_sin_sum += np.sin(line[0][1])
                theta_cos_sum += np.cos(line[0][1])
                theta_sum += line[0][1]
            rho_avg = rho_sum / len(line_group)
            n = len(line_group)
            # rho_avg = line_group[n // 2][0]
            line_group.sort(key=lambda x:x[0][1])
            theta_median = line_group[n // 2][0][1]
            # theta_avg = math.atan2((1 / n) * theta_sin_sum, (1 / n) * theta_cos_sum)
            # theta_avg = theta_sum / len(line_group)
            avg_lines[0].append([rho_avg, theta_median])

    return avg_lines, best_two_avg_lines(avg_lines)

def draw_lines(img, lines, color=(0,0,255)):
    img_lines = img.copy()
    if lines != [[]]:
        points = []
        for line in lines:
            a = np.cos(line[1])
            b = np.sin(line[1])
            x0 = a * line[0]
            y0 = b * line[0]
            x1 = int(x0 + 4000 * (-b))
            y1 = int(y0 + 4000 * (a))
            x2 = int(x0 - 4000 * (-b))
            y2 = int(y0 - 4000 * (a))
            m = (y2 - y1) / (x2 - x1 + 0.001)
            b = y1 - (m * x1)
            points.append((m, b))
            cv2.line(img_lines, (x1, y1), (x2, y2), color, 2)
    return img_lines

def draw_lane_rect(img, best_two):
    img_rect = img.copy()
    points = []
    for line in best_two:
        a = np.cos(line[1])
        b = np.sin(line[1])
        x0 = a * line[0]
        y0 = b * line[0]
        x1 = int(x0 + 1000 * (-b))
        y1 = int(y0 + 1000 * (a))
        x2 = int(x0 - 4000 * (-b))
        y2 = int(y0 - 4000 * (a))
        m = (y2 - y1) / (x2 - x1 + 0.000000001)
        b = y1 - (m * x1)
        points.append((m, b))
        # cv2.line(img_rect, (x1, y1), (x2, y2), (0, 0, 255), 2)

    p1 = [int((img.shape[0] - points[0][1]) // points[0][0]), int(img.shape[0])]
    p2 = [int((img.shape[0] - points[1][1]) // points[1][0]), int(img.shape[0])]
    xc = int((points[1][1] - points[0][1]) // (points[0][0] - points[1][0] +0.000001))
    yc = int(points[0][0] * xc + points[0][1])
    p3 = [xc, yc]
    pts = np.array([p1, p2, p3])
    road_mask = img_rect.copy()
    cv2.drawContours(road_mask, [pts], 0, (0, 255, 0, 100), -1)
    road_mask[0:yc+int(img.shape[0]*0.05), :] = img[0:yc+int(img.shape[0]*0.05), :]
    img_rect = img_rect*0.8 + road_mask*0.2
    img_rect = cv2.normalize(src=img_rect, dst=None, alpha=0, beta=255, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8UC1)
    return img_rect

def LaneDetection(img, prev_best_two=None):
    # img = cv2.GaussianBlur(img, (5,5), -1)
    hsv = compute_hsv_white_binary(img)
    edges = cv2.Canny(hsv, 50, 200, apertureSize=3)
    mask = cv2.imread('img/mask4.png',0)
    mask = cv2.resize(mask, (img.shape[1], img.shape[0]))
    edges = (mask / 255) * edges
    edges = cv2.normalize(src=edges, dst=None, alpha=0, beta=255, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8UC1)
    lines = cv2.HoughLines(edges, 1, np.pi / 180, 50)
    if lines is None:
        return img, None
    avg_lines, best_two = avg_of_line_groups(lines)
    prob = 0.5
    if prev_best_two is not None:
        diff_best_two = 0
        for i in range(2):
            diff_best_two += np.abs(prev_best_two[i][0] - best_two[i][0])
        if diff_best_two > 100:
            best_two = prev_best_two
        else:
            for i in range(2):
                best_two[i] = [best_two[i][0] * (1-prob) + prev_best_two[i][0] * prob, best_two[i][1] * (1-prob) + prev_best_two[i][1] * prob]
    img_lines = draw_lines(img, best_two)
    img_rect = draw_lane_rect(img, best_two)
    # mask = cv2.imread('img/mask4.png')
    # mask = cv2.resize(mask, (img.shape[1], img.shape[0]))
    # img_rect = img_rect * mask
    return img_rect, best_two

# def create_mask(img):
#

if __name__ == '__main__':
    cap = cv2.VideoCapture('vids/test4.mp4')
    # out = cv2.VideoWriter('project.mp4', cv2.VideoWriter_fourcc(*'MP42'), 15, (1280, 720))

    best_two = None
    while (cap.isOpened()):
        ret, frame = cap.read()
        if ret is True:
            if best_two is None:
                frame, best_two = LaneDetection(frame)
            else:
                frame, best_two = LaneDetection(frame, best_two)

            # mask = cv2.imread('img/mask2.png')
            # mask = cv2.resize(mask, (frame.shape[1], frame.shape[0]))
            # frame = (mask / 255) * frame
            # frame = cv2.normalize(src=frame, dst=None, alpha=0, beta=255, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8UC1)

            cv2.imshow('frame', frame)
            # out.write(frame)

            if cv2.waitKey(1) & 0xFF == ord('q'):
                break
        else:
            cap.release()
            # out.release()

    cv2.destroyAllWindows()


class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        low = 10001
        profit = 0
        for i in prices:
            if i < low:
                low = i
            elif i - low > profit:
                profit = i - low
        return profit


import pytest

from flaky import (
    flaky,
)

from web3._utils.module_testing import (  # noqa: F401
    EthModuleTest,
    ParityModuleTest,
    ParityPersonalModuleTest,
    ParitySetModuleTest,
    ParityTraceModuleTest,
    Web3ModuleTest,
)
from web3._utils.module_testing.eth_module import (
    UNKNOWN_ADDRESS,
)

# some tests appear flaky with Parity v1.10.x
MAX_FLAKY_RUNS = 3

class ParityWeb3ModuleTest(Web3ModuleTest):
    def _check_web3_clientVersion(self, client_version):
        assert client_version.startswith('Parity-Ethereum/')

class ParityEthModuleTest(EthModuleTest):
    @pytest.mark.xfail(reason='Parity returns a gas value even when a function will revert')
    def test_eth_estimate_gas_revert_with_msg(self, web3, revert_contract, unlocked_account):
        super().test_eth_estimate_gas_revert_with_msg(web3, revert_contract, unlocked_account)

    def test_eth_estimate_gas_revert_without_msg(
        self,
        web3,
        revert_contract,
        unlocked_account,
    ) -> None:
        with pytest.raises(ValueError, match="The execution failed due to an exception."):
            txn_params = revert_contract._prepare_transaction(
                fn_name="revertWithoutMessage",
                transaction={
                    "from": unlocked_account,
                    "to": revert_contract.address,
                },
            )
            web3.eth.estimate_gas(txn_params)

    @pytest.mark.xfail(reason='Parity dropped "pending" option in 1.11.1')
    def test_eth_getBlockByNumber_pending(self, web3):
        super().test_eth_getBlockByNumber_pending(web3)

    def test_eth_uninstall_filter(self, web3):
        pytest.xfail('eth_uninstallFilter calls to parity always return true')
        super().test_eth_uninstall_filter(web3)

    def test_eth_uninstallFilter_deprecated(self, web3):
        pytest.xfail('eth_uninstallFilter calls to parity always return true')
        super().test_eth_uninstallFilter_deprecated(web3)

    @pytest.mark.xfail(reason='Parity is not setup to auto mine')
    def test_eth_replace_transaction_already_mined(self, web3, unlocked_account):
        super().test_eth_replace_transaction_already_mined(web3, unlocked_account)

    @flaky(max_runs=MAX_FLAKY_RUNS)
    def test_eth_get_transaction_receipt_unmined(self, web3, unlocked_account):
        # Parity diverges from json-rpc spec and retrieves pending block
        # transactions with get_transaction_receipt.
        txn_hash = web3.eth.send_transaction({
            'from': unlocked_account,
            'to': unlocked_account,
            'value': 1,
            'gas': 21000,
            'gasPrice': web3.eth.gas_price,
        })
        receipt = web3.eth.get_transaction_receipt(txn_hash)
        assert receipt is not None
        assert receipt['blockHash'] is None

    @pytest.mark.xfail(reason="Parity matches None to asbent values")
    def test_eth_get_logs_with_logs_none_topic_args(self, web3):
        super().test_eth_get_logs_with_logs_none_topic_args(web3)

    @flaky(max_runs=MAX_FLAKY_RUNS)
    def test_eth_call_old_contract_state(self, web3, math_contract, unlocked_account):
        start_block = web3.eth.get_block('latest')
        block_num = start_block.number
        block_hash = start_block.hash

        math_contract.functions.increment().transact({'from': unlocked_account})

        # This isn't an incredibly convincing test since we can't mine, and
        # the default resolved block is latest, So if block_identifier was ignored
        # we would get the same result. For now, we mostly depend on core tests.
        # Ideas to improve this test:
        #  - Enable on-demand mining in more clients
        #  - Increment the math contract in all of the fixtures, and check the value in an old block

        block_hash_call_result = math_contract.functions.counter().call(block_identifier=block_hash)
        block_num_call_result = math_contract.functions.counter().call(block_identifier=block_num)
        latest_call_result = math_contract.functions.counter().call(block_identifier='latest')
        default_call_result = math_contract.functions.counter().call()

        assert block_hash_call_result == 0
        assert block_num_call_result == 0
        assert latest_call_result == 0
        assert default_call_result == 0

        # retrieve this right before using - Parity tests might hit a race otherwise
        pending_call_result = math_contract.functions.counter().call(block_identifier='pending')
        # should be '1' on first flaky run, '2' on second, or '3' on third
        if pending_call_result not in range(1, MAX_FLAKY_RUNS + 1):
            raise AssertionError("pending call result was %d!" % pending_call_result)

    def test_eth_get_logs_without_logs(self, web3, block_with_txn_with_log):
        # Test with block range

        filter_params = {
            "fromBlock": 0,
            "toBlock": block_with_txn_with_log['number'] - 1,
        }
        result = web3.eth.get_logs(filter_params)
        assert len(result) == 0

        # the range is wrong, parity returns error message
        filter_params = {
            "fromBlock": block_with_txn_with_log['number'],
            "toBlock": block_with_txn_with_log['number'] - 1,
        }
        with pytest.raises(ValueError):
            web3.eth.get_logs(filter_params)

        # Test with `address`

        # filter with other address
        filter_params = {
            "fromBlock": 0,
            "address": UNKNOWN_ADDRESS,
        }
        result = web3.eth.get_logs(filter_params)
        assert len(result) == 0

        # Test with multiple `address`

        # filter with other address
        filter_params = {
            "fromBlock": 0,
            "address": [UNKNOWN_ADDRESS, UNKNOWN_ADDRESS],
        }
        result = web3.eth.get_logs(filter_params)
        assert len(result) == 0

    @pytest.mark.xfail(reason='eth_signTypedData has not been released in Parity')
    def test_eth_sign_typed_data(self, web3, unlocked_account_dual_type):
        super().test_eth_sign_typed_data(web3, unlocked_account_dual_type)

    @pytest.mark.xfail(reason='eth_signTypedData has not been released in Parity')
    def test_invalid_eth_sign_typed_data(self, web3, unlocked_account_dual_type):
        super().test_invalid_eth_sign_typed_data(web3, unlocked_account_dual_type)

class ParityTraceModuleTest(ParityTraceModuleTest):
    @pytest.mark.xfail(reason="TODO: tracing not working on v2.5.13")
    def test_trace_block(self, web3):
        super().test_trace_block(web3)

    @pytest.mark.xfail(reason="TODO: tracing not working on v2.5.13")
    def test_trace_transaction(self, web3):
        super().test_trace_transaction(web3)

    @pytest.mark.xfail(reason="TODO: tracing not working on v2.5.13")
    def test_trace_filter(self, web3):
        super().test_trace_filter(web3)

class ParitySetModuleTest(ParitySetModuleTest):
    pass

class ParityModuleTest(ParityModuleTest):
    pass


class BSTIterator(object):
    def __init__(self, root):
        """
        Beats 95.12%
        """
        self.stack = []
        temp = root

        while temp:
            self.stack.append(temp)
            temp = temp.left

    def hasNext(self):
        """
        :rtype: bool
        """
        return self.stack != []

    def next(self):
        """
        :rtype: int
        """
        if not self.hasNext():
            return

        top = self.stack.pop()

        temp = top.right
        while temp:
            self.stack.append(temp)
            temp = temp.left

        return top.val

# Your BSTIterator will be called like this:
# i, v = BSTIterator(root), []
# while i.hasNext(): v.append(i.next())


import random
import matplotlib.pyplot as plt

import os

def clear_screen():
    os.system('cls' if os.name == 'nt' else 'clear')

class TSP():
    number_of_cities = None
    distances = None
    population_size = None
    population = None
    population_fitness = None
    child_population = None
    generations = None
    iterations = None

    def __init__(self) -> None:
        """
        This constructor, initializes all the fields required for this solution.
        """
        try:
            self.number_of_cities = int(input("[I/O] Enter the total number of cities: ")) #accepts the user input to total number of cities.
            self.status_update("[PROCESS] Initializing random distances to each cities!")
            self.distances = self.get_distance_matrix(self.number_of_cities) #generate random distances between cities.
            self.population_size = int(input("[I/O] Please enter population size: "))
            self.generations = list() #the output of each generation must be stored within this. e
            self.iterations = int(input("[I/O] Please enter the number of iterations you want: "))
        except Exception as e:
            self.status_update("[ERR] The following error occured while trying to intialize module params: "+str(e))

    def status_update(self, msg) -> None:
        """
        This method, accepts a string from other methods to give a update of current process to user.
        """
        print(msg)

    def get_distance_matrix(self, n) -> list:
        """
        This method generates a distance matrix for n cities.
        """
        try:
            matrix = list()
            self.status_update("[PROCESS] Initializing distances between %d cities"%(n))
            for i in range(n):
                row = list()
                for j in range(n):
                    if i == j :
                        row.append(0) #distance from a city to itself is zero!
                        continue

                    row.append(round(random.uniform(1, n), 4)) #append the distance between two cities.
                matrix.append(row)

            for i in range(len(matrix)):
                for j in range(len(matrix[i])):
                    matrix[j][i] = matrix[i][j]

            self.status_update("[PROCESS] Successfully intialized distances between %d cities."%(n))
            return matrix
        except Exception as e:
            self.status_update("[ERR] The following error occured while trying to create a distance matrix"+str(e))

    def get_population_string(self) -> list:
        """
        This method creates a instance for the population and returns it to the calling method.
        """
        try:
            string = list()

            while len(string) != self.number_of_cities:
                value = random.randint(0, (self.number_of_cities - 1))
                if value not in string:
                    string.append(value)
                else:
                    continue

            return string
        except Exception as e:
            pass

    def create_population(self, n) -> [[]]:
        """
        This method, accepts size of total population to be created,
        then creates each instance of population using "get_population_string" and returns the entire population created.
        """
        try:
            pop = list()
            self.status_update("[PROCESS] Creating population with size %d"%(n))
            for i in range(n):
                new_sample = self.get_population_string()
                pop.append(new_sample)
                print(f"\r[PROCESS] Total population created so far:  {round(((i/n)*100),2)}% DONE", end="")

            self.status_update("[PROCESS] A new population with size %d has been created successfully!"%(n))
            return pop
        except Exception as e:
            self.status_update("[ERR] The following error occured while trying to create population: "+str(e))

    def compute_distance_of_sample(self, instance:list) -> float:
        """
        This accepts a instance from population and then computes the total distance traveled.
        """
        try:
            distance = 0
            for i in range(len(instance) -1):
                j = i + 1
                distance = distance + self.distances[instance[i]][instance[j]]

            distance = distance + self.distances[instance[-1]][instance[0]]

            return round(distance,4)

        except Exception as e:
            self.status_update("[ERR] The following error occured while compute the distance for each sample: "+str(e))

    def create_population_distances(self) -> dict:
        """
        Computes distances for each sample within entire population:
        """
        try:
            self.status_update("[PROCESS] Trying to compute distances using population samples!")
            sample_distance = dict()
            join_and_convert = lambda lst: ','.join([str(i) for i in lst])
            for sample in self.population:
                distance = self.compute_distance_of_sample(sample)
                sample_distance[join_and_convert(sample)] = distance

            return sample_distance

        except Exception as e:
            self.status_update("[ERR] The following error occured while trying to compute distances for population samples: "+str(e))

    def fitness(self, population) -> dict:
        """
        This method will act as a fitness function for us to select, population instances or routes with shorter distances.
        We have a simpler approach, we shall normalize the fitness level of each of the population sample and then return their fitness levels.
        Here we have to compute inverse fitness because shorter paths must have larger fitness values.
        """
        try:
            self.status_update("[PROCESS] Computing fitness values for each of the instance/routes within the population.")
            total_distance = 0
            population_fitnesss = dict()
            for route, distance in population.items():
                total_distance = total_distance + distance

            self.status_update("[PROCESS] Normalizing values for each of the population instance/routes.")

            for route, distance in population.items():
                population_fitnesss[route] = 1 - (distance/total_distance) #gives us invert fitness values!

            self.status_update("[INFO] Fitness values have been created successfully for population samples!")
            return population_fitnesss

        except Exception as e:
            self.status_update("[ERR] The following error occured while trying to compute fitness of each function: "+str(e))

    def roulette_wheel(self) -> dict():
        """
        Roulette wheel generates a random point between 0.0, 1.0 and then selects those routes/population instances with fitness value greater than the generated value.
        """
        try:
            self.status_update("[PROCESS] Spinning roulette wheel on population instances.")
            self.status_update("[PROCESS] Determining random fitness cutoff for population.")

            cut_off = random.uniform(0.000, max(self.population_fitness.values()))
            selected_population = dict()

            for route, fitness_level in self.population_fitness.items():
                if fitness_level>=cut_off:
                    selected_population[route] = fitness_level
            self.status_update("[INFO] Population has been narrowed down to fit population.")
            return selected_population
        except Exception as e:
            self.status_update("[ERR] The following error occured while trying to spin roulette wheel over routes: "+str(e))

    def crossover(self, parent_one, parent_two) -> str:
        """
        The crossover method, accepts two parent strings from the population set,
        Then creates a new child instance(route) by combining the information from two parents.
        This resulting child is then returned as the next gen, instance of the population.
        """
        try:
            split_and_convert = lambda lst: [int(s) for s in lst.split(',')]
            parent_one = split_and_convert(parent_one)
            parent_two = split_and_convert(parent_two)

            if len(parent_one) != len(parent_two): #inorder to perform crossover we must have parents of same lenght
                raise Exception("Parents are of not same size!")

            random_index = random.randint(0, (len(parent_one)-1))

            child = parent_one[:random_index] + parent_two[random_index:]
            return child
        except Exception as e:
            self.status_update("[ERR] The following error occured while trying to perform crossover for two routes/parents: "+str(e))

    def perform_crossover(self, population_fitness) -> dict:
        """
        The perform_crossover accepts a population with their fitness values defined -> route: fitness.
        The isntances are all of resulting selected instances from roulette wheel selection.
        Upon these we are to perform the crossover by randomly selecting two samples.
        """
        try:
            children = dict()
            self.status_update("[PROCESS] Applying crossover to selected fit population.")

            parents = list(population_fitness.keys())
            attempts = random.randint(0, (len(parents)-1))
            for i in range(attempts):
                j = random.randint(0, (len(parents)-1))
                if i == j:
                    continue

                child = self.crossover(parent_one= parents[i], parent_two= parents[j])
                distance = self.compute_distance_of_sample(child)
                join_and_convert = lambda lst: ','.join([str(i) for i in lst])
                children[join_and_convert(child)] = distance

            self.status_update("[PROCESS] Created a offspring population of size: "+str(attempts))
            return children
        except Exception as e:
            self.status_update("[ERR] The following error occured while trying to apply crossover over selected population: "+str(e))

    def mutate(self, child:str, mutation_rate = 2) -> list:
        """
        The mutate method, is used mutuate a particular instance of a population.
        By default the mutation rate is 2% to maintain diversity and keep the frequency in check.
        """
        try:
            percentage = random.randint(1,100)

            split_and_convert = lambda lst: [int(s) for s in lst.split(',')]
            child = split_and_convert(child)
            if percentage>mutation_rate:
                return None
            else:
                i = random.randint(0, (len(child)-1))
                j = random.randint(0, (len(child)-1))

                temp = child[j]
                child[j] = child[i]
                child[i] = temp

            return child
        except Exception as e:
            self.status_update("[ERR] The following error occured while trying to mutate a sample: "+str(e))

    def apply_mutation(self, population: dict) -> dict:
        """
        This method applies mutate method to the child population to randomly mutate certain routes.
        """
        try:
            mutated_samples = 0
            mutated_population = dict()
            split_and_convert = lambda lst: [int(s) for s in lst.split(',')]
            join_and_convert = lambda lst: ','.join([str(i) for i in lst])
            self.status_update("[PROCESS] Trying to apply mutation over child population!")
            self.status_update("[PROCESS] The mutation rate is 2%")
            for route, distance in population.items():
                result  = self.mutate(route) #try and mutate the sample.
                if result is None:  #check if there is change in route from mutation
                    continue #no mutation occured we do nothing.
                route =  split_and_convert(route)

                mutated_samples= mutated_samples + 1 #count mutated values
                new_distance = self.compute_distance_of_sample(result) #compute distance for new route.
                mutated_population[join_and_convert(result)] = new_distance #save the distance for new mutated route.
            self.status_update("[PROCESS] Out of %d from child population a total of %d have undergone mutation."%(len(population), mutated_samples))

            return mutated_population
        except Exception as e:
            self.status_update("[ERR] The following error occured while trying to mutate the population: "+str(e))

    def get_population_results(self, population:dict, population_fitness: dict) -> list:
        """
        This method accepts the child population and then computes the following statistics within the entire population:
        1. best route.
        2. best route fitness within it's population.
        3. average fitness of the population.
        4. average distance of the population.
        """
        try:
            self.status_update("[PROCESS] Computing statistics for latest generation please wait.")
            shortest_path = str()
            shortest_distance = max(list(population.values()))
            total_fitness = 0.0
            average_fitness = 0.0
            average_distance = 0.0
            total_distance = 0.0
            n = len(population)
            self.status_update("[PROCESS] Computing best route.")
            self.status_update("[PROCESS] Computing best distance.")
            self.status_update("[PROCESS] Computing best Fitness.")
            for route, distance in population.items():
                total_distance = total_distance + distance
                if shortest_distance>distance:
                    shortest_path = route
                    shortest_distance = distance

            for route, fitness in population_fitness.items():
                total_fitness = total_fitness + fitness

            best_fitness = population_fitness[route]
            average_distance = total_distance/n
            average_fitness = total_fitness/n

            stats = {
                "best_path": shortest_path,
                "best_distance": shortest_distance,
                "best_fitness": best_fitness,
                "average_distance": average_distance,
                "average_fitness": average_fitness
            }

            self.status_update("[PROCESS] Stats for the latest generation are now ready.")
            return stats
        except Exception as e:
            self.status_update("[ERR] The following error occured while trying to compute statistics of the population: "+str(e))

    def plot_best_path_of_all_generations(self, generations):
        """
        Plots the best path across all provided generations.

        :param generations: List of dictionaries containing stats about each generation.
        """
        # Extract the path with the shortest distance from all generations
        best_gen = min(generations, key=lambda x: x["best_distance"])
        best_path = list(map(int, best_gen['best_path'].split(',')))

        print("Here's the best path: ", best_path)
        # Extract x and y coordinates from best path for plotting
        x_coords = [i for i, _ in enumerate(best_path)]
        y_coords = best_path

        # Plotting
        plt.figure(figsize=(10, 6))
        plt.plot(x_coords, y_coords, '-o', label=f'Best Path: Distance = {best_gen["best_distance"]:.2f}')
        plt.scatter(x_coords, y_coords, c='red')  # Highlight each city as a point

        plt.title('Best Path Across All Generations')
        plt.xlabel('City Index')
        plt.ylabel('City Order in Path')
        plt.legend()
        plt.grid(True)
        plt.show()

    def plot_best_path_evolution(self, generations):
        """
        Plots the evolution of the best path over the provided generations.

        :param generations: List of dictionaries containing stats about each generation.
        """
        # Extract the best paths and convert them to lists of integers
        best_paths = [list(map(int, gen['best_path'].split(','))) for gen in generations]

        # Extract x and y coordinates from best path for plotting
        x_coords = [i for i, _ in enumerate(best_paths[0])]
        y_coords = best_paths

        # Plotting
        plt.figure(figsize=(10, 6))

        for generation, y in enumerate(y_coords):
            plt.plot(x_coords, y, label=f'Generation {generation + 1}')

        plt.title('Best Path Across Generations')
        plt.xlabel('City Index')
        plt.ylabel('City Order in Path')
        plt.legend()
        plt.show()

# Sample usage
# generations = [ { ... }, { ... }, ... ]  # your list of dictionaries
# plot_best_path_evolution(generations)
    def verify_stats(self, stats) -> bool:
        """
        This method varifies if the results of the current generation are valid or not.
        """
        try:
            if stats is None:
                return False
            else:
                if stats["best_path"] == "":
                    return False
                elif stats["best_distance"] == 0:
                    return False
                elif stats["best_fitness"] == 0:
                    return False
                elif stats["average_fitness"] == 0.0:
                    return False
                elif stats["average_distance"] == 0.0:
                    return False
            return True
        except Exception as e:
            self.status_update("[ERR] The following error occured while trying to verify results for a generation: "+str(e))

    import matplotlib.pyplot as plt

    def plot_results(self, generations):
        # Extracting values
        gen_numbers = list(range(1, len(generations) + 1))
        best_distances = [gen['best_distance'] for gen in generations]
        average_distances = [gen['average_distance'] for gen in generations]

        plt.figure(figsize=(14, 6))

        # 1. Best distances over generations
        plt.subplot(2, 2, 1)
        plt.plot(gen_numbers, best_distances, marker='o', linestyle='-', color='b')
        plt.title('Best Distance over Generations')
        plt.xlabel('Generation')
        plt.ylabel('Best Distance')
        plt.grid(True)

        # 2. Average distances over generations
        plt.subplot(2, 2, 2)
        plt.plot(gen_numbers, average_distances, marker='o', linestyle='-', color='r')
        plt.title('Average Distance over Generations')
        plt.xlabel('Generation')
        plt.ylabel('Average Distance')
        plt.grid(True)

        # 3. Histogram of average distances
        plt.subplot(2, 2, 3)
        plt.hist(average_distances, bins=10, color='g', edgecolor='black')
        plt.title('Histogram of Average Distances')
        plt.xlabel('Distance')
        plt.ylabel('Count')

        # 4. Histogram of best distances
        plt.subplot(2, 2, 4)
        plt.hist(best_distances, bins=10, color='c', edgecolor='black')
        plt.title('Histogram of Best Distances')
        plt.xlabel('Distance')
        plt.ylabel('Count')

        plt.tight_layout()
        plt.show()

    def run(self) -> None:
        """
        The run method acts like the driver method for this module/class, kinda like a main function within C.
        """
        try:
            i = 0
            self.population = self.create_population(self.population_size) #create population

            while i<self.iterations:

                print("-"*100)
                print("\t\t\t\t\t\t Generation %d"%(len(self.generations)+1))
                print("-"*100)
                self.population_distance = self.create_population_distances()  #detemine total distance travelled for a route.
                self.population_fitness = self.fitness(self.population_distance) #call the fitness function on population, by normalizing the fitness for each of the population instance.
                self.population_fitness = self.roulette_wheel() #performs selection from fitness generated, and then selects fit instances from samples.
                if len(self.population_fitness) == 0:
                    self.status_update("[BREAK] Terminating abruptly because population size is too small!")
                    break
                self.child_population = self.perform_crossover(self.population_fitness) #performs crossover for fit parents in an attempt to create new children that are better.
                if len(self.child_population) == 0:
                    self.status_update("[BREAK] Terminating abruptly because population size is too small!")
                    break
                self.child_population.update(self.apply_mutation(self.child_population)) #apply mutation over this new population.
                self.child_fitness = self.fitness(self.child_population)
                stats = self.get_population_results(self.child_population, self.child_fitness)

                if self.verify_stats(stats=stats):
                    self.generations.append(stats)
                    i = i + 1
                else:
                    i=i-1 #recompute the results again.
                self.population_distance = self.child_population
                self.status_update("[INFO] Current child population shall become ordinary population for next generation.\n\n")
                clear_screen()

            self.plot_best_path_evolution(self.generations)
            self.plot_results(self.generations)
            self.plot_best_path_of_all_generations(self.generations)
        except Exception as e:
            self.status_update("[ERR] The following error occured while trying to run the module: "+str(e))

obj = TSP()
obj.run()


from django import forms
from django.forms.widgets import TextInput, EmailInput
from django.utils.translation import ugettext_lazy as _

from C4CApplication.models.branch import Branch

class CreateBranchForm(forms.Form):
    name = forms.CharField(
        widget=TextInput(
            attrs={'autofocus':'true', 'placeholder':_("branch name")}
        ), label= _("Name of the branch ")
    )

    branch_town = forms.CharField(
        widget=TextInput(
            attrs={'placeholder':_('town(s) of the branch')}
        ), label=_("Name of the town ")
    )

    branch_off = forms.EmailField(
        widget=EmailInput(
            attrs={'placeholder':_('branch_officer@mail.com')}
        ), label=_("Branch officer mail")
    )

    street = forms.CharField(
        required=False,
        widget=TextInput(
            attrs={'placeholder':_('street')}
        ),
        label=_("Street of the branch "),
    )

    zip = forms.CharField(
        required=False,
        widget=TextInput(
            attrs={'placeholder':_('postal code')}
        ),
        label=_("Zip of the branch "),
    )

    town = forms.CharField(
        required=False,
        widget=TextInput(
            attrs={'placeholder':_('town')}
        ),
        label=_("Town of the branch "),
    )

    def clean(self):
        """
        Overrides clean from super to add an error if 'other' has been checked,
        but nothing was provided in the text field.
        """
        cleaned_data = super(CreateBranchForm, self).clean()
        b_name = cleaned_data.get("name")
        list_branch = Branch.objects.filter(name=b_name)

        if len(list_branch) !=0 :
            self.add_error("name", forms.ValidationError(_("A branch already exist with this name."), code='invalid'))

        return cleaned_data


import datetime as dt

def date_range(start_date, end_date, increment=dt.timedelta(hours=24)):
    cur_date = start_date

    while cur_date < end_date:
        yield cur_date
        cur_date += increment

def month_range(start, end):
    cur = dt.date(start.year, start.month, 1)
    while cur < end:
        yield cur
        year = cur.year + cur.month // 12
        month = (cur.month % 12) + 1
        cur = dt.date(year, month, 1)


from datetime import datetime
import pymongo

class Log:
    def __init__(self):
        pass

    def write_log(self, sessionID, log_message):
        self.file_object = open("conversationLogs/"+sessionID+".txt", 'a+')
        self.now = datetime.now()
        self.date = self.now.date()
        self.current_time = self.now.strftime("%H:%M:%S")
        self.file_object.write(
            str(self.date) + "/" + str(self.current_time) + "\t\t" + log_message + "\n")
        self.file_object.close()

    def write_mongodb(self, sessionID, log_message):
        self.client = pymongo.MongoClient("mongodb://localhost:27017/")
        self.db = self.client['chatbot_log']
        self.collection = self.db['conversation_logs']
        self.comment = {"sessionID" : sessionID,
                        "time_stamp" : datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
                        "message" : log_message
                        }
        self.collection.insert(self.comment)