import os
import torch
import torch.nn as nn
import pickle
import math
import random

from utils.BiGRU import GRU, BiGRU

class TransferNet(nn.Module):
    def __init__(self, args, vocab):
        super().__init__()
        self.args = args
        self.vocab = vocab
        self.max_active = args.max_active
        self.ent_act_thres = args.ent_act_thres
        self.aux_hop = args.aux_hop
        dim_word = args.dim_word
        dim_hidden = args.dim_hidden

        with open(os.path.join(args.input_dir, 'wiki.pt'), 'rb') as f:
            self.kb_pair = torch.LongTensor(pickle.load(f))
            self.kb_range = torch.LongTensor(pickle.load(f))
            self.kb_desc = torch.LongTensor(pickle.load(f))

        print('number of triples: {}'.format(len(self.kb_pair)))

        num_words = len(vocab['word2id'])
        num_entities = len(vocab['entity2id'])
        self.num_steps = args.num_steps

        self.desc_encoder = BiGRU(dim_word, dim_hidden, num_layers=1, dropout=0.2)
        self.question_encoder = BiGRU(dim_word, dim_hidden, num_layers=1, dropout=0.2)

        self.word_embeddings = nn.Embedding(num_words, dim_word)
        self.word_dropout = nn.Dropout(0.2)
        self.step_encoders = []
        for i in range(self.num_steps):
            m = nn.Sequential(
                nn.Linear(dim_hidden, dim_hidden),
                nn.Tanh(),
            )
            self.step_encoders.append(m)
            self.add_module('step_encoders_{}'.format(i), m)
        self.rel_classifier = nn.Linear(dim_hidden, 1)

        self.q_classifier = nn.Linear(dim_hidden, num_entities)
        self.hop_selector = nn.Linear(dim_hidden, self.num_steps)

    def follow(self, e, pair, p):
        """
        Args:
            e [num_ent]: entity scores
            pair [rsz, 2]: pairs that are taken into consider
            p [rsz]: transfer probabilities of each pair
        """
        sub, obj = pair[:, 0], pair[:, 1]
        obj_p = e[sub] * p
        out = torch.index_add(torch.zeros_like(e), 0, obj, obj_p)
        return out

    def forward(self, questions, e_s, answers=None, hop=None):
        question_lens = questions.size(1) - questions.eq(0).long().sum(dim=1) # 0 means <PAD>
        q_word_emb = self.word_dropout(self.word_embeddings(questions)) # [bsz, max_q, dim_hidden]
        q_word_h, q_embeddings, q_hn = self.question_encoder(q_word_emb, question_lens) # [bsz, max_q, dim_h], [bsz, dim_h], [num_layers, bsz, dim_h]

        device = q_word_h.device
        bsz, dim_h = q_embeddings.size()
        last_e = e_s
        word_attns = []
        ent_probs = []

        path_infos = [] # [bsz, num_steps]
        for i in range(bsz):
            path_infos.append([])
            for j in range(self.num_steps):
                path_infos[i].append(None)

        for t in range(self.num_steps):
            cq_t = self.step_encoders[t](q_embeddings) # [bsz, dim_h]
            q_logits = torch.sum(cq_t.unsqueeze(1) * q_word_h, dim=2) # [bsz, max_q]
            q_dist = torch.softmax(q_logits, 1).unsqueeze(1) # [bsz, 1, max_q]
            q_dist = q_dist * questions.ne(0).float().unsqueeze(1)
            q_dist = q_dist / (torch.sum(q_dist, dim=2, keepdim=True) + 1e-6) # [bsz, 1, max_q]
            word_attns.append(q_dist.squeeze(1))
            ctx_h = (q_dist @ q_word_h).squeeze(1) # [bsz, dim_h]
            ctx_h = ctx_h + cq_t

            e_stack = []
            cnt_trunc = 0
            for i in range(bsz):
                # e_idx = torch.topk(last_e[i], k=1, dim=0)[1].tolist() + \
                #         last_e[i].gt(self.ent_act_thres).nonzero().squeeze(1).tolist()
                # TRY
                # if self.training and t > 0 and random.random() < 0.005:
                #     e_idx = last_e[i].gt(0).nonzero().squeeze(1).tolist()
                #     random.shuffle(e_idx)
                # else:
                sort_score, sort_idx = torch.sort(last_e[i], dim=0, descending=True)
                e_idx = sort_idx[sort_score.gt(self.ent_act_thres)].tolist()
                e_idx = set(e_idx) - set([0])
                if len(e_idx) == 0:
                    # print('no active entity at step {}'.format(t))
                    pad = sort_idx[0].item()
                    if pad == 0:
                        pad = sort_idx[1].item()
                    e_idx = set([pad])

                rg = []
                for j in e_idx:
                    rg.append(torch.arange(self.kb_range[j,0], self.kb_range[j,1]).long().to(device))
                rg = torch.cat(rg, dim=0) # [rsz,]
                # print(len(e_idx), len(rg))
                if len(rg) > self.max_active: # limit the number of next-hop
                    rg = rg[:self.max_active]
                    # TRY
                    # rg = rg[torch.randperm(len(rg))[:self.max_active]]
                    cnt_trunc += 1
                    # print('trunc: {}'.format(cnt_trunc))

                # print('step {}, desc number {}'.format(t, len(rg)))
                pair = self.kb_pair[rg] # [rsz, 2]
                desc = self.kb_desc[rg] # [rsz, max_desc]
                desc_lens = desc.size(1) - desc.eq(0).long().sum(dim=1)
                desc_word_emb = self.word_dropout(self.word_embeddings(desc))
                desc_word_h, desc_embeddings, _ = self.desc_encoder(desc_word_emb, desc_lens) # [rsz, dim_h]
                d_logit = self.rel_classifier(ctx_h[i:i+1] * desc_embeddings).squeeze(1) # [rsz,]
                d_prob = torch.sigmoid(d_logit) # [rsz,]
                # transfer probability
                e_stack.append(self.follow(last_e[i], pair, d_prob))

                # collect path
                act_idx = d_prob.gt(0.9)
                act_pair = pair[act_idx].tolist()
                act_desc = [' '.join([self.vocab['id2word'][w] for w in d if w > 0]) for d in desc[act_idx].tolist()]
                path_infos[i][t] = [(act_pair[_][0], act_desc[_], act_pair[_][1]) for _ in range(len(act_pair))]

            last_e = torch.stack(e_stack, dim=0)

            # reshape >1 scores to 1 in a differentiable way
            m = last_e.gt(1).float()
            z = (m * last_e + (1-m)).detach()
            last_e = last_e / z

            # Specifically for MetaQA: reshape cycle entities to 0, because A-r->B-r_inv->A is not allowed
            if t > 0:
                ent_m = torch.zeros_like(last_e)
                for i in range(bsz):
                    prev_inv = set()
                    for (s, r, o) in path_infos[i][t-1]:
                        prev_inv.add((o, r.replace('__subject__', 'obj').replace('__object__', 'sub'), s))
                    for (s, r, o) in path_infos[i][t]:
                        element = (s, r.replace('__subject__', 'sub').replace('__object__', 'obj'), o)
                        if r != '__self_rel__' and element in prev_inv:
                            ent_m[i, o] = 1
                            # print('block cycle: {}'.format(' ---> '.join(list(map(str, element)))))
                last_e = (1-ent_m) * last_e

            ent_probs.append(last_e)

        hop_res = torch.stack(ent_probs, dim=1) # [bsz, num_hop, num_ent]
        hop_logit = self.hop_selector(q_embeddings)
        hop_attn = torch.softmax(hop_logit, dim=1) # [bsz, num_hop]
        last_e = torch.sum(hop_res * hop_attn.unsqueeze(2), dim=1) # [bsz, num_ent]

        # Specifically for MetaQA: for 2-hop questions, topic entity is excluded from answer
        m = hop_attn.argmax(dim=1).eq(1).float().unsqueeze(1) * e_s
        last_e = (1-m) * last_e

        # question mask, incorporate language bias
        q_mask = torch.sigmoid(self.q_classifier(q_embeddings))
        last_e = last_e * q_mask

        if not self.training:
            return {
                'e_score': last_e,
                'word_attns': word_attns,
                'ent_probs': ent_probs,
                'path_infos': path_infos
            }
        else:
            weight = answers * 9 + 1
            loss_score = torch.mean(weight * torch.pow(last_e - answers, 2))

            loss = {'loss_score': loss_score}

            if self.aux_hop:
                loss_hop = nn.CrossEntropyLoss()(hop_logit, hop-1)
                loss['loss_hop'] = 0.01 * loss_hop

            return loss


import torch

class PointOnBones:
    def __init__(self, bone_ids):
        self.bone_ids = bone_ids

    def get_points(self, joints, num_per_bone=5):
        """Sample points on bones in canonical space.

        Args:
            joints (tensor): joint positions to define the bone positions. shape: [B, J, D]
            num_per_bone (int, optional): number of sample points on each bone. Defaults to 5.

        Returns:
            samples (tensor): sampled points in canoncial space. shape: [B, ?, 3]
            probs (tensor): ground truth occupancy for samples (all 1). shape: [B, ?]
        """

        num_batch, _, _ = joints.shape

        samples = []

        for bone_id in self.bone_ids:

            if bone_id[0] < 0 or bone_id[1] < 0:
                continue

            bone_dir = joints[:, bone_id[1]] - joints[:, bone_id[0]]

            scalars = (
                torch.linspace(0, 1, steps=num_per_bone, device=joints.device)
                .unsqueeze(0)
                .expand(num_batch, -1)
            )
            scalars = (
                scalars + torch.randn((num_batch, num_per_bone), device=joints.device) * 0.1
            ).clamp_(0, 1)

            samples.append(
                joints[:, bone_id[0]].unsqueeze(1).expand(-1, scalars.shape[-1], -1)
                + torch.einsum("bn,bi->bni", scalars, bone_dir) # b: num_batch, n: num_per_bone, i: 3-dim
            )

        samples = torch.cat(samples, dim=1)

        probs = torch.ones((num_batch, samples.shape[1]), device=joints.device)

        return samples, probs

    def get_joints(self, joints):
        """Sample joints in canonical space.

        Args:
            joints (tensor): joint positions to define the bone positions. shape: [B, J, D]

        Returns:
            samples (tensor): sampled points in canoncial space. shape: [B, ?, 3]
            weights (tensor): ground truth skinning weights for samples (all 1). shape: [B, ?, J]
        """
        num_batch, num_joints, _ = joints.shape

        samples = []
        weights = []

        for k in range(num_joints):
            samples.append(joints[:, k])
            weight = torch.zeros((num_batch, num_joints), device=joints.device)
            weight[:, k] = 1
            weights.append(weight)

        for bone_id in self.bone_ids:

            if bone_id[0] < 0 or bone_id[1] < 0:
                continue

            samples.append(joints[:, bone_id[1]])

            weight = torch.zeros((num_batch, num_joints), device=joints.device)
            weight[:, bone_id[0]] = 1
            weights.append(weight)

        samples = torch.stack(samples, dim=1)
        weights = torch.stack(weights, dim=1)

        return samples, weights

class PointInSpace:
    def __init__(self, global_sigma=1.8, local_sigma=0.01):
        self.global_sigma = global_sigma
        self.local_sigma = local_sigma

    def get_points(self, pc_input, sample_size=None):
        """Sample one point near each of the given point + 1/8 uniformly.

        Args:
            pc_input (tensor): sampling centers. shape: [B, N, D]

        Returns:
            samples (tensor): sampled points. shape: [B, N + sample_size, D]
        """

        batch_size, pts_num, dim = pc_input.shape

        if sample_size is None:
            sample_size = pts_num

        sample_local = pc_input + (torch.randn_like(pc_input) * self.local_sigma)

        sample_global = (torch.rand(batch_size, sample_size, dim, device=pc_input.device)
            * (self.global_sigma * 2)) - self.global_sigma

        sample = torch.cat([sample_global, sample_local], dim=1)

        return sample


from imports import *
from torch.utils.data import Dataset

from utils import load_img, load_msk, prepare_loaders

class BuildDataset(Dataset):
    def __init__(self, df, label=True, transforms=None):
        self.df = df
        self.label = label
        self.img_paths = df['image_path'].tolist()
        self.msk_paths = df['mask_path'].tolist()
        self.transforms = transforms

    def __len__(self):
        return len(self.df)

    def __getitem__(self, index):
        img_path = self.img_paths[index]
        img = []
        img = load_img(img_path)

        if self.label:
            msk_path = self.msk_paths[index]
            msk = load_msk(msk_path)
            if self.transforms:
                data = self.transforms(image=img, mask=msk)
                img = data['image']
                msk = data['mask']
            img = np.transpose(img, (2, 0, 1))
            msk = np.transpose(msk, (2, 0, 1))
            return torch.tensor(img), torch.tensor(msk)
        else:
            if self.transforms:
                data = self.transforms(image=img)
                img = data['image']
            img = np.transpose(img, (2, 0, 1))
            return torch.tensor(img)

train_loader, valid_loader = prepare_loaders(fold=5, debug=True)


from functools import total_ordering
from typing import Collection, List, Dict

import sortedcontainers

from utils.case_utils import get_trios_for_family

@total_ordering
class Pos:
    def __init__(self, chromosome, pos) -> None:
        self.chromosome = chromosome
        self.pos = pos

    def __str__(self) -> str:
        return "{}:{:d}".format(self.chromosome, self.pos)

    def __eq__(self, o: object) -> bool:
        if not isinstance(o, Pos):
            return False
        return self.chromosome == o.chromosome and self.pos == o.pos

    def __lt__(self, o):
        if not isinstance(o, Pos):
            raise TypeError
        chromosomes = []
        for c in [self.chromosome, o.chromosome]:
            if c.startswith('chr'):
                c = c[3:]
            c = c.lower()
            if c == 'm':
                c = 0
            elif c == 'x':
                c = 24
            elif c == 'y':
                c = 25
            else:
                c = int(c)
            chromosomes.append(c)
        if chromosomes[0] == chromosomes[1]:
            return self.pos < o.pos
        return chromosomes[0] < chromosomes[1]

    def __hash__(self) -> int:
        return hash((self.chromosome, self.pos))

class TSVReader:
    def __init__(self, tsv_calls_file:str, format_string:str, samples:Collection) -> None:
        super().__init__()
        self.samples = samples
        if format_string:
            patterns = dict()
            patterns.update({s:format_string.format(sample=s) for s in self.samples})
        else:
            patterns = None
        self.candidate_calls = sortedcontainers.SortedDict()
        with open(tsv_calls_file) as calls:
            for call in calls:
                if call.startswith('#'):
                    continue
                samples=set()
                if patterns:
                    for sample in patterns:
                        if patterns[sample] in call:
                            samples.add(sample)
                    if not samples:
                        continue

                data = call.split()
                key = Pos(data[0], int(data[1]))
                if samples:
                    self.candidate_calls[key] = samples
                else:
                    self.candidate_calls[key] = data[2:]

    def has_call(self, chromosome, pos):
        return Pos(chromosome, pos) in self.candidate_calls

    def has_sample(self, chromosome, pos, sample):
        call = self.candidate_calls.get(Pos(chromosome, pos))
        if call:
            return sample in call
        return False

    def call_list(self):
        return sorted([call for call in self.candidate_calls])

    def call_set(self):
        return {call for call in self.candidate_calls}

def create_tsv_reader(families:List,
                      metadata:Dict,
                      tsv_calls_file:str,
                      format_string:str) -> TSVReader:
    samples = set()
    if not families:
        families = [f for f in metadata]
    for f in families:
        family = metadata[f]
        trios = get_trios_for_family(family)
        for s in trios:
            samples.add(s)
    return TSVReader(tsv_calls_file, format_string, samples)


from django.shortcuts import render,redirect
from .models import Libreria

# Create your views here.

def inicio(request):
    libreria = Libreria.objects.all()
    return render(request,"libreria.html",{"libros": libreria})

def registarlibros(request):
    Libro = request.POST['Libro']
    Autor = request.POST['Autor']
    Editorial = request.POST['Editorial']
    libros=Libreria.objects.create(Libro=Libro, Autor=Autor, Editorial=Editorial)
    return redirect('/')

def edicionlibros(request,ID):
    libros=Libreria.objects.get(ID=ID)
    return render(request,"edicionlibros.html",{"libros": libros})

def editarlibros(request):
    IDLi = request.POST['ID']
    Libro = request.POST['Libro']
    Autor = request.POST['Autor']
    Editorial = request.POST['Editorial']

    libros=Libreria.objects.get(ID=IDLi)
    libros.Libro=Libro
    libros.Autor=Autor
    libros.Editorial=Editorial
    libros.save()
    return redirect('/')

def eliminarlibros(request,ID):
    libros=Libreria.objects.get(ID=ID)
    libros.delete()
    return redirect('/')


from . import _, PLUGIN_PATH
from Screens.Screen import Screen
from Screens.Standby import TryQuitMainloop
from Screens.ChoiceBox import ChoiceBox
from Screens.MessageBox import MessageBox
from Components.Sources.StaticText import StaticText
from Components.ActionMap import ActionMap, NumberActionMap
from Components.ConfigList import ConfigListScreen
import Components.ParentalControl
from Components.config import config, getConfigListEntry, ConfigSubsection, ConfigSubDict, ConfigInteger
from Components.FileList import FileList
from Components.Label import Label
from Components.Pixmap import Pixmap
from Tools.Directories import pathExists, SCOPE_SKIN_IMAGE, SCOPE_CURRENT_SKIN, resolveFilename, getSize
from enigma import eServiceReference, eServiceCenter, eTimer, getDesktop, eEPGCache
from Screens.EventView import EventViewSimple
from Screens.EpgSelection import EPGSelection
from ServiceReference import ServiceReference
from plugin import CheckTimeshift, BEHAVIOR
FIRST_BEHAVIOR = True

plugin_version = "1.17"

def getAlternativeChannels(service):
	alternativeServices = eServiceCenter.getInstance().list(eServiceReference(service))
	return alternativeServices and alternativeServices.getContent("S", True)

def GetWithAlternative(service):
	if service.startswith('1:134:'):
		channels = getAlternativeChannels(service)
		if channels:
			return channels[0]
	return service

service_types_tv = '1:7:1:0:0:0:0:0:0:0:(type == 1) || (type == 17) || (type == 22) || (type == 25) || (type == 31) || (type == 134) || (type == 195)'
service_types_radio = '1:7:2:0:0:0:0:0:0:0:(type == 2) || (type == 10)'

def getActions(xmlfile, hotkeys={}):
	result = { }
	try:
		import xml.etree.cElementTree
		root = xml.etree.cElementTree.parse(xmlfile).getroot()
	except:
		root = None
	if not root is None:
		for item in root.findall('action'):
			id = item.get('id')
			if id:
				result[id] = item.attrib.copy()
				result[id]['title'] = (result[id].get('title','') or id.replace('_',' ').title()).encode('UTF-8')
				result[id]['hotkey'] = int(result[id].get('hotkey', 0)) or hotkeys.get(id, 0)
				if result[id].get('type', '') in ('screen', 'code'):
					result[id]['args'] = item.text or ''
				result[id].pop('id')
	return result

ACTIONLIST = getActions('%s/actions.xml'%(PLUGIN_PATH), eval(config.plugins.NumberZapExt.hotkeys.value))

def getServiceFromNumber(self, number, acount=True, bouquet=None, startBouquet=None):
	def searchHelper(serviceHandler, num, bouquet):
		servicelist = serviceHandler.list(bouquet)
		if not servicelist is None:
			while num:
				s = servicelist.getNext()
				if not s.valid(): break
				try:
					playable = not (s.flags & (eServiceReference.isMarker|eServiceReference.isDirectory)) or (s.flags & eServiceReference.isNumberedMarker)
				except:
					playable = not (s.flags & (eServiceReference.isMarker|eServiceReference.isDirectory))
				if playable:
					num -= 1
			if not num: return s, num
		return None, num

	if self.servicelist is None: return None
	service = None
	serviceHandler = eServiceCenter.getInstance()
	if startBouquet and bouquet and startBouquet == bouquet:
		service, number = searchHelper(serviceHandler, number, bouquet)
	elif not config.usage.multibouquet.value:
		bouquet = self.servicelist.bouquet_root
		service, number = searchHelper(serviceHandler, number, bouquet)
	elif acount and self.servicelist.getMutableList() is not None:
		bouquet = self.servicelist.getRoot()
		service, number = searchHelper(serviceHandler, number, bouquet)
	elif acount and bouquet is not None:
		service, number = searchHelper(serviceHandler, number, bouquet)
	else:
		bouquet = self.servicelist.bouquet_root
		bouquetlist = serviceHandler.list(bouquet)
		if not bouquetlist is None:
			while number:
				bouquet = bouquetlist.getNext()
				if not bouquet.valid(): break
				if bouquet.flags & eServiceReference.isDirectory and not bouquet.flags & eServiceReference.isInvisible:
					service, number = searchHelper(serviceHandler, number, bouquet)
					if acount: break
	return service, bouquet

class DirectoryBrowser(Screen):
	skin = """<screen name="DirectoryBrowser" position="center,center" size="520,440" title=" " >
			<ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
			<ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
			<widget source="key_red" render="Label" position="0,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" transparent="1" />
			<widget source="key_green" render="Label" position="140,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#1f771f" transparent="1" />
			<widget source="curdir" render="Label" position="5,50" size="510,20"  font="Regular;20" halign="left" valign="center" backgroundColor="background" transparent="1" noWrap="1" />
			<widget name="filelist" position="5,80" size="510,345" scrollbarMode="showOnDemand" />
		</screen>"""

	def __init__(self, session, curdir, matchingPattern=None):
		Screen.__init__(self, session)

		self["Title"].setText(_("Directory browser"))
		self["key_red"] = StaticText(_("Cancel"))
		self["key_green"] = StaticText(_("Save"))
		self["curdir"] = StaticText(_("current:  %s")%(curdir or ''))

		self.filelist = FileList(curdir, matchingPattern=matchingPattern, enableWrapAround=True)
		self.filelist.onSelectionChanged.append(self.__selChanged)
		self["filelist"] = self.filelist

		self["FilelistActions"] = ActionMap(["SetupActions", "ColorActions"],
			{
				"green": self.keyGreen,
				"red": self.keyRed,
				"ok": self.keyOk,
				"cancel": self.keyRed
			})
		self.onLayoutFinish.append(self.__layoutFinished)

	def __layoutFinished(self):
		pass

	def getCurrentSelected(self):
		dirname = self.filelist.getCurrentDirectory()
		filename = self.filelist.getFilename()
		if not filename and not dirname:
			cur = ''
		elif not filename:
			cur = dirname
		elif not dirname:
			cur = filename
		else:
			if not self.filelist.canDescent() or len(filename) <= len(dirname):
				cur = dirname
			else:
				cur = filename
		return cur or ''

	def __selChanged(self):
		self["curdir"].setText(_("current:  %s")%(self.getCurrentSelected()))

	def keyOk(self):
		if self.filelist.canDescent():
			self.filelist.descent()

	def keyGreen(self):
		if self.filelist.canDescent() and self.getCurrentSelected():
			self.close(self.getCurrentSelected())

	def keyRed(self):
		self.close(False)

class NumberZapExt(Screen):
	if getDesktop(0).size().width() >= 1920:
		skin = """<screen name="NumberZapExt" position="center,center" size="900,240" title=" ">
				<widget name="chPicon" position="700,15"  size="150,90" alphatest="on" />
				<widget name="number"  position="7,52"    size="285,45" halign="right" font="Regular;39" />
				<widget name="chNum"   position="315,52"  size="360,45" halign="left"  font="Regular;39" />
				<widget name="channel" position="7,100"    size="285,45" halign="right" font="Regular;39" />
				<widget name="chName"  position="315,100"  size="550,45" halign="left"  font="Regular;36" noWrap="1" />
				<widget name="bouquet" position="7,173"   size="285,45" halign="right" font="Regular;39" />
				<widget name="chBouq"  position="315,173" size="550,45" halign="left"  font="Regular;36" noWrap="1" />
				<widget name="InfoIcon" pixmap="skin_default/buttons/key_info.png" position="5,180" zPosition="10" size="70,50" transparent="1" alphatest="on" />
			</screen>"""
	elif getDesktop(0).size().width() >= 1280:
		skin = """<screen name="NumberZapExt" position="center,center" size="600,160" title=" ">
				<widget name="chPicon" position="475,10"  size="100,60" alphatest="on" />
				<widget name="number"  position="5,35"    size="190,30" halign="right" font="Regular;26" />
				<widget name="chNum"   position="210,35"  size="240,30" halign="left"  font="Regular;26" />
				<widget name="channel" position="5,75"    size="190,30" halign="right" font="Regular;26" />
				<widget name="chName"  position="210,75"  size="375,30" halign="left"  font="Regular;24" noWrap="1" />
				<widget name="bouquet" position="5,115"   size="190,30" halign="right" font="Regular;26" />
				<widget name="chBouq"  position="210,115" size="375,30" halign="left"  font="Regular;24" noWrap="1" />
				<widget name="InfoIcon" pixmap="skin_default/buttons/key_info.png" position="5,120" zPosition="10" size="35,25" transparent="1" alphatest="on" />
			</screen>"""
	else:
		skin = """<screen name="NumberZapExt" position="center,center" size="350,145" title=" ">
				<widget name="chPicon" position="273,7"   size="70,53"  alphatest="on" />
				<widget name="number"  position="5,35"    size="110,25" halign="right" font="Regular;23" />
				<widget name="chNum"   position="130,35"  size="130,25" halign="left"  font="Regular;23" />
				<widget name="channel" position="5,70"    size="110,25" halign="right" font="Regular;23" />
				<widget name="chName"  position="130,70"  size="215,25" halign="left"  font="Regular;21" noWrap="1" />
				<widget name="bouquet" position="5,105"   size="110,25" halign="right" font="Regular;23" />
				<widget name="chBouq"  position="130,105" size="215,25" halign="left"  font="Regular;21" noWrap="1" />
				<widget name="InfoIcon" pixmap="skin_default/buttons/key_info.png" position="5,110" zPosition="10" size="35,25" transparent="1" alphatest="on" />
			</screen>"""

	def __init__(self, session, number, servicelist=None):
		Screen.__init__(self, session)
		self.session = session
		self.parental_control = False
		self.digits = config.plugins.NumberZapExt.digits.value
		self.field = str(number)
		self.servicelist = servicelist
		self.acount = config.plugins.NumberZapExt.acount.value
		self.startBouquet = None
		self.bouquets = None
		self.current_service = None
		if self.servicelist is not None:
			self.bouquets = self.servicelist.getBouquetList()
		else:
			self.bouquets = None
		self.BouquetsPriority = False
		if config.plugins.NumberZapExt.bouquets_enable.value:
			if config.usage.multibouquet.value:
				self.bouquet_root_tv = eServiceReference('1:7:1:0:0:0:0:0:0:0:FROM BOUQUET "bouquets.tv" ORDER BY bouquet')
				self.bouquet_root_radio = eServiceReference('1:7:1:0:0:0:0:0:0:0:FROM BOUQUET "bouquets.radio" ORDER BY bouquet')
			else:
				self.bouquet_root_tv = eServiceReference('%s FROM BOUQUET "userbouquet.favourites.tv" ORDER BY bouquet'%(service_types_tv))
				self.bouquet_root_radio = eServiceReference('%s FROM BOUQUET "userbouquet.favourites.radio" ORDER BY bouquet'%(service_types_radio))
			self.Bouquetlist = self.getBouquetlist(self.bouquet_root_tv) + self.getBouquetlist(self.bouquet_root_radio)
			self.hotkeys_bouquets = eval(config.plugins.NumberZapExt.hotkeys_bouquets.value)
		self.kdelay = config.plugins.NumberZapExt.kdelay.value
		self.bouqSelDlg = None
		self.bouquet = None
		self.action = ''
		self.bouquet_action = None
		self.defpicon = None
		if config.plugins.NumberZapExt.picons.value:
			for scope, path in [(SCOPE_CURRENT_SKIN, "picon_default.png"), (SCOPE_SKIN_IMAGE, "skin_default/picon_default.png")]:
				tmp = resolveFilename(scope, path)
				if pathExists(tmp) and getSize(tmp):
					self.defpicon = tmp
					break

		self["Title"].setText(_("Service"))
		self["number"]  = Label(_("Number:"))
		self["channel"] = Label(_("Channel:"))
		self["bouquet"] = Label(_("Bouquet:"))
		self["chNum"]   = Label()
		self["chName"]  = Label()
		self["chBouq"]  = Label()
		self['InfoIcon'] = Pixmap()
		self['InfoIcon'].hide()
		self["chPicon"] = Pixmap()
		self["actions"] = NumberActionMap([ "ShortcutActions", "SetupActions", "MenuActions", "InfobarEPGActions"],
			{
				"red": self.keyRed,
				"cancel": self.quit,
				"ok": self.keyOK,
				"green": self.keyGreen,
				"yellow": self.keyYellow,
				"blue": self.keyBlue,
				"menu": self.keyMenu,
				"showEventInfo": self.infobuttonClick,
				"showEventInfoSingleEPG": self.epgbuttonClick,
				"1": self.keyNumberGlobal,
				"2": self.keyNumberGlobal,
				"3": self.keyNumberGlobal,
				"4": self.keyNumberGlobal,
				"5": self.keyNumberGlobal,
				"6": self.keyNumberGlobal,
				"7": self.keyNumberGlobal,
				"8": self.keyNumberGlobal,
				"9": self.keyNumberGlobal,
				"0": self.keyNumberGlobal
			})
		self.Timer = eTimer()
		self.pauseTimer = eTimer()
		self.Timer.callback.append(self.keyOK)
		self.pauseTimer.callback.append(self.delayAnswerBouquets)
		self.onFirstExecBegin.append(self.__onStart)

	def __onStart(self):
		if self.servicelist is None: self.quit()
		if config.plugins.NumberZapExt.acount.value and self.servicelist.getMutableList() is None:
			if not self.bouquets: self.quit()
			if len(self.bouquets) == 1:
				self.bouquetSelected(self.bouquets[0][1])
			else:
				from Screens.ChannelSelection import BouquetSelector
				self.bouqSelDlg = self.session.openWithCallback(self.bouquetSelectorClosed, BouquetSelector, self.bouquets, self.bouquetSelected, enableWrapAround=True)
		else:
			self.printLabels()
			self.startTimer(firstPress=True)

	def getBouquetlist(self, root):
		bouquets = [ ]
		serviceHandler = eServiceCenter.getInstance()
		if config.usage.multibouquet.value:
			bouquetlist = serviceHandler.list(root)
			if bouquetlist:
				while True:
					s = bouquetlist.getNext()
					if not s.valid(): break
					if s.flags & eServiceReference.isDirectory and not s.flags & eServiceReference.isInvisible:
						info = serviceHandler.info(s)
						if info: bouquets.append((info.getName(s), s))
		else:
			info = serviceHandler.info(root)
			if info:
				bouquets.append((info.getName(root), root))
		return bouquets

	def epgbuttonClick(self):
		if self.Timer.isActive():
			return 0
		if self.current_service is None:
			return 0
		if self.current_service:
			serviceHandler = eServiceCenter.getInstance()
			info = serviceHandler.info(self.current_service)
			event = info and info.getEvent(self.current_service)
			if event:
				try:
					self.session.open(EPGSelection, self.current_service)
				except:
					pass

	def infobuttonClick(self):
		if self.Timer.isActive():
			return 0
		if self.current_service is None:
			return 0
		epglist = [ ]
		self.epglist = epglist
		cur = self.current_service
		serviceHandler = eServiceCenter.getInstance()
		info = serviceHandler.info(cur)
		event = info and info.getEvent(cur)
		if event:
			epglist.append(event)
		try:
			epg = eEPGCache.getInstance()
			next_event = epg.lookupEventTime(cur, -1, 1)
			if next_event:
				epglist.append(next_event)
		except:
			pass
		if event:
			self.session.open(EventViewSimple, event, ServiceReference(cur), self.eventViewCallback, self.openSimilarList)

	def eventViewCallback(self, setEvent, setService, val):
		epglist = self.epglist
		if epglist is None:
			return
		if len(epglist) > 1:
			tmp = epglist[0]
			epglist[0] = epglist[1]
			epglist[1] = tmp
			setEvent(epglist[0])

	def openSimilarList(self, eventid, refstr):
		self.session.open(EPGSelection, refstr, None, eventid)

	def keyMenu(self):
		if config.plugins.NumberZapExt.bouquets_enable.value and not config.plugins.NumberZapExt.bouquets_priority.value:
			self.BouquetsPriority = True
			self.printLabels()
			self.startTimer()

	def keyBlue(self):
		if self.acount and self.startBouquet is None and self.bouquets is not None and len(self.bouquets) > 3:
			self.startBouquet = self.bouquets[3][1]
			self.bouquetSelected(self.bouquets[3][1])

	def keyYellow(self):
		if self.acount and self.startBouquet is None and self.bouquets is not None and len(self.bouquets) > 2:
			self.startBouquet = self.bouquets[2][1]
			self.bouquetSelected(self.bouquets[2][1])

	def keyGreen(self):
		if self.acount and self.startBouquet is None and self.bouquets is not None and len(self.bouquets) > 1:
			self.startBouquet = self.bouquets[1][1]
			self.bouquetSelected(self.bouquets[1][1])

	def keyRed(self):
		if self.acount and self.startBouquet is None and self.bouquets is not None and len(self.bouquets) > 1:
			self.startBouquet = self.bouquets[0][1]
			self.bouquetSelected(self.bouquets[0][1])

	def bouquetSelectorClosed(self, retval):
		if retval is False:
			self.quit()
		else:
			self.bouqSelDlg = None

	def bouquetSelected(self, bouquet):
		if self.bouqSelDlg:
			self.bouqSelDlg.close(True)
		self.bouquet = bouquet
		if self.startBouquet is None:
			self.startBouquet = self.bouquet
		self.pauseTimer.stop()
		self.pauseTimer.start(50, True)

	def delayAnswerBouquets(self):
		if Components.ParentalControl.parentalControl.isServicePlayable(self.bouquet, self.bouquetParentalControlCallback, self.session):
			self.printLabels()
			self.parental_control = False
			self.startTimer(firstPress=True)
		else:
			self.parental_control = True

	def bouquetParentalControlCallback(self, ref):
		self.parental_control = False
		self.printLabels()
		self.startTimer(firstPress=True)

	def startTimer(self, firstPress=False):
		self.Timer.stop()
		self['InfoIcon'].hide()
		if firstPress:
			first_delay = config.plugins.NumberZapExt.first_delay.value
			if first_delay:
				self.current_service = None
				self.Timer.start(first_delay, True)
			else:
				self['InfoIcon'].show()
		else:
			if self.kdelay:
				self.current_service = None
				self.Timer.start(self.kdelay, True)
			else:
				self['InfoIcon'].show()

	def printLabels(self):
		self.bouquet_action = None
		bouquet_name = None
		self.action = ''
		hotkeys_priority = config.plugins.NumberZapExt.hotkeys_priority.value
		bouquets_priority = config.plugins.NumberZapExt.bouquets_priority.value or self.BouquetsPriority
		if hotkeys_priority or bouquets_priority:
			if bouquets_priority:
				bouquet_name, self.bouquet_action = self.getHotkeyBouquets(int(self.field))
			if self.bouquet_action is not None:
				name = _("%s" % (bouquet_name or ''))
				channel = _("Bouquet:")
				bouquet = bqname = ""
				service = None
			elif hotkeys_priority:
				self.action = self.getHotkeyAction(int(self.field))
				if self.action:
					name = _(ACTIONLIST[self.action]['title'])
					channel = _("Action:")
					bouquet = bqname = ""
					service = None
				else:
					channel = _("Channel:")
					bouquet = _("Bouquet:")
					service, name, bqname = self.getNameFromNumber(int(self.field))
					if name == 'N/A': name = _("invalid channel number")
			else:
				channel = _("Channel:")
				bouquet = _("Bouquet:")
				service, name, bqname = self.getNameFromNumber(int(self.field))
				if name == 'N/A':
					if not service is None:
						name = _("service not found")
					else:
						name = _("invalid channel number")
						self.action = self.getHotkeyAction(int(self.field))
						if self.action:
							name = _(ACTIONLIST[self.action]['title'])
							channel = _("Action:")
							bouquet = bqname = ""
							service = None
		else:
			channel = _("Channel:")
			bouquet = _("Bouquet:")
			service, name, bqname = self.getNameFromNumber(int(self.field))
			if name == 'N/A':
				if not service is None:
					name = _("service not found")
				else:
					name = _("invalid channel number")
					bouquet_name, self.bouquet_action = self.getHotkeyBouquets(int(self.field))
					if self.bouquet_action is not None:
						name = _("%s" % (bouquet_name or ''))
						channel = _("Bouquet:")
						bouquet = bqname = ""
						service = None
					else:
						self.action = self.getHotkeyAction(int(self.field))
						if self.action:
							name = _(ACTIONLIST[self.action]['title'])
							channel = _("Action:")
							bouquet = bqname = ""
							service = None
		self["chNum"].setText(self.field)
		self["channel"].setText(channel)
		self["bouquet"].setText(bouquet)
		self["chName"].setText(name)
		self["chBouq"].setText(bqname)
		if service and (name != _("service not found") or name != _("invalid channel number")):
			self.current_service = service
		else:
			self.current_service = None
		if config.plugins.NumberZapExt.picons.value:
			pngname = self.defpicon
			if service:
				refstr = service.toString()
				if refstr.startswith('1:134:'):
					refstr = GetWithAlternative(refstr)
				sname = ':'.join(refstr.split(':')[:11])
				pos = sname.rfind(':')
				if pos != -1:
					sname = sname[:pos].rstrip(':').replace(':','_')
					sname = config.plugins.NumberZapExt.picondir.value + sname + '.png'
					if pathExists(sname):
						pngname = sname
					else:
						self["chPicon"].instance.setPixmap(None)
						return
				self["chPicon"].instance.setScale(1)
				self["chPicon"].instance.setPixmapFromFile(pngname)
			else:
				self["chPicon"].instance.setPixmap(None)

	def quit(self):
		self.Timer.stop()
		self.close(0, None, None)

	def keyOK(self):
		self.Timer.stop()
		if self.parental_control:
			self.quit()
		else:
			self.close(int(self["chNum"].getText()), self.bouquet_action or self.action or self.bouquet, self.startBouquet)

	def keyNumberGlobal(self, number):
		if self.acount and self.startBouquet and self.bouquet and self.startBouquet == self.bouquet:
			pass
		else:
			self.bouquet = self.startBouquet = None
		self.BouquetsPriority = False
		self.startTimer()
		l = len(self.field)
		if l < self.digits:
			l += 1
			self.field += str(number)
			self.printLabels()
		elif self.kdelay:
			self.keyOK()

	def getNameFromNumber(self, number):
		name = 'N/A'
		bqname = 'N/A'
		service, bouquet = getServiceFromNumber(self, number, acount=self.acount, bouquet=self.bouquet, startBouquet=self.startBouquet)
		if not service is None:
			serviceHandler = eServiceCenter.getInstance()
			info = serviceHandler.info(service)
			name = info and info.getName(service) or 'N/A'
			if bouquet and bouquet.valid():
				info = serviceHandler.info(bouquet)
				bqname = info and info.getName(bouquet)
		return service, name, bqname

	def getHotkeyAction(self, number):
		if config.plugins.NumberZapExt.hotkey.value:
			for (key,val) in ACTIONLIST.items():
				if val.get('hotkey',-1) == number:
					return key
		return ''

	def getHotkeyBouquets(self, number):
		if config.plugins.NumberZapExt.bouquets_enable.value:
			for i in range(len(self.Bouquetlist)):
				if i in range(len(self.hotkeys_bouquets)):
					key = self.hotkeys_bouquets[i]
					if key == number:
						num = i - 1
						try:
							bouquet_ref = self.Bouquetlist[num][1] and self.Bouquetlist[num][1].toString()
						except:
							bouquet_ref = None
						if self.servicelist is not None and bouquet_ref is not None:
							if ('.%s"' % config.servicelist.lastmode.value) in str(bouquet_ref):
								return self.Bouquetlist[num][0], self.Bouquetlist[num][1]
		return None, None

class NumberZapExtSetupScreen(Screen, ConfigListScreen):
	def __init__(self, session, actionlist):
		Screen.__init__(self, session)
		self.skinName = ["NumberZapExtSetup", "Setup"]
		self.setup_title = _("Extended NumberZap Setup")
		self.actionlist = actionlist

		self["key_green"] = StaticText(_("Save"))
		self["key_red"] = StaticText(_("Cancel"))
		self["actions"] = NumberActionMap(["SetupActions"],
		{
			"cancel": self.keyRed,	# KEY_RED, KEY_EXIT
			"ok": self.keyOk,	# KEY_OK
			"save": self.keyGreen,	# KEY_GREEN
		}, -1)

		ConfigListScreen.__init__(self, [])
		if config.usage.multibouquet.value:
			self.bouquet_root_tv = eServiceReference('1:7:1:0:0:0:0:0:0:0:FROM BOUQUET "bouquets.tv" ORDER BY bouquet')
			self.bouquet_root_radio = eServiceReference('1:7:1:0:0:0:0:0:0:0:FROM BOUQUET "bouquets.radio" ORDER BY bouquet')
		else:
			self.bouquet_root_tv = eServiceReference('%s FROM BOUQUET "userbouquet.favourites.tv" ORDER BY bouquet'%(service_types_tv))
			self.bouquet_root_radio = eServiceReference('%s FROM BOUQUET "userbouquet.favourites.radio" ORDER BY bouquet'%(service_types_radio))
		self.Bouquetlist = self.getBouquetList(self.bouquet_root_tv) + self.getBouquetList(self.bouquet_root_radio)
		self.prev_hotkeys_bouquets = eval(config.plugins.NumberZapExt.hotkeys_bouquets.value)
		self.initConfig()
		self.createSetup()
		self.onClose.append(self.__closed)
		self.onLayoutFinish.append(self.__layoutFinished)

	def __closed(self):
		pass

	def __layoutFinished(self):
		self.setTitle(self.setup_title + ": " + plugin_version)

	def getBouquetList(self, root):
		bouquets = [ ]
		serviceHandler = eServiceCenter.getInstance()
		if config.usage.multibouquet.value:
			bouquetlist = serviceHandler.list(root)
			if bouquetlist:
				while True:
					s = bouquetlist.getNext()
					if not s.valid(): break
					if s.flags & eServiceReference.isDirectory and not s.flags & eServiceReference.isInvisible:
						info = serviceHandler.info(s)
						if info: bouquets.append((info.getName(s), s))
		else:
			info = serviceHandler.info(root)
			if info:
				bouquets.append((info.getName(root), root))
		return bouquets

	def initConfig(self):
		def getPrevValues(section):
			res = { }
			for (key,val) in section.content.items.items():
				if isinstance(val, ConfigSubsection):
					res[key] = getPrevValues(val)
				else:
					res[key] = val.value
			return res

		self.NZE = config.plugins.NumberZapExt
		self.prev_values = getPrevValues(self.NZE)
		self.cfg_enable = getConfigListEntry(_("Enable extended number zap"), self.NZE.enable)
		self.cfg_digits = getConfigListEntry(_("Number of channel number digits"), self.NZE.digits)
		self.cfg_fdelay = getConfigListEntry(_("Time to wait first keypress (ms)"), self.NZE.first_delay)
		self.cfg_kdelay = getConfigListEntry(_("Time to wait next keypress (ms)"), self.NZE.kdelay)
		self.cfg_acount = getConfigListEntry(_("Alternative service counter in bouquets"), self.NZE.acount)
		self.cfg_acounthelp = getConfigListEntry(_("<< Press colors keys (the first four bouquets) >>"), self.NZE.acount_help)
		self.cfg_timeshift_behavior = getConfigListEntry(_("Behavior when timeshift is enabled"), self.NZE.timeshift_behavior)
		self.cfg_key0 = getConfigListEntry(_("Check timeshift of 0 key in recall service"), self.NZE.key0)
		self.cfg_picons = getConfigListEntry(_("Enable picons"), self.NZE.picons)
		self.cfg_picondir = getConfigListEntry(_("Picons directory (press OK)"), self.NZE.picondir)
		self.cfg_hotkey = getConfigListEntry(_("Enable number hotkeys"), self.NZE.hotkey)
		self.cfg_hotkey_bouquets = getConfigListEntry(_("Enable bouquets hotkeys"), self.NZE.bouquets_enable)
		self.cfg_bouquets_priority = getConfigListEntry(_("Hotkey bouquets have priority"), self.NZE.bouquets_priority)
		self.cfg_bouquets_help = getConfigListEntry(_("<< Press menu key (for priority bouquets) >>"), self.NZE.bouquets_help)
		self.action = ConfigSubDict()
		for key,val in self.actionlist.items():
			self.action[key] = ConfigInteger(default=val['hotkey'], limits=(0,9999))
		self.BouquetsKey = ConfigSubDict()
		for i in range(len(self.Bouquetlist)):
			val = 0
			if i in range(len(self.prev_hotkeys_bouquets)):
				val = self.prev_hotkeys_bouquets[i]
			self.BouquetsKey[i] = ConfigInteger(default=val, limits=(0,9999))

	def createSetup(self):
		list = [ self.cfg_enable ]
		if self.NZE.enable.value:
			list.append(self.cfg_digits)
			list.append(self.cfg_fdelay)
			list.append(self.cfg_kdelay)
			list.append(self.cfg_acount)
			if self.NZE.acount.value:
				list.append(self.cfg_acounthelp)
			list.append(self.cfg_timeshift_behavior)
			if CheckTimeshift is not None:
				list.append(self.cfg_key0)
			list.append(self.cfg_picons)
			if self.NZE.picons.value:
				list.append(self.cfg_picondir)
			list.append(self.cfg_hotkey_bouquets)
			if self.NZE.bouquets_enable.value:
				list.append(self.cfg_bouquets_priority)
				if not self.NZE.bouquets_priority.value:
					list.append(self.cfg_bouquets_help)
				num = 0
				for bouquet in self.Bouquetlist:
					num += 1
					for i in range(len(self.Bouquetlist)):
						if num == i:
							list.append(getConfigListEntry(bouquet[0], self.BouquetsKey[i]))
			list.append(self.cfg_hotkey)
			if self.NZE.hotkey.value:
				list.append(getConfigListEntry(_("Hotkey action have priority"), self.NZE.hotkeys_priority))
				list.append(getConfigListEntry(_("Confirmation on hotkey action"), self.NZE.hotkeys_confirmation))
				for key,val in sorted(self.actionlist.items(), key=lambda x: int(x[1].get('weight', 0))):
					list.append(getConfigListEntry(_(val['title']), self.action[key]))
		self["config"].list = list
		self["config"].l.setList(list)

	def newConfig(self):
		cur = self["config"].getCurrent()
		if cur in (self.cfg_enable, self.cfg_hotkey, self.cfg_picons, self.cfg_timeshift_behavior, self.cfg_acount, self.cfg_hotkey_bouquets, self.cfg_bouquets_priority):
			self.createSetup()
		elif cur == self.cfg_picondir:
			self.keyOk()

	def keyOk(self):
		cur = self["config"].getCurrent()
		if cur == self.cfg_picondir:
			directory = self.NZE.picondir.value
			if directory == "":
				directory = None
			self.session.openWithCallback(self.directoryBrowserClosed, DirectoryBrowser, directory, matchingPattern="^.*\.png")

	def directoryBrowserClosed(self, path):
		if path != False and path != '':
			self.NZE.picondir.value = path
			self.createSetup()

	def keyRed(self):
		def setPrevValues(section, values):
			for (key,val) in section.content.items.items():
				value = values.get(key, None)
				if value is not None:
					if isinstance(val, ConfigSubsection):
						setPrevValues(val, value)
					else:
						val.value = value
		setPrevValues(self.NZE, self.prev_values)
		for key,val in self.actionlist.items():
			if self.action[key].value != val['hotkey']:
				self.action[key].value = val['hotkey']
		for i in range(len(self.Bouquetlist)):
			num = 0
			if i in range(len(self.prev_hotkeys_bouquets)):
				num = self.prev_hotkeys_bouquets[i]
			self.BouquetsKey[i].value = num
		self.keyGreen()

	def keyGreen(self):
		global FIRST_BEHAVIOR
		if not self.NZE.enable.value:
			self.NZE.acount.value = False
			self.NZE.timeshift_behavior.value = "0"
		if CheckTimeshift is None:
			self.NZE.key0.value = False
		self.NZE.save()
		tmp = dict()
		for key,val in self.actionlist.items():
			if self.action[key].value != val['hotkey']:
				self.actionlist[key]['hotkey'] = self.action[key].value
			if self.actionlist[key]['hotkey'] != 0:
				tmp[key] = self.actionlist[key]['hotkey']
		config.plugins.NumberZapExt.hotkeys.value = repr(tmp)
		config.plugins.NumberZapExt.hotkeys.save()
		setup_key = []
		for i in range(len(self.Bouquetlist)):
			setup_key.append((self.BouquetsKey[i].value))
		config.plugins.NumberZapExt.hotkeys_bouquets.value = str(setup_key)
		config.plugins.NumberZapExt.hotkeys_bouquets.save()
		need_restart = False
		cur_val = self.NZE.timeshift_behavior.value
		if BEHAVIOR == "1":
			if FIRST_BEHAVIOR and BEHAVIOR != cur_val:
				need_restart = True
		elif BEHAVIOR in ("0", "2"):
			if cur_val == "1" and BEHAVIOR != cur_val and FIRST_BEHAVIOR:
				need_restart = True
		if need_restart:
			open_list = [
				(_("No (do not remind)"), "notremind"),
				(_("Restart GUI"), "restart"),
				(_("No (close)"), "no"),
			]
			self.session.openWithCallback(self.restartGuiNow, ChoiceBox, title= _("GUI needs a restart to apply changes 'Behavior when timeshift is enabled'.\nRestart the GUI now?"), list = open_list)
		else:
			del self.action
			self.close()

	def restartGuiNow(self, ret):
		ret = ret and ret[1]
		if ret:
			if ret == "no":
				del self.action
				self.close()
			elif ret == "notremind":
				global FIRST_BEHAVIOR
				FIRST_BEHAVIOR = False
				del self.action
				self.close()
			elif ret == "restart":
				del self.action
				self.session.open(TryQuitMainloop, 3)

	def keyLeft(self):
		ConfigListScreen.keyLeft(self)
		self.newConfig()

	def keyRight(self):
		ConfigListScreen.keyRight(self)
		self.newConfig()


from pathlib import Path
import glob, os
import sys
import numpy as np

coord = lambda x: np.floor(float(x)/50*100)/100

WIRES = {}

tikzset_defs = set()
TIKZSET = """\\tikzset{
    partial ellipse/.style args={#1:#2:#3}{
        insert path={+ (#1:#3) arc (#1:#2:#3)}
    }
}"""
TIKZCODE = ""

unitvec = lambda vec: vec / np.linalg.norm(vec)

angle = lambda v: np.degrees(np.arctan2(v[1], v[0]))

node_degree = {}

def cleanup_text(text):

    text = text.replace("_", "\\_")

    return text

def rotate_vec(vec, deg):

    theta = np.deg2rad(deg)
    rot = np.array([[np.cos(theta), -np.sin(theta)], [np.sin(theta), np.cos(theta)]])
    return np.dot(rot, vec)

def name_of_component(component):
    return component.replace("/", "-")

def tikz_add(s):

    global TIKZCODE

    TIKZCODE += s + "\n"

def add_symbol(symfile):

    global TIKZSET

    tikzset_defs.add(symfile)

#     \tikzset{ pics/res.asy/.style args={#1/#2}{
# code={
# \draw (0.32,1.76) to (0.32,1.92);\draw (0.0,1.6) to (0.32,1.76);\draw (0.64,1.28) to (0.0,1.6);\draw (0.0,0.96) to (0.64,1.28);\draw (0.64,0.64) to (0.0,0.96);\draw (0.32,0.32) to (0.32,0.48);\draw (0.32,0.48) to (0.64,0.64);\draw (0.72,0.8) node {#1};\draw (0.72,1.52) node {#2};
# }
# }
# }

    with open(symfile, "r") as f:

        TIKZSET += "\\tikzset{ pics/" + name_of_component(symfile) + "/.style args={#1*^*#2}{code={"

        for i in f.read().split("\n"):

            cmd = i.split(" ")

            if cmd[0] == "LINE":

                coords = [coord(i) for i in cmd[2:6]]

                style = cmd[1]

                TIKZSET += f"\draw ({coords[0]},{coords[1]}) to ({coords[2]},{coords[3]});\n"

            elif cmd[0] == "CIRCLE":

                coords = [coord(i) for i in cmd[2:6]]

                style = cmd[1]

                pos = np.array(coords[0:2])
                size = abs(pos - coords[2:4])/2

                pos += size

                TIKZSET += f"\draw ({pos[0]},{pos[1]}) ellipse ({size[0]} and {size[1]});\n"

            elif cmd[0] == "ARC":

                coords = np.array([coord(i) for i in cmd[2:10]])

                pos = coords[0:2]

                size = abs(pos - coords[2:4])/2

                center = (pos + coords[2:4])/2

                theta_i = angle(coords[6:8]-center)
                theta_f = angle(coords[4:6]-center)

                TIKZSET += f"\draw ({center[0]},{center[1]}) [partial ellipse={theta_i}:{theta_f}:{size[0]} and {size[1]}];\n"

            elif cmd[0] == "WINDOW":

                # WINDOW 0 24 16 Left 2
                # WINDOW 1 36 80 Left 2

                type = cmd[1]
                pos = [coord(i) for i in cmd[2:4]]

                alignment = cmd[4]
                fontsize = cmd[5]

                text = ""

                if type=="0":
                    text = "#1"
                elif type=="3":
                    text = "#2"

                TIKZSET += f"\\draw ({pos[0]},{pos[1]}) node[yscale=-1] {{{text}}};\n"

        TIKZSET += "}}}\n"

def draw_symbol(symfile, loc, angle, data0, data3):

    global TIKZCODE

    if data0==None: data0 = ""
    if data3==None: data3 = ""

    data0, data3 = cleanup_text(data0), cleanup_text(data3)

    if symfile in tikzset_defs:
        # place in circ
        pass
    else:
        add_symbol(symfile)

    tikz_add(f"\path[rotate around ={'{'}{angle}:({loc[0]}, {loc[1]}){'}'}, anchor=west, transform shape] ({loc[0]}, {loc[1]}) pic{{{name_of_component(symfile)}={data0}*^*{data3}}};")

def incremenet_node_degree(p):

    try:
        node_degree[p] += 1
    except:
        node_degree[p] = 0

def text_window(text, pos, angle, align_vec=[0, 1]):

    if NO_COMMENTS_AND_COMMANDS == True: return

    global TIKZCODE

    align_cmd = ""

    align_vec = rotate_vec(align_vec, angle)

    if angle == 90 or angle == 270:
        align_vec = rotate_vec(align_vec, -90)

    if np.allclose(align_vec, [0, 1]):
        align_cmd = "[below]"
    elif np.allclose(align_vec, [0, -1]):
        align_cmd = "[above]"
    elif np.allclose(align_vec, [1, 0]):
        align_cmd = "[left]"
    elif np.allclose(align_vec, [-1, 0]):
        align_cmd = "[right]"

    TIKZCODE +=  f"\\draw ({pos[0]},{pos[1]}) node {align_cmd} {{{cleanup_text(text)}}};\n"

def parse_circuit(circuit, component_name, component_value, local_dir):

    global TIKZCODE

    circuit_split = circuit.split("\n")

    k=-1
    for i in circuit_split:

        k+=1

        cmd = i.split(" ")

        if "WIRE" in cmd[0]:

            # print(i)

            coords = [coord(i) for i in cmd[1:5]]

            tikz_add(f"\\draw ({coords[0]},{coords[1]}) to ({coords[2]},{coords[3]});")

            WIRES[(coords[0],coords[1])] = (coords[2],coords[3])
            WIRES[(coords[2],coords[3])] = (coords[0],coords[1])

            incremenet_node_degree((coords[0],coords[1]))
            incremenet_node_degree((coords[2],coords[3]))

        elif "FLAG" in cmd[0]:

            # tikz_add("%" + i)

            coords = [coord(i) for i in cmd[1:3]]

            node_type = cmd[3]

            if node_type == "0":
                draw_symbol("gnd.asy", coords, 0, "", "")

            # print(f"({coords[0]},{coords[1]}) to ({coords[0]},{coords[1]}) {node_type}")

        elif "TEXT" in cmd[0]:

            pos = [coord(i) for i in cmd[1:3]]

            if cmd[3] == "VBottom": cmd[3] = [0, -1]
            elif cmd[3] == "VTop": cmd[3] = [0, 1]
            elif cmd[3] == "Left": cmd[3] = [-1, 0]
            elif cmd[3] == "Right": cmd[3] = [1, 0]

            text = ' '.join(cmd[5:]) #[1:] # the [1:] removes the [; or !] char at the beginning of comment

            # TODO: cmd 4 is size (and add support for symbol window and symbol compiler!)

            text_window(text, pos, 0, align_vec=cmd[3])

        elif "SYMBOL" in cmd[0]:

            # if sys.platform == "darwin":
            #     os.chdir(os.path.expanduser('~') + "/Library/Application Support/LTspice/lib/sym")

            # elif sys.platform == "linux" or sys.platform == "linux2":
            #     os.chdir(os.path.expanduser('~') + "/Documents/LTspiceXVII/lib/sym")

            # elif sys.platform == "win32":
            #     os.chdir(os.path.expanduser('~') + "/Documents/LTspiceXVII/lib/sym")

            coords = np.array( [coord(i) for i in cmd[2:4]] )

            angle = int(cmd[4][1:])

            # check if symbol
            path = Path(local_dir + "/" + cmd[1]+".asy")

            # try:
            #     symfile = glob.glob(cmd[1].lower()+".asy")[0]
            # except:
            #     symfile = glob.glob(local_dir + "/" + cmd[1].lower()+".asy")[0]

            if not path.is_file():
                path = Path(cmd[1]+".asy")

            klocal = 0

            data0 = ""
            data3 = ""

            window0, window3 = None, None

            while klocal<100:
                klocal+=1

                cmd = circuit_split[k+klocal].split(" ")

                if cmd[0]=="SYMATTR":
                    if cmd[1] == "InstName" and component_name:
                        if data0!=None:
                            data0 = ' '.join(cmd[2:])
                        else:
                            pos = np.array([coord(window0[i]) for i in [0, 1]])
                            pos = rotate_vec(pos, angle)+coords

                            if window0[2] == "VBottom": window0[2] = [0, -1]
                            elif window0[2] == "VTop": window0[2] = [0, 1]
                            elif window0[2] == "Left": window0[2] = [-1, 0]
                            elif window0[2] == "Right": window0[2] = [1, 0]

                            text_window( ' '.join(cmd[2:]), pos, angle, align_vec=window0[2])

                    elif cmd[1] == "Value" and component_value:
                        if data3!=None:
                            data3 = ' '.join(cmd[2:])
                        else:
                            pos = [coord(window3[i]) for i in [0, 1]]
                            pos = rotate_vec(pos, angle)+coords

                            if window3[2] == "VBottom": window3[2] = [0, -1]
                            elif window3[2] == "VTop": window3[2] = [0, 1]
                            elif window3[2] == "Left": window3[2] = [-1, 0]
                            elif window3[2] == "Right": window3[2] = [1, 0]

                            text_window( ' '.join(cmd[2:]), pos, angle, align_vec=window3[2])

                elif cmd[0]=="WINDOW":
                    if cmd[1] == "0":
                        window0 = cmd[2:]
                        data0 = None
                    elif cmd[1] == "3":
                        window3 = cmd[2:]
                        data3 = None

                elif cmd[0] not in {"WINDOW"}:
                    break

            draw_symbol(symfile, coords, angle, data0, data3)

            # if "Voltage" in cmd[1]:

            #     print(f"({coords[0]},{coords[1]}) to [V,v<=$V_1$,rotate={angle}] ({coords[0]},{coords[1]})")

    tikz_add(";")

def post_process_circuit():

    global TIKZCODE

    for node, degree in node_degree.items():

        if degree > 1:

            draw_symbol("node.asy", node, 0, "", "")

def circ_to_latex(circuit, component_name=False, component_value=False, local_dir=".", entire_page=False):

    res = ""

    add_symbol("gnd.asy")
    add_symbol("node.asy")

    parse_circuit(circuit, component_name, component_value, local_dir)

    post_process_circuit()

    if entire_page: res += "\documentclass[tikz,border=5mm]{standalone}\n"
    res += TIKZSET
    if entire_page: res += "\n\\begin{document}"
    res += "\\begin{tikzpicture}[yscale = -1]\n"
    res += TIKZCODE
    res += "\n\end{tikzpicture}"
    if entire_page: res += "\end{document}"

    return res

def detect_encoding(file_path, expected_str: str = '') -> str:
    """
    Simple strategy to detect file encoding.  If an expected_str is given the function will scan through the possible
    encodings and return a match.
    If an expected string is not given, it will use the second character is null, high chances are that this file has an
    'utf_16_le' encoding, otherwise it is assuming that it is 'utf-8'.
    :param file_path: path to the filename
    :type file_path: str
    :param expected_str: text which the file should start with
    :type expected_str: str
    :return: detected encoding
    :rtype: str
    """
    for encoding in ('utf-8', 'utf-16-le', 'cp1252', 'cp1250', 'shift-jis'):
        try:
            with open(file_path, 'r', encoding=encoding) as f:
                lines = f.readlines()
                f.seek(0)
        except UnicodeDecodeError:
            # This encoding didn't work, let's try again
            continue
        else:
            if expected_str:
                if not expected_str in lines[0]:
                    # File did not start with expected string
                    # Try again with a different encoding (This is unlikely to resolve the issue)
                    continue
            if encoding == 'utf-8' and lines[0][1] == '\x00':
                continue
            return encoding
    else:
        raise UnicodeError("Unable to detect log file encoding")

def open_file(file):

    with open(file, "rb") as f:
        return decode_data(f.read()), os.path.dirname(os.path.realpath(file))

def decode_data(data):

    return data.decode(detect_encoding(sys.argv[1], "Version"))

    # data = data.replace(b'\x00', b'')

    try:
        circuit = data.decode('utf-16-le')
        print(circuit)
    except:
        try:
            circuit = data[1:].decode('utf-8')
        except:
            circuit = data[2:].decode('utf-8')

    return circuit

# def try_to_read(file):

if __name__=="__main__":

    try:
        import pyperclip
        clipboard = True
    except:
        clipboard = False
        print("If you want the result copied to your clipboard, run [pip install pyperclip]")

    circuit, dir = open_file(sys.argv[1])

    NO_COMMENTS_AND_COMMANDS = True

    res = circ_to_latex(circuit, component_name=False, component_value=False, local_dir=dir, entire_page=True)

    if clipboard:
        pyperclip.copy(res)
        print("latex code copied to clipboard")

    else:
        print("\n\n\n", res)


"""
Create by yy on 2020/2/16
"""
import json
from threading import RLock
from time import sleep

from tool_yy import debug, Thread, curl_data

lock = RLock()

class GetComic(Thread):
    def __init__(self, init_db):
        super().__init__()
        # self.table = "list_latest"
        self.table = "list"
        # self.comic_table = "comic_latest"
        self.comic_table = "comic"
        self.db = init_db("COMIC_DATABASE_CONFIG")

    def run(self):
        # self.get_page_list()
        # self.get_comic_data()
        self.get_comic_detail()

    def get_comic_detail(self):
        flag = True
        comic_list = self.get_comic_list_from_db()
        for item in comic_list:
            # if flag:
            #     if item["comic_id"] != 188:
            #         continue
            #     else:
            #         flag = False
            self.get_comic_data(item)
            debug("等待3秒再继续")
            sleep(2)
        # self.start_thread(comic_list, self.get_comic_data, max_worker=10, is_test=True)

    def get_comic_data(self, item):
        url = "https://fancuishou.xyz/home/api/chapter_list/tp/{id}-1-1-1000"
        debug("获取id为 ========> {id}的漫画".format(id=item["comic_id"]))
        url = url.format(id=item["comic_id"])
        debug(url)
        data = ""
        try:
            data = curl_data(url, open_virtual_ip=True)
        except Exception as e:
            debug("curl_data 获取数据失败{error}: ".format(error=e.__str__()))
        # with open("static/comic/single_list.json") as f:
        #     data = f.read()
        # with open("static/comic/single_list.json", "wb") as f:
        #     f.write(data.encode("utf-8"))
        if data == "":
            return self.get_comic_data(item)
        self.handle_comic_data(data)

    def handle_comic_data(self, data):
        try:
            data = json.loads(data)
        except Exception as e:
            debug(e)
        if not data["succ"]:
            debug("not succ")
            return
        debug("succ 获取成功 ====> ", data["succ"])
        try:
            chapter_list = data["result"]["list"]
        except Exception as e:
            debug(e)
            return
        for item in chapter_list:
            item["comic_id"] = item["id"]
            del item["cjid"]
            del item["id"]
            item["view"] = 0
            lock.acquire()
            sql = self.db.getInsertSql(item, self.comic_table)
            result = self.db.insert(sql, is_close_db=False)
            lock.release()
            if result == 0:
                debug("数据插入失败了")

    def get_page_list(self):
        url = "https://fancuishou.xyz/home/api/getpage/tp/1-newest-{page}"
        page = 1
        while True:
            data = self.get_page_list_data(page, url)
            page = page + 1
            # 这里判断一下数据是否为空，为空则停止
            result = self.handle_list(data)
            if result == 2:
                break

    def handle_list(self, data):
        try:
            data = json.loads(data)
        except Exception as e:
            debug("处理数据转为 dict 出错，错误信息 ============> {error}".format(error=e.__str__()))
            return 1
        try:
            if not data["succ"]:
                return 2
        except Exception as e:
            debug(e)
            return 1
        try:
            comic_list = data["result"]["list"]
        except Exception as e:
            debug("处理数据转获取 list 出错，错误信息 ============> {error}".format(error=e.__str__()))
            return 1
        for item in comic_list:
            insert_arr = dict()
            insert_arr["comic_id"] = item["id"]
            insert_arr["detail_json"] = json.dumps(item)
            self.insert_list(insert_arr)
        return 0

    def insert_list(self, insert_arr):
        lock.acquire()
        sql = self.db.getInsertSql(insert_arr, self.table)
        result = self.db.insert(sql, is_close_db=False)
        lock.release()
        return result

    def get_page_list_data(self, page, url):
        # with open('static/comic/data.json') as f:
        #     data = f.read()
        request_url = url.format(page=page)
        data = curl_data(request_url, open_virtual_ip=True)
        return data

    def get_comic_list_from_db(self):
        data = self.db.select({
            "table": self.table,
            "columns": ["comic_id"]
        }, is_close_db=False)
        return data


from starlette.testclient import TestClient

from fastapi_versioned import FastAPIVersioned

from .detectable_api import versions as detected_versions

def test_version_detection():
    api = FastAPIVersioned(title="Test API", versions=detected_versions)

    client = TestClient(api)
    for i in [1, 2]:
        prefix = f"0.0.{i}"
        response = client.get(f"/v{prefix}/test{i}")
        assert response.status_code == 200
        assert response.json() == {"version": prefix}


import collections
from typing import Optional

class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

def mergeTreesRecursive(root1, root2):
    if not root1:
        return root2
    if not root2:
        return root1

    root1.val += root2.val

    root1.left = mergeTreesRecursive(root1.left, root2.left)
    root1.right = mergeTreesRecursive(root1.right, root2.right)

    return root1
'''
root2       root1
    4           4
   / \         / \
  2   5       6   8
 / \         / \
1   3       1   2

'''

root2 = TreeNode(4)
root2.left = TreeNode(2)
root2.left.left = TreeNode(1)
root2.left.right = TreeNode(3)
root2.right = TreeNode(5)

root1 = TreeNode(1)
root1.left = TreeNode(2)
root1.right = TreeNode(3)
k = 1
mergeTreesRecursive(root1, root2)

def diameterOfBinaryTree(root: Optional[TreeNode]) -> int:
    def dfs(root):
        nonlocal diameter
        if not root:
            return 0

        left = dfs(root.left)
        right = dfs(root.right)

        diameter = max(diameter, left + right)

        return max(left, right) + 1

    diameter = 0

    dfs(root)

    return diameter

diameterOfBinaryTree(root2)

def kthSmallest(root: TreeNode, k: int) -> int:
    stack = []
    curr = root
    n = 0

    while curr or stack:
        while curr:
            stack.append(curr)
            curr = curr.left

        curr = stack.pop()
        print(curr.val)
        curr = curr.right

kthSmallest(root2, k=1)

def mergeTreesIterative(self, root1: Optional[TreeNode], root2: Optional[TreeNode]) -> Optional[TreeNode]:
    if root1 is None:
        return root2

    queue = [(root1, root2)]

    while len(queue):
        node1, node2 = queue.pop()
        if node1 is None or node2 is None:
            continue

        node1.val += node2.val

        if node1.left is None:
            node1.left = node2.left
            node2.left = None

        if node1.right is None:
            node1.right = node2.right
            node2.right = None

        queue.append((node1.left, node2.left))
        queue.append((node1.right, node2.right))

    return root1

def deepestLeavesSum(self, root: Optional[TreeNode]) -> int:
    # using BFS
    queue = collections.deque([root])
    ans = 0

    while queue:

        for i in range(len(queue)):

            node = queue.popleft()
            ans += node.val
            if node.left:
                queue.append(node.left)

            if node.right:
                queue.append(node.right)

        print(ans)

def partition(array, begin, end):
    pivot = begin

    for i in range(begin + 1, end + 1):

        if array[i] <= array[begin]:
            pivot += 1

            array[i], array[pivot] = array[pivot], array[i]

    array[pivot], array[begin] = array[begin], array[pivot]

    return pivot

def quicksort(array, begin, end):
    if begin >= end:
        return

    pivot = partition(array, begin, end)

    quicksort(array, begin, pivot - 1)

    quicksort(array, pivot + 1, end)

# added calling code

mylist = [8, 2, 17, 4, 12]

quicksort(mylist, 0, 4)


#!/usr/bin/env python
# Created at 2020/3/27
import torch
import torch.nn as nn

from Utils.torch_util import get_flat_params, set_flat_params

def sac_alpha_step(policy_net, q_net_1, q_net_2, alpha, q_net_target_1, q_net_target_2,
                   optimizer_policy, optimizer_q_net_1, optimizer_q_net_2, optimizer_a,
                   states, actions, rewards, next_states, masks, gamma, polyak, target_entropy,
                   update_target=False):
    rewards = rewards.unsqueeze(-1)
    masks = masks.unsqueeze(-1)

    """update qvalue net"""
    with torch.no_grad():
        next_actions, next_log_probs = policy_net.rsample(next_states)
        target_q_value = torch.min(
            q_net_target_1(next_states, next_actions),
            q_net_target_2(next_states, next_actions)
        ) - alpha * next_log_probs
        target_q_value = rewards + gamma * masks * target_q_value

    q_value_1 = q_net_1(states, actions)
    q_value_loss_1 = nn.MSELoss()(q_value_1, target_q_value)
    optimizer_q_net_1.zero_grad()
    q_value_loss_1.backward()
    optimizer_q_net_1.step()

    q_value_2 = q_net_2(states, actions)
    q_value_loss_2 = nn.MSELoss()(q_value_2, target_q_value)
    optimizer_q_net_2.zero_grad()
    q_value_loss_2.backward()
    optimizer_q_net_2.step()

    """update policy net"""
    new_actions, log_probs = policy_net.rsample(states)
    min_q = torch.min(
        q_net_1(states, new_actions),
        q_net_2(states, new_actions)
    )

    policy_loss = (alpha * log_probs - min_q).mean()
    optimizer_policy.zero_grad()
    policy_loss.backward()
    optimizer_policy.step()

    """update alpha"""
    alpha_loss = - alpha * (log_probs.detach() + target_entropy).mean()
    optimizer_a.zero_grad()
    alpha_loss.backward()
    optimizer_a.step()

    if update_target:
        """
        soft update target qvalue net
        """
        q_net_1_flat_params = get_flat_params(q_net_1)
        q_net_target_1_flat_params = get_flat_params(q_net_target_1)

        set_flat_params(q_net_target_1,
                        (1 - polyak) * q_net_1_flat_params + polyak * q_net_target_1_flat_params)

        q_net_2_flat_params = get_flat_params(q_net_2)
        q_net_target_2_flat_params = get_flat_params(q_net_target_2)

        set_flat_params(q_net_target_2,
                        (1 - polyak) * q_net_2_flat_params + polyak * q_net_target_2_flat_params)

    return {"q_value_loss_1": q_value_loss_1,
            "q_value_loss_2": q_value_loss_2,
            "policy_loss": policy_loss,
            "alpha_loss": alpha_loss
            }


import pytest
import json
from conftest import VALID_SERVER_PROVISIONS__RESPONSE_BODY, ADMIN_SERVER_DATA_URI

@pytest.mark.admin
def test_000_cleanup(admin_cleanup):

  admin_cleanup()

@pytest.mark.admin
def test_001_i_want_to_provision_two_uris_with_different_states_and_final_purge_on_admin_interface(admin_server_provision):

  # Provision
  admin_server_provision("purge_on_termination_test.provision.json", responseBodyRef=VALID_SERVER_PROVISIONS__RESPONSE_BODY)

@pytest.mark.server
def test_002_i_want_to_send_get_requests_for_provisioned_data_and_check_final_purge_on_traffic_interface(h2ac_traffic, h2ac_admin):

  # Send GET
  response = h2ac_traffic.get("/app/v1/foo/bar/1")
  responseBodyRef = { "foo":"bar-1-state-initial" }
  h2ac_traffic.assert_response__status_body_headers(response, 200, responseBodyRef)

  # Check that server data exists
  response = h2ac_admin.get(ADMIN_SERVER_DATA_URI)
  assert response["status"] == 200

  # Send GET again:
  response = h2ac_traffic.get("/app/v1/foo/bar/1")
  responseBodyRef = { "foo":"bar-1-state-final" }
  h2ac_traffic.assert_response__status_body_headers(response, 200, responseBodyRef)

  # Check that THERE IS NO server data
  response = h2ac_admin.get(ADMIN_SERVER_DATA_URI)
  assert response["status"] == 204

  # Send GET again to confirm rotation:
  response = h2ac_traffic.get("/app/v1/foo/bar/1")
  responseBodyRef = { "foo":"bar-1-state-initial" }
  h2ac_traffic.assert_response__status_body_headers(response, 200, responseBodyRef)

  # Check that server data exists again
  response = h2ac_admin.get(ADMIN_SERVER_DATA_URI)
  assert response["status"] == 200


import rsa
import base64

# 生成密钥
(pubkey, privkey) = rsa.newkeys(1024)

# 保存密钥
with open('public.pem', 'w+') as f:
    f.write(pubkey.save_pkcs1().decode())
with open('private.pem', 'w+') as f:
    f.write(privkey.save_pkcs1().decode())

# 私钥签名
def sign(message):
    with open('private.pem', 'r') as f:
        privkey = rsa.PrivateKey.load_pkcs1(f.read().encode())

        signature = rsa.sign(message.encode(), privkey, 'SHA-1')
        signature = base64.b64encode(signature)
        print("生成的签名:")
        print(signature)
        return signature

# 公钥验证
def Verify(message, signature):
    with open('public.pem', 'r') as f:
        pubkey = rsa.PublicKey.load_pkcs1(f.read().encode())
        signature = base64.b64decode(signature)

        v = rsa.verify(message.encode(), signature, pubkey)
        print("验签结果:")
        print(v)
        return v


import os
import django
from aiogram.utils.executor import start_webhook

from config.enviroments import WEBHOOK_URL, WEBHOOK_PATH, WEBAPP_HOST, PORT
from loader import bot, SSL_CERTIFICATE, sslContext
from src import filters

async def onStartup(dp):
    webhook_info = await bot.get_webhook_info()
    if webhook_info.url != WEBHOOK_URL:
        await bot.set_webhook(
            url=WEBHOOK_URL,
            certificate=SSL_CERTIFICATE
        )

    filters.setup(dp)

async def onShutdown(dp):
    await dp.storage.close()
    await dp.storage.wait_closed()

def setup_django():
    os.environ.setdefault(
        "DJANGO_SETTINGS_MODULE",
        "admin.settings"
    )
    os.environ.update({'DJANGO_ALLOW_ASYNC_UNSAFE': "true"})
    django.setup()

if __name__ == '__main__':
    setup_django()
    from src.handlers import dp
    start_webhook(
        dispatcher=dp,
        webhook_path=WEBHOOK_PATH,
        on_startup=onStartup,
        on_shutdown=onShutdown,
        skip_updates=True,
        host=WEBAPP_HOST,
        port=PORT,
        ssl_context=sslContext
    )


from skimage.io import imread
import os
from submissions import *
import json
import matplotlib.pyplot as plt
import re
import sys

# Return line plot markers for each submission

def get_color_and_marker(idx):

    if idx == 0:
        return ("b", "o")
    elif idx == 1:
        return ("g", "o")
    elif idx == 2:
        return ("r", "o")
    elif idx == 3:
        return ("c", "o")
    elif idx == 4:
        return ("m", "o")
    elif idx == 5:
        return ("y", "o")
    elif idx == 6:
        return ("b", "x")
    elif idx == 7:
        return ("g", "x")
    elif idx == 8:
        return ("r", "x")
    elif idx == 9:
        return ("c", "x")
    elif idx == 10:
        return ("m", "x")
    elif idx == 11:
        return ("y", "x")
    else:
        assert(0)

# Returns the error function (mean IoU for multiclass and binary) and the labels
# for each problem

def get_error_and_labels(results_type, raw_data_dir):

    if results_type == "BinarySegmentation":

        error_function = IntersectionOverUnionError()
        labels = [Label("Foreground", 255), Label("Background", 0)]

    elif results_type == "PartsSegmentation":

        with open(os.path.join(raw_data_dir, 'instrument_class_mapping.json')) as data_file:
            data = json.load(data_file)
            labels = [Label(d, data[d]) for d in data]
        error_function = MulticlassIntersectionOverUnionError(labels)

    elif results_type == "TypeSegmentation":

        with open(os.path.join(raw_data_dir, 'instrument_type_mapping.json')) as data_file:
            data = json.load(data_file)
            labels = [Label(d, data[d]) for d in data]
        error_function = MulticlassIntersectionOverUnionError(labels)

    return (error_function, labels)

# Process the submissions for each different challenge
# @param results_type The 'type' of the results from BinarySegmentation/PartsSegmentation/TypeSegmentation
# @param error_function The error function we use to process. From get_error_and_labels().

def process(results_type, error_function, data_dir):

    subs = [Submission("Seb Bodenstedt", "NCT", "Method 7", "SebBodenstedt", data_dir),
            Submission("Thomas Kurmann", "UB", "Method 8",
                       "ThomasKurmann", data_dir),
            Submission("Shiyun Zhou", "BIT", "Method 1",
                       "BIToptics", data_dir),
            Submission("Vladimir Iglovikov", "MIT", "Method 3",
                       "IglovikovShevts", data_dir),
            Submission("Houling Luo", "SIAT", "Method 2",
                       "HoulingLuo", data_dir),
            Submission("Luis Herrera", "UCL", "Method 4",
                       "LuisHerrera", data_dir),
            Submission("Nicola Reike", "TUM", "Method 5",
                       "NicolaReike", data_dir),
            Submission("Rahul Duggal", "Delhi", "Method 6",
                       "RahulDuggal", data_dir),
            Submission("Vincent Zhang", "UA", "Method 9",
                       "VincentZhang", data_dir),
            Submission("Yun Hsuan Su", "UW", "Method 10", "YunHsuanSu", data_dir)]

    NUM_GT_DIRS = 10
    ground_truth_dirs = ["instrument_dataset_{0}".format(
        i) for i in range(1, NUM_GT_DIRS+1)]

    # Iterate over all of the datasets
    # Load the ground truth frames for the dataset incrementally
    # For each submission, compute the results for this frame and add
    # then to a list of scores
    os.chdir(os.path.join(args.data, "processed_labels/instrument/"))
    cwd = os.getcwd()
    for dataset_dir in ground_truth_dirs:

        os.chdir(dataset_dir)
        print("[STATUS] Processing " + dataset_dir)

        for sub in subs:

            sub.dataset_results.append(DatasetResults(
                dataset_dir, len(os.listdir(".")), error_function))

        for frame in sorted(os.listdir(results_type), key=lambda x: re.findall(r'\d+', x)):

            ground_truth_image = imread(
                results_type + "/" + frame, as_gray=True)

            # check that if we skip the frame due to no ground truth pixels that we do this for all frames
            for sub in subs:
                submission_image = imread(os.path.join(
                    sub.dir, results_type, dataset_dir, frame), as_gray=True)
                if submission_image is None:
                    print("[WARNING] Image is not found : " +
                          os.path.join(sub.dir, results_type, dataset_dir, frame))
                    continue
                sub.dataset_results[-1].add_results_for_frame(
                    frame, ground_truth_image, submission_image)

        os.chdir(cwd)

    return subs

def generate_per_dataset_line(dataset_idx, submissions, title, results_dir):

    x_axis = np.array(submissions[0].get_dataset_results(
        dataset_idx).get_frame_numbers())

    plt.rcParams["figure.figsize"] = (50, 20)
    plt.rcParams.update({'font.size': 22})

    fig = plt.figure()

    for idx, submission in enumerate(submissions):
        line_color, line_marker = get_color_and_marker(idx)
        if not submission.get_dataset_results(dataset_idx).is_good():
            continue
        ious_with_Nones = submission.get_dataset_results(
            dataset_idx).get_per_frame_iou()
        ious_with_Nones = np.array(ious_with_Nones).astype(np.double)
        good_vals = np.isfinite(ious_with_Nones)
        plt.plot(x_axis[good_vals], ious_with_Nones[good_vals], label=submission.get_label_name(
        ), linestyle='-', marker=line_marker, color=line_color)

    ax = plt.gca()
    ax.set_title("{0} - Dataset {1}".format(title, dataset_idx+1))
    ax.set_xlabel('Frame No.')
    ax.set_ylabel('IOU')

    plt.legend()

    save_dir = os.path.join(results_dir, "dataset_" + str(dataset_idx+1))

    try:
        os.makedirs(save_dir)
    except:
        pass

    fig.savefig(save_dir + "/" + title.replace(" ", "_") + ".png")
    plt.close(fig)

def generate_plots(challenge, submissions, title, base_dir):

    print("[STATUS] Done loading. Generating plots")
    results_dir = os.path.join(
        base_dir, "results_FIXED/instrument/", title.replace(" ", "_"))
    try:
        os.makedirs(results_dir)
    except:
        pass

    # work out which entrants have submissions
    submissions_with_entries = []
    for submission in submissions:
        if submission.compute_scores_across_datasets():
            submissions_with_entries.append(submission)
        else:
            print("[WARNING] Excluding submission {} from challenge {}".format(
                submission.name, challenge))

    if len(submissions_with_entries) == 0:
        print("[WARNING] No submission with entries found for challenge {}".format(
            challenge))
        return

    with open(os.path.join(results_dir, "total_scores.txt"), "w") as f:

        for submission in submissions_with_entries:
            f.write("{0} : {1}\n".format(submission.name,
                                         submission.mean_iou_all_datasets))

        #f.write("\nConfusion Matrices\n")
        # for submission in submissions:
        #    f.write("{0} : \n{1}\n".format(submission.name, submission.total_confusion_matrix))

    with open(os.path.join(results_dir, "latex_table.tex"), "w") as l:

        l.write("\\begin{{table*}}\n\\centering\n\\begin{{tabular}}{{ l | {} c }}\n".format(
            "".join([" c |"] * (len(submissions)-1))))
        for submission in submissions_with_entries:
            l.write(" & {}".format(submission.institute))
        l.write(" \\\\\n\hline\n")

        for dset in range(submissions_with_entries[0].get_number_of_datasets()):
            l.write("Dataset {} ".format(dset))
            generate_per_dataset_line(
                dset, submissions_with_entries, title, results_dir)
            with open(os.path.join(results_dir, "dataset_" + str(dset+1), "scores.txt"), "w") as f:
                for submission in submissions_with_entries:
                    f.write("{0} : {1}\n".format(submission.name,
                                                 submission.mean_iou_per_dataset[dset]))
                    l.write(" & {0:.3f} ".format(
                        submission.mean_iou_per_dataset[dset]))
            l.write("\\\\\n")
            #f.write("\nConfusion Matrices\n")
            # for submission in submissions:
            #    f.write("{0} : \n{1}\n".format(submission.name, submission.confusion_matrix_per_dataset[dset]))
        l.write("\\end{tabular}\n")
        l.write(
            "\\caption{{\label{{fig:{}}} A caption...}}\n\\end{{table*}}\n".format(challenge))

def get_title_from_challenge(challenge):
    if challenge == "BinarySegmentation":
        return "Binary Segmentation"
    elif challenge == "PartsSegmentation":
        return "Parts-based Segmentation"
    elif challenge == "TypeSegmentation":
        return "Type Segmentation"
    else:
        assert(0)

if __name__ == '__main__':

    import argparse
    parser = argparse.ArgumentParser(
        description='Process MICCAI 2017 results.')
    parser.add_argument(
        'data', type=str, help='The directory where the data is stored.')

    args = parser.parse_args()

    raw_data_dir = os.path.join(args.data, "training_data/instrument/")

    if not os.path.exists(raw_data_dir):
        print("[ERROR] Unable to find data directories in {}".format(raw_data_dir))
        sys.exit(1)

    # Compute the binary segmentation results
    challenge = "BinarySegmentation"
    error_and_labels = get_error_and_labels(challenge, raw_data_dir)
    submissions = process(challenge, error_and_labels[0], args.data)
    generate_plots(challenge, submissions,
                   get_title_from_challenge(challenge), args.data)

    # Compute the parts-based segmentation results
    challenge = "PartsSegmentation"
    error_and_labels = get_error_and_labels(challenge, raw_data_dir)
    submissions = process(challenge, error_and_labels[0], args.data)
    generate_plots(challenge, submissions,
                   get_title_from_challenge(challenge), args.data)

    # Compute one-against-all results for each part
    for label in error_and_labels[1]:
        MulticlassIntersectionOverUnionError.switch_on_val(label)
        submissions = process(challenge, error_and_labels[0], args.data)
        generate_plots(challenge, submissions,
                       "{0} Part Segmentation".format(label.name), args.data)
        MulticlassIntersectionOverUnionError.reset_orig_vals()

    # Compute the type-based segmentation results
    challenge = "TypeSegmentation"
    error_and_labels = get_error_and_labels(challenge, raw_data_dir)
    submissions = process(challenge, error_and_labels[0], args.data)
    generate_plots(challenge, submissions,
                   get_title_from_challenge(challenge), args.data)

    # Compute one-against-all results for each type
    for label in error_and_labels[1]:
        MulticlassIntersectionOverUnionError.switch_on_val(label)
        submissions = process(challenge, error_and_labels[0], args.data)
        generate_plots(challenge, submissions,
                       "{0} Type Segmentation".format(label.name), args.data)
        MulticlassIntersectionOverUnionError.reset_orig_vals()


import requests
import threading

# python 里有一个 threading 模块，其中提供了一个函数：

# threading.Thread(target=function, args=(), kwargs={})

# function 是开发者定义的线程函数，
# args 是传递给线程函数的参数，必须是tuple类型，
# kwargs 是可选参数，字典类型。

# 调用 threading.Thread 之后，会创建一个新的线程，
# 参数 target 指定线程将要运行的函数，
# args 和 kwargs 则指定函数的参数来执行 function 函数。

# 改写一下前面抓取城市的天气的代码，将抓取的部分放在一个函数中：

def get_weather(city):
    req = requests.get('http://wthrcdn.etouch.cn/weather_mini?city=%s' % city)
    dic_city = req.json()

    city_data = dic_city.get('data')  # 没有’data‘的话返回 []
    print(city_data.get('city'))

    if city_data:
        city_forecast = city_data['forecast'][0]  # 下面的都可以换成'get'方法
        print('============================================================')
        print(
            city_data.get('city'),
            city_forecast.get('date'),
            city_forecast.get('high'),
            city_forecast.get('low'),
            city_forecast.get('type')
        )
        print('============================================================')
    else:
        print('未获得')
    # print()

# 之后，程序采用了三个循环，在第一个循环中，针对每一个城市，都创建了一个新线程，
# 并将线程加入到一个列表中，用于之后的启动。

threads = []
cities = ['北京', '南京', '上海', '深圳', '广州', '杭州', '苏州', '天津', '西安', '成都']
files = range(len(cities))
for i in files:  # 创建线程
    t = threading.Thread(target=get_weather, args=(cities[i],))
    threads.append(t)

# 在第二个循环中，start 正式开启子线程；
for i in files:
    threads[i].start()

# 在第三个循环中，join 用来同步数据，主线程运行到这一步，
# 将会停下来等待子线程运行完毕。
# 没有这句，主线程则会忽略子线程，运行完自己的代码后结束程序。
for i in files:
    threads[i].join()

print('结束获取天气资讯')

# 从输出结果可以看出：

# 在程序刚开始运行时，已经发送所有请求
# 收到的请求并不是按发送顺序，先收到就先显示
# 同样记录了所有10个城市的天气

# 所以，对于这种耗时长，但又独立的任务，使用多线程可以大大提高运行效率。
# 但在代码层面，可能额外需要做一些处理，保证结果正确。
# 如上例中，如果需要按输入列表城市顺序进行输出，就要另行排序。

# 多线程通常会用在网络收发数据、文件读写、用户交互等待之类的操作上，
# 以避免程序阻塞，提升用户体验或提高执行效率。

# 多线程的实现方法不止这一种。
# 另外多线程也会带来一些单线程程序中不会出现的问题。这里只是简单地开个头。

'''
# Reference:
https://www.cnblogs.com/xingchuxin/p/10433444.html

# Running Code:
cd /f/Github/xiangxing98.github.io/Python_Learning
python lesson72_multi_thread.py
'''


from time import time
from math import inf
from collections import deque, defaultdict
import unittest
a = time()

def readFile():
    # On renvoie le fichier d'entrée sous forme d'une liste de string
    with open(__file__[:-3] + "-" + "input.txt", "r") as f:
        return [i.strip().split('-') for i in f.readlines()]

def create_graph(scheme: list):
    graph = defaultdict(list)
    for elem in scheme:
        graph[elem[0]].append(elem[1])
        graph[elem[1]].append(elem[0])

    return graph

class Tree:
    def __init__(self, firstNode, graph, part):
        # Données du problème
        self.paths = 0
        self.part = part
        # Données relatives à l'arbre
        self.bestValue = inf
        self.openNodes = deque([firstNode])
        self.firstNode = firstNode
        self.graph = graph

    def expandTree(self):
        currentNode = self.openNodes.pop() # .pop() -> profondeur, .popleft() -> largeur
        if currentNode.cave == 'end':
            self.paths += 1
            if currentNode.value < self.bestValue: # Définir ici la condition de succès
                self.bestValue = currentNode.value
        else:
            for son in currentNode.reachableNodes(self.graph, self.part):
                self.openNodes.append(son)

class Node:
    def __init__(self, cave, path):
        self.cave = cave
        self.value = path.count('-')
        self.path = path # Définir ici comment qualifier un noeud avec un état unique

    def reachableNodes(self, graph, part):
        # Définir ici comment rechercher les prochains noeuds
        for reachable_cave in graph[self.cave]:
            if part == 1:
                if reachable_cave.upper() == reachable_cave or reachable_cave not in self.path:
                    yield Node(reachable_cave, f'{self.path}-{reachable_cave}')
            if part == 2:
                explored_small_caves = [elem for elem in self.path.split('-') if elem.lower() == elem and len(elem) == 2]
                if reachable_cave.upper() == reachable_cave or reachable_cave not in self.path:
                    yield Node(reachable_cave, f'{self.path}-{reachable_cave}')
                elif len(explored_small_caves) == len(set(explored_small_caves)) and len(reachable_cave) == 2:
                    yield Node(reachable_cave, f'{self.path}-{reachable_cave}')

class Tests(unittest.TestCase):

    def testP1(self):
        pass

def part1(scheme: str):
    graph = create_graph(scheme)
    firstNode = Node('start', 'start')
    tree = Tree(firstNode, graph, 1)
    comp = 0
    while tree.openNodes:
        tree.expandTree()
        comp += 1
    return tree.paths, comp

def part2(scheme: str):
    graph = create_graph(scheme)
    firstNode = Node('start', 'start')
    tree = Tree(firstNode, graph, 2)
    comp = 0
    while tree.openNodes:
        tree.expandTree()
        comp += 1
    return tree.paths, comp

if __name__ == "__main__":
    # unittest.main()
    scheme = readFile()
    p1 = part1(scheme)
    print(f"Part 1: {p1[0]} in {p1[1]} iterations")
    p2 = part2(scheme)
    print(f"Part 2: {p2[0]} in {p2[1]} iterations")
    # print(time()-a)


from __future__ import print_function

import io
import os
import sys

from setuptools import setup, find_packages
from setuptools_rust import Binding, RustExtension

packages = [p for p in find_packages() if "tests" not in p]

PACKAGE_NAME = "snips_nlu_parsers"
ROOT_PATH = os.path.dirname(os.path.abspath(__file__))
PACKAGE_PATH = os.path.join(ROOT_PATH, PACKAGE_NAME)
README = os.path.join(ROOT_PATH, "README.rst")
VERSION = "__version__"

RUST_EXTENSION_NAME = 'snips_nlu_parsers.dylib.libsnips_nlu_parsers_rs'
CARGO_ROOT_PATH = os.path.join(ROOT_PATH, 'ffi')
CARGO_FILE_PATH = os.path.join(CARGO_ROOT_PATH, 'Cargo.toml')
CARGO_TARGET_DIR = os.path.join(CARGO_ROOT_PATH, 'target')
os.environ['CARGO_TARGET_DIR'] = CARGO_TARGET_DIR

with io.open(os.path.join(PACKAGE_PATH, VERSION)) as f:
    version = f.readline()

with io.open(README, "rt", encoding="utf8") as f:
    readme = f.read()

required = [
    "future>=0.16,<0.18",
    "pathlib>=1.0,<2.0; python_version < '3.4'",
]

rust_extension = RustExtension(
    RUST_EXTENSION_NAME, CARGO_FILE_PATH, debug="develop" in sys.argv,
    args=["--verbose"] if "--verbose" in sys.argv else None,
    binding=Binding.NoBinding)

setup(name=PACKAGE_NAME,
      description="Python wrapper of the snips-nlu-parsers Rust crate",
      long_description=readme,
      version=version,
      license="Apache-2.0",
      author="Adrien Ball",
      author_email="adrien.ball@snips.ai",
      classifiers=[
          "Programming Language :: Python :: 3",
          "Programming Language :: Python :: 3.5",
          "Programming Language :: Python :: 3.6",
          "Programming Language :: Python :: 3.7",
      ],
      rust_extensions=[rust_extension],
      install_requires=required,
      packages=packages,
      include_package_data=True,
      zip_safe=False)


#!/usr/bin/env python

import os
import sys
import re
import click
import logging
from signal import signal, SIGPIPE, SIG_DFL
from ..helpers.file_helpers import return_filehandle, check_file_type
from ..helpers.sequence_helpers import get_seqio_fastx_record

signal(SIGPIPE, SIG_DFL)

def record_to_stdout(record, output_type, quality):
    '''Takes a record, the output_type and the quality and writes to stdout.

       The quality is assigned for fasta to fastq.
    '''
    if output_type == 'fasta':
        sys.stdout.write(record.format(output_type))  # can write normally
        sys.stdout.flush()
    elif output_type == 'fastq':
        length = len(record.seq)
        qualities = [quality] * length
        record.letter_annotations["solexa_quality"] = qualities
        sys.stdout.write(record.format(output_type))  # can write normally
        sys.stdout.flush()

def fastx_converter(input_file, input_type, output_type, quality):
    '''Convert input_file or stdin fasta to fastq or fastq to fasta

       based on input_type
    '''
    seqio_in = sys.stdin
    fh = ''
    if not input_file:  # Check STDIN
        for record in get_seqio_fastx_record(seqio_in, input_type):  # Generatea
            record_to_stdout(record, output_type, quality)
    else:  # Check file
        input_file = os.path.abspath(input_file)
        fh = return_filehandle(input_file)
        for record in get_seqio_fastx_record(fh, input_type):  # Generator
            record_to_stdout(record, output_type, quality)

@click.command()
@click.option('--input_file',
              help='''Input file, fasta or fastq, can be compressed''')
@click.option('--input_type', required=True,
              help='''Input file type.  fasta or fastq''')
@click.option('--output_quality', default=40,
   help='''Quality to assign if converting from fasta to fastq (default:40)''')
@click.option('--log_file', default='./fastx_converter.log',
             help='''File to write log to.  (default:./fastx_converter.log)''')
@click.option('--log_level', default='INFO',
    help='''Log level: DEBUG, INFO, WARNING, ERROR, CRITICAL (default:INFO)''')
def main(input_file, input_type, output_quality, log_file, log_level):
    '''Convert FASTA to FASTQ or FASTQ to FASTA

        cat input.[fa|fq] | fastx_converter.py --input_type <fasta/fastq>

        or

        fastx_converter.py --input input.[fa|fq] --input_type <fasta/fastq>
    '''
    log_level = getattr(logging, log_level.upper(), logging.INFO)
    msg_format = '%(asctime)s|%(name)s|[%(levelname)s]: %(message)s'
    logging.basicConfig(format=msg_format, datefmt='%m-%d %H:%M',
                        level=log_level)
    log_handler = logging.FileHandler(log_file, mode='w')
    formatter = logging.Formatter(msg_format)
    log_handler.setFormatter(formatter)
    logger = logging.getLogger('fastx_converter')
    logger.addHandler(log_handler)
    fasta_check = re.compile('fa|fasta|fna')
    fastq_check = re.compile('fq|fastq')
    output_type = ''
    if fastq_check.match(input_type):  # check input type set fastq
        input_type = 'fastq'
        output_type = 'fasta'
    elif fasta_check.match(input_type):  # check input type set fasta
        input_type = 'fasta'
        output_type = 'fastq'
    else:  # exit if not fasta or fastq
        logger.error('Input type: {} cannot be processed'.format(input_type))
        sys.exit(1)
    if input_file:
        input_type_check = check_file_type(input_file)
        if input_type_check != input_type:  # file doesnt look like input_type
            logger.error('Type mismatch, input_type:{}, file:{}'.format(
                                                             input_type,
                                                             input_type_check))
            sys.exit(1)
    fastx_converter(input_file, input_type, output_type, output_quality)

if __name__ == '__main__':
    main()