'''定义自己的数据集'''
# coding:utf8
import os
from PIL import Image
from torch.utils import data
import numpy as np
from torchvision import transforms as T
import scipy.io
import torch
import utils
from .SBDClassSeg import picFulPath

class VOCClassSeg(data.Dataset):

    class_names = np.array([
        'background',
        'aeroplane',
        'bicycle',
        'bird',
        'boat',
        'bottle',
        'bus',
        'car',
        'cat',
        'chair',
        'cow',
        'diningtable',
        'dog',
        'horse',
        'motorbike',
        'person',
        'potted plant',
        'sheep',
        'sofa',
        'train',
        'tv/monitor',
    ])
    mean_bgr = np.array([104.00698793, 116.66876762, 122.67891434])

    def __init__(self, txt_path, transforms=None,train=True):  # 此处train val test（指定此次的数据时用来做什么的，不同用处的数据集图片预处理方法不同，可以传入不同的txt_path即可）的指定应该用union

        '''

        参数：txt_path包含了每张图片的路径和图片的标签的路径（语义分割时就是标记好的图片的路径）
            transforms表示该读取图片后，图片要进行的预处理，如果为None,则使用默认的预处理
        '''

        # 1.指定数据集，常用的方法是给定图片路径的txt文档,将他们读入一个列表
        imgs = []
        self.train = train
        fh = open(txt_path, 'r')
        # 遍历整个txt文档，每张图片的路径作为list的一个元素
        for line in fh:
            line = line.rstrip()  # 去掉改行最后的回车符号
            words = line.split()
            imgs.append((words[0], words[1]))  # words[0]是原图片的路径，words[1]是标记好的图片的标签
        self.imgs = imgs
        # 2.指定读入图片后的预处理
        if transforms is None:

            def transforms(img, lbl):
                # T.Resize T.CenterCrop将图片保持纵横比缩放裁剪为同一大小，
                # T.Tensor,T.Normalize 将图片转为[0,1]的Tensor,并归一化
                if train==True:
                    transImg = T.Compose([T.Resize(224), T.CenterCrop(224),
                                   T.ToTensor(),
                                   T.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])])

                    transLbl = T.Compose([T.ToPILImage(),T.Resize(224), T.CenterCrop(224),
                                       T.ToTensor()])
                else:
                    transImg = T.Compose([T.ToTensor(),
                                          T.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])])

                    transLbl = T.Compose([ T.ToPILImage(),T.ToTensor()])

                img = transImg(img)

                lbl = transLbl(lbl)
                return img, lbl.long()  # lbl的训练集和验证集都很定时tensor,此处将他们都设计为3维的tensor[1*H*W]

            def untransforms(img, lbl):
                # 该trans是对已经归一化的tensor处理，得到归一化之前的Tensor
                trans = T.Compose(
                    [T.Normalize([-0.485 / 0.229, -0.456 / 0.224, -0.406 / 0.225], [1 / 0.229, 1 / 0.224, 1 / 0.225])])
                imgUntrans = trans(img)
                # for i in range(img.shape[0]):
                #     imgUntrans[i] = trans(img[i])

                return ((255*imgUntrans).type(torch.ByteTensor).transpose(0,1).transpose(1,2)).numpy(), (lbl.squeeze(0)).numpy()

            # 常规的数据操作：（裁剪为统一大小,可选T.scale），（数据增强，如随机裁剪等 语义分割时一般不做这个），ToTensor()后+T.Normalize
            #if self.train:  # 如果此次是训练集（训练集和验证集可能读取数据方法一样，但是预处理的过程不一样）
        self.transforms = transforms
        self.untransforms = untransforms
        fh.close()

    def __getitem__(self, index):  # 该方法是给定索引或键值，返回对应的值，常用在enumerate遍历数据集时
        '''返回一张图片的验证集和测试集的数据'''
        # 从list中获取图片的路径
        img_path = self.imgs[index][0]
        lbl_path = self.imgs[index][1]
        # 读取图片，为numpy格式
        im = Image.open(img_path)
        # lbl是mat格式，mat格式的处理参考https://blog.csdn.net/qq_32425195/article/details/85202552

        # load label
        lbl = Image.open(lbl_path)
        lbl = np.array(lbl, dtype=np.int32)
        lbl[lbl == 255] = -1
        lbl = torch.from_numpy(lbl)
        return self.transforms(im, lbl.unsqueeze(0))

    def __len__(self):
        '''
        返回为数据集中所有图片的个数
        :return:
        '''
        return len(self.imgs)

if __name__ == '__main__':
    pass


import json

from hc.api.models import Channel
from hc.test import BaseTestCase
from mock import patch

class ChannelModelTestCase(BaseTestCase):

    @patch("hc.api.models.requests.post")
    def test_it_refreshes_hipchat_access_token(self, mock_post):
        mock_post.return_value.json.return_value = {"expires_in": 100}

        channel = Channel(kind="hipchat", user=self.alice, value=json.dumps({
            "oauthId": "foo",
            "oauthSecret": "bar"
        }))

        channel.refresh_hipchat_access_token()

        # It should request a token using a correct tokenUrl
        mock_post.assert_called()
        self.assertTrue("expires_at" in channel.value)


# -*- coding: UTF-8 -*-

from spider import *
#from spider.common.get_cookie import get_cookie

class Race:

    def __init__(self,col):

        self.name = '赛马'
        self.session = requests.session()
        self.session.headers.update(headers)
        self.venues = ['S1','S2','ST','HV']
        self.col = col
        self.collect = mongodb.db[self.col]
        self.url = 'https://bet.hkjc.com/racing/getJSON.aspx'
        self.content_type = 'text/json; charset=utf-8'

        self.rtype = {'winplaodds': '独赢位置','qin':'连赢','qpl': '位置Q',}
        self.venue = None
        self.raceon = None
        self.map_page = {}
        self.init_venue()

    def update_one(self,condition,item):
        """更新数据"""
        try:

                self.collect.update_one(condition, {'$set': item}, upsert=True)
                logger.info('更新数据')

        except Exception as ex:
            logger.info(traceback.format_exc())

    def get_page(self):
        url = f'https://bet.hkjc.com/racing/script/rsdata.js?lang=ch&date={self.date}&venue={self.venue}&CV=L3.06R1f_1'
        response = self.session.get(url,timeout=timeout)

        text = response.text
        if not text[23:32] == 'Challenge':
            regex_page = re.compile('var mtgTotalRace = (.*);')
            regex_venue = re.compile('var mtgVenue = (.*);')
            page = regex_page.search(text)
            venue = regex_venue.search(text)

            if page:
                venue = eval(venue.group(1))
                page = int(page.group(1)) + 1
                self.map_page[venue] = page

                return page
            else:

                return None

        else:
            logger.info('响应不是json,获取cookie')
            get_cookie(self.session, url, response.text)
            return self.get_page()
    def init_venue(self):
        self.date = self.get_date()
        self.venue = self.get_venue()

        if self.venue:
            self.raceon = self.get_raceon()
            self.get_page()
        print(self.map_page)
    def get_date(self):
        date = datetime.datetime.now().strftime('%Y-%m-%d')
        return '2020-07-01'
    def get_venue(self):

        for venue in self.venues:
            param = {'type':'scratched','date': self.date,'venue':venue}
            response = self.session.get(self.url,params=param)
            text = response.text
            if not text[23:32] == 'Challenge':
                text = response.json()
                if text:

                    return text.get('SR')

            else:
                logger.info('响应不是json,获取cookie')
                get_cookie(self.session, self.url, response.text, para=param)
                return self.get_venue()

    def get_raceon(self):
        param = {'type': 'scratched'}
        param['date'] = self.date
        param['venue'] = self.venue
        try :
            response = self.session.get(self.url,params=param)
            text = response.text
            if not text[23:32] == 'Challenge':
                text = response.json()
                if text:
                    return  int(text.get('RAN_RACE')) + 1
                else:
                    return None
            else:
                logger.info('响应不是json,获取cookie')
                get_cookie(self.session, self.url, text, param)
                return self.get_raceon()
        except Exception as exc:
            logger.info(traceback.format_exc())

    def _get_race_info(self,page):

        url = f'https://bet.hkjc.com/racing/pages/odds_wp.aspx?lang=ch&date={self.date}&venue={self.venue}&raceno={page}'

        response = self.session.get(url)
        text = response.text
        if not text[23:32] == 'Challenge':

            return text
        else:
            logger.info('响应不是json,获取cookie')
            get_cookie(self.session, self.url, text,None)
            return self._get_race_info(page)

    def _parse_race_info(self,page,response):

        bs = BeautifulSoup(response, 'html.parser')
        desc = bs.find('span', attrs={'class': 'content'})
        if desc:
            desc = desc.get_text()

        regex_racech = re.compile('var infoDivideByRaceCh = (\[.*\])')
        regex_drawWgtByRace = re.compile("var drawWgtByRace = (.*);")
        regex_jockeysByRace = re.compile("var jockeysByRace = (.*);")
        regex_trainersByRace = re.compile("var trainersByRace = (.*);")
        infoDivideByRaceCh = regex_racech.search(response)
        #负磅
        drawWgtByRace = regex_drawWgtByRace.search(response)
        #骑师
        jockeysByRace  = regex_jockeysByRace.search(response)
        #练马师
        trainersByRace = regex_trainersByRace.search(response)
        if infoDivideByRaceCh:
            infoDivideByRaceCh  = eval(infoDivideByRaceCh.group(1))[page].split(';;')[0].split('|')[1:]
            drawWgtByRace1 = eval(drawWgtByRace.group(1))[page].split(';;')[2].split('|')[1:]
            gears = eval(drawWgtByRace.group(1))[page].split(';;')[1].split('|')[1:]

            jockeysByRace = eval(jockeysByRace.group(1))[page].split(';;')[0].split('|')[1:]
            trainersByRace = eval(trainersByRace.group(1))[page].split(';;')[0].split('|')[1:]
            item = {}
            item['description'] = desc
            item['raceon'] = self.raceon
            item['updateTime'] = datetime.datetime.now()
            item['raceInfo'] = []
            for i in range(0,len(infoDivideByRaceCh)):
                race_info = {}
                race_info['horseNumber'] = i + 1
                race_info['gear'] = gears[i]
                race_info['horseName'] = infoDivideByRaceCh[i]
                race_info['horseWeight'] = drawWgtByRace1[i]
                race_info['horseMan'] = jockeysByRace[i]
                race_info['horseTrainer'] = trainersByRace[i]
                item['raceInfo'].append(race_info)

            condition = {}
            condition['venue'] = self.venue
            condition['session'] = page
            condition['date'] = self.date
            condition['rtype'] = 'info'
            self.update_one(condition,item)

    def fetch_update_race_info(self):

        last_match_page = self.map_page[self.venue]
        for page in range(1,last_match_page):

            response = race._get_race_info(page)
            race._parse_race_info(page, response)

    def fetch(self):
        if self.venue:
            self.fetch_update_race_info()
            #for page in range(self.raceon,self.map_page[self.venue]):

                #self.tcetop(page)
    def get_winplaodds(self):
        url = f'https://bet.hkjc.com/racing/getJSON.aspx?type=winplaodds&date={self.date}&venue={self.venue}&start=1&end={self.map_page[self.venue]-1}'
        response =  self.session.get(url)
        text = response.text
        if not text[23:32] == 'Challenge':
            text = response.json()
            text = text['OUT'].split('@@@')[1:]

            for winpla in enumerate(text,1):
                item = {}
                item['win'] = []
                item['pla'] = []
                item['raceon'] = None
                item['updateTime'] = datetime.datetime.now()
                wins,plas = winpla[1].split('#')
                wins = wins.split(';')[1:]
                plas = plas.split(';')[1:]

                for win in wins:
                    win = win.split('=')
                    item['win'].append({'horseNumber': win[0],'odds': win[1],'trend':win[2]})

                for plas in plas:
                    plas = plas.split('=')
                    item['pla'].append({'horseNumber': plas[0],'odds': plas[1],'trend':plas[2]})

                condition = {}
                condition['date']= self.date
                condition['rtype'] = 'winpla'
                condition['session'] = winpla[0]
                condition['venue'] = self.venue
                self.update_one(condition,item)
        else:
            logger.info('响应不是json,获取cookie')
            get_cookie(sess, self.url, text, None)
            return self.get_winplaodds()

    def qintop(self,page):
        rtype = [
            'qintop', 'qinbank', 'qin',
            'qpltop', 'qplbank', 'qpl','tcetop']
        for r in rtype:
            url = f'https://bet.hkjc.com/racing/getJSON.aspx?type={r}&date={self.date}&venue={self.venue}&raceno={page}'
            response = self.session.get(url)
            text = response.text

            if not text[23:32] == 'Challenge':

                text = response.json()
                if r != 'qinbank' and r != 'qplbank':
                    item = {}
                    text = text['OUT'].split('@@@')[1:]
                    item['info'] = []
                    for winpla in enumerate(text, 1):

                        item['raceon'] = None
                        item['updateTime'] = datetime.datetime.now()
                        wins = winpla[1].split(';')[1:]
                        for win in wins:
                            win = win.split('=')
                            item['info'].append({'position': win[0], 'odds': win[1]})

                    condition = {}
                    condition['date'] = self.date
                    condition['rtype'] = r
                    condition['session'] = page
                    condition['venue'] = self.venue
                    self.update_one(condition, item)

                else:

                    text = text['OUT'].split(';')[1:]
                    item = {}
                    item['info'] = []
                    for winpla in enumerate(text, 1):

                        item['raceon'] = self.raceon
                        item['updateTime'] = datetime.datetime.now()
                        wins = winpla[1].split('|')
                        horseNumber,wins = wins[0],wins[1:]
                        for win in wins:
                            position = win.split('=')
                            item['info'].append({'horseNumber': horseNumber, 'position': position[0],'odds': position[1]})

                    condition = {}
                    condition['date'] = self.date
                    condition['rtype'] = r
                    condition['session'] = page
                    condition['venue'] = self.venue
                    self.update_one(condition, item)

            else:
                logger.info('响应不是json,获取cookie')
                get_cookie(sess, url, text, None)
                return self.qintop(page)

    def tcetop(self, page):
        rtype = [
            'tcetop','tcebank','tceinv',
            'tritop','tribank',
            'fftop','ffbank','ff',
            'qqttop', 'qqtbank',
            ]
        top = ['tcetop','tritop','ffttop','qqttop']
        bank = ['tcebank','tribank','ffbank', 'qqtbank']
        for r in rtype[5:6]:
            url = f'https://bet.hkjc.com/racing/getJSON.aspx?type={r}&date={self.date}&venue={self.venue}&raceno={page}'
            response = self.session.get(url)
            text = response.text

            if not text[23:32] == 'Challenge':

                text = response.json()
                if r in bank:
                    item = {}

                    text = text['OUT'].split(';')[1:]
                    item['info'] = []
                    for winpla in enumerate(text, 1):

                        item['raceon'] = self.raceon
                        item['updateTime'] = datetime.datetime.now()
                        wins = winpla[1].split('|')
                        horseNumber, wins = wins[0], wins[1:]
                        for win in wins:
                            position = win.split('=')
                            item['info'].append({'horseNumber': horseNumber, 'position': position[0],'odds': position[1]})

                    condition = {}
                    condition['date'] = self.date
                    condition['rtype'] = r
                    condition['session'] = page
                    condition['venue'] = self.venue
                    #self.update_one(condition, item)

                elif r == 'tceinv':

                    item = {}
                    item['info'] = []
                    item['raceon'] = self.raceon
                    item['updateTime'] = datetime.datetime.now()
                    text = text['OUT'].split(';')[1:]

                    for winpla in enumerate(text, 1):

                        wins = winpla[1].split('|')

                        horseNumber, wins = wins[0], wins[1:]
                        for win in wins:
                            position = win.split('=')
                            item['info'].append(
                                {'horseNumber': horseNumber, 'position': position[0], 'amount': position[1]})

                    condition = {}
                    condition['date'] = self.date
                    condition['rtype'] = r
                    condition['session'] = page
                    condition['venue'] = self.venue

                    self.update_one(condition, item)

                elif r in top:
                    item = {}
                    item['info'] = []
                    item['raceon'] = self.raceon
                    item['updateTime'] = datetime.datetime.now()
                    text = text['OUT'].split(';')[1:]
                    for winpla in enumerate(text, 1):

                        wins = winpla[1]
                        position = wins.split('=')
                        item['info'].append(
                            {'position': position[0], 'odds': position[1]})

                    condition = {}
                    condition['date'] = self.date
                    condition['rtype'] = r
                    condition['session'] = page
                    condition['venue'] = self.venue

                    self.update_one(condition, item)
            else:
                logger.info('响应不是json,获取cookie')
                get_cookie(sess, url, text, None)
                return self.qintop(page)

    def get_all(self,rtype,page,start):

        url = f'https://bet.hkjc.com/racing/getJSON.aspx?type={rtype}&date={self.date}&venue={self.venue}&raceno={page}&start={start}'

        try:
            response = self.session.get(url)
            text = response.text
            if not text[23:32] == 'Challenge':
                text = response.json()
                return text
            else:
                logger.info('响应不是json,获取cookie')
                get_cookie(sess, url, text, None)
                return self.get_all(rtype,page,start)

        except Exception as exc:
            logger.info(traceback.format_exc())

    def parse_all(self,page):
        rtype = ['tri', 'ff']
        for r in rtype:
            page = page
            start = 0
            item = {}
            item['info'] = []
            item['raceon'] = self.raceon
            item['updateTime'] = datetime.datetime.now()
            while True:
                response = race.get_all(r, page, start)

                response = response.get('OUT')
                if not response:
                    break
                start = start + 48
                response = response.split(';')[1:]
                for i in response:
                    position = i.split('=')
                    item['info'].append({'position':position[0],'odds':position[1]})

            condition = {}
            condition['date'] = self.date
            condition['rtype'] = r
            condition['session'] = page
            condition['venue'] = self.venue
            if item['info']:
                self.update_one(condition, item)

col = 'race'
race = Race(col=col)
race.fetch()


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

from flask import render_template, redirect, url_for, flash, request, abort
from flask_login import login_required, current_user
import datetime
import requests
from app import db
from app.main import main
from app.models import Level, Recitation, Vocabulary, Note
from app.main.forms import SettingForm, NoteForm

@main.before_app_request
def before_app_request():
    """
    如果用户已经登录但是没有设置词库和每日背诵的单词量，
    则只允许auth蓝本、static静态资源以及设置页面，访问其他
    页面时会重定向到设置页面。
    """
    if current_user.is_authenticated \
            and (current_user.recitation_level is None or current_user.quota_per_day is None) \
            and request.endpoint[:5] != 'auth.' \
            and request.endpoint != 'static' \
            and request.endpoint != 'main.setting':
        flash('请先设置你想要背诵的词库以及每天的单词量。', category='warning')
        return redirect(url_for('main.setting'))

@main.route('/')
@login_required
def index():
    """展示用户背单词的进度，包括当前词库、词库进度、今日单词量、今日已完成单词量，以及背单词的入口按钮。"""
    # 获得当前登录用户词库单词总量，已记住的单词量，计算得到词库进度百分比
    level_total, level_remember = current_user.get_level_recite_status()
    percent = format(level_remember/level_total, '.0%')

    # 获得今日单词总量，今日已完成单词量
    today_recite_status = current_user.get_today_recite_status()
    today_total = today_recite_status[0]
    today_remember = today_recite_status[1]

    # 如果今日分配的单词量已完成，则背单词入口按钮显示为再背一组，否则为开始背单词。
    if today_total == today_remember != 0:
        btn_message = '再背一组'
    else:
        btn_message = '开始背单词'
    return render_template('index.html',
                           level_percent=percent,
                           today_total=today_recite_status[0],
                           today_remember=today_recite_status[1],
                           btn_message=btn_message)

@main.route('/setting', methods=['GET', 'POST'])
@login_required
def setting():
    """用户进行背单词设置，包括词库和每日背诵的单词量。"""
    form = SettingForm()
    if form.validate_on_submit():
        current_user.recitation_level = Level.query.filter_by(name=form.recitation_level.data).first()
        current_user.quota_per_day = form.quota_per_day.data
        db.session.add(current_user)
        db.session.commit()     # 如果不commit下一步分配单词量将读不到用户配置信息
        current_user.recite_init()  # 用户设置完成后，在Recitation表中创建用户和词库中所有单词的背诵记录
        flash('设置完成，开始背单词吧～', category='success')
        return redirect(url_for('main.index'))
    return render_template('setting.html', form=form)

@main.route('/bdc')
@login_required
def bdc_init():
    """用户在首页上点击背单词入口按钮时的路由，进行背单词的初始化。"""
    # 如果用户已经背完了整个词库，跳转到设置路由并提醒用户换个词库。
    level_total, level_remember = current_user.get_level_recite_status()
    if level_total == level_remember:
        flash('你已经背完了整个词库，换一个词库来背吧～', category='warning ')
        return redirect(url_for('main.setting'))
    # 如果用户今天的任务已经完成，再从当前词库中分配一组单词
    if current_user.vocabularies.filter(Recitation.recite_date == datetime.date.today(),
                                        Recitation.recite_flag != True).first() is None:
        current_user.today_recite_init()
    # 得到用户该背的下一个单词，并重定向到背单词页面
    next_v = current_user.get_vocabulary()
    return redirect(url_for('main.bdc_preview', word=next_v.word))

@main.route('/bdc/<string:word>', methods=['GET', 'POST'])
@login_required
def bdc_preview(word):
    """背单词，可以显示单词信息，今日进度条，查看他人的笔记并添加笔记。"""
    # 如果单词在数据库中不存在则返回404
    v = Vocabulary.query.filter_by(word=word).first()
    if v is None:
        abort(404)
    form = NoteForm()   # 新增笔记的表单
    # 添加新笔记
    if form.validate_on_submit():
        note = Note(content=form.content.data,
                    vocabulary=v,
                    author=current_user._get_current_object())
        db.session.add(note)
        flash('添加笔记成功', category='success')
        return redirect(url_for('main.bdc_preview', word=word))
    # 进度条数据的获取与处理
    today_recite_status = current_user.get_today_recite_status()
    today_total = today_recite_status[0]
    progress_bar_data = today_recite_status[1:]
    progress_bar_percent = [format(x/today_total, '.1%') for x in progress_bar_data]
    # 近义词的获取与处理
    if v.synonyms is not None:
        synonyms = v.synonyms.split('/')
        synonyms_dict = dict()
        for i in synonyms:
            definition = requests.get('https://api.shanbay.com/bdc/search/?word=%s' % i).json()['data']['definition']
            synonyms_dict[i] = definition
    else:
        synonyms_dict = None
    # 笔记的获取与处理
    notes = v.notes.all()
    return render_template('vocabulary.html',
                           vocabulary=v,
                           form=form,
                           notes=notes,
                           synonyms=synonyms_dict,
                           progress_bar_data=progress_bar_data,
                           progress_bar_percent=progress_bar_percent)

@main.route('/remember/<string:word>')
@login_required
def remember(word):
    """用户标记该单词为记住了"""
    v = Vocabulary.query.filter_by(word=word).first()
    if v is None:
        abort(404)
    current_user.remember(v)
    # 获取下一个要背诵的单词，如果返回结果为None，则今天的学习任务完成，重定向到首页
    next_v = current_user.get_vocabulary()
    if next_v is None:
        flash('你已经完成了今天的学习任务，祝贺你！', category='success')
        return redirect(url_for('main.index'))
    return redirect(url_for('main.bdc_preview', word=next_v.word))

@main.route('/again/<string:word>')
@login_required
def again(word):
    """用户标记该单词为没记住"""
    v = Vocabulary.query.filter_by(word=word).first()
    if v is None:
        abort(404)
    current_user.not_remember(v)
    next_v = current_user.get_vocabulary()
    return redirect(url_for('main.bdc_preview', word=next_v.word))


# Copyright (C) 2014-2016 Cuckoo Foundation.
# This file is part of Cuckoo Sandbox - http://www.cuckoosandbox.org
# See the file 'docs/LICENSE' for copying permission.

import os
import subprocess
import time
import logging
import platform

from lib.common.abstracts import Auxiliary
from lib.common.results import NetlogFile
from lib.common.results import upload_to_host
from lib.core.config import Config

log = logging.getLogger(__name__)

class KTRACE(Auxiliary):
    """ktrace catch all syscall."""
    priority = -5

    def __init__(self):
        self.config = Config(cfg="analysis.conf")
        self.fallback_strace = False
    def start(self):
        log.info("ktrace start() %d" % os.getpid())
        os.system("/bin/dmesg -c &>/dev/null")
        root_path = os.getcwd()
        bin_path = os.path.join(root_path,"bin")
        module_path = os.path.join(bin_path, "ktrace.ko")
        if os.path.exists(module_path):
            os.system("/sbin/insmod %s analyzer=%d" % (module_path,os.getpid()))
            log.info("insmod command execute")
        else:
            log.info("kernel module not there")
        log.info("analyzer path:%s" % module_path)
        log.info("ktrace start() return versin 0.01")
        return True

    def get_pids(self):
        return []

    def stop(self):
        os.system("/sbin/rmmod ktrace")
        log.info("ktrace stop() %d" % os.getpid())
        os.system("/bin/dmesg > /var/log/ktrace.log")
        upload_to_host("/var/log/ktrace.log","logs/ktrace.log")
        upload_to_host("/proc/version","files/version")
        upload_to_host("/proc/modules","files/modules")


# -*- coding: utf-8 -*-
__author__ = 'kyota'
import utilities
import data_utilities
import numpy.linalg
import mysql.connector
import numpy as np
# import scipy
from scipy import linalg
import math
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import social_force
import logging
import cProfile

class Kriging:
    def __init__(self, prediction_person_id=None, nagget=0, sill=5, range=5, keys=[], all_Z=None):
        ### see nagget, range, sill figure explanation.
        ### https://drive.google.com/file/d/0B0sVf5AmJhwJSlhVT3U5RWhlZ0E/view?usp=sharing
        self.nagget = nagget    ### offset
        self.sill     = sill    ### steady state value, it can be got calculating variance of vecZ[i].
        self.range     = range    ### x-range of zero to steady state.
        self.prediction_person_id = prediction_person_id
        self.keys     = keys
        self.next_prediction_point = self.empty()
        self.prediction_point = self.empty()
        self.variograms = []    # [variogram, distance]
        self.last_prediction_point = None
        self.all_Z = all_Z
        self.real_point = self.empty()

    def krige_all_place(self, vecZ, point_range=(0, 100), x_range=range(-8, 14), y_range=range(-4, 14),\
                          prediction_type='v', destination=0, plot_type="all", frame=-1):
        predicted_points = {}
        # xmax = x_range[-1]
        for y in y_range:
            for x in x_range:
                hash = self.empty()
                hash['x'], hash['y'] = x, y
                self.prediction_point = hash
                prediction_point, vec_omega =  self.krige(vecZ)
                # self.matC, self.vecD, invC = self.get_matrixes(vecZ, self.prediction_point)
                # vec_omega = self.get_weight(self.vecD, invC)
                # prediction_point = self.predict(self.prediction_point, vec_omega, prediction_type)
                prediction_point['x'], prediction_point['y'] = x, y
                predicted_points[y*(100) + x] = prediction_point
        return predicted_points

    ##### return vec_omega, lamda
    ##### args: C=np.ndarray(), D=np.ndarray
    ##### cf : kriging example https://drive.google.com/file/d/0B0sVf5AmJhwJd2VaRDNoU0UwWm8/view?usp=sharing
    ##### point_selection は 'predicted': 前回の予測点を使う, 'real': 実際の点を使う.
    ##### support_persons -> 'current': use current persons only, 'past': use current and past persons both
    def krige(self, _vecZ, Z=None, prediction_type='v', point_selection='predicted', prediction_point=None,
              tracked_prediction_point=None, support_persons='current', use_self_flag=False, frame=None):
        """
        :param _vecZ:
        :param Z:
        :param prediction_type:
        :param point_selection:
        :param prediction_point: 予測対象の現在の x,y座標 を持っている. 将来の地点へ行く速度の予測を行う.
        :param support_persons:
        :param use_self_flag:
        :param frame:
        :return:
        """
        persons = _vecZ.copy()
        self.prediction_point, real_point, other_persons = self.get_prediction_point(
            persons, self.prediction_person_id, tracked_prediction_point, point_selection=point_selection,
            use_self_flag=use_self_flag)
        # self.next_point = self.get_prediction_point(next_vecZ, self.prediction_person_id, self.prediction_point)

        if not self.prediction_point or other_persons.__len__() == 0:
            return self.empty(), self.empty(), np.zeros(len(other_persons)), other_persons, {}
        ### get invC, one, oneT, vecD
        if (support_persons == 'current'):
            self.matC, self.vecD, invC = self.get_matrixes(other_persons, self.prediction_point)
        else:
            support_persons = self.get_support_people(self.prediction_point, Z, frame)
            self.matC, self.vecD, invC = self.get_matrixes(support_persons, self.prediction_point)

        vec_omega = self.get_weight(self.vecD, invC)
        dict_omega = self.get_dict_omega(vec_omega, other_persons)
        ### クリギングによる予測
        prediction_point = self.predict(self.prediction_point, vec_omega, other_persons, prediction_type)
        self.last_prediction_point = prediction_point ### 次の周で参照のために保存
        return prediction_point, real_point, vec_omega, other_persons, dict_omega

    # 信頼度の入力を得る. 同一方向に向かう人物の数, range内の予測に使える人の数, range内の人の近さ.

    # 予測に使用する人物との距離を得る.
    def get_input_distances(self, other_persons, prediction_point):
        distances = []
        for person in other_persons.values():
            distance = utilities.get_distance(prediction_point, person)
            distances.append(distance)
        return distances

    def get_support_people(self, prediction_person, Z, frame):
        support_people = {}
        if (Z == None):
            return {}
        # _Z = Z[0:50]
        _Z = Z[(frame - 100):frame]
        for frame, vecZ in enumerate(_Z):
            for person_id, person in vecZ.iteritems():
                ## key は一意になれば何でも良い
                support_people[person_id * 10000 + frame ] = person
        return support_people

    def get_distance_summary(self, distances):
        in_range_num     = 0
        people_num         = distances.__len__()
        out_range_num     = 0
        for distance in distances:
            if (distance < self.range):
                in_range_num += 1
        if (in_range_num is 0 and people_num is not 0):
            ### range に含まる人がいないときの range外の人の数.
            out_range_num = people_num
        return people_num, in_range_num, out_range_num

    ### plot用に重みをdictに入れる.
    def get_dict_omega(self, vec_omega, persons):
        logging.debug("in get_dict_omega: persons = "+str(persons))
        dict_omega = {}
        for i, person_id in enumerate(self.vecZ.keys()):
            dict_omega[person_id] = vec_omega[i]
        return dict_omega

    ### get vector of omega which is weight of points.
    def get_weight(self, vecD, invC):
        oneT = np.ones((self.vecD.size))
        one = oneT[np.newaxis].T
        ### lambda = (D.T*invC*ones - 1)*(ones.T*invC*ones)
        lamda = (np.dot(np.dot(self.vecD.T, invC), one) - 1) / np.dot(np.dot(oneT, invC), one)
        ### omegas = invC*(vecD - lambda*ones)
        ### ∵ σ2E
        ###     = E{(Z0(r) − ˆ Z0(r))2}2
        ###     = V {Z0(r) − ˆ Z0(r)}
        ###     = C_00 + w.T*C*w − 2w.T*D
        vec_omega = np.dot(invC, (self.vecD - lamda * one)).flatten()
        logging.debug("in get_weight: omega = "+str(vec_omega))
        return vec_omega

    def get_matrixes(self, vecZ, prediction_point):
        " get kriging matrixes vecD, invC"
        sample_size = vecZ.__len__()
        logging.debug("in get_matrixes: vecZ = "+str(vecZ))
        self.vecZ = vecZ
        self.matC = self.make_matC(vecZ)
        logging.debug("in get_matrixes: matC = "+str(self.matC))
        self.vecD = self.make_vecD(vecZ, prediction_point)
        logging.debug("in get_matrixes: vecD = "+str(self.vecD))
        invC = self.matC
        try:
            invC = linalg.pinv(self.matC)
        except np.linalg.LinAlgError as e:
            print(e)
        except ValueError as e:
            print(e)
        return self.matC, self.vecD, invC

    def empty(self):
        return dict.fromkeys(self.keys, 0)

    @classmethod
    def get_dest_tablename(self, destination):
        if (destination < 0):
            table = "person_destination_minus"
        elif (destination == 0):
            table = "person_destination_both"
        elif (destination > 0):
            table = "person_destination_plus"
        return table

    def get_dest_dirname(self, destination, data_set):
        " データ出力するディレクトリを返す, destination, data_set によって決まる.  "
        if (destination < 0):
            dest_dir = "destination_minus"
        elif (destination == 0):
            dest_dir = "destination_both"
        elif (destination > 0):
            dest_dir = "destination_plus"
        dest_dir = data_set+'_'+dest_dir
        return dest_dir

    def predict(self, ex_prediction_point, vec_omega, other_persons, type='v'):
        prediction = self.empty()
        for i, hash in enumerate(self.vecZ.values()):
            for j, k in enumerate(self.keys):
                prediction[k] += hash[k] * vec_omega[i]
            try:
                if (math.isnan(vec_omega[0])):
                    raise IndexError("vec_omega has NaN.")
            except IndexError as e:
                if (self.last_prediction_point):
                    prediction['vx'] = self.last_prediction_point['vx']
                    prediction['vy'] = self.last_prediction_point['vy']
                else:
                    prediction['vx'] = self.prediction_point['vx']
                    prediction['vy'] = self.prediction_point['vy']
    # print 'vx = '+ str(prediction['vx']) + '\tvy = ' + str(prediction['vy'])
        prediction = self.set_velocity(prediction)
        # prediction = self.direction_adjust(ex_prediction_point, prediction)
        prediction['person_id'] = ex_prediction_point['person_id']
        if not ex_prediction_point:
            return self.empty()
        prediction['x'] = ex_prediction_point['x'] # 移動前なので x, y は変化させない。
        prediction['y'] = ex_prediction_point['y']
        if (type == 'dv'):
            # 二階微分使用時
            prediction['vx'] = ex_prediction_point['vx']
            prediction['vy'] = ex_prediction_point['vy']
        return prediction

    def move_point(self, predicted_point, type='v'):
        next_point = self.empty()
        if (type=='v'):
            next_point['vx'] = predicted_point['vx']
            next_point['vy'] = predicted_point['vy']
            next_point['x']= predicted_point['x'] + predicted_point['vx']
            next_point['y']= predicted_point['y'] + predicted_point['vy']
        elif (type=='dv'):
            next_point['vx'] = predicted_point['vx'] + predicted_point['dvx']
            next_point['vy'] = predicted_point['vy'] + predicted_point['dvy']
            next_point['x']= predicted_point['x'] + next_point['vx']
            next_point['y']= predicted_point['y'] + next_point['vy']
        self.prediction_point = next_point
        return next_point

    def set_velocity(self, prediction):
        vx, vy = prediction['vx'], prediction['vy']
        velocity, theta = data_utilities.get_v_theta(vx, vy)
        prediction['velocity'], prediction['theta'] = velocity, theta
        return prediction

    def direction_adjust(self, ex_prediction_point, prediction_point):
        cnx = mysql.connector.connect(user='kyota', host='localhost', database='kriging')
        cursor = cnx.cursor()
        # y, x = int(prediction_point['x']), int(prediction_point['y'])
        y, x = math.floor(prediction_point['x']), math.floor(prediction_point['y'])
        table = 'vx_plus' if (prediction_point['vx'] > 0) else 'vx_minus'
        query     = ("select `mean(dtheta)`, `std(dtheta)` from "+table+" where `floor(y)` = "+str(y)+" and    `floor(x)` = "+str(x)+" ; ")
        cursor.execute(query)
        row = cursor.fetchall()
        if (len(row) != 0):
            dtheta_avg, dtheta_std = float(row[0][0]), float(row[0][1])
            if (dtheta_avg > 0):
                dtheta_threshold = (dtheta_avg + 1.97*dtheta_std)*(math.pi/180)
            else:
                dtheta_threshold = (dtheta_avg - 1.97*dtheta_std)*(math.pi/180)
        else:
            dtheta_threshold = 30*(math.pi/180)
        cos_threshold = math.cos(dtheta_threshold)
        theta_diff = prediction_point['theta'] - ex_prediction_point['theta']
        if math.cos(theta_diff) > cos_threshold:
            return prediction_point
        ## adjust theta
        ### if current theta > ex theta
        if math.sin(theta_diff) > 0:
            prediction_point['theta'] = ex_prediction_point['theta'] + dtheta_threshold
        else:
            prediction_point['theta'] = ex_prediction_point['theta'] - dtheta_threshold
        prediction_point = data_utilities.set_vx_vy(prediction_point)
        return prediction_point

    def get_prediction_point(self, vecZ, prediction_person_id, tracked_prediction_point, point_selection='predicted', use_self_flag=False):
        """ point_selection は 'predicted': 前回の予測点を使う, 'real': 実際の点を使う. 'given': 与えられた点を使う"""
        ### if vecZ has prediction_person: copy it and delete from vecZ.
        real_point = vecZ.pop(prediction_person_id)
        _prediction_point = real_point  # 前回の予測結果がなければ実測値が入ったまま返る.
        # when current vecZ has target person
        if point_selection == 'predicted':
            if tracked_prediction_point and tracked_prediction_point != self.empty():
                # if previous predicted point exist, overwrite _prediction point with that.
                _prediction_point = tracked_prediction_point
            if use_self_flag:
                # 前回予測(追跡)された値をクリギングの予測に使用する.
                vecZ[prediction_person_id] = _prediction_point
        elif point_selection == 'real': pass
        return _prediction_point, real_point, vecZ

    def make_matC(self, persons):
        sample_size = persons.__len__()
        if (0 < sample_size <= 1):
            return np.zeros((1,1))
        self.matC = np.ndarray((sample_size, sample_size))
        # if (isinstance(persons, list)): ### personsのlist が与えられたらpersonsに分解する.
        #     people = persons
        #     for persons in people:

        for row, hash1 in enumerate(persons.values()):
                    for col, hash2 in enumerate(persons.values()):
                        # val = self.variogram(hash1, hash2, self.nagget, self.sill, self.range)
                        val = self.cosineogram(hash1, hash2, self.nagget, self.sill, self.range)
                        if (math.isnan(val) or math.isinf(val)):
                            self.matC[row][col] = 0
                        else:
                            self.matC[row][col] = val

        return self.matC

    def make_vecD(self, persons, prediction_point):
        sample_size = persons.__len__()
        self.vecD = np.ndarray((sample_size, 1))
        # for i in range(0, self.sample_size):
        ### personsのlist が与えられたらpersonsに分解する.
        # if (isinstance(persons, list)):
        #     people = persons
        #     for persons in people:
        for i, hash in enumerate(persons.values()):
                    # self.vecD[i] = self.variogram(hash, prediction_point, self.nagget, self.sill, self.range)
                    self.vecD[i] = self.cosineogram(hash, prediction_point, self.nagget, self.sill, self.range)
        return self.vecD

    ### return spherical variogram
    def variogram(self, sample1, sample2, nagget, sill, range):
        distance = utilities.get_distance(sample1, sample2)
        # if distance > range:
        #     distance = range
        variogram = nagget + sill * ((3 / 2) * (distance / range) - (1 / 2) * (distance / range) ** 3)
        if distance > range:
            variogram = nagget + sill
        # variogram = sill*(1 - (3/2)*(distance/range) + (1/2)*math.pow(distance/range, 3))
        self.variograms.append([variogram, distance])
        return variogram

    def cosineogram(self, sample1, sample2, nagget, sill, range):
        distance = utilities.get_distance(sample1, sample2)
        variogram = ( (1-nagget) - ( ( (1-nagget) - (sill**2))*((3.0/2.0)*(distance/range) - (1.0/2.0)*((distance/range)**3))))
        if distance > range:
            variogram = nagget + sill
        self.variograms.append([variogram, distance])
        return variogram

    def get_means(self, xdata, ydata):
        dict_y = {}
        for i, x in enumerate(xdata):
            if (not isinstance(dict_y.get(x), list)):
                dict_y[x] = []
            if (not math.isnan(ydata[i])):
                dict_y[x].append(ydata[i])
        xs, ymeans = [], []
        for x, ys in dict_y.iteritems():
            ys = np.array(ys)
            # ymeans[x] = ys.mean()
            ymeans.append(ys.mean())
            xs.append(x)
        return xs, ymeans

    def plot_diffs(self, person_id, velocity_diffs, distances_list, dirname):
        xdata1, xdata2, xdata3, ydata = [], [], [], []
        for i, distances in enumerate(distances_list):
            person_num, in_range_num, out_range_num= self.get_distance_summary(distances)
            x1 = in_range_num
            x2 = person_num
            x3 = out_range_num
            try:
                y = velocity_diffs[i][1]
            except:
                print("y data index error.")
            xdata1.append(x1)
            xdata2.append(x2)
            xdata3.append(x3)
            ydata.append(y)

        utilities.mkdir(dirname + "velocity_diff")
        x1s, ymeans = self.get_means(xdata1, ydata)
        plt.clf()
        plt.scatter(xdata1, ydata)
        plt.scatter(x1s, ymeans, color='r')
        plt.xlabel("in range people num")
        plt.ylabel("difference of velocity")
        plt.savefig(dirname + "velocity_diff/in_range_diff_"+str(person_id)+".png")

        x2s, ymeans = self.get_means(xdata2, ydata)
        plt.clf()
        plt.scatter(xdata2, ydata)
        plt.scatter(x2s, ymeans, color='r')
        plt.xlabel("people num")
        plt.ylabel("difference of velocity")
        plt.savefig(dirname + "velocity_diff/people_diff_"+str(person_id)+".png")
        # plt.close()

        xs, ymeans = self.get_means(xdata3, ydata)
        plt.clf()
        plt.scatter(xdata3, ydata)
        plt.scatter(xs, ymeans, color='r')
        plt.xlabel("out range people num")
        plt.ylabel("difference of velocity")
        plt.savefig(dirname + "velocity_diff/out_range_diff_"+str(person_id)+".png")
        # plt.close()

if __name__ == "__main__":
    main()


#!/usr/bin/env python
# coding: utf-8

import yaml
import helper
import logging.handlers

logger = logging.getLogger(__name__)

__SECURE_DATA_FILEPATH = "res/secure_data.yml"
__EMAIL_TEXT_FILE_PATH = 'res/annonce_2022.txt'
__EMAIL_OBJECT = "[Annonce Emploi] Pôle Nord Compagnie recherche Lutins créatifs"

def main():
    _configure_logger('email_annonce.log')
    logger.info("##### Le Pere Noel de la Fremo #####")

    with open(__SECURE_DATA_FILEPATH, 'r') as stream:
        secure_data = yaml.safe_load(stream)

    with open(__EMAIL_TEXT_FILE_PATH, 'r') as file:
        body = file.read()

    # for debug, change key form personnes to personnes_test
    for id_, id_param in secure_data['personnes'].items():
        helper.gmail_send_email(
            secure_data['sender_email'],
            __EMAIL_OBJECT,
            body,
            id_param['email'])

    logger.info("Finish")

def _configure_logger(filename):
    """
    write to console, simple message with log level info
    write to file, formatted message with log level debug
    """
    logger = logging.getLogger('')
    logger.setLevel(logging.DEBUG)

    # Console
    consoleHandler = logging.StreamHandler()
    consoleHandler.setLevel(logging.INFO)
    consoleFormatter = logging.Formatter('%(message)s')
    consoleHandler.setFormatter(consoleFormatter)
    logger.addHandler(consoleHandler)

    # File
    fileHandler = logging.handlers.RotatingFileHandler(filename, maxBytes=1024 * 1024, backupCount=1)
    fileHandler.setLevel(logging.DEBUG)
    fileFormatter = logging.Formatter(
        fmt='[%(asctime)s][%(name)s][%(levelname)-5s]%(message)s',
        datefmt='%Y-%m-%d %H:%M:%S')
    fileHandler.setFormatter(fileFormatter)
    logger.addHandler(fileHandler)

if __name__ == "__main__":
    main()


#!/usr/bin/python3

# To run and check this file, you need Python 3 + mypy
# See install instructions at: http://mypy.readthedocs.io/en/latest/getting_started.html
# To typecheck this file: mypy kyber.py
# To run this file: python3 kyber.py

from speclib import *
from keccak import shake128, shake256, sha3_512, sha3_256, shake128_absorb, shake128_squeeze

kyber_q   = 7681
kyber_n   =  256

variant_k   = refine3(nat, lambda x: x == 2 or x == 3 or x == 4)
variant_eta = refine3(nat, lambda x: x == 5 or x == 4 or x == 3)

kyber_dt  =   11
kyber_du  =   11
kyber_dv  =    3

zqelem   = refine3(nat, lambda x: x < kyber_q)
zqelem_t = zqelem

zqpoly_t    = refine3(array[zqelem_t], lambda x: array.length(x) == kyber_n)
zqpolyvec_t = array[zqpoly_t] #refine3(array[zqpoly_t], lambda x: array.length(x) == kyber_k)

omega     = zqelem(3844)
psi       = zqelem(62)
n_inv     = zqelem(7651)
psi_inv   = zqelem(1115)
omega_inv = zqelem(6584)

def to_zqelem(x:nat_t) -> zqelem_t:
    return zqelem(x % kyber_q)

def zqadd(a:zqelem_t, b:zqelem_t) -> zqelem_t:
    return to_zqelem(a + b)

def zqsub(a:zqelem_t, b:zqelem_t) -> zqelem_t:
    return to_zqelem(a + kyber_q - b)

def zqmul(a:zqelem_t, b:zqelem_t) -> zqelem_t:
    return to_zqelem(a * b)

def zqexp(a:zqelem_t, exp:nat_t) -> zqelem_t:
    return to_zqelem(pow(a, exp, kyber_q))

#poly
def zqpoly_add(p:zqpoly_t, q:zqpoly_t) -> zqpoly_t:
    np = array.create(kyber_n, zqelem(0))
    for i in range(kyber_n):
        np[i] = zqadd(p[i], q[i])
    return np

def zqpoly_sub(p:zqpoly_t, q:zqpoly_t) -> zqpoly_t:
    np = array.create(kyber_n, zqelem(0))
    for i in range(kyber_n):
        np[i] = zqsub(p[i], q[i])
    return np

def zqpoly_pointwise_mul(p:zqpoly_t, q:zqpoly_t) -> zqpoly_t:
    np = array.create(kyber_n, zqelem(0))
    for i in range(kyber_n):
        np[i] = zqmul(p[i], q[i])
    return np

def zqpoly_ntt(p:zqpoly_t) -> zqpoly_t:
    np = array.create(kyber_n, zqelem(0))
    for i in range(kyber_n):
        for j in range(kyber_n):
            np[i] = zqadd(np[i], zqmul(zqmul(zqexp(psi, j), p[j]), zqexp(omega, i * j)))
    return np

def zqpoly_invntt(p:zqpoly_t) -> zqpoly_t:
    np = array.create(kyber_n, zqelem(0))
    for i in range(kyber_n):
        for j in range(kyber_n):
            np[i] = zqadd(np[i], zqmul(p[j], zqexp(omega_inv, i * j)))
        np[i] = zqmul(np[i], zqmul(n_inv, zqexp(psi_inv, i)))
    return np

def zqpoly_mul(p:zqpoly_t, q:zqpoly_t) -> zqpoly_t:
    return zqpoly_invntt(zqpoly_pointwise_mul(zqpoly_ntt(p), zqpoly_ntt(q)))

# just for debugging
def zqpoly_mul_schoolbook(p:zqpoly_t, q:zqpoly_t) -> zqpoly_t:
    s = array.create(kyber_n + kyber_n, zqelem(0))
    for i in range(kyber_n):
        for j in range(kyber_n):
            s[i+j] = zqadd(s[i+j], zqmul(p[i], q[j]))
    high = s[kyber_n:(kyber_n + kyber_n)]
    low = s[0:kyber_n]
    r = zqpoly_sub(low, high)
    return r

#polyvec
def zqpolyvec_add(kyber_k:variant_k, a:zqpolyvec_t, b:zqpolyvec_t) \
    -> contract(zqpolyvec_t,
                lambda kyber_k, a, b: array.length(a) == kyber_k and array.length(b) == kyber_k,
                lambda kyber_k, a, b, res: array.length(res) == kyber_k):
    r = array.create(kyber_k, array.create(kyber_n, zqelem_t(0)))
    for i in range(kyber_k):
        r[i] = zqpoly_add(a[i], b[i])
    return r

def zqpolyvec_ntt(kyber_k:variant_k, r:zqpolyvec_t) \
    -> contract(zqpolyvec_t,
                lambda kyber_k, r: array.length(r) == kyber_k,
                lambda kyber_k, r, res: array.length(res) == kyber_k):
    res = array.create(kyber_k, array.create(kyber_n, zqelem_t(0)))
    for i in range(kyber_k):
        res[i] = zqpoly_ntt(r[i])
    return res

def zqpolyvec_invntt(kyber_k:variant_k, r:zqpolyvec_t) \
    -> contract(zqpolyvec_t,
                lambda kyber_k, r: array.length(r) == kyber_k,
                lambda kyber_k, r, res: array.length(res) == kyber_k):
    res = array.create(kyber_k, array.create(kyber_n, zqelem_t(0)))
    for i in range(kyber_k):
        res[i] = zqpoly_invntt(r[i])
    return res

#kyber
kyber_symbytes = 32
kyber_polycompressedbytes = 96
kyber_polybytes = 416

def kyber_polyveccompressedbytes(kyber_k:variant_k):
    return (kyber_k * 352)

def kyber_polyvecbytes(kyber_k:variant_k):
    return (kyber_k * kyber_polybytes)

def kyber_indcpa_publickeybytes(kyber_k:variant_k):
    return (kyber_polyveccompressedbytes(kyber_k) + kyber_symbytes)

def kyber_indcpa_secretkeybytes(kyber_k:variant_k):
    return kyber_polyvecbytes(kyber_k)

def kyber_indcpa_bytes(kyber_k:variant_k):
    return (kyber_polyveccompressedbytes(kyber_k) + kyber_polycompressedbytes)

symbytes_t = bytes_t(kyber_symbytes)

def bit_reverse(x:uint8_t) -> uint8_t:
    y = uint8(0)
    for i in range(8):
        y += (x & uint8(1)) << (7 - i)
        x = x >> 1
    return y

def bit_reversed_poly(p:zqpoly_t) -> zqpoly_t:
    res = array.create(kyber_n, zqelem_t(0))
    for i in range(kyber_n):
        i_new = bit_reverse(uint8(i))
        res[i] = p[int(i_new)]
    return res

def bit_reversed_polyvec(kyber_k:variant_k, p:zqpolyvec_t) \
    -> contract(zqpolyvec_t,
                lambda kyber_k, p: array.length(p) == kyber_k,
                lambda kyber_k, p, res: array.length(res) == kyber_k):
    res = array.create(kyber_k, array.create(kyber_n, zqelem_t(0)))
    for j in range(kyber_k):
        res[j] = bit_reversed_poly(p[j])
    return res

def msg_topoly(m:symbytes_t) -> zqpoly_t:
    res = array.create(kyber_n, zqelem_t(0))
    for i in range(kyber_symbytes):
        for j in range(8):
            mask = (uint16(m[i]) >> j) & uint16(1)
            res_ij = (-mask) & uint16((kyber_q + 1) // 2)
            res[8 * i + j] = zqelem(int(res_ij))
    return res

def poly_tomsg(p:zqpoly_t) -> symbytes_t:
    msg = array.create(kyber_symbytes, uint8(0))
    for i in range(kyber_symbytes):
        for j in range(8):
            t = uint16(p[8 * i + j]) << 1
            t = (int(t) + kyber_q // 2) // kyber_q
            t = uint16(t) & uint16(1)
            t = uint8(t)
            msg[i] = msg[i] | (t << j);
    return msg

def bytesToBits(b:vlbytes_t) -> bitvector_t:
    return bitvector(bytes.to_nat_le(b), 8 * array.length(b))

def cbd(kyber_eta:variant_eta, buf:bytes_t) \
    -> contract(zqpoly_t,
                lambda kyber_eta, buf: array.length(buf) == kyber_eta * kyber_n // 4,
                lambda kyber_eta, buf, res: True):
    beta = bytesToBits(buf)
    res = array.create(kyber_n, zqelem(0))
    for i in range(kyber_n):
        a = nat(0)
        b = nat(0)
        for j in range(kyber_eta):
            a = a + bit.to_int(beta[2 * i * kyber_eta + j])
        for j in range(kyber_eta):
            b = b + bit.to_int(beta[2 * i * kyber_eta + kyber_eta + j])
        res[i] = zqsub(zqelem(a), zqelem(b))
    return res

#cbd(prf(seed, nonce)), prf = shake256
def poly_getnoise(kyber_eta:variant_eta, seed:symbytes_t, nonce:uint8_t) -> zqpoly_t:
    extseed = array.create(kyber_symbytes + 1, uint8(0))
    extseed[0:kyber_symbytes] = seed
    extseed[kyber_symbytes] = nonce
    buf = shake256(kyber_symbytes + 1, extseed, kyber_eta * kyber_n // 4)
    r = cbd(kyber_eta, buf)
    return r

def poly_tobytes (a:zqpoly_t) -> bytes_t(kyber_polybytes):
    res = array.create(kyber_polybytes, uint8(0))
    tmp = array.create(8, uint16(0))
    for i in range(kyber_n // 8):
        for j in range(8):
            tmp[j] = (a[8*i+j]) % kyber_q

        res[13*i+0] = uint8(tmp[0] & 0xff)
        res[13*i+1] = uint8((tmp[0] >> 8) | ((tmp[1] & 0x07) << 5))
        res[13*i+2] = uint8((tmp[1] >> 3) & 0xff)
        res[13*i+3] = uint8((tmp[1] >> 11) | ((tmp[2] & 0x3f) << 2))
        res[13*i+4] = uint8((tmp[2] >> 6) | ((tmp[3] & 0x01) << 7))
        res[13*i+5] = uint8((tmp[3] >> 1) & 0xff)
        res[13*i+6] = uint8((tmp[3] >> 9) | ((tmp[4] & 0x0f) << 4))
        res[13*i+7] = uint8((tmp[4] >> 4) & 0xff)
        res[13*i+8] = uint8((tmp[4] >> 12) | ((tmp[5] & 0x7f) << 1))
        res[13*i+9] = uint8((tmp[5] >> 7) | ((tmp[6] & 0x03) << 6))
        res[13*i+10] = uint8((tmp[6] >> 2) & 0xff)
        res[13*i+11] = uint8((tmp[6] >> 10) | ((tmp[7] & 0x1f) << 3))
        res[13*i+12] = uint8(tmp[7] >> 5)
    return res

def poly_frombytes (a:bytes_t(kyber_polybytes)) -> zqpoly_t:
    res = array.create(kyber_n, zqelem_t(0))

    for i in range(kyber_n // 8):
        res[8*i+0] = zqelem(int(uint16(a[13*i+0]) | ((uint16(a[13*i+1]) & uint16(0x1f)) << 8)))
        res[8*i+1] = zqelem(int((uint16(a[13*i+1]) >> 5) | (uint16(a[13*i+2]) << 3) | ((uint16(a[13*i+3]) & uint16(0x03)) << 11)))
        res[8*i+2] = zqelem(int((uint16(a[13*i+3]) >> 2) | ((uint16(a[13*i+4]) & uint16(0x7f)) << 6)))
        res[8*i+3] = zqelem(int((uint16(a[13*i+4]) >> 7) | (uint16(a[13*i+5]) << 1) | ((uint16(a[13*i+6]) & uint16(0x0f)) << 9)))
        res[8*i+4] = zqelem(int((uint16(a[13*i+6]) >> 4) | (uint16(a[13*i+7]) << 4) | ((uint16(a[13*i+8]) & uint16(0x01)) << 12)))
        res[8*i+5] = zqelem(int((uint16(a[13*i+8]) >> 1) | ((uint16(a[13*i+9]) & uint16(0x3f)) << 7)))
        res[8*i+6] = zqelem(int((uint16(a[13*i+9]) >> 6) | (uint16(a[13*i+10]) << 2) | ((uint16(a[13*i+11]) & uint16(0x07)) << 10)))
        res[8*i+7] = zqelem(int((uint16(a[13*i+11]) >> 3) | (uint16(a[13*i+12]) << 5)))
    return res

def poly_compress_vec(a:zqpoly_t) -> bytes_t(352):
    res = array.create(352, uint8(0))
    tmp = array.create(8, uint16(0))

    for j in range(kyber_n // 8):
        for k in range(8):
            tmp_k = (int(uint32((a[8*j+k]) % kyber_q) << 11) + kyber_q // 2) // kyber_q
            tmp[k] = tmp_k & 0x7ff

        res[11*j+0] = uint8(tmp[0] & 0xff)
        res[11*j+1] = uint8((tmp[0] >> 8) | ((tmp[1] & 0x1f) << 3))
        res[11*j+2] = uint8((tmp[1] >> 5) | ((tmp[2] & 0x03) << 6))
        res[11*j+3] = uint8((tmp[2] >> 2) & 0xff)
        res[11*j+4] = uint8((tmp[2] >> 10) | ((tmp[3] & 0x7f) << 1))
        res[11*j+5] = uint8((tmp[3] >> 7) | ((tmp[4] & 0x0f) << 4))
        res[11*j+6] = uint8((tmp[4] >> 4) | ((tmp[5] & 0x01) << 7))
        res[11*j+7] = uint8((tmp[5] >> 1) & 0xff)
        res[11*j+8] = uint8((tmp[5] >> 9) | ((tmp[6] & 0x3f) << 2))
        res[11*j+9] = uint8((tmp[6] >> 6) | ((tmp[7] & 0x07) << 5))
        res[11*j+10] = uint8(tmp[7] >> 3)
    return res

def poly_decompress_vec(a:bytes_t(352)) -> zqpoly_t:
    res = array.create(kyber_n, zqelem_t(0))

    for j in range(kyber_n // 8):
      res[8*j+0] = zqelem(int((((uint32(a[11*j+0]) | ((uint32(a[11*j+1]) & uint32(0x07)) << 8)) * uint32(kyber_q)) + uint32(1024)) >> 11))
      res[8*j+1] = zqelem(int(((((uint32(a[11*j+1]) >> 3) | ((uint32(a[11*j+2]) & uint32(0x3f)) << 5)) * uint32(kyber_q)) + uint32(1024)) >> 11))
      res[8*j+2] = zqelem(int(((((uint32(a[11*j+2]) >> 6) | ((uint32(a[11*j+3]) & uint32(0xff)) << 2) | ((uint32(a[11*j+4]) & uint32(0x01)) << 10)) * uint32(kyber_q)) + uint32(1024)) >> 11))
      res[8*j+3] = zqelem(int(((((uint32(a[11*j+4]) >> 1) | ((uint32(a[11*j+5]) & uint32(0x0f)) << 7)) * uint32(kyber_q)) + uint32(1024)) >> 11))
      res[8*j+4] = zqelem(int(((((uint32(a[11*j+5]) >> 4) | ((uint32(a[11*j+6]) & uint32(0x7f)) << 4)) * uint32(kyber_q)) + uint32(1024)) >> 11))
      res[8*j+5] = zqelem(int(((((uint32(a[11*j+6]) >> 7) | ((uint32(a[11*j+7]) & uint32(0xff)) << 1) | ((uint32(a[11*j+8]) & uint32(0x03)) <<  9)) * uint32(kyber_q)) + uint32(1024)) >> 11))
      res[8*j+6] = zqelem(int(((((uint32(a[11*j+8]) >> 2) | ((uint32(a[11*j+9]) & uint32(0x1f)) << 6)) * uint32(kyber_q)) + uint32(1024)) >> 11))
      res[8*j+7] = zqelem(int(((((uint32(a[11*j+9]) >> 5) | ((uint32(a[11*j+10]) & uint32(0xff)) << 3)) * uint32(kyber_q)) + uint32(1024)) >> 11))
    return res

def poly_compress(a:zqpoly_t) -> bytes_t(kyber_polycompressedbytes):
    res = array.create(kyber_polycompressedbytes, uint8(0))
    tmp = array.create(8, uint32(0))
    k = 0

    for i in range(kyber_n // 8):
        for j in range(8):
            tmp[j] = (((a[i*8+j] << 3) + kyber_q // 2) // kyber_q) & 7

        res[k] = uint8(tmp[0] | (tmp[1] << 3) | (tmp[2] << 6))
        res[k+1] = uint8((tmp[2] >> 2) | (tmp[3] << 1) | (tmp[4] << 4) | (tmp[5] << 7))
        res[k+2] = uint8((tmp[5] >> 1) | (tmp[6] << 2) | (tmp[7] << 5))
        k = k + 3
    return res

def poly_decompress(a:bytes_t(kyber_polycompressedbytes)) -> zqpoly_t:
    res = array.create(kyber_n, zqelem_t(0))
    k = 0

    for i in range(kyber_n // 8):
        res[8*i+0] = zqelem(int(((uint16(a[k+0]) & uint16(7)) * uint16(kyber_q)) + uint16(4)) >> 3)
        res[8*i+1] = zqelem(int((((uint16(a[k+0]) >> 3) & uint16(7)) * uint16(kyber_q)) + uint16(4)) >> 3)
        res[8*i+2] = zqelem(int((((uint16(a[k+0]) >> 6) | ((uint16(a[k+1]) << 2) & uint16(4))) * uint16(kyber_q)) + uint16(4)) >> 3)
        res[8*i+3] = zqelem(int((((uint16(a[k+1]) >> 1) & uint16(7)) * uint16(kyber_q)) + uint16(4)) >> 3)
        res[8*i+4] = zqelem(int((((uint16(a[k+1]) >> 4) & uint16(7)) * uint16(kyber_q)) + uint16(4)) >> 3)
        res[8*i+5] = zqelem(int((((uint16(a[k+1]) >> 7) | ((uint16(a[k+2]) << 1) & uint16(6))) * uint16(kyber_q)) + uint16(4)) >> 3)
        res[8*i+6] = zqelem(int((((uint16(a[k+2]) >> 2) & uint16(7)) * uint16(kyber_q)) + uint16(4)) >> 3)
        res[8*i+7] = zqelem(int((((uint16(a[k+2]) >> 5)) * uint16(kyber_q)) + uint16(4)) >> 3)
        k = k + 3
    return res

def polyvec_tobytes(kyber_k:variant_k, a:zqpolyvec_t) \
    -> contract(bytes_t,
                lambda kyber_k, a: array.length(a) == kyber_k,
                lambda kyber_k, a, res: array.length(res) == kyber_polyvecbytes(kyber_k)):
    res = array.create(kyber_polyvecbytes(kyber_k), uint8(0))

    for i in range(kyber_k):
        res[i*kyber_polybytes:(i+1)*kyber_polybytes] = poly_tobytes(a[i])
    return res

def polyvec_frombytes(kyber_k:variant_k, a:bytes_t) \
    -> contract(zqpolyvec_t,
                lambda kyber_k, a: array.length(a) == kyber_polyvecbytes(kyber_k),
                lambda kyber_k, a, res: array.length(res) == kyber_k):
    res = array.create(kyber_k, array.create(kyber_n, zqelem_t(0)))

    for i in range(kyber_k):
        res[i] = poly_frombytes(a[i*kyber_polybytes:(i+1)*kyber_polybytes])
    return res

def polyvec_compress(kyber_k:variant_k, a:zqpolyvec_t) \
    -> contract(bytes_t,
                lambda kyber_k, a: array.length(a) == kyber_k,
                lambda kyber_k, a, res: array.length(res) == kyber_polyveccompressedbytes(kyber_k)):
    res = array.create(kyber_polyveccompressedbytes(kyber_k), uint8(0))

    for i in range(kyber_k):
        res[i*352:(i+1)*352] = poly_compress_vec(a[i])
    return res

def polyvec_decompress(kyber_k:variant_k, a:bytes_t) \
    -> contract(zqpolyvec_t,
                lambda kyber_k, a: array.length(a) == kyber_polyveccompressedbytes(kyber_k),
                lambda kyber_k, a, res: array.length(res) == kyber_k):
    res = array.create(kyber_k, array.create(kyber_n, zqelem_t(0)))

    for i in range(kyber_k):
        res[i] = poly_decompress_vec(a[i*352:(i+1)*352])
    return res

def pack_sk(kyber_k:variant_k, sk:zqpolyvec_t) \
    -> contract(bytes_t,
                lambda kyber_k, sk: array.length(sk) == kyber_k,
                lambda kyber_k, sk, res: array.length(res) == kyber_indcpa_secretkeybytes(kyber_k)):
    return polyvec_tobytes(kyber_k, sk)

def unpack_sk(kyber_k:variant_k, packedsk:bytes_t) \
    -> contract(zqpolyvec_t,
                lambda kyber_k, packedsk: array.length(packedsk) == kyber_indcpa_secretkeybytes(kyber_k),
                lambda kyber_k, packedsk, res: array.length(res) == kyber_k):
    return polyvec_frombytes(kyber_k, packedsk)

def pack_pk(kyber_k:variant_k, pk:zqpolyvec_t, seed:symbytes_t) \
    -> contract(bytes_t,
                lambda kyber_k, pk: array.length(pk) == kyber_k,
                lambda kyber_k, pk, res: array.length(res) == kyber_indcpa_publickeybytes(kyber_k)):
    res = array.create(kyber_indcpa_publickeybytes(kyber_k), uint8(0))
    res[0:kyber_polyveccompressedbytes(kyber_k)] = polyvec_compress(kyber_k, pk)
    res[kyber_polyveccompressedbytes(kyber_k):kyber_indcpa_publickeybytes(kyber_k)] = seed
    return res

def unpack_pk(kyber_k:variant_k, packedpk:bytes_t) \
    -> contract((zqpolyvec_t, symbytes_t),
                lambda kyber_k, packedpk: array.length(packedpk) == kyber_indcpa_publickeybytes(kyber_k),
                lambda kyber_k, packedpk, res: True): # array.length(fst(res)) == kyber_k
    pk = polyvec_decompress(kyber_k, packedpk[0:kyber_polyveccompressedbytes(kyber_k)])
    seed = packedpk[kyber_polyveccompressedbytes(kyber_k):kyber_indcpa_publickeybytes(kyber_k)]
    return (pk, seed)

def pack_ciphertext(kyber_k:variant_k, b:zqpolyvec_t, v:zqpoly_t) \
    -> contract(bytes_t,
                lambda kyber_k, b, v: array.length(b) == kyber_k,
                lambda kyber_k, b, v, res: array.length(res) == kyber_indcpa_bytes(kyber_k)):
    res = array.create(kyber_indcpa_bytes(kyber_k), uint8(0))
    res[0:kyber_polyveccompressedbytes(kyber_k)] = polyvec_compress(kyber_k, b)
    res[kyber_polyveccompressedbytes(kyber_k):kyber_indcpa_bytes(kyber_k)] = poly_compress(v)
    return res

def unpack_ciphertext(kyber_k:variant_k, c:bytes_t) \
    -> contract((zqpolyvec_t, zqpoly_t),
                lambda kyber_k, c: array.length(c) == kyber_indcpa_bytes(kyber_k),
                lambda kyber_k, c, res: True): # array.length(fst(res)) == kyber_k
    u = polyvec_decompress(kyber_k, c[0:kyber_polyveccompressedbytes(kyber_k)])
    v = poly_decompress(c[kyber_polyveccompressedbytes(kyber_k):kyber_indcpa_bytes(kyber_k)])
    return (u, v)

#parse(xof(p || a || b)), xof = shake128
def genAij(seed:symbytes_t, a:uint8_t, b:uint8_t) -> zqpoly_t:
    shake128_rate = 168
    res = array.create(kyber_n, zqelem(0))

    extseed = array.create(kyber_symbytes + 2, uint8(0))
    extseed[0:kyber_symbytes] = seed
    extseed[kyber_symbytes] = a
    extseed[kyber_symbytes + 1] = b

    maxnblocks = 4
    nblocks = maxnblocks
    state = shake128_absorb(kyber_symbytes + 2, extseed)
    buf = shake128_squeeze(state, shake128_rate * nblocks)

    i = 0
    j = 0
    while (j < kyber_n):
        d = uint16(buf[i]) | (uint16(buf[i + 1]) << 8)
        d = int(d & uint16(0x1fff))
        if (d < kyber_q):
            res[j] = zqelem(d)
            j = j + 1
        i = i + 2
        if (i > shake128_rate * nblocks - 2):
            nblocks = 1
            buf = shake128_squeeze(state, shake128_rate * nblocks)
            i = 0
    return res

def kyber_cpapke_keypair(kyber_k:variant_k, kyber_eta:variant_eta, coins:symbytes_t) \
    -> contract((bytes_t, bytes_t),
                lambda kyber_k, kyber_eta, coins: True,
                lambda kyber_k, kyber_eta, coins, res: True): # array.length(fst(res)) == kyber_indcpa_publickeybytes(kyber_k) and array.length(snd(res)) == kyber_indcpa_secretkeybytes(kyber_k)
    rhosigma = sha3_512(kyber_symbytes, coins)
    rho = rhosigma[0:kyber_symbytes]
    sigma = rhosigma[kyber_symbytes:(2*kyber_symbytes)]

    n = uint8(0)
    s = array.create(kyber_k, array.create(kyber_n, zqelem_t(0)))
    e = array.create(kyber_k, array.create(kyber_n, zqelem_t(0)))
    that = array.create(kyber_k, array.create(kyber_n, zqelem_t(0)))
    A = array.create(kyber_k, array.create(kyber_k, array.create(kyber_n, zqelem_t(0))))

    for i in range(kyber_k):
        A[i] = array.create(kyber_k, array.create(kyber_n, zqelem_t(0)))
        for j in range(kyber_k):
            A[i][j] = array.create(kyber_n, zqelem_t(0))

    for i in range(kyber_k):
        for j in range(kyber_k):
            A[i][j] = genAij(rho, uint8(j), uint8(i))

    for i in range(kyber_k):
        s[i] = poly_getnoise(kyber_eta, sigma, n)
        n += uint8(1)

    for i in range(kyber_k):
        e[i] = poly_getnoise(kyber_eta, sigma, n)
        n += uint8(1)

    shat = bit_reversed_polyvec(kyber_k, zqpolyvec_ntt(kyber_k, s))

    # that = A * shat
    for i in range(kyber_k):
        for j in range(kyber_k):
            that[i] = zqpoly_add(that[i], zqpoly_pointwise_mul(A[i][j], shat[j]))

    t = zqpolyvec_invntt(kyber_k, bit_reversed_polyvec(kyber_k, that))
    t = zqpolyvec_add(kyber_k, t, e)

    sk = pack_sk(kyber_k, shat)
    pk = pack_pk(kyber_k, t, rho)

    return (pk, sk)

def kyber_cpapke_encrypt(kyber_k:variant_k, kyber_eta:variant_eta, m:symbytes_t, packedpk:bytes_t, coins:symbytes_t) \
    -> contract(bytes_t,
                lambda kyber_k, kyber_eta, m, packedpk, coins: array.length(packedpk) == kyber_indcpa_publickeybytes(kyber_k),
                lambda kyber_k, kyber_eta, m, packedpk, coins, res: array.length(res) == kyber_indcpa_bytes(kyber_k)):
    n = uint8(0)
    r = array.create(kyber_k, array.create(kyber_n, zqelem_t(0)))
    e1 = array.create(kyber_k, array.create(kyber_n, zqelem_t(0)))
    uhat = array.create(kyber_k, array.create(kyber_n, zqelem_t(0)))
    vhat = array.create(kyber_n, zqelem(0))
    At = array.create(kyber_k, array.create(kyber_k, array.create(kyber_n, zqelem_t(0))))

    t, rho = unpack_pk(kyber_k, packedpk)

    for i in range(kyber_k):
        At[i] = array.create(kyber_k, array.create(kyber_n, zqelem_t(0)))
        for j in range(kyber_k):
            At[i][j] = array.create(kyber_n, zqelem_t(0))

    for i in range(kyber_k):
        for j in range(kyber_k):
            At[i][j] = genAij(rho, uint8(i), uint8(j))

    for i in range(kyber_k):
        r[i] = poly_getnoise(kyber_eta, coins, n)
        n += uint8(1)

    for i in range(kyber_k):
        e1[i] = poly_getnoise(kyber_eta, coins, n)
        n += uint8(1)

    e2 = poly_getnoise(kyber_eta, coins, n)

    rhat = bit_reversed_polyvec(kyber_k, zqpolyvec_ntt(kyber_k, r))

    for i in range(kyber_k):
        for j in range(kyber_k):
            uhat[i] = zqpoly_add(uhat[i], zqpoly_pointwise_mul(At[i][j], rhat[j]))

    u = zqpolyvec_invntt(kyber_k, bit_reversed_polyvec(kyber_k, uhat))
    u = zqpolyvec_add(kyber_k, u, e1)

    that = bit_reversed_polyvec(kyber_k, zqpolyvec_ntt(kyber_k, t))

    for i in range(kyber_k):
        vhat = zqpoly_add(vhat, zqpoly_pointwise_mul(that[i], rhat[i]))

    v = zqpoly_invntt(bit_reversed_poly(vhat))
    v = zqpoly_add(zqpoly_add(v, e2), msg_topoly(m))
    c = pack_ciphertext(kyber_k, u, v)

    return c

def kyber_cpapke_decrypt(kyber_k:variant_k, kyber_eta:variant_eta, c:bytes_t, sk:bytes_t) \
    -> contract(symbytes_t,
                lambda kyber_k, kyber_eta, c, sk: array.length(c) == kyber_indcpa_bytes(kyber_k) and array.length(sk) == kyber_indcpa_secretkeybytes(kyber_k),
                lambda kyber_k, kyber_eta, c, sk, res: True):
    dhat = array.create(kyber_n, zqelem(0))

    u, v = unpack_ciphertext(kyber_k, c)
    s = unpack_sk(kyber_k, sk)

    uhat = bit_reversed_polyvec(kyber_k, zqpolyvec_ntt(kyber_k, u))

    for i in range(kyber_k):
        dhat = zqpoly_add(dhat, zqpoly_pointwise_mul(s[i], uhat[i]))

    d = zqpoly_invntt(bit_reversed_poly(dhat))
    d = zqpoly_sub(v, d)
    msg = poly_tomsg(d)

    return msg

#KyberKEM
def kyber_publickeybytes(kyber_k:variant_k):
    return kyber_indcpa_publickeybytes(kyber_k)

def kyber_secretkeybytes(kyber_k:variant_k):
    return (kyber_indcpa_secretkeybytes(kyber_k) + kyber_indcpa_publickeybytes(kyber_k) + 2 * kyber_symbytes)

def kyber_ciphertextbytes(kyber_k:variant_k):
    return kyber_indcpa_bytes(kyber_k)

def crypto_kem_keypair(kyber_k:variant_k, kyber_eta:variant_eta, keypaircoins:symbytes_t, coins:symbytes_t) \
    -> contract((bytes_t, bytes_t),
                lambda kyber_k, kyber_eta, keypaircoins, coins: True,
                lambda kyber_k, kyber_eta, keypaircoins, coins, res: True): #array.length(fst(res)) == kyber_publickeybytes(kyber_k) and array.length(snd(res)) == kyber_secretkeybytes(kyber_k)
    sk = array.create(kyber_secretkeybytes(kyber_k), uint8(0))
    pk, sk1 = kyber_cpapke_keypair(kyber_k, kyber_eta, keypaircoins)
    sk[0:kyber_indcpa_secretkeybytes(kyber_k)] = sk1
    sk[kyber_indcpa_secretkeybytes(kyber_k):(kyber_indcpa_secretkeybytes(kyber_k) + kyber_indcpa_publickeybytes(kyber_k))] = pk
    sk[(kyber_indcpa_secretkeybytes(kyber_k) + kyber_indcpa_publickeybytes(kyber_k)):(kyber_secretkeybytes(kyber_k) - kyber_symbytes)] = sha3_256(kyber_publickeybytes(kyber_k), pk)
    sk[(kyber_secretkeybytes(kyber_k) - kyber_symbytes):kyber_secretkeybytes(kyber_k)] = coins
    return (pk, sk)

def crypto_kem_enc(kyber_k:variant_k, kyber_eta:variant_eta, pk:bytes_t, msgcoins:symbytes_t) \
    -> contract((bytes_t, symbytes_t),
                lambda kyber_k, kyber_eta, pk, msgcoins: array.length(pk) == kyber_publickeybytes(kyber_k),
                lambda kyber_k, kyber_eta, pk, msgcoins, res: True): #array.length(fst(res)) == kyber_ciphertextbytes(kyber_k)
    buf = array.create(2 * kyber_symbytes, uint8(0))

    buf[0:kyber_symbytes] = sha3_256(kyber_symbytes, msgcoins)
    buf[kyber_symbytes:(2 * kyber_symbytes)] = sha3_256(kyber_publickeybytes(kyber_k), pk)

    kr = sha3_512(2 * kyber_symbytes, buf)
    ct = kyber_cpapke_encrypt(kyber_k, kyber_eta, buf[0:kyber_symbytes], pk, kr[kyber_symbytes:(2*kyber_symbytes)])
    kr[kyber_symbytes:(2*kyber_symbytes)] = sha3_256(kyber_ciphertextbytes(kyber_k), ct)
    ss = sha3_256(2*kyber_symbytes, kr)
    return (ct, ss)

def crypto_kem_dec(kyber_k:variant_k, kyber_eta:variant_eta, ct:bytes_t, sk:bytes_t(kyber_secretkeybytes)) \
    -> contract(symbytes_t,
                lambda kyber_k, kyber_eta, ct, sk: array.length(ct) == kyber_ciphertextbytes(kyber_k) and array.length(sk) == kyber_secretkeybytes(kyber_k),
                lambda kyber_k, kyber_eta, ct, sk, res: True):
    buf = array.create(2 * kyber_symbytes, uint8(0))
    pk = sk[kyber_indcpa_secretkeybytes(kyber_k):(kyber_indcpa_secretkeybytes(kyber_k) + kyber_indcpa_publickeybytes(kyber_k))]
    sk1 = sk[0:kyber_indcpa_secretkeybytes(kyber_k)]
    buf[0:kyber_symbytes] = kyber_cpapke_decrypt(kyber_k, kyber_eta, ct, sk1)
    buf[kyber_symbytes:(2 * kyber_symbytes)] = sk[(kyber_indcpa_secretkeybytes(kyber_k) + kyber_indcpa_publickeybytes(kyber_k)):(kyber_secretkeybytes(kyber_k) - kyber_symbytes)]
    kr = sha3_512(2 * kyber_symbytes, buf)
    cmp1 = kyber_cpapke_encrypt(kyber_k, kyber_eta, buf[0:kyber_symbytes], pk, kr[kyber_symbytes:(2 * kyber_symbytes)])
    kr[kyber_symbytes:(2 * kyber_symbytes)] = sha3_256(kyber_ciphertextbytes(kyber_k), ct)
    if (cmp1 == ct):
        kr[0:kyber_symbytes] = kr[0:kyber_symbytes]
    else:
        kr[0:kyber_symbytes] = sk[(kyber_secretkeybytes(kyber_k) - kyber_symbytes):kyber_secretkeybytes(kyber_k)]
    ss = sha3_256(2 * kyber_symbytes, kr)
    return ss


import logging

import click
import pandas as pd
from tqdm import tqdm

from tucasa.parsers import zonaprop

@click.command()
@click.argument('url')
@click.option('-o', '--output-file', 'archivo_salida',
              default='resultados.csv', show_default=True)
def main(url, archivo_salida):
    busqueda = zonaprop.ResultadoBusqueda(url)
    resultados = busqueda.cantidad_de_resultados
    paginas = busqueda.cantidad_de_paginas
    print(f"Encontré {resultados} resultados en {paginas} páginas.")
    propiedades = []
    for n in tqdm(range(1, paginas + 1), desc='Página'):
        url_pagina = busqueda.listado_pagina(n)
        logging.debug(f"Parseando página {url_pagina}")
        listado = zonaprop.Listado(url_pagina)
        for url in tqdm(listado.propiedades_url, desc='Propiedad',
                        leave=False):
            logging.debug(f"Parseando propiedad {url}")
            propiedad = zonaprop.Propiedad(url)
            propiedades.append(propiedad)
    info = []
    for i, p in enumerate(propiedades):
        info.append(p.informacion)
    df = pd.DataFrame(info)
    df.to_csv(archivo_salida)

if __name__ == '__main__':
    main()


import re

def atoi(s):
    max_div10 = 2147483647 / 10
    max_int = 2147483647
    min_int = -2147483648
    i = 0
    s_len = len(s)
    while i < s_len and s[i] == ' ':
        i += 1
    sign = 1
    if i < s_len and s[i] == '+':
        i += 1
    elif i < s_len and s[i] == '-':
        sign = -1
        i += 1
    num = 0
    while i < s_len and s[i].isdigit():
        digit = int(s[i])
        if num > max_div10 or num == max_div10 and digit >= 8:
            return max_int if sign == 1 else min_int
        num = num * 10 + digit
        i += 1
    return sign * num

def atoi_reg(s):
    '''
    THIS SOLUTION IS NOT OK
    The string can contain additional characters after those that form the integral number,
    which are ignored and have no effect on the behavior of this function.
    If the first sequence of non-whitespace characters in str is not a valid integral number,
    or if no such sequence exists because either str is empty or it contains only whitespace characters,
    no conversion is performed.
    If no valid conversion could be performed, a zero value is returned.
    If the correct value is out of the range of representable values,
    the maximum integer value (2147483647) or the minimum integer value (–2147483648) is returned.
    '''
    s = str(s).rstrip()
    print(s)
    s = re.findall(r'^[+-]?\d+', s)
    try:
        res = int(''.join(s))
        max_int = 2147483647
        min_int = -2147483648
        if res > max_int:
            return max_int
        if res < min_int:
            return min_int
        return res
    except:
        return 0

print(atoi('   010'))