from io import BytesIO
from typing import Optional, Union
from pathlib import Path

from PIL import Image
import aiohttp

from hoshino import MessageSegment

from hoshino import res_dir
from hoshino.util.sutil import get_random_file, anti_harmony as anti_harmony_img

class ResImg:
    def __init__(self, abs_path: Union[str, Path]):
        if isinstance(abs_path, str):
            abs_path = Path(abs_path)
        #if not abs_path.is_relative_to(res_dir):
            #raise ValueError('Cannot access outside RESOUCE_DIR')
        self._path = abs_path

    @property
    def path(self):
        """资源文件的路径，供bot内部使用"""
        return self._path

    @property
    def cqcode(self) -> MessageSegment:
        with open(self.path, 'rb') as f:
            b = f.read()
        return MessageSegment.image(file=b)
        #return MessageSegment.image(f'file:///{os.path.abspath(self.path)}')

    @property
    def url(self) -> str:
        return self.path.as_uri()

    def open(self) -> Image.Image:
        try:
            return Image.open(self.path)
        except FileNotFoundError:
            print(f'缺少图片资源：{self.path}')
            raise

class ResRec:
    def __init__(self, abs_path: Union[str, Path]):
        if isinstance(abs_path, str):
            abs_path = Path(abs_path)
        #if not abs_path.is_relative_to(res_dir):
            #raise ValueError('Cannot access outside RESOUCE_DIR')
        self._path = abs_path

    @property
    def path(self):
        """资源文件的路径，供bot内部使用"""
        return self._path

    @property
    def cqcode(self) -> MessageSegment:
        with open(self.path, 'rb') as f:
            b = f.read()
        return MessageSegment.record(file=b)

    @property
    def url(self) -> str:
        return self.path.as_uri()

class Res:
    """
    Res资源封装类
    img 和 image 代表的分别为ResImg和 MessageSegment 对象
    img用于图像操作， image用于发送
    """
    base_dir = Path(res_dir)
    image_dir = base_dir.joinpath('image')
    record_dir = base_dir.joinpath('record')

    if not image_dir.exists():
        image_dir.mkdir()

    if not record_dir.exists():
        record_dir.mkdir()

    @classmethod
    def img(cls, p: Union[str, Path]) -> ResImg:
        if isinstance(p, str):
            p = Path(p)
        if p.exists():
            return ResImg(p)
        elif cls.image_dir.joinpath(p).exists():
            return ResImg(cls.image_dir.joinpath(p))
        else:
            raise ValueError('file not found')

    @classmethod
    def image(cls, p: Union[str, Path], anti_harmony: bool=False) -> MessageSegment:
        """
        将资源转换为可发送的图片
        params:
        p: 资源路径
        anti_harmony: 是否启用图片反和谐
        """
        img = cls.img(p).open()
        if anti_harmony:
            img = anti_harmony_img(img)
        return cls.image_from_memory(img)

    @classmethod
    def record(cls, p: Union[str, Path]) -> MessageSegment:
        if isinstance(p, str):
            p = Path(p)
        if p.exists():
            return ResRec(p).cqcode
        elif cls.record_dir.joinpath(p).exists():
            return ResRec(cls.record_dir.joinpath(p)).cqcode
        else:
            raise ValueError('file not found')

    @classmethod
    def get_random_img(cls, folder: Union[str, Path]) -> ResImg:
        """
        随机获取一个给定路径下的img， 以res_dir为基准目录
        """
        image_path = cls.base_dir.joinpath(folder)
        image_name = get_random_file(image_path)
        return cls.img(image_path.joinpath(image_name))

    @classmethod
    def get_random_record(cls, folder=None) -> MessageSegment:
        """
        随机获取一个给定路径下的record， 以res_dir为基准目录
        """
        record_path = cls.base_dir.joinpath(folder)
        rec_name = get_random_file(record_path)
        return cls.record(record_path.joinpath(rec_name))

    @classmethod
    def image_from_memory(cls, data: Union[bytes, Image.Image]) -> MessageSegment:
        if isinstance(data, Image.Image):
            out = BytesIO()
            data.save(out, format='png')
            data = out.getvalue()
        if not isinstance(data, bytes):
            raise ValueError(f'不支持的参数类型 {type(data)}')
        return MessageSegment.image(file=data, cache=False)

    @classmethod
    async def image_from_url(cls, url: str, anti_harmony: bool=False, timeout=30) -> MessageSegment:
        """
        download the image from url and return a MessageSegment in base64
        should be used in async function
        params:
        url: image url
        anti_harmony: bool = False 是否启用图片反和谐
        """
        timeout = aiohttp.ClientTimeout(total=timeout)
        async with aiohttp.ClientSession(timeout=timeout) as session:
            async with session.get(url) as resp:
                if resp.status != 200:
                    raise ValueError(f'请求失败 {resp.status}')
                data = await resp.read()
        if anti_harmony:
            data = anti_harmony_img(Image.open(BytesIO(data)))
        return cls.image_from_memory(data)


from django.urls import path

from . import views

app_name = "hangman"
urlpatterns = [
    path('', views.play, name='play'),
    path('reset/', views.reset, name='reset'),
    path('<str:letter>/', views.shot, name='shot'),
]


from datetime import tzinfo, timedelta, datetime
import json
from io import StringIO
import re
import sys
import os
import jmespath

from optparse import OptionParser
parser = OptionParser()

# take input report: path, project: which project; summary: whether it's summary
parser.add_option("-r", "--report", action="store", type="string", dest="report")
parser.add_option("-p", "--project", action="store", type="string", dest="project")
parser.add_option("-s", "--summary", action="store_true", dest="summary", default=False)

(options, args) = parser.parse_args(sys.argv)

# project is a subdir under the report dir
report_path=os.path.join(options.report, options.project)

# check everything is there
if not os.path.exists(report_path):
   print ("\nReport path for project {} does not exist. Please check the inputs.\n".format(options.project))
   quit()

# init project summary
project={}
project["name"]=options.project
project["iam"]=0
project["sas"]=0
project["violations"]=0
project["warnings"]=0
project["kms"]=0
project["vpcs"]=0
project["subnets"]=0
project["fwr"]=0
project["roles"]=0
project["peers"]=0

# init violation summaries for item
c2d1={}
c2d1["violation"]=False
c1d12={}
c1d12["violation"]=False
c2d8={}
c2d8["violation"]=False
c2d8["offendings"]=[]
c4d3={}
c4d3["violation"]=False
c4d3["offendings"]=[]
c4d1={}
c4d2={}
c4d1["violation"]=False
c4d1["offendings"]=[]
c4d2["violation"]=False
c4d2["offendings"]=[]

# read in iam
f = open(os.path.join(report_path, 'project-iam'))
iam = json.loads(f.read())
f.close()

# check iam policies
iam["totalAuditConfig"]=0
iam["hasAllServices"]=False
if "auditConfigs" in iam:
    iam["totalAuditConfig"]=len(iam["auditConfigs"])
    allservice = jmespath.search("auditConfigs[?service == 'allServices']", iam)
    if len(allservice) > 0 and len(allservice[0])==3:
      iam["hasAllServices"]=True

# check iam violations
if iam["totalAuditConfig"]==0:
  c2d1["violation"]=True
  project["violations"] += 1
elif not iam["hasAllServices"]:
  c2d1["violation"]=True
  c2d1["message"]="No audit settings found for this project. Please set it explicitly"

if "bindings" in iam:
  project["roles"] = len(iam["bindings"])
  members=jmespath.search("bindings[].members[]", iam)
  members=list(set(members))
  project["iam"] = len(members)
  sas=jmespath.search("[?starts_with(@, `serviceAccount:`)]", members)
  project["sas"] = len(sas)
  owner= jmespath.search("bindings[?role==`roles/owner` && members[?starts_with(@,`serviceAccount:`)]]", iam)

# check owner role violations
  if len(owner)>0:
      c1d12["violation"]=True
      c1d12["offendings"]=[]
      for onrs in owner:
        for onr in onrs["members"]:
          if onr.startswith('serviceAccount:'):
             project["violations"] += 1
             c1d12["offendings"].append(onr)

# check kms violations
kmsfile=os.path.join(report_path,'project-kms')
if os.path.isfile(kmsfile):
  with open(kmsfile) as fp:
    kstart=True
    for line in fp:
      line = re.sub('[\n"]','',line)
      if kstart:
        project["kms"] += 1
        kms=line
        kstart=False
      else:
          if line=="null":
              c2d8["violation"]=True
              project["violations"] += 1
              c2d8["offendings"].append(kms)
          else:
              line = re.sub('s', '', line)
              period = int(line) / 24/ 60 /60
              if period > 90:
                    c2d8["violation"]=True
                    project["violations"] += 1
                    c2d8["offendings"].append(kms)
          kstart=True

# read in network information
nwpath=os.path.join(report_path,'project-network')
f=open(nwpath)
network = json.loads(f.read())
f.close()
subspath=os.path.join(report_path,'project-subnets')
f=open(subspath)
subnets = json.loads(f.read())
f.close()

# init network summaries
dt = datetime.now()
dtstr = dt.isoformat(' ')
project["vpcs"] = len(network)
project["subnets"] = len(subnets)

noflowflag= jmespath.search("[?!enableFlowLogs]", subnets)

# check vpc violation
c4d3["violation"] = len(noflowflag) > 0
project["violations"] += len(noflowflag)
for sbn in noflowflag:
   c4d3["offendings"].append({"name":sbn["name"], "vpc":sbn["network"], "region": sbn["region"]})

# read firewall information
fwrpath=os.path.join(report_path,'project-firewall-rules')
f=open(fwrpath)
firewallrs = json.loads(f.read())
f.close()

def arr_in_range (arr, num):
   """
   this is a utility for testing port range array contains port number
   """
   return any([in_range(s, num) for s in arr])

def in_range(rg, num):
   """
   this is a utility for testing port range contains port number
   """
   if rg.isdigit():
      return int(rg) == num
   sar = rg.split('-')
   if len(sar)!=2:
      return False
   if not sar[0].isdigit() or int(sar[0]) > num:
      return False
   if not sar[1].isdigit() or int(sar[1]) < num:
      return False
   return True

# check firewall violations
project["fwr"] = len(firewallrs)
for rule in firewallrs:
    if any([s.startswith('0.0.0.0') for s in rule["sourceRanges"]]):
        for ald in rule["allowed"]:
            if ald["IPProtocol"] == 'tcp' and arr_in_range(ald["ports"],22):
                c4d1["violation"]=True
                c4d1["offendings"].append(rule)
                project["violations"] += 1
            if ald["IPProtocol"] == 'tcp' and arr_in_range(ald["ports"],3389):
                c4d2["violation"]=True
                c4d2["offendings"].append(rule)
                project["violations"] += 1
            if ald["IPProtocol"] == 'ssh':
                c4d1["violation"]=True
                c4d1["offendings"].append(rule)
                project["violations"] += 1
            if ald["IPProtocol"] == 'rdp':
                c4d2["violation"]=True
                c4d2["offendings"].append(rule)
                project["violations"] += 1

# check peer violations
peers=jmespath.search("[?peerings]", network)
c4d5={}
c4d5["warning"]=len(peers) > 0
c4d5["offendings"]=[]

for pr in peers:
    project["warnings"] += len(pr["peerings"])
    project["peers"] += len(pr["peerings"])
    for p in pr["peerings"]:
      c4d5["offendings"].append({"vpc": pr["name"], "state": p["state"], "network":p["network"]})

def do_offending():
  """
  print out html of each benchmark
  """
  print ("""

SMX Benchmark	Level	VPC	Findings

""")
  if c1d12["violation"]:
      for v in c1d12["offendings"]:
          print ("""
 	{}	{}	{}	{}
""".format("SMX-1.12", "Alert", "ALL", "Service account {} has an owner role".format(v)))

  if c2d1["violation"]:
      print ("""
 	{}	{}	{}	{}
""".format("SMX-2.1",
        "Alert","ALL", "No log audit settings found for this project. Please set it explicitely globally using 'allServices'"))

  if c2d8["violation"]:
     for k in c2d8["offendings"]:
       vio = "Cryptographic key {} does not have a rotation schedule or schedule period is longer that 90 days.".format(k)
       print ("""
 	{}	{}	{}	{}
""".format("SMX-2.8", "Alert", "ALL", vio))

  if c4d1["violation"]:
     for k in c4d1["offendings"]:
         print ("""
 	{}	{}	{}	Wide open SSH:
{}
""".format("SMX-4.1", "Alert", os.path.basename(k["network"]), json.dumps(k)))

  if c4d2["violation"]:
      for k in c4d2["offendings"]:
          print ("""
 	{}	{}	{}	Wide open RDP:
{}
""".format("SMX-4.2", "Alert", os.path.basename(k["network"]), json.dumps(k)))

  if c4d3["violation"]:
      for k in c4d3["offendings"]:
          print ("""
 	{}	{}	{}	Subnet flow log need to be turn on for subnet '{}' in region '{}'.
""".format("SMX-4.3", "Alert", os.path.basename(k["vpc"]), k["name"], os.path.basename(k["region"])))

  if c4d5["warning"]:
      for k in c4d5["offendings"]:
          print ("""
 	{}	{}	{}	Network Contains {} peered VPCs. Peer network security need to be checked to ensure security.

""".format("SMX-4.5", "Warning", k["vpc"], json.dumps(k)))

def do_summary():
  """
  print out html summary
  """
  html="""

            Scan Summary For Project: {}
            IAM Principals: {}
			Service Accounts: {}
            Cypher Keys: {}, Peer VPC: {}

            VPCs: {}
            Subnets: {}
            Firewall Rules: {}

            Violations: {}
            Warnings: {}
            Report Date: {}

  """.format(project["name"], project["iam"],project["sas"],project["kms"], project["peers"], project["vpcs"],project["subnets"], project["fwr"], project["violations"], project["warnings"], dtstr)
  print(html)

# this is the main - print out everything
print ("
")
do_summary()
do_offending()
print ("

")


#Дана последовательность чисел.
# Получить список уникальных элементов заданной последовательности,
# список повторяемых и убрать дубликаты из заданной последовательности.
#Пример:
#[1, 2, 3, 5, 1, 5, 3, 10] => [2, 10] и [1, 3, 5] и [1, 2, 5, 3, 10]
import itertools

lst_input = input('Введите последовательность чисел :  ')
lst_number = [int(num)for num in lst_input.split()]
lst_not_doble = list(set(lst_number))
lst_sort = sorted(lst_number)
lst_unique = []
lst_repeat = []
for num, lst_num in itertools.groupby(lst_sort):
    if len(list(lst_num)) ==1:
        lst_unique.append(num)
    else:
        lst_repeat.append(num)
print(f'Исходная последовательность чисел:   {lst_number}')
print(f'Список неповторяющихся чисел:   {lst_unique}')
print(f'Список повторяющихся чисел последовательности:   {lst_repeat}')
print(f'Список без дублей:   {lst_not_doble}')


import os
import pickle
import argparse
import pandas as pd

from vocab import WordVocab

from utils import split_camel

def parse_args():

    parser = argparse.ArgumentParser("Path Vocab Generation!!")

    # 数据的路径
    parser.add_argument('--data_path', type=str, default='/.../APathCS/path_data/',help="data location")
    # 数据的类型
    parser.add_argument('--data_name', type=str, default='example', help="dataset name")
    # 语言的类型
    parser.add_argument('--lang_type', type=str, default='java', help="different code type")
    # 词典的大小
    parser.add_argument("--vocab_size", default=None, type=int)
    # 最小频率
    parser.add_argument("--min_freq", default=1, type=int)

    return parser.parse_args()

def main():
    # 参数配置
    args = parse_args()

    # /path_data/exmaple/java/
    lang_path = os.path.join(args.data_path, args.data_name, args.lang_type)

    # /data/hugang/DeveCode/PSCS/data/exmaple/java/code_path/test/java
    input_path = os.path.join(lang_path,os.path.join('code_path','train',args.lang_type))
    # /data/hugang/DeveCode/PSCS/data/exmaple/java/processed
    out_path = os.path.join(lang_path, 'processed')

    # 根据词典将token转为数字，
    f = open(os.path.join(out_path,'descr_vocab.pickle'), 'rb')
    descrs_vocab = pickle.load(f)
    print(descrs_vocab)
    f.close()

    def protoken_func(x):
        #  字符串切成列表
        split_list = split_camel(x)
        #  列表转成数字
        num_list = descrs_vocab.to_seq(split_list)
        #  拼接数字串
        return ' '.join([str(i) for i in num_list])

    '''
    id	token
    14	empty
    78	concatMapEagerDelayError
    70	offer
    23	CheckReturnValue
    '''

    #  对代码的tokens做分词处理
    tokens_paths = [os.path.join(lang_path,os.path.join('code_path', i, args.lang_type, 'tokens.csv')) for i in ['train','test']]

    for tokens_path in tokens_paths:
        # 读取csv数据
        tokens = pd.read_csv(tokens_path)
        tokens['token_cut'] = tokens['token'].apply(protoken_func)
        tokens['token_cut'] = tokens['token_cut'].astype(str)
        tokens.to_csv(tokens_path, index=False)

    #node_types 包含 path_contexts和path指定的词
    node_path = os.path.join(input_path, 'node_types.csv')
    nodes_vocab = pd.read_csv(node_path)
    nodes_vocab['node_type'] = nodes_vocab.apply(lambda x: '_'.join(x['node_type'].split()), axis=1)

    '''
               id                          node_type
           0   43             ExpressionStatement_UP
           1    3       SingleVariableDeclaration_UP
    '''

    node_idx = nodes_vocab.set_index('id').to_dict(orient='dict')
    node_dict = node_idx['node_type']

    '''
    {'node_type': {43: 'ExpressionStatement_UP',... 3: 'SingleVariableDeclaration_UP'}
    '''

    paths_path = os.path.join(input_path, 'paths.csv')
    paths = pd.read_csv(paths_path)
    #path为数字转字符，先构建字典在映射
    paths['path_tokens'] = paths.apply(lambda x: ' '.join([node_dict.get(int(i), '<unk>') for i in x['path'].split(' ')]), axis=1)

    '''
        id         path                                path_tokens
    0    308       1 2 0 0 7 5           SimpleName_UP SimpleType_UP <unk> <unk> Method...
    1    309       1 6 39 40 7 5         SimpleName_UP MethodInvocation_UP ClassInstanc...
    '''
    path_words= paths['path_tokens'].values.tolist()

    vocab = WordVocab(path_words, max_size=args.vocab_size, min_freq=args.min_freq)
    print("VOCAB SIZE:", len(vocab))

    vocab.save_vocab(os.path.join(out_path, 'path_vocab.pickle'))

if __name__ == '__main__':
    main()


import pygame as pyg
import numpy as np
import os

from AI import simulation
from Game import tetris as tet

def activate_scene():
    pyg.font.init()

    current_simulation = simulation.Simulation(
        gen_size=22,
        n_allowed_to_reproduce=5,
        single_reproductions=2,
        max_mutation=1,
        mutation_chance=20,
    )

    GRID_THICKNESS = 2
    SQUARE_SIZE = 40

    X_SQUARES = 10
    Y_SQUARES = 20

    NON_GRID_WIDTH_LEFT = 400
    NON_GRID_WIDTH_RIGHT = 500

    WIDTH, HEIGHT = X_SQUARES * SQUARE_SIZE + GRID_THICKNESS * (
        X_SQUARES - 1
    ) + NON_GRID_WIDTH_LEFT + NON_GRID_WIDTH_RIGHT, Y_SQUARES * SQUARE_SIZE + GRID_THICKNESS * (
        Y_SQUARES - 1
    )

    RIGHT_AREA_OFFSET = WIDTH - NON_GRID_WIDTH_RIGHT

    WIN = pyg.display.set_mode((WIDTH, HEIGHT))
    pyg.display.set_caption("Tetrisonator-10000")

    icon = pyg.image.load(os.path.join("./assets", "Tetris_Logo.png"))
    pyg.display.set_icon(icon)

    # neuron_image = pyg.image.load(os.path.join('assets', "neuron.png"))
    # neuron_image = neuron_image

    grid_surf_vert = pyg.Surface((GRID_THICKNESS, HEIGHT))
    grid_surf_horiz = pyg.Surface(
        (WIDTH - NON_GRID_WIDTH_LEFT - NON_GRID_WIDTH_RIGHT + 2, GRID_THICKNESS)
    )

    grid_surf_vert.fill((50, 50, 50))
    grid_surf_horiz.fill((50, 50, 50))

    tetromino_surf = pyg.Surface((SQUARE_SIZE, SQUARE_SIZE))
    ghost_sprite = pyg.image.load(os.path.join("./assets", "ghost_square.png"))

    colour_by_tetromino_code = {
        1: (0, 255, 255),
        2: (0, 25, 200),
        3: (255, 170, 0),
        4: (255, 255, 0),
        5: (0, 255, 0),
        6: (125, 0, 125),
        7: (255, 0, 0),
    }

    FONT_SIZE = 50
    text_font = pyg.font.SysFont("monospace", FONT_SIZE)

    HOLD_LOCATION = 80

    NEXT_LOCATION = HOLD_LOCATION + 200
    LEVEL_LOCATION = NEXT_LOCATION + 250
    LINES_LOCATION = LEVEL_LOCATION + 150

    GENERATION_LOCATION = 0
    NETWORK_LOCATION = GENERATION_LOCATION + 275

    FPS = 720

    piece_distances = {
        1: (NON_GRID_WIDTH_LEFT - (4 * (SQUARE_SIZE + GRID_THICKNESS))) / 2,
        2: (NON_GRID_WIDTH_LEFT - (3 * (SQUARE_SIZE + GRID_THICKNESS))) / 2,
        3: (NON_GRID_WIDTH_LEFT - (3 * (SQUARE_SIZE + GRID_THICKNESS))) / 2,
        4: (NON_GRID_WIDTH_LEFT - (2 * (SQUARE_SIZE + GRID_THICKNESS))) / 2,
        5: (NON_GRID_WIDTH_LEFT - (3 * (SQUARE_SIZE + GRID_THICKNESS))) / 2,
        6: (NON_GRID_WIDTH_LEFT - (3 * (SQUARE_SIZE + GRID_THICKNESS))) / 2,
        7: (NON_GRID_WIDTH_LEFT - (3 * (SQUARE_SIZE + GRID_THICKNESS))) / 2,
    }

    RED_TUPLE = (255, 60, 60)

    def draw_window(
        grid_lines_vert: list[pyg.Rect],
        grid_lines_horiz: list[pyg.Rect],
        board: tet.TetrisBoard,
        _simulation: simulation.Simulation,
    ):
        # Blitting the ghost
        WIN.fill((0, 0, 0))
        for coord in board.active_piece.ghost.occupying_squares:
            WIN.blit(
                ghost_sprite,
                coord * SQUARE_SIZE
                + coord * GRID_THICKNESS
                + np.array([NON_GRID_WIDTH_LEFT + GRID_THICKNESS, 0]),
            )

        pieces_to_blit = board.all_pieces
        # Blitting all pieces
        for piece in pieces_to_blit:
            for coord in piece.occupying_squares:
                tetromino_surf.fill(colour_by_tetromino_code.get(piece.tetromino_code))
                WIN.blit(
                    tetromino_surf,
                    coord * SQUARE_SIZE
                    + coord * GRID_THICKNESS
                    + np.array([NON_GRID_WIDTH_LEFT + GRID_THICKNESS, 0]),
                )

        # Blitting the grid
        for grid_line in grid_lines_vert:
            WIN.blit(grid_surf_vert, (grid_line.x, grid_line.y))
        for grid_line in grid_lines_horiz:
            WIN.blit(grid_surf_horiz, (grid_line.x, grid_line.y))

        # BLitting the "hold" text
        hold_text_image = text_font.render("Hold", True, (255, 255, 255))
        WIN.blit(
            hold_text_image,
            ((NON_GRID_WIDTH_LEFT - hold_text_image.get_width()) / 2, HOLD_LOCATION),
        )

        # Blitting the held piece
        hold_piece = board.hold
        if hold_piece is not None:
            relative_coords = np.array(np.nonzero(a=hold_piece.base_rotation_grid)).T

            hold_piece_min_distance_from_left = piece_distances.get(
                hold_piece.tetromino_code
            )

            tetromino_surf.fill(colour_by_tetromino_code.get(hold_piece.tetromino_code))
            for coord in relative_coords:
                WIN.blit(
                    tetromino_surf,
                    coord * (SQUARE_SIZE + GRID_THICKNESS)
                    + np.array([hold_piece_min_distance_from_left, HOLD_LOCATION + 80]),
                )

        # Blitting the "Next" text
        hold_text_image = text_font.render("Next", True, (255, 255, 255))
        WIN.blit(
            hold_text_image,
            ((NON_GRID_WIDTH_LEFT - hold_text_image.get_width()) / 2, NEXT_LOCATION),
        )

        # Blitting the next piece
        next_piece = board.next
        relative_coords = np.array(np.nonzero(a=next_piece.base_rotation_grid)).T

        next_piece_min_distance_from_left = piece_distances.get(
            next_piece.tetromino_code
        )

        tetromino_surf.fill(colour_by_tetromino_code.get(next_piece.tetromino_code))
        for coord in relative_coords:
            WIN.blit(
                tetromino_surf,
                coord * (SQUARE_SIZE + GRID_THICKNESS)
                + np.array([next_piece_min_distance_from_left, NEXT_LOCATION + 80]),
            )

        # Blitting the score
        score_image = text_font.render(f"{board.score}", True, (255, 255, 255))
        WIN.blit(score_image, ((NON_GRID_WIDTH_LEFT - score_image.get_width()) / 2, 0))

        # BLitting the level
        level_text_image = text_font.render("level", True, (255, 255, 255))
        WIN.blit(
            level_text_image,
            ((NON_GRID_WIDTH_LEFT - level_text_image.get_width()) / 2, LEVEL_LOCATION),
        )

        level_image = text_font.render(f"{board.level}", True, (255, 255, 255))
        WIN.blit(
            level_image,
            ((NON_GRID_WIDTH_LEFT - level_image.get_width()) / 2, LEVEL_LOCATION + 50),
        )

        # Blitting the line count
        lines_text_image = text_font.render("lines", True, (255, 255, 255))
        WIN.blit(
            lines_text_image,
            ((NON_GRID_WIDTH_LEFT - lines_text_image.get_width()) / 2, LINES_LOCATION),
        )

        lines_count_image = text_font.render(
            f"{board.lines_on_level + (board.level - 1) * 10}", True, (255, 255, 255)
        )
        WIN.blit(
            lines_count_image,
            (
                (NON_GRID_WIDTH_LEFT - lines_count_image.get_width()) / 2,
                LINES_LOCATION + 50,
            ),
        )

        # Blitting the generation and unit
        generation_text_image = text_font.render("generation", True, (255, 255, 255))
        WIN.blit(
            generation_text_image,
            (
                RIGHT_AREA_OFFSET
                + (NON_GRID_WIDTH_RIGHT - generation_text_image.get_width()) / 2,
                GENERATION_LOCATION,
            ),
        )

        generation_image = text_font.render(
            f"{_simulation.generation + 1}", True, (255, 255, 255)
        )
        WIN.blit(
            generation_image,
            (
                RIGHT_AREA_OFFSET
                + (NON_GRID_WIDTH_RIGHT - generation_image.get_width()) / 2,
                GENERATION_LOCATION + 50,
            ),
        )

        unit_text_image = text_font.render("Player", True, (255, 255, 255))
        WIN.blit(
            unit_text_image,
            (
                RIGHT_AREA_OFFSET
                + (NON_GRID_WIDTH_RIGHT - unit_text_image.get_width()) / 2,
                GENERATION_LOCATION + 100,
            ),
        )

        unit_image = text_font.render(
            f"{_simulation.tetting_index + 1}", True, (255, 255, 255)
        )
        WIN.blit(
            unit_image,
            (
                RIGHT_AREA_OFFSET + (NON_GRID_WIDTH_RIGHT - unit_image.get_width()) / 2,
                GENERATION_LOCATION + 150,
            ),
        )

        # Blitting the neural network
        # blit_network(brain=simulation.active_tetting.brain)

        pyg.display.update()

    clock = pyg.time.Clock()
    run = True

    grid_rects_vert = [
        pyg.Rect(x, 0, GRID_THICKNESS, HEIGHT)
        for x in range(
            NON_GRID_WIDTH_LEFT,
            WIDTH - NON_GRID_WIDTH_RIGHT + 3,
            SQUARE_SIZE + GRID_THICKNESS,
        )
    ]
    grid_rects_horiz = [
        pyg.Rect(NON_GRID_WIDTH_LEFT, y, WIDTH, GRID_THICKNESS)
        for y in range(SQUARE_SIZE, HEIGHT, SQUARE_SIZE + GRID_THICKNESS)
    ]

    tetris_board = current_simulation.active_tetting.board
    current_simulation.next_piece()
    t = 1

    while run:
        clock.tick(FPS)

        for event in pyg.event.get():
            if event.type == pyg.QUIT:
                run = False

        current_simulation.update()

        if current_simulation.dead_tetting_flag:
            tetris_board = current_simulation.active_tetting.board

        draw_window(
            grid_lines_vert=grid_rects_vert,
            grid_lines_horiz=grid_rects_horiz,
            board=tetris_board,
            _simulation=current_simulation,
        )

        t += 1

    pyg.quit()

if __name__ == "__main__":
    activate_scene()


from flask.views import MethodView
from flask import request, jsonify, json

from traceback import print_exc

from block_compass.db import get_block_by_timestamp, get_chains

class Blocks(MethodView):
    def get(self):

        try:
            params = request.args.to_dict()
            timestamp = int(params['timestamp'])
            chain_ids = params.get('chain_ids')

            if chain_ids is None:
                chain_ids = [chain['id'] for chain in get_chains()]
            else:
                chain_ids = json.loads(chain_ids)

            blocks = {}
            for chain_id in chain_ids:
                blocks[chain_id] = get_block_by_timestamp(timestamp, chain_id)['number']

            return jsonify(success=True, blocks=blocks), 200

        except Exception as e:
            print_exc()
            return jsonify(success=False, message='Bad Request!'), 400


import logging
import os
import sys
from argparse import ArgumentParser, FileType

from erdpy import (cli_contracts, config, dependencies, errors, facade, ide,
                   nodedebug, projects, proxy, transactions)

def setup_parser_contract(subparsers):
    parser = subparsers.add_parser("contract")
    subparsers = parser.add_subparsers()

    sub = subparsers.add_parser("new", description="Create a new Smart Contract project based on a template.")
    sub.add_argument("name")
    sub.add_argument("--template", required=True, help="the template to use")
    sub.add_argument("--directory", type=str, default=os.getcwd(), help="the parent directory of the project")
    sub.set_defaults(func=create)

    sub = subparsers.add_parser("templates", description="List the available Smart Contract templates.")
    sub.add_argument("--json", action="store_true", help="whether to print the list in JSON format")
    sub.set_defaults(func=list_templates)

    sub = subparsers.add_parser("build", description="Build a Smart Contract project using the appropriate buildchain.")
    sub.add_argument("project", nargs='?', default=os.getcwd())
    sub.add_argument("--debug", action="store_true", default=False)
    sub.add_argument("--no-optimization", action="store_true", default=False)
    sub.set_defaults(func=build)

    sub = subparsers.add_parser("deploy", description="Deploy a Smart Contract.")
    sub.add_argument("project", nargs='?', default=os.getcwd(), help="the project directory")
    sub.add_argument("--proxy", required=True, help="the URL of the proxy")
    sub.add_argument("--pem", required=True, help="the PEM file of the owner")
    sub.add_argument("--arguments", nargs='+', help="constructor arguments")
    sub.add_argument("--gas-price", default=config.DEFAULT_GAS_PRICE, help="the gas price")
    sub.add_argument("--gas-limit", required=True, help="the gas limit")
    sub.add_argument("--value", default="0", help="the value to transfer")
    sub.add_argument("--metadata-upgradeable", action="store_true", default=False, help="whether the contract is upgradeable")
    sub.add_argument("--outfile", type=FileType("w"), default=sys.stdout, help="where to save the command's output")
    sub.set_defaults(func=deploy)

    sub = subparsers.add_parser("call")
    sub.add_argument("contract")
    sub.add_argument("--proxy", required=True)
    sub.add_argument("--pem", required=True)
    sub.add_argument("--function", required=True)
    sub.add_argument("--arguments", nargs='+')
    sub.add_argument("--gas-price", default=config.DEFAULT_GAS_PRICE)
    sub.add_argument("--gas-limit", required=True)
    sub.add_argument("--value", default="0")
    sub.set_defaults(func=call)

    sub = subparsers.add_parser("upgrade")
    sub.add_argument("contract")
    sub.add_argument("project")
    sub.add_argument("--proxy", required=True)
    sub.add_argument("--pem", required=True)
    sub.add_argument("--arguments", nargs='+')
    sub.add_argument("--gas-price", default=config.DEFAULT_GAS_PRICE)
    sub.add_argument("--gas-limit", required=True)
    sub.add_argument("--value", default="0")
    sub.add_argument("--metadata-upgradeable", action="store_true", default=False)
    sub.set_defaults(func=upgrade)

    sub = subparsers.add_parser("query")
    sub.add_argument("contract")
    sub.add_argument("--proxy", required=True)
    sub.add_argument("--function", required=True)
    sub.add_argument("--arguments", nargs='+')
    sub.set_defaults(func=query)

    # TODO: arwendebug
    # node_parser = subparsers.add_parser("nodedebug")
    # group = node_parser.add_mutually_exclusive_group()
    # group.add_argument('--stop', action='store_true')
    # group.add_argument('--restart', action='store_true', default=True)
    # node_parser.set_defaults(func=do_nodedebug)

    sub = subparsers.add_parser("test")
    sub.add_argument("project", nargs='?', default=os.getcwd())
    sub.add_argument("--directory", default="test")
    sub.add_argument("--wildcard", required=False)
    sub.set_defaults(func=run_tests)

    sub = subparsers.add_parser("ide")
    sub.add_argument("workspace", nargs='?', default=os.getcwd())
    sub.set_defaults(func=run_ide)

def list_templates(args):
    json = args.json
    projects.list_project_templates(json)

def create(args):
    name = args.name
    template = args.template
    directory = args.directory

    projects.create_from_template(name, template, directory)

def build(args):
    project = args.project
    options = {
        "debug": args.debug,
        "optimized": not args.no_optimization,
        "verbose": args.verbose
    }

    projects.build_project(project, options)

def deploy(args):
    facade.deploy_smart_contract(args)

def call(args):
    facade.call_smart_contract(args)

def upgrade(args):
    facade.upgrade_smart_contract(args)

def query(args):
    facade.query_smart_contract(args)

def run_tests(args):
    projects.run_tests(args)

def run_ide(args):
    workspace = args.workspace
    ide.run_ide(workspace)

# def do_nodedebug(args):
#     stop = args.stop
#     restart = args.restart

#     if restart:
#         nodedebug.stop()
#         nodedebug.start()
#     elif stop:
#         nodedebug.stop()
#     else:
#         nodedebug.start()


import os

from metalift.analysis_new import VariableTracker, analyze
from metalift.ir import *

import typing
from typing import Callable, Union, Protocol

from metalift.synthesis_common import SynthesisFailed, VerificationFailed

def observeEquivalence(
    inputState: Expr, synthState: Expr, queryParams: typing.List[Var]
) -> Expr:
    return Call("equivalence", Bool(), inputState, synthState, *queryParams)

def opsListInvariant(
    fnNameBase: str, synthState: Expr, synthStateType: Type, opType: Type
) -> Expr:
    return And(
        Eq(
            Call(
                "apply_state_transitions",
                synthStateType,
                TupleGet(synthState, IntLit(len(synthStateType.args) - 1)),
                Var(
                    f"{fnNameBase}_next_state",
                    FnT(synthStateType, synthStateType, *opType.args),
                ),
                Var(
                    f"{fnNameBase}_init_state",
                    FnT(synthStateType),
                ),
            ),
            synthState,
        ),
        Call(
            "ops_in_order",
            Bool(),
            TupleGet(synthState, IntLit(len(synthStateType.args) - 1)),
        ),
    )

def supportedCommand(synthState: Expr, args: typing.Any) -> Expr:
    return Call("supportedCommand", Bool(), synthState, *args)

def unpackOp(op: Expr) -> typing.List[Expr]:
    if op.type.name == "Tuple":
        return [TupleGet(op, IntLit(i)) for i in range(len(op.type.args))]
    else:
        return [op]

def opListAdditionalFns(
    synthStateType: Type,
    opType: Type,
    initState: Callable[[], Expr],
    inOrder: Callable[[typing.Any, typing.Any], Expr],
    opPrecondition: Callable[[typing.Any], Expr],
) -> typing.List[Union[FnDecl, FnDeclNonRecursive, Axiom]]:
    def list_length(l: Expr) -> Expr:
        return Call("list_length", Int(), l)

    def list_get(l: Expr, i: Expr) -> Expr:
        return Call("list_get", opType, l, i)

    def list_tail(l: Expr, i: Expr) -> Expr:
        return Call("list_tail", ListT(opType), l, i)

    data = Var("data", ListT(opType))
    next_state_fn = Var(
        "next_state_fn",
        FnT(
            synthStateType,
            synthStateType,
            *(opType.args if opType.name == "Tuple" else [opType]),
        ),
    )

    init_state_fn = Var("init_state_fn", FnT(synthStateType))

    reduce_fn = FnDecl(
        "apply_state_transitions",
        synthStateType,
        Ite(
            Eq(list_length(data), IntLit(0)),
            CallValue(init_state_fn),
            CallValue(
                next_state_fn,
                Call(
                    "apply_state_transitions",
                    synthStateType,
                    list_tail(data, IntLit(1)),
                    next_state_fn,
                    init_state_fn,
                ),
                *(
                    [
                        # TODO(shadaj): unnecessary cast
                        typing.cast(
                            Expr, TupleGet(list_get(data, IntLit(0)), IntLit(i))
                        )
                        for i in range(len(opType.args))
                    ]
                    if opType.name == "Tuple"
                    else [list_get(data, IntLit(0))]
                ),
            ),
        ),
        data,
        next_state_fn,
        init_state_fn,
    )

    next_op = Var("next_op", opType)
    ops_in_order_helper = FnDecl(
        "ops_in_order_helper",
        Bool(),
        And(
            opPrecondition(unpackOp(next_op)),
            Ite(
                Eq(list_length(data), IntLit(0)),
                BoolLit(True),
                And(
                    inOrder(unpackOp(list_get(data, IntLit(0))), unpackOp(next_op)),
                    Call(
                        "ops_in_order_helper",
                        Bool(),
                        list_get(data, IntLit(0)),
                        list_tail(data, IntLit(1)),
                    ),
                ),
            ),
        ),
        next_op,
        data,
    )

    ops_in_order = FnDecl(
        "ops_in_order",
        Bool(),
        Ite(
            Eq(list_length(data), IntLit(0)),
            BoolLit(True),
            Call(
                "ops_in_order_helper",
                Bool(),
                list_get(data, IntLit(0)),
                list_tail(data, IntLit(1)),
            ),
        ),
        data,
    )

    return [reduce_fn, ops_in_order_helper, ops_in_order]

class SynthesizeFun(Protocol):
    def __call__(
        self,
        basename: str,
        targetLang: typing.List[Union[FnDecl, FnDeclNonRecursive, Axiom]],
        vars: typing.Set[Var],
        invAndPs: typing.List[Synth],
        preds: Union[str, typing.List[Expr]],
        vc: Expr,
        loopAndPsInfo: typing.List[Expr],
        cvcPath: str = "cvc5",
        uid: int = 0,
        noVerify: bool = False,
        unboundedInts: bool = False,
        optimize_vc_equality: bool = False,
        listBound: int = 2,
        log: bool = True,
    ) -> typing.List[FnDecl]:
        ...

def synthesize_crdt(
    filename: str,
    fnNameBase: str,
    loopsFile: str,
    cvcPath: str,
    synthStateType: Type,
    initState: Callable[[], Expr],
    grammarStateInvariant: Callable[[Expr, int, int], Expr],
    grammarSupportedCommand: Callable[[Expr, typing.Any, int, int], Expr],
    inOrder: Callable[[typing.Any, typing.Any], Expr],
    opPrecondition: Callable[[typing.Any], Expr],
    grammar: Callable[[Expr, typing.List[Var], int], Expr],
    grammarQuery: Callable[[str, typing.List[Var], Type, int], Synth],
    grammarEquivalence: Callable[[Expr, Expr, typing.List[Var], int], Expr],
    targetLang: Callable[[], typing.List[Union[FnDecl, FnDeclNonRecursive, Axiom]]],
    synthesize: SynthesizeFun,
    stateTypeHint: typing.Optional[Type] = None,
    opArgTypeHint: typing.Optional[typing.List[Type]] = None,
    queryArgTypeHint: typing.Optional[typing.List[Type]] = None,
    queryRetTypeHint: typing.Optional[Type] = None,
    uid: int = 0,
    unboundedInts: bool = True,
    useOpList: bool = False,
    listBound: int = 1,
    baseDepth: int = 2,
    invariantBoost: int = 0,
    log: bool = True,
    skipSynth: bool = False,
) -> typing.List[FnDecl]:
    basename = os.path.splitext(os.path.basename(filename))[0]

    tracker = VariableTracker()

    state_transition_analysis = analyze(
        filename,
        fnNameBase + "_next_state",
        loopsFile,
    )

    query_analysis = analyze(
        filename,
        fnNameBase + "_response",
        loopsFile,
    )

    origSynthStateType = synthStateType

    op_arg_types = (
        [v.type for v in state_transition_analysis.arguments[1:]]
        if opArgTypeHint is None
        else opArgTypeHint
    )
    opType = TupleT(*op_arg_types) if len(op_arg_types) > 1 else op_arg_types[1]

    if useOpList:
        synthStateType = TupleT(*synthStateType.args, ListT(opType))

    queryParameterTypes = (
        [v.type for v in query_analysis.arguments[1:]]
        if queryArgTypeHint is None
        else queryArgTypeHint
    )

    def supportedCommandWithList(synthState: Expr, args: typing.Any) -> Expr:
        return And(
            opPrecondition(args),
            Ite(
                Eq(
                    Call(
                        "list_length",
                        Int(),
                        TupleGet(synthState, IntLit(len(synthStateType.args) - 1)),
                    ),
                    IntLit(0),
                ),
                BoolLit(True),
                inOrder(
                    unpackOp(
                        Call(
                            "list_get",
                            opType,
                            TupleGet(synthState, IntLit(len(synthStateType.args) - 1)),
                            IntLit(0),
                        )
                    ),
                    args,
                ),
            ),
        )

    seq_start_state = tracker.variable(
        "seq_start_state", state_transition_analysis.arguments[0].type
    )
    synth_start_state = tracker.variable("synth_start_state", synthStateType)
    equivalence_query_vars = [
        tracker.variable(
            f"start_state_query_var_{i}", query_analysis.arguments[i + 1].type
        )
        for i in range(len(query_analysis.arguments) - 1)
    ]

    synth_after_op = tracker.variable("synth_after_op", synthStateType)

    first_op_group = tracker.group("first_op")
    first_op_args = [
        first_op_group.variable(v.name(), t)
        for v, t in zip(state_transition_analysis.arguments[1:], op_arg_types)
    ]

    second_op_group = tracker.group("second_op")
    second_op_args = [
        second_op_group.variable(v.name(), t)
        for v, t in zip(state_transition_analysis.arguments[1:], op_arg_types)
    ]

    vcStateTransition = state_transition_analysis.call(seq_start_state, *first_op_args)(
        tracker,
        lambda seq_after_op: Implies(
            And(
                observeEquivalence(
                    seq_start_state, synth_start_state, equivalence_query_vars
                ),
                *(
                    [
                        opsListInvariant(
                            fnNameBase, synth_start_state, synthStateType, opType
                        ),
                        supportedCommandWithList(synth_start_state, first_op_args),
                    ]
                    if useOpList
                    else [
                        opPrecondition(first_op_args),
                        supportedCommand(synth_start_state, first_op_args),
                    ]
                ),
                Eq(
                    synth_after_op,
                    Call(
                        f"{fnNameBase}_next_state",
                        synthStateType,
                        synth_start_state,
                        *first_op_args,
                    ),
                ),
            ),
            query_analysis.call(seq_start_state, *equivalence_query_vars)(
                tracker,
                lambda seqQueryResult: Implies(
                    Eq(
                        seqQueryResult,
                        Call(
                            f"{fnNameBase}_response",
                            seqQueryResult.type,
                            synth_start_state,
                            *equivalence_query_vars,
                        ),
                    ),
                    And(
                        observeEquivalence(
                            seq_after_op, synth_after_op, equivalence_query_vars
                        ),
                        query_analysis.call(seq_after_op, *equivalence_query_vars)(
                            tracker,
                            lambda seqQueryResult: Eq(
                                seqQueryResult,
                                Call(
                                    f"{fnNameBase}_response",
                                    seqQueryResult.type,
                                    synth_after_op,
                                    *equivalence_query_vars,
                                ),
                            ),
                        ),
                        *(
                            [
                                Implies(
                                    And(
                                        inOrder(first_op_args, second_op_args),
                                        opPrecondition(second_op_args),
                                    ),
                                    supportedCommand(synth_after_op, second_op_args),
                                )
                            ]
                            if not useOpList
                            else []
                        ),
                    ),
                ),
            ),
        ),
    )

    # define synthesis problem for state transition
    cur_state_param = Var("cur_state", synthStateType)

    op_arg_vars = [
        Var(v.name(), t)
        for v, t in zip(state_transition_analysis.arguments[1:], op_arg_types)
    ]

    stateTransitionSynthNode = grammar(
        cur_state_param,
        op_arg_vars,
        baseDepth,
    )

    invAndPsStateTransition = (
        [
            Synth(
                fnNameBase + "_next_state",
                Tuple(
                    # the grammar directly produces the tupled next state, unpack to tack on the op-list
                    *stateTransitionSynthNode.args,
                    Call(
                        "list_prepend",
                        ListT(opType),
                        Tuple(*op_arg_vars) if len(op_arg_vars) > 1 else op_arg_vars[0],
                        TupleGet(
                            cur_state_param,
                            IntLit(len(synthStateType.args) - 1),
                        ),
                    ),
                ),
                cur_state_param,
                *op_arg_vars,
            )
        ]
        if useOpList
        else [
            Synth(
                fnNameBase + "_next_state",
                stateTransitionSynthNode,
                cur_state_param,
                *op_arg_vars,
            )
        ]
    )
    # end state transition (in order)

    # begin query
    invAndPsQuery = [
        grammarQuery(
            query_analysis.name,
            [Var(query_analysis.arguments[0].name(), synthStateType)]
            + (
                [
                    Var(query_analysis.arguments[i + 1].name(), queryArgTypeHint[i])
                    for i in range(len(queryArgTypeHint))
                ]
                if queryArgTypeHint
                else query_analysis.arguments[1:]
            ),
            query_analysis.return_type
            if queryRetTypeHint is None
            else queryRetTypeHint,
            baseDepth,
        )
    ]
    # end query

    # begin init state
    initState_analysis = analyze(
        filename,
        fnNameBase + "_init_state",
        loopsFile,
    )

    synthInitState = tracker.variable("synth_init_state", synthStateType)

    init_op_arg_vars = []
    for i, typ in enumerate(op_arg_types):
        init_op_arg_vars.append(tracker.variable(f"init_op_arg_{i}", typ))

    queryParamVars = [
        tracker.variable(
            f"init_state_equivalence_query_param_{i}",
            query_analysis.arguments[i + 1].type,
        )
        for i in range(len(query_analysis.arguments) - 1)
    ]

    vcInitState = initState_analysis.call()(
        tracker,
        lambda seqInitialState: Implies(
            Eq(synthInitState, Call(f"{fnNameBase}_init_state", synthStateType)),
            And(
                observeEquivalence(seqInitialState, synthInitState, queryParamVars),
                query_analysis.call(seqInitialState, *queryParamVars)(
                    tracker,
                    lambda seqQueryResult: Eq(
                        seqQueryResult,
                        Call(
                            f"{fnNameBase}_response",
                            seqQueryResult.type,
                            synthInitState,
                            *queryParamVars,
                        ),
                    ),
                ),
                BoolLit(True)
                if useOpList
                else Implies(
                    opPrecondition(init_op_arg_vars),
                    supportedCommand(synthInitState, init_op_arg_vars),
                ),
            ),
        ),
    )

    initStateSynthNode = initState()
    invAndPsInitState = [
        Synth(
            fnNameBase + "_init_state",
            Tuple(
                *initStateSynthNode.args,
                Call("list_empty", ListT(opType)),
            )
            if useOpList
            else Tuple(
                *initStateSynthNode.args,
            ),
        )
    ]
    # end init state

    # begin equivalence
    inputStateForEquivalence = Var(
        "inputState",
        state_transition_analysis.arguments[0].type
        if stateTypeHint is None
        else stateTypeHint,
    )
    synthStateForEquivalence = Var("synthState", synthStateType)

    equivalenceQueryParams = [
        Var(f"equivalence_query_param_{i}", queryParameterTypes[i])
        for i in range(len(queryParameterTypes))
    ]

    invAndPsEquivalence = [
        Synth(
            "equivalence",
            And(
                grammarEquivalence(
                    inputStateForEquivalence,
                    synthStateForEquivalence,
                    equivalenceQueryParams,
                    baseDepth,
                ),
                *(
                    [
                        grammarStateInvariant(
                            synthStateForEquivalence, baseDepth, invariantBoost
                        )
                    ]
                    if not useOpList
                    else []
                ),
            ),
            inputStateForEquivalence,
            synthStateForEquivalence,
            *equivalenceQueryParams,
        )
    ]

    synthStateForSupported = Var(f"supported_synthState", synthStateType)
    argList = [
        Var(
            f"supported_arg_{i}",
            op_arg_types[i],
        )
        for i in range(len(op_arg_types))
    ]
    invAndPsSupported = (
        [
            Synth(
                "supportedCommand",
                grammarSupportedCommand(
                    synthStateForSupported, argList, baseDepth, invariantBoost
                ),
                synthStateForSupported,
                *argList,
            )
        ]
        if not useOpList
        else []
    )
    # end equivalence

    if log:
        print("====== synthesis")

    combinedVCVars = set(tracker.all())

    combinedInvAndPs = (
        invAndPsStateTransition
        + invAndPsQuery
        + invAndPsInitState
        + invAndPsEquivalence
        + invAndPsSupported
    )

    combinedVC = And(vcStateTransition, vcInitState)

    lang = targetLang()
    if useOpList:
        lang = lang + opListAdditionalFns(
            synthStateType, opType, initState, inOrder, opPrecondition
        )

    if skipSynth:
        return  # type: ignore

    try:
        out = synthesize(
            basename,
            lang,
            combinedVCVars,
            combinedInvAndPs,
            [],
            combinedVC,
            [*combinedInvAndPs],
            cvcPath,
            uid=uid,
            unboundedInts=unboundedInts,
            noVerify=useOpList,
            listBound=listBound,
            log=log,
        )
    except VerificationFailed:
        # direct synthesis mode
        print(
            f"#{uid}: CVC5 failed to verify synthesized design, increasing Rosette data structure bounds to",
            listBound + 1,
        )
        return synthesize_crdt(
            filename,
            fnNameBase,
            loopsFile,
            cvcPath,
            origSynthStateType,
            initState,
            grammarStateInvariant,
            grammarSupportedCommand,
            inOrder,
            opPrecondition,
            grammar,
            grammarQuery,
            grammarEquivalence,
            targetLang,
            synthesize,
            stateTypeHint=stateTypeHint,
            opArgTypeHint=opArgTypeHint,
            queryArgTypeHint=queryArgTypeHint,
            queryRetTypeHint=queryRetTypeHint,
            uid=uid,
            unboundedInts=unboundedInts,
            useOpList=useOpList,
            listBound=listBound + 1,
            baseDepth=baseDepth,
            invariantBoost=invariantBoost,
            log=log,
        )

    if useOpList:
        print(
            f"#{uid}: Synthesizing invariants for unbounded verification (Rosette structure/history bound: {listBound})"
        )
        equivalence_fn = [x for x in out if x.args[0] == "equivalence"][0]
        state_transition_fn = [
            x for x in out if x.args[0] == f"{fnNameBase}_next_state"
        ][0]
        query_fn = [x for x in out if x.args[0] == f"{fnNameBase}_response"][0]
        init_state_fn = [x for x in out if x.args[0] == f"{fnNameBase}_init_state"][0]

        equivalence_fn.args[3] = Var(
            equivalence_fn.args[3].args[0],
            TupleT(*equivalence_fn.args[3].type.args[:-1]),
        )

        equivalence_fn.args[1] = equivalence_fn.args[1].rewrite(
            {equivalence_fn.args[3].args[0]: equivalence_fn.args[3]}
        )

        state_transition_fn.args[2] = Var(
            state_transition_fn.args[2].args[0],
            TupleT(*state_transition_fn.args[2].type.args[:-1]),
        )

        # drop the op-list
        state_transition_fn.args[1] = Tuple(
            *[
                e.rewrite(
                    {state_transition_fn.args[2].args[0]: state_transition_fn.args[2]}
                )
                for e in state_transition_fn.args[1].args[:-1]
            ]
        )

        query_fn.args[2] = Var(
            query_fn.args[2].args[0], TupleT(*query_fn.args[2].type.args[:-1])
        )

        query_fn.args[1] = query_fn.args[1].rewrite(
            {query_fn.args[2].args[0]: query_fn.args[2]}
        )

        init_state_fn.args[1] = Tuple(*init_state_fn.args[1].args[:-1])

        try:
            # attempt to synthesize the invariants
            return synthesize_crdt(
                filename,
                fnNameBase,
                loopsFile,
                cvcPath,
                origSynthStateType,
                lambda: init_state_fn.args[1],  # type: ignore
                grammarStateInvariant,
                grammarSupportedCommand,
                inOrder,
                opPrecondition,
                lambda inState, args, _baseDepth: typing.cast(
                    Expr, state_transition_fn.args[1]
                ).rewrite(
                    {
                        cur_state_param.name(): inState,
                        **{orig.name(): new for orig, new in zip(op_arg_vars, args)},
                    }
                ),
                lambda _name, _args, _retT, _baseDepth: Synth(
                    query_fn.args[0], query_fn.args[1], *query_fn.args[2:]
                ),
                lambda a, b, _baseDepth, _invariantBoost: equivalence_fn.args[1],  # type: ignore
                targetLang,
                synthesize,
                stateTypeHint=stateTypeHint,
                opArgTypeHint=opArgTypeHint,
                queryArgTypeHint=queryArgTypeHint,
                queryRetTypeHint=queryRetTypeHint,
                uid=uid,
                unboundedInts=unboundedInts,
                useOpList=False,
                listBound=listBound,
                baseDepth=baseDepth,
                invariantBoost=invariantBoost,
                log=log,
            )
        except SynthesisFailed:
            try:
                # try to re-verify with a larger bound
                print(
                    f"#{uid}: re-verifying with history bound {listBound + 1} and attempting to re-synthesize invariants with deeper grammar"
                )
                return synthesize_crdt(
                    filename,
                    fnNameBase,
                    loopsFile,
                    cvcPath,
                    origSynthStateType,
                    lambda: init_state_fn.args[1],  # type: ignore
                    grammarStateInvariant,
                    grammarSupportedCommand,
                    inOrder,
                    opPrecondition,
                    lambda inState, args, _baseDepth: typing.cast(
                        Expr, state_transition_fn.args[1]
                    ).rewrite(
                        {
                            cur_state_param.name(): inState,
                            **{
                                orig.name(): new for orig, new in zip(op_arg_vars, args)
                            },
                        }
                    ),
                    lambda _name, args, _retT, _baseDepth: Synth(
                        query_fn.args[0], query_fn.args[1], *args
                    ),
                    lambda a, b, c, _baseDepth: equivalence_fn.args[1],  # type: ignore
                    targetLang,
                    synthesize,
                    stateTypeHint=stateTypeHint,
                    opArgTypeHint=opArgTypeHint,
                    queryArgTypeHint=queryArgTypeHint,
                    queryRetTypeHint=queryRetTypeHint,
                    uid=uid,
                    unboundedInts=unboundedInts,
                    useOpList=useOpList,
                    listBound=listBound + 1,
                    baseDepth=baseDepth,
                    invariantBoost=invariantBoost + 1,
                    log=log,
                )
            except SynthesisFailed:
                print(
                    f"#{uid}: could not synthesize invariants, re-synthesizing entire design with history bound {listBound + 1}"
                )
                return synthesize_crdt(
                    filename,
                    fnNameBase,
                    loopsFile,
                    cvcPath,
                    origSynthStateType,
                    initState,
                    grammarStateInvariant,
                    grammarSupportedCommand,
                    inOrder,
                    opPrecondition,
                    grammar,
                    grammarQuery,
                    grammarEquivalence,
                    targetLang,
                    synthesize,
                    stateTypeHint=stateTypeHint,
                    opArgTypeHint=opArgTypeHint,
                    queryArgTypeHint=queryArgTypeHint,
                    queryRetTypeHint=queryRetTypeHint,
                    uid=uid,
                    unboundedInts=unboundedInts,
                    useOpList=useOpList,
                    listBound=listBound + 1,
                    baseDepth=baseDepth,
                    invariantBoost=invariantBoost,
                    log=log,
                )
    else:
        return out


import logging
import requests
import json
import sys
import config
from pathlib import Path
from abc import ABC, abstractmethod
from utils import convert_webp_webm, convert_webp_png, check_directories, progressBar

logger = logging.getLogger("run")

class BaseEmote(ABC):
    def __init__(self, url, all_variants: bool = False):
        self.url: str = url
        self.emote_id: str = ""
        self.name: str = ""
        self.animated: bool = False
        self.api_emote_url: str = ""
        self.cdn_url: str = ""
        self.cdn_file_name = ""
        self.filepath = None
        self.all_variants = all_variants

    @classmethod
    @abstractmethod
    def get_emote_details(cls) -> None:
        pass

    @classmethod
    @abstractmethod
    def download_emote(cls) -> None:
        pass

    @classmethod
    @abstractmethod
    def get_emote_id(cls):
        pass

    def process_emote(self):
        self.get_emote_id()
        self.get_emote_details()
        self.download_emote()
        if self.animated:
            convert_webp_webm(self.filepath, self.name)
        else:
            convert_webp_png(self.filepath, self.name)

class SevenTVEmote(BaseEmote):
    def __init__(self, url):
        super().__init__(url)
        self.api_emote_url = "https://7tv.io/v3/emotes/"
        self.cdn_url = "http://cdn.7tv.app/emote/"
        self.cdn_file_name = "4x.webp"

    def get_emote_id(self):
        self.emote_id = self.url.split("/")[-1]

    def get_emote_details(self):
        url = self.api_emote_url + self.emote_id
        response = requests.get(url)
        if response.status_code == 200:
            response_dict = json.loads(response.content.decode("utf-8"))
            self.name = response_dict["name"]
            self.animated = response_dict["animated"]
        else:
            logger.error(f"Failed to get emote name of id: {self.emote_id}. Status code: {response.status_code}")

    def download_emote(self):
        download_url = self.cdn_url + self.emote_id + "/" + self.cdn_file_name
        self.filepath = Path(config.TEMP_FOLDER + self.name + "_" + self.cdn_file_name)
        response = requests.get(download_url)
        if response.status_code == 200:
            with open(self.filepath, "wb") as file:
                file.write(response.content)
            logger.info(f"Emote file with id {self.emote_id} downloaded successfully.")
        else:
            logger.error(f"Failed to download emote file with id {self.emote_id}. Status code:", response.status_code)

class BetterTTVEmote(BaseEmote):
    def __init__(self, url):
        super().__init__(url)
        self.api_emote_url = "https://api.betterttv.net/3/emotes/"
        self.cdn_url = "https://cdn.betterttv.net/emote/"
        self.cdn_file_name = "3x.webp"

    def get_emote_details(self):
        url = self.api_emote_url + self.emote_id
        response = requests.get(url)
        if response.status_code == 200:
            response_dict = json.loads(response.content.decode("utf-8"))
            self.name = response_dict["code"]
            self.animated = response_dict["animated"]
        else:
            logger.error(f"Failed to get emote name of id: {self.emote_id}. Status code: {response.status_code}")

    def download_emote(self):
        download_url = self.cdn_url + self.emote_id + "/" + self.cdn_file_name
        self.filepath = Path(config.TEMP_FOLDER + self.name + "_" + self.cdn_file_name)
        response = requests.get(download_url)
        if response.status_code == 200:
            with open(self.filepath, "wb") as file:
                file.write(response.content)
            logger.info(f"Emote file with id {self.emote_id} downloaded successfully.")
        else:
            logger.error(f"Failed to download emote file with id {self.emote_id}. Status code:", response.status_code)

    def get_emote_id(self):
        self.emote_id = self.url.split("/")[-1]

class FrankFaseZEmote(BaseEmote):
    def __init__(self, url):
        super().__init__(url)
        self.api_emote_url = "https://api.frankerfacez.com/v2/emote/"
        self.cdn_url = "https://cdn.frankerfacez.com/emote/"
        self.cdn_file_name = ""

    def get_emote_details(self):
        url = self.api_emote_url + self.emote_id
        response = requests.get(url)
        if response.status_code == 200:
            response_dict = json.loads(response.content.decode("utf-8"))
            self.name = response_dict["emote"]["name"]
            self.animated = response_dict["emote"]["animated"]
        else:
            logger.error(f"Failed to get emote name of id: {self.emote_id}. Status code: {response.status_code}")

    def download_emote(self):
        if self.animated:
            download_url = self.cdn_url + self.emote_id + "/animated/4"
        else:
            download_url = self.cdn_url + self.emote_id + "/4"
        self.filepath = Path(config.TEMP_FOLDER + self.name + ".webp")
        response = requests.get(download_url)
        if response.status_code == 200:
            with open(self.filepath, "wb") as file:
                file.write(response.content)
            logger.info(f"Emote file with id {self.emote_id} downloaded successfully.")
        else:
            logger.error(f"Failed to download emote file with id {self.emote_id}. Status code:", response.status_code)

    def get_emote_id(self):
        self.emote_id = self.url.split("/")[-1].split("-")[0]

def main():

    urls = []
    urls_file = "emote_links.txt"
    with open(urls_file, "r") as f:
        urls.extend([line.strip() for line in f.readlines()])

    logger.info(f"Links: {urls}")
    if "--all" in sys.argv:
        config.ALL_VARIANTS = True
    if urls:
        check_directories()
    for url in progressBar(urls, prefix="Progress:", suffix="Complete", length=50):
        try:
            if "7tv.app" in url:
                emote = SevenTVEmote(url)
            elif "betterttv.com" in url:
                emote = BetterTTVEmote(url)
            elif "frankerfacez.com" in url:
                emote = FrankFaseZEmote(url)
            else:
                continue
            emote.process_emote()
        except Exception as e:
            logger.exception(f"Exception caught while processing {url}: {e}")

# TODO: add poetry
# TODO: update calling with args
if __name__ == "__main__":
    if sys.argv:
        logger.info(f"Args: {sys.argv}")
    main()


import xml_to_od
from _ectt_to_od import ectt_data
from Models.instance import instance
from _objective_function import objective_function
from _initial_solution import initial_solution
from _roulette_wheel_selection import roulette_wheel_selection
from _simulated_annealing import simulated_annealing
from _operators_lookup import operators_lookup
import random
import math
import copy
import time
from Experiments.parameters import parameters
from Experiments.configs import configs
from Experiments.statistics import statistics
import uuid

class alns:

    def __init__(self):

        # Get data from instance file
        if configs.instance_type == 1:
            raw_data = xml_to_od.xml_data()
        else:
            raw_data = ectt_data()

        self.instance_data = instance(raw_data)

        #  It turns out that the usage of different percentages depending on the instance size is beneficial,
        #  i.e., ds is used for small instances with less than 280 lectures and dl for larger instances.
        if self.instance_data.total_lectures <= 280:
            self.destroy_permille = parameters.ds
        else:
            self.destroy_permille = parameters.dl

    # main function to find solution of CB-CTT instance using ALNS
    def find_optimal_solution(self, solution, Uc):
        # reset statistics value
        statistics_instance = statistics()
        statistics_instance.reset()

        obj_func_instance = objective_function("UD2", self.instance_data)

        current_best = solution

        # Calculate cost/objective function of current solution
        current_cost, courses_penalties, curricula_penalties = obj_func_instance.cost(solution)

        avg_cost = current_cost / self.instance_data.total_lectures
        unassigned_lectures_cost = max(float(1), float(avg_cost))
        current_cost += unassigned_lectures_cost * len(Uc)

        global_best = current_best
        global_best_cost = current_cost
        global_best_has_uc = len(Uc) > 0

        if global_best_cost == 0:
            return global_best, global_best_cost

        #  The reference destroy limit nmax 0 is set to d percent of the total number of lectures.
        # calculate upper bound for events to be destoryed
        destroy_upper_bound = self.instance_data.total_lectures * self.destroy_permille
        iteration = 0
        no_best_found_count = 0
        # destroy limit based on iterations since limit -> limit increased after reheat
        iterations_since_reheat = 0
        remaining_iterations = parameters.iteration_limit
        ref_iter_limit = parameters.iteration_limit

        time_start = time.time()

        SA = simulated_annealing(current_cost)

        while (time.time() - time_start) < parameters.time_limit:
            deviation_ref_iter = (remaining_iterations + iterations_since_reheat) - ref_iter_limit
            destroy_decrease_power = math.log((parameters.destroy_decrease - 1) * destroy_upper_bound / parameters.destroy_decrease) \
                                     / math.log(ref_iter_limit + deviation_ref_iter)
            iteration += 1
            iterations_since_reheat += 1
            statistics.iterations += 1
            print("Iteration: ", iteration)
            remaining_iterations = parameters.iteration_limit - ((time.time()-time_start)/parameters.time_limit) * parameters.iteration_limit
            print("Remaining Iterations: ", remaining_iterations)
            # -------------------------------------------------------------------------------------------------------------------- #
            removal_operators_probabilities = roulette_wheel_selection.get_probability_list(operators_lookup.removal_operators_weights)
            # print("Removal Operators Probabilities: ", removal_operators_probabilities)
            removal_operator_index = roulette_wheel_selection.spin_roulettewheel(removal_operators_probabilities)

            repair_operators_probabilities = roulette_wheel_selection.get_probability_list(operators_lookup.repair_operators_weights)
            # print("Repair Operators Probabilities: ", repair_operators_probabilities)

            # GA algorithm in our case it is designed in that way
            # that it will always expect that there is always at least on feasible spot for every unscheduled lecture
            # under the assumption that the unscheduled lectures were removed from a feasibile schedule
            # hence, if we have unfeasible solution we need to handle it with 2 stage repair operator instead
            print("Uc: ", Uc)
            if Uc:
                repair_operator_index = 0
            else:
                repair_operator_index = roulette_wheel_selection.spin_roulettewheel(repair_operators_probabilities)

            lecture_period_operators_probabilities = roulette_wheel_selection.get_probability_list(operators_lookup.lecture_period_operators_weights)
            # print("Lecture-Period Operators Probabilities: ", lecture_period_operators_probabilities)
            lecture_period_operator_index = roulette_wheel_selection.spin_roulettewheel(lecture_period_operators_probabilities)
            if lecture_period_operator_index == 0:
                statistics.two_stage_best_count += 1
            elif lecture_period_operator_index == 1:
                statistics.two_stage_mean_count += 1

            lecture_room_operators_probabilities = roulette_wheel_selection.get_probability_list(operators_lookup.lecture_room_operators_weights)
            # print("Lecture-Room Operators Probabilities: ", lecture_period_operators_probabilities)
            lecture_room_operator_index = roulette_wheel_selection.spin_roulettewheel(lecture_room_operators_probabilities)
            if lecture_period_operator_index == 0:
                statistics.two_stage_greatest_count += 1
            elif lecture_period_operator_index == 1:
                statistics.two_stage_match_count += 1

            priority_rules_probabilities = roulette_wheel_selection.get_probability_list(operators_lookup.priority_rules_weights)
            # print("Priority Rules Probabilities: ", lecture_period_operators_probabilities)
            priority_rule_index = roulette_wheel_selection.spin_roulettewheel(priority_rules_probabilities)
            if lecture_period_operator_index == 0:
                statistics.saturation_degree_count += 1
            elif lecture_period_operator_index == 1:
                statistics.largest_degree_count += 1
            else:
                statistics.random_order_count += 1

            # -------------------------------------------------------------------------------------------------------------------- #
            # number of events to be destroyed (lectures to remove) in this iteration
            destroy_limit = min(self.instance_data.total_lectures - len(Uc), parameters.min_destroy_lectures +
                                (random.randrange(max(parameters.min_destroy_lectures, round(destroy_upper_bound) - round(math.pow(iterations_since_reheat, destroy_decrease_power))))))

            # Find neighbor solution by applying destruction/repair operator to the current solution
            solution_clone = copy.deepcopy(solution)
            new_sol, Uc = self.neighbor(solution_clone, destroy_limit,
                                    removal_operator_index, repair_operator_index, lecture_period_operator_index, lecture_room_operator_index, priority_rule_index,
                                    courses_penalties, curricula_penalties, Uc)

            print("Uc: ", Uc)
            if new_sol is not None:
                # Calculate the new solution's cost
                new_cost, courses_penalties, curricula_penalties = obj_func_instance.cost(new_sol)
                # print("New solution cost: ", new_cost)

                if statistics.time_feasible == 0 and len(Uc) == 0:
                    statistics.iteration_feasible = iteration
                    statistics.time_feasible = time.time() - time_start

                temp_cost = new_cost + len(Uc) * unassigned_lectures_cost
                # The acceptance probability function takes in the old cost, new cost, and current temperature
                # and spits out a number between 0 and 1, which is a sort of recommendation on whether or not to jump to the new solution.
                accept = SA.accept_new_solution(temp_cost, current_cost, remaining_iterations)

                score_w1 = 0
                score_w2 = 0
                score_w3 = 0

                if accept:

                    if len(Uc) > 0:
                        unassigned_lectures_cost = min(unassigned_lectures_cost * parameters.adjust_unscheduled_cost,
                                                       float(self.instance_data.max_cost))
                    else:
                        unassigned_lectures_cost = max(float(1), unassigned_lectures_cost / parameters.adjust_unscheduled_cost)

                    statistics.accepted_count += 1
                    # print("New solution accepted.")
                    if temp_cost > current_cost: # worse than current solution
                        # print("New solution is worse than the current solution.")
                        statistics.worse_count += 1
                        score_w3 = parameters.w3
                    else: # better than current solution
                        # print("New solution is better than the current solution.")
                        statistics.better_count += 1
                        score_w2 = parameters.w2

                    solution = new_sol
                    current_cost = temp_cost
                # else:
                #     # print("New solution NOT accepted.")

                if (global_best_has_uc or new_cost < global_best_cost) and len(Uc) == 0:
                    global_best_has_uc = False
                    # print("New solution is the global best.")
                    statistics.global_best_counts += 1
                    statistics.iteration_best = iteration
                    statistics.time_best = time.time() - time_start
                    global_best = new_sol
                    global_best_cost = new_cost
                    score_w1 = parameters.w1

                if no_best_found_count >= parameters.reheat_limit and iteration < parameters.iteration_limit:
                    SA.reheat(new_cost)
                    no_best_found_count = 0
                    statistics.reheats_count += 1
                    iterations_since_reheat = 0
                    ref_iter_limit = remaining_iterations
                else:
                    no_best_found_count += 1

                if global_best_cost == 0:
                    return global_best, global_best_cost
                #
                # print("Score W1: ", score_w1)
                # print("Score W2: ", score_w3)
                # print("Score W3: ", score_w3)

                psi = max(score_w1, score_w2, score_w3)
                # print("PSI: ", psi)
                lambda_param = 0.8

                # recalculate weights of  operators based on the accepted solution
                operators_lookup.removal_operators_weights[str(removal_operator_index)] = lambda_param * operators_lookup.removal_operators_weights[str(removal_operator_index)] + (1-lambda_param) * psi
                operators_lookup.repair_operators_weights[str(repair_operator_index)] = lambda_param * operators_lookup.repair_operators_weights[str(repair_operator_index)] + (1-lambda_param) * psi

                # we need to recalculate weights only if two-stage operation was performed
                # if GA was performed it means that the below operators weren't used, hence didn't have impact in the result
                # consequently we won't update the weights in this iteration
                if repair_operator_index == 0:
                    operators_lookup.lecture_period_operators_weights[str(lecture_period_operator_index)] = lambda_param * operators_lookup.lecture_period_operators_weights[str(lecture_period_operator_index)] + (1-lambda_param) * psi
                    operators_lookup.lecture_room_operators_weights[str(lecture_room_operator_index)] = lambda_param * operators_lookup.lecture_room_operators_weights[str(lecture_room_operator_index)] + (1-lambda_param) * psi
                    operators_lookup.priority_rules_weights[str(priority_rule_index)] = lambda_param * operators_lookup.priority_rules_weights[str(priority_rule_index)] + (1-lambda_param) * psi

        # print('===============================\n')
        # print("Best solution cost: ", global_best_cost)
        # print('===============================\n')

        statistics.time = time.time() - time_start

        statistics_instance.print_statistics()
        return global_best, global_best_cost

    def neighbor(self, solution, destroy_limit,
                 removal_operator_index, repair_operator_index, lecture_period_operator_index, lecture_room_operator_index, priority_rule_index,
                 courses_penalties, curricula_penalties, Uc):

        # print("Destroy Limit: ", destroy_limit)
        lectures_to_remove = random.randint(1, destroy_limit)
        # print("Lectures to remove number: ", lectures_to_remove)

        # different destroy operators expect different input parameters
        # we are handling it accordingly below
        if removal_operator_index == 0:
            schedule, lectures_removed = operators_lookup.removal_operators[removal_operator_index](solution, lectures_to_remove, self.instance_data, courses_penalties)
        elif removal_operator_index == 1:
            schedule, lectures_removed = operators_lookup.removal_operators[removal_operator_index](solution, lectures_to_remove, self.instance_data, curricula_penalties)
        else:
            schedule, lectures_removed = operators_lookup.removal_operators[removal_operator_index](solution, lectures_to_remove, self.instance_data)

        # append lectured left unscheduled from prev row
        for l in Uc:
            lectures_removed.append(l)

        # repair_operator_index = 0
        # lecture_period_operator_index = 0
        # lecture_room_operator_index = 0
        # priority_rule_index = 0
        if repair_operator_index == 0:
            schedule, Uc = operators_lookup.repair_operators[repair_operator_index](schedule, self.instance_data, lectures_removed,
                                                                                operators_lookup.lecture_period_operators[lecture_period_operator_index],
                                                                                operators_lookup.lecture_room_operators[lecture_room_operator_index],
                                                                                operators_lookup.priority_rules[priority_rule_index])
        elif repair_operator_index == 1:
            schedule = operators_lookup.repair_operators[repair_operator_index](schedule, self.instance_data, lectures_removed)

        return schedule, Uc

    def execute(self):
        Uc = []

        print("START " + configs.instance_name)
        time_start = time.time()
        # Generate initial solution
        initial_solution_instance = initial_solution(self.instance_data)
        init_sol, Uc = initial_solution_instance.generate_solution()

        if statistics.time_feasible == 0 and len(Uc) == 0:
            statistics.iteration_feasible = -1
            statistics.time_feasible = time.time() - time_start

        schedule, cost = self.find_optimal_solution(init_sol, Uc)

        rows = []

        for i in range(self.instance_data.days):
            for j in range(self.instance_data.periods_per_day):
                for k in range(self.instance_data.rooms_count):
                    if schedule[i][j][k] != -1:
                        row = self.instance_data.courses_ids[schedule[i][j][k]] + " " + self.instance_data.rooms[
                            k].id + " " + str(i) + " " + str(
                            j) + '\n'
                        rows.append(row)

        # write formatted input to a file to be used by the next process (max-SAT)
        partial_temp_filename = 'C:/Users/vlere/qq/sol' + configs.instance_name + str(uuid.uuid4())

        with open(partial_temp_filename, 'w+') as f:
            for row in rows:
                f.write(row)

        print("DONE " + configs.instance_name)
        return schedule, cost


import contextlib, random

import numpy as np
import torch
import torch.nn.functional as F
from torch.nn.utils import parameters_to_vector as p2v

def current_val_interval(cfg, step):
    v_intervals = [(int(k), int(v)) for k, v in cfg["training"]["val_interval"].items()]
    for k, v in sorted(v_intervals, reverse=True):
        if step > k:
            return v

def resize_input(input, target, align_corners=True, mode='bilinear'):
    """Resize input to match last two dimensions of target (generally, spatial dimensions h, w)."""
    h, w = input.shape[-2:]
    ht, wt = target.shape[-2:]

    if h != ht and w != wt:
        return F.interpolate(input, size=(ht, wt), mode=mode, align_corners=align_corners)
    return input

def count(module):
    """Count total number of parameters in nn.Module."""
    return p2v(module.parameters()).numel()

def setup_seeds(seed):
    torch.backends.cudnn.deterministic = True
    random.seed(seed)
    np.random.seed(seed)
    torch.manual_seed(seed)
    torch.cuda.manual_seed_all(seed)

@contextlib.contextmanager
def np_local_seed(seed):
    state = np.random.get_state()
    np.random.seed(seed)
    try:
        yield
    finally:
        np.random.set_state(state)

def get_trainer(cfg):
    if 'da' in cfg.training:
        from training.da_train import Trainer
    else:
        from training.train import Trainer
    return Trainer(cfg)


from django.core.exceptions import ObjectDoesNotExist

from rest_framework.permissions import BasePermission

from consultant.models import Consultant

from .models import Circle
from .conf import settings

class CanViewCircle(BasePermission):

    def has_permission(self, request, view):
        can_view = False
        circle_name = view.kwargs.get('name')
        try:
            circle = Circle.objects.get(
                name__iexact=circle_name)
            can_view = circle.is_user_in_followers(request.user)
        except Circle.DoesNotExist:
            if circle_name == settings.CIRCLES_PROJECT_QUESTION_CIRCLE_NAME:
                can_view = request.user in Consultant.objects.filter_consulting_enabled().users()
            else:
                raise ObjectDoesNotExist

        return can_view or request.user.is_superuser


import __init__
import torch
from operations import *

class Cell(nn.Module):
    def __init__(self, genotype, C_prev_prev, C_prev, C):
        super(Cell, self).__init__()
        self.preprocess0 = MLP([C_prev_prev, C], 'relu', 'batch', bias=False)
        self.preprocess1 = MLP([C_prev, C], 'relu', 'batch', bias=False)

        op_names, indices = zip(*genotype.normal)
        concat = genotype.normal_concat
        self._compile(C, op_names, indices, concat)

    def _compile(self, C, op_names, indices, concat):
        assert len(op_names) == len(indices)
        self._steps = len(op_names) // 2
        self._concat = concat
        self.multiplier = len(concat)

        self._ops = nn.ModuleList()
        for name, index in zip(op_names, indices):
            op = OPS[name](C, 1, True)
            self._ops += [op]
        self._indices = indices

    def forward(self, s0, s1, edge_index, drop_prob):
        s0 = self.preprocess0(s0)
        s1 = self.preprocess1(s1)

        states = [s0, s1]
        for i in range(self._steps):
            h1 = states[self._indices[2 * i]]
            h2 = states[self._indices[2 * i + 1]]
            op1 = self._ops[2 * i]
            op2 = self._ops[2 * i + 1]
            h1 = op1(h1, edge_index)
            h2 = op2(h2, edge_index)
            if self.training and drop_prob > 0.:
                if not isinstance(op1, Identity):
                    h1 = drop_path(h1, drop_prob)
                if not isinstance(op2, Identity):
                    h2 = drop_path(h2, drop_prob)
            s = h1 + h2
            states += [s]
        return torch.cat([states[i] for i in self._concat], dim=1)

class AuxiliaryHeadPPI(nn.Module):

    def __init__(self, C, num_classes):
        super(AuxiliaryHeadPPI, self).__init__()
        self.features = nn.Sequential(
            MLP([C, 128, 768], 'relu', 'batch', bias=False)

        )
        self.classifier = nn.Linear(768, num_classes)

    def forward(self, x):
        x = self.features(x)
        x = self.classifier(x)
        return x

class NetworkPPI(nn.Module):

    def __init__(self, C, num_classes, layers, auxiliary, genotype, stem_multiplier=3, in_channels=3):
        super(NetworkPPI, self).__init__()
        self._layers = layers
        self._auxiliary = auxiliary
        self._in_channels = in_channels
        self.drop_path_prob = 0.

        C_curr = stem_multiplier * C
        self.stem = nn.Sequential(
            MLP([in_channels, C_curr], None, 'batch', bias=False),
        )

        C_prev_prev, C_prev, C_curr = C_curr, C_curr, C
        self.cells = nn.ModuleList()
        for i in range(layers):
            cell = Cell(genotype, C_prev_prev, C_prev, C_curr)
            self.cells += [cell]
            C_prev_prev, C_prev = C_prev, cell.multiplier * C_curr
            if i == 2 * layers // 3:
                C_to_auxiliary = C_prev

        if auxiliary:
            self.auxiliary_head = AuxiliaryHeadPPI(C_to_auxiliary, num_classes)
        self.global_pooling = nn.AdaptiveAvgPool1d(1)
        self.classifier = nn.Linear(C_prev + 1, num_classes)

    def forward(self, input):
        logits_aux = None
        x, edge_index = input.x, input.edge_index
        s0 = s1 = self.stem(x)
        for i, cell in enumerate(self.cells):
            s0, s1 = s1, cell(s0, s1, edge_index, self.drop_path_prob)
            if i == 2 * self._layers // 3:
                if self._auxiliary and self.training:
                    logits_aux = self.auxiliary_head(s1)
        out = self.global_pooling(s1.unsqueeze(0)).squeeze(0)
        logits = self.classifier(torch.cat((out, s1), dim=1))
        return logits, logits_aux

def drop_path(x, drop_prob):
    if drop_prob > 0.:
        keep_prob = 1. - drop_prob
        mask = torch.cuda.FloatTensor(x.size(0), 1).bernoulli_(keep_prob)
        x.div_(keep_prob)
        x.mul_(mask)
    return x


import os
import sqlite3
import urllib
from unittest import mock

import pytest
from yarl import URL

from neuro_cli import __version__
from neuro_cli.stats import (
    NEURO_EVENT_CATEGORY,
    SCHEMA,
    add_usage,
    delete_oldest,
    ensure_schema,
    make_record,
    select_oldest,
)

@pytest.fixture
def db() -> sqlite3.Connection:
    db = sqlite3.connect(":memory:")
    db.row_factory = sqlite3.Row
    return db

def check_tables(db: sqlite3.Connection) -> None:
    tables = {}

    for name, sql in db.execute(
        "SELECT name, sql from sqlite_master WHERE type='table'"
    ):
        tables[name] = sql

    assert tables == SCHEMA

def test_ensure_schema_empty(db: sqlite3.Connection) -> None:
    ensure_schema(db)
    check_tables(db)

def test_ensure_schema_invalid(db: sqlite3.Connection) -> None:
    db.execute("CREATE TABLE stats (invalid INTEGER)")
    ensure_schema(db)
    check_tables(db)

def test_add_usage(db: sqlite3.Connection) -> None:
    ensure_schema(db)
    add_usage(db, "neuro run", [{}, {"-s": "cpu-small", "image": None, "cmd": None}])
    add_usage(
        db,
        "neuro ps",
        [{}, {"-s": "('failed', 'running')", "image": None, "cmd": None}],
    )
    ret = list(db.execute("SELECT cmd, args, version FROM stats"))
    assert len(ret) == 2
    assert dict(ret[0]) == {
        "cmd": "neuro run",
        "args": '[{}, {"-s": "cpu-small", "image": null, "cmd": null}]',
        "version": __version__,
    }
    assert dict(ret[1]) == {
        "cmd": "neuro ps",
        "args": '[{}, {"-s": "(\'failed\', \'running\')", "image": null, "cmd": null}]',
        "version": __version__,
    }

def test_select_oldest(db: sqlite3.Connection) -> None:
    ensure_schema(db)
    add_usage(db, "neuro run", [{}, {"-s": "cpu-small", "image": None, "cmd": None}])
    add_usage(
        db,
        "neuro ps",
        [{}, {"-s": "('failed', 'running')", "image": None, "cmd": None}],
    )
    old = select_oldest(db, limit=1)
    assert len(old) == 1
    assert dict(old[0]) == {
        "rowid": mock.ANY,
        "cmd": "neuro run",
        "args": '[{}, {"-s": "cpu-small", "image": null, "cmd": null}]',
        "timestamp": mock.ANY,
        "version": __version__,
    }

def test_delete_oldest(db: sqlite3.Connection) -> None:
    ensure_schema(db)
    add_usage(db, "neuro run", [{}, {"-s": "cpu-small", "image": None, "cmd": None}])
    add_usage(
        db,
        "neuro ps",
        [{}, {"-s": "('failed', 'running')", "image": None, "cmd": None}],
    )
    old = select_oldest(db, limit=1)
    delete_oldest(db, old)
    ret = list(db.execute("SELECT cmd, args, version FROM stats"))
    assert len(ret) == 1
    assert dict(ret[0]) == {
        "cmd": "neuro ps",
        "args": '[{}, {"-s": "(\'failed\', \'running\')", "image": null, "cmd": null}]',
        "version": __version__,
    }

def test_make_record_cli() -> None:
    record = make_record(
        uid="uid",
        url=URL("https://dev.neu.ro/api/v1"),
        cmd="cmd",
        args="args",
        version="version",
    )
    parsed_record = urllib.parse.parse_qs(record)
    assert parsed_record["ec"] == ["CLI"]

def test_make_record_web_shell() -> None:
    os.environ[NEURO_EVENT_CATEGORY] = "WEB-CLI"
    record = make_record(
        uid="uid",
        url=URL("https://dev.neu.ro/api/v1"),
        cmd="cmd",
        args="args",
        version="version",
    )
    del os.environ[NEURO_EVENT_CATEGORY]
    parsed_record = urllib.parse.parse_qs(record)
    assert parsed_record["ec"] == ["WEB-CLI"]


from tensorflow.keras.models import load_model
import cv2
import numpy as np
import serial
import time

# Connect to Arduino
ser = serial.Serial('COM3', 9600, timeout=1)

# Load mask detector model
model = load_model('saved_models/MobileNetModel.h5')
SIZE = (224, 224)

# Import face detector
face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')

# Face detection function
def detect(frame):
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    face_locations = face_cascade.detectMultiScale(gray, 1.3, 5)
    out_locations = []
    x_pos, y_pos, width, height = 0, 0, 0, 0
    for face in face_locations:
        x_pos, y_pos, width, height = face
        out_locations.append((x_pos, y_pos, width, height))
    return out_locations

# Make sure sprayer is off
ser.write(b'L')
prev_unmasked_flag = False
curr_unmasked_flag = False

# Initialize model
test_pred = model.predict(np.random.random([1, SIZE[0], SIZE[1], 3]))

# Start video capture
video_capture = cv2.VideoCapture(0)

while video_capture.isOpened():

    # Capturues video_capture frame by frame
    ret, frame = video_capture.read()
    if not ret:
        break

    num_people = 0
    # Get list of face positions [(x, y, w, h), ...]
    faces = detect(frame)

    # Initialize x, y, w, h
    x, y, w, h = 0, 0, 0, 0
    # If faces ARE detected:
    if len(faces) > 0:
        # For each face:
        for face in faces:
            x, y, w, h = face
            roi = frame[y:y+h, x:x+w]
            data = cv2.resize(roi, SIZE, interpolation=cv2.INTER_AREA)
            data = data.astype('float')/255.0
            data = np.reshape(data, [1, SIZE[0], SIZE[1], 3])
            pred = model.predict(data) # [unmasked, masked]
            masked_confidence = pred[0][1] # pred[0][0]
            unmasked_confidence = pred[0][0] # 1 - masked_confidence
            # If unmasked:
            if unmasked_confidence > masked_confidence:
                label = 'UNMASKED: {:.2%}'.format(unmasked_confidence)
                color = (0, 0, 255) # (B, G, R)
                curr_unmasked_flag = True
            # If masked
            else:
                label = 'MASKED: {:.2%}'.format(masked_confidence)
                color = (0, 255, 0)
                curr_unmasked_flag = False

            # Draw a rectangle around each face
            cv2.rectangle(frame, (x, y), (x + w, y + h), color, 2)
            # Label confidence percentage
            cv2.putText(frame, label, (x, y), cv2.FONT_HERSHEY_SIMPLEX, 1, color, 2)
    # If faces AREN'T detected
    else:
        # Label 'No Face Found'
        cv2.putText(frame, 'No Face Found', (20, 60), cv2.FONT_HERSHEY_SIMPLEX, 2, (0, 0, 255), 2)
        curr_unmasked_flag = False

    # Display the camera feed
    cv2.imshow('MASK DETECTOR', frame)

    # If changed to an unmasked face
    if curr_unmasked_flag != prev_unmasked_flag and curr_unmasked_flag:
        # Trigger relay to spray water
        ser.write(b'H')
        print('SPRAY')
    # If changed to all masked
    elif curr_unmasked_flag != prev_unmasked_flag and not curr_unmasked_flag:
        # Turn off relay
        ser.write(b'L')
        print('STOP SPRAYING')
    prev_unmasked_flag = curr_unmasked_flag

    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

# Release the capture once all the processing is done
video_capture.release()
cv2.destroyAllWindows()