""" Pythonic launcher.

This now runs with a config file and copies the config file into the results
directory. If it already exists, copy it over with a new number extension.

Sample run:
    python scripts/run_jobs_slurm.py configs/reproducibility/low_n_demo.json

"""

import os
import shutil
import argparse
import subprocess
import typing
from typing import List, Optional, Tuple
import time
from datetime import datetime
import json

def get_args() -> Tuple[dict, str]:
    """ get_args.

    Return:
        Tuple[dict,str]: Args and name of file used
    """
    parser = argparse.ArgumentParser()
    parser.add_argument("config_file", help="Name of configuration file")
    args = parser.parse_args()
    print(f"Loading experiment from: {args.config_file}\n")
    args_new = json.load(open(args.config_file, "r"))
    return args_new, args.config_file

def dump_config_file(save_dir : str, config : str):
    """ dump_config_file.

    Try to dump the output config file continuously. If it doesn't work,
    increment it.

    Args:
        save_dir (str): Name of the save dir where to put this
        config (str): Location of the config file
    """

    # Dump experiment
    new_file = "experiment.config"
    config_path = os.path.join(save_dir, new_file)
    ctr = 1
    os.makedirs(save_dir, exist_ok=True)
    # Keep incrementing the counter
    while os.path.exists(config_path):
        new_file =  f"experiment_{ctr}.config"
        config_path = os.path.join(save_dir, new_file)
        ctr += 1

    shutil.copy2(config, config_path)
    TIME_STAMP_DATE = datetime.now().strftime("%m_%d_%y")

    # Open timestamps file
    with open(os.path.join(save_dir, "timestamps.txt"), "a") as fp:
          fp.write(f"Experiment {new_file} run on {TIME_STAMP_DATE}.\n")

def main(seeds : List[int] = range(10), n_ensembles : int = 5,
         datasets : List[str] = ["lipo"], dataset_types = ["regression"] ,
         dataset_splits : List[str] = ["random"],
         methods : List[str] = ["evidence_new_reg"],
         reg_coefs : List[float] = [0.2],
         split_sizes: List[float] = [0.8,0.1,0.1],
         save_dir : str = "results/submission_results_paper",
         dropout : float = 0.1,
         epochs: float = 100,
         ensemble_threads: int = 2,
         debug : bool = False,
         use_gpu: bool = True,
         job_name_prefix : str = "gnn_job",
         experiment_name : str = "chemprop",
         num_minutes : int = 30,
         num_hours : int= 1,
         num_days : int= 0,
         use_slurm : bool = True,
         atomistic : bool = False,
         experiment_file_name: Optional[str]= None,
         max_lr_atomistic : float = 0.0002,
         no_smiles_export : bool = False,
         final_lr_atomistic : float = 1e-4):
    """ main.

    Run the launching procedure to spin up different Chemprop trials.

    Args:
        seeds (List[int]): List of the seeds to run this fn with. Default
            range(10)
        n_ensembles (int): Number of ensembles to use when running UQ methods
            that take a set number of ensembles (e.g., dropout and ensemble).
            Default 5.
        datasets (List[str]): List of datasets to run! Default ['lipo']
        dataset_types (List[str]): List of dataset types to use.
            Default ['regression']. Options are "regression" and
            "classification". Must be same length as datasets
        dataset_splits (List[str]): List of dataset splits. Must be same size
            as above. Default ["random"]
        methods (List[str]): List of UQ methods to use (e.g.,
            "evidence_new_reg", "evidence", "dropout", "ensemble").
            Default "evidence_new_reg".
        reg_coefs (List[float]): List of floats to use when you running
            evidence method. Note; This must be the same size as the methods
            list for convenience
        split_sizes (List[float}): List of train, val, test split sizes for this trial to run.
            Default [0.8, 0.1, 0.1]
        save_dir (str): Save directory. Default: "results/submission_results_paper"
        dropout (float): Amount of dropout for dropout uncrtainty method.
            Default 0.1
        error (str): Type of error to run with. Deafult "rmse"
        debug (bool): If true, debug. Default False
        use_gpu (bool): If true, run wtith gres. Default True
        job_name_prefix (str): Name of log file outputs. Default "gnn_job"
        experiment_name (str): Name to launch job on clust. Default "chemprop"
        num_minutes (int): Num minutes for the job on the cluster. Default 30
        num_hours (int): Num hours for the job on the cluster. Default 1
        num_days (int): Num days for the job on the cluster. Default 0
        use_slurm (bool): If true, use slurm launcher. Default True.
        atomistic (bool): If true, launch atomistic experiments.
        experiment_file_name (Optional[str]): Name of the expriment file used to launch
            this
        max_lr_atomistic (float): Max learning rate ofr atomistic.
            Default 0.0002.
        no_smiles_export (bool): If true, don't export smiles. Default False.
        final_lr_atomistic (float): Final lr atomistic. Default 1e-4.
    """

    # Verify the length constraints
    assert (len(datasets) == len(dataset_types))
    assert (len(datasets) == len(dataset_splits))
    assert (len(dataset_types) == len(dataset_splits))
    assert (len(methods) == len(reg_coefs))
    assert (len(split_sizes) == 3)

    # Dump out file
    if experiment_file_name:
        dump_config_file(save_dir, experiment_file_name)

    # Handle sbatch args
    SBATCH_ARGS = f"--output=logs/{job_name_prefix}_%J.log -J {experiment_name} -t {num_days}-{num_hours}:{num_minutes}:00"
    if use_gpu:
        SBATCH_ARGS = f"--gres=gpu:volta:1 {SBATCH_ARGS}"

    BASE_ARGS = "--save_confidence conf.txt --use_entropy --confidence_evaluation_methods cutoff"

    if no_smiles_export:
        BASE_ARGS = f"{BASE_ARGS} --no_smiles_export"

    if atomistic:
        SBATCH_ARGS = f"{SBATCH_ARGS} -c 2"
        if use_slurm: BASE_ARGS = f"{BASE_ARGS} --slurm_job"

    for trial in seeds:
        seed = trial
        for dataset, dataset_type, split_type in zip(datasets, dataset_types, dataset_splits):

            save_dir_ = os.path.join(f"{save_dir}", split_type)
            for coeff, method in zip(reg_coefs, methods):
                METHOD_ARGS = ""
                method_name = method
                if method == "ensemble":
                    METHOD_ARGS=f"--ensemble_size {n_ensembles} --threads {ensemble_threads}"
                elif method == "dropout":
                    METHOD_ARGS=f"--ensemble_size {n_ensembles} --dropout {dropout} --no_dropout_inference"
                elif method == "evidence":
                    raise ValueError("Should only see new evidence with evidence_new_reg")
                elif method == "evidence_new":
                    raise ValueError("Should only see new evidence with evidence_new_reg")
                    METHOD_ARGS=f"--new_loss"
                    method_name= "evidence"
                elif method == "evidence_new_reg":
                    METHOD_ARGS=f"--new_loss --regularizer_coeff {coeff}"
                    method_name= "evidence"
                    # Rename method to have a name for the coefficient
                    method = f"{method}_{coeff}"
                else:
                    pass

                SPLIT_ARGS=f"--split_type {split_type} --split_sizes {split_sizes[0]} {split_sizes[1]} {split_sizes[2]}"

                # Add train split here
                LOG_ARGS = f"--save_dir {save_dir_}/{dataset}/{method}"

                # Set dataset args
                if dataset == "freesolv":
                    EPOCH_ARGS=f"--epochs {epochs}"
                elif dataset=="qm9":
                    EPOCH_ARGS=f"--epochs {epochs} --metric mae"
                elif dataset=="qm7":
                    EPOCH_ARGS=f"--epochs {epochs} --metric rmse"
                elif dataset=="delaney":
                    EPOCH_ARGS= f"--epochs {epochs}"
                else:
                    EPOCH_ARGS=f"--epochs {epochs}"

                if debug:
                    EPOCH_ARGS="--epochs 3"

                if atomistic:

                    # assert atomistic args
                    assert (dataset == "qm9")
                    assert (dataset_type == "regression")
                    assert (split_type == "random")
                    assert (method != "dropout")

                    LEARNING_ARGS = f"--batch_size 100 --final_lr {final_lr_atomistic} --max_lr {max_lr_atomistic}" #--patience 20" --max_lr 0.0002"

                    python_string=f"python train_atomistic.py --atomistic {LEARNING_ARGS}  --confidence {method_name} {EPOCH_ARGS} {METHOD_ARGS} {LOG_ARGS} {BASE_ARGS} {SPLIT_ARGS} --seed {trial} --dataset_type {dataset_type} --data_path data/{dataset}.db --atomistic"

                else:
                    python_string=f"python train.py --confidence {method_name} {EPOCH_ARGS} {METHOD_ARGS} {LOG_ARGS} {BASE_ARGS} {SPLIT_ARGS} --seed {trial} --dataset_type {dataset_type} --data_path data/{dataset}.csv"

                if debug:
                    python_string = f"{python_string} --debug"

                bash_string=f"sbatch {SBATCH_ARGS} --export=CMD=\"{python_string}\" scripts/generic_slurm.sh"

                if use_slurm:
                    print(f"{bash_string}")
                    subprocess.call(bash_string, shell=True)
                else:
                    print(f"{python_string}")
                    subprocess.call(python_string, shell=True)

                time.sleep(3)

if __name__ == "__main__":
    os.makedirs("logs", exist_ok=True)
    args, exp_file  = get_args()
    main( experiment_file_name = exp_file, **args)


import os
from scrapy import cmdline
from lxml import etree

mainpath = os.path.dirname(__file__) + '/lab1'
root = None

def task_1_parse():
    cmdline.execute("scrapy crawl uartlib".split())

def task_1_processing():
    result = open(mainpath + '/results/o_uartlib.xml', 'rb')
    root = etree.parse(result)
    result.close()

    pageCount = root.xpath('count(//page)')
    textCount = root.xpath('count(//fragment[@type="text"])')
    result = 'Average count of text fragments per page: %f' % (textCount / pageCount)

    f = open(mainpath + '/results/r_uartlib.txt', 'w')
    f.write(result)
    f.close()

def task_2_parse():
    cmdline.execute("scrapy crawl hozmart".split())

def task_2_processing():
    dom = etree.parse(mainpath + '/results/o_hozmart.xml')
    xslt = etree.parse(mainpath + '/hozmart.xslt')
    transform = etree.XSLT(xslt)
    newdom = transform(dom)
    with open(mainpath + '/results/r_hozmart.html', 'wb') as f:
        f.write(etree.tostring(newdom, pretty_print=True))

task_1_parse()


'''

Explanation

The answer is 2 because 11+16+26 = 53 and 53 mod 17 is 2.

'''

import sys

def min_segment_sum(a, k, p):
    min_sum = sys.maxsize
    for i in range(len(a)):
        for j in range(i, len(a)):
            if (sum(a[i:j+1]) % p) >= k:
                min_sum = min(min_sum, sum(a[i:j+1]) % p)
    return min_sum

def main():
    n, k, p = map(int, input().split())
    a = []
    for i in range(n):
        a.append(int(input()))
    print(min_segment_sum(a, k, p))

if __name__ == '__main__':
    main()


#!/usr/bin/env Python
from sys import argv
from collections import Counter
import decimal

with open(argv[1],'r') as in_file:
  in_data = in_file.read().rstrip().split(" ")
in_file.closed

prob_list = []
for entry in in_data:
  i = float(entry)
  prob = 2*((i/2)*(i/2))+2*(((1-i)/2)*((1-i)/2))
  prob_list.append(round(decimal.Decimal(prob),3))

with open("intro_probability_output.txt",'w') as out_file:
  for i in range(len(prob_list)):
    out_file.write(str(prob_list[i]))
    if (i < len(prob_list) - 1):
      out_file.write(" ")
out_file.closed


# TensorFlow2.3
# python3.8
# hanlp v2.0.0-alpha.0

import os, datetime
import math

os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID"
# # 设置为-1表示不实用GPU，GPU加速效果明显
os.environ["CUDA_VISIBLE_DEVICES"]="0"
from datetime import datetime

import tensorflow as tf
from tensorflow.keras import models,layers,losses,callbacks,optimizers
from tensorflow.keras.layers import Input, GlobalAveragePooling1D, Dropout, TimeDistributed, Dense
from tensorflow.keras.models import Model
from hanlp.common.structure import SerializableDict
from hanlp.transform.tsv import TSVTaggingTransform
from hanlp.common.vocab import Vocab
from hanlp.optimizers.adamw.optimization import AdamWeightDecay
from hanlp.utils import io_util
from hanlp.common.transform import Transform

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

from layers import WindowEmbedding, WindowEmbeddingforword

trn_path = 'dataset/data0129_bidata/train0129_all.txt'
dev_path = 'dataset/data0129_bidata/dev0129_all.txt'
save_model='model_dir/0129_best_model/'       #存储model
save_dir = 'save_dir/'    #存储vacab.json等初始化文件
static_model_path = './static_model/model/'

class SparseAccuracy(tf.keras.metrics.Metric):
    def __init__(self, name='Sparse_accuracy', **kwargs):
        super(SparseAccuracy,self).__init__(name=name,**kwargs)
        self.total = self.add_weight(name='total', dtype=tf.int32, initializer=tf.zeros_initializer())
        self.count = self.add_weight(name='count', dtype=tf.int32, initializer=tf.zeros_initializer())

    @tf.function
    def update_state(self, y_true, y_pred, sample_weight=None):
        y_true = tf.cast(y_true,tf.int32)
        y_pred = tf.cast(tf.argmax(y_pred,axis=-1),tf.int32)
        v1 = y_true*y_true
        v2 = y_pred*y_true
        values = tf.cast(tf.equal(tf.cast(v1,tf.int32), tf.cast(v2,tf.int32)), tf.int32)
        num = tf.cast(tf.equal(tf.reduce_sum(values,1),tf.reduce_sum(tf.ones_like(values),1)),tf.int32)
        self.total.assign_add(tf.shape(y_true)[0])
        self.count.assign_add(tf.reduce_sum(num))

    @tf.function
    def result(self):
        return self.count/self.total

def size_of_dataset(dataset: tf.data.Dataset) -> int:
    count = 0
    for element in dataset.unbatch().batch(1):
        count += 1
        tf.print(count)
    return count

def load_vocabs(transform,save_dir,filename='vocabs.json'):
    vocabs = SerializableDict()
    vocabs.load_json(os.path.join(save_dir, filename))
    for key, value in vocabs.items():
        vocab = Vocab()
        vocab.copy_from(value)
        setattr(transform, key, vocab)

def scheduler(epoch, lr):
  if epoch < 50:
    return lr
  else:
    return lr * math.exp(-0.01)

def build_model(transform, embeddings_size=100, rnn_units=100, window_size=1, **kwargs) -> tf.keras.Model:
    S_inputs = Input(shape=(None,), dtype='int32')
    embedding = tf.keras.layers.Embedding(input_dim=len(transform.word_vocab),
                                          output_dim=embeddings_size,
                                          trainable=True,
                                          mask_zero=True,)(S_inputs)
    # 静态embedding层
    # static_model = tf.keras.models.load_model(static_model_path, compile=False)
    # static_embeddings_param = static_model.get_weights()[0]
    # static_embedding = StaticEmbed(static_embeddings_param,
    #                                input_dim=len(transform.word_vocab),
    #                                embedding_size=embeddings_size,
    #                                mask_zero=True)(S_inputs)
    # static_embedding = tf.concat([embedding, static_embedding], axis=2)

    # window_embedding层
    window_embeddings = WindowEmbeddingforword(window_size)(embedding)

    dropout_in = Dropout(0.5)(window_embeddings)
    bilstm = tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(units=rnn_units,
                                                                return_sequences=True,), name="bilstm")(dropout_in)
    dropout_out = Dropout(0.5)(bilstm)
    outputs = TimeDistributed(Dense(len(transform.tag_vocab)), name='dense')(dropout_out)
    model = Model(inputs=S_inputs, outputs=outputs)
    return model

def build(transform):
    model = build_model(transform,embeddings=100, embedding_trainable=True,
            rnn_input_dropout=0.5, rnn_output_dropout=0.5, rnn_units=300, window_size=4)

    x_shape = [None]
    model.build(input_shape=x_shape)

    def build_optimizer(optimizer):
        if isinstance(optimizer, (str, dict)):
            custom_objects = {'AdamWeightDecay': AdamWeightDecay(learning_rate=0.001,
                                                                weight_decay_rate=0.01,
                                                                beta_1=0.9,
                                                                beta_2=0.999,
                                                                epsilon=1e-6,
                                                                exclude_from_weight_decay=['layer_norm', 'bias'])}

            optimizer: tf.keras.optimizers.Optimizer = tf.keras.utils.deserialize_keras_object(optimizer,
                                                                                module_objects=tf.keras.optimizers,
                                                                                custom_objects=custom_objects)
            # optimizer: tf.keras.optimizers.Optimizer = tf.keras.utils.deserialize_keras_object(optimizer)
        return optimizer

    # optimizer = tf.keras.optimizers.Adam(learning_rate=0.0001) #build_optimizer('Adam')
    optimizer = build_optimizer("AdamWeightDecay")
    loss = tf.keras.losses.SparseCategoricalCrossentropy(reduction=losses.Reduction.SUM,from_logits=True)
    metrics = [tf.keras.metrics.SparseCategoricalAccuracy('accuracy'),SparseAccuracy()]
    model.compile(optimizer=optimizer, loss=loss, metrics=metrics, run_eagerly=None)

    tf.print(model.summary())
    return model

def main():
    batch_size = 512
    epochs = 2000

    transform = TSVTaggingTransform()
    # 读取字典
    load_vocabs(transform, save_dir)
    # 构建模型
    # strategy = tf.distribute.MirroredStrategy(devices=['/device:GPU:0', '/device:GPU:1'])
    # with strategy.scope():
    #     model = build(transform)
    model = build(transform)

    # 把训练数据和验证数据转为tf.data.Dataset格式
    trn_data=transform.file_to_dataset(trn_path, batch_size=batch_size,shuffle=False,repeat=1)
    dev_data = transform.file_to_dataset(dev_path, batch_size=batch_size, shuffle=True,repeat=1)

    # 设立指标，存储指标最有点的模型
    metrics="Sparse_accuracy"
    monitor = f'val_{metrics}'
    checkpoint = tf.keras.callbacks.ModelCheckpoint(
                save_model,
                # verbose=1,
                monitor=monitor, save_best_only=True,
                mode='max',
                save_weights_only=False)

    tensorboard_callback = tf.keras.callbacks.TensorBoard(
                            log_dir=io_util.makedirs(io_util.path_join(save_model, 'logs')))
    earlystop = tf.keras.callbacks.EarlyStopping(monitor, mode='max', patience=50)
    csvlogger = tf.keras.callbacks.CSVLogger("0129train.csv")
    learning_rate_scheduler = tf.keras.callbacks.LearningRateScheduler(scheduler, verbose=1)
    callbacks = [checkpoint, tensorboard_callback, earlystop, csvlogger, learning_rate_scheduler]

    model.save('./model_struct/0129_best_model/', save_format='tf')
    # 模型训练
    history = model.fit(trn_data, epochs=epochs,
                         validation_data=dev_data,
                         callbacks=callbacks,verbose=1)

if __name__ == "__main__":
    main()


import pygame, sys, random
from pygame.locals import *
from inpt import beforeStart
from data import *

# Tạo sẵn các màu sắc
BLACK = (0,   0,   0)
WHITE = (255, 255, 255)
RED = (255,   0,   0)
GREEN = (0, 255,   0)
BLUE = (0,   0, 255)
SILVER = (215, 215, 215)
YELLOW = (255, 255, 0)
MAGENTA = (255, 0, 255)
MAROON = (128, 0, 0)
PURPLE = (128, 0, 128)
TEAL = (0, 128, 128)
NAVY = (0, 0, 128)
ORANGE = (255, 140, 0)
EMPTY = (0, 0, 0, 0)
# Thông số cơ bản của màn hình hiển thị
WIDTH = 25
HEIGHT = 25
BLANK = 2
NUM_X = 16
NUM_Y = 16
WINDOWHEIGHTADD = NUM_Y*HEIGHT + (NUM_Y + 1)*BLANK + 100
WINDOWWIDTH = NUM_X*WIDTH + (NUM_X + 1)*BLANK
WINDOWHEIGHT = NUM_Y*HEIGHT + (NUM_Y + 1)*BLANK
# Thông số cơ bản của game
NUM_MINE = 40

pygame.init()
FPS = 6
fpsClock = pygame.time.Clock()

SCREEN = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHTADD), SRCALPHA, pygame.RESIZABLE)
programIcon = pygame.image.load('image/mine.png')
pygame.display.set_icon(programIcon)
pygame.display.set_caption('Miner')

# Các hàm hiển thị
def color():
    x = random.randrange(0, 10)
    list_color = [BLACK, RED, GREEN, BLUE, YELLOW, MAGENTA, MAROON, PURPLE, TEAL, NAVY, ORANGE]
    color = list_color[x]
    return color

def display(font_size, status, font_color, X1, X2, Y1, Y2):
    status = str(status)
    font = pygame.font.SysFont('consolas', font_size)
    surface = font.render(status, True, font_color)
    size = surface.get_size()
    posx = (X1 - size[0]) / 2 + X2
    posy = (Y1 - size[1]) / 2 + Y2
    SCREEN.blit(surface, (posx, posy))
    return [posx, posy]

def displayImage(name_file, scaleX, scaleY, X1, X2, Y1, Y2, relative = False, posx = 0, posy = 0):
    surface = pygame.image.load('image/' + str(name_file))
    surface = pygame.transform.scale(surface, (scaleX, scaleY))
    size = surface.get_size()
    if relative:
        posx = posx
        posy = posy
    else:
        posx = (X1 - size[0]) / 2 + X2
        posy = (Y1 - size[0]) / 2 + Y2
    SCREEN.blit(surface, (posx, posy))
    return [posx, posy]

def choice_color(number):
    list_color = [RED, GREEN, BLUE, YELLOW, ORANGE]
    return list_color[number]

# Các hàm xử lý dữ liệu
def changeDatabase(name, point, time, realtime):
    insert_check = False
    data = readSqliteTable()
    print(data)
    endid = len(data) - 1
    if endid == 0:
        pass
    else:
        for i in range(endid):
            deleteSqliteRecord(i)

    for i in range(len(data)):
        if point > data[i][2] and not insert_check:
            data.insert(i, [0, name, point, time, realtime])
            insert_check = True
        elif point == data[i][2] and not insert_check:
            if realtime <= data[i][4] and not insert_check:
                data.insert(i, (0, name, point, time, realtime))
                insert_check = True

    print(data)
    for i in range(len(data)):
        InsertbyQueryPython(i, data[i][1], data[i][2], data[i][3], data[i][4])

def changeTime(realtime):
    second_after_process = int(realtime / 1000)
    minute = int(second_after_process / 60)
    second = second_after_process - minute * 60
    if minute < 10:
        if second < 10:
            time = '0' + str(minute) + ':' + '0' + str(second)
        else:
            time = '0' + str(minute) + ':' + str(second)
    else:
        if second < 10:
            time = str(minute) + ':' + '0' + str(second)
        else:
            time = str(minute) + ':' + str(second)
    return time

def randomPositionMine():
    # Tạo ra mìn
    position_mine = []
    quantity_mine = 0
    while quantity_mine < NUM_MINE:
        check = False
        x = random.randrange(0, NUM_X, 1)
        y = random.randrange(0, NUM_Y, 1)
        if len(position_mine) == 0:
            pass
        else:
            for i in range(len(position_mine)):
                if x == position_mine[i][0] and y == position_mine[i][1]:
                    check = True
                else:
                    pass
        if not check:
            position_mine.append([x, y])
        quantity_mine = len(position_mine)
    print(position_mine)
    return position_mine

def createNumber(position_mine):

    position_number = []
    # Tạo ra số
    for i in range(NUM_X):
        for j in range(NUM_Y):
            count = 0
            around = [[i - 1, j - 1], [i, j - 1], [i + 1, j - 1], [i - 1, j], [i + 1, j], [i - 1, j + 1], [i, j + 1],
                           [i + 1, j + 1]]
            for around in around:
                for mine in position_mine:
                    if around[0] == mine[0] and around[1] == mine[1]:
                        count += 1
            position_number.append([i, j, count])

    for number in position_number:
        for mine in position_mine:
            if number[0] == mine[0] and number[1] == mine[1]:
                number[2] = 9

    return position_number

def Position(position_number):
    position = position_number

    # Tạo ra cái gì đó
    for i in position:
        i.append(0)

    return position

def check_pos_mouse(pos):
    check_pos_position = False
    check_pos = []
    for i in range(NUM_X + 1):
        for j in range(NUM_Y + 1):
            x = BLANK * (i + 1) + WIDTH * i
            y = BLANK * (j + 1) + HEIGHT * j
            if x > pos[0] and y > pos[1] and check_pos_position == False:
                check_pos = [i - 1, j - 1]
                check_pos_position = True
    return check_pos

def check_lose(pos, position_mine):
    pos = check_pos_mouse(pos)
    for mine in position_mine:
        if pos[0] == mine[0] and pos[1] == mine[1]:
            return True

def check_win(coverList):
    count = 0
    for cover in coverList:
        if cover[3] == 0:
            count += 1
    if count == NUM_MINE:
        return True
    else:
        return False

# Các class chạy trong hàm GameRun()
class Board():

    def __init__(self):
        self.surface = pygame.Surface((WINDOWWIDTH, WINDOWHEIGHT))
        self.time = 0
        self.color = color()
        self.quantity = 0
        self.image_icon = str('smile.png')

    def draw(self):

        displayImage('back2.jpg', WINDOWWIDTH, 100, 0, 0, 0, 0, True, 0, WINDOWHEIGHT)
        self.surface.fill(BLACK)
        SCREEN.blit(self.surface, (0, 0))

        for i in range(NUM_X):
            for j in range(NUM_Y):
                color = WHITE
                x = BLANK * (i + 1) + WIDTH * i
                y = BLANK * (j + 1) + HEIGHT * j
                pygame.draw.rect(SCREEN, color, (x, y, WIDTH, HEIGHT))

        pos = display(HEIGHT, str(self.quantity), WHITE, WINDOWWIDTH / 2, 0, 100, WINDOWHEIGHT)
        displayImage('flag.jpg', WIDTH, HEIGHT, 0, 0, 0, 0, True, pos[0] - 40, pos[1])
        display(HEIGHT, str(self.time), WHITE, WINDOWWIDTH / 2, WINDOWWIDTH / 2, 100, WINDOWHEIGHT)
        displayImage(self.image_icon, WIDTH * 2, HEIGHT * 2, WINDOWWIDTH, 0, 100, WINDOWHEIGHT)
        pygame.draw.rect(SCREEN, self.color, pygame.Rect(WINDOWWIDTH / 4 - WIDTH * 7 / 4 - 20, 50 + WINDOWHEIGHT - HEIGHT / 10 * 11, WIDTH * 2 + 40, HEIGHT * 2), 2)

    def update(self, quantity, time, changeicon, color):
        self.color = color
        self.quantity = quantity
        self.time = changeTime(time)
        if changeicon == 1:
            self.image_icon = str('glass.png')
        elif changeicon == 2:
            self.image_icon = str('cry.png')

    def output(self):
        return self.time

class Mine():

    def __init__(self):
        self.position = []

    def start(self, position_mine):
        self.position = position_mine

    def draw(self):
        for i in range(len(self.position)):
            x = BLANK * (self.position[i][0] + 1) + WIDTH * self.position[i][0]
            y = BLANK * (self.position[i][1] + 1) + HEIGHT * self.position[i][1]
            displayImage('mine.png', WIDTH, HEIGHT, 0, 0, 0, 0, True, x, y)

    def output(self):
        return self.position

class Number():

    def __init__(self):
        self.position = []
        self.color = [BLACK, RED, BLUE, TEAL, MAGENTA, MAROON, PURPLE, GREEN, NAVY]
        self.font = pygame.font.SysFont('consolas', 22)
        self.surface = self.font.render('', True, RED)

    def start(self, position_number):
        self.position = position_number

    def draw(self):
        color_num = BLACK
        for i in range(len(self.position)):
            x = self.position[i][2]
            if x == 9:
                pass
            else:
                color_num = self.color[x]

            self.surface = self.font.render(str(self.position[i][2]), True, color_num)
            size = self.surface.get_size()
            x = BLANK * (self.position[i][0] + 1) + WIDTH * self.position[i][0] + (WIDTH - size[0])/2
            y = BLANK * (self.position[i][1] + 1) + HEIGHT * self.position[i][1] + (HEIGHT - size[1])/2
            if self.position[i][2] != 0 and self.position[i][2] != 9:
                SCREEN.blit(self.surface, (x, y))

    def output(self):
        return self.position

class CoverBoard():

    def __init__(self):
        self.cover = []
        self.check_pos = [None, None]
        self.endL = 0

    def start(self, position):
        self.cover = position

    def inpt(self, pos):
        self.check_pos = pos

    def draw(self):
        for cover in self.cover:
            if cover[3] == 1:
                pass
            else:
                color = YELLOW
                x = BLANK * (cover[0] + 1) + WIDTH * cover[0]
                y = BLANK * (cover[1] + 1) + HEIGHT * cover[1]
                # displayImage('block.png', WIDTH, HEIGHT, 0, 0, 0, 0, True, x, y)
                pygame.draw.rect(SCREEN, color, (x, y, WIDTH, HEIGHT))

    def update(self, process):
        if process == 1:
            for cover in self.cover:
                if cover[0] == self.check_pos[0] and cover[1] == self.check_pos[1]:
                    cover[3] = 1
            for cover in self.cover:
                if cover[3] == 1 and cover[2] == 0:
                    i = cover[0]
                    j = cover[1]
                    around = [[i-1, j-1], [i, j-1], [i+1, j-1], [i-1, j], [i+1, j], [i-1, j+1], [i, j+1], [i+1, j+1]]
                    for around in around:
                        for cover in self.cover:
                            if cover[0] == around[0] and cover[1] == around[1]:
                                    cover[3] = 1
        elif process == 2:
            for cover in self.cover:
                cover[3] = 1
        elif process == 3:
            for cover in self.cover:
                if cover[1] == self.endL:
                    cover[3] = 0
            self.endL += 1

    def output(self):
        return self.cover

    def end(self):
        return self.endL

class Mark():

    def __init__(self):
        self.position = []
        self.quantity = len(self.position)
        self.surface = pygame.image.load("image/flag.jpg")
        self.surface = pygame.transform.scale(self.surface, (WIDTH, HEIGHT))

    def draw(self):
        for i in range(len(self.position)):
            x = BLANK * (self.position[i][0] + 1) + WIDTH * self.position[i][0]
            y = BLANK * (self.position[i][1] + 1) + HEIGHT * self.position[i][1]
            SCREEN.blit(self.surface, (x, y))

    def update(self, pos):
        check_pos_position = False

        for i in range(NUM_X + 1):
            for j in range(NUM_Y + 1):
                x = BLANK * (i + 1) + WIDTH * i
                y = BLANK * (j + 1) + HEIGHT * j
                if x > pos[0] and y > pos[1] and check_pos_position == False:
                    if self.position.count([i - 1, j - 1]) > 0:
                        self.position.remove([i - 1, j - 1])
                        check_pos_position = True
                    else:
                        self.position.append([i - 1, j - 1])
                        check_pos_position = True

    def output(self):
        self.quantity = len(self.position)
        return self.quantity

# Các hàm xử lý chính ( các screen trong game ~ mỗi hàm là một màn hình)
def GameStart(name):
    while True:
        for event in pygame.event.get():
            if event.type == QUIT:
                pygame.quit()
                sys.exit()
            elif event.type == KEYDOWN:
                return

        displayImage('back.png', WINDOWWIDTH + 300, WINDOWHEIGHTADD, 0, 0, 0, 0, True, 0, 0)
        display(100, 'MINER', color(), WINDOWWIDTH, 0, WINDOWHEIGHT, 0)
        display(30, 'Welcome to MINER,' + ' ' + str(name), color(), WINDOWWIDTH, 0, WINDOWHEIGHT, 100)
        display(20, 'Press anything to continue', RED, WINDOWWIDTH, 0, WINDOWHEIGHT, 200)

        pygame.display.update()
        fpsClock.tick(FPS)

def GameRun(board, mine, number, coverboard, mark):

    # Khởi tạo hệ thống
    randomBoard = randomPositionMine()
    mine.start(randomBoard)
    createNum = createNumber(mine.output())
    number.start(createNum)
    position = Position(number.output())
    coverboard.start(position)

    # Khởi tạo các giá trị boolen xác định trạng thái game
    pressSpace = False
    checkwin = False
    checklose = False
    checktime = False
    changeIcon = 0
    process_in_coverboard = 1
    starttime = 0

    # Vòng lặp game
    while True:
        for event in pygame.event.get():
            if event.type == QUIT:
                pygame.quit()
                sys.exit()
            # Chuột trái mở map
            elif event.type == MOUSEBUTTONDOWN and event.button == BUTTON_LEFT:
                if not checkwin and not checklose:
                    pos = pygame.mouse.get_pos()
                    coverboard.inpt(check_pos_mouse(pos))
                    checklose = check_lose(pos, randomBoard)
                    checktime = True
            # Chuột phải đánh dấu
            elif event.type == MOUSEBUTTONDOWN and event.button == BUTTON_RIGHT:
                if not checkwin and not checklose:
                    pos = pygame.mouse.get_pos()
                    mark.update(pos)
                    checktime = True
            elif event.type == KEYDOWN:
                if event.key == K_SPACE:
                    if checkwin or checklose:
                        pressSpace = True
                # Khởi tạo lại thời gian
                if event.key == K_RETURN and checktime == False:
                    starttime = pygame.time.get_ticks()
                    checktime = True

        # Draw game
        time = pygame.time.get_ticks() - starttime
        board.update(mark.output(), time, changeIcon, color())
        board.draw()
        mine.draw()
        number.draw()
        coverboard.update(process_in_coverboard)
        coverboard.draw()
        if not checktime:
            display(20, 'Press "enter" to start', color(), WINDOWWIDTH, 0, WINDOWHEIGHT * 2, 10)

        # Kiểm tra điều kiện thắng
        if not checkwin and not checklose:
            mark.draw()
            checkwin = check_win(coverboard.output())
        else:
            if checkwin:
                display(80, 'You win', color(), WINDOWWIDTH, 0, WINDOWHEIGHT, 0)
                changeIcon = 1
            elif checklose:
                display(80, 'You lose', color(), WINDOWWIDTH, 0, WINDOWHEIGHT, 0)
                changeIcon = 2
            display(20, 'Press "space" to continnue', color(), WINDOWWIDTH, 0, WINDOWHEIGHT * 2, 10)

            if pressSpace == False:
                process_in_coverboard = 2
            else:
                process_in_coverboard = 3
                check = coverboard.end()
                if check == NUM_Y:
                    if checkwin == True:
                        return [NUM_MINE, str(board.output()), time]
                    else:
                        return [0, 0, 0]

        pygame.display.update()
        fpsClock.tick(FPS)

def GameEnd(name, point, time, realtime):
    list = []
    if point == 0 and realtime == 0:
        pass
    else:
        changeDatabase(name, point, time, realtime)

    data = readSqliteTable()
    for i in range(5):
        list.append(data[i])

    SCREEN.fill(WHITE)
    displayImage('back4.jpg', WINDOWWIDTH, WINDOWHEIGHTADD, 0, 0, 0, 0, True, 0, 0)

    while True:
        for event in pygame.event.get():
            if event.type == QUIT:
                pygame.quit()
                sys.exit()
            if event.type == KEYDOWN:
                if event.key == K_a:
                    return 1
                elif event.key == K_q:
                    pygame.quit()
                    sys.exit()
                else:
                    return 0

        display(50, 'CONGTURALATION!', color(), WINDOWWIDTH, 0, WINDOWHEIGHTADD / 4, 0)

        sepWinX = WINDOWWIDTH / 4
        sepWinY = WINDOWHEIGHTADD / 32

        color_ = color()

        display(30, 'Rank', color_, sepWinX, 0, sepWinY, sepWinY * 8)
        for i in range(len(list)):
            status = i + 1
            display(30, status, choice_color(i), sepWinX, 0, sepWinY * 3, sepWinY * 8 + (i + 1) * 50)

        display(30, 'Name', color_, sepWinX, sepWinX, sepWinY, sepWinY * 8)
        for i in range(len(list)):
            status = str(list[i][1])
            display(30, status, choice_color(i), sepWinX, sepWinX, sepWinY * 3, sepWinY * 8 + (i + 1) * 50)

        display(30, 'Score', color_, sepWinX, sepWinX * 2, sepWinY, sepWinY * 8)
        for i in range(len(list)):
            status = str(list[i][2])
            display(30, status, choice_color(i), sepWinX, sepWinX * 2, sepWinY * 3, sepWinY * 8 + (i + 1) * 50)

        display(30, 'Time', color_, sepWinX, sepWinX * 3, sepWinY, sepWinY * 8)
        for i in range(len(list)):
            status = str(list[i][3])
            display(30, status, choice_color(i), sepWinX, sepWinX * 3, sepWinY * 3, sepWinY * 8 + (i + 1) * 50)

        display(20, 'Press "A" to play again', WHITE, WINDOWWIDTH, 0, 100, WINDOWHEIGHT - 40)
        display(20, 'Press anything to continue', WHITE, WINDOWWIDTH, 0, 100, WINDOWHEIGHT)

        pygame.display.update()
        fpsClock.tick(FPS)

def main():

    again = 0
    while True:
        # Khai báo tiền xử lý
        board = Board()
        mine = Mine()
        number = Number()
        coverboard = CoverBoard()
        mark = Mark()

        if again == 0:
            name = beforeStart(SCREEN, color(), fpsClock, 60, WINDOWWIDTH, WINDOWHEIGHTADD)
            GameStart(name)
        else:
            pass

        score = GameRun(board, mine, number, coverboard, mark)
        again = GameEnd(name, score[0], score[1], score[2])

if __name__ == '__main__':
    main()


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Extract intermediate phenotype from clinical cohort
"""
import numpy as np
from sklearn.preprocessing import StandardScaler
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
from sklearn.model_selection import LeaveOneOut
from sklearn.utils import shuffle
from sklearn.metrics import balanced_accuracy_score, f1_score
from sklearn.metrics import matthews_corrcoef
from sklearn.model_selection import GridSearchCV
from sklearn.utils import resample
from tqdm import tqdm

scale = StandardScaler()

#####################################################################
# %% Prepare data
#####################################################################
# Vector containing CNV codes for each subject
# 1q21.1 del - 1
# 1q21.1 dup - 1
# 15q11.2 del - 1
# 15q11.2 dup - 1
# 16p11.2 del - 1
# 16p11.2 dup - 1
# 22q11.2 del - 1
# 22q11.2 dup - 1
y = np.load('')  # vector containing CNV codes for each subject
X_mut = np.load('')  # matrix containing regional volumes for each CNV carrier
X_ctrl = np.load('')  # matrix containing regional volumes for each control
X_full = np.concatenate((X_mut, X_ctrl))
category_names = ['1q21.1del', '1q21.1dup', '15q11.2del', '15q11.2dup',
                  '16p11.2del', '16p11.2dup', '22q11.2del', '22q11.2dup']

n_boot = 100  # nb of bootstraps during LDA model learning
n_iter = 100  # nb of random label permutations

#####################################################################
# %%  Calculate Cohen's d using brain volumes
####################################################################

def cohen_d(x, y):
    nx = len(x)
    ny = len(y)
    dof = nx + ny - 2
    res = (np.mean(x) - np.mean(y)) / \
        np.sqrt(((nx-1)*np.std(x, ddof=1) ** 2 +
                 (ny-1)*np.std(y, ddof=1) ** 2) / dof)
    return (res)

# Cohens d
X_coh = []
for i, cat in enumerate(category_names):
    X_cnv = X_mut[y == i, :]
    X_star = np.concatenate((X_cnv, X_ctrl))
    scale.fit(X_star)
    X_ctrl_ss = scale.transform(X_ctrl)
    X_cnv_ss = scale.transform(X_cnv)
    tmp_y = y[y == i]

    y_star = np.concatenate((tmp_y, np.ones(X_ctrl.shape[0])*10))
    y_star = (y_star < 10)*1
    cnv_coh = np.zeros(X_cnv.shape[1])
    for j in range(X_cnv.shape[1]):
        cnv_coh[j] = cohen_d(X_cnv_ss[:, j], X_ctrl_ss[:, j])
    X_coh.append(cnv_coh)

#####################################################################
# Classification
####################################################################

def create_traintest(X, y, n_ctrl, n_mut, boot):
    X_ctrl = X[y == 0]
    X_mut = X[y == 1]
    id_ctrl = np.arange(0, n_ctrl)
    id_mut = np.arange(0, n_mut)
    id_ctrl_train = resample(id_ctrl, replace=False, n_samples=n_mut,
                             random_state=boot)
    id_mut_train = resample(id_mut, replace=True, n_samples=n_mut,
                            random_state=boot)
    id_ctrl_test = np.setdiff1d(id_ctrl, id_ctrl_train)
    id_mut_test = np.setdiff1d(id_mut, id_mut_train)
    id_ctrl_test = np.random.choice(id_ctrl_test, size=len(id_mut_test),
                                    replace=False)  # same number of train
    X_train = np.concatenate((X_ctrl[id_ctrl_train, :],
                              X_mut[id_mut_train, :]))
    X_test = np.concatenate((X_ctrl[id_ctrl_test, :], X_mut[id_mut_test, :]))
    y_train = np.concatenate((np.zeros(n_mut), np.ones(n_mut)))
    y_test = np.concatenate((np.zeros(id_ctrl_test.shape[0]),
                             np.ones(id_mut_test.shape[0])))
    return X_train, X_test, y_train, y_test, id_mut_test

def optimize_hyperparameter(X_train, y_train, cat_id):
    model = LinearDiscriminantAnalysis(solver='eigen')
    param = {"shrinkage": np.arange(0.01, 0.91, 0.1)}
    loo = LeaveOneOut()
    search = GridSearchCV(model, param, scoring='accuracy', cv=loo,
                          n_jobs=-1, refit=True)
    # execute search
    result = search.fit(X_train, y_train)
    # get the best performing model fit on the whole training set
    best_model = result.best_estimator_
    best_model.fit(X_train, y_train)
    # re-order discriminant function
    if np.corrcoef(best_model.scalings_[:, 0], X_coh[cat_id, :])[0, 1] < 0:
        best_model.scalings_ = -best_model.scalings_
    return best_model

def boot_performance(X_test, y_test, model):
    y_predict = model.predict(X_test)
    # Performance
    acc = balanced_accuracy_score(y_test, y_predict, adjusted=False)
    f1 = f1_score(y_test, y_predict)
    mcc = matthews_corrcoef(y_test, y_predict)
    return acc, f1, mcc

def boot_main(cat_name, cat_id, X, y, boot):
    n_ctrl = np.sum(y == 0)  # nb of controls
    n_mut = np.sum(y == 1)  # nb of subjects
    X_train, X_test, y_train, y_test, id_mut_test = create_traintest(X, y,
                                                                     n_ctrl,
                                                                     n_mut,
                                                                     boot)
    model = optimize_hyperparameter(X_train, y_train, cat_id)
    acc, f1, mcc = boot_performance(X_test, y_test, model)
    return model,  acc, f1, mcc

def performance_chance(X, y, model, n_iter):
    acc = np.zeros(n_iter)
    f1 = np.zeros(n_iter)
    mcc = np.zeros(n_iter)
    # Label permutation
    for i in range(n_iter):
        rand_y = shuffle(y, random_state=i)
        y_predict = (np.matmul(X, model) > 0)*1
        # Chance
        acc[i] = balanced_accuracy_score(rand_y, y_predict, adjusted=False)
        f1[i] = f1_score(rand_y, y_predict)
        mcc[i] = matthews_corrcoef(rand_y, y_predict)
    return acc, f1, mcc

###############################################################################
# Initialize variables
accs = np.zeros([len(category_names), n_boot])
mccs = np.zeros([len(category_names), n_boot])
f1s = np.zeros([len(category_names), n_boot])
accs_chance = np.zeros([len(category_names), n_iter])
f1s_chance = np.zeros([len(category_names), n_iter])
mccs_chance = np.zeros([len(category_names), n_iter])
all_models = []
all_models_avg = np.zeros([len(category_names), X_full.shape[1]])
# Learn bagged LDA models for each CNV
for i, category in enumerate(category_names):
    print(category)
    tmp_X = X_mut[y == i, :]
    X_star = np.concatenate((tmp_X, X_ctrl))
    X_star_ss = scale.fit_transform(X_star)
    tmp_y = y[y == i]

    y_star = np.concatenate((tmp_y, np.ones(X_ctrl.shape[0])*10))
    y_star = (y_star < 10)*1
    models = []
    for j in tqdm(np.arange(0, n_boot)):
        model, accs[i, j], f1s[i, j], mccs[i, j] = boot_main(category, i,
                                                             X_star_ss,
                                                             y_star, j)
        models.append(model)

    average_model = np.average(np.array([model.scalings_[:, 0] for model in models]), axis=0)
    accs_chance[i, :], f1s_chance[i, :], mccs_chance[i, :] = performance_chance(X_star_ss,
                                                                                y_star,
                                                                                average_model,
                                                                                n_iter)
    all_models.append(models)
    all_models_avg[i, :] = average_model


import os
import sys
import inspect
import collections
import threading

class HidingLock(object):
    def __init__(self, obj, lock=None):
        self.lock = lock or threading.RLock()
        self._obj = obj

    def __enter__(self):
        self.lock.acquire()
        return self._obj

    def __exit__(self, exc_type, exc_value, traceback):
        self.lock.release()

from pimpmyclass.mixins import LogMixin

from lantz.core.driver import Driver, Base
from lantz.core.flock import initialize_many, finalize_many
from lantz.core.helpers import MISSING

from .connect import connect_setup, connect_driver, connect_feat
from .widgets import DriverTestWidget, SetupTestWidget
from .objwrapper import QDriver
from .utils.qt import QtCore, QtGui, SuperQObject, MetaQObject
from .log import get_logger, LOGGER

ICON_FEDORA = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'assets', 'fedora.png')

class ThreadLogMixin:

    _PP_THREADS = HidingLock({})

    def log_current_thread(self, msg='Current thread is'):
        thread = self.thread()
        thid = int(thread.currentThreadId())
        thname = thread.objectName()

        with self._PP_THREADS as d:
            if thid in d:
                pp = d[thid]
            else:
                pp = d[thid] = len(d)

        self.log_debug(msg + ' %s (%d-%s)' % (thname, pp, thid))

    def moveToThread(self, thread):
        super().moveToThread(thread)
        self.log_current_thread('Moved to thread:')

class InstrumentSlot:

    def __str__(self):
        return '<InstrumentSlot>'

    def initialize(self):
        LOGGER.warning('The Instrument slot {} has not been assigned '
                       'to an actual instrument', self._slot_name )

    def finalize(self):
        pass

class FlockSlot:

    def __init__(self, *required_names):
        self.require_names = required_names

    def __str__(self):
        return '<FlockSlot>'

    def initialize(self):
        LOGGER.warning('The Flock slot {} has not been assigned '
                       'to an actual flock', self._slot_name )

    def finalize(self):
        pass

class BackendSlot:

    def __str__(self):
        return '<BackendSlot>'

    def initialize(self):
        LOGGER.warning('The Backend slot {} has not been assigned '
                       'to an actual instrument', self._slot_name )

    def finalize(self):
        pass

Front2Back = collections.namedtuple('Front2Back', 'frontend_class backend_name')

class Back2Back(collections.namedtuple('Back2Back', 'backend_class local_attribute foreign_attribute')):

    def link(self, local_name, foreign_name=None):
        return Back2Back(self.backend_class, local_name, foreign_name or local_name)

class _BackendType(MetaQObject):

    def create_instrument_property(cls, key):
        def getter(self):
            return self.instruments[key]
        def setter(self, instrument):
            if not isinstance(instrument, QtCore.QObject):
                raise ValueError("The object provided for InstrumentSlot '%s' is not subclass of QObject.\n"
                                 "Maybe you forgot to wrap your driver class?\n"
                                 "  from lantz.qt import wrap_driver_cls\n"
                                 "  QMyDriver = wrap_driver_cls(QMyDriver)\n" % key)
            instrument.name = key
            self.instruments[key] = instrument

        return property(getter, setter)

    def create_flock_property(cls, key):
        def getter(self):
            return self.flocks[key]
        def setter(self, flock):
            current = self.flocks[key]
            if set(current.required_names) <= set(flock.keys()):
                raise ValueError('The flock {} must have '
                                 'the following names (given {})'.format(key,
                                                                         set(current.required_names),
                                                                         set(flock.keys())))
            self.flocks[key] = flock

        return property(getter, setter)

    def create_backend_property(cls, key):
        def getter(self):
            return self.backends[key]
        def setter(self, backend):
            self.backends[key] = backend

        return property(getter, setter)

    def __init__(cls, classname, bases, class_dict):
        super().__init__(classname, bases, class_dict)

        cls.instruments = dict()
        cls.flocks = dict()
        cls.backends = dict()
        for key, value in class_dict.items():
            if isinstance(value, InstrumentSlot) or value is InstrumentSlot:
                if value is InstrumentSlot:
                    value = value()
                cls.instruments[key] = value
                cls.instruments[key]._slot_name = key
                setattr(cls, key, cls.create_instrument_property(key))
                LOGGER.debug('In {}, adding instrument named {} of type {}'.format(cls, key, value))

            elif isinstance(value, FlockSlot) or value is FlockSlot:
                if value is FlockSlot:
                    value = value()
                cls.flocks[key] = value
                cls.flocks[key]._slot_name = key
                setattr(cls, key, cls.create_flock_property(key))
                LOGGER.debug('In {}, adding flock named {} of type {}'.format(cls, key, value))

            elif value is BackendSlot:
                cls.backends[key] = value
                cls.backends[key]._slot_name = key
                setattr(cls, key, cls.create_backend_property(key))
                LOGGER.debug('In {}, adding backend named {} of type {}'.format(cls, key, value))

            else:
                pass
                #LOGGER.debug('In {}, unhandled attribute named {} = {}'.format(cls, key, value))

    def __str__(cls):
        return cls.__name__

class _FrontendType(MetaQObject):

    def create_frontend_property(cls, key):
        def getter(self):
            return self.frontends[key]
        def setter(self, frontend):
            self.frontends[key] = frontend

        return property(getter, setter)

    def __init__(cls, classname, bases, class_dict):
        super().__init__(classname, bases, class_dict)

        cls.frontends = dict()

        for key, value in class_dict.items():
            if isinstance(value, Front2Back) or hasattr(value, 'frontends'):
                cls.frontends[key] = value
                setattr(cls, key, cls.create_frontend_property(key))
                LOGGER.debug('{}, adding frontend named {} of type {}'.format(cls, key, value))

    def __str__(cls):
        return cls.__name__

class Frontend(LogMixin, ThreadLogMixin, QtGui.QMainWindow, metaclass=_FrontendType):

    logger_name = None
    _get_logger = get_logger

    frontends = {}

     # a declarative way to indicate the user interface file to use.
    gui = None

    # connect widgets to instruments using connect_setup
    auto_connect = False

    def __init__(self, parent=None, backend=None):
        super().__init__(parent)

        self._backend = None

        if self.logger_name is None:
            self.logger_name = 'lantz.qt.frontend.' + str(self)

        if self.gui:
            for cls in self.__class__.__mro__:
                if cls is object:
                    raise ValueError('{}: loading gui file {}, reached object parent'.format(self, self.gui))

                filename = os.path.dirname(inspect.getfile(cls))
                if isinstance(self.gui, tuple):
                    filename = os.path.join(filename, *self.gui)
                else:
                    filename = os.path.join(filename, self.gui)
                if os.path.exists(filename):
                    self.log_debug('loading gui file {} in Main Window'.format(filename))
                    self.widget = QtGui.loadUi(filename)
                    if isinstance(self.widget, QtGui.QMainWindow):
                        self.log_debug('reloading gui file {} AS Main Window'.format(filename))
                        self.widget = QtGui.loadUi(filename, self)
                    else:
                        self.setCentralWidget(self.widget)
                    break
            else:
                raise ValueError('{}: loading gui file {}'.format(self, self.gui))

        # Iterate over all frontend items in the current frontend
        # and instantiate each of them.
        # Note: a frontend declares which sub backend requires
        # but instantation is delegated to lantz

        for name, frontend in self.frontends.items():

            if isinstance(frontend, Front2Back):

                # The item is a frontend that requires a backend.

                cls = frontend.frontend_class
                if backend is None:
                    # If the current backend is None, then we cannot give
                    # anything to the sub frontend item
                    widget = cls()
                    self.log_debug('{} ({}) requires a backend but no backend defined'.format(name, cls))
                else:
                    # If the current backend exists then we get which of its attribute
                    # is the backend of the subfrontend
                    sub_backend_name = frontend.backend_name
                    if sub_backend_name is None:
                        # Is the same backend
                        widget = cls(backend=backend)
                        self.log_debug('{} ({}) connected to parent backend'.format(name, cls))
                    else:
                        # Is in an attribute
                        try:
                            sub_backend=getattr(backend, sub_backend_name)
                        except AttributeError:
                            raise ValueError("{} ({}) requires a '{}' attribute which is not provided by {}".format(name, cls, sub_backend_name, backend))
                        widget = cls(backend=sub_backend)
                        self.log_debug('{} ({}) connected to backend.{}'.format(name, cls, sub_backend_name))
            else:
                # This backend does not declare a required backend
                self.log_debug('{} ({}) created'.format(name, frontend))
                widget = frontend()

            widget.setParent(self)
            setattr(self, name, widget)

        self.setupUi()
        self.backend = backend

        self.log_current_thread()

    def __str__(self):
        return self.__class__.__name__

    def setupUi(self):
        pass

    def connect_backend(self):
        pass

    @property
    def backend(self):
        return self._backend

    @backend.setter
    def backend(self, backend):
        if self._backend is not None:
            self.log_debug('disconnecting backend: {}'.format(backend))
            self.disconnect(backend)

        self._backend = backend

        if backend is not None:
            self.log_debug('connecting backend: {}'.format(backend))
            if self.auto_connect:
                connect_setup(self.widget, backend.instruments.values())

            self.connect_backend()

    @classmethod
    def using(cls, backend_name):
        return Front2Back(cls, backend_name)

    @classmethod
    def using_parent_backend(cls):
        return Front2Back(cls, backend_name=None)

    def connect_feat(self, widget, target, feat_name=None, feat_key=MISSING):
        return connect_feat(widget, target, feat_name, feat_key)

class Backend(Base, ThreadLogMixin, SuperQObject, metaclass=_BackendType):

    _observer_signal_init = lambda: QtCore.pyqtSignal(object, object)

    backends = None
    instruments = None
    flocks = None

    def __init__(self, parent=None, **instruments_and_backends):

        # First we check that the names provided do not collide with parent classes
        invalid = set(dir(Base)) | set(dir(SuperQObject)) | set(dir(_BackendType))
        for name in instruments_and_backends.keys():
            if name in invalid:
                raise ValueError('{} is an invalid instrument or backend name'
                                 ' as it collides with attribute of parent class'.format(name))

        if self.logger_name is None:
            self.logger_name = 'lantz.qt.backend.' + str(self)

        Base.__init__(self, self.logger_name)
        super().__init__(parent)

        inst_keys = set(self.instruments.keys())
        flo_keys = set(self.flocks.keys())
        be_keys = set(self.backends.keys())

        for key, value in instruments_and_backends.items():
            if key in inst_keys:
                inst_keys.remove(key)
                setattr(self, key, value)
            elif key in flo_keys:
                flo_keys.remove(key)
                self.flocks[key] = value
            elif key in be_keys:
                be_keys.remove(key)
                self.backends[key] = value
            else:
                raise ValueError('Cannot link argument. No InstrumentSlot, BackendSlot or FlockSlot named {}'.format(key))

        if inst_keys:
            raise ValueError('No value provided for InstrumentSlot {}'.format(inst_keys))

        if be_keys:
            raise ValueError('No value provided for BackendSlot {}'.format(be_keys))

        self.log_current_thread()

    def __str__(self):
        return self.__class__.__name__

    def initialize(self, register_finalizer=False):
        initialize_many(self.instruments.values(), register_finalizer=register_finalizer)

    def finalize(self):
        finalize_many(self.instruments.values())

    def __enter__(self):
        self.initialize(register_finalizer=False)
        return self

    def __exit__(self, *args):
        self.finalize()

    def invoke(self, func, *args, **kwargs):
        QtCore.QTimer.singleShot(0, lambda: func(*args, **kwargs))

    def moveToThread(self, thread):
        if self.thread().objectName().startswith('pinned-'):
            return
        super().moveToThread(thread)
        for inst in self.instruments.values():
            inst.moveToThread(thread)
        for be in self.backends.values():
            be.moveToThread(thread)

def build_qapp(qapp_or_args=None, after_func=None):
    if isinstance(qapp_or_args, QtGui.QApplication):
        qapp = qapp_or_args
    else:
        qapp = QtGui.QApplication(qapp_or_args or [''])
        qapp.setWindowIcon(QtGui.QIcon(ICON_FEDORA))

    if after_func:
        qapp = after_func(qapp)

    return qapp

def start_gui_app(backend, frontend_class, qapp_or_args=None, after_qapp_creation=None):
    qapp = build_qapp(qapp_or_args, after_qapp_creation)

    QtCore.QThread.currentThread().setObjectName('main')

    background_thread = QtCore.QThread()
    background_thread.setObjectName('background')
    backend.moveToThread(background_thread)
    background_thread.start()

    frontend = frontend_class(backend=backend)
    frontend.show()

    qapp.aboutToQuit.connect(background_thread.quit)

    if sys.platform.startswith('darwin'):
        frontend.raise_()

    sys.exit(qapp.exec_())

def start_test_app(target, width=500, qapp_or_args=None, after_qapp_creation=None):
    """Start a single window test application with a form automatically
    generated for the driver.

    Parameters
    ----------
    target :
        a driver object or a collection of drivers.
    width :
        to be used as minimum width of the window. (Default value = 500)
    qapp_or_args :
        arguments to be passed to QApplication. (Default value = None)

    Returns
    -------

    """

    qapp = build_qapp(qapp_or_args, after_qapp_creation)

    if isinstance(target, (Driver, QDriver)):
        main = DriverTestWidget(None, target)
    else:
        main = SetupTestWidget(None, target)

    main.setMinimumWidth(width)
    main.setWindowTitle('Lantz Driver Test Panel')
    main.show()
    if sys.platform.startswith('darwin'):
        main.raise_()
    qapp.exec_()

def start_gui(ui_filename, drivers, qapp_or_args=None, after_qapp_creation=None):
    """Start a single window application with a form generated from
    a designer file.

    Parameters
    ----------
    ui_filename :
        the full path of a file generated with QtDesigner.
    drivers :
        a driver object or a collection of drivers.
    qapp_or_args :
        arguments to be passed to QApplication. (Default value = None)

    Returns
    -------

    """
    qapp = build_qapp(qapp_or_args, after_qapp_creation)

    main = QtGui.loadUi(ui_filename)

    if isinstance(drivers, Driver):
        connect_driver(main, drivers)
    else:
        connect_setup(main, drivers)

    main.show()
    if sys.platform.startswith('darwin'):
        main.raise_()
    qapp.exec_()

def start_frontend(frontend_class, qapp_or_args=None, after_qapp_creation=None):
    qapp = build_qapp(qapp_or_args, after_qapp_creation)

    frontend = frontend_class()
    frontend.show()

    if sys.platform.startswith('darwin'):
        frontend.raise_()

    sys.exit(qapp.exec_())


# -*- coding: utf-8 -*
"""novelWriter Book Tree Class

 novelWriter – Book Tree Class
===============================
 Holds the tree of items and files of the book project

 File History:
 Created: 2017-10-18 [0.4.0]

"""

import logging
import nw

from os           import path
from time         import time
from hashlib      import sha256
from itertools    import chain
from nw.file.item import BookItem
from nw.file.doc  import DocFile

logger = logging.getLogger(__name__)

class BookTree():

    ORD_UP    = 0
    ORD_DOWN  = 1
    ORD_NUP   = 2
    ORD_NDOWN = 3

    validOrder = [ORD_UP,ORD_DOWN,ORD_NUP,ORD_NDOWN]

    def __init__(self):

        self.docPath    = None
        self.theTree    = []
        self.treeLookup = {}
        self.parOfItems = {}
        self.parOfFiles = {}
        self.treeOrder  = []

        self.fixedOrder = [
            BookItem.TYP_BOOK,
            BookItem.TYP_CHAR,
            BookItem.TYP_PLOT,
            BookItem.TYP_NOTE,
        ]
        self.fixedItems = {
            BookItem.TYP_BOOK : None,
            BookItem.TYP_CHAR : None,
            BookItem.TYP_PLOT : None,
            BookItem.TYP_NOTE : None,
        }

        return

    def clearTree(self):

        self.docPath    = None
        self.theTree    = []
        self.treeLookup = {}
        self.parOfItems = {}
        self.parOfFiles = {}
        self.treeOrder  = []

        self.fixedOrder = [
            BookItem.TYP_BOOK,
            BookItem.TYP_CHAR,
            BookItem.TYP_PLOT,
            BookItem.TYP_NOTE,
        ]
        self.fixedItems = {
            BookItem.TYP_BOOK : None,
            BookItem.TYP_CHAR : None,
            BookItem.TYP_PLOT : None,
            BookItem.TYP_NOTE : None,
        }

        return

    #
    # Add Elements to Main Tree
    #

    def addFile(self, pHandle):

        parEntry = self.getItem(pHandle)["entry"]
        parClass = parEntry.itemClass
        parType  = parEntry.itemType

        if not parClass == BookItem.CLS_CONT:
            logger.debug("BookTree: Entry is not a container, getting its parent")
            parParent = self.getItem(pHandle)["parent"]
            if not parParent is None:
                pHandle  = parParent
                parEntry = self.getItem(pHandle)["entry"]
                parClass = parEntry.itemClass
                parType  = parEntry.itemType
            else:
                logger.error("BookTree: A file must be added to a folder")

        if parType == BookItem.TYP_BOOK:
            newClass   = BookItem.CLS_SCENE
            newName    = "New Scene"
            newCompile = True
        else:
            newClass   = BookItem.CLS_NOTE
            newName    = "New Note"
            newCompile = None

        newItem = BookItem()
        newItem.setClass(newClass)
        newItem.setLevel(BookItem.LEV_FILE)
        newItem.setType(parType)
        newItem.setName(newName)
        newItem.setCompile(newCompile)

        self.appendItem(None,pHandle,None,newItem)
        self.sortTree()

        return

    def addChapter(self):

        newItem = BookItem()
        newItem.setClass(BookItem.CLS_CONT)
        newItem.setLevel(BookItem.LEV_ITEM)
        newItem.setType(BookItem.TYP_BOOK)
        newItem.setSubType(BookItem.SUB_CHAP)
        newItem.setName("New Chapter")
        newItem.setCompile(True)

        self.appendItem(None,self.fixedItems[BookItem.TYP_BOOK],None,newItem)
        self.sortTree()

        return

    def addCharacter(self):

        newItem = BookItem()
        newItem.setClass(BookItem.CLS_CONT)
        newItem.setLevel(BookItem.LEV_ITEM)
        newItem.setType(BookItem.TYP_CHAR)
        newItem.setName("New Character")

        self.appendItem(None,self.fixedItems[BookItem.TYP_CHAR],None,newItem)
        self.sortTree()

        return

    def addPlot(self):

        newItem = BookItem()
        newItem.setClass(BookItem.CLS_CONT)
        newItem.setLevel(BookItem.LEV_ITEM)
        newItem.setType(BookItem.TYP_PLOT)
        newItem.setName("New Plot")

        self.appendItem(None,self.fixedItems[BookItem.TYP_PLOT],None,newItem)
        self.sortTree()

        return

    #
    # Tree Item Maintenance
    #

    def updateItem(self, itemHandle, tTag, tValue):
        self.theTree[self.treeLookup[itemHandle]]["entry"].setFromTag(tTag,tValue)
        return

    def getItem(self, itemHandle):
        return self.theTree[self.treeLookup[itemHandle]]

    def changeOrder(self, itemHandle, moveIt):

        treeItem   = self.getItem(itemHandle)
        itemParent = treeItem["parent"]
        itemEntry  = treeItem["entry"]

        if itemEntry.itemLevel == BookItem.LEV_FILE:
            currList = self.parOfFiles[itemParent]
        elif itemEntry.itemLevel == BookItem.LEV_ITEM:
            currList = self.parOfItems[itemParent]
        else:
            logger.error("BookTree: Cannot change order of ROOT elements")
            return

        if moveIt not in self.validOrder:
            logger.error("BUG: Unknown ordering requested")
            return

        if itemHandle not in currList:
            logger.error("BUG: Cannot change order of %s, as it is not where it should be" % itemHandle)
            return

        # If move withing parent, just swap the indices, and refresh the master index
        if moveIt == self.ORD_UP or moveIt == self.ORD_DOWN:

            currIndex = currList.index(itemHandle)

            if moveIt == self.ORD_UP:
                newIndex = currIndex - 1
            elif moveIt == self.ORD_DOWN:
                newIndex = currIndex + 1

            if newIndex < 0 or newIndex >= len(currList): return

            currList[currIndex], currList[newIndex] = currList[newIndex], currList[currIndex]

            if itemEntry.itemLevel == BookItem.LEV_FILE:
                self.parOfFiles[itemParent] = currList
            elif itemEntry.itemLevel == BookItem.LEV_ITEM:
                self.parOfItems[itemParent] = currList

            self.buildTreeOrder()
            self.updateEntryOrder()

        # If moving to a new node, update parent and set order to None
        elif moveIt == self.ORD_NUP or moveIt == self.ORD_NDOWN:

            # This is only allowed for FILE entries
            if itemEntry.itemLevel == BookItem.LEV_ITEM: return

            treeParent = self.getItem(itemParent)
            parParent  = treeParent["parent"]
            parEntry   = treeParent["entry"]

            if parParent is not None:
                # Move to next or previous node
                parList = self.parOfItems[parParent]
                if itemParent not in parList:
                    logger.error("BUG: Something unexpected happened while moving entry")
                    return
                parIndex = parList.index(itemParent)
                if moveIt == self.ORD_NUP:
                    newIndex = parIndex - 1
                elif moveIt == self.ORD_NDOWN:
                    newIndex = parIndex + 1

                if newIndex < 0 or newIndex >= len(parList):
                    self.theTree[self.treeLookup[itemHandle]]["parent"] = parParent
                    self.sortTree()
                else:
                    self.theTree[self.treeLookup[itemHandle]]["parent"] = parList[newIndex]
                    self.sortTree()
            else:
                # Move to last child node
                parList = self.parOfItems[itemParent]
                self.theTree[self.treeLookup[itemHandle]]["parent"] = parList[len(parList)-1]
                self.sortTree()

        return

    def createRootItem(self, rootType):

        if rootType in BookItem.validTypes:
            if rootType == BookItem.TYP_BOOK: rootName = "Book"
            if rootType == BookItem.TYP_CHAR: rootName = "Characters"
            if rootType == BookItem.TYP_PLOT: rootName = "Plots"
            if rootType == BookItem.TYP_NOTE: rootName = "Notes"
        else:
            logger.error("BookTree: Cannot create root item of type '%s'" % str(rootType))
            return

        if self.fixedItems[rootType] is not None:
            logger.warning("BookTree: Root item already exists")
            return

        rootHandle = self.makeHandle()
        rootItem   = BookItem()
        rootItem.setClass(BookItem.CLS_CONT)
        rootItem.setLevel(BookItem.LEV_ROOT)
        rootItem.setType(rootType)
        rootItem.setName(rootName)

        logger.info("BookTree: Creating root item '%s' with handle %s" % (rootName, rootHandle))

        self.appendItem(rootHandle,None,None,rootItem)
        self.fixedItems[rootType] = rootHandle

        return

    def appendItem(self, tHandle, pHandle, tOrder, bookItem):
        """
        Appends an entry to the main project tree.
        """

        tHandle = self.checkString(tHandle,self.makeHandle(),False)
        pHandle = self.checkString(pHandle,None,True)
        tOrder  = self.checkInt(tOrder,None,True)

        logger.verbose("BookTree: Adding entry %s with parent %s" % (str(tHandle),str(pHandle)))

        if bookItem.itemLevel == BookItem.LEV_FILE:
            docItem = DocFile(self.docPath,tHandle,bookItem.itemClass)
        else:
            docItem = None

        self.theTree.append({
            "handle" : tHandle,
            "parent" : pHandle,
            "order"  : tOrder,
            "entry"  : bookItem,
            "doc"    : docItem,
        })
        lastIdx = len(self.theTree)-1
        self.treeLookup[tHandle] = lastIdx

        return

    def validateTree(self):

        errCount = 0

        # Checking ROOT level
        for treeItem in self.theTree:

            itemHandle = treeItem["handle"]
            itemParent = treeItem["parent"]
            bookEntry  = treeItem["entry"]
            itemIdx    = self.treeLookup[itemHandle]

            if not bookEntry.itemLevel == BookItem.LEV_ROOT: continue
            logger.verbose("BookTree: Checking ROOT with handle %s" % itemHandle)

            if itemParent is not None:
                self.theTree[itemIdx]["parent"] = None
                logger.warning("BookTree: Parent was set for ROOT element %s" % itemHandle)
                errCount += 1

            for itemType in BookItem.validTypes:
                if bookEntry.itemType == itemType:
                    if self.fixedItems[itemType] is None:
                        self.fixedItems[itemType] = itemHandle
                        logger.debug("BookTree: Root handle for type %s set to %s" % (itemType,itemHandle))
                    else:
                        logger.warning("BookTree: Encountered a second ROOT of type %s with handle %s" % (itemType,itemHandle))
                        errCount += 1

        for rootType in self.fixedItems.keys():
            if self.fixedItems[rootType] is None:
                logger.info("BookTree: Root item missing, creating it")
                self.createRootItem(rootType)

        # Checking ITEM level
        for treeItem in self.theTree:

            itemHandle = treeItem["handle"]
            itemParent = treeItem["parent"]
            bookEntry  = treeItem["entry"]
            itemIdx    = self.treeLookup[itemHandle]
            hasError   = False

            if not bookEntry.itemLevel == BookItem.LEV_ITEM: continue
            logger.verbose("BookTree: Checking ITEM with handle %s" % itemHandle)

            for itemType in BookItem.validTypes:
                if bookEntry.itemType == itemType:
                    if itemParent is None:
                        logger.warning("BookTree: Parent was missing for ITEM of type %s with handle %s" % (itemType,itemHandle))
                        self.theTree[itemIdx]["parent"] = self.fixedItems[itemType]
                        errCount += 1

        logger.info("BookTree: Found %d error(s) while parsing the project tree" % errCount)

        return

    def sortTree(self):

        # Resetting Indices
        self.parOfItems = {}
        self.parOfFiles = {}

        treeOrder = []
        logger.debug("TreeSort: Reading previous order")
        tempOrder = [None] * len(self.theTree)
        for treeItem in self.theTree:
            itemHandle = treeItem["handle"]
            itemOrder  = treeItem["order"]
            itemName   = treeItem["entry"].itemName
            if itemOrder is not None and isinstance(itemOrder,int):
                if tempOrder[itemOrder] is None:
                    tempOrder[itemOrder] = itemHandle
                    logger.vverbose("TreeSort: Entry '%s' %s has order %s" % (
                        str(itemName), str(itemHandle), str(itemOrder)
                    ))
                else:
                    tempOrder.append(itemHandle)
                    logger.vverbose("TreeSort: Entry '%s' %s has no order, appending" % (
                        str(itemName), str(itemHandle)
                    ))
            else:
                tempOrder.append(itemHandle)
                logger.vverbose("TreeSort: Entry '%s' %s has no order, appending" % (
                    str(itemName), str(itemHandle)
                ))
        for tempItem in tempOrder:
            if tempItem is not None: treeOrder.append(tempItem)

        # Scanning ROOT level
        logger.debug("TreeSort: Sorting ROOT entries")
        for rootType in self.fixedOrder:
            itemHandle = self.fixedItems[rootType]
            self.parOfItems[itemHandle] = []
            self.parOfFiles[itemHandle] = []

        # Scanning ITEM level
        logger.debug("TreeSort: Sorting ITEM entries")
        for itemHandle in treeOrder:

            itemIdx    = self.treeLookup[itemHandle]
            treeItem   = self.theTree[itemIdx]

            itemHandle = treeItem["handle"]
            itemParent = treeItem["parent"]
            bookEntry  = treeItem["entry"]

            if not bookEntry.itemLevel == BookItem.LEV_ITEM: continue

            if itemParent in self.parOfItems.keys():
                self.parOfItems[itemParent].append(itemHandle)
                logger.vverbose("TreeSort: ITEM '%s' %s appended to %s" % (
                    bookEntry.itemName, str(itemHandle), str(itemParent)
                ))
                self.parOfFiles[itemHandle] = []
            else:
                logger.warning("BUG: itemParent %s not found in itemParent" % itemParent)

        # Scanning FILE level
        logger.verbose("TreeSort: Sorting FILE entries")
        for itemHandle in treeOrder:

            itemIdx    = self.treeLookup[itemHandle]
            treeItem   = self.theTree[itemIdx]

            itemHandle = treeItem["handle"]
            itemParent = treeItem["parent"]
            bookEntry  = treeItem["entry"]

            if not bookEntry.itemLevel == BookItem.LEV_FILE: continue

            if itemParent in self.parOfFiles.keys():
                self.parOfFiles[itemParent].append(itemHandle)
                logger.vverbose("TreeSort: FILE '%s' %s appended to %s" % (
                    bookEntry.itemName, str(itemHandle), str(itemParent)
                ))
            else:
                logger.warning("BUG: itemParent %s not found in fileParent" % itemParent)

        self.buildTreeOrder()
        self.updateEntryOrder()

        return

    def buildTreeOrder(self):

        # Resetting Indices
        self.treeOrder = []

        rootOrder = []
        itemOrder = []
        fileOrder = []

        for rootType in self.fixedOrder:
            itemHandle = self.fixedItems[rootType]
            rootOrder.append(itemHandle)

        logger.debug("TreeSort: %d ROOT entries added to index" % len(rootOrder))

        for itemParent in rootOrder:
            itemOrder += self.parOfItems[itemParent]

        logger.debug("TreeSort: %d ITEM entries added to index" % len(itemOrder))

        for itemParent in chain(rootOrder,itemOrder):
            fileOrder += self.parOfFiles[itemParent]

        logger.debug("TreeSort: %d FILE entries added to index" % len(fileOrder))

        errCount = 0
        logger.debug("TreeSort: Assempling index, and checking for consistency")
        self.treeOrder = rootOrder + itemOrder + fileOrder
        for itemHandle in self.treeLookup.keys():
            if itemHandle not in self.treeOrder:
                logger.warning("BUG: Handle %s not in index" % itemHandle)
                errCount += 1
        if errCount == 0:
            logger.debug("TreeSort: Index is consistent")
        else:
            logger.warning("BUG: %d errors found in the index" % errCount)

        uniqueSet = set(self.treeOrder)
        if len(uniqueSet) == len(self.treeOrder):
            logger.debug("TreeSort: No duplicates found in index")

        return

    def updateEntryOrder(self):

        logger.debug("TreeSort: Setting order parameter of tree entries")
        for itemOrder in range(len(self.treeOrder)):
            itemHandle = self.treeOrder[itemOrder]
            itemIdx    = self.treeLookup[itemHandle]
            self.theTree[itemIdx]["order"] = itemOrder
            logger.vverbose("TreeSort: Setting '%s' %s to order %d" % (
                str(self.theTree[itemIdx]["entry"].itemName), itemHandle, itemOrder
            ))

        return

    #
    # Setters and Getters
    #

    def setPath(self, docPath):
        self.docPath = docPath
        return

    #
    # Internal Functions
    #

    def makeHandle(self,seed=""):
        itemHandle = sha256((str(time())+seed).encode()).hexdigest()[0:13]
        if itemHandle in self.treeLookup.keys():
            logger.warning("BookTree: Duplicate handle encountered! Retrying ...")
            itemHandle = self.makeHandle(seed+"!")
        return itemHandle

    def checkString(self,checkValue,defaultValue,allowNone=False):
        if allowNone:
            if checkValue == None:   return None
            if checkValue == "None": return None
        if isinstance(checkValue,str): return str(checkValue)
        return defaultValue

    def checkInt(self,checkValue,defaultValue,allowNone=False):
        if allowNone:
            if checkValue == None:   return None
            if checkValue == "None": return None
        try:
            return int(checkValue)
        except:
            return defaultValue

# End Class BookTree


from chj.util.DotGraph import DotGraph

import chj.util.fileutil as UF
import chj.util.dotutil as UD
import chj.util.graphutil as UG

import chj.index.Taint as T

from typing import cast, Dict, List, Optional, Set, Sequence, Tuple, TYPE_CHECKING

if TYPE_CHECKING:
    from chj.index.AppAccess import AppAccess
    import xml.etree.ElementTree as ET

class TaintGraph():

    def __init__(self,
            app: "AppAccess",
            appname: str,
            taintsourceid: str,
            loops: bool=False,
            sink: Optional[str]=None) -> None:
        self.app = app                   # AppAccess
        self.jd = self.app.jd            # DataDictionary
        self.loops = loops
        self.sink = sink

        self.xnodes: "ET.Element"
        self.xedges: "ET.Element"

        self.pathnodes: List[int] = []
        self.nodes: List[int] = []
        self.edges: List[Tuple[int, int]] = []

        self._build_graph(appname, taintsourceid)

    def _get_edges(self, appname: str, taintsourceid: str) -> None:
        try:
            (path,_) = UF.get_engagement_app_jars(appname)
            UF.check_analysisdir(path)
            xtrail = UF.get_data_taint_trail_xnode(path,int(taintsourceid))
        except UF.CHJError as e:
            print(str(e.wrap()))
            return

        self.xnodes = UF.safe_find(xtrail, 'node-dictionary', 'node-dictionary missing from xml')
        self.xedges = UF.safe_find(xtrail, 'edges' , 'edges missing from xml')

        self.nodes = [ UF.safe_get(n, 'ix', 'ix missing from xml', int) for n in self.xnodes.findall('tn') ]

    def _get_root_node(self, nodes: List[int], enode: "ET.Element") -> int:
        tgts = []
        for en in enode.findall('edge'):
            tgts.append(UF.safe_get(en, 'src', 'src missing from xml for taintgraph', int))
        for n in nodes:
            if not n in tgts:
                return n
        raise UF.CHJError("Root missing from TaintGraph")

    def _build_graph(self, appname: str, taintsourceid: str) -> None:
        if self.jd.ttd is None:
            raise UF.CHJError("Taint analysis results not found! Please create them first")

        self._get_edges(appname, taintsourceid)

        pathnodes: Set[int] = set([])

        if (not self.sink is None) or self.loops:
            sinkids = []

            if not self.sink is None:
                for n in self.nodes:
                    cms = self.jd.ttd.get_taint_node_type(n)
                    if self.sink in str(cms):
                        sinkids.append(n)
                if len(sinkids) == 0:
                    return

            if self.loops:
                for n in self.nodes:
                    cms = self.jd.ttd.get_taint_node_type(n)
                    if cms.is_var() and str(cast(T.VariableTaintNode, cms).get_variable()) == 'lc':
                        sinkids.append(n)

            edge_adjacencylists: Dict[int, List[int]] = {}
            for m in self.xedges.findall('edge'):
                src = UF.safe_get(m, 'src', 'src missing from xml', int)
                tgts = [ int(x) for x in UF.safe_get(m, 'tgts', 'tgts missing from xml', str).split(',') ]
                for t in tgts:
                    edge_adjacencylists.setdefault(t,[])
                    edge_adjacencylists[t].append(src)

            srcid = self._get_root_node(self.nodes, self.xedges)

            srcname = str(self.jd.ttd.get_taint_node_type(srcid))
            for sinkid in sinkids:
                sinkname = str(self.jd.ttd.get_taint_node_type(sinkid))

            for sinkid in sinkids:
                if sinkid in pathnodes: continue
                g = UG.DirectedGraph(self.nodes,edge_adjacencylists)
                g.find_paths(srcid,sinkid)
                for p in g.paths:
                    pathnodes = pathnodes.union(p)

        # if no restrictions include all nodes
        if len(pathnodes) == 0:
            pathnodes = set(self.nodes)

        edges = []
        for j in self.xedges.findall('edge'):
            src = UF.safe_get(j, 'src', 'src missing from xml', int)
            if src in self.nodes:
                tgts = [ int(x) for x in UF.safe_get(j, 'tgts', 'tgts missing from xml', str).split(',') ]
                for tgt in tgts:
                    if tgt in self.nodes:
                        edges.append((src,tgt))

        self.pathnodes = list(pathnodes)
        self.edges = edges
        return

    def as_dot(self, taintsourceid: str) -> DotGraph:
        if self.app.jd.ttd is None:
            raise UF.CHJError("Taint analysis results not found! Please create them first")

        graphname = 'trail_' + str(taintsourceid)
        dotgraph = DotGraph(graphname)
        for n in self.nodes:
            if not n in self.pathnodes: continue
            color = None
            cms = self.app.jd.ttd.get_taint_node_type(n)
            shaded = cms.is_call()
            cmslabel = cms.dotlabel()
            if cms.is_var():
                cms = cast(T.VariableTaintNode, cms)
                if str(cms.get_variable()) == 'lc':
                    color = 'red'
                if str(cms.get_variable()) == 'return':
                    color = 'green'
            elif cms.is_conditional():
                color = 'yellow'
            dotgraph.add_node(str(n),str(cmslabel),shaded=shaded,fillcolor=color)
        for (src,tgt) in self.edges:
            if src in self.pathnodes and tgt in self.pathnodes:
                dotgraph.add_edge(str(tgt),str(src))
        return dotgraph


from .env import log

class Breeds:
    """Representing a collection of breeds"""

    def __init__(self, env):
        self.breeds = {}
        self.env = env
        self.loaded = False

    def get(self, breed_no):
        if breed_no in self.breeds:
            return self.breeds[breed_no]
        else:
            return None

    def load(self, force=False):
        if self.loaded and not force:
            return

        log.debug('Loading Breeds')

        cursor = self.env.get_cursor()
        sql = 'select breed_no, breed_desc, spec_desc, billcat_desc from vwbreed'

        cursor.execute(sql)
        for row in cursor:
            breed_no = row[0]
            breed = Breed(breed_no)
            self.breeds[breed_no] = breed
            breed.desc = row[1]
            breed.spec = row[2]
            breed.bill_category = row[3]

        self.loaded = True

class Breed:
    """Representing a particular breed"""

    def __init__(self, breed_no):
        self.no = breed_no
        self.desc = ''
        self.spec = ''
        self.bill_category = ''

    def __str__(self):
        return self.desc


from buyer import Buyer
from products import Products
from cart_iter import CartIter

class Order:

    """
    Created class Order and here we construct our methods
    """

    def __init__(self, buyer: Buyer):
        self.cart = []
        self.quantity = []
        self.buyer = buyer

    def add_product(self, products: Products, quantity: int | float):
        self.cart.append(products)
        self.quantity.append(quantity)

    def total_price(self):
        total = 0
        for i, item in enumerate(self.cart):
            total += item.price * self.quantity[i]
        return total

    def __str__(self):
        res = f'{self.buyer}\n'
        for i, item in enumerate(self.cart):
            tmp = f'\t{item} UAH * {self.quantity[i]} = {self.quantity[i] * item.price} UAH \n'
            res += tmp
        res += f'Total price: {self.total_price()} UAH'
        return res

    def __getitem__(self, index):
        if isinstance(index, int):
            if 0 <= index <= len(self.cart):
                return self.cart[index]
            else:
                raise IndexError

        if isinstance(index, slice):
            slice_cart = []
            start = 0 if index.start is None else index.start
            stop = len(self.cart) if index.stop is None else index.stop
            step = 1 if index.step is None else index.step
            if 0 > index.start and index.stop > len(self.cart):
                raise IndexError
            for i in range(start, stop, step):
                slice_cart.append(self.cart[i])
            return slice_cart
        else:
            raise TypeError

    def __len__(self):
        return self.cart  # может потом попробовать len

    def __iter__(self):
        return CartIter(self.cart)

    # def __init__(self, buyer: Buyer):
    #     self.cart = {}
    #     self.buyer = buyer
    #
    # def add_product(self, products: Products, quantity: int | float):
    #     if self.cart.get(products):
    #         self.cart[products] += quantity
    #     else:
    #         self.cart[products] = quantity
    #
    # def total_price(self):
    #     total = 0
    #     for key, value in self.cart.items():
    #         total += key.price * value
    #     return total
    #
    # def __str__(self):
    #     res = f'{self.buyer}\n'
    #     for key, value in self.cart.items():
    #         tmp = f'\t{key} UAH * {value} = {key.price * value} UAH \n'
    #         res += tmp
    #     res += f'Total price: {self.total_price()} UAH'
    #     return res


from django.conf.urls import url
from . import views # . artinya mau ngambil views di folder yang sama kaya folder urls (sama2 di folder poll)

urlpatterns = [
    # /poll/
    url(r'^$', views.index, name='index'),
    # /poll/help_me
    url(r'^help_me/$', views.help_me, name='help_me'),
    # ex: /polls/5/results/
    url(r'^(?P<question_id>[0-9]+)/$', views.detail_question, name='detail_question'),
    # /poll/vote/
    url(r'^vote/$', views.vote, name='vote'),
    url(r'^(?P<question_id>[0-9]+)/results/$', views.results, name='results'),
]


# Definition for a  binary tree node
# class TreeNode:
#    def __init__(self, x):
#        self.val = x
#        self.left = None
#        self.right = None

class Solution:
    # @param A : root node of tree
    # @return an integer
    def isBalanced(self, A):
        if A is None or (A.left is None and A.right is None):
            return 1
        queue = [A]
        while len(queue) > 0:
            T = queue.pop()
            if T.left:
                queue.append(T.left)
                if not T.right and (T.left.left or T.left.right):
                    return 0
            if T.right:
                queue.append(T.right)
                if not T.left and (T.right.left or T.right.right):
                    return 0
        return 1

Tree Data Structure/Simple tree ops/Balanced_Binary_Tree.py


from picamera import PiCamera
from time import sleep
from datetime import datetime, date
# from dbinsert import insert
from . getTemperature import getTemperature
from . thermoSnapshot import thermo

from . models import Photo, Temperature

def takePhoto(camera, path, format):
    now = datetime.now()
    today = date.today()
    today = today.strftime("%d-%m-%Y_")

    current_time = now.strftime("%H_%M_%S")

    fileName = ''+today+current_time
    camera.capture(path + fileName + format)
    print('Photo taken at [' + fileName + ']')

# function take photos from vision and thermal camera
def takePhotos(camera, path, format, path2):
    now = datetime.now()
    today = date.today()
    today = today.strftime("%d-%m-%Y_")
    current_time = now.strftime("%H_%M_%S")

    file_name = ''+today + current_time
    pathPhoto = path + file_name
    pathTermo = path2

    thermo(pathTermo, 'thermo' + file_name, format)
    camera.capture(pathPhoto + format)

    photo = Photo()
    photo.name = file_name
    photo.image = file_name + format
    photo.save()

    print('Photos taken at [' + file_name + ']')
    t = getTemperature()

    temperature = Temperature()
    temperature.temperature1 = t[0]
    temperature.temperature2 = t[1]
    temperature.save()
    # print ('Temperatures:', t[0], ';', t[1])

    # insertion pictures in databese with data from temp sensors
    # insert(path + fileName + format, str(t[0]), str(t[1]), path2 + fileName + format)