#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
 @author: Chao
 @contact: zhaochaocs@gmail.com
 @time: 5/9/2019 11:00 AM
"""
import argparse
import opts
import pickle
from collections import defaultdict

import numpy as np
from tqdm import tqdm
import dgl

import torch
import torch.nn as nn

from plan.GCNEncoder import GCN, load_bin_vec, GCNConfig
from plan.dataset import Dataset
from plan.plan_eval import eval_acc_strict_loop, eval_strict, eval_strict2

import os
os.environ["CUDA_VISIBLE_DEVICES"] = "1"

torch.manual_seed(1)  # cpu
torch.cuda.manual_seed(1)  # gpu
np.random.seed(1)  # numpy
torch.backends.cudnn.deterministic = True  # cudnn

# import traceback
# import warnings
# import sys
#
# def warn_with_traceback(message, category, filename, lineno, file=None, line=None):
#
#     log = file if hasattr(file,'write') else sys.stderr
#     traceback.print_stack(file=log)
#     log.write(warnings.formatwarning(message, category, filename, lineno, line))
#
# warnings.showwarning = warn_with_traceback

# with open('delex_dict.json') as data_file:
#     delex_dict = json.load(data_file)

def parse_args():
    parser = argparse.ArgumentParser(
        description='plan.py',
        formatter_class=argparse.ArgumentDefaultsHelpFormatter)

    opts.add_md_help_argument(parser)
    opts.plan_opts(parser)

    opt = parser.parse_args()
    torch.manual_seed(opt.seed)

    return opt

def batch_train(net, batched_data):
    batched_graphs, batched_sizes, batched_labels, batched_split = zip(*batched_data)
    G = dgl.batch(batched_graphs)
    L = torch.cat([torch.tensor(label) for label in batched_labels])

    # for G, G_sizes, L in train_data.graph_batch_generator(triple_batch_size, True):
    if torch.cuda.is_available():
        L = L.cuda()
    logits = net(G, batched_sizes)

    # we only compute loss for labeled nodes
    loss = bce_loss(logits, L) / L.sum()
    return loss

def batch_test(net, batched_data, pred_path_dict):
    batched_graphs, batched_sizes, batched_ids, batched_local_predicates, batched_node_feature_ids = zip(*batched_data)
    G = dgl.batch(batched_graphs)
    cur_batch_size, cur_triple_size = len(batched_sizes), batched_sizes[0]
    local_pred = torch.zeros(cur_batch_size, cur_triple_size).long()

    for step in range(cur_triple_size):
        with torch.no_grad():
            logits = net(G, batched_sizes)  # n
            logits = logits.cpu()
        logits = logits.reshape(-1, cur_triple_size)

        max_value, max_idx = torch.max(logits, 1)
        local_pred[:, step] = max_idx
        accessed = torch.zeros(cur_batch_size, cur_triple_size).long()
        accessed[range(cur_batch_size), max_idx] = 1
        accessed = accessed.reshape(-1, 1)
        if torch.cuda.is_available():
            accessed = accessed.cuda()
        G.ndata["access"][G.ndata['spo'][:, 1].bool()] += accessed

        G.ndata["pre_access"] *= 0
        G.ndata["pre_access"][G.ndata['spo'][:, 1].bool()] += accessed

    local_pred = local_pred.tolist()
    # global_pred = batched_node_feature_ids.gather(index=local_pred, dim=1).tolist()

    # max_idx = max_idx.tolist()
    for i, id in enumerate(batched_ids):
        tripleset_id = id.strip()
        pred_path_dict[tripleset_id] = local_pred[i]

def eval_plan(src_file, pred_path_dict):
    lex_id_file = src_file[:-13] + 'translate.lexid.txt'
    golden_file = src_file[:-13] + 'src-rel-order.txt'
    pred_file = src_file[:-13] + 'src-rel-order-pred.txt'
    triple_file = src_file[:-14] + '.triple'
    with open(lex_id_file, 'r', encoding='utf-8') as fr_id, \
            open(pred_file, 'w', encoding='utf-8') as fw_tp:
        for id in fr_id:
            id = id.strip()
            if int(id.split("_")[1]) < triple_len_filter:
                fw_tp.write("0\n")
            else:
                plan = list(map(str, pred_path_dict[id]))
                fw_tp.write(" ".join(plan) + '\n')

    for mode in ['seen', 'unseen', 'whole']:
        acc, bleu = eval_strict2(pred_file, golden_file, lex_id_file, triple_file,
                                 baseline_path_dict=None, mode=mode)
        return acc, bleu

if __name__ == '__main__':

    opt = parse_args()

    edge_to_id = {e: i for i, e in enumerate(['sp', 'po', 'op', 'ps', 'll', 'ne'])}
    triple_len_filter = 2

    node_to_id, id_to_node = Dataset.build_node_mapping([opt.train_src, opt.test_src])

    # process data (delexicalization and idlization)
    train_data = Dataset()
    train_data.read_examples(type="train", opt=opt, node_to_id=node_to_id, triple_len_filter=triple_len_filter)
    print('Load the training data done...')
    dev_data = Dataset()
    dev_data.read_examples(type="valid", opt=opt, node_to_id=node_to_id, triple_len_filter=triple_len_filter)
    print('Load the dev data done...')
    test_data = Dataset()
    test_data.read_examples(type="test", opt=opt, node_to_id=node_to_id, triple_len_filter=triple_len_filter)
    print('Load the test data done...')

    # emb_weight = load_bin_vec(fname="/home/chao/tools/glove/glove.6B.100d.w2v.txt", vocab=node_to_id, emb_size=100)
    emb_weight = None

    # init model and data
    model_config = GCNConfig(vocab_size=len(node_to_id), emb_size=100, emb_weight=emb_weight, freeze=True,
              in_feats=105, hidden_size=100, num_classes=1, edge_to_id=edge_to_id, num_hidden_layers=2)
    net = GCN(model_config)
    if torch.cuda.is_available():
        net = net.cuda()

    bce_loss = nn.KLDivLoss(reduction="sum")
    optimizer = torch.optim.Adam(net.parameters(), lr=0.001)

    triple_batch_size = 100
    graph_batch_size = 100

    train_graphs, train_triple_sizes, train_labels, train_split = train_data.load_dataset()
    dev_graphs, dev_triple_sizes, dev_ids, dev_local_predicates, dev_node_feature_ids = dev_data.load_test_dataset()
    test_graphs, test_triple_sizes, test_ids, test_local_predicates, test_node_feature_ids = test_data.load_test_dataset()

    random_baselines_dev = dev_data.generate_random_plan()
    random_baselines_test = test_data.generate_random_plan()

    prev_acc = 0

    # train the model
    for epoch in range(3):
        net.train()
        loss_value = 0

        with tqdm(total=train_data.graph_size / triple_batch_size) as pbar:
            for batched_data in Dataset._batch_generator(list(zip(train_graphs, train_triple_sizes, train_labels, train_split)),
                                                         batch_size=triple_batch_size, shuffle=True):
                pbar.update(1)
                loss = batch_train(net, batched_data)
                loss_value += loss.item()

                optimizer.zero_grad()
                loss.backward()
                optimizer.step()

        print('Epoch %d | Loss : %.4f' % (epoch, loss_value))

        # eval on valid set
        pred_path_dict = dict()
        for batched_data in Dataset.data_batch_generator(
                data=list(zip(dev_graphs, dev_triple_sizes, dev_ids, dev_local_predicates, dev_node_feature_ids)),
                batch_size=100, shuffle=False, group=True):
            batch_test(net, batched_data, pred_path_dict)
        acc, bleu = eval_plan(opt.valid_src, pred_path_dict)

        if acc > prev_acc:
            prev_acc = acc
            if os.path.exists(opt.model_output):
                os.remove(opt.model_output)
            torch.save(net.state_dict(), opt.model_output)

    with open('data/plan_word_mapping.pkl', 'wb') as fwb:
        pickle.dump([node_to_id, id_to_node], fwb)
    with open('data/plan_config.pkl', 'wb') as fwb:
        pickle.dump(model_config, fwb)


import sys
import argparse
from utils.load_data import make_dataset_pickle
import time

for dataset in ['NCI1', 'NCI109', 'PTC', 'PROTEINS', 'MUTAG']:
    gname = 'data/{}.graph'.format(dataset)
    lname = 'data/{}.node'.format(dataset)
    tname = 'data/{}.label'.format(dataset)
    pickle_name = 'data/{}.pickle'.format(dataset)

    start_time = time.time()
    print("Starting to pickle...")
    make_dataset_pickle(gname, lname, tname, pickle_name)
    print("Done pickling!")
    print("Time elapsed: {:.2f}".format(time.time() - start_time))


#!/usr/bin/python3
# -*- coding: utf-8; tab-width: 4; indent-tabs-mode: t -*-

import sys
sys.path.append('../lib')
from fvm_util import FvmUtil

class Test:

	def main(self):
		FvmUtil.createWinUsbImg("abc.img", 1024, "ntfs")

t = Test()
t.main()


import pymc as pm
from matplotlib import pyplot as plt

N = 100
p = pm.Uniform("freq_cheating", 0, 1)

@pm.deterministic
def p_skewed(p=p):
    return 0.5 * p + 0.25

X = 100
yes_responses = pm.Binomial("number_cheaters", 100, p_skewed, value=X, observed=True)

model = pm.Model([yes_responses, p_skewed, p])

mcmc = pm.MCMC(model)
mcmc.sample(25000, 2500)

p_trace = mcmc.trace("freq_cheating")[:]
plt.hist(p_trace, histtype="stepfilled", normed=True, alpha=0.85, bins=30,
         label="posterior distribution", color="#348ABD")
plt.vlines([.05, .35], [0, 0], [5, 5], alpha=0.2)
plt.xlim(0, 1)
plt.legend()

plt.show()

Master/Anul I/Semestrul I/Programare Probabilista/Lab 3/cheating_freq_2.py


from django import forms
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Submit, Layout, Fieldset, HTML
from crispy_forms.bootstrap import FormActions, AppendedText

from .models import DataSource, ECCServer, DataRouter, Experiment, ConfigId, RunMetadata, Observable, Measurement

class CrispyModelFormBase(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.helper = FormHelper()
        self.helper.form_method = 'post'
        self.helper.form_class = 'form-horizontal'
        self.helper.label_class = 'col-lg-2'
        self.helper.field_class = 'col-lg-8'

        self.helper.add_input(Submit('submit', 'Submit'))

class DataSourceForm(CrispyModelFormBase):
    class Meta:
        model = DataSource
        fields = ['name', 'ecc_server', 'data_router']

class ECCServerForm(CrispyModelFormBase):
    class Meta:
        model = ECCServer
        fields = ['name', 'ip_address', 'port', 'log_path', 'config_root', 'config_backup_root']

    def save(self, commit=True):
        instance = super().save(commit=False)
        current_expt = Experiment.objects.get(is_active=True)
        instance.experiment = current_expt
        instance.save()
        self.save_m2m()
        return instance

class DataRouterForm(CrispyModelFormBase):
    class Meta:
        model = DataRouter
        fields = ['name', 'ip_address', 'port', 'connection_type', 'log_path']

    def save(self, commit=True):
        instance = super().save(commit=False)
        current_expt = Experiment.objects.get(is_active=True)
        instance.experiment = current_expt
        instance.save()
        self.save_m2m()
        return instance

class ConfigSelectionForm(CrispyModelFormBase):
    """A form used to select a config file set for an ECC server."""
    class Meta:
        model = ECCServer
        fields = ['selected_config']
        help_texts = {
            'selected_config': 'Name is given as "describe/prepare/configure" triple.'
        }

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['selected_config'].queryset = ConfigId.objects.filter(ecc_server=self.instance)

class ExperimentForm(CrispyModelFormBase):
    class Meta:
        model = Experiment
        fields = ['name']

class ExperimentChoiceForm(forms.Form):
    experiment = forms.ModelChoiceField(queryset=Experiment.objects.all(), label='Choose experiment')

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.helper = FormHelper()
        self.helper.form_method = 'post'

        new_expt_btn_html = """
        New experiment
        """
        self.helper.layout = Layout(
            'experiment',
            Submit('submit', 'Load experiment', css_class='btn btn-primary btn-block'),
            HTML("
or
"),
            HTML(new_expt_btn_html),
        )

class NewExperimentForm(forms.ModelForm):
    class Meta:
        model = Experiment
        fields = ['name']
        labels = {'name': 'Experiment name'}

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.helper = FormHelper()
        self.helper.form_method = 'post'

        self.helper.add_input(Submit('submit', 'Create experiment', css_class='btn btn-primary btn-block'))

    def save(self, commit=True):
        """Override to make the new experiment the active one."""
        instance = super().save(commit=False)
        instance.is_active = True
        instance.save()
        self.save_m2m()

        return instance

class RunMetadataForm(CrispyModelFormBase):
    class Meta:
        model = RunMetadata
        fields = ['run_number', 'run_class', 'title', 'start_datetime', 'stop_datetime', 'config_name']

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        observables = Observable.objects.filter(experiment=self.instance.experiment)

        field_type_map = {
            Observable.INTEGER: forms.IntegerField,
            Observable.FLOAT: forms.FloatField,
            Observable.STRING: forms.CharField,
        }

        for obs in observables:
            measurement, created = Measurement.objects.get_or_create(run_metadata=self.instance, observable=obs)
            field_type = field_type_map[obs.value_type]
            self.fields[obs.name] = field_type(initial=measurement.value, required=False, help_text=obs.comment)

        # Build form layout
        self.helper.inputs = None  # Override default input provided by base class
        run_fieldset = Fieldset(
            'Run information',
            *self.Meta.fields
        )
        measurement_fieldset = Fieldset(
            'Measurements',
            *(AppendedText(obs.name, obs.units) if obs.units else obs.name for obs in observables)
        )
        prepop_btn_html = """

                Fill from last run

        """.format(self.instance.pk)
        buttons = FormActions(
            Submit('submit', 'Submit'),
            HTML(prepop_btn_html),
        )
        self.helper.layout = Layout(
            run_fieldset,
            measurement_fieldset,
            buttons,
        )

    def save(self, commit=True):
        for name, value in self.cleaned_data.items():
            if name in self.Meta.fields:
                continue

            observable = Observable.objects.get(name=name, experiment=self.instance.experiment)
            measurement = Measurement.objects.get(run_metadata=self.instance, observable=observable)
            measurement.value = value
            measurement.save()

        return super().save(commit=commit)

class ObservableForm(CrispyModelFormBase):
    class Meta:
        model = Observable
        fields = ['name', 'value_type', 'units', 'comment']
        help_texts = {
            'comment': 'This comment will be shown on the run sheet next to the field for this measurement.',
        }

    def __init__(self, *args, **kwargs):
        self.disabled_fields = kwargs.pop('disabled_fields', [])
        super().__init__(*args, **kwargs)

        for field_name in self.disabled_fields:
            try:
                self.fields[field_name].disabled = True
            except KeyError:
                raise ValueError('Cannot disable field {:s} which does not exist.'.format(field_name)) from None

class DataSourceListUploadForm(forms.Form):
    data_source_list = forms.FileField()

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.helper = FormHelper()
        self.helper.form_id = 'datasource-list-upload-form'
        self.helper.form_method = 'post'
        self.helper.add_input(Submit('submit', 'Submit'))

class EasySetupForm(forms.Form):
    # General fields
    num_cobos = forms.IntegerField(label='Number of CoBos',
                                   help_text='CoBos will be numbered sequentially starting at 0.')
    one_ecc_server = forms.BooleanField(required=False, label='Use one ECC server for all sources?',
                                        help_text='This includes the MuTAnT, if present.')

    # CoBo configuration fields
    first_cobo_ecc_ip = forms.GenericIPAddressField(protocol='IPv4', label='IP address of first CoBo ECC server')
    first_cobo_data_router_ip = forms.GenericIPAddressField(protocol='IPv4',
                                                            label='IP address of first CoBo data router')
    cobo_ecc_log_file_location = forms.CharField(max_length=500, label='Location of CoBo ECC server log files')
    cobo_router_log_file_location = forms.CharField(max_length=500, label='Location of CoBo data router log files')
    cobo_config_root = forms.CharField(max_length=500, label='Location of CoBo config files')
    cobo_config_backup_root = forms.CharField(max_length=500, label='CoBo config file backup destination')

    # MuTAnT configuration fields
    mutant_is_present = forms.BooleanField(required=False, label='Is there a MuTAnT?',
                                           help_text='The remaining fields are only required if the MuTAnT is present.')
    mutant_ecc_ip = forms.GenericIPAddressField(protocol='IPv4', required=False,
                                                label='IP address of MuTAnT ECC server')
    mutant_data_router_ip = forms.GenericIPAddressField(protocol='IPv4', required=False,
                                                        label='IP address of MuTAnT data router')
    mutant_ecc_log_file_location = forms.CharField(max_length=500, required=False,
                                                   label='Location of MuTAnT ECC server log files')
    mutant_router_log_file_location = forms.CharField(max_length=500, required=False,
                                                      label='Location of MuTAnT data router log files')
    mutant_config_root = forms.CharField(max_length=500, required=False,
                                         label='Location of MuTAnT config files')
    mutant_config_backup_root = forms.CharField(max_length=500, required=False,
                                                label='MuTAnT config file backup destination')

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.helper = FormHelper()
        self.helper.form_id = 'easy-setup-form'
        self.helper.form_method = 'post'

        general_help = """

Use this form to quickly set up the system with some default values. Note that this will
                replace the current configuration of the system if it's already set up.

        """

        ip_help = """

The next two fields configure the IP addresses for the CoBos. The first CoBo will get an
                ECC server and data router with these IP addresses. This first address will then be incremented
                by one for each remaining CoBo.

Note that if there is only one ECC server, the ECC server IP address entered below will apply
                to all CoBos and the MuTAnT, if present.

        """

        config_file_help = """

The next fields set the paths to config files and log files. These paths are on
                the remote computer where the GET software is running. These paths will be applied
                to each ECC server and data router created, so if they are not the same for each CoBo,
                they will need to be edited manually later.

                    Note: These must be full paths, and they may not contain '~'.

        """

        delete_warning = """

                Warning: Submitting this form will remove all ECC servers, data routers, and data sources from
                this experiment and replace them with new ones!

        """

        self.helper.layout = Layout(
            HTML(general_help),
            Fieldset(
                'CoBo setup',
                'num_cobos',
                'one_ecc_server',
                HTML(ip_help),
                'first_cobo_ecc_ip',
                'first_cobo_data_router_ip',
                HTML(config_file_help),
                'cobo_ecc_log_file_location',
                'cobo_router_log_file_location',
                'cobo_config_root',
                'cobo_config_backup_root',
            ),
            Fieldset(
                'MuTAnT setup',
                'mutant_is_present',
                'mutant_ecc_ip',
                'mutant_data_router_ip',
                'mutant_ecc_log_file_location',
                'mutant_router_log_file_location',
                'mutant_config_root',
                'mutant_config_backup_root',
            ),
            HTML(delete_warning),
            FormActions(Submit('submit', 'Submit'))
        )

    def clean(self):
        super().clean()

        if self.cleaned_data['mutant_is_present']:
            if not self.cleaned_data['one_ecc_server'] and self.cleaned_data['mutant_ecc_ip'] == '':
                raise forms.ValidationError('Must provide ECC IP for MuTAnT if MuTAnT is present')
            if self.cleaned_data['mutant_data_router_ip'] == '':
                raise forms.ValidationError('Must provide router IP for MuTAnT if MuTAnT is present')
            if self.cleaned_data['mutant_ecc_log_file_location'] == '':
                raise forms.ValidationError('Must provide ECC log file path for MuTAnT if MuTAnT is present')
            if self.cleaned_data['mutant_router_log_file_location'] == '':
                raise forms.ValidationError('Must provide data router log file path for MuTAnT if MuTAnT is present')
            if self.cleaned_data['mutant_config_root'] == '':
                raise forms.ValidationError('Must provide config file directory for MuTAnT if MuTAnT is present')
            if self.cleaned_data['mutant_config_backup_root'] == '':
                raise forms.ValidationError('Must provide config file backup root for MuTAnT if MuTAnT is present')


from get_json_data import GetJsonData

class Animal:

    def __init__(self, species, name, gender, age, weight):
        self.species = species
        self.age = (int)(age) * 12
        self.name = name
        self.gender = gender
        self.weight = (int)(weight)
        self.pregnant = False
        self.pregnancy = 0
        self.was_pregnant = False
        self.after_pregnancy = 0
        self.info = GetJsonData("database.json", self.species)

    # how much food the animal eats in kilos
    # and it can be multiply by the cost of eaten food so we will have the
    # outcomes
    def eat(self):
        return self.weight * self.info.food_for_weight()

    def grows(self):
        self.age += 1
        if self.weight < self.info.average_weight():
            self.weight += self.info.gained_weight_for_month()
            if self.weight > self.info.average_weight():
                self.weight = self.info.average_weight()

    # We could add dead before max age reached
    def die(self):
        if self.chance_of_dying >= 1:
            return True
        return False

    def chance_of_dying(self):
        return (
            (self.age / 12) / self.info.life_expectancy()
        )


# 事前にgoogletransをインストールしておく
# 参考URL
# https://qiita.com/_yushuu/items/83c51e29771530646659
# https://sig9.hatenablog.com/entry/2021/08/26/000000
# pip install googletrans だとバージョンが古いため動かない
# pip uninstall googletrans アンインストール方法
# pip install googletrans=4.0.0-rc1 が最新バージョン

from googletrans import Translator
import eel

#課題１
def translate_input(word: str):
	translator = Translator()
	trans_word = translator.translate(text=word, src="en", dest="ja").text
	print(f"翻訳結果：{trans_word}")
	return trans_word

#Webアプリ用
def translate_input_lang(word: str, src_lang: str, dest_lang: str):
	translator = Translator()
	trans_word = translator.translate(text=word, src=src_lang, dest=dest_lang).text
	print(f"翻訳結果：{trans_word}")
	return trans_word

if __name__ == "__main__":
	en_words = input("英語を翻訳します。翻訳したい英語を入力してください：")
	translate_input(en_words)


#!/usr/bin/env python3
# vim: set fileencoding=UTF-8 :

import argparse
import csv
import json

def get_maps_urls(csv_path):
    """
    Load the vendor_map column from `csv_path` into a list.
    """
    with open(csv_path) as fo:
        reader = csv.reader(fo)
        headers = next(reader)
        url_idx = headers.index('vendor-map')
        maps_urls = {row[url_idx] for row in reader}

    return list(maps_urls)

def fill_start_urls(json_path, maps_urls, in_place=False):
    with open(json_path, 'r', encoding='utf8') as fo:
        scrape_job = json.load(fo)

    scrape_job['startUrl'] = maps_urls
    if in_place is True:
        out_path = json_path
    else:
        out_path = json_path.rstrip('json') + 'out.json'

    with open(out_path, 'w', encoding='utf8') as fo:
        json.dump(scrape_job, fo, indent=4)

    print(f"Updated {out_path} with {len(maps_urls)} URLs.")

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument('csv_path')
    parser.add_argument('json_path')
    parser.add_argument('--in-place', action='store_true')
    args = parser.parse_args()
    urls = get_maps_urls(args.csv_path)
    fill_start_urls(args.json_path, urls, in_place=args.in_place)


from urllib import request

if __name__ == '__main__':
    url = 'http://www.csdn.net/'
    head = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit\
            /537.36 (KHTML, like Gecko) Chrome/27.0.1453.94 Safari/537.36'
    }
    req = request.Request(url, headers=head)
    response = request.urlopen(req)
    html = response.read().decode('utf-8')
    print(html)


import tempfile

import pytest

from gretel_trainer.benchmark import create_dataset, Datatype
from gretel_trainer.benchmark.core import BenchmarkException

def test_creating_good_datasets(df):
    str_datatype = create_dataset(df, datatype="tabular", name="via_str")
    capital_str_datatype = create_dataset(df, datatype="TABULAR", name="via_str")
    enum_datatype = create_dataset(df, datatype=Datatype.TABULAR, name="via_str")
    with tempfile.NamedTemporaryFile() as f:
        df.to_csv(f.name, index=False)
        file_source = create_dataset(f.name, datatype="tabular", name="from_file")

    for dataset in [str_datatype, capital_str_datatype, enum_datatype, file_source]:
        assert dataset.row_count == 3
        assert dataset.column_count == 2

def test_creating_bad_datasets(df):
    with pytest.raises(BenchmarkException):
        create_dataset([1, 2, 3], datatype="tabular", name="nope")  # type:ignore

    with pytest.raises(BenchmarkException):
        create_dataset("nonexistent.csv", datatype="tabular", name="nope")

    with pytest.raises(BenchmarkException):
        create_dataset(df, datatype="nonsense", name="nope")


size = int(input("Enter step size : "))

def printPyramid(n):
     s = ''
     for i in range(1, n+1):
          s += '\n'
          for j in range(1, i+1):
                 temp = i * j
                 s += ' ' + str(temp)

     print(s)

printPyramid(size)


#!/usr/bin/env python
# -*- coding: UTF-8 -*-

"""KnickKnack"""

__name__ = "KnickKnack"
__author__ = 'Shane R. Spencer'
__email__ = "shane@bogomip.com"
__license__ = 'None'
__copyright__ = '2013 Shane R. Spencer'
__version__ = '0.0.1'
__status__ = "Prototype"
__description__ = "KnackHQ Data Dumper"

KNACKHQ_API_URI = "https://api.knackhq.com/v1"


from PIL import Image, ImageDraw, ImageFont
from pixel import Pixel

class SerializeablePixel(Pixel):
    def __init__(self, pixel):
        super().__init__(pixel)

    def __json__(self):
        return dict(
            {"color": self.color, "char": self.char, "grayscale": self.grayscale}
        )

def create_gif_from_images(images, backgroundColor, fontFamilyNumber, textColor):
    createdImages = []

    for image in images:
        createdImages.append(
            create_image_from_ascii_string(
                image, backgroundColor, fontFamilyNumber, textColor, 8
            )
        )

    filename = "./static/images/conversions/gifConversion.gif"
    createdImages[0].save(
        filename, save_all=True, append_images=createdImages, duration=100, loop=0
    )

    return filename

def make_gif_ascii_string(image_path, character_key, width=80, height=None):
    width = int(width)
    if height is not None:
        height = int(height)

    gifImage = Image.open(image_path)

    firstImage = make_image_ascii_string(gifImage, character_key, width, height)
    frames = []

    for frame in range(0, gifImage.n_frames, 2):
        gifImage.seek(frame)
        frames.append(make_image_ascii_string(gifImage, character_key, width, height))

    responseData = {"previewImage": firstImage, "frames": frames}

    return responseData

def create_image_from_ascii_string(
    image_text, background_color, font_family_number, text_color, font_size=15
):
    # Create the image with the correct background color
    # Set the size to be the character width * number of characters

    fonts = {
        1: "SourceCodePro-Black",
        2: "CourierPrime-Bold",
        3: "DMMono-Medium",
        4: "SpaceMono-Bold",
        5: "RobotoMono-Bold",
    }

    imageHeight = len(image_text)
    imageWidth = len(image_text[0])
    fontSize = font_size
    fontName = fonts.get(int(font_family_number))
    fontWidth = fontSize * 0.5

    img = Image.new(
        "RGB",
        (int(fontWidth * imageWidth * 1.5), int(imageHeight * fontSize)),
        color=background_color,
    )

    # Get the chosen font
    fnt = ImageFont.truetype(f"./static/fonts/{fontName}.ttf", fontSize)

    # Draw the image
    d_img = ImageDraw.Draw(img)

    # For each row
    #   For each character
    #     Place a colored character with the correct width and height offset
    for r in range(0, imageHeight - 1):
        for c in range(0, imageWidth - 1):

            if text_color == "Black":
                fontColor = (0, 0, 0)
            else:
                fontColor = tuple(image_text[r][c].get("color"))

            d_img.text(
                (int(fontWidth * c * 1.5), int(fontSize * r)),
                image_text[r][c].get("char"),
                font=fnt,
                fill=(fontColor),
            )

    return img

def make_image_ascii_string(image_path, character_key, width=80, height=None):
    """Given a list of pixels, returns the ascii representation of them
    Takes the pixels of the image, the character length of the ascii result
    and the height in number of lines."""

    width = int(width)
    if height is not None:
        height = int(height)

    # get a matrix of pixels from an image
    pixels = get_image_pixels(image_path)

    # get the size reduction factors for the image
    reduction_factors = get_image_reduction_factors(pixels, width, height)

    # reduce the images size using the reduction factors
    reduced_pixels = reduce_image_size(
        pixels, reduction_factors[0], reduction_factors[1]
    )

    # get the string representation of the image
    image_text = make_ascii_string_from_pixels(reduced_pixels, character_key)

    return image_text

def get_image_pixels(image):

    if type(image) is not str:
        # get the imageObject
        im = image
    else:
        # open the image
        im = Image.open(image)

    # convert the image to use rgb format
    im = im.convert("RGB")

    # get list of raw pixels
    raw_pixels = list(im.getdata())
    width, height = im.size

    # process pixel list into a matrix
    pixels = [raw_pixels[i * width : (i + 1) * width] for i in range(height)]

    return pixels

def get_image_reduction_factors(pixels, maxwidth, maxheight=None):
    """Calculates the factors for reducing the size of an image so
    that it stays proportional and fits within the maxwidth and maxheight
    returns a tuple (width_factor, height_factor)"""

    image_width = len(pixels[0])
    image_height = len(pixels)

    height_ratio = (image_height * 2.8) / (image_width * 4)

    width_reduction_factor = int(image_width / maxwidth)

    # if no maxheight is given, make the height proportional to width
    if maxheight is None:
        height_reduction_factor = int((image_height / ((height_ratio * maxwidth))))
    else:
        height_reduction_factor = int(image_height / maxheight)

    if height_reduction_factor < 1:
        height_reduction_factor = 1
    if width_reduction_factor < 1:
        width_reduction_factor = 1

    return (width_reduction_factor, height_reduction_factor)

def reduce_image_size(pixels, width_reduction_factor, height_reduction_factor):
    """reduces the size of an array of pixels by the given reduction factors for
    width and height"""

    reduced_list = []
    row = 0

    while row < len(pixels) - height_reduction_factor:
        column = 0
        row_list = []

        while column < len(pixels[0]):

            pixel = SerializeablePixel(pixels[row][column])

            row_list.append(pixel)

            column += width_reduction_factor

        reduced_list.append(row_list)
        row += height_reduction_factor

    return reduced_list

def make_ascii_string_from_pixels(pixels, ascii_key):
    """converts an array of rgb pixels into an array of ascii
    symbols based on the brightness of each pixel"""
    ascii_character_list = []

    for row in range(0, len(pixels)):
        ascii_character_row = []
        for col in range(0, len(pixels[0])):

            # get the grayscale value of the pixel from its color
            pixels[row][col].getGrayscaleFromColor()

            # set the pixel to the corresponding char from the key
            pixels[row][col].char = ascii_key[
                pixels[row][col].grayscale % len(ascii_key) - 1
            ]

            # add the pixel to the display array
            ascii_character_row.append(pixels[row][col])

        ascii_character_list.append(ascii_character_row)

    return ascii_character_list


# -*- coding: utf-8 -*-
from sanic import Sanic
from sanic.request import RequestParameters
from sanic.response import json

app = Sanic(__name__)

@app.route('/', methods=['GET'])
async def verify(request):
    """ Verify Token.
    when the endpoint is registered as a webhook, it must echo back
    the 'hub.challenge' value it receives in the query arguments
    """
    query_params = RequestParameters()
    if not query_params:
        return json({'response': 'hacer > hablar'})

    if query_params.get('hub.verify_token') == 'hacker':
        return json({
            query_params.get('hub.challenge'),
        })
    return json({'Err, Token Invalid'})

@app.route('/', methods=['POST'])
async def webhook(request):
    messages = json(request.body)
    for entry in messages['entry']:
        for message in entry['messaging']:
            return json({'response': '{} o/'.format(message)})
    return json({'response': 'o/'})


import json
import logging
from datetime import date
from typing import Iterable, Optional

from django.conf import settings
from django.db import models
from django.db.models import Max, Subquery
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _

import jq
import jsonschema
from rest_framework import serializers
from vng_api_common.constants import Archiefstatus
from vng_api_common.validators import (
    UniekeIdentificatieValidator as _UniekeIdentificatieValidator,
    URLValidator,
)

from openzaak.components.documenten.constants import Statussen
from openzaak.components.documenten.models import (
    EnkelvoudigInformatieObject,
    EnkelvoudigInformatieObjectCanonical,
)
from openzaak.utils.auth import get_auth
from openzaak.utils.serializers import get_from_serializer_data_or_instance

from ..models import Zaak

logger = logging.getLogger(__name__)

class RolOccurenceValidator:
    """
    Validate that max x occurences of a field occur for a related object.

    Should be applied to the serializer class, not to an individual field
    """

    message = _("There are already {num} `{value}` occurences")

    def __init__(self, omschrijving_generiek: str, max_amount: int = 1):
        self.omschrijving_generiek = omschrijving_generiek
        self.max_amount = max_amount

    def set_context(self, serializer):
        """
        This hook is called by the serializer instance,
        prior to the validation call being made.
        """
        # Determine the existing instance, if this is an update operation.
        self.instance = getattr(serializer, "instance", None)

    def __call__(self, attrs):
        roltype = attrs["roltype"]

        attrs["omschrijving"] = roltype.omschrijving
        attrs["omschrijving_generiek"] = roltype.omschrijving_generiek

        if attrs["omschrijving_generiek"] != self.omschrijving_generiek:
            return

        is_noop_update = (
            self.instance
            and self.instance.omschrijving_generiek == self.omschrijving_generiek
        )
        if is_noop_update:
            return

        existing = (
            attrs["zaak"]
            .rol_set.filter(omschrijving_generiek=self.omschrijving_generiek)
            .count()
        )

        if existing >= self.max_amount:
            message = self.message.format(
                num=existing, value=self.omschrijving_generiek
            )
            raise serializers.ValidationError(
                {"roltype": message}, code="max-occurences"
            )

class UniekeIdentificatieValidator(_UniekeIdentificatieValidator):
    """
    Valideer dat de combinatie van bronorganisatie en zaak uniek is.
    """

    message = _("Deze identificatie bestaat al voor deze bronorganisatie")

    def __init__(self):
        super().__init__("bronorganisatie", "identificatie")

class NotSelfValidator:
    code = "self-forbidden"
    message = _("The '{field_name}' may not be a self-reference")

    def set_context(self, field):
        """
        This hook is called by the serializer instance,
        prior to the validation call being made.
        """
        # Determine the existing instance, if this is an update operation.
        self.field_name = field.field_name
        self.instance = getattr(field.root, "instance", None)

    def __call__(self, obj: models.Model):
        if self.instance == obj:
            message = self.message.format(field_name=self.field_name)
            raise serializers.ValidationError(message, code=self.code)

class HoofdzaakValidator:
    code = "deelzaak-als-hoofdzaak"
    message = _("Deelzaken van deelzaken wordt niet ondersteund.")

    def __call__(self, obj: models.Model):
        if obj.hoofdzaak_id is not None:
            raise serializers.ValidationError(self.message, code=self.code)

class HoofdZaaktypeRelationValidator:
    code = "invalid-deelzaaktype"
    message = _("Zaaktype niet vastgelegd in deelzaaktypen van hoofdzaak.zaaktype")
    requires_context = True

    def __call__(self, attrs, serializer):
        hoofdzaak = get_from_serializer_data_or_instance("hoofdzaak", attrs, serializer)
        zaaktype = get_from_serializer_data_or_instance("zaaktype", attrs, serializer)

        # keys may be missing because of earlier validation
        if not hoofdzaak or not zaaktype:
            return

        if zaaktype not in hoofdzaak.zaaktype.deelzaaktypen.all():
            raise serializers.ValidationError(
                {"hoofdzaak": self.message}, code=self.code
            )

class CorrectZaaktypeValidator:
    code = "zaaktype-mismatch"
    message = _("De referentie hoort niet bij het zaaktype van de zaak.")

    def __init__(self, url_field: str, zaak_field: str = "zaak", resource: str = None):
        self.url_field = url_field
        self.zaak_field = zaak_field
        self.resource = resource or url_field

    def __call__(self, attrs):
        url = attrs.get(self.url_field)
        zaak = attrs.get(self.zaak_field)
        if not url or not zaak:
            return

        if url.zaaktype != zaak.zaaktype:
            raise serializers.ValidationError(self.message, code=self.code)

class DateNotInFutureValidator:
    code = "date-in-future"
    message = _("Deze datum mag niet in de toekomst zijn")

    def __call__(self, value):
        now = timezone.now()

        if type(value) is date:  # noqa - datetime is subclass of date
            now = now.date()

        if value > now:
            raise serializers.ValidationError(self.message, code=self.code)

class ZaakArchiveIOsArchivedValidator:
    """
    On archival of a zaak, validate that the related documents are archived.
    """

    requires_context = True

    def __call__(self, attrs: dict, serializer: serializers.Serializer):
        instance: Optional[Zaak] = serializer.instance

        default_archiefstatus = (
            instance.archiefstatus if instance else Archiefstatus.nog_te_archiveren
        )
        archiefstatus = attrs.get("archiefstatus", default_archiefstatus)

        # no archiving status set -> nothing to do
        if archiefstatus == Archiefstatus.nog_te_archiveren:
            return

        # create of a zaak, there is no existing data to validate
        if instance is None:
            return

        documents_not_archived_error = serializers.ValidationError(
            {
                "archiefstatus": _(
                    "Er zijn gerelateerde informatieobjecten waarvan de `status` nog niet gelijk is aan "
                    "`gearchiveerd`. Dit is een voorwaarde voor het zetten van de `archiefstatus` "
                    "op een andere waarde dan `nog_te_archiveren`."
                ),
            },
            code="documents-not-archived",
        )

        if not settings.CMIS_ENABLED:
            self.validate_local_eios_archived(
                attrs, instance, documents_not_archived_error
            )
        self.validate_remote_eios_archived(
            attrs, instance, documents_not_archived_error
        )
        self.validate_extra_attributes(attrs, instance)

    def validate_local_eios_archived(
        self, attrs: dict, instance: Optional[Zaak], error: serializers.ValidationError
    ):
        # TODO: check remote ZIO.informatieobject
        # search for related informatieobjects with status != 'gearchiveerd'
        canonical_ids = instance.zaakinformatieobject_set.values("_informatieobject_id")
        io_ids = (
            EnkelvoudigInformatieObjectCanonical.objects.filter(
                id__in=Subquery(canonical_ids)
            )
            .annotate(last=Max("enkelvoudiginformatieobject"))
            .values("last")
        )

        if (
            EnkelvoudigInformatieObject.objects.filter(id__in=Subquery(io_ids))
            .exclude(status=Statussen.gearchiveerd)
            .exists()
        ):
            raise error

    def validate_remote_eios_archived(
        self, attrs: dict, instance: Optional[Zaak], error: serializers.ValidationError
    ):
        remote_zios = instance.zaakinformatieobject_set.filter(
            _informatieobject_base_url__isnull=False
        )
        # This is a very naive approach to load all the remote objects - it happens
        # sequentially, while futures.concurrent _could_ be used. Let's see first
        # how performance is in this setup. Because we're looping and exiting as
        # soon as an error condition is found, we can reduce unnecessary network
        # calls.
        for zio in remote_zios:
            if zio.informatieobject.status != Statussen.gearchiveerd:
                raise error

    def validate_extra_attributes(self, attrs: dict, instance: Optional[Zaak]):
        for attr in ["archiefnominatie", "archiefactiedatum"]:
            if not attrs.get(attr, getattr(instance, attr) if instance else None):
                raise serializers.ValidationError(
                    {
                        attr: _(
                            "Moet van een waarde voorzien zijn als de 'Archiefstatus' een waarde heeft anders dan "
                            f"'{Archiefstatus.nog_te_archiveren}'."
                        )
                    },
                    code=f"{attr}-not-set",
                )

class EndStatusIOsUnlockedValidator:
    """
    Validate that related InformatieObjects are unlocked when the end status is
    being set.

    The serializer sets the __is_eindstatus attribute in the data dict as
    part of the ``to_internal_value`` method.
    """

    code = "informatieobject-locked"
    message = (
        "Er zijn gerelateerde informatieobjecten die nog gelocked zijn."
        "Deze informatieobjecten moet eerst unlocked worden voordat de zaak afgesloten kan worden."
    )

    def __call__(self, attrs: dict):
        if not attrs.get("__is_eindstatus"):
            return

        zaak = attrs.get("zaak")
        # earlier validation failed possibly
        if not zaak:
            return

        local_zios = zaak.zaakinformatieobject_set.filter(
            _informatieobject__isnull=False,
        )
        if local_zios.exclude(_informatieobject__lock="").exists():
            raise serializers.ValidationError(self.message, code=self.code)

        remote_zios = zaak.zaakinformatieobject_set.filter(
            _informatieobject_base_url__isnull=False
        )
        for zio in remote_zios:
            if zio.informatieobject.locked:
                raise serializers.ValidationError(self.message, code=self.code)

class EndStatusIOsIndicatieGebruiksrechtValidator:
    """
    Validate that related InformatieObjects have ``indicatieGebruiksrecht`` set
    when the end status is being set.

    The serializer sets the __is_eindstatus attribute in the data dict as
    part of the ``to_internal_value`` method.
    """

    code = "indicatiegebruiksrecht-unset"
    message = (
        "Er zijn gerelateerde informatieobjecten waarvoor `indicatieGebruiksrecht` nog niet "
        "gespecifieerd is. Je moet deze zetten voor je de zaak kan afsluiten."
    )

    def __call__(self, attrs: dict):
        if not attrs.get("__is_eindstatus"):
            return

        zaak = attrs.get("zaak")
        # earlier validation failed possibly
        if not zaak:
            return

        if not settings.CMIS_ENABLED:
            self.validate_local_eios_indicatie_set(zaak)
        self.validate_remote_eios_indicatie_set(zaak)

    def validate_local_eios_indicatie_set(self, zaak: Zaak):
        canonical_ids = zaak.zaakinformatieobject_set.values("_informatieobject_id")
        io_ids = (
            EnkelvoudigInformatieObjectCanonical.objects.filter(
                id__in=Subquery(canonical_ids)
            )
            .annotate(last=Max("enkelvoudiginformatieobject"))
            .values("last")
        )

        if (
            EnkelvoudigInformatieObject.objects.filter(id__in=Subquery(io_ids))
            .filter(indicatie_gebruiksrecht__isnull=True)
            .exists()
        ):
            raise serializers.ValidationError(self.message, self.code)

    def validate_remote_eios_indicatie_set(self, zaak: Zaak):
        remote_zios = zaak.zaakinformatieobject_set.filter(
            _informatieobject_base_url__isnull=False
        )
        for zio in remote_zios:
            if zio.informatieobject.indicatie_gebruiksrecht is None:
                raise serializers.ValidationError(self.message, self.code)

class EitherFieldRequiredValidator:
    default_message = _("One of %(fields)s must be provided")
    default_code = "invalid"
    requires_context = True

    def __init__(
        self,
        fields: Iterable[str],
        message: str = "",
        code: str = "",
        skip_for_updates=False,
    ):
        self.fields = fields
        self.message = (message or self.default_message) % {"fields": ", ".join(fields)}
        self.code = code or self.default_code
        self.skip_for_updates = skip_for_updates

    def __call__(self, attrs: dict, serializer):
        if self.skip_for_updates and serializer.instance:
            return

        values = [attrs.get(field, None) for field in self.fields]
        if not any(values):
            raise serializers.ValidationError(self.message, code=self.code)

class JQExpressionValidator:
    message = _("This is not a valid jq expression.")
    code = "invalid"

    def __call__(self, value: str):
        try:
            jq.compile(value)
        except ValueError:
            raise serializers.ValidationError(self.message, code=self.code)

class ObjectTypeOverigeDefinitieValidator:
    code = "invalid"

    def __call__(self, attrs: dict):
        object_type_overige_definitie: Optional[dict] = attrs.get(
            "object_type_overige_definitie"
        )
        object_url: str = attrs.get("object", "")

        if not object_type_overige_definitie:
            return

        # object type overige definitie can only be used with object URL reference
        if object_type_overige_definitie and not object_url:
            raise serializers.ValidationError(
                {
                    "object_url": _(
                        "Indien je `objectTypeOverigeDefinitie` gebruikt, dan moet je "
                        "een OBJECT url opgeven."
                    )
                },
                code="required",
            )

        if attrs.get("object_identificatie"):
            logger.warning(
                "Both object URL and objectIdentificatie supplied, clearing the latter."
            )
            attrs["object_identificatie"] = None

        # now validate the schema
        url_validator = URLValidator(get_auth=get_auth)

        response = url_validator(object_type_overige_definitie["url"])
        try:
            object_type = response.json()
        except json.JSONDecodeError:
            raise serializers.ValidationError(
                {
                    "objectTypeOverigeDefinitie.url": _(
                        "The endpoint did not return valid JSON."
                    )
                },
                code="invalid",
            )

        schema_jq = jq.compile(object_type_overige_definitie["schema"])
        record_data_jq = jq.compile(object_type_overige_definitie["object_data"])

        try:
            json_schema_definition = schema_jq.input(object_type).first()
        except ValueError:
            json_schema_definition = None

        if not json_schema_definition:
            raise serializers.ValidationError(
                {
                    "objectTypeOverigeDefinitie.schema": _(
                        "No schema was found at the specified path."
                    )
                },
                code="invalid",
            )

        # validate the object
        object_response = url_validator(object_url)
        try:
            object_resource = object_response.json()
        except json.JSONDecodeError:
            raise serializers.ValidationError(
                {"object": _("The endpoint did not return valid JSON.")}, code="invalid"
            )

        try:
            object_data = record_data_jq.input(object_resource).first()
        except ValueError:
            object_data = None
        if object_data is None:
            raise serializers.ValidationError(
                {
                    "objectTypeOverigeDefinitie.objectData": _(
                        "No data was found at the specified path."
                    )
                },
                code="invalid",
            )

        # validate the schema
        try:
            jsonschema.validate(instance=object_data, schema=json_schema_definition)
        except jsonschema.ValidationError:
            raise serializers.ValidationError(
                {"object": _("The object data does not match the specified schema.")},
                code="invalid-schema",
            )

class StatusRolValidator:
    code = "zaak-mismatch"
    message = _("De 'gezetdoor' rol hoort niet bij het zaak.")

    def __call__(self, attrs):
        gezetdoor = attrs.get("gezetdoor")
        zaak = attrs.get("zaak")
        if not gezetdoor:
            return

        if gezetdoor.zaak != zaak:
            raise serializers.ValidationError(self.message, code=self.code)

class ZaakArchiefStatusValidator:
    code = "zaak-archiefstatus-invalid"
    message = _(
        "De huidige zaak archiefstatus staat dit request niet toe. "
        "Archiefstatus moet gelijk zijn aan 'nog_te_archiveren'"
    )
    requires_context = True

    def __call__(self, attrs, serializer):
        zaak = get_from_serializer_data_or_instance("zaak", attrs, serializer)

        if not zaak:
            return

        if zaak.archiefstatus != Archiefstatus.nog_te_archiveren:
            raise serializers.ValidationError(self.message, code=self.code)


from wand.image import Image
import os
import random

class Imagif:
    def __init__(self, readDirectory = os.getcwd(), writeDirectory = os.getcwd()):
        self.readDirectory = readDirectory
        self.writeDirectory = writeDirectory

    def getReadDir(self):
        return self.readDirectory

    def use_plain(self, input):
        filename = extractFilename(input)
        output_filename = str(random.randint(1, 2**16)) + "_" + filename + ".gif"
        with Image() as output:
            with Image(filename=os.path.join(self.readDirectory, input)) as img:
                output.sequence.append(img)
            output.type = 'optimize'
            output.format = 'gif'
            with open(os.path.join(self.writeDirectory, output_filename), "wb+") as f:
                output.save(file=f)
        return output_filename

    def use_noise_switch(self, input):
        filename = extractFilename(input)
        output_filename = str(random.randint(1, 2**16)) + "_" + filename + ".gif"
        with Image() as output:
            with Image(filename=os.path.join(self.readDirectory, input)) as img:
                output.sequence.append(img)
                with img.clone() as transformation:
                    transformation.noise('poisson',attenuate=1.0)
                    output.sequence.append(transformation)
            output.sequence[0].delay = 40
            output.sequence[1].delay = 40
            output.format = 'gif'
            output.type = 'optimize'
            with open(os.path.join(self.writeDirectory, output_filename), "wb+") as f:
                output.save(file=f)
        return output_filename

    def use_party_mode(self, input):
        filename = extractFilename(input)
        output_filename = str(random.randint(1, 2**16)) + "_" + filename + ".gif"
        with Image() as output:
            with Image(filename=os.path.join(self.readDirectory, input)) as img:
                output.sequence.append(img)
                with img.clone() as transformation:
                    transformation.gaussian_blur(9,1)
                    with Image(width=100, height=1, pseudo="plasma:") as affinity:
                        transformation.remap(affinity)
                    output.sequence.append(transformation)
            for cursor in range(2):
                with output.sequence[cursor] as frame:
                    frame.delay = 100 * (cursor + 1)
            output.format = 'gif'
            output.type = 'optimize'
            with open(os.path.join(self.writeDirectory, output_filename), "wb+") as f:
                output.save(file=f)
        return output_filename

'''
Helpers
'''
def extractFilename(input):
    lastIndex  = input.rfind('/')
    filename = ""
    if lastIndex == -1: #There is no slash.
        filename = input
    else:
        filename = input[lastIndex+1:]
    if len(filename) > 4 and filename[-4] == '.':
        dotIndex = len(filename) - 4
        filename = filename[0:dotIndex]
    return filename


import matplotlib.pyplot as plt
from math import floor

XCOL = 0
YCOL = 1
BARLENGTH = 20

def redraw(i, total, particles, ax):
    _progress(i, total, particles)
    _particlechart(particles, ax)

def _progress(i, total, particles):
    percent = i / total
    complete = floor(percent * BARLENGTH)
    remaining = BARLENGTH - complete
    bar = '{}{}'.format(complete * '#', remaining * '-')
    message = 'Filtrating | {} | {:.2f} %'.format(bar, percent * 100)
    message += '\tNR: ' + str(_total_robots(particles))
    message += '\tNP: ' + str(len(particles))
    print(message, end='\r')

def _total_robots(particles):
    k = 0
    for p in particles:
        k += len(p.robots)
    return k

def _particlechart(particles, ax):
    xs, ys = _robots_coords(particles)
    ax.clear()
    ax.plot([-1, 1, 1, -1, -1], [1, 1, -1, -1, 1], 'k-')
    ax.plot([0, 0, 1, -1], [1, -1, 0, 0], 'ks')
    ax.plot(xs, ys, 'go', markersize=1)
    plt.pause(0.0001)

def _robots_coords(particles):
    xs = []
    ys = []
    for p in particles:
        xs.extend(p.robots_xs())
        ys.extend(p.robots_ys())
    return xs, ys


import json
import hashlib
import uuid
from flask import Blueprint
from flask_restful import Api, Resource, marshal, reqparse, inputs
from .model import Customers
from blueprints import db, app, admin_required, buyer_required, seller_required
from sqlalchemy import desc
from flask_jwt_extended import create_access_token, get_jwt_identity, jwt_required, get_jwt_claims

bp_customer = Blueprint('customer', __name__)
api = Api(bp_customer)

class CustomerResource(Resource):
    def __init__(self):
        pass

    @buyer_required
    @admin_required
    def get(self):
        claims = get_jwt_claims()
        qry = Customers.query.get(claims['id'])
        if qry is not None:
            return marshal(qry, Customers.response_field), 200
        return {'status': 'NOT_FOUND'}, 404

    @buyer_required
    def post(self):
        claims = get_jwt_claims()
        if claims['status'] == 'buyer':
            parser = reqparse.RequestParser()
            parser.add_argument('name', location='json', required=True)
            parser.add_argument('email', location='json', required=True)
            parser.add_argument('province', location='json', required=True)
            parser.add_argument('city', location='json', required=True)
            parser.add_argument('postal_code', location='json', required=True)
            parser.add_argument('city_type', location='json', required=True)
            parser.add_argument('street', location='json', required=True)
            parser.add_argument('phone', location='json')
            parser.add_argument('bod', location='json')
            parser.add_argument('client_id', location='json', default='show')

            args = parser.parse_args()

            customer = Customers(
                args['name'], args['email'], args['province'], args['city'], args['postal_code'], args['city_type'], args['street'], args['phone'], args['bod'], claims['id'])
            db.session.add(customer)
            db.session.commit()
            app.logger.debug('DEBUG: %s', customer)

            return marshal(customer, Customers.response_field), 200, {'Content-Type': 'application/json'}

    @buyer_required
    def patch(self, id):
        claims = get_jwt_claims()
        qry = Clients.query.get(claims['id'])
        if qry is None:
            return {'status': 'NOT_FOUND'}, 404
        else:
            parser = reqparse.RequestParser()
            parser.add_argument('name', location='json')
            parser.add_argument('email', location='json')
            parser.add_argument('province', location='json')
            parser.add_argument('city', location='json')
            parser.add_argument('postal_code', location='json')
            parser.add_argument('city_type', location='json')
            parser.add_argument('street', location='json')
            parser.add_argument('phone', location='json')
            parser.add_argument('bod', location='json')

            args = parser.parse_args()

            qry.name = args['name']
            qry.email = args['email']
            qry.province = args['province']
            qry.city = args['city']
            qry.postal_code = args['postal_code']
            qry.city_type = args['city_type']
            qry.street = args['street']
            qry.phone = args['phone']
            qry.bod = args['bod']

            db.session.commit()

            return marshal(customer, Customers.response_field), 200

api.add_resource(CustomerResource, '/profile')


import joblib
import pandas as pd
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.linear_model import SGDClassifier
from sklearn.metrics import accuracy_score
from sklearn.base import TransformerMixin
from sklearn.pipeline import Pipeline
from sklearn.svm import LinearSVC
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix
import spacy
import string
import logging
import numpy as np

logger = logging.getLogger(__name__)

LANGUAGE = "DE"
MODEL_NAME = "scikit_model"
punctuations = string.punctuation

class SpacyScikitModel:

    def __init__(self):
        if LANGUAGE == "DE":
            from spacy.lang.de.stop_words import STOP_WORDS
            self.nlp = spacy.load('de_core_news_sm')
            self.domain_stopwords = ["Ausschreibung", "Bekanntmachung"]
            from spacy.lang.de import German
            self.parser = German()
        elif LANGUAGE == "EN":
            from spacy.lang.en.stop_words import STOP_WORDS
            self.nlp = spacy.load('en')
            self.domain_stopwords = ["contract", "system", "service", "tender", "company", "notice", "procurement",
                                     "work", "include", "support", "approximately", "management", "agreement",
                                     "office", "solution", "manage", "product", "design", "program", "project",
                                     "supply", "trust", "equipment"]
            from spacy.lang.en import English
            self.parser = English()
        else:
            raise Exception("unknown language")

        self.stopwords = list(STOP_WORDS)
        self.stopwords.extend(self.domain_stopwords)
        self.pipe = None

    def spacy_tokenizer(self, sentence):
        sentence_tokens = self.parser(sentence)
        sentence_tokens = [word.lemma_.lower().strip() if word.lemma_ != "-PRON-" else word.lower_ for word in sentence_tokens]
        sentence_tokens = [word for word in sentence_tokens if word not in self.stopwords and word not in punctuations]
        return sentence_tokens

    class Predictors(TransformerMixin):

        def __clean_text(self, text):
            if text is None:
                return ""
            return str(text).strip().lower()

        def transform(self, X, **transform_params):
            return [self.__clean_text(text) for text in X]

        def fit(self, X, y=None, **fit_params):
            return self

        def get_params(self, deep=True):
            return {}

    def __load_model(self):
        if not self.pipe:
            self.pipe = joblib.load(MODEL_NAME)

    def __convert_to_input(self, tenders):
        titles = list(map(lambda x: x.get_title("DE"), tenders))
        return titles

    def classify(self, tenders):
        self.__load_model()

        titles = self.__convert_to_input(tenders)
        predictions = self.pipe.predict(titles)
        tuples = zip(tenders, predictions)
        selected_tenders = [t for t, p in tuples if p == 1]
        return selected_tenders

    def train(self, labelled_tenders):
        self.__load_model()

        tenders = [i for i, j in labelled_tenders]
        labels = [j for i, j in labelled_tenders]
        titles = self.__convert_to_input(tenders)

        training_df = pd.DataFrame({"title": titles, "label": labels})
        T = training_df["title"]
        y = training_df["label"]

        T_train, T_test, y_train, y_test = train_test_split(T, y, test_size=0.1, random_state=42)
        logger.info("start training")
        self.pipe.fit(T_train, y_train)
        logger.info("start testing")
        y_pred = self.pipe.predict(T_test)
        logger.info(f"accuracy: {self.pipe.score(T_test, y_test)} , tested with {len(T_test)} instances")
        tn, fp, fn, tp = confusion_matrix(y_test, y_pred).ravel()
        logger.info(f"tn: {tn} fp: {fp}")
        logger.info(f"fn: {fn} tp:{tp}")
        joblib.dump(self.pipe, MODEL_NAME)

    def create_new_model(self):
        vectorizer = CountVectorizer(tokenizer=self.spacy_tokenizer, ngram_range=(1, 2))

        classifier = LinearSVC()
        predictor = self.Predictors()

        self.pipe = Pipeline([("cleaner", predictor),
                              ('vectorizer', vectorizer),
                              ('classifier', classifier)])

        joblib.dump(self.pipe, MODEL_NAME)


def EsBisiesto(Año):
    Bisiesto=False
    if(Año%4==0):
        if(Año%100==0):
            if(Año%400==0):
                Bisiesto=True
        else:
            Bisiesto=True
    return Bisiesto

def queDiaEs(Día, Mes, Año):
    numero=Año%100
    numero+=int(numero/4)
    numero+=Día
    if(Mes==1):
        numero+=1
        if(EsBisiesto(Año)==True):
            numero-=1
    elif(Mes==2):
        numero+=4
        if(EsBisiesto(Año)==True):
            numero-=1
    elif(Mes==3):
        numero+=4
    elif(Mes==5):
        numero+=2
    elif(Mes==6):
        numero+=5
    elif(Mes==8):
        numero+=3
    elif(Mes==9):
        numero+=6
    elif(Mes==10):
        numero+=1
    elif(Mes==11):
        numero+=4
    elif(Mes==12):
        numero+=6
    Centenas=int(Año/100)
    if(Centenas==16 or Centenas==20):
        numero+=6
    elif(Centenas==17 or Centenas==21):
        numero+=4
    elif(Centenas==18):
        numero+=2
    modulo=numero%7
    Hoy=""
    if(modulo==1):
        Hoy="Domingo"
    elif(modulo==2):
        Hoy="Lunes"
    elif(modulo==3):
        Hoy="Martes"
    elif(modulo==4):
        Hoy="Miércoles"
    elif(modulo==5):
        Hoy="Jueves"
    elif(modulo==6):
        Hoy="Viernes"
    else:
        Hoy="Sábado"
    return Hoy


import unittest
from contextlib import contextmanager
from timeit import default_timer

import matplotlib.pyplot as plt
from common import TestUnitTests
from pysmt.shortcuts import (
    GE,
    GT,
    LE,
    LT,
    REAL,
    TRUE,
    And,
    Equals,
    Minus,
    Or,
    Plus,
    Real,
    Symbol,
    Times,
)

from funman.funman import Funman, FUNMANConfig
from funman.model.bilayer import BilayerDynamics
from funman.model.query import QueryTrue

class TestS21BUnitTest(TestUnitTests):
    steps = 50
    step_size = 2
    dreal_precision = 1e-3
    expected_max_infected = 0.6
    test_threshold = 0.1
    expected_max_day = 47
    test_max_day_threshold = 25

    s2_models = [
        "Mosaphir_petri_to_bilayer",
        "UF_petri_to_bilayer",
        "Morrison_bilayer",
        "Skema_bilayer",
    ]

    speedups = {m: [] for m in s2_models}

    @contextmanager
    def elapsed_timer(self):
        start = default_timer()
        elapser = lambda: default_timer() - start
        try:
            yield elapser
        finally:
            elapser = None

    def sidarthe_extra_1_1_d_2d(self, steps, init_values, step_size=1):
        return And(
            [
                self.make_bounds(steps, init_values, step_size=step_size),
            ]
        )

    def analyze_model(self, model_name: str, dreal_mcts: bool = False):
        initial = self.initial_state_sidarthe()
        scenario = self.make_scenario(
            BilayerDynamics(
                json_graph=self.sidarthe_bilayer(self.models[model_name])
            ),
            initial,
            self.bounds_sidarthe(),
            [],
            self.steps * self.step_size,
            QueryTrue(),
            extra_constraints=self.sidarthe_extra_1_1_d_2d(
                self.steps * self.step_size, initial, self.step_size
            ),
        )
        config = FUNMANConfig(
            num_steps=self.steps,
            step_size=self.step_size,
            solver="dreal",
            initial_state_tolerance=0.0,
            save_smtlib=True,
            dreal_mcts=dreal_mcts,
            dreal_precision=self.dreal_precision,
        )
        result_sat = Funman().solve(scenario, config=config)
        self.report(result_sat, name=model_name)
        if result_sat.consistent:
            max_infected, max_day = self.analyze_results(result_sat)
        else:
            max_infected = max_day = -1

        return max_infected, max_day

    def analyze_results(self, result_sat):
        df = result_sat.dataframe()

        df["infected_states"] = df.apply(
            lambda x: sum([x["I"], x["D"], x["A"], x["R"], x["T"]]), axis=1
        )
        max_infected = df["infected_states"].max()
        max_day = df["infected_states"].idxmax()
        ax = df["infected_states"].plot(
            title=f"I+D+A+R+T by day (max: {max_infected}, day: {max_day})",
        )
        ax.set_xlabel("Day")
        ax.set_ylabel("I+D+A+R+T")
        try:
            plt.savefig(f"funman_s2_1_b_i_infected.png")
        except Exception as e:
            pass
        plt.clf()

        return max_infected, max_day

    def common_test_model(self, model_name: str, dreal_mcts: bool = False):
        max_infected, max_day = self.analyze_model(
            model_name, dreal_mcts=dreal_mcts
        )
        # assert (
        #     abs(max_infected - self.expected_max_infected) < self.test_threshold
        # )
        # assert (
        #     abs(max_day - self.expected_max_day) < self.test_max_day_threshold
        # )

    def compute_speedup(self, elapsed_base_dreal, elapsed_mcts_dreal, model):
        mcts_speedup = elapsed_base_dreal / elapsed_mcts_dreal
        self.speedups[model].append(mcts_speedup)
        print(f"Speedups: {self.speedups}")

    def compare_mcts_speedup(self, model):
        with self.elapsed_timer() as t:
            self.common_test_model(model)
            elapsed_base_dreal = t()
        for i in range(5):
            with self.elapsed_timer() as t:
                self.common_test_model(model, dreal_mcts=True)
                elapsed_mcts_dreal = t()
            self.compute_speedup(elapsed_base_dreal, elapsed_mcts_dreal, model)

    def test_model_0(self):
        self.compare_mcts_speedup(self.s2_models[0])

    @unittest.expectedFailure
    def test_model_1(self):
        self.compare_mcts_speedup(self.s2_models[1])

    def test_model_2(self):
        self.compare_mcts_speedup(self.s2_models[2])

    def test_model_3(self):
        self.compare_mcts_speedup(self.s2_models[3])

    @classmethod
    def tearDownClass(cls):
        print(f"Speedup: {cls.speedups}")

if __name__ == "__main__":
    unittest.main()


import sys
import os
from glob import glob
import subprocess

import numpy as np
import open3d as o3d
import cv2

import argparse

from recover_mesh import recover_mesh

parser = argparse.ArgumentParser()
parser.add_argument('object_name', help='name of the target object (e.g., 00152)', type=str)
parser.add_argument('view_index', help='index of the reference view', type=int)
parser.add_argument('--wo-sfs', action='store_true')
parser.add_argument('--exp-name', default='nlmvss', type=str)
args = parser.parse_args()

object_name = args.object_name
view_index = args.view_index

out_dir = './run/mesh_per_view'
result_dir = './run/est_shape_mat_per_view'
if args.wo_sfs:
    out_dir = out_dir+'_wo_sfs'
    result_dir = result_dir+'_wo_sfs'
out_dir = out_dir+'/'+args.exp_name+'/'+object_name+'/'+str(view_index).zfill(3)
result_dir = result_dir+'/'+args.exp_name+'/'+object_name+'/'+str(view_index).zfill(3)+'/final_results'
os.makedirs(out_dir, exist_ok=True)
print('result_dir:', result_dir)
print('out_dir:', out_dir)

# create unnormalized gt mesh
gt_mesh_files = sorted(glob(os.environ['HOME']+'/data/mvs_eval/assets/shape/*.obj'))
if len(gt_mesh_files) != 6:
    gt_mesh_file = None
else:
    object_id = int(object_name)
    gt_mesh_file = gt_mesh_files[(object_id // 6) % len(gt_mesh_files)]

    mesh = o3d.io.read_triangle_mesh(gt_mesh_file)
    verts = np.asarray(mesh.vertices)
    faces = np.asarray(mesh.triangles)

    bbox_min = np.min(verts, axis=0)
    bbox_max = np.max(verts, axis=0)
    bbox_center = 0.5 * (bbox_min + bbox_max)
    bbox_diagonal = np.linalg.norm(bbox_max - bbox_min)
    camera_min_distance = 1.0
    camera_tangent = 1.0 / (2.0 / 1200 * 5000.0)
    scale = 0.5 * bbox_diagonal / camera_tangent / camera_min_distance

    verts -= bbox_center
    verts /= scale
    mesh.vertices = o3d.utility.Vector3dVector(verts)
    o3d.io.write_triangle_mesh(out_dir+'/mesh_gt.ply', mesh)
    gt_mesh_file = out_dir+'/mesh_gt.ply'

recover_mesh(
    result_dir,
    out_dir,
    gt_mesh_file=gt_mesh_file,
    compute_mesh_errors=False,
    num_neighbors=-1
)

subprocess.run([
    'meshlabserver',
    '-i', out_dir+'/merged_points.ply',
    '-o', out_dir+'/mesh_poisson.ply',
    '-m', 'sa',
    '-s', './data/remeshing_sharp.mlx'
])

subprocess.run([
    'meshlabserver',
    '-i', out_dir+'/mesh_poisson.ply',
    '-o', out_dir+'/mesh_poisson.ply',
    '-m', 'sa',
    '-s', './data/loop_subdivision.mlx'
])

subprocess.run([
    'python',
    'eval_utils/remove_invisible_facets.py',
    out_dir,
    '-n', str(-1)
])

subprocess.run([
    'meshlabserver',
    '-i', out_dir+'/mesh.ply',
    '-o', out_dir+'/mesh.ply',
    '-m', 'sa',
    '-s', './data/close_holes.mlx'
])

# render from other views
if not os.path.exists('./run/est_shape_mat/nlmvss/'+object_name+'/final_results'):
    exit()
os.makedirs(out_dir+'/novel_view_rendering', exist_ok=True)
for view_id in range(20):
    view_dir = out_dir+'/novel_view_rendering/view-'+str(1+view_id).zfill(2)
    os.makedirs(view_dir, exist_ok=True)
    intrinsic_file = './run/est_shape_mat/nlmvss/'+object_name+'/final_results/view-'+str(1+view_id).zfill(2)+'/intrinsics.npy'
    extrinsic_file = './run/est_shape_mat/nlmvss/'+object_name+'/final_results/view-'+str(1+view_id).zfill(2)+'/extrinsics.npy'

    subprocess.run([
        'python', 'eval_utils/render_geometry_mgl.py',
        '-i', intrinsic_file,
        '-e', extrinsic_file,
        '-n', view_dir+'/mesh_normal.npy',
        '-d', view_dir+'/mesh_depth.npy',
        '-m', view_dir+'/mesh_mask.png',
        '--up-sampling', '4',
        out_dir+'/mesh.ply',
        '128', '128',
    ])
    img_shading = (255*(np.clip(0.8*np.load(view_dir+'/mesh_normal.npy')[:,:,2], 0, 1)**(1/2.2))).astype(np.uint8)
    mesh_mask = cv2.imread(view_dir+'/mesh_mask.png', 0)
    cv2.imwrite(view_dir+'/mesh_shading.png', np.concatenate([
        img_shading[:,:,None], img_shading[:,:,None], img_shading[:,:,None], mesh_mask[:,:,None]
    ], axis=-1))
    print('created', view_dir+'/mesh_shading.png')

    if not (gt_mesh_file is None):
        subprocess.run([
            'python', 'eval_utils/render_geometry_mgl.py',
            '-i', intrinsic_file,
            '-e', extrinsic_file,
            '-n', view_dir+'/gt_mesh_normal.npy',
            '-d', view_dir+'/gt_mesh_depth.npy',
            '-m', view_dir+'/gt_mesh_mask.png',
            '--up-sampling', '4',
            out_dir+'/mesh_gt.ply',
            '128', '128',
        ])
        img_shading = (255*(np.clip(0.8*np.load(view_dir+'/gt_mesh_normal.npy')[:,:,2], 0, 1)**(1/2.2))).astype(np.uint8)
        mesh_mask = cv2.imread(view_dir+'/gt_mesh_mask.png', 0)
        cv2.imwrite(view_dir+'/gt_mesh_shading.png', np.concatenate([
            img_shading[:,:,None], img_shading[:,:,None], img_shading[:,:,None], mesh_mask[:,:,None]
        ], axis=-1))
        print('created', view_dir+'/gt_mesh_shading.png')


""" Python wrapper for lldpd (http://vincentbernat.github.io/lldpd/) """
# -*- coding: utf-8 -*-
from __future__ import print_function

import cffi
from contextlib import contextmanager
import json
import logging
import time
import threading

import liblldpctl

FFI = cffi.FFI()
LIB = liblldpctl.load(FFI)
_ = dir(LIB)
LOGGER = logging.getLogger(__name__)

class Atom(object):
    """ Atoms are the primary datatype in lldpctl. Possible keys are listed
        in an enum, every key has a `lldpctl_k_` prefix.
    """
    _prefix = 'lldpctl_k_'
    _keys = [(_k, getattr(LIB, _k)) for _k in dir(LIB) if _k.startswith(_prefix)]

    # By omission values are imported as strings. This dict keeps track of atoms which
    # refer to lists, and should be decoded as specific class types.
    _key_to_type = dict()

    def __init__(self, ptr):
        """ Given a ctype pointer we should decode as much as possible. """
        for keyname, keynum in self._keys:
            if keyname in self._key_to_type:
                func = self._decode_as_atom
            else:
                func = self._decode_as_string

            val = func(keyname, keynum, ptr)
            if val is not None:
                setattr(self, keyname.replace(self._prefix, ''), val)

    @classmethod
    def _decode_as_atom(cls, keyname, keynum, ptr):
        """ Get a key field from pointer and extract it as an atom. """
        raw = LIB.lldpctl_atom_get(ptr, keynum)
        cls_ = cls._key_to_type[keyname]
        return [cls_(i) for i in Atom._walk(raw)] if raw != FFI.NULL else []

    @classmethod
    def _decode_as_string(cls, _, keynum, ptr):
        """ Get a key field from pointer and extract it as a string. """
        raw = LIB.lldpctl_atom_get_str(ptr, keynum)
        return FFI.string(raw) if raw != FFI.NULL else None

    def _enabled(self, flag):
        """ Check to see if capability field matches flag. """
        value = int(getattr(self, 'chassis_cap_enabled', 0))
        return bool(value & flag)

    def __repr__(self):
        return str(self.__dict__)

    @classmethod
    def _walk(cls, ptr):
        """ Given an atom list ptr, iterate over contained atoms. """
        iterator = LIB.lldpctl_atom_iter(ptr)
        while iterator != FFI.NULL:
            value = LIB.lldpctl_atom_iter_value(ptr, iterator)
            yield value
            iterator = LIB.lldpctl_atom_iter_next(ptr, iterator)
            LIB.lldpctl_atom_dec_ref(value)

class Port(Atom):
    _key_to_type = dict(lldpctl_k_chassis_mgmt=Atom)

    @property
    def repeater_enabled(self):
        return self._enabled(0x02)

    @property
    def bridge_enabled(self):
        return self._enabled(0x04)

    @property
    def wlan_enabled(self):
        return self._enabled(0x08)

    @property
    def router_enabled(self):
        return self._enabled(0x10)

class Ports(Atom):
    _key_to_type = dict(lldpctl_k_port_neighbors=Port)

class Interface(Atom):
    def __init__(self, ptr):
        super(Interface, self).__init__(ptr)
        self.port = Ports(LIB.lldpctl_get_port(ptr))

    @classmethod
    def iterator(cls, conn):
        intfs = LIB.lldpctl_get_interfaces(conn)
        if intfs == FFI.NULL:
            raise StopIteration
        for i in Interface._walk(intfs):
            yield Interface(i)

class Encoder(json.JSONEncoder):
    """ Encodes atom objects. """
    def __init__(self, *args, **kwargs):
        self.schema = kwargs.pop('schema', None)
        super(Encoder, self).__init__(*args, **kwargs)

    def default(self, obj):
        """ Encode Atom object filtering by schema. """
        if isinstance(obj, Atom):
            attrs = (i for i in dir(obj) if not i.startswith('_'))
            attrs = (i for i in attrs if self.schema is None or i in self.schema)
            return dict((k, getattr(obj, k)) for k in attrs)
        return super(Encoder, self).default(obj)

class Watcher(threading.Thread):
    """ A thread which can be subclassed to watch for LLDP events. """
    def __init__(self):
        threading.Thread.__init__(self)
        LIB.lldpctl_log_callback(self.log)
        self.stop = threading.Event()
        self.daemon = True

    @contextmanager
    def connect(self):
        """ Connect to lldpd synchronously for now.
            We'd like to release connection once done, but in practice thread
            is blocking on watch, so there's no clean way of stopping it.
        """
        conn = LIB.lldpctl_new(FFI.NULL, FFI.NULL, FFI.NULL)
        # XXX: error handling
        selfptr = FFI.new_handle(self)
        LIB.lldpctl_watch_callback(conn, self.process, selfptr)
        yield conn
        LIB.lldpctl_release(conn)

    @staticmethod
    @FFI.callback("void (int, const char *)")
    def log(severity, msg):
        """ Callback for tracking logging in application rather than
            directly to STDERR. Useful for debugging library.
        """
        if severity == 5:
            logger = LOGGER.info
        elif severity == 4:
            logger = LOGGER.warning
        elif severity < 4:
            logger = LOGGER.error
        else:
            logger = LOGGER.debug
        logger(FFI.string(msg))

    @staticmethod
    @FFI.callback("lldpctl_change_callback")
    def process(_, cbtype, local, remote, selfptr):
        """ Called on every change. Dispatch to correct
            event callback.
        """
        self = FFI.from_handle(selfptr)
        args = Atom(local), Port(remote)
        if cbtype == LIB.lldpctl_c_added:
            self.on_add(*args)
        elif cbtype == LIB.lldpctl_c_deleted:
            self.on_delete(*args)
        elif cbtype == LIB.lldpctl_c_updated:
            self.on_update(*args)

    def on_add(self, local, remote):
        """ Should be subclassed. """
        pass

    def on_delete(self, local, remote):
        """ Should be subclassed. """
        pass

    def on_update(self, local, remote):
        """ Should be subclassed. """
        pass

    @property
    def running(self):
        """ Check if thread should still be running. """
        return not self.stop.is_set()

    def run(self):
        while self.running:
            with self.connect() as conn:
                self.load(conn)
                self.loop(conn)
            # delay retrying to connect in case socket is unavailable.
            time.sleep(1)

    def load(self, conn):
        """ Load LLDP neighbors by pretending they've just been
            added.
        """
        for interface in Interface.iterator(conn):
            for port in interface.port.port_neighbors:
                self.on_add(interface, port)

    def loop(self, conn):
        """ Wait and react to events. """
        while self.running and not LIB.lldpctl_watch(conn):
            pass


import pandas as pd
import numpy as np
from numpy import random
from numpy.linalg import norm
from sklearn.preprocessing import MinMaxScaler
import os
import time

#THIS IS THE MAIN CODE
#FOR EVALUATIONS AND TESTING, PLEASE REFER TO THE FILE "EVALUATION_TESTS.PY)

class PrimeGenerator:
    #This class generates a replicatable sequence of prime numbers to be used as the random seeds of each epoch

    def __init__(self):
        #Initlalizer for Prime Generator Class
        self.current = 1

    def __iter__(self):
        #Return self
        return self

    @staticmethod
    def is_prime(n):
        #Returns True if input number is prime, otherwise False
        for i in range(2, n):
            if n % i == 0:
                return False
        return True

    #Returns the next prime number in the sequence
    def __next__(self):
        next_prime = self.current + 1
        while not self.is_prime(next_prime):
            next_prime += 1
        self.current = next_prime
        return self.current

class Preprocessor:
    #This class transforms a dataset into a database of profiles

    @staticmethod
    def get_data_from_filename(filename):
        #Takes in a filename, and reads the file to a pandas df
        file_path = os.path.join(os.path.dirname(__file__), filename)
        return pd.read_csv(file_path)

    @staticmethod
    def split_names_by_gender(names):
        #Takes in a file of names, and splits them into male names and female names
        return names["male names"], names["female names"]

    @staticmethod
    def get_relevant_data(data, columns):
        #Takes in a pandas df, and drops duplicate rows as well as rows with missing data
        data = data.drop_duplicates()
        return data[columns].dropna()

    @staticmethod
    def replace_values_with_dictionary(data, dictionaries, valid_input):
        #Takes in a pandas df and a dictionary of values, and replaces the relevant df columns with the values
        for dictionary in dictionaries:
            label = dictionary["attribute"]
            if label not in valid_input.get_categorical_inputs():
                raise ValueError(f"{label} is not a valid attribute!")
            dictionary.pop("attribute")
            data.replace({label: dictionary}, inplace=True)
        return data

    @staticmethod
    def convert_numerical_data_to_scaled_array(data, maximum=10):
        #Takes in a pandas df, and scales numerical attributes to a given range using MinMax
        normalizer = MinMaxScaler(feature_range=(0, maximum))
        return normalizer.fit_transform(data.to_numpy())

    @staticmethod
    def combine_attributes_and_names(names, numeric_attributes, english_attributes):
        #For each of the profiles in the two attribute arrays(numeric and english),
        #this function assigns to them a random name from the names dataset provided
        profile_numerical = np.hstack(([[None] for attribute in numeric_attributes], numeric_attributes))
        profile_english = np.hstack(([[None] for attribute in english_attributes], english_attributes))
        for i in range(0, np.size(profile_numerical, axis=0)):
            random_name = np.random.choice(names)
            profile_numerical[i][0] = random_name
            profile_english[i][0] = random_name
        return profile_numerical, profile_english

class DatingApp:
    #Mimics an interface for a real dating application
    #Selects profiles to recommend based on the user's behaviour
    def __init__(self, male_names, female_names, profiles_normalized, profiles_english):
        self.gender = ""
        self.male_names = male_names
        self.female_names = female_names
        self.profiles_normalized = profiles_normalized
        self.profiles_english = profiles_english
        self.recommendation_number = 1
        self.like_list = []
        self.dislike_list = []
        self.like_array_in_memory = None
        self.dislike_array_in_memory = None
        self.current_profile = None
        self.current_english = None
        self.random_recommendation = False
        self.recommended_profiles = []

    def set_gender(self, preprocessor, gender):
        #Takes in a specified gender, and assigns a gender-specific name to each profile in the database
        if gender == "Female":
            self.profiles_normalized, self.profiles_english = preprocessor.combine_attributes_and_names(self.male_names, self.profiles_normalized, self.profiles_english)

        elif gender == "Male":
            self.profiles_normalized, self.profiles_english = preprocessor.combine_attributes_and_names(self.female_names, self.profiles_normalized, self.profiles_english)
        else:
            raise ValueError("Invalid Gender Specified!")

    def get_a_recommendation(self, random_recommend_chance=5, top_choices=30, number_of_stored_profiles=30):
        #Calculates the best profile, and recommends it
        #There is a chance of a random_recommendation recommendation, which decreases as iterations increase
        self.recommendation_number += 1

        if self.recommendation_number <= 10:  # Random recommendations for the first ten recommendations
            rand_index = np.random.randint(0, np.size(self.profiles_normalized, axis=0))
            self.current_english = self.profiles_english[rand_index]
            self.current_profile = self.profiles_normalized[rand_index]
        else:
            if not self.like_list:  # Contingency in the case that no profiles have been liked after 10 recommendations
                dislike_array = np.array(self.dislike_list)
                worst_array = np.average(dislike_array[:, 1:], axis=0)
                self.like_list.append(np.array(["Sam", 10-worst_array[0], 10-worst_array[1], 10-worst_array[2], 10-worst_array[3], 10-worst_array[4]], dtype="O"))
            if not self.dislike_list: # Contingency in the case that no profiles have been disliked for 10 recommendations
                like_array = np.array(self.like_list)
                best_array = np.average(like_array[:, 1:], axis=0)
                self.dislike_list.append(np.array(["Sam", 10-best_array[0], 10-best_array[1], 10-best_array[2], 10-best_array[3], 10-best_array[4]], dtype="O"))

            self.like_array_in_memory = np.array(self.like_list)[-number_of_stored_profiles:] # Limit cap on how many profiles the algorithm uses to calculate average
            self.dislike_array_in_memory = np.array(self.dislike_list)[-number_of_stored_profiles:]

            random_recommend_chance = random_recommend_chance / (self.recommendation_number + random_recommend_chance) # Chance of a random recommendation

            best_array = np.average(self.like_array_in_memory[:, 1:], axis=0, weights=np.arange(1, np.size(self.like_array_in_memory[:, 1:], axis=0) + 1))  # Weighted average of the liked profiles
            worst_array = np.average(self.dislike_array_in_memory[:, 1:], axis=0, weights=np.arange(1, np.size(self.dislike_array_in_memory[:, 1:], axis=0) + 1))  # Weighed average of the disliked profiles
            profiles_normalized_enumerated = np.array(sorted(enumerate(self.profiles_normalized), key = lambda x: (np.linalg.norm(x[1][1:] - best_array) - (np.linalg.norm(x[1][1:] - worst_array)))), dtype="O") # Sorts according to distance to liked and disliked profiles
            indices = profiles_normalized_enumerated[:, 0]
            profiles_norm = profiles_normalized_enumerated[:, 1]
            index = np.random.choice(top_choices, 1)[0]
            self.profiles_english = np.array([self.profiles_english[i] for i in indices])
            self.profiles_normalized = profiles_norm

            random_number = np.random.random()
            if random_number > random_recommend_chance:
                self.current_profile = profiles_norm[index]
                self.current_english = self.profiles_english[index]
                self.random_recommendation = False
            else:  # Random recommendation
                random_index = np.random.choice(profiles_norm.shape[0], 1)[0]
                self.current_profile = profiles_norm[random_index]
                self.current_english = self.profiles_english[random_index]
                self.random_recommendation = True

        return self.current_profile, self.current_english

    def receive_like_or_dislike(self, preference):
        #Takes in either a "like" or "dislike", and appends the current profile to the appropriate list
        if preference == "like":
            self.like_list.append(self.current_profile)
        elif preference == "dislike":
            self.dislike_list.append(self.current_profile)

class ValidInputs:
    #Ensures that inputs passed into the system are valid

    def __init__(self):
        self.numerical_inputs = None
        self.categorical_inputs = None

    def set_limits(self, filename):
        #Takes in a filename, and sets the appropriate inputs
        file = open(filename, 'r')
        lines = file.readlines()
        file.close()

        categorical_inputs = lines[0].split(',')[1:]
        numerical_inputs = lines[1].split(',')[1:]

        self.numerical_inputs = numerical_inputs
        self.categorical_inputs = categorical_inputs

    def get_numerical_inputs(self):
        #Returns the specified valid numerical inputs
        return self.numerical_inputs

    def get_categorical_inputs(self):
        #Returns the specified valid categorical inputs
        return self.categorical_inputs

class Bot:
    #A model of a user
    #It has its own implicit preferences and target profile

    def __init__(self, preference_attributes, target_attributes, max_recommendations, number_of_stored_profiles, number_of_top_choices,
                 total_num_of_epochs, random_recommendation_weight, get_mean_recommendations, get_mean_distance, get_std_recommendations,
                 get_std_distance, get_time):
        self.num_of_recommendations_per_epoch = []
        self.current_num_of_epochs = 1
        self.ideal_arrays = []
        self.recommended_profiles = []
        self.max_recommendations = max_recommendations
        self.stored_profiles= number_of_stored_profiles
        self.top_choices = number_of_top_choices
        self.epochs = total_num_of_epochs
        self.random_recommendation = random_recommendation_weight
        self.get_mean_recommendations = get_mean_recommendations
        self.get_std_recommendations = get_std_recommendations
        self.get_mean_distance = get_mean_distance
        self.get_std_distance = get_std_distance
        self.get_time = get_time
        self.preference_attributes = preference_attributes
        self.target_attributes = target_attributes

    @staticmethod
    def preference(profile, preference_attributes):
        #Implicit preference

        if isinstance(preference_attributes, str):
            if preference_attributes == "Liker":
                return True
            elif preference_attributes == "Disliker":
                return False
            elif preference_attributes == "Random":
                if random.random() >= 0.5:
                    return True
                else:
                    return False

        age, drugs, drinks, smokes, height = profile[1], profile[2], profile[3], profile[4], profile[5]
        attributes = [age, drugs, drinks, smokes, height]
        preference = True
        for i in range(6):
            try:
                print(attributes[i], preference_attributes[i])
                if not attributes[i] >= preference_attributes[i]:
                    preference = False
            except IndexError:
                return preference

    @staticmethod
    def target_profile(profile, target_attributes):

        if not target_attributes:
            return False

        age, drugs, drinks, smokes, height = profile[1], profile[2], profile[3], profile[4], profile[5]
        attributes = [age, drugs, drinks, smokes, height]
        goal = True
        for i in range(6):
            try:
                if not attributes[i] >= target_attributes[i]:
                    goal = False
            except IndexError:
                return goal

    def run(self):
        #Runs the program
        gender = "Male"

        #Encodings of categorical data -> Numerical values
        attributes = ["age", "drugs", "drinks", "smokes", "height"]
        drugs_dictionary = {"attribute": "drugs", "never": 1, "sometimes": 2, "often": 3}
        drinks_dictionary = {"attribute": "drinks", "not at all": 1, "rarely": 2, "socially": 3, "often": 4, "very often": 5, "desperately": 6}
        smokes_dictionary = {"attribute": "smokes", "no": 1, "trying to quit": 2, "when drinking": 3, "sometimes": 4, "yes": 5}
        dictionary_list = [drugs_dictionary, drinks_dictionary, smokes_dictionary]

        #Valid Inputs
        valid_input = ValidInputs()
        valid_input.set_limits("ValidInputs")

        # Preprocessing
        preprocessor = Preprocessor()
        okcupid_data = preprocessor.get_data_from_filename("okcupid_profiles.csv")
        names_data = preprocessor.get_data_from_filename("baby_names.csv")
        okcupid_relevant_data = preprocessor.get_relevant_data(okcupid_data, attributes)
        okcupid_relevant_data= okcupid_relevant_data.drop_duplicates()
        profiles_english = okcupid_relevant_data.to_numpy()
        okcupid_relevant_data_numerical = preprocessor.replace_values_with_dictionary(okcupid_relevant_data, dictionary_list, valid_input)
        normalized_okcupid_data_array = preprocessor.convert_numerical_data_to_scaled_array(okcupid_relevant_data_numerical)
        male_names, female_names = preprocessor.split_names_by_gender(names_data)

        #Interacting with App
        interface = DatingApp(male_names, female_names, normalized_okcupid_data_array, profiles_english)
        interface.set_gender(preprocessor, gender)
        target_reached = False

        primes = PrimeGenerator()

        start = time.time()

        while self.current_num_of_epochs <= self.epochs: # Check to see if 30 epochs have been reached
            print(f"Epoch Number: {self.current_num_of_epochs}")
            np.random.seed(next(primes))  # Setting the seed of the epoch to be next prime number
            while interface.recommendation_number <= self.max_recommendations:
                if target_reached and not interface.random_recommendation and interface.recommendation_number > 10:  # Random recommendations cannot be target profiles
                    break

                print("Recommendation No.", interface.recommendation_number, sep="")

                profile, profile_english = interface.get_a_recommendation(self.random_recommendation, self.top_choices, self.stored_profiles)

                if interface.recommendation_number == 11:
                    self.ideal_arrays.append(profile[1:])

                print(profile_english)
                print(profile)

                target_reached = self.target_profile(profile, self.target_attributes)

                if self.preference(profile, self.preference_attributes):  # Passing a like or dislike into the face based on implicit preferences
                    interface.receive_like_or_dislike("like")
                    print("Like")
                else:
                    interface.receive_like_or_dislike("dislike")
                    print("Dislike")

            print("")
            print("Number of recommendations taken:", interface.recommendation_number-1)
            print("Final Recommendation: ", profile)
            print("")
            self.num_of_recommendations_per_epoch.append(interface.recommendation_number)
            self.recommended_profiles.append(profile[1:])
            self.current_num_of_epochs += 1
            interface = DatingApp(male_names, female_names, normalized_okcupid_data_array, profiles_english)
            interface.set_gender(preprocessor, gender)
            target_reached = False

        #Various metric outputs
        if self.get_mean_recommendations:
            print("Average Number of Recommendations Across Epochs:", np.average(self.num_of_recommendations_per_epoch))

        if self.get_std_recommendations:
            print("Average Standard Deviation Across Number of Recommendations:", np.std(self.num_of_recommendations_per_epoch))

        if self.get_time:
            print("Total Time Taken for All Epochs:", time.time()-start)

        if self.get_mean_distance:
            distances = [np.linalg.norm(self.recommended_profiles[i] - self.ideal_arrays[i]) for i in range(len(self.recommended_profiles))]
            print("Average Distance from Initial Implicit Preferences:", np.average(distances))

        if self.get_std_distance:
            distances = [np.linalg.norm(self.recommended_profiles[i] - self.ideal_arrays[i]) for i in range(len(self.recommended_profiles))]
            print("Average Standard Deviation Across Distance From Implicit Preferences", np.std(distances))

        print("")