# Author: Swadhin Agrawal
# E-mail: swadhin12a@gmail.com

from random import uniform
import numpy as np
# from multiprocessing import Pool
from multiprocessing.pool import ThreadPool as Pool
import matplotlib.pyplot as plt
import itertools
import random_number_generator as rng
import pandas as pd
import Object as obj
import DecisionMaking as DM
import Params as params
from math import sqrt,exp
import ParamSet as ps
from numba.typed import List
import os
from functools import partial
import copy
from numba import guvectorize, float64
from scipy.special import lambertw
import time
def parallel(func,inputs):
	batch_size = len(inputs)
	inps = [(i,) for i in inputs]
	output = []
	for i in range(0,len(inputs),batch_size):
		opt_var = []
		with Pool(20) as processor:#,ray_address="auto") as p:
			opt_var = processor.starmap(func,inps[i:i+batch_size])

		output += list(opt_var)
	return output

def option_assignment(num_opts,num_robo):
    opts = np.arange(1,num_opts+1)
    assig = np.copy(opts)
    for i in range(int(num_robo/num_opts)):
        assig = np.concatenate((assig,np.copy(opts)))
    np.random.shuffle(assig)
    return assig

def deciding_phase(p,robots,time_counter):
    options = parallel(partial(obj.Object,o_type = 'O', p = p),range(p.num_opts))

    opt_assignment =  option_assignment(num_opts = p.num_opts, num_robo = p.num_opts*p.mu_m_1)
    for r in robots[:p.num_opts*p.mu_m_1]:
        r.assigned_opt = opt_assignment[r.id]

    decision = DM.DecisionMaking(robots[:p.num_opts*p.mu_m_1],options,p,time_counter,p.memory_length,p.delta_h)

    matching = decision.compare_with_best(options)

    return decision, options

def nullifier(i,robotss,run):
    robotss[i].response = 0	# 0 = "No", 1 = "Yes"
    robotss[i].opt = -1 #self.response*self.assigned_opt
    robotss[i].best_opt = None
    robotss[i].threshold_update = 0

def param_change(i,p,robotss):
    robotss[i].p = p

def PDF(pdf_func,mu,sigma,bins):
    pdf =  pdf_func(bins,mu,sigma)                          #   PDF function values at each base values (array)
    normalized_pdf = pdf/(np.sum(pdf)*(bins[1]-bins[0]))
    ar = np.sum(pdf)*(bins[1]-bins[0])                #   Normalized PDF
    return normalized_pdf,ar

class Prediction:
    @staticmethod
    @guvectorize([(float64[:], float64[:], float64[:],float64[:])], '(n),(m),(m)->(n)')
    def gaussian(x,mu,sigma,result):
        '''
        Inputs: base, list of means, list of variance (in case of bimodal distributions)
        Output: list of Normal PDF values
        '''
        n = x.shape[0]
        m = mu.shape[0]
        for j in range(x.shape[0]):         #   For all base values we need the PDF values
            f = 0.0
            for i in range(len(mu)):        #   We calculate the PDF value due to each modal and superimpose them to
                #   get PDF of bimodal distribution (We can later also make it weighted by adding weights list for each peak)
                k = 1/(sqrt(2*np.pi)*sigma[i])
                f += k*exp(-((x[j]-mu[i])**2)/(2*(sigma[i]**2)))
            result[j] = f

    @staticmethod
    @guvectorize([(float64[:], float64[:], float64[:],float64[:])], '(n),(m),(m)->(n)')
    def uniform(x,mu,sigma,result):
        '''
        Inputs: base, list of means, list of variance (in case of bimodal distributions)
        Output: list of Uniform PDF values
        '''
        n = x.shape[0]
        m = mu.shape[0]
        for j in range(n):      #   For all base values we need the PDF values
            f = 0.0
            for i in range(m):  #   We calculate the PDF value due to each modal and superimpose them to
                #   get PDF of bimodal distribution (We can later also make it weighted by adding weights list for each peak)
                a = (mu[i] - np.sqrt(3)*sigma[i])   #   Lower bound of PDF
                b = (mu[i] + np.sqrt(3)*sigma[i])   #   Upper bound of PDF
                if x[j]<=b and x[j]>=a:
                    f += 1/abs(b-a)
            result[j] = f

    @staticmethod
    def ICPDF(area,mu,step,x,pdf):
        '''
        Inputs: Area where we need base of PDF, list of mean of PDF, resolution of PDF, base of PDF, PDF function values
        Output: The base where cummulative area under the PDF is as desired
        '''
        if len(mu)>1:                           #   If the PDF is bimodal
            dummy_area = 0.5                    #   We make a dummy area variable to start at a known point closest to the area where we need the base
            x_ = (mu[0]+mu[1])/2.0              #   The base where dummy area under the PDF is true is the mean of means
        else:
            dummy_area =0.5
            x_ = mu[0]                          #   If the PDF is unimodal, the 50% area is at the mean of PDF

        count = np.argmin(np.abs(x-x_))         #   We find the index of element in our base list closest to the known base point for dummy area

        while abs(dummy_area-area)>0.001:       #   While the distance between dummy area and the desired area is not small enough, we keep searching the point
            if dummy_area>area:                 #   If desired area is smaller than the dummy
                count -= 1                      #   We decrease the index count in base list
                dummy_area -= pdf[count]*step   #   Hence, decrease the area under the PDF accordingly
                x_ -= step                      #   Also, move the search point location towards left
            elif area>dummy_area:               #   Otherwise, if desired area > dummy
                count += 1                      #   We increment the index of base list
                dummy_area += pdf[count]*step   #   Hence, add area to existing dummy
                x_ += step                      #   Also, move the search point rightward
        return x_

def looper(p,vP):
    # robots = parallel(partial(obj.Object,o_type = 'R', p = p),range(p.num_robots))
    prd = Prediction()
    num_opt = [47, 59, 88,  9, 13]
    dist = [2, 0, 1, 2, 0]
    for run in range(len(num_opt)):
        # Update world
        p.Dx = vP.Dx[dist[run]]
        p.mu_x_1 = (p.mu_x_2 + p.mu_x_1)/2 + 1 #+ np.random.randint(2)*(-2)
        if p.Dx == 'G' or p.Dx == 'U':
            p.mu_x_2 = p.mu_x_1
        else:
            p.mu_x_2 = p.mu_x_1 + 5
        p.sigma_x_1 = 1
        p.sigma_x_2 = 1
        p.num_opts = num_opt[run]#np.random.randint(101)
        mean_x = List([p.mu_x_1,p.mu_x_2])
        sigma_x = List([1,1])
        step = 0.0001
        stop = np.sum(mean_x)/len(mean_x) + 2*np.sum(sigma_x)+5
        start = np.sum(mean_x)/len(mean_x) - 2*np.sum(sigma_x)-5
        x = np.arange(start,stop,0.0001)
        if p.Dx == 'G':
            pdf_x,area = PDF(prd.gaussian,mean_x,sigma_x,x)
            sig_h = (0.07*np.log10(p.num_opts)+0.57)*1
            mu_h = prd.ICPDF(1-(1/p.num_opts),mean_x,step,x,pdf_x)

        elif p.Dx == 'K':
            pdf_x,area = PDF(prd.gaussian,mean_x,sigma_x,x)
            sig_h = (0.05*np.log10(p.num_opts)+0.58)*1
            mu_h = prd.ICPDF(1-(1/p.num_opts),mean_x,step,x,pdf_x)

        elif p.Dx == 'U':
            pdf_x,area = PDF(prd.uniform,mean_x,sigma_x,x)
            sig_h = (-0.07*np.log10(p.num_opts)+0.67)*1
            mu_h = prd.ICPDF(1-(1/p.num_opts),mean_x,step,x,pdf_x)

        p.mu_h_1 = mu_h
        p.mu_h_2 = mu_h
        p.sigma_h_1 = sig_h
        p.sigma_h_2 = sig_h
        p.mu_m_1 = int(p.num_robots/p.num_opts)
        p.mu_m_2 = int(p.num_robots/p.num_opts)
        p.h_distribution_fn = rng.threshold_n
        p.packaging(vP)
        p.data_columns_name = p.data_columns_name[:6]
        p.add_columns(p.num_robots)
        p.pre = p.prefix(vP.results_path)
        open(vP.results_path+str(p.pre),'w+')
        p.save_data(vP.results_path)
        time.sleep(5)
        robots = parallel(partial(obj.Object,o_type = 'R', p = p),range(p.num_robots))
        data = {'$\mu_{h_1}$':np.round(p.mu_h_1,decimals=3),'$\sigma_{h_1}$':np.round(p.sigma_h_1,decimals=3),'$x_{max}$ opt No.':None,'$x_{max}$':None,'$CDM$ opt No.':None,'$CDM$':None}
        data['Dq'] = p.Dx
        data['$\mu_{q_1}$'] = p.mu_x_1
        data['$\mu_{q_2}$'] = p.mu_x_2
        data['$\sigma_{q_1}$'] = p.sigma_x_1
        data['$\sigma_{q_2}$'] = p.sigma_x_2
        data['n'] = p.num_opts

        for i in range(len(robots[:p.num_opts*p.mu_m_1])):
            data['h_'+str(i)] = np.round(robots[i].threshold,decimals=3)
            data['tr_'+str(i)] = np.round(robots[i].t_r,decimals=3)
            data['Response_'+str(i)] = robots[i].response
            data['rt_step'+str(i)] = robots[i].delta_t_r
        out = pd.DataFrame(data=[data],columns=p.data_columns_name)
        out.to_csv(p.data_f_path,mode = 'a',header = False, index=False)
        for repeat in range(100):
            parallel(partial(nullifier,robotss=robots,run=run),range(p.num_robots))
            decision,options = deciding_phase(p,robots[:p.num_opts*p.mu_m_1],1)

            data = {'$\mu_{h_1}$':np.round(p.mu_h_1,decimals=3),'$\sigma_{h_1}$':np.round(p.sigma_h_1,decimals=3),'$x_{max}$ opt No.':decision.ref_best,'$x_{max}$':np.round(options[decision.ref_best].quality,decimals=3),'$CDM$ opt No.':decision.best_option,'$CDM$':np.round(options[decision.best_option].quality,decimals=3)}
            out = pd.DataFrame(data=[data],columns=p.data_columns_name)
            out.to_csv(p.data_f_path,mode = 'a',header = False, index=False)

def paramObjects(fixed_params,vP_,data_columns,path,fixed_params_column):
    p = params.Params(data_columns,path)
    p.initializer(vP_,n = fixed_params[0]['n'], Dm = fixed_params[0]['$D_{m}$'], mum1 = fixed_params[0]['$\mu_{m_{1}}$'],\
        mum2 = fixed_params[0]['$\mu_{m_{2}}$'], sm1 = fixed_params[0]['$\sigma_{m_{1}}$'], sm2 = fixed_params[0]['$\sigma_{m_{2}}$'],\
        dmum = vP_.delta_mu_m, Dx = fixed_params[0]['$D_{x}$'], mux1 = fixed_params[0]['$\mu_{x_{1}}$'],\
        mux2 = fixed_params[0]['$\mu_{x_{2}}$'], sx1 = fixed_params[0]['$\sigma_{x_{1}}$'], sx2 = fixed_params[0]['$\sigma_{x_{2}}$'],\
        dmux = vP_.delta_mu_x, Dh = fixed_params[0]['$D_{h}$'], muh1 = fixed_params[0]['$\mu_{h_{1}}$'],\
        muh2 = fixed_params[0]['$\mu_{h_{2}}$'], sh1 = fixed_params[0]['$\sigma_{h_{1}}$'], sh2 = fixed_params[0]['$\sigma_{h_{2}}$'],\
        dmuh = fixed_params[0]['$\delta_{\mu_{h}}$'], delta_tr = fixed_params[0]['delta_tr'])

    p.packaging(vP_)
    p.add_columns(p.num_robots)
    p.pre = p.prefix(path)
    p.save_params(fixed_params_column,fixed_params,path)
    p.save_data(path)
    return p

if __name__=="__main__":
    path = os.path.realpath(os.path.dirname(__file__)) + "/results/"

    data_columns = ['$\mu_{h_1}$','$\sigma_{h_1}$','$x_{max}$ opt No.','$x_{max}$','$CDM$ opt No.','$CDM$']

    packed_parameters = []
    vP = ps.variableParams()
    gaussianM = 1
    uniformM = 0
    # for delt_tr in np.arange(0.001,0.21,0.01):
    if gaussianM:
        # for n in vP.num_opts:
        n = 10
        delt_tr = 1/(n*n)
        fixed_params_column = ['n','$D_{m}$','$\mu_{m_{1}}$','$\mu_{m_{2}}$','$\sigma_{m_{1}}$','$\sigma_{m_{2}}$',\
            '$D_{x}$','$\mu_{x_{1}}$','$\mu_{x_{2}}$','$\sigma_{x_{1}}$','$\sigma_{x_{2}}$',\
            '$D_{h}$','$\mu_{h_{1}}$','$\mu_{h_{2}}$','$\sigma_{h_{1}}$','$\sigma_{h_{2}}$','$\delta_{\mu_{h}}$','delta_tr']
        fixed_params = [{'n': n, '$D_{m}$':vP.Dm[0],'$\mu_{m_{1}}$':vP.mu_m_1[1],'$\mu_{m_{2}}$':vP.mu_m_2[1],\
            '$\sigma_{m_{1}}$':vP.sigma_m_1[0],'$\sigma_{m_{2}}$':vP.sigma_m_2[0],'$D_{x}$':vP.Dx[0],\
            '$\mu_{x_{1}}$':17,'$\mu_{x_{2}}$':17,'$\sigma_{x_{1}}$':vP.sigma_x_1[9],\
            '$\sigma_{x_{2}}$':vP.sigma_x_2[9], '$D_{h}$':None, '$\mu_{h_{1}}$': 13, '$\mu_{h_{2}}$': 13,\
            '$\sigma_{h_{1}}$':0, '$\sigma_{h_{2}}$':0,'$\delta_{\mu_{h}}$':0,'delta_tr':delt_tr}]

        packed_parameters.append(paramObjects(fixed_params=fixed_params,vP_=vP,data_columns=copy.copy(data_columns),path=path,fixed_params_column=fixed_params_column))

    elif uniformM:
        for n in vP.num_opts[:5]:
            fixed_params_column = ['n','$D_{m}$','$\mu_{m_{1}}$','$\mu_{m_{2}}$','$\sigma_{m_{1}}$','$\sigma_{m_{2}}$',\
                '$D_{x}$','$\mu_{x_{1}}$','$\mu_{x_{2}}$','$\sigma_{x_{1}}$','$\sigma_{x_{2}}$',\
                '$D_{h}$','$\mu_{h_{1}}$','$\mu_{h_{2}}$','$\sigma_{h_{1}}$','$\sigma_{h_{2}}$','$\delta_{\mu_{h}}$','delta_tr']
            fixed_params = [{'n': n, '$D_{m}$':vP.Dm[0],'$\mu_{m_{1}}$':vP.mu_m_1[1],'$\mu_{m_{2}}$':vP.mu_m_2[1],\
                '$\sigma_{m_{1}}$':vP.sigma_m_1[0],'$\sigma_{m_{2}}$':vP.sigma_m_2[0],'$D_{x}$':vP.Dx[0],\
                '$\mu_{x_{1}}$':vP.mu_x_1[99],'$\mu_{x_{2}}$':vP.mu_x_2[99],'$\sigma_{x_{1}}$':vP.sigma_x_1[9],\
                '$\sigma_{x_{2}}$':vP.sigma_x_2[9], '$D_{h}$':None, '$\mu_{h_{1}}$': 13, '$\mu_{h_{2}}$': 13,\
                '$\sigma_{h_{1}}$':0, '$\sigma_{h_{2}}$':0,'$\delta_{\mu_{h}}$':0,'delta_tr':None}]

            packed_parameters.append(paramObjects(fixed_params=fixed_params,vP_=vP,data_columns=copy.copy(data_columns),path=path,fixed_params_column=fixed_params_column))

    looper(p = packed_parameters[0], vP = vP)


from fastapi import WebSocket
from app.db.config import client # redis

class ConnectionManager:
    def __init__(self):
        self.active_connections: List[WebSocket] = []

    async def connect(self, websocket: WebSocket, user_id: str):
        await websocket.accept()
        self.active_connections.append(websocket)

        client.sadd("online_users", user_id)

    def disconnect(self, websocket: WebSocket, user_id: str):
        client.srem("online_users", user_id)
        self.active_connections.remove(websocket)

    async def send_personal_message(self, message: str, websocket: WebSocket):
        await websocket.send_text(message)

    async def broadcast(self, message: str):
        for connection in self.active_connections:
            await connection.send_text(message)


#Ensemble Backend Project by I Ahmed

from flask import Flask, request, jsonify
from flask_sqlalchemy import SQLAlchemy
from flask_marshmallow import Marshmallow
import os

#Initialize App

backend_app = Flask(__name__)
base_directory = os.path.abspath(os.path.dirname(__file__))

#Database
backend_app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(base_directory, 'db.sqlite')
#backend_app['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

# Initialize Database
db = SQLAlchemy(backend_app)

#initialize Marshmallow
ma = Marshmallow(backend_app)

# Movie Class (Object Creation)
class Movie(db.Model):

    id = db.Column(db.Integer, primary_key = True)
    movie_title = db.Column(db.String(100), unique=True) #we dont want 2 movies with same name so unique = true
    description = db.Column(db.String(400))
    release_year = db.Column(db.Integer)
    duration = db.Column(db.Integer) #duration in minutes
    rating = db.Column(db.Float)
    likes = db.Column(db.Integer) #we start at 0 likes when we create a movie
    dislikes = db.Column(db.Integer) #we start at 0  dislikes when we create a movie

    def __init__(self, movie_title, description, release_year, duration, rating, likes, dislikes):

        self.movie_title = movie_title
        self.description = description
        self.release_year = release_year
        self.duration = duration
        self.rating = rating
        self.likes = likes
        self.dislikes = dislikes

# Movie Schema

class MovieSchema(ma.Schema):
    class Meta:
        fields = ('id', 'movie_title', 'description', 'release_year', 'duration', 'rating', 'likes', 'dislikes')

#Initialize Schema
movie_schema = MovieSchema()
movies_schema = MovieSchema(many=True) #if we are dealing with many movies(list)

#App routes

#Add or create a movie
@backend_app.route('/movie', methods=['POST'])
def add_movie():
    movie_title = request.json['movie_title']
    description = request.json['description']
    release_year = request.json['release_year']
    duration = request.json['duration']
    rating = request.json['rating']
    likes = request.json['likes']
    dislikes = request.json['dislikes']

    new_movie = Movie(movie_title, description, release_year, duration, rating, likes, dislikes)
    db.session.add(new_movie)
    db.session.commit()

    return movie_schema.jsonify(new_movie)

#Get all movies
@backend_app.route('/movie', methods=['GET'])
def get_movies():
    all_movies = Movie.query.all()
    return_result = movies_schema.dump(all_movies)
    return jsonify(return_result)

#Get single movie by using ID
@backend_app.route('/movie/<id>', methods=['GET'])
def get_movie(id):
    movie = Movie.query.get(id)
    return movie_schema.jsonify(movie)

#Search Movie by using Movie Title (query)
@backend_app.route('/movie/<movie_title>')
def show_movie_by_title(movie_title):
    movie = Movie.query.filter_by(movie_title=movie_title).first_or_404()
    return render_template('show_movie_by_title', movie=movie)

#update a movie info
@backend_app.route('/movie/<id>', methods=['PUT'])
def update_movie(id):
    movie = Movie.query.get(id)

    movie_title = request.json['movie_title']
    description = request.json['description']
    release_year = request.json['release_year']
    duration = request.json['duration']
    rating = request.json['rating']
    likes = request.json['likes']
    dislikes = request.json['dislikes']

    movie.movie_title = movie_title
    movie.description = description
    movie.release_year = release_year
    movie.duration = duration
    movie.rating = rating
    movie.likes = likes
    movie.dislikes = dislikes

    db.session.commit()

    return movie_schema.jsonify(movie)

#update likes
@backend_app.route('/movie/<id>', methods=['PUT'])
def update_likes(id):
    setattr(id, 'likes', id.likes + 1)
    db.session.commit()

#update dislikes
@backend_app.route('/movie/<id>', methods=['PUT'])
def update_dislikes(id):
    setattr(id, 'dislikes', id.dislikes + 1)
    db.session.commit()

#Delete a movie
@backend_app.route('/movie/<id>', methods=['DELETE'])
def delete_movie(id):
    movie = Movie.query.get(id)
    db.session.delete(movie)
    db.session.commit()

    return movie_schema.jsonify(movie)

#running server

if __name__ == '__main__':
    backend_app.run(debug=True)


import random
from art import logo
import replit
print(logo)
cards = [11, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10]

def deal_card():
  """Deals new randomly chosen card"""
  new_card = random.choice(cards)
  return new_card

def calculate_score(cards_delt):
  """"Checks for blackjack, calculates score, converts ace to one if over 21"""
  if cards_delt == [10, 11] or cards_delt == [11, 10]:
    return 0
  if 11 in cards_delt and sum(cards_delt) > 21:
      cards_delt.remove(11)
      cards_delt.append(1)
  return sum(cards_delt)

def compare(user_score, computer_score):
  if user_score == computer_score:
    return "It's a draw"
  elif computer_score == 0:
    return "Computer has blackjack, You lose!"
  elif user_score == 0:
    return "BlackJack, You win!"
  elif user_score > 21:
    return f"Bust, you lose with a score of {user_score}"
  elif computer_score > 21:
    return f"Computer busts with a score of {computer_score}, You Win!"
  elif user_score < computer_score:
    return f"Computer has {computer_score}, you have {user_score}, computer wins"
  else:
    return f"You have {user_score}, computer has {computer_score}, YOU WIN"

continue_playing = True

while continue_playing:
  user_cards = []
  computer_cards = []
  for i in range(2):
      user_cards.append(deal_card())
      computer_cards.append(deal_card())
  user_score = calculate_score(user_cards)
  computer_score = calculate_score(computer_cards)
  print(f'You have {user_cards} with a total score of {user_score}')
  print(f'The computer has [{computer_cards[0]}]')

  while user_score <= 21 and user_score != 0:
    hit = input('Do you want another card? Y/N: ')
    if hit == "Y" or hit == "y":
      user_cards.append(deal_card())
      user_score = calculate_score(user_cards)
      print(f"You have {user_cards} with a total score of {user_score}")
    else:
      break

  while computer_score < 17 and user_score <= 21:
    computer_cards.append(deal_card())
    computer_score = calculate_score(computer_cards)
    print(f'Computer draws a card, computer has {computer_cards} totalling {computer_score}')

  print(compare(user_score, computer_score))

  fortsette = input('Do you want to play again? Y/N: ')
  if fortsette == "y" or fortsette == "Y":
    continue_playing = True
    replit.clear()
  else:
    print('Thank you for playing!')
    break


import json
import random
from typing import Any, Dict, Iterable, List, Mapping, Tuple
from unittest.mock import patch

import pendulum
import pytest
import requests_mock
import timeout_decorator
from airbyte_cdk.models import ConnectorSpecification
from airbyte_cdk.sources.streams.http.exceptions import UserDefinedBackoffException
from source_tiktok_marketing import SourceTiktokMarketing
from source_tiktok_marketing.streams import Ads, Advertisers, JsonUpdatedState

SANDBOX_CONFIG_FILE = "secrets/sandbox_config.json"
PROD_CONFIG_FILE = "secrets/prod_config.json"

@pytest.fixture(scope="module")
def prepared_sandbox_args():
    """Generates streams settings from a file for sandbox"""
    with open(SANDBOX_CONFIG_FILE, "r") as f:
        return SourceTiktokMarketing._prepare_stream_args(json.loads(f.read()))

@pytest.fixture(scope="module")
def prepared_prod_args():
    """Generates streams settings from a file for production"""
    with open(PROD_CONFIG_FILE, "r") as f:
        return SourceTiktokMarketing._prepare_stream_args(json.loads(f.read()))

@timeout_decorator.timeout(20)
@pytest.mark.parametrize("error_code", (40100, 50002))
def test_backoff(prepared_sandbox_args, error_code):
    """TiktokMarketing sends the header 'Retry-After' about needed delay.
    All streams have to handle it"""
    stream = Advertisers(**prepared_sandbox_args)
    with requests_mock.Mocker() as m:
        url = stream.url_base + stream.path()
        m.get(url, text=json.dumps({"code": error_code}))
        with pytest.raises(UserDefinedBackoffException):
            list(stream.read_records(sync_mode=None))

def generate_pages(items: List[Mapping[str, Any]], page_size: int, last_empty: bool = False) -> Iterable[Tuple[int, Dict]]:
    pages = []
    for i in range(0, len(items), page_size):
        pages.append(items[i : i + page_size])
    if last_empty:
        pages.append([])
    total_number = len(items)
    for page_number, page_items in enumerate(pages, start=1):
        yield (
            page_number,
            {
                "message": "OK",
                "code": 0,
                "request_id": "unique_request_id",
                "data": {
                    "page_info": {"total_number": total_number, "page": page_number, "page_size": page_size, "total_page": len(page_items)},
                    "list": page_items,
                },
            },
        )

def random_integer(max_value: int = 1634125471, min_value: int = 1) -> int:
    return random.randint(min_value, max_value)

def unixtime2str(unix_time: int) -> str:
    "Converts unix time to string"
    return pendulum.from_timestamp(unix_time).strftime("%Y-%m-%d %H:%M:%S")

def test_random_items(prepared_prod_args):
    stream = Ads(**prepared_prod_args)
    advertiser_count = 100
    test_advertiser_ids = set([str(random_integer()) for _ in range(advertiser_count)])
    advertiser_count = len(test_advertiser_ids)
    page_size = 100
    with requests_mock.Mocker() as m:
        # mock for advertisers' list
        advertisers = [{"advertiser_id": i, "advertiser_name": str(i)} for i in test_advertiser_ids]
        for _, page_response in generate_pages(items=advertisers, page_size=advertiser_count):
            m.register_uri("GET", "/open_api/v1.3/oauth2/advertiser/get/", json=page_response)
        stream = Ads(**prepared_prod_args)
        stream.page_size = page_size
        stream.get_advertiser_ids()
        assert not set(test_advertiser_ids).symmetric_difference(stream._advertiser_ids), "stream found not all  advertiser IDs"

        current_state = None
        max_updated_value = None
        for stream_slice in stream.stream_slices():
            advertiser_id = stream_slice["advertiser_id"]
            test_ad_ids = [random_integer() for _ in range(random_integer(max_value=999))]
            ad_items = []
            for ad_id in test_ad_ids:
                create_time = random_integer(min_value=1507901660)
                ad_items.append(
                    {
                        "create_time": unixtime2str(create_time),
                        "modify_time": unixtime2str(create_time + 60),
                        "advertiser_id": advertiser_id,
                        "ad_id": ad_id,
                    }
                )
                if not max_updated_value or max_updated_value < ad_items[-1][stream.cursor_field]:
                    max_updated_value = ad_items[-1][stream.cursor_field]

            # mock for ads
            for page, page_response in generate_pages(items=ad_items, page_size=page_size, last_empty=True):
                uri = f"/open_api/v1.3/ad/get/?page_size={page_size}&advertiser_id={advertiser_id}"
                if page != 1:
                    uri += f"&page={page}"
                m.register_uri("GET", uri, complete_qs=True, json=page_response)

            for record in stream.read_records(sync_mode=None, stream_slice=stream_slice):
                current_state = stream.get_updated_state(current_state, record)
                assert isinstance(current_state[stream.cursor_field], JsonUpdatedState), "state should be an  JsonUpdatedState object"
                if advertisers[-1]["advertiser_id"] != advertiser_id:
                    assert (
                        current_state[stream.cursor_field].dict() == ""
                    ), "max updated cursor value should be returned for last slice only"
        assert len(stream._advertiser_ids) == 0, "all advertisers should be popped"
        assert current_state[stream.cursor_field].dict() == max_updated_value

@pytest.mark.parametrize(
    "config, stream_len",
    [
        (PROD_CONFIG_FILE, 36),
        (SANDBOX_CONFIG_FILE, 28),
    ],
)
def test_source_streams(config, stream_len):
    with open(config) as f:
        config = json.load(f)
    streams = SourceTiktokMarketing().streams(config=config)
    assert len(streams) == stream_len

def test_source_spec():
    spec = SourceTiktokMarketing().spec(logger=None)
    assert isinstance(spec, ConnectorSpecification)

@pytest.fixture(name="config")
def config_fixture():
    config = {
        "account_id": 123,
        "access_token": "TOKEN",
        "start_date": "2019-10-10T00:00:00",
        "end_date": "2020-10-10T00:00:00",
    }
    return config

@pytest.fixture(name="logger_mock")
def logger_mock_fixture():
    return patch("source_tiktok_marketing.source.logger")

def test_source_check_connection_ok(config, logger_mock):
    with patch.object(Advertisers, "stream_slices"):
        with patch.object(Advertisers, "read_records", return_value=iter([1])):
            assert SourceTiktokMarketing().check_connection(logger_mock, config=config) == (True, None)

def test_source_check_connection_failed(config, logger_mock):
    with patch.object(Advertisers, "read_records", return_value=0):
        assert SourceTiktokMarketing().check_connection(logger_mock, config=config)[0] is False

@pytest.mark.parametrize(
    "config_file",
    ["integration_tests/invalid_config_oauth.json", "integration_tests/invalid_config_access_token.json", "secrets/config.json"],
)
def test_source_prepare_stream_args(config_file):
    with open(config_file) as f:
        config = json.load(f)
        args = SourceTiktokMarketing._prepare_stream_args(config)
        assert "authenticator" in args

def test_minimum_start_date(config, caplog):
    config["start_date"] = "2000-01-01"
    source = SourceTiktokMarketing()
    streams = source.streams(config)

    for stream in streams:
        assert stream._start_time == "2012-01-01 00:00:00"
    assert "The start date is too far in the past. Setting it to 2012-01-01" in caplog.text


import time
import os
import pprint
from sys import exit
from math import ceil
from signal import signal, SIGINT
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.firefox.options import Options
from tqdm import tqdm
from dotenv import load_dotenv
from utils import is_subseq
from webdriver_manager.firefox import GeckoDriverManager
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
import pandas as pd
from datetime import datetime

load_dotenv()

result = []
col_names = [
    "lieu",
    "duree",
    "tarif",
    "teletravail",
    "debut",
    "description",
    "date",
    "link",
]
my_df = pd.DataFrame(columns=col_names)
options = Options()
options.headless = True
driver = webdriver.Firefox(
    options=options, service=Service(GeckoDriverManager().install())
)

def handler(signal_received, frame):
    print("SIGINT or CTRL-C detected. Exiting gracefully")
    my_df.to_csv(
        "report_file" + str(datetime.now()) + ".csv", sep=";", encoding="utf-8"
    )
    driver.close()
    exit(0)

driver.get("https://www.freelance-info.fr/login-page.php")

username_elem = driver.find_element(by=By.ID, value="_username")
password_elem = driver.find_element(by=By.ID, value="_password")

username_elem.clear()
password_elem.clear()

username_elem.send_keys(os.getenv("USERNAME"))  # email freelance-info
password_elem.send_keys(os.getenv("PASSWORD"))  # mot de passe freelance-info
password_elem.send_keys(Keys.RETURN)

list_keywords = ["développeur", "python", "flask", "django", "backend", "test"]
mandatory_keywords = ["python", "django", "flask"]
param_keyword = ",".join(list_keywords)
current_page = 1
driver.get(
    "https://www.freelance-info.fr/missions?keywords=" + param_keyword + "&page=1"
)
nb_total_page = (
    max(
        [
            int(word)
            for word in driver.find_element(by=By.ID, value="mission2").text.split()
            if word.isdigit()
        ]
    )
    / 10
)
signal(SIGINT, handler)

for page in tqdm(range(1, ceil(nb_total_page))):
    print(page)
    driver.get(
        "https://www.freelance-info.fr/missions?keywords="
        + param_keyword
        + "&page="
        + str(page)
    )
    pagination_xpath = "/html/body/div[2]/main/div/div/div[1]/nav/ul"
    list_pagination = driver.find_element(
        by=By.XPATH, value=pagination_xpath
    ).find_elements(by=By.XPATH, value="./*")

    list_offers = driver.find_elements(by=By.ID, value="offre")
    link_list = [
        offer.find_element(
            by=By.CSS_SELECTOR, value=".rtitre.filter-link"
        ).get_attribute("href")
        for offer in list_offers
    ]
    for link in link_list:
        driver.get(link)
        abstract = driver.find_element(by=By.CSS_SELECTOR, value=".col-8.left")
        list_abstract_content_line = abstract.text.split("\n")
        list_abstract_content_split = [
            elem.split(":") for elem in list_abstract_content_line
        ]
        payload = {}
        payload["title"] = driver.find_element(
            by=By.CLASS_NAME, value="title-grand"
        ).text
        payload["lieu"] = list_abstract_content_split[0][1].strip()
        payload["duree"] = list_abstract_content_split[1][1].strip()
        payload["tarif"] = list_abstract_content_split[2][1].strip()
        payload["teletravail"] = list_abstract_content_split[3][1].strip()
        payload["debut"] = list_abstract_content_split[4][1].strip()
        payload["description"] = driver.find_element(
            by=By.ID, value="description-mission"
        ).text
        payload["link"] = link
        tmp_date = driver.find_element(by=By.ID, value="publié").text.split(" ")[2]
        payload["date"] = datetime.strptime(tmp_date, "%d/%m/%Y")
        tmp_df = pd.DataFrame(columns=col_names)
        # TODO on recupere toutes les donnees puis on filtre ensuite
        my_df.loc[len(my_df)] = payload

        # if is_subseq(mandatory_keywords, [payload["description"].lower()]):
        #     print(payload["title"], payload["link"])
        #     result.append(payload)

    current_page += 1

my_df.to_csv("report_file" + str(datetime.now()) + ".csv", sep=";", encoding="utf-8")
driver.close()
# with open(
#     "report_file.txt", "w", encoding="utf-8"
# ) as output_file:  # enregistrement des resultats
#     output_file.write(pprint.pformat(result, indent=4))


__all__ = ["CONFIG_SCHEMA"]

import yaml

# Configuration for SimpleCsc
CONFIG_SCHEMA = yaml.safe_load(
    """
$schema: http://json-schema.org/draft-07/schema#
$id: https://github.com/lsst-ts/ts_hexrotcomm/blob/main/python/lsst/ts/hexrotcomm/config_schema.py
title: MTRotator v2
description: Configuration for SimpleCsc, which has no configuration.
type: object
properties:
  host:
    description: >-
      IP address of the TCP/IP interface.
      Ignored for SimpleCsc, because it always runs in simulation mode.
    type: string
    format: hostname
  port:
    description: >-
      Port number of the TCP/IP interface.
      Ignored for SimpleCsc, because it always runs in simulation mode.
    type: integer
  connection_timeout:
    description: Time limit for connecting to the TCP/IP interface (sec)
    type: number
    exclusiveMinimum: 0
required: [host, port, connection_timeout]
additionalProperties: false
"""
)


import webbrowser
import json
from parse_plan import parse_plan
import click

from parse_idxs import find_identifiers
from dfs import DAG, get_leaf_to_filename
from run_notebook import get_raw_plan

# Spark Explain Output Related variables
FINAL_COLUMNS_HEAD = "AdaptiveSparkPlan"
URL = "https://www.beeline-track.ml/"
raw_plan_content = []
parsed_plan_content = []

# Dependency clauses to parse
AS_CLAUSE = " AS "
FILTERING_CLAUSES = ["Filter", "BroadcastHashJoin"]

# Graph-related variables
adj_map = {}

def initialize(is_explain: bool, file_path: str):
    global parsed_plan_content, raw_plan_content
    if is_explain:
        raw_plan = []
        explain_file = open(file_path, 'r')
        for line in explain_file:
            raw_plan.append(line)
    else:
        raw_plan = get_raw_plan(file_path)
    skip = True
    for line in raw_plan:
        if len(line) <= 1:
            skip = False
        if not skip:
            raw_plan_content.append(line)
    parsed_plan_content = parse_plan(raw_plan_content)

def add_as_clause_dependency(line: str):
    for i in range(0, len(line)-3):
        if line[i:i+4] == AS_CLAUSE:
            parent_name = find_identifiers(line[i:], True)
            if parent_name is None:
                continue
            if not(line[i+4:].strip().startswith(parent_name)):
                continue
            left = i
            bracket_depth = 0
            while not(left < 1 or (bracket_depth == 0 and line[left] in [',', '['])):
                if line[left] == ')':
                    bracket_depth += 1
                elif line[left] == '(':
                    bracket_depth -= 1
                left -= 1
            child_names = find_identifiers(line[left:i])
            if parent_name not in adj_map:
                adj_map[parent_name] = []
            for child in child_names:
                adj_map[parent_name].append(child)

def add_as_clause_deps():
    global raw_plan_content
    for line in raw_plan_content:
        add_as_clause_dependency(line)

def get_filtering_deps():
    filtering_deps = []
    for step in parsed_plan_content:
        if step["_name"] == "Filter":
            filtering_deps += find_identifiers(step["Condition"])
        elif step["_name"] == "BroadcastHashJoin":
            filtering_deps += find_identifiers(step["Left keys"])
            filtering_deps += find_identifiers(step["Right keys"])
            filtering_deps += find_identifiers(step["Join condition"])
    return list(set(filtering_deps))

def get_final_ids():
    final_ids = []
    for step in parsed_plan_content:
        if step["_name"] == "AdaptiveSparkPlan":
            final_ids = find_identifiers(step["Output"])
            break
    return final_ids

@click.command()
@click.argument('file_path')
@click.option('--mode', type=click.Choice(['explain', 'script']), required=True)
def run(file_path, mode):
    initialize(mode == "explain", file_path)
    add_as_clause_deps()
    final_ids = get_final_ids()

    dag = DAG(adj_map)

    final_id_to_deps = dict()
    for id in final_ids:
        final_id_to_deps[id] = dag.get_deps(id)

    leaf_to_filename = get_leaf_to_filename(parsed_plan_content)

    common_leaf_deps = set()

    for id in get_filtering_deps():
        for leaf in dag.get_deps(id):
            common_leaf_deps.add(leaf)

    filtered_deps = set()
    filtered_source_names = set()

    for dep in common_leaf_deps:
        if dep not in leaf_to_filename:
                continue
        source_name = leaf_to_filename[dep]
        col_name = dep.split('#')[0]
        formatted_col_name = f"{source_name}.{col_name}"

        filtered_deps.add(formatted_col_name)
        filtered_source_names.add(source_name)

    result = {"non_trivial_cols_deps": list(filtered_deps)}
    result["non_trivial_data_sources"] = list(filtered_source_names)

    for id, deps in final_id_to_deps.items():
        col_names = set()
        source_names = set()
        for dep in set(deps):
            if dep not in leaf_to_filename:
                continue

            source_name = leaf_to_filename[dep]
            col_name = dep.split('#')[0]
            formatted_col_name = f"{source_name}.{col_name}"

            if dep in deps:
                col_names.add(formatted_col_name)

            source_names.add(source_name)

        result[id.split('#')[0]] = {
            "data_sources": list(source_names),
            "cols_deps": list(col_names)
        }

    pretty_json = json.dumps(result, indent=4)
    print(pretty_json)

    json_file = open("deps_graph.json", "w")
    json_file.write(pretty_json)
    json_file.close()

    webbrowser.open_new_tab(URL)

if __name__ == '__main__':
    run()


# %%
import _lib.lime_survey as ls
import _lib.preprocess as pp
import pandas as pd
import plotly.express as px
# %%
df, stats = pp.hils_swls_metrics()

ls.questionaire(200, 'hils', color='black', collage_color=False)

# %%

constructs = ['hils', 'swls']
construct = constructs[1]
df = pp.time_invariant_oc(construct=construct)
text, set = pp.string_set(df, 'words')

# %%
word_df = pd.DataFrame()

for i, row in df.iterrows():
    word_list = row['words'].split()
    word_dict = {
        'word': word_list,
        construct: [row[construct]]*len(word_list)
    }
    word_df = pd.concat([word_df, pd.DataFrame(word_dict)],
                        ignore_index=True)
# %%
fig = px.histogram(
    data_frame=word_df,
    x=construct,
    color='word',
    barmode='overlay',
    opacity=0.5,
    marginal='violin'
)
fig.write_html('_graphs/swls_bar.html')
# %%
fig.show()

# %%

df = pd.read_csv('_data/Big_swls_delta_set.csv')
# %%


import typing_extensions

from api.paths import PathValues
from api.apis.paths.daily_ import Daily
from api.apis.paths.leaderboard_seed import LeaderboardSeed
from api.apis.paths.tombstone_seed import TombstoneSeed

PathToApi = typing_extensions.TypedDict(
    'PathToApi',
    {
        PathValues.DAILY_: Daily,
        PathValues.LEADERBOARD_SEED: LeaderboardSeed,
        PathValues.TOMBSTONE_SEED: TombstoneSeed,
    }
)

path_to_api = PathToApi(
    {
        PathValues.DAILY_: Daily,
        PathValues.LEADERBOARD_SEED: LeaderboardSeed,
        PathValues.TOMBSTONE_SEED: TombstoneSeed,
    }
)


import os
import time
import datetime
import cv2
import queue
import threading
import ctypes
import pyarrow.plasma as plasma
import multiprocessing as mp
import subprocess as sp
import numpy as np
import copy
import itertools
import json
from collections import defaultdict
from frigate.util import draw_box_with_label, area, calculate_region, clipped, intersection_over_union, intersection, EventsPerSecond, listen, PlasmaManager
from frigate.objects import ObjectTracker
from frigate.edgetpu import RemoteObjectDetector
from frigate.motion import MotionDetector

def get_frame_shape(source):
    ffprobe_cmd = " ".join([
        'ffprobe',
        '-v',
        'panic',
        '-show_error',
        '-show_streams',
        '-of',
        'json',
        '"'+source+'"'
    ])
    print(ffprobe_cmd)
    p = sp.Popen(ffprobe_cmd, stdout=sp.PIPE, shell=True)
    (output, err) = p.communicate()
    p_status = p.wait()
    info = json.loads(output)
    print(info)

    video_info = [s for s in info['streams'] if s['codec_type'] == 'video'][0]

    if video_info['height'] != 0 and video_info['width'] != 0:
        return (video_info['height'], video_info['width'], 3)

    # fallback to using opencv if ffprobe didnt succeed
    video = cv2.VideoCapture(source)
    ret, frame = video.read()
    frame_shape = frame.shape
    video.release()
    return frame_shape

def get_ffmpeg_input(ffmpeg_input):
    frigate_vars = {k: v for k, v in os.environ.items() if k.startswith('FRIGATE_')}
    return ffmpeg_input.format(**frigate_vars)

def filtered(obj, objects_to_track, object_filters, mask):
    object_name = obj[0]

    if not object_name in objects_to_track:
        return True

    if object_name in object_filters:
        obj_settings = object_filters[object_name]

        # if the min area is larger than the
        # detected object, don't add it to detected objects
        if obj_settings.get('min_area',-1) > obj[3]:
            return True

        # if the detected object is larger than the
        # max area, don't add it to detected objects
        if obj_settings.get('max_area', 24000000) < obj[3]:
            return True

        # if the score is lower than the threshold, skip
        if obj_settings.get('threshold', 0) > obj[1]:
            return True

        # compute the coordinates of the object and make sure
        # the location isnt outside the bounds of the image (can happen from rounding)
        y_location = min(int(obj[2][3]), len(mask)-1)
        x_location = min(int((obj[2][2]-obj[2][0])/2.0)+obj[2][0], len(mask[0])-1)

        # if the object is in a masked location, don't add it to detected objects
        if mask[y_location][x_location] == [0]:
            return True

        return False

def create_tensor_input(frame, region):
    cropped_frame = frame[region[1]:region[3], region[0]:region[2]]

    # Resize to 300x300 if needed
    if cropped_frame.shape != (300, 300, 3):
        cropped_frame = cv2.resize(cropped_frame, dsize=(300, 300), interpolation=cv2.INTER_LINEAR)

    # Expand dimensions since the model expects images to have shape: [1, 300, 300, 3]
    return np.expand_dims(cropped_frame, axis=0)

def start_or_restart_ffmpeg(ffmpeg_cmd, frame_size, ffmpeg_process=None):
    if not ffmpeg_process is None:
        print("Terminating the existing ffmpeg process...")
        ffmpeg_process.terminate()
        try:
            print("Waiting for ffmpeg to exit gracefully...")
            ffmpeg_process.communicate(timeout=30)
        except sp.TimeoutExpired:
            print("FFmpeg didnt exit. Force killing...")
            ffmpeg_process.kill()
            ffmpeg_process.communicate()
        ffmpeg_process = None

    print("Creating ffmpeg process...")
    print(" ".join(ffmpeg_cmd))
    process = sp.Popen(ffmpeg_cmd, stdout = sp.PIPE, stdin = sp.DEVNULL, bufsize=frame_size*10, start_new_session=True)
    return process

class CameraCapture(threading.Thread):
    def __init__(self, name, ffmpeg_process, frame_shape, frame_queue, take_frame, fps, detection_frame):
        threading.Thread.__init__(self)
        self.name = name
        self.frame_shape = frame_shape
        self.frame_size = frame_shape[0] * frame_shape[1] * frame_shape[2]
        self.frame_queue = frame_queue
        self.take_frame = take_frame
        self.fps = fps
        self.skipped_fps = EventsPerSecond()
        self.plasma_client = PlasmaManager()
        self.ffmpeg_process = ffmpeg_process
        self.current_frame = 0
        self.last_frame = 0
        self.detection_frame = detection_frame

    def run(self):
        frame_num = 0
        self.skipped_fps.start()
        while True:
            if self.ffmpeg_process.poll() != None:
                print(f"{self.name}: ffmpeg process is not running. exiting capture thread...")
                break

            frame_bytes = self.ffmpeg_process.stdout.read(self.frame_size)
            self.current_frame = datetime.datetime.now().timestamp()

            if len(frame_bytes) == 0:
                print(f"{self.name}: ffmpeg didnt return a frame. something is wrong.")
                continue

            self.fps.update()

            frame_num += 1
            if (frame_num % self.take_frame) != 0:
                self.skipped_fps.update()
                continue

            # if the detection process is more than 1 second behind, skip this frame
            if self.detection_frame.value > 0.0 and (self.last_frame - self.detection_frame.value) > 1:
                self.skipped_fps.update()
                continue

            # put the frame in the plasma store
            self.plasma_client.put(f"{self.name}{self.current_frame}",
                    np
                        .frombuffer(frame_bytes, np.uint8)
                        .reshape(self.frame_shape)
                )
            # add to the queue
            self.frame_queue.put(self.current_frame)
            self.last_frame = self.current_frame

def track_camera(name, config, global_objects_config, frame_queue, frame_shape, detection_queue, detected_objects_queue, fps, detection_fps, read_start, detection_frame):
    print(f"Starting process for {name}: {os.getpid()}")
    listen()

    detection_frame.value = 0.0

    # Merge the tracked object config with the global config
    camera_objects_config = config.get('objects', {})
    # combine tracked objects lists
    objects_to_track = set().union(global_objects_config.get('track', ['person', 'car', 'truck']), camera_objects_config.get('track', []))
    # merge object filters
    global_object_filters = global_objects_config.get('filters', {})
    camera_object_filters = camera_objects_config.get('filters', {})
    objects_with_config = set().union(global_object_filters.keys(), camera_object_filters.keys())
    object_filters = {}
    for obj in objects_with_config:
        object_filters[obj] = {**global_object_filters.get(obj, {}), **camera_object_filters.get(obj, {})}

    frame = np.zeros(frame_shape, np.uint8)

    # load in the mask for object detection
    if 'mask' in config:
        mask = cv2.imread("/config/{}".format(config['mask']), cv2.IMREAD_GRAYSCALE)
    else:
        mask = None

    if mask is None:
        mask = np.zeros((frame_shape[0], frame_shape[1], 1), np.uint8)
        mask[:] = 255

    motion_detector = MotionDetector(frame_shape, mask, resize_factor=6)
    object_detector = RemoteObjectDetector(name, '/labelmap.txt', detection_queue)

    object_tracker = ObjectTracker(10)

    plasma_client = PlasmaManager()
    avg_wait = 0.0
    fps_tracker = EventsPerSecond()
    fps_tracker.start()
    object_detector.fps.start()
    while True:
        read_start.value = datetime.datetime.now().timestamp()
        frame_time = frame_queue.get()
        duration = datetime.datetime.now().timestamp()-read_start.value
        read_start.value = 0.0
        avg_wait = (avg_wait*99+duration)/100
        detection_frame.value = frame_time

        # Get frame from plasma store
        frame = plasma_client.get(f"{name}{frame_time}")

        if frame is plasma.ObjectNotAvailable:
            continue

        fps_tracker.update()
        fps.value = fps_tracker.eps()
        detection_fps.value = object_detector.fps.eps()

        # look for motion
        motion_boxes = motion_detector.detect(frame)

        tracked_objects = object_tracker.tracked_objects.values()

        # merge areas of motion that intersect with a known tracked object into a single area to look at
        areas_of_interest = []
        used_motion_boxes = []
        for obj in tracked_objects:
            x_min, y_min, x_max, y_max = obj['box']
            for m_index, motion_box in enumerate(motion_boxes):
                if intersection_over_union(motion_box, obj['box']) > .2:
                    used_motion_boxes.append(m_index)
                    x_min = min(obj['box'][0], motion_box[0])
                    y_min = min(obj['box'][1], motion_box[1])
                    x_max = max(obj['box'][2], motion_box[2])
                    y_max = max(obj['box'][3], motion_box[3])
            areas_of_interest.append((x_min, y_min, x_max, y_max))
        unused_motion_boxes = set(range(0, len(motion_boxes))).difference(used_motion_boxes)

        # compute motion regions
        motion_regions = [calculate_region(frame_shape, motion_boxes[i][0], motion_boxes[i][1], motion_boxes[i][2], motion_boxes[i][3], 1.2)
            for i in unused_motion_boxes]

        # compute tracked object regions
        object_regions = [calculate_region(frame_shape, a[0], a[1], a[2], a[3], 1.2)
            for a in areas_of_interest]

        # merge regions with high IOU
        merged_regions = motion_regions+object_regions
        while True:
            max_iou = 0.0
            max_indices = None
            region_indices = range(len(merged_regions))
            for a, b in itertools.combinations(region_indices, 2):
                iou = intersection_over_union(merged_regions[a], merged_regions[b])
                if iou > max_iou:
                    max_iou = iou
                    max_indices = (a, b)
            if max_iou > 0.1:
                a = merged_regions[max_indices[0]]
                b = merged_regions[max_indices[1]]
                merged_regions.append(calculate_region(frame_shape,
                    min(a[0], b[0]),
                    min(a[1], b[1]),
                    max(a[2], b[2]),
                    max(a[3], b[3]),
                    1
                ))
                del merged_regions[max(max_indices[0], max_indices[1])]
                del merged_regions[min(max_indices[0], max_indices[1])]
            else:
                break

        # resize regions and detect
        detections = []
        for region in merged_regions:

            tensor_input = create_tensor_input(frame, region)

            region_detections = object_detector.detect(tensor_input)

            for d in region_detections:
                box = d[2]
                size = region[2]-region[0]
                x_min = int((box[1] * size) + region[0])
                y_min = int((box[0] * size) + region[1])
                x_max = int((box[3] * size) + region[0])
                y_max = int((box[2] * size) + region[1])
                det = (d[0],
                    d[1],
                    (x_min, y_min, x_max, y_max),
                    (x_max-x_min)*(y_max-y_min),
                    region)
                if filtered(det, objects_to_track, object_filters, mask):
                    continue
                detections.append(det)

        #########
        # merge objects, check for clipped objects and look again up to N times
        #########
        refining = True
        refine_count = 0
        while refining and refine_count < 4:
            refining = False

            # group by name
            detected_object_groups = defaultdict(lambda: [])
            for detection in detections:
                detected_object_groups[detection[0]].append(detection)

            selected_objects = []
            for group in detected_object_groups.values():

                # apply non-maxima suppression to suppress weak, overlapping bounding boxes
                boxes = [(o[2][0], o[2][1], o[2][2]-o[2][0], o[2][3]-o[2][1])
                    for o in group]
                confidences = [o[1] for o in group]
                idxs = cv2.dnn.NMSBoxes(boxes, confidences, 0.5, 0.4)

                for index in idxs:
                    obj = group[index[0]]
                    if clipped(obj, frame_shape):
                        box = obj[2]
                        # calculate a new region that will hopefully get the entire object
                        region = calculate_region(frame_shape,
                            box[0], box[1],
                            box[2], box[3])

                        tensor_input = create_tensor_input(frame, region)
                        # run detection on new region
                        refined_detections = object_detector.detect(tensor_input)
                        for d in refined_detections:
                            box = d[2]
                            size = region[2]-region[0]
                            x_min = int((box[1] * size) + region[0])
                            y_min = int((box[0] * size) + region[1])
                            x_max = int((box[3] * size) + region[0])
                            y_max = int((box[2] * size) + region[1])
                            det = (d[0],
                                d[1],
                                (x_min, y_min, x_max, y_max),
                                (x_max-x_min)*(y_max-y_min),
                                region)
                            if filtered(det, objects_to_track, object_filters, mask):
                                continue
                            selected_objects.append(det)

                        refining = True
                    else:
                        selected_objects.append(obj)

            # set the detections list to only include top, complete objects
            # and new detections
            detections = selected_objects

            if refining:
                refine_count += 1

        # now that we have refined our detections, we need to track objects
        object_tracker.match_and_update(frame_time, detections)

        # add to the queue
        detected_objects_queue.put((name, frame_time, object_tracker.tracked_objects))

    print(f"{name}: exiting subprocess")


import time
import plotly as py
import numpy as np
import plotly.figure_factory as ff
import os
import sys
# 愉快的使用相对路径
os.chdir(sys.path[0])

# x轴, 对应于画图位置的起始坐标x
# start, time, of, every, task, , //每个工序的开始时间
n_start_time = []
# length, 对应于每个图形在x轴方向的长度
# duration, time, of, every, task, , //每个工序的持续时间
n_duration_time = []

# y轴, 对应于画图位置的起始坐标y
# bay, id, of, every, task, , ==工序数目，即在哪一行画线
n_bay_start = []

# 机器号，可以根据机器号选择使用哪一种颜色
# n_job_id = [1, 9, 8, 2, 0, 4, 6, 9, 9, 0, 6, 4, 7, 1, 5, 8, 3, 8, 2, 1, 1, 8, 9, 6, 8, 5, 8, 4, 2, 0, 6, 7, 3, 0, 2, 1, 7, 0, 4, 9, 3, 7, 5, 9, 5, 2, 4, 3, 3, 7, 5, 4, 0, 6, 5]
n_job_id = []

op = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]

machine_detail = []

colors = ('rgb(46, 137, 205)',
          'rgb(114, 44, 121)',
          'rgb(198, 47, 105)',
          'rgb(58, 149, 136)',
          'rgb(107, 127, 135)',
          'rgb(46, 180, 50)',
          'rgb(150, 44, 50)',
          'rgb(100, 47, 150)',
          'rgb(58, 100, 180)',
          'rgb(150, 127, 50)',
          'rgb(100,100,100)',
          'rgb(110,100,100)',
          'rgb(120,100,100)')

millis_seconds_per_minutes = 1000 * 60
start_time = time.time() * 1000

job_sumary = {}

def handle(x, workpiece, process):
    # 输入：粒子的位置，输出：对工序部分处理后的列表
    piece_mark = np.zeros(workpiece)  # 统计工序的标志
    array = []  # 经过处理后的工序列表
    for i in range(workpiece*process):
        piece_mark[int(x[i]-1)] += 1
        array.append((int(x[i]), int(piece_mark[int(x[i]-1)])))
    return array

# 获取工件对应的第几道工序

def get_op_num(job_num):
    index = job_sumary.get(str(job_num))
    new_index = 1
    if index:
        new_index = index + 1
    job_sumary[str(job_num)] = new_index
    return new_index

# 仅仅用来排序 lamba函数表达不好

def my_sort(elum):
    return int(elum['Task'][1:])

# 用于显示机器占用情况
def create_draw_defination2(workpiece, process, n_table):
    df = []
    for index in range(len(machine_detail)):
        operation = {}
        # 机器，纵坐标
        # 工序号  纵坐标
        task_str = 'J' + str(machine_detail[index][3])
        operation['Task'] = task_str

        operation['Start'] = machine_detail[index][0]
        operation['Finish']=machine_detail[index][2]
        job_num = machine_detail[index][4]+1
        operation['Resource'] = 'M' + str(job_num)
        df.append(operation)
    df.sort(key=my_sort, reverse=True)
    return df

# 用于显示任务加工情况
def create_draw_defination(workpiece, process, n_table):
    df = []
    array = handle(n_bay_start, workpiece, process)
    for index in range(len(n_job_id)):
        machine_index = (array[index][0])*process+(array[index][1]-1)
        operation = {}
        # 机器，纵坐标
        # 工序号  纵坐标
        task_str = 'M' + str(n_bay_start.__getitem__(index)+1)
        operation['Task'] = task_str
        operation['Start'] = n_duration_time[index]
        job_num = op.index(n_job_id.__getitem__(machine_index)) + 1
        operation['Resource'] = 'J' + str(job_num)
        operation['my_duration'] = n_duration_time[index]
        df.append(operation)
    df.sort(key=my_sort, reverse=True)
    for i in range(workpiece):
        for j in range(process):
            df[i*process+j]['Finish'] = start_time.__add__(
                n_table[workpiece-i-1][j] * millis_seconds_per_minutes)
            df[i*process+j]['Start'] = df[i*process+j]['Finish'] - \
                df[i*process+j]['Start']*millis_seconds_per_minutes
            if df[i*process+j]['my_duration'] != 0:
                machine_detail.append([df[i*process+j]['Start'], df[i*process+j]['my_duration'],
                                       df[i*process+j]['Finish'], int(df[i*process+j]['Resource'][1:]),int(df[i*process+j]['Task'][1:])])
    #         df[i*process+j]['Start']= start_time if (i*process+j)%5==0 else df[i*process+j -1]['Finish']
    #         df[i*process+j]['Finish']=df[i*process+j]['Start'] + df[i*process+j]['Finish'] * millis_seconds_per_minutes
    machine_detail.sort(key=lambda x: x[3])
    return df

def draw_prepare(workpiece, process, n_table):
    df = create_draw_defination(workpiece, process, n_table)
    return ff.create_gantt(df, colors=colors, index_col='Resource',
                           title='最佳调度', show_colorbar=True,
                           group_tasks=True, data=n_duration_time,
                           showgrid_x=True, showgrid_y=True), df

def draw_prepare2(workpiece, process, n_table):
    df = create_draw_defination2(workpiece, process, n_table)
    return ff.create_gantt(df, colors=colors, index_col='Resource',
                           title='最佳调度', show_colorbar=True,
                           group_tasks=True, data=n_duration_time,
                           showgrid_x=True, showgrid_y=True), df

def add_annotations(fig, df):
    y_pos = 0
    for index in range(len(n_job_id)):

        y_pos = int(df[index]['Task'][1:])-1
        x_pos = (df[index]['Finish'] - df[index]
                 ['Start']) / 2 + df[index]['Start']
        # 工件，
        # job_num = op.index(n_job_id.__getitem__(index)) + 1
        job_num = int(df[index]['Resource'][1:])

        text = 'T: ' + str(df[index]['my_duration'])
        if df[index]['my_duration'] == 0:
            text = ''
        text_font = dict(size=7, color='black')
        fig['layout']['annotations'] += tuple(
            [dict(x=x_pos, y=y_pos, text=text, textangle=0, showarrow=False, font=text_font)])

        # fig['layout']['annotations'] += tuple(
        #     [dict(x=x_pos, y=y_pos,  showarrow=False)])

def add_annotations2(fig, df):
    for index in range(len(machine_detail)):
        # 计算 y pos地方 机器是跳着用的
        if index == 0:
            y_pos = 0
        if machine_detail[index][3] != machine_detail[index-1][3] and index > 0:
            y_pos = y_pos+1
        x_pos = (machine_detail[index][2] - machine_detail[index]
                 [0]) / 2 + machine_detail[index][0]
        text = 'T:'+str(machine_detail[index][1])
        # text = ''
        if machine_detail[index][1] == 0:
            text = ''
        text_font = dict(size=7, color='black')
        fig['layout']['annotations'] += tuple(
            [dict(x=x_pos, y=y_pos, text=text, textangle=0, showarrow=False, font=text_font)])

def draw_fjssp_gantt(draw_array):
    workpiece = draw_array[0]  # 工件数目
    process = draw_array[1]  # 每个工件的工序数目
    for i in range(workpiece*process):
        n_bay_start.append(int(draw_array[2][i]-1))
        n_job_id.append(int(draw_array[3][i]))
        n_duration_time.append(int(draw_array[4][i]))
        n_table = draw_array[5]
    fig, df = draw_prepare(workpiece, process, n_table)
    add_annotations(fig, df)
    project_path = os.path.dirname(os.path.abspath(__file__))
    py.offline.plot(fig, filename=project_path + '\\templates\\draw_pso.html')

    fig, df = draw_prepare2(workpiece, process, n_table)
    add_annotations2(fig, df)
    project_path = os.path.dirname(os.path.abspath(__file__))
    py.offline.plot(fig, filename=project_path +
                    '\\templates\\draw_pso-machine.html')

# if __name__ == '__main__':
#     draw_fjssp_gantt()


#INTILIZATION
#import Mail as mail
import ultra as mu
import MQ as msg
import DHT as dht
import bluetooth as blue
import temp_iot as iot
import time

#Flags
ml=0
mq=0
bl=0

while True:
 dht.DHT()
 time.sleep(1)
 iot.thermometer()
 while( ml <= 5):
  mu.ultra()
  time.sleep(1)
  ml+=1
 ml=0
 if(mq == 0):
  msg.MQ()
  mq+=1
  print("Message")
 mq=0
 while(bl <= 5):
  blue.blue()
  bl+=1
 bl=0
 time.sleep(5)


from copy import copy
from typing import Iterable, Union, Any
import pygame
import random
import os
from enum import Enum
from pygame.sprite import AbstractGroup

# Configuración
scrip_dir = os.path.dirname(__file__)
pygame.init()
fps = 60
clock = pygame.time.Clock()

ANCHO, ALTURA = (480, 320)
pantalla = pygame.display.set_mode((ANCHO, ALTURA))
objects = pygame.sprite.Group()
misiles = pygame.sprite.Group()

class EVENTOS(Enum):
    SPAWN_PIPE = pygame.USEREVENT + 1

class Misil(pygame.sprite.Sprite):
    def __init__(self, *groups) -> None:
        super().__init__(*groups)
        self.image = pygame.Surface((32, 16))
        self.image.fill((255, 215, 0))
        self.rect = self.image.get_rect()

    def update(self, dt):
        self.rect.x += 20 * dt
        if self.rect.x > ANCHO:
            self.kill()

class Ammo(pygame.sprite.Sprite):

    def __init__(self, *groups) -> None:
        super().__init__(*groups)
        self.image = pygame.image.load(
            os.path.join(scrip_dir, "sprites\\ammo.png")
        ).convert_alpha()
        self.rect = self.image.get_rect()

    def update(self, dt):
        self.rect.x -= 10 * dt
        if self.rect.x + self.rect.width < 0:
            self.kill()

class Area(pygame.sprite.Sprite):
    def __init__(self, rect, sprite_url, *groups) -> None:
        super().__init__(*groups)
        self.rect = rect
        self.image = pygame.image.load(os.path.join(scrip_dir, f"sprites\{sprite_url}"))
        self.image = pygame.transform.scale(self.image, (rect.width, rect.height))

    def update(self, dt):
        self.rect.x -= 10 * dt
        if self.rect.x + self.rect.width < 0:
            self.kill()

class Jugador(pygame.sprite.Sprite):
    def __init__(self, *groups) -> None:
        super().__init__(*groups)
        self.image = pygame.image.load(
            os.path.join(scrip_dir, "sprites\\flappy_bird.png")
        )
        self.rect = self.image.get_rect()
        self.rect.x = 30
        self.rect.y = ALTURA - 32
        self.salto = -20
        self.velocidad_y = 0
        self.ammo = 100

    def input(self):
        keys = pygame.key.get_pressed()
        if keys[pygame.K_SPACE]:
            self.velocidad_y = self.salto

    def shoot(self):
        if self.ammo > 0 and self.ammo != 0:
            self.ammo -= 2
            print(self.ammo)
            return self.rect.centerx, self.rect.centery
        return None, None

    def update(self, dt):
        self.input()
        self.velocidad_y += 4.5 * dt
        self.rect.y += self.velocidad_y * dt
        if self.rect.y + 32 >= ALTURA:
            self.rect.y = ALTURA - 32
            self.velocidad_y = 0
        if self.rect.y < 0:
            self.rect.y = 1

class Pipe(pygame.sprite.Group):
    def __init__(self, *sprites: Any | AbstractGroup | Iterable) -> None:
        super().__init__(*sprites)
        self.areas = self.genAreas(4)
        self.add(self.areas)

    def genAreas(self, numAreas):
        hueco = random.randint(0, numAreas - 1)
        ancho, alto = 50, ALTURA // numAreas
        areas = []
        for index in range(numAreas):
            if hueco == index:
                ammo = Ammo(objects)
                ammo.rect.centerx = ANCHO + 50 + ancho // 2
                ammo.rect.centery = index * alto + alto // 2
                continue
            rect = pygame.Rect(0, index * alto, ancho, alto)
            rect.x = ANCHO + 50
            area = Area(rect, self.chooseSprite(index, hueco), self)
            areas.append(area)
        return areas

    def chooseSprite(self, index, hueco):
        if index == hueco - 1:
            return "flappy_todown.png"
        elif index == hueco + 1:
            return "flappy_totop.png"
        return "flappy_pipe.png"

    def canBeRemoved(self):
        if all(area.rect.right <= 0 for area in self.areas):
            return True
        return False

# delta time
current_time = pygame.time.get_ticks()
previous_time = current_time
pipes_group = pygame.sprite.Group()
pipes = []
jugador = pygame.sprite.GroupSingle(Jugador())
pygame.time.set_timer(EVENTOS.SPAWN_PIPE.value, 3000)

while True:
    pantalla.fill((0, 255, 255))
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            break
        if event.type == pygame.KEYUP:
            if event.key == pygame.K_e:
                x, y = jugador.sprites()[0].shoot()
                if all([x, y]):
                    misil = Misil(misiles)
                    misil.rect.centerx = x
                    misil.rect.centery = y
        elif event.type == EVENTOS.SPAWN_PIPE.value:
            pipe = Pipe()
            pipes.append(pipe)
            pipes_group.add(pipe)
    # update
    deltatime = (current_time - previous_time) / 1000.0  # Tiempo en segundos
    previous_time = deltatime
    jugador.update(deltatime)
    pipes_group.update(deltatime)
    objects.update(deltatime)
    misiles.update(deltatime)

    if pygame.sprite.spritecollide(jugador.sprite, pipes_group, False):
        pipes_group.empty()
        pipes.clear()

    if pygame.sprite.groupcollide(misiles, pipes_group, True, True):
        pass

    if pygame.sprite.spritecollide(jugador.sprite, objects, True):
         jugador.sprites()[0].ammo += 1

    for pipe in pipes:
        if pipe.canBeRemoved():
            pipes.remove(pipe)
            pipes_group.remove(pipe)
    # Draw
    jugador.draw(pantalla)
    objects.draw(pantalla)
    pipes_group.draw(pantalla)
    misiles.draw(pantalla)
    # Final
    pygame.display.flip()
    clock.tick(fps)


from botocore.exceptions import ClientError

from .aws_helper import create_s3_session
from .config import create_config

default_bucket_name = "no-name-bucket"
region = "ru-central1"
endpoint_url = "https://storage.yandexcloud.net"

def initialize():
    bucket_name = default_bucket_name
    aws_access_key_id = input("input key id: ")
    aws_secret_access_key = input("input secret key: ")
    bucket_name = input("bucket name: ")

    try:
        s3 = create_s3_session(aws_access_key_id, aws_secret_access_key, endpoint_url, region)
        s3.create_bucket(Bucket=bucket_name, ACL='public-read-write')
    except ClientError as clientError:
        if clientError.response["Error"]["Code"] != "BucketAlreadyOwnedByYou":
            raise clientError

    create_config(access_key=aws_access_key_id, secret_key=aws_secret_access_key, bucket_name=bucket_name)


import pytest
import numpy as np

import time_evolving_mpo as tempo

# -----------------------------------------------------------------------------
# -- Test C: Spin-1 boson model -------------------------------------------------

# Initial state:
initial_state_C = np.array([[0.0,0.0,0.0],
                            [0.0,1.0,0.0],
                            [0.0,0.0,0.0]])

# System operator
h_sys_C = np.array([[1.0,0.0,0.0],
                    [0.0,0.5,0.0],
                    [0.0,0.0,0.0]])
h_sys_C += np.array([[0.0,0.5,0.0],
                     [0.5,0.0,0.5],
                     [0.0,0.5,0.0]])

# Markovian dissipation
gamma_C_1 = 0.1
gamma_C_2 = 0.2
lindblad_operators_C_1 = np.array([[0.0, 0.0, 0.0],
                                   [0.0, 0.0, 0.0],
                                   [0.0, 1.0, 0.0]])
lindblad_operators_C_2 = np.array([[0.5, 0.0, 0.0],
                                   [0.0,-0.5, 0.0],
                                   [0.0, 0.0, 0.0]])

# Ohmic spectral density with exponential cutoff
coupling_operator_C = np.array([[0.5, 0.0, 0.0],
                                [0.0,-0.5, 0.0],
                                [0.0, 0.0, 0.0]])
alpha_C = 0.3
cutoff_C = 5.0
temperature_C = 0.0

# end time
t_end_C = 1.0

# result obtained with release code (made hermitian, dkmax=10):
rho_C = np.array(
    [[ 0.12576653+0.j        ,-0.11739956-0.14312036j, 0.12211454-0.05963583j],
     [-0.11739956+0.14312036j, 0.61315893+0.j        ,-0.06636825+0.26917271j],
     [ 0.12211454+0.05963583j,-0.06636825-0.26917271j, 0.26107455+0.j        ]])

correlations_C = tempo.PowerLawSD(alpha=alpha_C,
                                  zeta=1.0,
                                  cutoff=cutoff_C,
                                  cutoff_type="exponential",
                                  temperature=temperature_C,
                                  name="ohmic",
                                  max_correlation_time=0.55)
bath_C = tempo.Bath(coupling_operator_C,
                    correlations_C,
                    name="phonon bath")
system_C = tempo.System(h_sys_C,
                        gammas=[gamma_C_1, gamma_C_2],
                        lindblad_operators=[lindblad_operators_C_1,
                                            lindblad_operators_C_2])

# -----------------------------------------------------------------------------

@pytest.mark.parametrize('backend',["tensor-network"])
def test_tensor_network_tempo_backend_C(backend):
    tempo_params_C = tempo.TempoParameters(dt=0.05,
                                           dkmax=10,
                                           epsrel=10**(-7))
    tempo_C = tempo.Tempo(system_C,
                          bath_C,
                          tempo_params_C,
                          initial_state_C,
                          start_time=0.0,
                          backend=backend)
    tempo_C.compute(end_time=1.0)
    dyn_C = tempo_C.get_dynamics()
    assert dyn_C.times[-1] == 1.0
    np.testing.assert_almost_equal(dyn_C.states[-1], rho_C, decimal=4)

@pytest.mark.parametrize('backend',["tensor-network"])
def test_tensor_network_pt_tempo_backend_C(backend):
    tempo_params_C = tempo.PtTempoParameters(dt=0.05,
                                             dkmax=10,
                                             epsrel=10**(-7))
    pt = tempo.pt_tempo_compute(
                bath_C,
                start_time=0.0,
                end_time=1.0,
                parameters=tempo_params_C,
                backend=backend)
    state = pt.compute_final_state_from_system(system=system_C,
                                               initial_state=initial_state_C)
    np.testing.assert_almost_equal(state, rho_C, decimal=4)

    dyn = pt.compute_dynamics_from_system(system=system_C,
                                          initial_state=initial_state_C)
    assert dyn.times[-1] == 1.0
    np.testing.assert_almost_equal(dyn.states[-1], rho_C, decimal=4)

# -----------------------------------------------------------------------------


#!/usr/bin/env python3
import logging
import socket
import traceback
import sys
import selectors
import json
import io
import struct

logging.basicConfig(level=logging.DEBUG, format="%(asctime)s %(levelname)s %(threadName)s %(name)s %(message)s")
logger = logging.getLogger('CLIENT')
logger.setLevel(logging.INFO)

def _create_request_message(methode, parameter):
    return dict(
        type="text/json",
        encoding="utf-8",
        content=dict(methode=methode, parameter=parameter),
    )

class Client:
    settings = None
    host = None
    port = None

    def send_server_request(self, methode, parameter):
        sel = selectors.DefaultSelector()
        address = (self.host, self.port)
        logger.info("Starting connection to %s", address)
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.setblocking(False)
        sock.connect_ex(address)
        events = selectors.EVENT_READ | selectors.EVENT_WRITE
        request = _create_request_message(methode, parameter)
        logger.info("Send %s | %s", methode, parameter)
        message = Message(sel, sock, address, request, self.pi_controller)
        sel.register(sock, events, data=message)

        try:
            while True:
                events = sel.select(timeout=1)
                for key, mask in events:
                    message = key.data
                    try:
                        message.process_events(mask)
                    except Exception:
                        logger.error("main: error: exception for %s: \n%s", message.addr, traceback.format_exc())
                        message.close()
                # Check for a socket being monitored to continue.
                if not sel.get_map():
                    break
        except KeyboardInterrupt:
            logger.error("Caught keyboard interrupt, exiting")
        finally:
            sel.close()

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

        with open("settings.json") as file:
            self.settings = json.load(file)

        self.host, self.port = self.settings["client"]["host-ip"], int(self.settings["client"]["host-port"])

class Message:
    def __init__(self, selector, sock, addr, request, controller):
        self.selector = selector
        self.sock = sock
        self.addr = addr
        self.request = request
        self._recv_buffer = b""
        self._send_buffer = b""
        self._request_queued = False
        self._jsonheader_len = None
        self.jsonheader = None
        self.response = None
        self.controller = controller

    def _set_selector_events_mask(self, mode):
        """Set selector to listen for events: mode is 'r', 'w', or 'rw'."""
        if mode == "r":
            events = selectors.EVENT_READ
        elif mode == "w":
            events = selectors.EVENT_WRITE
        elif mode == "rw":
            events = selectors.EVENT_READ | selectors.EVENT_WRITE
        else:
            raise ValueError(f"Invalid events mask mode {repr(mode)}.")
        self.selector.modify(self.sock, events, data=self)

    def _read(self):
        try:
            # Should be ready to read
            data = self.sock.recv(4096)
            logger.debug("Data received")
        except BlockingIOError:
            # Resource temporarily unavailable (errno EWOULDBLOCK)
            logger.error("Blocking errror")
            pass
        else:
            if data:
                self._recv_buffer += data
            else:
                raise RuntimeError("Peer closed.")

    def _write(self):
        if self._send_buffer:
            logger.debug("Sending %s to %s", repr(self._send_buffer), self.addr)
            try:
                # Should be ready to write
                sent = self.sock.send(self._send_buffer)
            except BlockingIOError:
                # Resource temporarily unavailable (errno EWOULDBLOCK)
                logger.error("BlockingIORead")
                pass
            else:
                self._send_buffer = self._send_buffer[sent:]

    def _json_encode(self, obj, encoding):
        return json.dumps(obj, ensure_ascii=False).encode(encoding)

    def _json_decode(self, json_bytes, encoding):
        tiow = io.TextIOWrapper(
            io.BytesIO(json_bytes), encoding=encoding, newline=""
        )
        obj = json.load(tiow)
        tiow.close()
        return obj

    def _create_message(
            self, *, content_bytes, content_type, content_encoding
    ):
        jsonheader = {
            "byteorder": sys.byteorder,
            "content-type": content_type,
            "content-encoding": content_encoding,
            "content-length": len(content_bytes),
        }
        jsonheader_bytes = self._json_encode(jsonheader, "utf-8")
        message_hdr = struct.pack(">H", len(jsonheader_bytes))
        message = message_hdr + jsonheader_bytes + content_bytes
        return message

    def _process_response_json_content(self):
        if self.response.get("methode") == "RESPONSE":
            logger.debug("Received Response: Methode: %s; Description: %s; Value: %s", self.response.get("methode"),
                        self.response.get("description"), self.response.get("value"))
        self.controller.process_response(self.response)

    def process_events(self, mask):
        if mask & selectors.EVENT_READ:
            self.read()
        if mask & selectors.EVENT_WRITE:
            self.write()

    def read(self):
        self._read()

        if self._jsonheader_len is None:
            self.process_protoheader()

        if self._jsonheader_len is not None:
            if self.jsonheader is None:
                self.process_jsonheader()

        if self.jsonheader:
            if self.response is None:
                self.process_response()

    def write(self):
        # INFO Wenn init request nicht geqeued ist, wird sie hier gequeued
        if not self._request_queued:
            self.queue_request()

        self._write()

        if self._request_queued:
            if not self._send_buffer:
                # Set selector to listen for read events, we're done writing.
                self._set_selector_events_mask("r")

    def close(self):
        logger.debug("Closing connection to %s", self.addr)
        try:
            self.selector.unregister(self.sock)
        except Exception as e:
            logger.error("error: selector.unregister() exception for %s: %s", self.addr, repr(e))

        try:
            self.sock.close()
        except OSError as e:
            logger.error("error: socket.close() exception for %s: %s", self.addr, repr(e))
        finally:
            # Delete reference to socket object for garbage collection
            self.sock = None

    def queue_request(self):
        content_type = self.request["type"]
        content_encoding = self.request["encoding"]
        content = self.request["content"]
        if content_type == "text/json":
            req = {
                "content_bytes": self._json_encode(content, content_encoding),
                "content_type": content_type,
                "content_encoding": content_encoding,
            }
        else:
            req = {
                "content_bytes": content,
                "content_type": content_type,
                "content_encoding": content_encoding,
            }
        message = self._create_message(**req)
        self._send_buffer += message
        self._request_queued = True

    def process_protoheader(self):
        hdrlen = 2
        if len(self._recv_buffer) >= hdrlen:
            self._jsonheader_len = struct.unpack(
                ">H", self._recv_buffer[:hdrlen]
            )[0]
            self._recv_buffer = self._recv_buffer[hdrlen:]

    def process_jsonheader(self):
        hdrlen = self._jsonheader_len
        if len(self._recv_buffer) >= hdrlen:
            self.jsonheader = self._json_decode(
                self._recv_buffer[:hdrlen], "utf-8"
            )
            self._recv_buffer = self._recv_buffer[hdrlen:]
            for reqhdr in (
                    "byteorder",
                    "content-length",
                    "content-type",
                    "content-encoding",
            ):
                if reqhdr not in self.jsonheader:
                    raise ValueError(f'Missing required header "{reqhdr}".')

    def process_response(self):
        content_len = self.jsonheader["content-length"]
        if not len(self._recv_buffer) >= content_len:
            return
        data = self._recv_buffer[:content_len]
        self._recv_buffer = self._recv_buffer[content_len:]
        if self.jsonheader["content-type"] == "text/json":
            encoding = self.jsonheader["content-encoding"]
            self.response = self._json_decode(data, encoding)
            self._process_response_json_content()
        # Close when response has been processed
        self.close()


import os
import math
import ast
import json
import cv2
import random

from langchain.chat_models import ChatOpenAI
from langchain.output_parsers import PydanticOutputParser

from langchain.chains import LLMChain

from LangChainPipeline.PromptTemplates.spatial_position_prompt import get_spatial_position_prompt_chat as get_spatial_position_prompt

from LangChainPipeline.PydanticClasses.Rectangle import Rectangle

from backend.image_processor import ImageProcessor

class SpatialChain():
    def __init__(
        self,
        verbose=False,
        top_k = 10,
        neighbors_left = 0,
        neighbors_right = 0,
        video_id="4LdIvyfzoGY",
        interval=10
    ):
        self.visual_metadata = None
        self.transcript_metadata = None
        self.interval = None
        self.video_id = None
        self.set_video(video_id, interval)
        self.position = SpatialPositionChain(verbose)
        self.image_processor = ImageProcessor()

        self.top_k = top_k
        self.neighbors_left = neighbors_left
        self.neighbors_right = neighbors_right
        print("Initialized SpatialChain")

    def set_video(self, video_id, interval):
        if self.video_id == video_id and self.interval == interval:
            return

        self.video_id = video_id

        self.is_combined = True
        metadata_filepath = f"metadata/{video_id}_{str(interval)}_combined.txt"
        if os.path.exists(metadata_filepath) == False:
            print("ERROR: Metadata file does not exist: ", metadata_filepath)
            metadata_filepath = f"metadata/{video_id}_{str(interval)}.txt"
            self.is_combined = False

        self.visual_metadata = []
        self.transcript_metadata = []
        with open(metadata_filepath) as f:
            raw_lines = f.readlines()
            for line in raw_lines:
                interval = ast.literal_eval(line.rstrip())
                visual_data = {
                    "action": interval["action_pred"],
                    "abstract_caption": interval["synth_caption"],
                    "dense_caption": interval["dense_caption"],
                }
                visual_data_str = (interval["synth_caption"].strip() + ", "
                    + interval["dense_caption"].strip() + ", "
                    + interval["action_pred"].strip())

                if self.is_combined:
                    visual_data = {
                        "action": interval["action_pred"],
                        "abstract_caption": interval["synth_caption"],
                        "objects": interval["objects"],
                        "dense_caption": interval["dense_caption_2"],
                    }
                    visual_data_str = (json.dumps(interval["synth_caption"]).strip() + ", "
                        + json.dumps(interval["dense_caption_2"]).strip() + ", "
                        + json.dumps(interval["action_pred"]).strip() + ", "
                        + json.dumps(interval["objects"]).strip())

                transcript = interval["transcript"].strip()
                self.visual_metadata.append({
                    "start": interval["start"],
                    "end": interval["end"],
                    "data": visual_data_str,
                    "structured_data": visual_data,
                })
                self.transcript_metadata.append({
                    "start": interval["start"],
                    "end": interval["end"],
                    "data": transcript,
                })
        print("Set video SpatialChain")

    def set_parameters(self, top_k, neighbors_left, neighbors_right):
        self.top_k = top_k
        self.neighbors_left = neighbors_left
        self.neighbors_right = neighbors_right
        # self.transcript.set_parameters(top_k, neighbors_left, neighbors_right)
        # self.visual.set_parameters(top_k, neighbors_left, neighbors_right)
        print("Set parameters SpatialChain")

    def process_visual_command(self, command, frame_sec, video_shape, offsets):
        input_images, input_bboxes, frame_id, img = self.image_processor.get_candidates_from_frame(frame_sec, self.video_id)
        bbox = self.image_processor.extract_related_crop(
            command[0],
            input_bboxes,
            input_images,
            frame_id,
            img
        )
        image_shape = img.shape
        candidate = {
            "x": bbox[0] / image_shape[1] * video_shape[1],
            "y": bbox[1] / image_shape[0] * video_shape[0],
            "width": bbox[2] / image_shape[1] * video_shape[1],
            "height": bbox[3] / image_shape[0] * video_shape[0],
            "rotation": 0,
            "source": command.copy(),
            "offsets": offsets.copy(),
        }
        return candidate

    def get_intersection(self, candidate1, candidate2):
        x1 = max(candidate1["x"], candidate2["x"])
        y1 = max(candidate1["y"], candidate2["y"])
        x2 = min(candidate1["x"] + candidate1["width"], candidate2["x"] + candidate2["width"])
        y2 = min(candidate1["y"] + candidate1["height"], candidate2["y"] + candidate2["height"])
        if x2 <= x1 or y2 <= y1:
            return {
                "x": 0,
                "y": 0,
                "width": 0,
                "height": 0,
                "info": ["Intersection"],
            }
        else:
            return {
                "x": x1,
                "y": y1,
                "width": x2 - x1,
                "height": y2 - y1,
                "info": ["Intersection"],
            }

    def get_union(self, candidate1, candidate2):
        x1 = min(candidate1["x"], candidate2["x"])
        y1 = min(candidate1["y"], candidate2["y"])
        x2 = max(candidate1["x"] + candidate1["width"], candidate2["x"] + candidate2["width"])
        y2 = max(candidate1["y"] + candidate1["height"], candidate2["y"] + candidate2["height"])
        return {
            "x": x1,
            "y": y1,
            "width": x2 - x1,
            "height": y2 - y1,
            "info": ["Union"],
        }

    def get_candidate_frame_sec(self, start, finish):
        result = int(start)
        if result < 0:
            result = 0
        if result > finish:
            print("WARNING: candidate frame sec: start > finish")
        return result

    def get_candidate_bboxes(self,
        start, finish,
        commands, labels, offsets,
        ref_timestamp, ref_bboxes,
        video_shape,
    ):
        ### if no visual-dependent & no sketches -> return full frame as candidate
        ### if no visual-dependent -> return sketches as candidates
        ### if visual-dependent -> return visual-dependent+sketches x segmentations (sum or argmax) as candidate
        ### if visual-dependent but no sketches -> return visual-dependent x segmentations (sum or argmax) as candidate
        vs_texts = []
        vs_offsets = []
        for i in range(len(commands)):
            if len(labels) <= i:
                print("ERROR: label not found", commands[i])
                continue
            if labels[i] == "visual-dependent":
                vs_texts.append(commands[i])
                vs_offsets.append(offsets[i])
        if len(vs_texts) == 0:
            if len(ref_bboxes) > 0:
                ### return sketches as candidates
                return [
                    {
                        "x": round(bbox["x"]),
                        "y": round(bbox["y"]),
                        "width": round(bbox["width"]),
                        "height": round(bbox["height"]),
                        "rotation": 0,
                        "info": ["Sketch"],
                        "source": ["sketch"],
                        "offsets": [-1],
                    } for bbox in ref_bboxes
                ]
            else:
                ### return full frame as candidate
                return [
                    {
                        "x": 0,
                        "y": 0,
                        "width": round(video_shape[1] / 2),
                        "height": round(video_shape[0] / 2),
                        "rotation": 0,
                        "info": ["Default location"],
                        "source": ["default"],
                        "offsets": [-1],
                    }
                ]
        if len(ref_bboxes) > 0:
            filename_prefix = "{}_{}".format(self.video_id, str(random.randint(0, 100000)))
            _, _, _, image = self.image_processor.get_candidates_from_frame(round(ref_timestamp), self.video_id)
            scaled_ref_bboxes = []
            for bbox in ref_bboxes:
                scaled_bbox = [
                    round(bbox['x'] / video_shape[1] * image.shape[1]),
                    round(bbox['y'] / video_shape[0] * image.shape[0]),
                    round(bbox['width'] / video_shape[1] * image.shape[1]),
                    round(bbox['height'] / video_shape[0] * image.shape[0]),
                ]
                scaled_ref_bboxes.append(scaled_bbox)
            output_ref_image = image.copy()
            for bbox in scaled_ref_bboxes:
                cv2.rectangle(output_ref_image, (bbox[0], bbox[1]), (bbox[0] + bbox[2], bbox[1] + bbox[3]), (0, 0, 255), 2)
            cv2.imwrite("./images/{}_!ref_image.jpg".format(filename_prefix), output_ref_image)
            ref_image = image.copy()

            (
                _, segmentation_bboxes, _, image
            ) = self.image_processor.get_candidates_from_frame(self.get_candidate_frame_sec(start, finish), self.video_id)

            (
                candidate_bbox_argmax,
                candidate_bbox_sum,
            ) = self.image_processor.get_candidate_ref_text_single(
                image.copy(),
                ref_image.copy(), segmentation_bboxes, vs_texts, scaled_ref_bboxes
            )
            final_candidate = candidate_bbox_sum
            return [{
                "x": round(final_candidate[0] / image.shape[1] * video_shape[1]),
                "y": round(final_candidate[1] / image.shape[0] * video_shape[0]),
                "width": round(final_candidate[2] / image.shape[1] * video_shape[1]),
                "height": round(final_candidate[3] / image.shape[0] * video_shape[0]),
                "rotation": 0,
                "info": ["Visual Dependent"],
                "source": vs_texts,
                "offsets": vs_offsets,
            }]
        else:
            (
                _, segmentation_bboxes, _, image
            ) = self.image_processor.get_candidates_from_frame(self.get_candidate_frame_sec(start, finish), self.video_id)
            (
                candidate_bbox_argmax,
                candidate_bbox_sum,
            ) = self.image_processor.get_candidate_text(
                image.copy(),
                segmentation_bboxes, vs_texts
            )
            final_candidate = candidate_bbox_sum
            return [{
                "x": round(final_candidate[0] / image.shape[1] * video_shape[1]),
                "y": round(final_candidate[1] / image.shape[0] * video_shape[0]),
                "width": round(final_candidate[2] / image.shape[1] * video_shape[1]),
                "height": round(final_candidate[3] / image.shape[0] * video_shape[0]),
                "rotation": 0,
                "info": ["Visual Dependent"],
                "source": vs_texts,
                "offsets": vs_offsets,
            }]

    def run(self,
        original_command,
        command, candidates, label,
        offsets,
        start, finish,
        video_shape,
    ):
        new_candidates = []
        if label == "independent":
            # left top
            context = [f"Frame Size: height: {str(video_shape[0])}, width: {str(video_shape[1])}",
                f'The original command was: {original_command}',
            ]
            for candidate in candidates:
                new_candidates.append(self.position.run(
                    context,
                    command,
                    candidate,
                    offsets,
                ))
        elif label == "visual-dependent":
            refining_candidates = [self.process_visual_command(command, self.get_candidate_frame_sec(start, finish), video_shape, offsets)]
            for candidate in candidates:
                for refinement in refining_candidates:
                    ### if there is intersection, then take the intersection
                    ### otherwise, take the union
                    intersection = self.get_intersection(candidate, refinement)
                    if intersection["width"] * intersection["height"] < 0.5 * refinement["width"] * refinement["height"]:
                        union = self.get_union(candidate, refinement)
                        if union["width"] * union["height"] > 2 * candidate["width"] * candidate["height"]:
                            continue
                        else:
                            candidate["x"] = round(union["x"])
                            candidate["y"] = round(union["y"])
                            candidate["width"] = round(union["width"])
                            candidate["height"] = round(union["height"])
                            candidate["info"].extend(union["info"])
                            candidate["source"].extend(refinement["source"])
                            candidate["offsets"].extend(refinement["offsets"])
                    else:
                        candidate["x"] = round(intersection["x"])
                        candidate["y"] = round(intersection["y"])
                        candidate["width"] = round(intersection["width"])
                        candidate["height"] = round(intersection["height"])
                        candidate["info"].extend(intersection["info"])
                        candidate["source"].extend(refinement["source"])
                        candidate["offsets"].extend(refinement["offsets"])
                new_candidates.append(candidate)
        elif label == "other":
            print("\"other\" label detected", command)
        else:
            print("ERROR: label not recognized", label)
            new_candidates = candidates
        #elif label == "condition":
            ### foreground/background rotoscoping
        return new_candidates

class SpatialPositionChain():
    def __init__(
            self,
            verbose=False,
    ):
        self.llm = ChatOpenAI(temperature=0.1, model_name="gpt-4-1106-preview")
        self.parser = PydanticOutputParser(pydantic_object=Rectangle)

        self.prompt_template = get_spatial_position_prompt({
            "format_instructions": self.parser.get_format_instructions(),
        })

        self.chain = LLMChain(
            llm=self.llm,
            prompt=self.prompt_template,
            verbose=verbose,
            output_parser=self.parser,
        )
        print("Initialized SpatialPositionChain")

    def run(self, context, command, candidate, offsets):
        try:
            result = self.chain.predict(
                context=json.dumps(context),
                command=json.dumps(command),
                rectangle=Rectangle.get_instance(
                    x=candidate["x"],
                    y=candidate["y"],
                    width=candidate["width"],
                    height=candidate["height"],
                    rotation=0,
                ).model_dump_json()
            )
        except:
            print("ERROR: Failed to parse: ", command)
            return candidate

        candidate["x"] = result.x
        candidate["y"] = result.y
        candidate["width"] = result.width
        candidate["height"] = result.height
        candidate["rotation"] = result.rotation
        candidate["info"].append("gpt")
        candidate["source"] = candidate["source"].copy() + command.copy()
        candidate["offsets"] = candidate["offsets"].copy() + offsets.copy()
        return candidate


#!/usr/bin/env python
# encoding:utf8

"""
    unittests
    =========

    :created: 2015 by Jens Diemer - www.jensdiemer.de
    :copyleft: 2015 by the DragonPy team, see AUTHORS for more details.
    :license: GNU GPL v3 or above, see LICENSE for more details.
"""

from __future__ import absolute_import, division, print_function

import unittest
from pygments.token import Token

from dragonlib.dragon32.pygments_lexer import BasicLexer

class TestHighlighting(unittest.TestCase):
    def test(self):
        lexer = BasicLexer()
        listing='10 PRINT"FOO"'
        tokensource = lexer.get_tokens(listing)
        self.assertEqual(list(tokensource), [
            (Token.Name.Label, '10'),
            (Token.Text, ' '),
            (Token.Name.Builtin, 'PRINT'),
            (Token.Literal.String, '"FOO"'),
            (Token.Text, '\n')
        ])


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

"""
@author: jbl
@time: 2021/10/6 9:57
"""
from typing import List

class Solution:
    def thirdMax(self, nums: List[int]) -> int:
        a = b = c = float('-inf')
        for n in nums:
            if n > c:
                a, b, c = b, c, n
            elif b < n < c:
                a, b = b, n
            elif a < n < b:
                a = n
            else:
                pass
        if a == float('-inf'):
            return c
        else:
            return a

# class Solution:
#     def thirdMax(self, nums: List[int]) -> int:
#         nums = set(nums)
#         if len(nums) < 3:
#             return max(nums)
#         heap = []
#         for n in nums:
#             heapq.heappush(heap, -n)
#         heapq.heappop(heap)
#         heapq.heappop(heap)
#         return -heapq.heappop(heap)

if __name__ == '__main__':
    solution = Solution()
    print(solution)