from time import sleep
from time import sleep
from tkinter import *
from tkinter import ttk
from PIL import ImageTk
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
from matplotlib.backends.backend_tkagg import (
    FigureCanvasTkAgg, NavigationToolbar2Tk)
from matplotlib.figure import Figure
from window_utilities import window_utils
import serial
from scipy.ndimage import gaussian_filter1d

class PAYLOAD_PLOT_SCREEN:
    def __init__(self, SCREEN,serial_device):
        # self.ser = serial.Serial('COM7', 9600)
        self.ser = serial_device
        self.start_plotting = False
        self.temperature_c = self.temperature_f = self.humidity = self.heat_index_c = self.heat_index_f = self.uv_index = self.uv_sensor_voltage = np.array([
        ])
        # ser=serial.Serial('COM7',9600)
        # ser.reset_input_buffer()
        ## print(id(serial_device))
        # self.temperature_c = temperature_c.to_numpy()

        def update_plot():
            try:
                # while self.ser.in_waiting:
                data = self.ser.readline()
                data = data.decode()
                data = data.strip('\r\n')
                data = data.split(',')
                for i in range(len(data)):
                    data[i] = float(data[i])
                #print(data)
                self.humidity = np.append(self.humidity, data[0])
                self.temperature_c = np.append(
                    self.temperature_c, data[1])
                self.temperature_f = np.append(
                    self.temperature_f, data[2])
                self.heat_index_c = np.append(
                    self.heat_index_c, data[3])
                self.heat_index_f = np.append(
                    self.heat_index_f, data[4])
                self.uv_index = np.append(self.uv_index, data[5])
                self.uv_sensor_voltage = np.append(
                    self.uv_sensor_voltage, data[6])

                lines1.set_xdata(np.linspace(
                    0, len(self.humidity), len(self.humidity)))
                lines1.set_ydata(gaussian_filter1d(self.humidity, sigma=2))

                lines2.set_xdata(np.linspace(
                    0, len(self.temperature_c), len(self.temperature_c)))
                lines2.set_ydata(gaussian_filter1d(
                    self.temperature_c, sigma=2))

                lines3.set_xdata(np.linspace(
                    0, len(self.temperature_f), len(self.temperature_f)))
                lines3.set_ydata(gaussian_filter1d(
                    self.temperature_f, sigma=2))

                lines4.set_xdata(np.linspace(
                    0, len(self.heat_index_c), len(self.heat_index_c)))
                lines4.set_ydata(gaussian_filter1d(self.heat_index_c, sigma=2))

                lines5.set_xdata(np.linspace(
                    0, len(self.heat_index_f), len(self.heat_index_f)))
                lines5.set_ydata(gaussian_filter1d(self.heat_index_f, sigma=2))

                lines6.set_xdata(np.linspace(
                    0, len(self.uv_index), len(self.uv_index)))
                lines6.set_ydata(gaussian_filter1d(self.uv_index, sigma=2))

                lines7.set_xdata(np.linspace(
                    0, len(self.uv_sensor_voltage), len(self.uv_sensor_voltage)))
                lines7.set_ydata(gaussian_filter1d(
                    self.uv_sensor_voltage, sigma=2))

                update_plots_axes()
                ## print(temperature_c.tolist().append(10))
                # lines.set_xdata(float(serial_data.strip()))
                ## print(type(temperature_c))
                canvas1.draw()
                #print('update plot evoked')
                pass
            except Exception as e:
                #print('error updating plot')
                #print(e)
                pass
            self.real_time_plot_monitor=SCREEN.after(1000, update_plot)

        # data, temperature_c, temperature_f, humidity, heat_index_c, heat_index_f = pd.Series(np.array(np.zeros(1))),pd.Series(np.array(np.zeros(1))),pd.Series(np.array(np.zeros(1))),pd.Series(np.array(np.zeros(1))),pd.Series(np.array(np.zeros(1))),pd.Series(np.array(np.zeros(1)))

        def start_plotting():
            self.real_time_plot_monitor= SCREEN.after(1000, update_plot)
            # update_plot()
            start_plotting_btn['state'] = 'disabled'
            stop_plotting_btn['state'] = 'normal'
            pass

        def stop_plotting():
            SCREEN.after_cancel(self.real_time_plot_monitor)
            start_plotting_btn['state'] = 'normal'
            stop_plotting_btn['state'] = 'disabled'
            pass
        START_STOP_BTN_FRAME = window_utils.create_frame(SCREEN)
        start_plotting_btn = Button(
            START_STOP_BTN_FRAME, text='START PLOTTING', borderwidth=1, command=start_plotting)
        start_plotting_btn.pack(side=LEFT, anchor=CENTER, padx=10)
        stop_plotting_btn = Button(START_STOP_BTN_FRAME, text='STOP PLOTTING',command=stop_plotting)
        stop_plotting_btn.pack(side=LEFT, anchor=CENTER, padx=10)

        def update_plots_axes():
            xlim_start = 0
            if len(self.humidity) > 60:
                xlim_start = len(self.humidity)-60
            xlim_end = len(self.humidity)
            fig1.set_xlim(xlim_start, xlim_end)
            fig1.set_ylim(self.humidity.min()-5, self.humidity.max()+5)

            xlim_start = 0
            if len(self.temperature_c) > 60:
                xlim_start = len(self.temperature_c)-60
            xlim_end = len(self.temperature_c)
            fig2.set_xlim(xlim_start, xlim_end)
            fig2.set_ylim(self.temperature_c.min()-5,
                          self.temperature_c.max()+5)

            xlim_start = 0
            if len(self.temperature_f) > 60:
                xlim_start = len(self.temperature_f)-60
            xlim_end = len(self.temperature_f)
            fig3.set_xlim(xlim_start, xlim_end)
            fig3.set_ylim(self.temperature_f.min()-5,
                          self.temperature_f.max()+5)

            xlim_start = 0
            if len(self.heat_index_c) > 60:
                xlim_start = len(self.heat_index_c)-60
            xlim_end = len(self.heat_index_c)
            fig4.set_xlim(xlim_start, xlim_end)
            fig4.set_ylim(self.heat_index_c.min()-5, self.heat_index_c.max()+5)

            xlim_start = 0
            if len(self.heat_index_f) > 60:
                xlim_start = len(self.heat_index_f)-60
            xlim_end = len(self.heat_index_f)
            fig5.set_xlim(xlim_start, xlim_end)
            fig5.set_ylim(self.heat_index_f.min()-5, self.heat_index_f.max()+5)

            xlim_start = 0
            if len(self.uv_index) > 60:
                xlim_start = len(self.uv_index)-60
            xlim_end = len(self.uv_index)
            fig6.set_xlim(xlim_start, xlim_end)
            fig6.set_ylim(self.uv_index.min()-5, self.uv_index.max()+5)

            xlim_start = 0
            if len(self.uv_sensor_voltage) > 60:
                xlim_start = len(self.uv_sensor_voltage)-60
            xlim_end = len(self.uv_sensor_voltage)
            fig7.set_xlim(xlim_start, xlim_end)
            fig7.set_ylim(self.uv_sensor_voltage.min()-5,
                          self.uv_sensor_voltage.max()+5)
            pass
        figure = plt.figure(figsize=(20, 8))
        # humidity
        fig1 = figure.add_subplot(331)
        # fig1.plot(self.humidity)
        fig1.set_xlabel('Time (s)', fontsize=int(
            SCREEN.winfo_screenheight()/80))
        fig1.set_ylabel('Humidity (%)', fontsize=int(
            SCREEN.winfo_screenheight()/80))
        # xlim_start = len(self.temperature_c)-100
        # if xlim_start < 0:
        #     xlim_start = 0
        # xlim_end = int(len(self.temperature_c))
        # ylim_start = 0
        # ylim_end = max(self.temperature_c)
        # fig1.set_xlim(xlim_start, xlim_end)
        # fig1.set_ylim(ylim_start, ylim_end+5)
        lines1 = fig1.plot([], [])[0]

        # temperature_c
        fig2 = figure.add_subplot(332)
        # fig2.plot(self.humidity)
        fig2.set_xlabel('Time (s)', fontsize=int(
            SCREEN.winfo_screenheight()/80))
        fig2.set_ylabel('Temperature (°C)', fontsize=int(
            SCREEN.winfo_screenheight()/80))
        # xlim_start = len(self.humidity)-100
        # if xlim_start < 0:
        #     xlim_start = 0
        # xlim_end = int(len(self.humidity))
        # ylim_start = 0
        # ylim_end = self.humidity.max()
        # fig2.set_xlim(xlim_start, xlim_end)
        # fig2.set_ylim(ylim_start, ylim_end+5)
        lines2 = fig2.plot([], [])[0]

        # temperature_f
        fig3 = figure.add_subplot(333)
        # fig3.plot(self.heat_index_c)
        fig3.set_xlabel('Time (s)', fontsize=int(
            SCREEN.winfo_screenheight()/80))
        fig3.set_ylabel('Temperature (°F)', fontsize=int(
            SCREEN.winfo_screenheight()/80))
        # xlim_start = len(self.heat_index_c)-100
        # if xlim_start < 0:
        #     xlim_start = 0
        # xlim_end = int(len(self.heat_index_c))
        # ylim_start = 0
        # ylim_end = self.heat_index_c.max()
        # fig3.set_xlim(xlim_start, xlim_end)
        # fig3.set_ylim(ylim_start, ylim_end+5)
        lines3 = fig3.plot([], [])[0]

        # heat_index_c
        fig4 = figure.add_subplot(334)
        # fig4.plot(self.temperature_f)
        fig4.set_xlabel('Time (s)', fontsize=int(
            SCREEN.winfo_screenheight()/80))
        fig4.set_ylabel('Heat Index (°C)', fontsize=int(
            SCREEN.winfo_screenheight()/80))
        # xlim_start = len(self.temperature_f)-100
        # if xlim_start < 0:
        #     xlim_start = 0
        # xlim_end = int(len(self.temperature_f))
        # ylim_start = 0
        # ylim_end = self.temperature_f.max()
        # fig4.set_xlim(xlim_start, xlim_end)
        # fig4.set_ylim(ylim_start, ylim_end+10)
        lines4 = fig4.plot([], [])[0]

        # heat_index_f
        fig5 = figure.add_subplot(335)
        # fig5.plot(self.heat_index_f)
        fig5.set_xlabel('Time (s)', fontsize=int(
            SCREEN.winfo_screenheight()/80))
        fig5.set_ylabel('Heat Index (°F)', fontsize=int(
            SCREEN.winfo_screenheight()/80))
        # xlim_start = len(self.heat_index_f)-100
        # if xlim_start < 0:
        #     xlim_start = 0
        # xlim_end = int(len(self.heat_index_f))
        # ylim_start = 0
        # ylim_end = self.heat_index_f.max()
        # fig5.set_xlim(xlim_start, xlim_end)
        # fig5.set_ylim(ylim_start, ylim_end+5)
        lines5 = fig5.plot([], [])[0]

        # uv index
        fig6 = figure.add_subplot(336)
        # fig5.plot(self.heat_index_f)
        fig6.set_xlabel('Time (s)', fontsize=int(
            SCREEN.winfo_screenheight()/80))
        fig6.set_ylabel('UV Index', fontsize=int(
            SCREEN.winfo_screenheight()/80))
        # xlim_start = len(self.heat_index_f)-100
        # if xlim_start < 0:
        #     xlim_start = 0
        # xlim_end = int(len(self.heat_index_f))
        # ylim_start = 0
        # ylim_end = self.heat_index_f.max()
        # fig5.set_xlim(xlim_start, xlim_end)
        # fig5.set_ylim(ylim_start, ylim_end+5)
        lines6 = fig6.plot([], [])[0]

        fig7 = figure.add_subplot(337)
        # fig5.plot(self.heat_index_f)
        fig7.set_xlabel('Time (s)', fontsize=int(
            SCREEN.winfo_screenheight()/80))
        fig7.set_ylabel('UV Sensor Voltage', fontsize=int(
            SCREEN.winfo_screenheight()/80))
        # xlim_start = len(self.heat_index_f)-100
        # if xlim_start < 0:
        #     xlim_start = 0
        # xlim_end = int(len(self.heat_index_f))
        # ylim_start = 0
        # ylim_end = self.heat_index_f.max()
        # fig5.set_xlim(xlim_start, xlim_end)
        # fig5.set_ylim(ylim_start, ylim_end+5)
        lines7 = fig7.plot([], [])[0]

        figure.tight_layout()

        canvas1 = FigureCanvasTkAgg(figure, master=SCREEN)
        canvas1.get_tk_widget().pack(anchor=CENTER, side=TOP)
        canvas1.draw()
        toolbar = NavigationToolbar2Tk(canvas1, SCREEN)
        toolbar.config(bg='')
        toolbar.update()


# www.acmicpc.net/problem/12886
# 백준 12886번 문제: 돌 그룹
from collections import deque
import sys
input = sys.stdin.readline

graph = list(map(int, input().split()))

result = (graph[0] + graph[1] + graph[2]) / 3
visited = [[False for _ in range(1501)] for _ in range(1501)]

dx = [-2, -1, 1, 2]

def bfs():

  queue = deque()

  queue.append(0)

  while queue:

    x = queue.popleft()

    for i in range(4):

      nx = x + dx[i]

      if 0 <= nx < len(graph) and visited[graph[x]][graph[nx]] == False:

        if graph[nx] > graph[x]:

          visited[graph[x]][graph[nx]] = True
          graph[nx] -= graph[x]
          graph[x] += graph[x]
          queue.append(nx)

        elif graph[nx] < graph[x]:

          visited[graph[x]][graph[nx]] = True
          graph[x] -= graph[nx]
          graph[nx] += graph[nx]
          queue.append(nx)

    if graph[0] == result and graph[1] == result and graph[2] == result:
      return 1

if bfs() == 1:
  print(1)
else:
  print(0)


# Day 28 - Type Hinting

# The benefits of type hinting:
# 1.It makes it easier to understand our code, because our helpful variable names are now accompanied by a description
# of the sort of data we expect to be assigned to them.
# 2.Most modern editors are able to make good use of our type annotations to provide more meaningful hints when we do
# things like calling functions.
# 3. We can use tools like mypy to check that our type annotations are being honoured, helping us catch bugs caused by
# passing around incorrect types.

# Installing mypy : python -m pip install mypy

# from typing import Union
#
# name: str = "Phil"
# age: int = 29
# height_metres: Union[int, float] = 1.87

# from typing import Any
#
# name: str = "Phil"
# age: int = 29
# height_metres: Any = 1.87

# from typing import List

# names: List[str]  =  ["Rick", "Morty", "Summer", "Beth", "Jerry"]

# from typing import List, Union
#
# random_values: List[Union[str, int]] =  ["x", 13, "camel", 0]

# from typing import Tuple
#
# movie: Tuple[str, str, int] = ("Toy Story 3", "Lee Unkrich", 2010)

# In Python 3.9 we won't have to import things like Tuple, List, and Dict from the typing module.
# Instead, we'll be able to use the standard tuple, list, and dict types for annotation.

# from typing import List, Tuple
#
# movies: List[Tuple[str, str, int]] = [
#     ("Finding Nemo", "Andrew Stanton", 2005),
#     ("Inside Out", "Pete Docter", 2015),
#     ("Toy Story 3", "Lee Unkrich", 2010)
# ]

# from typing import List, Tuple
#
# Movie = Tuple[str, str, int]
#
# movies: List[Movie] = [
#     ("Finding Nemo", "Andrew Stanton", 2005),
#     ("Inside Out", "Pete Docter", 2015),
#     ("Toy Story 3", "Lee Unkrich", 2010)
# ]

from typing import List, Tuple, Union

Movie = Tuple[str, str, int]

def find_movie(search_term: str, movies: List[Movie]):
    for title, director, year in movies:
        if title == search_term:
            return (title, director, year)

def show_movies(movies: List[Movie]):
    for movie in movies:
        print_movie(movie)

def print_movie(movie: Movie):
    title, director, year = movie
    print(f"{title} ({year}), by {director}")

movies: List[Movie] = [
    ("Finding Nemo", "Andrew Stanton", 2005),
    ("Inside Out", "Pete Docter", 2015),
    ("Toy Story 3", "Lee Unkrich", 2010)
]

show_movies(movies)

search_result: Union[Movie, None] = find_movie("Finding Nemo", movies)

if search_result:
    print_movie(search_result)
else:
    print("Couldn't find movie.")

"""Exercises
There's only one exercise today, because it's a big one. Take your final solution to the day 14 project
(easy or hard version) and implement type hinting for your code.

If you're unsure of how to do something, remember that you can always look at the typing module documentation."""


from urllib.request import urlopen

import re
from bs4 import BeautifulSoup

from com.sis001.Tool import Tool

class DetailPage:
    def __init__(self, bs_obj, folder_path):
        self.bsObj = bs_obj
        self.folderPath = folder_path
        self.resourceName = ""
        self.torrentName = ""

    def get_title(self):
        try:
            title = self.bsObj.find("td", {"class": "postcontent"}).find("div", {"class": "postmessage defaultpost"}).find("h2").text
        except:
            print("出现异常")
            title = ""
        self.resourceName = re.sub("[\s+\.\!\/_,$%^*(+\"\']+|[+——！，。？、~@#￥%……&*（）]+", "", title)
        return title

    def get_filtered_title(self):
        title = self.get_title()
        return re.sub("[\s+\.\!\/_,$%^*(+\"\']+|[+——！，。？、~@#￥%……&*（）]+", "", title)

    def get_image_url(self):
        image_url_list = []
        try:
            tag_list = self.bsObj.find("td", {"class": "postcontent"}).find("div", {"class": "postmessage defaultpost"}).find("div", {"class": "t_msgfont"})
        except:
            print("出现异常")
            tag_list = []
        if tag_list:
            for child in tag_list:
                if child.name == "img" and child["src"].startswith("http"):
                    image_url_list.append(child["src"])
        return image_url_list

    def get_torrent_url(self):
        try:
            torrent_tag = self.bsObj.find("dl", {"class", "t_attachlist"}).find("dt").find("a", {"style": None})
            self.torrentName = torrent_tag.text
        except:
            print("出现异常")
        if self.torrentName == "":
            return None
        else:
            return "http://162.252.9.10/forum/"+torrent_tag["href"]

    def save_resource(self):
        print("保存------------------------------------"+self.get_title()+"--------------------------------------")
        image_url_list = self.get_image_url()
        torrent_url = self.get_torrent_url()
        print("链接获取完成")
        Tool.save_image(image_url_list, self.folderPath + self.resourceName + "\\", self.resourceName, {"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0) Gecko/20100101 Firefox/23.0"})
        #Tool.save_attachment(torrent_url, self.folderPath + self.resourceName + "\\", self.torrentName, {"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0) Gecko/20100101 Firefox/23.0"})

if __name__ == "__main__":
    headers = {"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0) Gecko/20100101 Firefox/23.0"}
    prePath = "D:\\_developTool\\SuperCrawler\\resource\\"
    url = "http://38.103.161.140/forum/viewthread.php?tid=10065101&extra=page%3D1%26amp%3Bfilter%3Dtype%26amp%3Btypeid%3D1255"
    html = urlopen(url)
    bsObj = BeautifulSoup(html, "html.parser")
    detailPage = DetailPage(bsObj, prePath)
    #print(detailPage.get_title())
    #print(detailPage.resourceName)
    print(detailPage.get_image_url())
    print(detailPage.get_torrent_url())
    #print(detailPage.torrentName)
    detailPage.save_resource()


from node import Node
from enums import *
import config

class SplitNode(Node):
    """Node of the tree

    Contains two children, which can be nodes or children.
    PlaneType defines whether the node is split horizontally or vertically
    """

    def __init__(self, **kwargs):
        Node.__init__(self, 2)

        self.plane_type = kwargs.get('plane_type', PLANE.HORIZONTAL)
        self.split_ratio = kwargs.get('split_ratio', 0.5)

    # --------------------------------------------------------------------------
    # Getters
    # --------------------------------------------------------------------------

    def get_plane_type(self):
        return self.plane_type

    def get_split_coordinate(self):
        ((_, _), (x_size, y_size)) = self.parent.get_viewport(self)

        if self.get_plane_type() == PLANE.HORIZONTAL:
            split_coordinate = int(y_size * self.get_split_ratio())
        elif self.get_plane_type() == PLANE.VERTICAL:
            split_coordinate = int(x_size * self.get_split_ratio())
        else:
            raise Exception("Invalid plane")

        return split_coordinate

    def get_split_ratio_from_split_coordinate(self, split_coordinate):
        ((_, _), (x_size, y_size)) = self.parent.get_viewport(self)

        if self.get_plane_type() == PLANE.HORIZONTAL:
            split_ratio = float(split_coordinate) / float(y_size)
        elif self.get_plane_type() == PLANE.VERTICAL:
            split_ratio = float(split_coordinate) / float(x_size)
        else:
            raise Exception("Invalid plane")

        return split_ratio

    def get_split_ratio(self):
        return self.split_ratio

    # --------------------------------------------------------------------------
    # Setters
    # --------------------------------------------------------------------------

    def set_plane_type(self, new_plane_type):
        self.plane_type = new_plane_type

    def set_split_ratio(self, new_split_ratio):
        self.split_ratio = new_split_ratio

    def alter_split_coordinate(self, increment):
        new_split_coordinate = self.get_split_coordinate() + increment
        new_split_ratio = self.get_split_ratio_from_split_coordinate(
            new_split_coordinate)
        self.set_split_ratio(new_split_ratio)

    # --------------------------------------------------------------------------
    # Trickle downs
    # --------------------------------------------------------------------------

    def to_json(self):
        json = Node.to_json(self)
        json['type'] = 'split_node'
        json['plane_type'] = self.get_plane_type()
        json['split_ratio'] = self.get_split_ratio()

        return json

    def get_layout_json(self):
        json = Node.get_layout_json(self)
        json['type'] = 'split_node'
        json['plane_type'] = self.get_plane_type()
        json['split_ratio'] = self.get_split_ratio()

        return json

    def restore_splits(self):
        self.set_split_ratio(self.get_split_ratio())
        [c.restore_splits() for c in self.get_children()]

    def set_regular_state(self, state=WINDOW_STATE.NORMAL):
        [win.set_regular_state(state) for win in self.get_children()]

    # --------------------------------------------------------------------------
    # Bubble ups
    # --------------------------------------------------------------------------

    def get_split_node(self):
        return self

    def get_smallest_immutable_subtree(self, calling_child):
        return calling_child

    # --------------------------------------------------------------------------
    # Child Requests
    # --------------------------------------------------------------------------

    def get_viewports(self):
        """
        Horizontal Split

                 x size
               |-----------|

        (x, y) +-----------+  -        -
               |           |  |        |
               |           |  | y      | split
               +-----------+  | size   -
               |           |  |
               |           |  |
               +-----------+  -

        Vertical Split

                 x size
               |-----------|

        (x, y) +-----+-----+  -
               |     |     |  |
               |     |     |  | y
               |     |     |  | size
               |     |     |  |
               |     |     |  |
               +-----+-----+  -

               |-----|
                split
        """
        (x_pos, y_pos), (x_size, y_size) = self.parent.get_viewport(self)
        split = self.get_split_coordinate()

        if self.get_plane_type() == PLANE.HORIZONTAL:
            x_pos_1 = x_pos
            y_pos_1 = y_pos
            x_size_1 = x_size
            y_size_1 = split

            x_pos_2 = x_pos
            y_pos_2 = y_pos + split
            x_size_2 = x_size
            y_size_2 = y_size - split

            # Gap correction
            y_size_1 -= config.get_config('gap') / 2

            y_pos_2 += config.get_config('gap') / 2
            y_size_2 -= config.get_config('gap') / 2

        elif self.get_plane_type() == PLANE.VERTICAL:
            x_pos_1 = x_pos
            y_pos_1 = y_pos
            x_size_1 = split
            y_size_1 = y_size

            x_pos_2 = x_pos + split
            y_pos_2 = y_pos
            x_size_2 = x_size - split
            y_size_2 = y_size

            # Gap correction
            x_size_1 -= config.get_config('gap') / 2

            x_pos_2 += config.get_config('gap') / 2
            x_size_2 -= config.get_config('gap') / 2
        else:
            raise Exception("Invalid plane")

        viewport_1 = ((x_pos_1, y_pos_1), (x_size_1, y_size_1))
        viewport_2 = ((x_pos_2, y_pos_2), (x_size_2, y_size_2))
        return [viewport_1, viewport_2]

    def get_viewport(self, calling_child):
        index = self.get_child_index(calling_child)
        return self.get_viewports()[index]

    def change_plane(self):
        if self.get_plane_type() == PLANE.HORIZONTAL:
            self.set_plane_type(PLANE.VERTICAL)
        else:
            self.set_plane_type(PLANE.HORIZONTAL)

        self.set_split_ratio(0.5)
        self.restore_splits()
        self.redraw()

    # --------------------------------------------------------------------------
    # Other
    # --------------------------------------------------------------------------

    def resize(self, child, plane_type, increment):
        if self.get_plane_type() != plane_type:
            self.parent.resize(self, plane_type, increment)
            return

        if self.get_child_index(child) == 1:
            increment *= -1
        self.alter_split_coordinate(increment)
        self.redraw()

    # TODO: Refactor name
    def all_are_bees(self, caller_child):
        """If the calling child is 'ChildB', ripple the call up to check if THIS
        caller is also 'ChildB'
        Returns True if the entire call stack up to the screen are all
        'ChildB's.

        Returns False if any along the call stack are 'ChildA'
        """
        if self.get_child_index(caller_child) == 1:
            return self.parent.all_are_bees(self)
        return False

    # TODO: Refactor name
    def find_earliest_a_but_not_me(self, caller_child):
        """Returns the earliest (deepest in the tree, but above the caller)
        'ChildA' that is not part of the call stack
        """
        if self.get_child_index(caller_child) == 0:
            return self.parent.find_earliest_a_but_not_me(self)
        return self.get_child(0)


import torch
import numpy as np
from torchsummary import summary

depthwise_conv = torch.nn.Conv2d(3, 3, (3, 3), padding="same", groups=3)
pointwise_conv = torch.nn.Conv2d(3, 16, (1, 1))

depthwise_separable_conv = torch.nn.Sequential(depthwise_conv, pointwise_conv).cuda()

input = torch.randn(3, 224, 224).cuda()

output = pointwise_conv(input)

summary(model=depthwise_separable_conv, input_size=(3, 224, 224))
print(output.shape)


import numpy as np
import glob
import matplotlib.pyplot as plt
import cv2 as cv
import time
import  os

def fill_and_delete(label):
    gray_label = label[:,:,0].copy()
    # print(np.unique(gray_label))
    res1=cv.findContours(gray_label,mode=cv.RETR_EXTERNAL,method=cv.CHAIN_APPROX_NONE)
    contours,idx1=res1
    # print(len(contours))

    for i in range(len(contours)):
        area=cv.contourArea(contours[i])
        cv.fillPoly(gray_label,[contours[i]],(255,255,255))
        '''
        填补空洞
        '''
        if area<=1000:
            # print('正在填充面积小于100的区域')
            cv.drawContours(gray_label,contours,i,0,cv.FILLED)
            continue

    res1=cv.findContours(gray_label,mode=cv.RETR_EXTERNAL,method=cv.CHAIN_APPROX_NONE)
    contours1,idx1=res1
    # print(len(contours1))
    plt.imshow(gray_label)
    cv.imwrite('gray.png',gray_label)
    return gray_label,contours1

def dilate_process(h, w, contours, kernel, iter_time):
    result = []
    for j in range(len(contours)):
        cur_img = np.zeros((h, w), dtype=np.uint8)
        #         print(len(contours))
        cv.drawContours(cur_img, contours, j, 255, cv.FILLED)
        dilate1 = cv.dilate(cur_img, kernel, iterations=iter_time)
        res = cv.findContours(dilate1, mode=cv.RETR_EXTERNAL, method=cv.CHAIN_APPROX_NONE)
        if len(res) == 2:
            contours1, _ = res
        else:
            _, contours1, _ = res
        result.append(contours1[0])
    #     print('膨胀阶段')
    return result

def fill_small_target(img, contours):
    fill_flag = False
    for i in range(len(contours)):
        area = cv.contourArea(contours[i])
        cv.fillPoly(img, [contours[i]], (255, 255, 255))
        if area <= 500:
            fill_flag = True
            #             print('正在填充腐蚀之后面积小于1000的区域')
            cv.drawContours(img, contours, i, 0, cv.FILLED)
            continue
    return img, fill_flag

def erode_process(img, kernel_size, iteration):
    erode = img.copy()
    kernel = np.ones((1, kernel_size), np.uint8)
    erosion1 = cv.erode(erode, kernel, iterations=iteration)
    contours1, _ = cv.findContours(erosion1, mode=cv.RETR_EXTERNAL, method=cv.CHAIN_APPROX_NONE)
    if len(contours1) == 1:
        #         print('此处没有发生水平方向的重叠')
        return None
    else:
        #         print('此物体发生了水平方向的重叠')
        erosion1, flag = fill_small_target(erosion1, contours1)
        if not flag:
            #             print('没有可以填充的小物体存在')
            h, w = img.shape
            cnt = dilate_process(h, w, contours1, kernel, iteration)
            return cnt
        else:
            contours1, _ = cv.findContours(erosion1, mode=cv.RETR_EXTERNAL, method=cv.CHAIN_APPROX_NONE)
            if len(contours1) == 0:
                return False
            h, w = img.shape
            cnt = dilate_process(h, w, contours1, kernel, iteration)
            return cnt

def erode_process1(img, kernel_size, iteration):
    erode = img.copy()
    kernel = np.ones((kernel_size, 1), np.uint8)
    erosion1 = cv.erode(erode, kernel, iterations=iteration)
    contours1, _ = cv.findContours(erosion1, mode=cv.RETR_EXTERNAL, method=cv.CHAIN_APPROX_NONE)
    if len(contours1) == 1:
        #         print('此处没有发生竖直方向的重叠')
        return None
    else:
        #         print('此物体发生了竖直方向的重叠')
        erosion1, flag = fill_small_target(erosion1, contours1)
        if not flag:
            #             print('没有可以填充的小物体存在')
            h, w = img.shape
            cnt = dilate_process(h, w, contours1, kernel, iteration)
            '''
            返回了多个目标的cnt
            '''
            return cnt

        else:
            contours1, _ = cv.findContours(erosion1, mode=cv.RETR_EXTERNAL, method=cv.CHAIN_APPROX_NONE)
            h, w = img.shape
            if len(contours1) == 0:
                return False
            cnt = dilate_process(h, w, contours1, kernel, iteration)

            return cnt

def iou(bbox1, bbox2):
    '''
    bbox1---->[4,]
    bbox2---->[N,4]
    '''
    wh = np.minimum(bbox1[2:], bbox2[:, 2:]) - np.maximum(bbox1[:2], bbox2[:, :2])
    wh = np.maximum(wh, 0)

    bbox1_area = (bbox1[2] - bbox1[0]) * (bbox1[3] - bbox1[1])
    bbox2_area = (bbox2[:, 2] - bbox2[:, 0]) * (bbox2[:, 3] - bbox2[:, 1])
    union_area = wh[:, 0] * wh[:, 1]

    res_iou = union_area / (bbox1_area + bbox2_area - union_area)

    return res_iou

def compute_iou(cnt1, cnt2):
    all_bbox1 = []
    for i in range(len(cnt1)):
        x1, y1, w1, h1 = cv.boundingRect(cnt1[i])
        x2 = x1 + w1
        y2 = y1 + h1
        all_bbox1.append([x1, y1, x2, y2])
    all_bbox1 = np.array(all_bbox1)

    all_bbox2 = []
    for i in range(len(cnt2)):
        x1, y1, w1, h1 = cv.boundingRect(cnt2[i])
        x2 = x1 + w1
        y2 = y1 + h1
        all_bbox2.append([x1, y1, x2, y2])
    all_bbox2 = np.array(all_bbox2)

    valid_cnt1_index = []
    valid_cnt2_index = []

    all_mask = [False] * len(all_bbox2)
    for i in range(len(all_bbox1)):
        res_iou = iou(all_bbox1[i], all_bbox2)
        iou_mask = res_iou > 0.7
        all_mask += iou_mask
        if not np.any(iou_mask):
            valid_cnt1_index.append(i)

    for i in range(len(all_mask)):
        if all_mask[i]:
            continue
        valid_cnt2_index.append(i)

    return valid_cnt1_index, valid_cnt2_index

def eroede_dilate_process(gray_label, contours1):
    h, w = gray_label.shape
    all_cnt = []
    for i in range(len(contours1)):
        plot_img = np.zeros((h, w), dtype=np.uint8)
        cv.drawContours(plot_img, contours1, i, 255, cv.FILLED)
        #         plt.imshow(plot_img)
        cur_cnt = erode_process(plot_img, 5, 5)
        cur_cnt1 = erode_process1(plot_img, 5, 5)

        if cur_cnt == False or cur_cnt1 == False:
            continue
        elif cur_cnt is None and cur_cnt1 is None:
            all_cnt.append(contours1[i])
            continue
        #           没有新目标的产生,默认使用原始的cnt
        elif cur_cnt is not None and cur_cnt1 is not None:
            #         dely_compute_iou

            for k in cur_cnt:
                all_cnt.append(k)
            for k in cur_cnt1:
                all_cnt.append(k)

            '''
            valid_1,valid_2 = compute_iou(cur_cnt,cur_cnt1)
            if len(valid_1)>=1:
                for m in valid_1:
                    all_cnt.append(cur_cnt[m])

            if len(valid_2)>=1:
                for n in valid_2:
                    all_cnt.append(cur_cnt1[n])
            '''
            continue
            '''此处函数待验证是否有BUG以及是否实现所需功能'''
        elif cur_cnt is not None:
            for j in range(len(cur_cnt)):
                all_cnt.append(cur_cnt[j])
            continue
        else:
            for j in range(len(cur_cnt1)):
                all_cnt.append(cur_cnt1[j])
    #         plt.show()
    #         plt.cla()
    return all_cnt

def small_target(input_img,edge,epsilon):
    approx = cv.approxPolyDP(edge,epsilon,True)
    points = approx.reshape((-1, 2))
    count=0
    rate=0.002
    while len(points)!=4:
        epsilon = rate * cv.arcLength(edge, True)
        rate=rate+0.002
        approx = cv.approxPolyDP(edge,epsilon,True)
        points = approx.reshape((-1, 2))
        count+=1
        if count>10:
            break
    if len(points)==4:
        print("小目标的优化结果为4边形")
    else:
        print("小目标的优化方法为外接最小矩形")
        rect = cv.minAreaRect(edge)
        # 得到最小外接矩形的（中心(x,y), (宽,高), 旋转角度）
        points = cv.boxPoints(rect)
    return points

def big_building(img,edge,epsilon):
    epsilon = 0.005 * cv.arcLength(edge, True)
    approx = cv.approxPolyDP(edge,epsilon, True)
#     points = approx.reshape((-1, 2))
    return approx

def big_building1(img,edge,epsilon):
    epsilon = 0.004 * cv.arcLength(edge, True)
    approx = cv.approxPolyDP(edge,epsilon, True)
#     points = approx.reshape((-1, 2))
    return approx

def big_building2(img,edge,epsilon):
    epsilon = 0.002 * cv.arcLength(edge, True)
    approx = cv.approxPolyDP(edge,epsilon, True)
#     points = approx.reshape((-1, 2))
    return approx

def only_plt(input_img,all_cnt):
    for i in range(len(all_cnt)):
        cv.drawContours(input_img,all_cnt,i,255,cv.FILLED)
    return input_img

def model_confuse(path, name=''):
    '''
    save_path = 'all_result' + '/' + dir_name
    print(save_path)
    os.makedirs(save_path, exist_ok=True)
    '''

    all_path = glob.glob(path + '/' + '*.png')
    print(all_path)

    if len(all_path) != 5:
        print('no five images')
        return

    label = cv.imread(all_path[0])
    gray_label, cnt = fill_and_delete(label)
    all_cnt = eroede_dilate_process(gray_label, cnt)
    label = np.zeros((label.shape))
    l1 = only_plt(label.copy(), all_cnt)

    label = cv.imread(all_path[1])
    gray_label, cnt = fill_and_delete(label)
    all_cnt = eroede_dilate_process(gray_label, cnt)
    label = np.zeros((label.shape))
    l2 = only_plt(label.copy(), all_cnt)

    label = cv.imread(all_path[2])
    gray_label, cnt = fill_and_delete(label)
    all_cnt = eroede_dilate_process(gray_label, cnt)
    label = np.zeros((label.shape))
    l3 = only_plt(label.copy(), all_cnt)

    label = cv.imread(all_path[3])
    gray_label, cnt = fill_and_delete(label)
    all_cnt = eroede_dilate_process(gray_label, cnt)
    label = np.zeros((label.shape))
    l4 = only_plt(label.copy(), all_cnt)

    label = cv.imread(all_path[4])
    gray_label, cnt = fill_and_delete(label)
    all_cnt = eroede_dilate_process(gray_label, cnt)
    label = np.zeros((label.shape))
    l5 = only_plt(label.copy(), all_cnt)

    final_label = l1 // 255 + l2 // 255 + l3 // 255 + l4 // 255 + l5 // 255

    # cv.imwrite(save_path + '/' + 'sliding_bam1.png', l1)
    # cv.imwrite(save_path + '/' + 'sliding_deep1.png', l2)
    # cv.imwrite(save_path + '/' + 'sliding_scse1.png', l3)
    # cv.imwrite(save_path + '/' + 'sliding_res341.png', l4)
    # cv.imwrite(save_path + '/' + 'sliding_hrnet1.png', l5)

    label = np.where(final_label >= 3, 255, 0)
    label = np.array(label, np.uint8)
    # print(label.dtype)

    def only_plt1(input_img, all_cnt):
        all_color = [[255, 0, 0], [0, 255, 0], [0, 0, 255], [255, 255, 0], [255, 0, 255], [0, 255, 255],
                     [255, 255, 255]]
        for i in range(len(all_cnt)):
            colors = all_color[i % 7]
            cv.drawContours(image=input_img,
                            contours=[all_cnt[i]],
                            contourIdx=-1,
                            color=colors,
                            thickness=3)
        return input_img

    gray_label, cnt = fill_and_delete(label)
    all_cnt = eroede_dilate_process(gray_label, cnt)
    # plot_res = only_plt1(images, all_cnt)

    label = np.zeros(gray_label.shape,np.uint8)
    for i in range(len(all_cnt)):
        cv.drawContours(label, all_cnt, i, 255, cv.FILLED)

    # h, w, c = plot_res.shape

    cv.imwrite(path + r'\{}_result.png'.format(name),label)
    # cv.imwrite(save_path + '/' + 'sliding_plot_images.png', l1)

    '''
    top = 0
    down = 512
    left = 0
    right = 512
    while down <= h:
        #     left = 0
        #     right = 512
        while right <= w:
            cv.line(plot_res, (left, 0), (left, h), (0, 255, 0), 2, 8)
            cv.line(plot_res, (right, 0), (right, h), (255, 0, 0), 2, 8)
            left = right - int(512 * 0.5)
            right = left + 512

        cv.line(plot_res, (0, top), (w, top), (255, 255, 255), 2, 8)

        cv.line(plot_res, (0, down), (w, down), (0, 0, 0), 2, 8)

        top = down - int(512 * 0.5)
        down = top + 512
        print(top, down)

    cv.imwrite(save_path + '/' + 'sliding_plot_images.png', plot_res)
    '''

if __name__ == '__main__':

    name = os.listdir('D:/res_image')
    # 名称

    for i in range(len(name)):
        path = 'D:/res_image' +'/'+ name[i]
        #     绝对路劲
    #     child path
        model_confuse(path,name[i])
        print('图片{}预测结束'.format(name[i]))


import numpy as np
import keras

from keras.layers import Input, Dense, Reshape, Flatten, Dropout, multiply, GaussianNoise
from keras.layers import BatchNormalization, Activation, Embedding, ZeroPadding2D
from keras.layers import MaxPooling2D, Lambda
from keras.layers.convolutional import UpSampling2D, Conv2D, Conv2DTranspose, Cropping2D
from keras.models import Sequential, Model
from keras.layers import MaxPooling2D, concatenate, Add
import keras.backend as K

import keras.utils
from keras.engine.topology import Layer
class Bias(Layer):
    def build(self, input_shape):
        self.bias = self.add_weight(shape=(input_shape[-1],),
                                        initializer="zeros",
                                        name='bias',
                                        regularizer=None,
                                        constraint=None)
        super(Bias, self).build(input_shape)

    def call(self, inputs):
        outputs = K.bias_add(
                inputs,
                self.bias)
        return outputs

    def compute_output_shape(self, input_shape):
        return input_shape

keras.layers.Bias = Bias

def partial_convolution(input_, mask, filters, shape, stride, activation):
    convolution_layer = Conv2D(filters, shape, strides=stride, use_bias=False,
                               padding="same")

    mask_sum_layer = Conv2D(filters, shape, strides=stride,
                                  padding="same",
                                  weights=[np.ones((shape[0], shape[1], input_.shape[-1], filters)),
                                           np.zeros((filters,))])

    mask_sum_layer.trainable = False

    mask_sum = mask_sum_layer(mask)

    new_mask = Lambda(lambda x: K.clip(x, 0, 1))(mask_sum)

    output = convolution_layer(keras.layers.multiply([mask, input_]))

    inv_sum = Lambda(lambda x: filters * shape[0] * shape[1] / (.0001 + x))(mask_sum)

    output = keras.layers.multiply([output, inv_sum])

    output = Bias()(output)

    output = activation(output)

    return output, new_mask

def nvidia_unet(patch_size=256):
    input_ = Input((patch_size, patch_size, 3))
    input_mask = Input((patch_size, patch_size, 3))
    skips = []
    output = input_
    mask = input_mask
    for shape, filters in zip([7, 5, 5, 3, 3, 3, 3, 3], [64, 128, 256, 512, 512, 512, 512, 512]):
        skips.append((output, mask))
        print(output.shape)
        output, mask = partial_convolution(output, mask, filters, (shape, shape), 2,
                                           Activation("relu"))
        if shape != 7:
            output = BatchNormalization()(output)
    for shape, filters in zip([4, 4, 4, 4, 4, 4, 4, 4], [512, 512, 512, 512, 256, 128, 64, 3]):
        output = keras.layers.UpSampling2D()(output)
        mask = keras.layers.UpSampling2D()(mask)
        skip_output, skip_mask = skips.pop()
        output = concatenate([output, skip_output], axis=3)
        mask = concatenate([mask, skip_mask], axis=3)

        if filters != 3:
            activation = keras.layers.LeakyReLU(.2)
        else:
            activation = Activation("linear")
        output, mask = partial_convolution(output, mask, filters, (shape, shape), 1, activation)
        if filters != 3:
            output = BatchNormalization()(output)
    assert len(skips) == 0
    return Model([input_, input_mask], [output])

def pad_to_patch_size(image, mask, patch_size=256):
    #Network only accepts square images with size as a multiple of 256.
    #Use the mask to make sure that the output only depends on the valid rectangle.
    network_input = np.zeros((1, patch_size, patch_size, 3))
    network_mask = np.zeros((1, patch_size, patch_size, 3))

    network_input[:, :image.shape[1], :image.shape[2]] = image
    network_mask[:, :mask.shape[1], :mask.shape[2]] = mask

    return network_input, network_mask

def compute_patch_size_to_fit(z):
    num_patches = (max(z.shape[1], z.shape[2]) - 1) // 256 + 1
    return 256 * num_patches


from decimal import Decimal, getcontext
from vector import Vector

getcontext().prec = 30

class Plane(object):
    '''Vector representation of a Plane in three dimension'''

    NO_NONZERO_ELTS_FOUND_MSG = 'No nonzero elements found'

    def __init__(self, normal_vector=None, constant_term=None):
        '''Create a Plane Object

        Ax + By + Cz = k
        Vector([A, B, C]) represents a normal Vector'''
        self.dimension = 3

        if not normal_vector:
            all_zeros = ['0'] * self.dimension
            normal_vector = Vector(all_zeros)
        self.normal_vector = normal_vector

        if not constant_term:
            constant_term = Decimal('0')
        self.constant_term = Decimal(constant_term)

        self.set_basepoint()

    def __getitem__(self, i):
        return self.normal_vector[i]

    def set_basepoint(self):
        '''find the first non zero coordinate, either (0, k/B) or (k/A, 0)'''
        try:
            n = self.normal_vector
            c = self.constant_term
            basepoint_coords = ['0'] * self.dimension

            initial_index = Plane.first_nonzero_index(n)
            initial_coefficient = n[initial_index]

            basepoint_coords[initial_index] = c / initial_coefficient
            self.basepoint = Vector(basepoint_coords)

        except Exception as e:
            if str(e) == Plane.NO_NONZERO_ELTS_FOUND_MSG:
                self.basepoint = None
            else:
                raise e

    def __str__(self):

        num_decimal_places = 3

        def write_coefficient(coefficient, is_initial_term=False):
            coefficient = round(coefficient, num_decimal_places)
            if coefficient % 1 == 0:
                coefficient = int(coefficient)

            output = ''

            if coefficient < 0:
                output += '-'
            if coefficient > 0 and not is_initial_term:
                output += '+'

            if not is_initial_term:
                output += ' '

            if abs(coefficient) != 1:
                output += '{}'.format(abs(coefficient))

            return output

        n = self.normal_vector

        try:
            initial_index = Plane.first_nonzero_index(n)
            terms = []
            for i in range(self.dimension):
                if round(n[i], num_decimal_places) != 0:
                    terms.append(write_coefficient(
                        n[i],
                        is_initial_term=(i == initial_index)) +
                        'x_{}'.format(i + 1))
            output = ' '.join(terms)

        except Exception as e:
            if str(e) == self.NO_NONZERO_ELTS_FOUND_MSG:
                output = '0'
            else:
                raise e

        constant = round(self.constant_term, num_decimal_places)
        if constant % 1 == 0:
            constant = int(constant)
        output += ' = {}'.format(constant)

        return output

    @staticmethod
    def first_nonzero_index(iterable):
        for k, item in enumerate(iterable):
            if not MyDecimal(item).is_near_zero():
                return k
        raise Exception(Plane.NO_NONZERO_ELTS_FOUND_MSG)

    def is_parallel_to(self, plane2):
        '''two planes are parallel if their normal vectors are parallel'''
        return self.normal_vector.is_parallel_to(plane2.normal_vector)

    def __eq__(self, plane2):
        '''two planes are equal, if the vector connecting one point on each
        plane is orthogonal to the planes normal vectors'''
        # normal vector have to be parallel in order to be equal
        # if not self.is_parallel_to(plane2):
        #     return False

        # v_connect = self.basepoint.minus(plane2.basepoint)
        # return v_connect.is_orthogonal_to(self.normal_vector)
        if self.normal_vector.is_zero():
            if not plane2.normal_vector.is_zero():
                return False

            diff = self.constant_term - plane2.constant_term
            return MyDecimal(diff).is_near_zero()

        elif plane2.normal_vector.is_zero():
            return False

        if not self.is_parallel_to(plane2):
            return False

        basepoint_difference = self.basepoint.minus(plane2.basepoint)
        return basepoint_difference.is_orthogonal_to(self.normal_vector)

class MyDecimal(Decimal):
    def is_near_zero(self, eps=1e-10):
        return abs(self) < eps

if __name__ == '__main__':

    print('################################')
    print('Quiz: Planes in 3 Dimensions - 2')

    p1 = Plane(Vector([-0.412, 3.806, 0.728]), -3.46)
    p2 = Plane(Vector([1.03, -9.515, -1.82]), 8.65)
    print('equal: {0}'.format(p1 == p2))
    print('parallel but unequal: {0}'.format(p1.is_parallel_to(p2)))

    p3 = Plane(Vector([2.611, 5.528, 0.283]), 4.6)
    p4 = Plane(Vector([7.715, 8.306, 5.342]), 3.76)
    print('equal: {0}'.format(p3 == p4))
    print('parallel but unequal: {0}'.format(p3.is_parallel_to(p4)))

    p5 = Plane(Vector([-7.926, 8.625, -7.212]), -7.952)
    p6 = Plane(Vector([-2.642, 2.875, -2.404]), -2.443)
    print('equal: {0}'.format(p5 == p6))
    print('parallel but unequal: {0}'.format(p5.is_parallel_to(p6)))


import arxiv
from django.core.paginator import Paginator, EmptyPage

ALL_QUERY = 'all:psychiatry OR all:therapy OR all:data science OR all:machine learning'
AUTHOR_QUERY = 'au:{0}'

def fetch_all_articles(num_articles, start=0):
    all_data = arxiv.query(
        search_query=ALL_QUERY,
        max_results=num_articles,
        sort_by='lastUpdatedDate',
        start=start
    )
    cleaned_data = list()
    for data in all_data:
        cleaned_data.append({
            'title': data['title'],
            'authors': data['authors'],
            'summary': data['summary'],
            'published': data['published']
        })
    return cleaned_data

def fetch_articles_by_author(author_name, num_articles, start=0):
    all_data = arxiv.query(
        search_query=AUTHOR_QUERY.format(author_name),
        max_results=num_articles,
        sort_by='lastUpdatedDate',
        start=start
    )
    cleaned_data = list()
    for data in all_data:
        cleaned_data.append({
            'title': data['title'],
            'published': data['published'],
            'summary': data['summary']
        })
    return cleaned_data

def paginate_view(request, query_set, page=None, num_items=None):
    """ Paginates view from queryset """
    if page is None:
        page = request.GET.get('page', default=1)
    if num_items is None:
        num_items = request.GET.get('num_items', default=10)
    paginator = Paginator(query_set, num_items)
    try:
        data_set = paginator.page(page)
    except EmptyPage:
        data_set = paginator.page(paginator.num_pages)
    return data_set, num_items, page


from django.contrib import admin
from .models import *
# Register your models here.

class AnswerInLine(admin.TabularInline):
    #inquiry 모델에 인라인 모델로 추가
    model = Answer
    extra = 5

@admin.register(FAQ)
class FAQAdmin(admin.ModelAdmin):
    list_display = (
        'title',
        'category',
        'updated_at',
    )
    search_fields = (
        'title',
    )
    fields = ['category']

@admin.register(Inquiry)
class InquiryAdmin(admin.ModelAdmin):
    list_display = (
        'Inquiry_title',
        'Inquiry_category',
        'Inquiry_updated_at',
        'Inquiry_writer',
    )
    search_fields = (
        'Inquiry_title',
        'Inquiry_email',
        'Inquiry_number',
    )
    fields = ['Inquiry_category']
    inlines = [
        AnswerInLine,
    ]


from tkinter import Label

from config import PALETTE, FONTS

# klasa bazowa tekstu
class Text(Label):
    def __init__(self, window, font, text, color=PALETTE["PRIMARY"]):
        super().__init__(window)

        self["text"] = text
        self["foreground"] = color
        self["background"] = PALETTE["BACKGROUND"]
        self["font"] = font
        self["wraplength"] = 500

# klasa nagłówka strony aplikacji
class PageHeader(Text):
    def __init__(self, window, text):
        super().__init__(window, font=FONTS["PAGE_HEADER"], text=text)

# klasa nagłówka sekcji strony
class SectionHeader(Text):
    def __init__(self, window, text):
        super().__init__(window, font=FONTS["SECTION_HEADER"], text=text)

# klasa zwykłego tekstu
class NormalText(Text):
    def __init__(self, window, text):
        super().__init__(
            window, font=FONTS["NORMAL_TEXT"], text=text, color=PALETTE["WHITE"]
        )


from pyasn1 import debug
from pyasn1 import error
from pyasn1.codec.ber import eoo
from pyasn1.compat.integer import to_bytes
from pyasn1.compat.octets import (int2oct, oct2int, ints2octs, null,
                                  str2octs, isOctetsType)
from pyasn1.type import char
from pyasn1.type import tag
from pyasn1.type import univ
from pyasn1.type import useful

__all__ = ['encode']

class AbstractItemEncoder(object):
    supportIndefLenMode = True

    # An outcome of otherwise legit call `encodeFun(eoo.endOfOctets)`
    eooIntegerSubstrate = (0, 0)
    eooOctetsSubstrate = ints2octs(eooIntegerSubstrate)

    # noinspection PyMethodMayBeStatic
    def encodeTag(self, singleTag, isConstructed):
        tagClass, tagFormat, tagId = singleTag
        encodedTag = tagClass | tagFormat
        if isConstructed:
            encodedTag |= tag.tagFormatConstructed
        if tagId < 31:
            return encodedTag | tagId,
        else:
            substrate = tagId & 0x7f,
            tagId >>= 7
            while tagId:
                substrate = (0x80 | (tagId & 0x7f),) + substrate
                tagId >>= 7
            return (encodedTag | 0x1F,) + substrate

    def encodeLength(self, length, defMode):
        if not defMode and self.supportIndefLenMode:
            return (0x80,)
        if length < 0x80:
            return length,
        else:
            substrate = ()
            while length:
                substrate = (length & 0xff,) + substrate
                length >>= 8
            substrateLen = len(substrate)
            if substrateLen > 126:
                raise error.PyAsn1Error('Length octets overflow (%d)' % substrateLen)
            return (0x80 | substrateLen,) + substrate

    def encodeValue(self, value, asn1Spec, encodeFun, **options):
        raise error.PyAsn1Error('Not implemented')

    def encode(self, value, asn1Spec=None, encodeFun=None, **options):

        if asn1Spec is None:
            tagSet = value.tagSet
        else:
            tagSet = asn1Spec.tagSet

        # untagged item?
        if not tagSet:
            substrate, isConstructed, isOctets = self.encodeValue(
                value, asn1Spec, encodeFun, **options
            )
            return substrate

        defMode = options.get('defMode', True)

        for idx, singleTag in enumerate(tagSet.superTags):

            defModeOverride = defMode

            # base tag?
            if not idx:
                substrate, isConstructed, isOctets = self.encodeValue(
                    value, asn1Spec, encodeFun, **options
                )

                if not substrate and isConstructed and options.get('ifNotEmpty', False):
                    return substrate

                # primitive form implies definite mode
                if not isConstructed:
                    defModeOverride = True

            header = self.encodeTag(singleTag, isConstructed)
            header += self.encodeLength(len(substrate), defModeOverride)

            if isOctets:
                substrate = ints2octs(header) + substrate

                if not defModeOverride:
                    substrate += self.eooOctetsSubstrate

            else:
                substrate = header + substrate

                if not defModeOverride:
                    substrate += self.eooIntegerSubstrate

        if not isOctets:
            substrate = ints2octs(substrate)

        return substrate

class EndOfOctetsEncoder(AbstractItemEncoder):
    def encodeValue(self, value, asn1Spec, encodeFun, **options):
        return null, False, True

class BooleanEncoder(AbstractItemEncoder):
    supportIndefLenMode = False

    def encodeValue(self, value, asn1Spec, encodeFun, **options):
        return value and (1,) or (0,), False, False

class IntegerEncoder(AbstractItemEncoder):
    supportIndefLenMode = False
    supportCompactZero = False

    def encodeValue(self, value, asn1Spec, encodeFun, **options):
        if value == 0:
            # de-facto way to encode zero
            if self.supportCompactZero:
                return (), False, False
            else:
                return (0,), False, False

        return to_bytes(int(value), signed=True), False, True

class BitStringEncoder(AbstractItemEncoder):
    def encodeValue(self, value, asn1Spec, encodeFun, **options):
        if asn1Spec is not None:
            # TODO: try to avoid ASN.1 schema instantiation
            value = asn1Spec.clone(value)

        valueLength = len(value)
        if valueLength % 8:
            alignedValue = value << (8 - valueLength % 8)
        else:
            alignedValue = value

        maxChunkSize = options.get('maxChunkSize', 0)
        if not maxChunkSize or len(alignedValue) <= maxChunkSize * 8:
            substrate = alignedValue.asOctets()
            return int2oct(len(substrate) * 8 - valueLength) + substrate, False, True

        baseTag = value.tagSet.baseTag

        # strip off explicit tags
        if baseTag:
            tagSet = tag.TagSet(baseTag, baseTag)
        else:
            tagSet = tag.TagSet()

        alignedValue = alignedValue.clone(tagSet=tagSet)

        stop = 0
        substrate = null
        while stop < valueLength:
            start = stop
            stop = min(start + maxChunkSize * 8, valueLength)
            substrate += encodeFun(alignedValue[start:stop], asn1Spec, **options)

        return substrate, True, True

class OctetStringEncoder(AbstractItemEncoder):

    def encodeValue(self, value, asn1Spec, encodeFun, **options):

        if asn1Spec is None:
            substrate = value.asOctets()

        elif not isOctetsType(value):
            substrate = asn1Spec.clone(value).asOctets()

        else:
            substrate = value

        maxChunkSize = options.get('maxChunkSize', 0)

        if not maxChunkSize or len(substrate) <= maxChunkSize:
            return substrate, False, True

        else:

            # strip off explicit tags for inner chunks

            if asn1Spec is None:
                baseTag = value.tagSet.baseTag

                # strip off explicit tags
                if baseTag:
                    tagSet = tag.TagSet(baseTag, baseTag)
                else:
                    tagSet = tag.TagSet()

                asn1Spec = value.clone(tagSet=tagSet)

            elif not isOctetsType(value):
                baseTag = asn1Spec.tagSet.baseTag

                # strip off explicit tags
                if baseTag:
                    tagSet = tag.TagSet(baseTag, baseTag)
                else:
                    tagSet = tag.TagSet()

                asn1Spec = asn1Spec.clone(tagSet=tagSet)

            pos = 0
            substrate = null

            while True:
                chunk = value[pos:pos + maxChunkSize]
                if not chunk:
                    break

                substrate += encodeFun(chunk, asn1Spec, **options)
                pos += maxChunkSize

            return substrate, True, True

class NullEncoder(AbstractItemEncoder):
    supportIndefLenMode = False

    def encodeValue(self, value, asn1Spec, encodeFun, **options):
        return null, False, True

class ObjectIdentifierEncoder(AbstractItemEncoder):
    supportIndefLenMode = False

    def encodeValue(self, value, asn1Spec, encodeFun, **options):
        if asn1Spec is not None:
            value = asn1Spec.clone(value)

        oid = value.asTuple()

        # Build the first pair
        try:
            first = oid[0]
            second = oid[1]

        except IndexError:
            raise error.PyAsn1Error('Short OID %s' % (value,))

        if 0 <= second <= 39:
            if first == 1:
                oid = (second + 40,) + oid[2:]
            elif first == 0:
                oid = (second,) + oid[2:]
            elif first == 2:
                oid = (second + 80,) + oid[2:]
            else:
                raise error.PyAsn1Error('Impossible first/second arcs at %s' % (value,))
        elif first == 2:
            oid = (second + 80,) + oid[2:]
        else:
            raise error.PyAsn1Error('Impossible first/second arcs at %s' % (value,))

        octets = ()

        # Cycle through subIds
        for subOid in oid:
            if 0 <= subOid <= 127:
                # Optimize for the common case
                octets += (subOid,)
            elif subOid > 127:
                # Pack large Sub-Object IDs
                res = (subOid & 0x7f,)
                subOid >>= 7
                while subOid:
                    res = (0x80 | (subOid & 0x7f),) + res
                    subOid >>= 7
                # Add packed Sub-Object ID to resulted Object ID
                octets += res
            else:
                raise error.PyAsn1Error('Negative OID arc %s at %s' % (subOid, value))

        return octets, False, False

class RealEncoder(AbstractItemEncoder):
    supportIndefLenMode = 0
    binEncBase = 2  # set to None to choose encoding base automatically

    @staticmethod
    def _dropFloatingPoint(m, encbase, e):
        ms, es = 1, 1
        if m < 0:
            ms = -1  # mantissa sign
        if e < 0:
            es = -1  # exponenta sign
        m *= ms
        if encbase == 8:
            m *= 2 ** (abs(e) % 3 * es)
            e = abs(e) // 3 * es
        elif encbase == 16:
            m *= 2 ** (abs(e) % 4 * es)
            e = abs(e) // 4 * es

        while True:
            if int(m) != m:
                m *= encbase
                e -= 1
                continue
            break
        return ms, int(m), encbase, e

    def _chooseEncBase(self, value):
        m, b, e = value
        encBase = [2, 8, 16]
        if value.binEncBase in encBase:
            return self._dropFloatingPoint(m, value.binEncBase, e)
        elif self.binEncBase in encBase:
            return self._dropFloatingPoint(m, self.binEncBase, e)
        # auto choosing base 2/8/16
        mantissa = [m, m, m]
        exponenta = [e, e, e]
        sign = 1
        encbase = 2
        e = float('inf')
        for i in range(3):
            (sign,
             mantissa[i],
             encBase[i],
             exponenta[i]) = self._dropFloatingPoint(mantissa[i], encBase[i], exponenta[i])
            if abs(exponenta[i]) < abs(e) or (abs(exponenta[i]) == abs(e) and mantissa[i] < m):
                e = exponenta[i]
                m = int(mantissa[i])
                encbase = encBase[i]
        return sign, m, encbase, e

    def encodeValue(self, value, asn1Spec, encodeFun, **options):
        if asn1Spec is not None:
            value = asn1Spec.clone(value)

        if value.isPlusInf:
            return (0x40,), False, False
        if value.isMinusInf:
            return (0x41,), False, False
        m, b, e = value
        if not m:
            return null, False, True
        if b == 10:
            return str2octs('\x03%dE%s%d' % (m, e == 0 and '+' or '', e)), False, True
        elif b == 2:
            fo = 0x80  # binary encoding
            ms, m, encbase, e = self._chooseEncBase(value)
            if ms < 0:  # mantissa sign
                fo |= 0x40  # sign bit
            # exponenta & mantissa normalization
            if encbase == 2:
                while m & 0x1 == 0:
                    m >>= 1
                    e += 1
            elif encbase == 8:
                while m & 0x7 == 0:
                    m >>= 3
                    e += 1
                fo |= 0x10
            else:  # encbase = 16
                while m & 0xf == 0:
                    m >>= 4
                    e += 1
                fo |= 0x20
            sf = 0  # scale factor
            while m & 0x1 == 0:
                m >>= 1
                sf += 1
            if sf > 3:
                raise error.PyAsn1Error('Scale factor overflow')  # bug if raised
            fo |= sf << 2
            eo = null
            if e == 0 or e == -1:
                eo = int2oct(e & 0xff)
            else:
                while e not in (0, -1):
                    eo = int2oct(e & 0xff) + eo
                    e >>= 8
                if e == 0 and eo and oct2int(eo[0]) & 0x80:
                    eo = int2oct(0) + eo
                if e == -1 and eo and not (oct2int(eo[0]) & 0x80):
                    eo = int2oct(0xff) + eo
            n = len(eo)
            if n > 0xff:
                raise error.PyAsn1Error('Real exponent overflow')
            if n == 1:
                pass
            elif n == 2:
                fo |= 1
            elif n == 3:
                fo |= 2
            else:
                fo |= 3
                eo = int2oct(n & 0xff) + eo
            po = null
            while m:
                po = int2oct(m & 0xff) + po
                m >>= 8
            substrate = int2oct(fo) + eo + po
            return substrate, False, True
        else:
            raise error.PyAsn1Error('Prohibited Real base %s' % b)

class SequenceEncoder(AbstractItemEncoder):
    omitEmptyOptionals = False

    # TODO: handling three flavors of input is too much -- split over codecs

    def encodeValue(self, value, asn1Spec, encodeFun, **options):

        substrate = null

        if asn1Spec is None:
            # instance of ASN.1 schema
            value.verifySizeSpec()

            namedTypes = value.componentType

            for idx, component in enumerate(value.values()):
                if namedTypes:
                    namedType = namedTypes[idx]

                    if namedType.isOptional and not component.isValue:
                            continue

                    if namedType.isDefaulted and component == namedType.asn1Object:
                            continue

                    if self.omitEmptyOptionals:
                        options.update(ifNotEmpty=namedType.isOptional)

                chunk = encodeFun(component, asn1Spec, **options)

                # wrap open type blob if needed
                if namedTypes and namedType.openType:
                    wrapType = namedType.asn1Object
                    if wrapType.tagSet and not wrapType.isSameTypeWith(component):
                        chunk = encodeFun(chunk, wrapType, **options)

                substrate += chunk

        else:
            # bare Python value + ASN.1 schema
            for idx, namedType in enumerate(asn1Spec.componentType.namedTypes):

                try:
                    component = value[namedType.name]

                except KeyError:
                    raise error.PyAsn1Error('Component name "%s" not found in %r' % (namedType.name, value))

                if namedType.isOptional and namedType.name not in value:
                    continue

                if namedType.isDefaulted and component == namedType.asn1Object:
                    continue

                if self.omitEmptyOptionals:
                    options.update(ifNotEmpty=namedType.isOptional)

                chunk = encodeFun(component, asn1Spec[idx], **options)

                # wrap open type blob if needed
                if namedType.openType:
                    wrapType = namedType.asn1Object
                    if wrapType.tagSet and not wrapType.isSameTypeWith(component):
                        chunk = encodeFun(chunk, wrapType, **options)

                substrate += chunk

        return substrate, True, True

class SequenceOfEncoder(AbstractItemEncoder):
    def encodeValue(self, value, asn1Spec, encodeFun, **options):
        if asn1Spec is None:
            value.verifySizeSpec()
        else:
            asn1Spec = asn1Spec.componentType

        substrate = null

        for idx, component in enumerate(value):
            substrate += encodeFun(value[idx], asn1Spec, **options)

        return substrate, True, True

class ChoiceEncoder(AbstractItemEncoder):
    def encodeValue(self, value, asn1Spec, encodeFun, **options):
        if asn1Spec is None:
            component = value.getComponent()
        else:
            names = [namedType.name for namedType in asn1Spec.componentType.namedTypes
                     if namedType.name in value]
            if len(names) != 1:
                raise error.PyAsn1Error('%s components for Choice at %r' % (len(names) and 'Multiple ' or 'None ', value))

            name = names[0]

            component = value[name]
            asn1Spec = asn1Spec[name]

        return encodeFun(component, asn1Spec, **options), True, True

class AnyEncoder(OctetStringEncoder):
    def encodeValue(self, value, asn1Spec, encodeFun, **options):
        if asn1Spec is None:
            value = value.asOctets()
        elif not isOctetsType(value):
            value = asn1Spec.clone(value).asOctets()

        return value, not options.get('defMode', True), True

tagMap = {
    eoo.endOfOctets.tagSet: EndOfOctetsEncoder(),
    univ.Boolean.tagSet: BooleanEncoder(),
    univ.Integer.tagSet: IntegerEncoder(),
    univ.BitString.tagSet: BitStringEncoder(),
    univ.OctetString.tagSet: OctetStringEncoder(),
    univ.Null.tagSet: NullEncoder(),
    univ.ObjectIdentifier.tagSet: ObjectIdentifierEncoder(),
    univ.Enumerated.tagSet: IntegerEncoder(),
    univ.Real.tagSet: RealEncoder(),
    # Sequence & Set have same tags as SequenceOf & SetOf
    univ.SequenceOf.tagSet: SequenceOfEncoder(),
    univ.SetOf.tagSet: SequenceOfEncoder(),
    univ.Choice.tagSet: ChoiceEncoder(),
    # character string types
    char.UTF8String.tagSet: OctetStringEncoder(),
    char.NumericString.tagSet: OctetStringEncoder(),
    char.PrintableString.tagSet: OctetStringEncoder(),
    char.TeletexString.tagSet: OctetStringEncoder(),
    char.VideotexString.tagSet: OctetStringEncoder(),
    char.IA5String.tagSet: OctetStringEncoder(),
    char.GraphicString.tagSet: OctetStringEncoder(),
    char.VisibleString.tagSet: OctetStringEncoder(),
    char.GeneralString.tagSet: OctetStringEncoder(),
    char.UniversalString.tagSet: OctetStringEncoder(),
    char.BMPString.tagSet: OctetStringEncoder(),
    # useful types
    useful.ObjectDescriptor.tagSet: OctetStringEncoder(),
    useful.GeneralizedTime.tagSet: OctetStringEncoder(),
    useful.UTCTime.tagSet: OctetStringEncoder()
}

# Put in ambiguous & non-ambiguous types for faster codec lookup
typeMap = {
    univ.Boolean.typeId: BooleanEncoder(),
    univ.Integer.typeId: IntegerEncoder(),
    univ.BitString.typeId: BitStringEncoder(),
    univ.OctetString.typeId: OctetStringEncoder(),
    univ.Null.typeId: NullEncoder(),
    univ.ObjectIdentifier.typeId: ObjectIdentifierEncoder(),
    univ.Enumerated.typeId: IntegerEncoder(),
    univ.Real.typeId: RealEncoder(),
    # Sequence & Set have same tags as SequenceOf & SetOf
    univ.Set.typeId: SequenceEncoder(),
    univ.SetOf.typeId: SequenceOfEncoder(),
    univ.Sequence.typeId: SequenceEncoder(),
    univ.SequenceOf.typeId: SequenceOfEncoder(),
    univ.Choice.typeId: ChoiceEncoder(),
    univ.Any.typeId: AnyEncoder(),
    # character string types
    char.UTF8String.typeId: OctetStringEncoder(),
    char.NumericString.typeId: OctetStringEncoder(),
    char.PrintableString.typeId: OctetStringEncoder(),
    char.TeletexString.typeId: OctetStringEncoder(),
    char.VideotexString.typeId: OctetStringEncoder(),
    char.IA5String.typeId: OctetStringEncoder(),
    char.GraphicString.typeId: OctetStringEncoder(),
    char.VisibleString.typeId: OctetStringEncoder(),
    char.GeneralString.typeId: OctetStringEncoder(),
    char.UniversalString.typeId: OctetStringEncoder(),
    char.BMPString.typeId: OctetStringEncoder(),
    # useful types
    useful.ObjectDescriptor.typeId: OctetStringEncoder(),
    useful.GeneralizedTime.typeId: OctetStringEncoder(),
    useful.UTCTime.typeId: OctetStringEncoder()
}

class Encoder(object):
    fixedDefLengthMode = None
    fixedChunkSize = None

    # noinspection PyDefaultArgument
    def __init__(self, tagMap, typeMap={}):
        self.__tagMap = tagMap
        self.__typeMap = typeMap

    def __call__(self, value, asn1Spec=None, **options):
        try:
            if asn1Spec is None:
                typeId = value.typeId
            else:
                typeId = asn1Spec.typeId

        except AttributeError:
            raise error.PyAsn1Error('Value %r is not ASN.1 type instance '
                                    'and "asn1Spec" not given' % (value,))

        if debug.logger & debug.flagEncoder:
            logger = debug.logger
        else:
            logger = None

        if logger:
            logger('encoder called in %sdef mode, chunk size %s for '
                   'type %s, value:\n%s' % (not options.get('defMode', True) and 'in' or '', options.get('maxChunkSize', 0), asn1Spec is None and value.prettyPrintType() or asn1Spec.prettyPrintType(), value))

        if self.fixedDefLengthMode is not None:
            options.update(defMode=self.fixedDefLengthMode)

        if self.fixedChunkSize is not None:
            options.update(maxChunkSize=self.fixedChunkSize)

        try:
            concreteEncoder = self.__typeMap[typeId]

            if logger:
                logger('using value codec %s chosen by type ID %s' % (concreteEncoder.__class__.__name__, typeId))

        except KeyError:
            if asn1Spec is None:
                tagSet = value.tagSet
            else:
                tagSet = asn1Spec.tagSet

            # use base type for codec lookup to recover untagged types
            baseTagSet = tag.TagSet(tagSet.baseTag, tagSet.baseTag)

            try:
                concreteEncoder = self.__tagMap[baseTagSet]

            except KeyError:
                raise error.PyAsn1Error('No encoder for %r (%s)' % (value, tagSet))

            if logger:
                logger('using value codec %s chosen by tagSet %s' % (concreteEncoder.__class__.__name__, tagSet))

        substrate = concreteEncoder.encode(value, asn1Spec, self, **options)

        if logger:
            logger('codec %s built %s octets of substrate: %s\nencoder completed' % (concreteEncoder, len(substrate), debug.hexdump(substrate)))

        return substrate

#: Turns ASN.1 object into BER octet stream.
#:
#: Takes any ASN.1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative)
#: walks all its components recursively and produces a BER octet stream.
#:
#: Parameters
#: ----------
#: value: either a Python or pyasn1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative)
#:     A Python or pyasn1 object to encode. If Python object is given, `asnSpec`
#:     parameter is required to guide the encoding process.
#:
#: Keyword Args
#: ------------
#: asn1Spec:
#:     Optional ASN.1 schema or value object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative
#:
#: defMode: :py:class:`bool`
#:     If `False`, produces indefinite length encoding
#:
#: maxChunkSize: :py:class:`int`
#:     Maximum chunk size in chunked encoding mode (0 denotes unlimited chunk size)
#:
#: Returns
#: -------
#: : :py:class:`bytes` (Python 3) or :py:class:`str` (Python 2)
#:     Given ASN.1 object encoded into BER octetstream
#:
#: Raises
#: ------
#: :py:class:`~pyasn1.error.PyAsn1Error`
#:     On encoding errors
#:
#: Examples
#: --------
#: Encode Python value into BER with ASN.1 schema
#:
#: .. code-block:: pycon
#:
#:    >>> seq = SequenceOf(componentType=Integer())
#:    >>> encode([1, 2, 3], asn1Spec=seq)
#:    b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03'
#:
#: Encode ASN.1 value object into BER
#:
#: .. code-block:: pycon
#:
#:    >>> seq = SequenceOf(componentType=Integer())
#:    >>> seq.extend([1, 2, 3])
#:    >>> encode(seq)
#:    b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03'
#:
encode = Encoder(tagMap, typeMap)