import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.nn.init as init

from myssd.nets.mobilenetv2 import InvertedResidual, mobilenet_v2
from myssd.nets.vgg import vgg as add_vgg

from myssd.nets.ECANET import eca_block

class L2Norm(nn.Module):
    def __init__(self, n_channels, scale):
        super(L2Norm, self).__init__()
        self.n_channels = n_channels
        self.gamma = scale or None
        self.eps = 1e-10
        self.weight = nn.Parameter(torch.Tensor(self.n_channels))
        self.reset_parameters()

    def reset_parameters(self):
        init.constant_(self.weight, self.gamma)

    def forward(self, x):
        norm = x.pow(2).sum(dim=1, keepdim=True).sqrt() + self.eps
        # x /= norm
        x = torch.div(x, norm)
        out = self.weight.unsqueeze(0).unsqueeze(2).unsqueeze(3).expand_as(x) * x
        return out

def add_extras(in_channels, backbone_name):
    layers = []
    if backbone_name == 'vgg':
        # Block 6
        # 19,19,1024 -> 19,19,256 -> 10,10,512
        layers += [nn.Conv2d(in_channels, 256, kernel_size=1, stride=1)]
        layers += [nn.Conv2d(256, 512, kernel_size=3, stride=2, padding=1)]

        # Block 7
        # 10,10,512 -> 10,10,128 -> 5,5,256
        layers += [nn.Conv2d(512, 128, kernel_size=1, stride=1)]
        layers += [nn.Conv2d(128, 256, kernel_size=3, stride=2, padding=1)]

        # Block 8
        # 5,5,256 -> 5,5,128 -> 3,3,256
        layers += [nn.Conv2d(256, 128, kernel_size=1, stride=1)]
        layers += [nn.Conv2d(128, 256, kernel_size=3, stride=1)]

        # Block 9
        # 3,3,256 -> 3,3,128 -> 1,1,256
        layers += [nn.Conv2d(256, 128, kernel_size=1, stride=1)]
        layers += [nn.Conv2d(128, 256, kernel_size=3, stride=1)]
    else:
        layers += [InvertedResidual(in_channels, 512, stride=2, expand_ratio=0.2)]
        layers += [InvertedResidual(512, 256, stride=2, expand_ratio=0.25)]
        layers += [InvertedResidual(256, 256, stride=2, expand_ratio=0.5)]
        layers += [InvertedResidual(256, 64, stride=2, expand_ratio=0.25)]

    return nn.ModuleList(layers)

# 下采样模块
def Downsampling():
    layers = []
    in_channels = 3

    # 300->38
    # pool1 = nn.MaxPool2d(kernel_size=8, stride=8, ceil_mode=True)
    pool1 = nn.MaxPool2d(kernel_size=2, stride=2, ceil_mode=True)
    pool2 = nn.MaxPool2d(kernel_size=2, stride=2, ceil_mode=True)
    pool3 = nn.MaxPool2d(kernel_size=2, stride=2, ceil_mode=True)

    # 38->19
    pool4 = nn.MaxPool2d(kernel_size=2, stride=2)
    # 19->10
    pool5 = nn.MaxPool2d(kernel_size=2, stride=2, ceil_mode=True)
    # 10->5
    pool6 = nn.MaxPool2d(kernel_size=2, stride=2)

    layers += [pool1, pool2, pool3, pool4, pool5, pool6]

    return nn.Sequential(*layers)

class ConvBlock(nn.Module):

    def __init__(self, in_planes, out_planes, kernel_size, stride=1, padding=0, dilation=1, groups=1, relu=True, bn=True, bias=False):
        super(ConvBlock, self).__init__()
        self.out_channels = out_planes
        self.conv = nn.Conv2d(in_planes, out_planes, kernel_size=kernel_size, stride=stride, padding=padding, dilation=dilation, groups=groups, bias=bias)
        self.bn = nn.BatchNorm2d(out_planes, eps=1e-5, momentum=0.01, affine=True) if bn else None
        self.relu = nn.ReLU(inplace=False) if relu else None

    def forward(self, x):
        x = self.conv(x)
        if self.bn is not None:
            x = self.bn(x)
        if self.relu is not None:
            x = self.relu(x)
        return x

class LFIP(nn.Module):

    def __init__(self, in_planes):
        super(LFIP, self).__init__()
        self.iter_ds = Iter_Downsample()
        self.lcb1 = nn.Sequential(
            ConvBlock(in_planes, 128, kernel_size=(3, 3), padding=1), ConvBlock(128, 128, kernel_size=1, stride=1),
            ConvBlock(128, 128, kernel_size=(3, 3), padding=1), ConvBlock(128, 512, kernel_size=1, relu=False))
        self.lcb2 = nn.Sequential(
            ConvBlock(in_planes, 256, kernel_size=(3, 3), padding=1), ConvBlock(256, 256, kernel_size=1),
            ConvBlock(256, 256, kernel_size=(3, 3), padding=1), ConvBlock(256, 256, kernel_size=1, stride=1),
            ConvBlock(256, 256, kernel_size=(3, 3), padding=1), ConvBlock(256, 1024, kernel_size=1, relu=False))
        self.lcb3 = nn.Sequential(
            ConvBlock(in_planes, 128, kernel_size=(3, 3), padding=1), ConvBlock(128, 128, kernel_size=1),
            ConvBlock(128, 128, kernel_size=(3, 3), padding=1), ConvBlock(128, 128, kernel_size=1),
            ConvBlock(128, 128, kernel_size=(3, 3), padding=1), ConvBlock(128, 512, kernel_size=1, relu=False))
        self.lcb4 = nn.Sequential(
            ConvBlock(in_planes, 64, kernel_size=(3, 3), padding=1), ConvBlock(64, 64, kernel_size=1),
            ConvBlock(64, 64, kernel_size=(3, 3),  padding=1), ConvBlock(64, 64, kernel_size=1),
            ConvBlock(64, 64, kernel_size=(3, 3), padding=1), ConvBlock(64, 256, kernel_size=1, relu=False))

    def forward(self, x):
        img1, img2, img3, img4 = self.iter_ds(x)
        s1 = self.lcb1(img1)
        s2 = self.lcb2(img2)
        s3 = self.lcb3(img3)
        s4 = self.lcb4(img4)
        return s1, s2, s3, s4

class Iter_Downsample(nn.Module):

    def __init__(self,):
        super(Iter_Downsample, self).__init__()
        self.init_ds = nn.Sequential(
            nn.MaxPool2d(kernel_size=2, stride=2, padding=0), nn.MaxPool2d(kernel_size=2, stride=2, padding=0))
        self.ds1 = nn.MaxPool2d(kernel_size=2, stride=2, padding=1)
        self.ds2 = nn.MaxPool2d(kernel_size=2, stride=2, padding=0)
        self.ds3 = nn.MaxPool2d(kernel_size=2, stride=2, padding=1)
        self.ds4 = nn.MaxPool2d(kernel_size=2, stride=2, padding=0)

    def forward(self, x):
        x = self.init_ds(x)
        x1 = self.ds1(x)
        x2 = self.ds2(x1)
        x3 = self.ds3(x2)
        x4 = self.ds4(x3)
        return x1, x2, x3, x4

class FAM(nn.Module):

    def __init__(self, plane1, plane2, bn=True, ds=True, att=True):
        super(FAM, self).__init__()
        self.att = att
        self.bn = nn.BatchNorm2d(plane2, eps=1e-5, momentum=0.01, affine=True) if bn else None
        self.dsc = ConvBlock(plane1, plane2, kernel_size=(3, 3), stride=2, padding=1, relu=False) if ds else None
        self.down = ConvBlock(plane2, plane2//2, kernel_size=(1, 1), stride=1)
        self.merge = ConvBlock(plane2, plane2, kernel_size=(3, 3), stride=1, padding=1)
        self.relu = nn.ReLU(inplace=False)

    def forward(self, o, s, p):

        # o_bn = self.bn(o) if self.bn is not None else o
        # s_bn = s
        # if self.att:
        #     x = o_bn * s_bn + self.dsc(p) if self.dsc is not None else o_bn * s_bn
        # else:
        #     x = o_bn + self.dsc(p) if self.dsc is not None else o_bn
        # out = self.merge(self.relu(x))
        #
        # return out

        o_bn = self.bn(o) if self.bn is not None else o
        s_bn = s
        if self.att:
            # o_bn = self.down(o_bn)
            # s_bn = self.down(s_bn)
            x = o_bn + s_bn + self.dsc(p) if self.dsc is not None else o_bn + s_bn
            # x = torch.cat([o_bn,s_bn], 1) + self.dsc(p) if self.dsc is not None else torch.cat([o_bn,s_bn], 1)

        else:
            x = o_bn + self.dsc(p) if self.dsc is not None else o_bn
        out = self.merge(self.relu(x))

        return out

class SSD300(nn.Module):
    def __init__(self, num_classes, backbone_name, pretrained=False):
        super(SSD300, self).__init__()
        self.num_classes = num_classes
        if backbone_name == "vgg":
            self.vgg = add_vgg(pretrained)
            self.extras = add_extras(1024, backbone_name)
            self.L2Norm = L2Norm(512, 20)

            self.lfip = LFIP(in_planes=3)
            self.Downsampling = Downsampling()

            self.fam1 = FAM(plane1=512, plane2=512, bn=True, ds=False, att=True)
            self.fam2 = FAM(plane1=512, plane2=1024, bn=True, ds=True, att=True)
            self.fam3 = FAM(plane1=1024, plane2=512, bn=False, ds=True, att=True)
            self.fam4 = FAM(plane1=512, plane2=256, bn=False, ds=True, att=False)

            self.eca_attention1 = eca_block(512)
            self.eca_attention2 = eca_block(1025)
            self.eca_attention3 = eca_block(512)
            self.eca_attention4 = eca_block(256)

            self.primary_conv1 = nn.Sequential(
                nn.Conv2d(512, 256, kernel_size=1, stride=1),
                nn.BatchNorm2d(256),
                nn.ReLU(inplace=True)
            )

            self.primary_conv2 = nn.Sequential(
                nn.Conv2d(1024, 512, kernel_size=1, stride=1),
                nn.BatchNorm2d(512),
                nn.ReLU(inplace=True)
            )

            self.primary_conv3 = nn.Sequential(
                nn.Conv2d(512, 256, kernel_size=1, stride=1),
                nn.BatchNorm2d(256),
                nn.ReLU(inplace=True)
            )

            self.primary_conv4 = nn.Sequential(
                nn.Conv2d(256, 128, kernel_size=1, stride=1),
                nn.BatchNorm2d(128),
                nn.ReLU(inplace=True)
            )

            self.cheap_operation1 = nn.Sequential(
                nn.Conv2d(256, 256, kernel_size=3, padding=1, groups=256, bias=False),
                nn.BatchNorm2d(256),
                nn.ReLU(inplace=True)
            )

            self.cheap_operation2 = nn.Sequential(
                nn.Conv2d(512, 512, kernel_size=3, padding=1, groups=512, bias=False),
                nn.BatchNorm2d(512),
                nn.ReLU(inplace=True)
            )

            self.cheap_operation3 = nn.Sequential(
                nn.Conv2d(256, 256, kernel_size=3, padding=1, groups=256, bias=False),
                nn.BatchNorm2d(256),
                nn.ReLU(inplace=True)
            )

            self.cheap_operation4 = nn.Sequential(
                nn.Conv2d(128, 128, kernel_size=3, padding=1, groups=128, bias=False),
                nn.BatchNorm2d(128),
                nn.ReLU(inplace=True)
            )

            self.down_convg1 = nn.Sequential(
                nn.MaxPool2d(kernel_size=2, stride=2, ceil_mode=True),
                nn.Conv2d(512, 1024, kernel_size=1, stride=1),
                nn.PReLU(1024)
            )

            self.NETconv2d1 = nn.ConvTranspose2d(1024, 512, 2, 2)

            self.down_convg3 = nn.Sequential(
                nn.MaxPool2d(kernel_size=2, stride=2, ceil_mode=True),
                nn.Conv2d(512, 256, kernel_size=1, stride=1),
                nn.PReLU(256)
            )

            self.NETconv2d3 = nn.ConvTranspose2d(256, 512, 2, 2)

            self.pool1234 = nn.MaxPool2d(kernel_size=2, stride=2, ceil_mode=True)

            mbox = [4, 6, 6, 6, 4, 4]

            loc_layers = []
            conf_layers = []
            backbone_source = [21, -2]
            # ---------------------------------------------------#
            #   在add_vgg获得的特征层里
            #   第21层和-2层可以用来进行回归预测和分类预测。
            #   分别是conv4-3(38,38,512)和conv7(19,19,1024)的输出
            # ---------------------------------------------------#
            for k, v in enumerate(backbone_source):
                loc_layers += [nn.Conv2d(self.vgg[v].out_channels, mbox[k] * 4, kernel_size=3, padding=1)]
                conf_layers += [nn.Conv2d(self.vgg[v].out_channels, mbox[k] * num_classes, kernel_size=3, padding=1)]
            # -------------------------------------------------------------#
            #   在add_extras获得的特征层里
            #   第1层、第3层、第5层、第7层可以用来进行回归预测和分类预测。
            #   shape分别为(10,10,512), (5,5,256), (3,3,256), (1,1,256)
            # -------------------------------------------------------------#
            for k, v in enumerate(self.extras[1::2], 2):
                loc_layers += [nn.Conv2d(v.out_channels, mbox[k] * 4, kernel_size=3, padding=1)]
                conf_layers += [nn.Conv2d(v.out_channels, mbox[k] * num_classes, kernel_size=3, padding=1)]
        else:
            self.mobilenet = mobilenet_v2(pretrained).features
            self.extras = add_extras(1280, backbone_name)
            self.L2Norm = L2Norm(96, 20)
            mbox = [6, 6, 6, 6, 6, 6]

            loc_layers = []
            conf_layers = []
            backbone_source = [13, -1]
            for k, v in enumerate(backbone_source):
                loc_layers += [nn.Conv2d(self.mobilenet[v].out_channels, mbox[k] * 4, kernel_size=3, padding=1)]
                conf_layers += [nn.Conv2d(self.mobilenet[v].out_channels, mbox[k] * num_classes, kernel_size=3, padding=1)]
            for k, v in enumerate(self.extras, 2):
                loc_layers += [nn.Conv2d(v.out_channels, mbox[k] * 4, kernel_size=3, padding=1)]
                conf_layers += [nn.Conv2d(v.out_channels, mbox[k] * num_classes, kernel_size=3, padding=1)]

        self.loc = nn.ModuleList(loc_layers)
        self.conf = nn.ModuleList(conf_layers)
        self.backbone_name = backbone_name

    def forward(self, x):
        # ---------------------------#
        #   x是300,300,3
        # ---------------------------#
        sources = list()
        loc = list()
        conf = list()

        # generate image pyramid
        s1, s2, s3, s4 = self.lfip(x)

        a1 = self.primary_conv1(s1)
        b1 = self.cheap_operation1(a1)
        c1 = torch.cat([a1,b1], 1)
        s1 = c1 + s1

        a2 = self.primary_conv2(s2)
        b2 = self.cheap_operation2(a2)
        c2 = torch.cat([a2,b2], 1)
        s2 = c2 + s2

        a3 = self.primary_conv3(s3)
        b3 = self.cheap_operation3(a3)
        c3 = torch.cat([a3,b3], 1)
        s3 = c3 + s3

        a4 = self.primary_conv4(s4)
        b4 = self.cheap_operation4(a4)
        c4 = torch.cat([a4,b4], 1)
        s4 = c4 + s4

        # ---------------------------#
        #   获得conv4_3的内容
        #   shape为38,38,512
        # ---------------------------#
        if self.backbone_name == "vgg":
            for k in range(23):
                x = self.vgg[k](x)
        else:
            for k in range(14):
                x = self.mobilenet[k](x)
        # ---------------------------#
        #   conv4_3的内容
        #   需要进行L2标准化
        # ---------------------------#
        x = self.L2Norm(x)
        f1 = self.fam1(x, s1, None)
        sources.append(f1)

        # ---------------------------#
        #   获得conv7的内容
        #   shape为19,19,1024
        # ---------------------------#
        if self.backbone_name == "vgg":
            for k in range(23, len(self.vgg)):
                x = self.vgg[k](x)
        else:
            for k in range(14, len(self.mobilenet)):
                x = self.mobilenet[k](x)
        f2 = self.fam2(x, s2, f1)
        sources.append(f2)

        # -------------------------------------------------------------#
        #   在add_extras获得的特征层里
        #   第1层、第3层、第5层、第7层可以用来进行回归预测和分类预测。
        #   shape分别为(10,10,512), (5,5,256), (3,3,256), (1,1,256)
        # -------------------------------------------------------------#
        for k, v in enumerate(self.extras):
            x = F.relu(v(x), inplace=True)
            if self.backbone_name == "vgg":
                if k == 1:
                    f3 = self.fam3(x, s3, f2)
                    sources.append(f3)
                elif k == 3:
                    f4 = self.fam4(x, s4, f3)
                    sources.append(f4)
                elif k % 2 == 1:
                    sources.append(x)
            else:
                sources.append(x)

        # 4个有效特征层
        s1 = sources[0]
        s2 = sources[1]
        s3 = sources[2]
        s4 = sources[3]

        s1 = self.eca_attention1(s1)
        s2 = self.eca_attention2(s2)
        s3 = self.eca_attention3(s3)
        s4 = self.eca_attention4(s4)

        g1 = self.down_convg1(s1) # 上采样10->38
        outlayer1 = torch.nn.Sigmoid()  # sigmoid
        g1 = outlayer1(g1)  # sigmoid

        g3 = self.down_convg3(s3)  # 上采样10->38
        outlayer2 = torch.nn.Sigmoid()  # sigmoid
        g3 = outlayer2(g3)  # sigmoid

        pes12 = s2 * g1
        p2 = s2 + pes12
        pes12 = self.NETconv2d1(pes12)
        p1 = s1 - pes12

        pes34 = s4 * g3
        p4 = s4 + pes34
        pes34 = self.NETconv2d3(pes34)
        p3 = s3 - pes34

        #
        p1 = self.eca_attention1(p1)
        p2 = self.eca_attention2(p2)
        p3 = self.eca_attention3(p3)
        p4 = self.eca_attention4(p4)

        sources[0] = p1
        sources[1] = p2
        sources[2] = p3
        sources[3] = p4

        # -------------------------------------------------------------#
        #   为获得的6个有效特征层添加回归预测和分类预测
        # -------------------------------------------------------------#
        for (x, l, c) in zip(sources, self.loc, self.conf):
            loc.append(l(x).permute(0, 2, 3, 1).contiguous())
            conf.append(c(x).permute(0, 2, 3, 1).contiguous())

        # -------------------------------------------------------------#
        #   进行reshape方便堆叠
        # -------------------------------------------------------------#
        loc = torch.cat([o.view(o.size(0), -1) for o in loc], 1)
        conf = torch.cat([o.view(o.size(0), -1) for o in conf], 1)
        # -------------------------------------------------------------#
        #   loc会reshape到batch_size, num_anchors, 4
        #   conf会reshap到batch_size, num_anchors, self.num_classes
        # -------------------------------------------------------------#
        output = (
            loc.view(loc.size(0), -1, 4),
            conf.view(conf.size(0), -1, self.num_classes),
        )
        return output

# if __name__ == '__main__':
#     net =


from django.http import HttpResponse
from django.shortcuts import render
def home(request):
	a=5
	b=6
	c=a+b
	return HttpResponse("HI this is Hello world %s" %c)

# Create your views here.


import sys
sys.setrecursionlimit(10**6)

class Tree:
    def __init__(self, datalist):
        self.data = max(datalist, key=lambda x: x[1])
        leftlist = list(filter(lambda x: x[0] < self.data[0], datalist))
        rightlist = list(filter(lambda x: x[0] > self.data[0], datalist))

        if leftlist != []:
            self.left = Tree(leftlist)
        else:
            self.left = None

        if rightlist != []:
            self.right = Tree(rightlist)
        else:
            self.right = None

def solution(nodeinfo):
    def fix(root,post,pre):
        post.append(root.data)
        if root.left != None:
            fix(root.left,post,pre)

        if root.right != None:
            fix(root.right,post,pre)
        pre.append(root.data)
    answer = []
    root = Tree(nodeinfo)
    post, pre = [], []
    fix(root, post, pre)
    answer.append((list(map(lambda x: nodeinfo.index(x)+1,post))))
    answer.append((list(map(lambda x: nodeinfo.index(x)+1,pre))))
    return answer


#!/usr/bin/python
from bs4 import BeautifulSoup
#import jwplatform
#import json
from selenium import webdriver
import time
#import shutil
#import urllib

def main():

    # Set up the webdriver with extensiosn
    # options = webdriver.ChromeOptions()
    # options.add_extension("./optional-chromedriver-plugins/ublockorigin.crx")
    # options.add_extension("./optional-chromedriver-plugins/blockimages.crx")
    # options.add_extension("./optional-chromedriver-plugins/disableautoplay.crx")
    # driver = webdriver.Chrome(chrome_options=options)
    # driver.get("https://www.kissanime.to/Login")

    #ffprofile = webdriver.FirefoxProfile("./366j48ag.selenium")
    #driver= webdriver.Firefox(firefox_profile=ffprofile)

    #driver.get("https://www.kissanime.ru/Login")

    #time.sleep(5)

    # Get inputs for login + serach -- OUTDATED
    # username = input("Username: ")
#    user_elem = driver.find_element_by_id("username")
#    user_elem.send_keys('pybot')

#    pass_elem = driver.find_element_by_id("password")
#    pass_elem.send_keys('thisisabotthing')

#    driver.find_element_by_id("btnSubmit").click()

    # get keywords to search
    keyword = input("Enter Search Terms: ")
    searchurl = "http://9anime.to/search?keyword=" + keyword
    print("Loading...")

    import requests
    search_request = requests.get(searchurl)
    search_html = search_request.text

    #print(search_html)

    # Send data
#    search_elem = driver.find_element_by_id("keyword")
   # search_elem.send_keys(keyword)

  #  driver.find_element_by_id("imgSearch").click()
    # check if you typed exact anime (kiss will forward to episodes page)

    # parse links
    links = []
    soup = BeautifulSoup(search_html, "html.parser")

    for a in soup.find_all('a', href=True):
        if "/watch/" in a['href']:
            if(a['href'] not in links):
                links.append(a['href'])

    # Get Input
    print("Enter which ones to download:")

    for i in range(0, len(links)):
        print("  " + str(i+1) + "  " + links[i][7:])
    print("--------------------------------------------------")

    num_string = input(">> ")

    # Map input to a list of ints
    nums = map(int, num_string.split(' '))

    #setup driver
    ffprofile = webdriver.FirefoxProfile()
    ffprofile.set_preference("http.response.timeout", 10)
    ffprofile.set_preference("dom.max_script_run_time", 10)
    driver= webdriver.Firefox(firefox_profile=ffprofile)

    # Cycle through the list of ints (Shows)
    for which in nums:
        theName = links[which-1][23:]

        #driver.get("9anime.to" + links[which-1])
        print(links[which-1])
        nexturl = requests.get(links[which-1])

        #find all the episodes
        #soup = BeautifulSoup(driver.page_source, "html.parser")
        soup = BeautifulSoup(nexturl.text, "html.parser")

        episode_links = []

        #parse episode links from html, get this first LEN links
        #  where LEN is the number of episodes in the series
        biggest_ep = -1
        for a in soup.find_all('a', href=True):
            if "/watch/" in a['href'] and "http://" not in a['href']:
                if(int(a['data-base']) > biggest_ep):
                    biggest_ep = int(a['data-base'])
                    episode_links.append(a['href'])

        #episode_links.sort()
        print("Enter which ones to download (Press ENTER for all):")

        for i in range(0, len(episode_links)):
            print("  " + str(i+1) + "  " + episode_links[i])
        print("--------------------------------------------------")

        episodes_in = input(">> ")
        if(episodes_in == ""):
            which_episodes = list(range(1, 1+len(episode_links)))
        else:
            if '-' in episodes_in:
                episode_range = list(map(int, episodes_in.split('-')))
                which_episodes = list(range(episode_range[0], episode_range[1]+1))
            else:
                which_episodes = list(map(int, episodes_in.split(' ')))

        print("Downloading episodes ",  which_episodes)

        # Cycle through the episodes and download one at a time
        for n in which_episodes:
            #driver.get("https://kissanime.ru"+ episode_links[n-1])
            #soup = BeautifulSoup(driver.page_source, "html.parser")

            #episode_req = requests.get("https://9anime.to" + episode_links[n-1], stream=True)

            #get the episode key
        #    splits = episode_links[n-1].split('/')
        #    key = splits[len(splits)-1]

#            print(key)

#            jwclient = jwplatform.Client()
#            epreq = jwclient.videos.show(video_key=key)
            #print(epreq)

            time.sleep(0.1)

            #get the page in driver
            driver.get("http://9anime.to" + episode_links[n-1])

            soup = BeautifulSoup(driver.page_source, "html.parser")

            #return to blank to prevent page load
            driver.get("about:home")

            #thelink = 0
            thelink = soup.find("video").get("src")

            print(thelink)

            #for video in soup.find('div'):
            #    if "redirector.googlevideo.com" in video['src']:
            #        thelink = video['src']
            #        break

            # replace the 'redirector' with a wierd string
            #https://r16---sn-bvvbax-hn26.googlevideo.com/
            #newlink = 'https://r2---sn-bvvbax-hn26' + thelink[18:]

            filename = theName.split(".")[0] + "_" + str(n) + ".mp4"

            print("Downloading " + filename + "...")

            #urllib.request.urlcleanup()
            #req = urllib.request.Request(thelink, headers={'User-Agent': 'Mozilla/4.0'})
            #response = urllib.request.urlopen(req)

            #f = open(filename, "wb")

            #google made things difficult :\
            #r = requests.get(thelink, allow_redirects=True,
            #testfile = urllib.URLopener()
            #testfile.retrieve(thelink, filename)

            user_agent = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.7) Gecko/2009021910 Firefox/3.0.7'

            with open(filename, 'wb') as handle:
                response = requests.get(thelink, allow_redirects=True, stream=True, headers={'user-agent': user_agent})

                if not response.ok:
                    print('something wrong')
                # Something went wrong

                for block in response.iter_content(1024):
                    handle.write(block)

            #f.write(r.content)

    print("Done!")

#end main

if __name__ == "__main__":
    main()


from tkinter import *
import tkinter as tk
from tkinter import ttk
from tkinter import filedialog
import tkinter.messagebox
from tkinter import messagebox
import subprocess
import os
import logic

class Netrecon:
    def __init__(self, master):
        # Frame
        #top = Toplevel()

        top_frame = Frame(master)
        top_frame.pack(side="top", fill="x")

        # Menubar
        menubar = Menu(master)
        file = Menu(menubar, tearoff=0)

        # Frame for buttons
        bottom_frame = Frame(master)
        bottom_frame.pack(side="bottom", fill="x")

        # Display terminal Frame
        main = Frame(master)
        main.pack(fill='both', expand=True)
        self.terminal = Text(main, wrap='word')
        self.terminal.pack(fill='both', expand=True)
        self.terminal1 = Text(main, height=10, width=30, wrap='word')
        self.terminal1.pack(fill='both', expand=True)

        # Entry
        self.entry = Entry(master)
        self.entry.pack(side='top', fill='x')

        # Function Buttons
        nmap_button = Button(top_frame, text="Network Scan", command=self.nmap)
        nmap_button.pack(side='left')
        searchsploit_button = Button(top_frame, text="Exploit_db", command=self.searchsploit)
        searchsploit_button.pack(side='right')
        discover_button = Button(top_frame, text="Discover", command=self.netdiscover)
        discover_button.pack(side='left')
        dns_button = Button(top_frame, text="Test", command=self.ping)
        dns_button.pack(side='left')

        # Additional Buttons
        open_file_button = Button(bottom_frame, text="Open File", command=self.open)
        open_file_button.pack(side='right')
        save_button = Button(bottom_frame, text="Save", command=self.save)
        save_button.pack(side='left')
        clear_button = ttk.Button(bottom_frame, text="Clear", command=self.clear_output)
        clear_button.pack(side='left')

        # Menubar label
        file.add_command(label="Open", command=self.open)
        file.add_command(label="Save", command=self.save)
        file.add_command(label="Clear", command=self.clear_output)
        file.add_separator()
        file.add_command(label="Exit", command=master.quit)
        menubar.add_cascade(label="File", menu=file)

    def nmap(self):
        target = self.entry.get()
        output = logic.run_nmap(target)
        self.terminal.insert('end', output)

    def ping(self):
        target = self.entry.get()
        output = logic.run_ping(target)
        self.terminal.insert('end', output)

    def searchsploit(self):
        target = self.entry.get()
        output = logic.run_searchsploit(target)
        self.terminal.insert('end', output)

    def netdiscover(self):
        target = self.entry.get()
        output = logic.run_netdiscover(target)
        self.terminal.insert('end', output)

    def save(self):
        file_path = filedialog.asksaveasfilename(defaultextension=".txt")
        if file_path:
            with open(file_path, "w") as f:
                f.write(self.terminal.get("1.0", "end"))
                f.write(self.terminal1.get("1.0", "end"))
            tkinter.messagebox.showinfo("Info", "File saved successfully")
        else:

            tkinter.messagebox.showinfo("Error", "Failed to save file.")

    #Open file function
    def open(self):
        file_path = filedialog.askopenfilename(defaultextension=".txt",
                                               filetypes=[("Text Files", "*.txt"),
                                                          ("All Files", "*.*")])
        try:
            with open(file_path, "r") as file:
                contents = file.read()
                self.terminal1.insert("end", contents)
        except:
            messagebox.showerror("Error", "Could not open the file.")
    #Clear terminal function
    def clear_output(self):
        self.terminal.delete("1.0", "end")
        self.terminal1.delete("1.0", "end")

root = Tk()
root.title("NetReconTool")
window = Netrecon(root)
root.mainloop()


import pandas as pd

def df_rescale_meanzero(data, retain=None):

    '''ZERO MEAN SCALER
    Takes in a dataframe or series, and rescales features
    so that mean for each feature becomes 0 and standard
    deviation becomes 1.
    USE
    ===
    mean_zero(df[['Age','Fare','Pclass']],retain='Pclass')
    PARAMETERS
    ==========
    data :: pandas dataframe or series object
    retain :: if some column should be excluded from rescaling
    '''
    # avoiding transformation of y, labels, etc
    try:
        data = data.copy(deep=True)
    except TypeError:
        data = pd.DataFrame(data)
        is_array = True

    try:
        col_list = list(data.columns)
    except AttributeError:
        col_list = list(pd.DataFrame(data.columns))

    if retain is not None:
        col_list.remove(retain)

    numeric = data.select_dtypes(exclude=['int', 'float'])
    numeric = list(numeric.columns)

    for col in numeric:
        col_list.remove(col)

    for col in col_list:

        # storing the temp values
        data_mean = data[col].mean(axis=0)
        data_std = data[col].std(axis=0)

        # transforming the data
        col_data = data[col] - data_mean
        data[col] = col_data / data_std

    try:
        is_array is True
        return data.values
    except UnboundLocalError:
        return data


import os
import argparse
import logging
import time
import numpy as np
import numpy.random as npr
import matplotlib

matplotlib.use("agg")
import matplotlib.pyplot as plt
import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F
import datetime

parser = argparse.ArgumentParser()
parser.add_argument("--adjoint", type=eval, default=True)
parser.add_argument("--visualize", type=eval, default=True)
parser.add_argument("--niters", type=int, default=2000)
parser.add_argument("--lr", type=float, default=0.01)
parser.add_argument("--gpu", type=int, default=0)
parser.add_argument("--noise", type=int, default=0.15)
parser.add_argument("--end_time", type=int, default=40)
parser.add_argument("--samples", type=int, default=100)
parser.add_argument("--async_data", type=int, default=True)
parser.add_argument("--vis_freq", type=int, default=10)
args = parser.parse_args()

# Another way of calculating the gradients
if args.adjoint:
    from torchdiffeq import odeint_adjoint as odeint
else:
    from torchdiffeq import odeint

def curve_function(timestamps, func_type):
    if func_type == 0:
        return np.sin(timestamps) * np.exp(-0.1 * timestamps)
    elif func_type == 1:
        return np.cos(0.5 * timestamps) * np.exp(-0.05 * timestamps)

def generate_curve(
    func_type,
    ncurves=1000,
    ntotal=500,
    nsample=100,
    start=0.0,
    stop=40,
    noise_std=0.1,
    savefig=True,
    async_data=True,
):
    """ Generate one curve
    Args:
      nspiral: number of spirals, i.e. batch dimension
      ntotal: total number of datapoints per spiral
      nsample: number of sampled datapoints for model fitting per spiral
      start: spiral starting theta value
      stop: spiral ending theta value
      noise_std: observation noise standard deviation
      a, b: parameters of the Archimedean spiral
      savefig: plot the ground truth for sanity check.

      Returns:
        Tuple where first element is true trajectory of size (nspiral, ntotal, 2),
        second element is noisy observations of size (nspiral, nsample, 2),
        third element is timestamps of size (ntotal,),
        and fourth element is timestamps of size(nsample,) """
    if async_data:
        # Create async. time tensor
        time_rnd = np.random.random_sample(nsample)
        time_rnd = np.sort(time_rnd)
        time_rnd = time_rnd * stop
        time = time_rnd
    else:
        # Or sync. time tensor
        time = np.linspace(0, stop, nsample)

    # Make sure that starting time 0 is the first time
    time[0] = 0.0
    # Create cont. time tensor
    time_cont = np.linspace(0, stop, ntotal)

    # Generate continuous y values
    true_y_cont = curve_function(time_cont, func_type)

    # Generate noisy y values
    dt = time[1:nsample] - time[0 : nsample - 1]
    dt = np.insert(dt, 0, 0)
    true_y_dt = []
    for _ in range(ncurves):
        noise = args.noise * (np.random.rand(nsample) - 0.5) * 2
        new_true_y = curve_function(time, func_type) + noise
        # One of the inputs is the diff. in time between points.
        new_true_dt = dt
        new_true_y_dt = np.stack((new_true_y, new_true_dt), axis=1)
        true_y_dt.append(new_true_y_dt)

    true_y_dt = np.asarray(true_y_dt)
    return true_y_cont, true_y_dt, time_cont, time

def create_plot():
    # Create plot
    if args.visualize:
        figSamp = plt.figure(figsize=(12, 4), facecolor="white")
        ax_traj_samp = figSamp.add_subplot(132, frameon=False)
        ax_traj_samp.cla()  # Clears
        ax_traj_samp.set_title("Ground Truth N' Samples")
        ax_traj_samp.set_xlabel("Time")
        ax_traj_samp.set_ylabel("Curves")
        return figSamp, ax_traj_samp

def plot_data(fig, subplt, y_values, timestamps, line_type, label_name):
    plt.plot(timestamps, y_values, line_type, label=label_name)
    fig.tight_layout()
    plt.legend()
    plt.draw()

# Plot some of the sensors timestamps vs each other
height_async_data = 0

def plot_unsync_sensors(timestamps, label_name):
    global height_async_data
    plt.plot(
        timestamps, height_async_data * np.ones(timestamps.size), "o", label=label_name
    )
    plt.ylim(-0.05, 2 * height_async_data)
    plt.legend()
    plt.draw()
    height_async_data += 0.05

def save_plot(file_name):
    plt.savefig("latent_ode_sync_fig/" + file_name + ".png", dpi=500)

# NODE in the latent space
class LatentNode(nn.Module):
    def __init__(self, latent_dim=4, nhidden=20):
        super(LatentNode, self).__init__()
        self.elu = nn.ELU(inplace=True)
        self.fc1 = nn.Linear(latent_dim, nhidden)
        self.fc2 = nn.Linear(nhidden, nhidden)
        self.fc3 = nn.Linear(nhidden, latent_dim)
        self.nfe = 0

    def forward(self, t, x):
        self.nfe += 1
        out = self.fc1(x)
        out = self.elu(out)
        out = self.fc2(out)
        out = self.elu(out)
        out = self.fc3(out)
        return out

# Bringing input in Y domain to lantent space Z with RNN
class RnnEncoder(nn.Module):
    def __init__(self, latent_dim=4, obs_dim=2, nhidden=25, nbatch=1):
        super(RnnEncoder, self).__init__()
        self.nhidden = nhidden
        self.batch = nbatch
        self.input_to_hidden = nn.Linear(obs_dim + nhidden, nhidden)
        self.hidden_to_output = nn.Linear(nhidden, latent_dim * 2)

    def forward(self, x, h):
        combined = torch.cat((x, h), dim=1)
        hidden_state = torch.tanh(self.input_to_hidden(combined))
        out = self.hidden_to_output(hidden_state)
        return out, hidden_state

    def init_hidden_state(self):
        return torch.zeros(self.batch, self.nhidden)

# Since NODE are space preserving we need to decode.
# Brings new points in latent Z space to Y space.
class Decoder(nn.Module):
    def __init__(self, latent_dim=4, obs_dim=3, nhidden=20):
        super(Decoder, self).__init__()
        self.relu = nn.ReLU(inplace=True)
        self.fc1 = nn.Linear(latent_dim, nhidden)
        self.fc2 = nn.Linear(nhidden, obs_dim)

    def forward(self, z):
        out = self.fc1(z)
        out = self.relu(out)
        out = self.fc2(out)
        return out

# Calculating average loss for better overview of training
class RunningAverageMeter(object):
    """Computes and stores the average and current value"""

    def __init__(self, momentum=0.99):
        self.momentum = momentum
        self.reset()

    def reset(self):
        self.val = None
        self.avg = 0

    def update(self, val):
        if self.val is None:
            self.avg = val
        else:
            self.avg = self.avg * self.momentum + val * (1 - self.momentum)
        self.val = val

# Creating a pick from logarithmic normal probability distribution
# Basically providing the log of a relative likelihood that the value of the
# random variable would equal that sample.(wikipedia: Probability density function)
def log_normal_prob_dist(x, mean, logvar):
    const = torch.from_numpy(np.array([2.0 * np.pi])).float().to(x.device)
    const = torch.log(const)
    return -0.5 * (const + logvar + (x - mean) ** 2.0 / torch.exp(logvar))

# Kullback-Leibler divergence between a diagonal multivariate normal,
# and a normal distribution with specified mu and logvar.
# (Wikipedia: Kullback-Leibler Divergence, examples: Multivariate normal distribution)
def kullback_leibler_divergence_normaldist(mu1, lv1, mu2, lv2):
    v1 = torch.exp(lv1)
    v2 = torch.exp(lv2)
    lstd1 = lv1 / 2.0
    lstd2 = lv2 / 2.0

    kl = lstd2 - lstd1 + ((v1 + (mu1 - mu2) ** 2.0) / (2.0 * v2)) - 0.5
    return kl

# Combine timestamps into a single tensor
def combine_timestamps(t1, t2):
    t1 = t1.cpu().numpy()
    t2 = t2.cpu().numpy()
    indx1 = []
    indx2 = []
    combine_timestamps = np.concatenate((t1, t2), axis=0)
    combine_timestamps.sort()
    # Remove one of the common timepoints 0.0
    combine_timestamps = np.delete(combine_timestamps, 0)
    # Find index for the both original time tensors t1 and t2
    boolean_match1 = np.in1d(combine_timestamps, t1)
    boolean_match2 = np.in1d(combine_timestamps, t2)
    indx = np.linspace(0, combine_timestamps.size - 1, combine_timestamps.size)
    indx_t1 = indx[boolean_match1]
    indx_t2 = indx[boolean_match2]
    indx_t1 = indx_t1.astype(int)
    indx_t2 = indx_t2.astype(int)
    return combine_timestamps, indx_t1, indx_t2

# Fills in the holes in the original data
def forward_rnn_data(pred_x_A, pred_x_B, time_indx_A, time_indx_B, true_y_A, true_y_B):
    pred_x_A[:, time_indx_A] = true_y_A
    pred_x_B[:, time_indx_B] = true_y_B
    return pred_x_A, pred_x_B

if __name__ == "__main__":
    latent_dim_total = 4
    latent_dim_sensors = 2
    nhidden = 20
    rnn_nhidden = 25
    obs_dim_total = 2  # A and B sensors
    obs_dim_sensors = 2  # Sensor value and dt
    ncurves = 1000
    noise_std = 0.3
    device = torch.device(
        "cuda:" + str(args.gpu) if torch.cuda.is_available() else "cpu"
    )
    # Create folder if vis is true
    current_time = datetime.datetime.now()
    str_current_day = (
        str(current_time.year)
        + "_"
        + str(current_time.month)
        + "_"
        + str(current_time.day)
        + "_"
        + str(current_time.hour)
        + "_"
        + str(current_time.minute)
    )
    directory_name = "async_unsync_" + str_current_day
    if not os.path.exists(directory_name):
        os.makedirs(directory_name)

    # Generate two curves with different time vectors
    # Plot ground truth
    true_y_cont_A, true_y_dt_A, time_cont_A, time_A = generate_curve(func_type=0, ncurves=ncurves)
    fig, subplt = create_plot()
    plot_data(fig, subplt, true_y_cont_A, time_cont_A, "-", "Cont. A")
    true_y_cont_B, true_y_dt_B, time_cont_B, time_B = generate_curve(func_type=1, ncurves=ncurves)
    plot_data(fig, subplt, true_y_cont_B, time_cont_B, "-", "Cont. B")
    plot_data(fig, subplt, true_y_dt_A[0, :, 0], time_A, "o", "Samples A")
    plot_data(fig, subplt, true_y_dt_B[0, :, 0], time_B, "o", "Samples B")
    save_plot("ground_truth_samples")

    # Plot a sample to see the unsync. curves
    sample_A = time_A[0:10]
    sample_B = time_B[0:10]
    fig_time, subplt_time = create_plot()
    plot_unsync_sensors(sample_A, "Sensor A")
    plot_unsync_sensors(sample_B, "Sensor B")
    save_plot("unsync_sensors")

    # Make data into torch tensors at GPU, if possible
    true_y_cont_A = torch.from_numpy(true_y_cont_A).float().to(device)
    true_y_dt_A = torch.from_numpy(true_y_dt_A).float().to(device)
    time_cont_A = torch.from_numpy(time_cont_A).float().to(device)
    time_A = torch.from_numpy(time_A).float().to(device)
    true_y_A = true_y_dt_A[:, :, 0]

    true_y_cont_B = torch.from_numpy(true_y_cont_B).float().to(device)
    true_y_dt_B = torch.from_numpy(true_y_dt_B).float().to(device)
    time_cont_B = torch.from_numpy(time_cont_B).float().to(device)
    time_B = torch.from_numpy(time_B).float().to(device)
    true_y_B = true_y_dt_B[:, :, 0]

    # Fetching the common timestamps from sensors for prediction
    # Calculates the dt for forward rnn
    common_timestamps, time_indx_A, time_indx_B = combine_timestamps(time_A, time_B)
    common_timestamps = torch.from_numpy(common_timestamps).float().to(device)
    size = common_timestamps.size(0)
    common_dt = common_timestamps[1:size] - common_timestamps[0 : size - 1]
    common_dt = common_dt.cpu()
    common_dt = np.insert(common_dt, 0, 0)
    common_dt = torch.ones((ncurves, args.samples * 2 - 1)) * common_dt
    common_dt = common_dt.to(device)

    # Create models
    latent_node = LatentNode(latent_dim_total, nhidden).to(device)
    latent_node_fwd = LatentNode(latent_dim_total, nhidden).to(device)
    rnn_encoder_A = RnnEncoder(
        latent_dim_sensors, obs_dim_sensors, rnn_nhidden, ncurves
    ).to(device)
    rnn_encoder_B = RnnEncoder(
        latent_dim_sensors, obs_dim_sensors, rnn_nhidden, ncurves
    ).to(device)
    decoder = Decoder(latent_dim_total, obs_dim_total, nhidden).to(device)
    decoder_fwd = Decoder(latent_dim_total, obs_dim_total, nhidden).to(device)
    rnn_encoder_forw = RnnEncoder(
        latent_dim_total, obs_dim_total + 1, rnn_nhidden, ncurves
    ).to(device)
    params = (
        list(latent_node.parameters())
        + list(rnn_encoder_A.parameters())
        + list(rnn_encoder_B.parameters())
        + list(decoder.parameters())
    )
    optimizer = optim.Adam(params, lr=args.lr)
    # optimizer = optim.RMSprop(params, lr=1e-3)
    loss_meter = RunningAverageMeter()

    for itr in range(1, args.niters + 1):
        optimizer.zero_grad()
        # Run backwards in time through encoder for both A and B sensor
        h_A = rnn_encoder_A.init_hidden_state().to(device)
        h_B = rnn_encoder_B.init_hidden_state().to(device)

        training_times_A = reversed(range(int(np.trunc(true_y_dt_A.size(1)))))
        training_times_B = reversed(range(int(np.trunc(true_y_dt_B.size(1)))))
        # Run through sensor A
        for t in training_times_A:
            obs_A = true_y_dt_A[:, t, :]
            out_A, h_A = rnn_encoder_A.forward(obs_A, h_A)
        # picking out mean and log variance for A sensor
        qz0_mean_A, qz0_logvar_A = (
            out_A[:, :latent_dim_sensors],
            out_A[:, latent_dim_sensors:],
        )

        # Run through sensor B
        for t in training_times_B:
            obs_B = true_y_dt_B[:, t, :]
            out_B, h_B = rnn_encoder_B.forward(obs_B, h_B)
        # picking out mean and log variance for B sensor
        qz0_mean_B, qz0_logvar_B = (
            out_B[:, :latent_dim_sensors],
            out_B[:, latent_dim_sensors:],
        )

        qz0_mean_comb = torch.cat((qz0_mean_A, qz0_mean_B), dim=1)
        qz0_logvar_comb = torch.cat((qz0_logvar_A, qz0_logvar_B), dim=1)
        epsilon = torch.randn(qz0_mean_comb.size()).to(device)
        z0 = epsilon * torch.exp(0.5 * qz0_logvar_comb) + qz0_mean_comb

        # Sending z0 to odeint to integrate 'sample' timesteps forward
        # Permute just permutes the tensor.

        pred_z = odeint(latent_node, z0, common_timestamps).permute(1, 0, 2)
        pred_x = decoder(pred_z)

        # We can only correct our predictions against known values
        # so we pick out the known values from pred_x_A and _B
        pred_x_A = pred_x[:, :, 0]
        pred_x_B = pred_x[:, :, 1]
        pred_x_A_known = pred_x_A[:, time_indx_A]
        pred_x_B_known = pred_x_B[:, time_indx_B]

        # Compute loss
        # First create noise as log var then call log_normal_pdf
        # samp_trajs acts as our x, pred_x as our mean i.o.w mu, noise_logvar as our logvar
        # Create logpx for A and B sensors
        noise_std_A = torch.zeros(pred_x_A_known.size()).to(device) + noise_std
        noise_std_B = torch.zeros(pred_x_B_known.size()).to(device) + noise_std
        noise_logvar_A = 2.0 * torch.log(noise_std_A).to(device)
        noise_logvar_B = 2.0 * torch.log(noise_std_B).to(device)

        logpx_A = log_normal_prob_dist(true_y_A, pred_x_A_known, noise_logvar_A).sum(-1)
        logpx_B = log_normal_prob_dist(true_y_B, pred_x_B_known, noise_logvar_B).sum(-1)

        pz0_mean = pz0_logvar = torch.zeros(z0.size()).to(device)
        analytic_kl = kullback_leibler_divergence_normaldist(
            qz0_mean_comb, qz0_logvar_comb, pz0_mean, pz0_logvar
        ).sum(-1)

        # Take the original data and fill in the gaps with predictions
        pred_true_A, pred_true_B = forward_rnn_data(
            pred_x_A, pred_x_B, time_indx_A, time_indx_B, true_y_A, true_y_B
        )
        # We also need to create a dt vector
        pred_true_AB = torch.stack((pred_true_A, pred_true_B, common_dt), dim=2)

        # #We also need to create a guidance of the rnn_encoder_forw and decoder to generalize better
        # h_forward = rnn_encoder_forw.init_hidden_state().to(device)
        # pred_true_AB_samples = pred_true_AB[:, 0 : args.samples, :]
        # max_time = int(np.trunc(pred_true_AB_samples.size(1)))
        # random_stop_time = np.random.randint(low=0, high=max_time, size=1)[0]
        # training_times_forward = range(random_stop_time)

        # for t in training_times_forward:
        #     obs_forward = pred_true_AB_samples[:, t, :]
        #     out_forward, h_forward = rnn_encoder_forw.forward(obs_forward, h_forward)
        # # picking out mean and log variance
        # qz0_mean_forward, qz0_logvar_forward = (
        #     out_forward[:, :latent_dim_total],
        #     out_forward[:, latent_dim_total:],
        # )

        # epsilon = torch.randn(qz0_mean_forward.size()).to(device)
        # z0 = epsilon * torch.exp(0.5 * qz0_logvar_forward) + qz0_mean_forward

        # y0 = decoder(z0)
        # y0_correct = pred_true_AB[:, random_stop_time-1, 0:2]
        # loss_enc_dec = (y0 - y0_correct).sum(-1)

        loss = torch.mean(
            (-logpx_A) + (-logpx_B) + analytic_kl,
            dim=0,
        )
        #+ loss_enc_dec   - Can be added to loss for training encoder decoder
        loss.backward()
        optimizer.step()
        loss_meter.update(loss.item())
        print("Iter: {}, running avg elbo: {:.4f}".format(itr, -loss_meter.avg))

        #
        if args.visualize and itr % args.vis_freq == 0:
            print("vizing")
            with torch.no_grad():

                h_A = rnn_encoder_A.init_hidden_state().to(device)
                h_B = rnn_encoder_B.init_hidden_state().to(device)

                training_times_A = reversed(range(int(np.trunc(true_y_dt_A.size(1)))))
                training_times_B = reversed(range(int(np.trunc(true_y_dt_B.size(1)))))
                # Run through sensor A
                for t in training_times_A:
                    obs_A = true_y_dt_A[:, t, :]
                    out_A, h_A = rnn_encoder_A.forward(obs_A, h_A)
                # picking out mean and log variance for A sensor
                qz0_mean_A, qz0_logvar_A = (
                    out_A[:, :latent_dim_sensors],
                    out_A[:, latent_dim_sensors:],
                )

                # Run through sensor B
                for t in training_times_B:
                    obs_B = true_y_dt_B[:, t, :]
                    out_B, h_B = rnn_encoder_B.forward(obs_B, h_B)
                # picking out mean and log variance for B sensor
                qz0_mean_B, qz0_logvar_B = (
                    out_B[:, :latent_dim_sensors],
                    out_B[:, latent_dim_sensors:],
                )

                qz0_mean_comb = torch.cat((qz0_mean_A, qz0_mean_B), dim=1)
                qz0_logvar_comb = torch.cat((qz0_logvar_A, qz0_logvar_B), dim=1)
                epsilon = torch.randn(qz0_mean_comb.size()).to(device)
                z0 = qz0_mean_comb

                # Saving prediction to file
                pred_z_all = odeint(latent_node, z0, time_cont_A)
                pred_x_all = decoder(pred_z_all)
                print("saving files")
                torch.save(pred_x_all, directory_name + "/pred_x_all"+str(itr)+".pt")
                torch.save(time_cont_A, directory_name + "/time_all"+str(itr)+".pt")
                print("files saved")

                # Sending z0 to odeint to integrate 'sample' timesteps forward
                # Permute just permutes the tensor.
                # First traject for vis.
                z0 = z0[0]
                pred_z = odeint(latent_node, z0, time_cont_A)
                pred_x = decoder(pred_z)

                # Predicting into the future with rnn forward!
                h_forward = rnn_encoder_forw.init_hidden_state().to(device)
                pred_times_forward = range(args.samples-1)
                pred_true_AB_dt_correct = pred_true_AB[:, args.samples : args.samples * 2 - 1, :]
                for t in pred_times_forward:
                    obs_forward = pred_true_AB_dt_correct[:, t, :]
                    out_forward, h_forward = rnn_encoder_forw.forward(obs_forward, h_forward)
                # picking out mean and log variance
                qz0_mean_forward, qz0_logvar_forward = (
                    out_forward[:, :latent_dim_total],
                    out_forward[:, latent_dim_total:],
                )

                epsilon = torch.randn(qz0_mean_forward.size()).to(device)
                #z0 = epsilon * torch.exp(0.5 * qz0_logvar_forward) + qz0_mean_forward
                z0 = qz0_mean_forward
                z0 = z0[0]
                # Creating time vector of timepoints we want to evaluate in the untrained half
                # Picks out the times from the first timepoint after we stopped the RNN forward
                # and then subtracts the time at which we stopped.
                t_forward_pred = torch.linspace(0,args.end_time,steps=100)

                pred_z = odeint(latent_node, z0, t_forward_pred)
                pred_x_forward = decoder(pred_z)

                plt.figure()
                plt.plot(
                    time_cont_A.cpu().detach().numpy(),
                    pred_x.cpu().detach().numpy(),
                    label="Predictions Back-RNN",
                )
                plt.plot(
                    time_cont_A.cpu().detach().numpy(),
                    true_y_cont_A.cpu().detach().numpy(),
                    label="Ground truth A",
                )
                plt.plot(
                    time_cont_B.cpu().detach().numpy(),
                    true_y_cont_B.cpu().detach().numpy(),
                    label="Ground truth B",
                )
                #plt.plot((t_forward_pred+args.end_time).cpu().detach().numpy(), pred_x_forward.cpu().detach().numpy(), '-', label="RNN forward prediction")
                plt.axvspan(0, 20, facecolor="b", alpha=0.5)
                plt.legend()
                plt.draw()
                plt.savefig(
                    directory_name+"/ground_truth_with_pred" + str(itr) + ".png",
                    dpi=500,
                )
                plt.close()

    params = (
        list(latent_node_fwd.parameters())
        + list(rnn_encoder_forw.parameters())
        + list(decoder_fwd.parameters())
    )
    optimizer = optim.Adam(params, lr=args.lr)
    # optimizer = optim.RMSprop(params, lr=1e-3)
    loss_meter = RunningAverageMeter()
    pred_true_AB = pred_true_AB.detach()
    common_timestamps = common_timestamps.detach()
    print("****Beginning forward training****")
    for itr in range(1, args.niters + 1):
        optimizer.zero_grad()
        # Only take half of the samples to run forward rnn over so
        # we have some space for prediction.
        pred_true_AB_samples = pred_true_AB[:, 0 : args.samples, :]
        # *2-1 cause we have a common point in both sensors, t=0
        rnd_stop = int(np.random.rand(1)*(args.samples-10))+10
        pred_true_AB_correct = pred_true_AB[:, rnd_stop : args.samples * 2 - 1, 0:2]
        h_forward = rnn_encoder_forw.init_hidden_state().to(device)
        training_times_forward = range(rnd_stop)

        for t in training_times_forward:
            obs_forward = pred_true_AB_samples[:, t, :]
            out_forward, h_forward = rnn_encoder_forw.forward(obs_forward, h_forward)
        # picking out mean and log variance
        qz0_mean_forward, qz0_logvar_forward = (
            out_forward[:, :latent_dim_total],
            out_forward[:, latent_dim_total:],
        )

        epsilon = torch.randn(qz0_mean_forward.size()).to(device)
        z0 = epsilon * torch.exp(0.5 * qz0_logvar_forward) + qz0_mean_forward
        # Creating time vector of timepoints we want to evaluate in the untrained half
        # Picks out the times from the first timepoint after we stopped the RNN forward
        # and then subtracts the time at which we stopped.
        t_forward_odeint = common_timestamps[rnd_stop : common_timestamps.size(0)]
        t_forward_odeint = t_forward_odeint - common_timestamps[rnd_stop - 1]

        pred_z = odeint(latent_node_fwd, z0, t_forward_odeint).permute(1, 0, 2)
        pred_x = decoder_fwd(pred_z)

        noise_std_forward = torch.zeros(pred_x.size()).to(device) + noise_std
        noise_logvar_forward = 2.0 * torch.log(noise_std_forward).to(device)

        logpx_forward = log_normal_prob_dist(
            pred_true_AB_correct, pred_x, noise_logvar_forward
        ).sum(-1).sum(-1)

        pz0_mean = pz0_logvar = torch.zeros(z0.size()).to(device)
        analytic_kl_forward = kullback_leibler_divergence_normaldist(
            qz0_mean_forward, qz0_logvar_forward, pz0_mean, pz0_logvar
        ).sum(-1)

        loss = torch.mean(
            (-logpx_forward) + analytic_kl_forward,
            dim=0,
        )
        #+ loss_enc_dec   - Can be added to loss for training encoder decoder
        loss.backward()
        optimizer.step()
        loss_meter.update(loss.item())
        print("Iter: {}, running avg elbo: {:.4f}".format(itr, -loss_meter.avg))

        if args.visualize and itr % args.vis_freq == 0:
            print("vizing")
            with torch.no_grad():

                h_A = rnn_encoder_A.init_hidden_state().to(device)
                h_B = rnn_encoder_B.init_hidden_state().to(device)

                training_times_A = reversed(range(int(np.trunc(true_y_dt_A.size(1)))))
                training_times_B = reversed(range(int(np.trunc(true_y_dt_B.size(1)))))
                # Run through sensor A
                for t in training_times_A:
                    obs_A = true_y_dt_A[:, t, :]
                    out_A, h_A = rnn_encoder_A.forward(obs_A, h_A)
                # picking out mean and log variance for A sensor
                qz0_mean_A, qz0_logvar_A = (
                    out_A[:, :latent_dim_sensors],
                    out_A[:, latent_dim_sensors:],
                )

                # Run through sensor B
                for t in training_times_B:
                    obs_B = true_y_dt_B[:, t, :]
                    out_B, h_B = rnn_encoder_B.forward(obs_B, h_B)
                # picking out mean and log variance for B sensor
                qz0_mean_B, qz0_logvar_B = (
                    out_B[:, :latent_dim_sensors],
                    out_B[:, latent_dim_sensors:],
                )

                qz0_mean_comb = torch.cat((qz0_mean_A, qz0_mean_B), dim=1)
                qz0_logvar_comb = torch.cat((qz0_logvar_A, qz0_logvar_B), dim=1)
                epsilon = torch.randn(qz0_mean_comb.size()).to(device)
                z0 = qz0_mean_comb

                # Sending z0 to odeint to integrate 'sample' timesteps forward
                # Permute just permutes the tensor.
                # First traject for vis.
                z0 = z0[0]
                pred_z = odeint(latent_node, z0, time_cont_A)
                pred_x = decoder(pred_z)

                # Predicting into the future with rnn forward!
                h_forward = rnn_encoder_forw.init_hidden_state().to(device)
                pred_times_forward = range(pred_true_AB.size()[1])
                pred_true_AB_dt_correct = pred_true_AB[:, args.samples : args.samples * 2 - 1, :]
                for t in pred_times_forward:
                    obs_forward = pred_true_AB[:, t, :]
                    out_forward, h_forward = rnn_encoder_forw.forward(obs_forward, h_forward)
                # picking out mean and log variance
                qz0_mean_forward, qz0_logvar_forward = (
                    out_forward[:, :latent_dim_total],
                    out_forward[:, latent_dim_total:],
                )

                epsilon = torch.randn(qz0_mean_forward.size()).to(device)
                #z0 = epsilon * torch.exp(0.5 * qz0_logvar_forward) + qz0_mean_forward
                z0 = qz0_mean_forward
                z0 = z0[0]
                # Creating time vector of timepoints we want to evaluate in the untrained half
                # Picks out the times from the first timepoint after we stopped the RNN forward
                # and then subtracts the time at which we stopped.
                t_forward_pred = torch.linspace(0,args.end_time,steps=100)

                pred_z = odeint(latent_node_fwd, z0, t_forward_pred)
                pred_x_forward = decoder_fwd(pred_z)

                plt.figure()
                plt.plot(
                    time_cont_A.cpu().detach().numpy(),
                    pred_x.cpu().detach().numpy(),
                    label="Predictions Back-RNN",
                )
                plt.plot(
                    time_cont_A.cpu().detach().numpy(),
                    true_y_cont_A.cpu().detach().numpy(),
                    label="Ground truth A",
                )
                plt.plot(
                    time_cont_B.cpu().detach().numpy(),
                    true_y_cont_B.cpu().detach().numpy(),
                    label="Ground truth B",
                )
                plt.plot((t_forward_pred+args.end_time).cpu().detach().numpy(), pred_x_forward.cpu().detach().numpy(), '-', label="RNN forward prediction")
                plt.axvspan(0, 20, facecolor="b", alpha=0.5)
                plt.legend()
                plt.draw()
                plt.savefig(
                    directory_name+"/ground_truth_with_pred_forward" + str(itr) + ".png",
                    dpi=500,
                )
                plt.close()


from typing import List

from odd_models.models import DataSetField, DataSetFieldType, Type
from oddrn_generator import ClickHouseGenerator

from ..domain import Column
from ..grammar_parser.column_type import (
    AggregateFunction,
    Array,
    BasicType,
    DateTime,
    DateTime64,
    LowCardinality,
    Map,
    NamedTuple,
    Nested,
    ParseType,
    Tuple,
)
from ..grammar_parser.parser import parser, traverse_tree
from ..logger import logger
from .types import TYPES_SQL_TO_ODD

def build_dataset_fields(
    columns: list[Column], oddrn_generator: ClickHouseGenerator, table_oddrn_path: str
) -> List[DataSetField]:
    generated_dataset_fields = []
    ds_fields_oddrn = {}

    def _build_dataset_fields(
        column_name: str, column_type: ParseType, parent_oddrn=None
    ):
        logger.debug(
            f"Process {column_name} with type {column_type} and parent {parent_oddrn}"
        )
        column_names = column_name.split(".")
        if parent_oddrn is None:
            oddrn = oddrn_generator.get_oddrn_by_path(
                f"{table_oddrn_path}_columns", column_names[0]
            )
        else:
            oddrn = f"{parent_oddrn}/keys/{column_names[0]}"
        logger.debug(f"Column {column_names[0]} has oddrn {oddrn}")

        if len(column_names) != 1:
            logger.debug(f"Process complex column {column_name}")

            if not column_names[0] in ds_fields_oddrn:
                ds_fields_oddrn[column_names[0]] = oddrn
                generated_dataset_fields.append(
                    DataSetField(
                        oddrn=oddrn,
                        name=column_names[0],
                        type=DataSetFieldType(
                            type=type_to_oddrn_type(column_type),
                            logical_type="Array",
                            is_nullable=False,
                        ),
                        owner=None,
                    )
                )
            else:
                logger.debug(f"Alrady processed {column_names[0]}")
            if isinstance(column_type, Array):
                _build_dataset_fields(
                    column_names[1], column_type.type, ds_fields_oddrn[column_names[0]]
                )
            else:
                logger.debug(
                    f"Expect that in complex structure type starts with 'Array'. Started from {column_type}"
                )
        else:
            if isinstance(column_type, Map):
                generated_dataset_fields.append(
                    DataSetField(
                        oddrn=oddrn,
                        name=column_name,
                        type=DataSetFieldType(
                            type=Type.TYPE_MAP,
                            logical_type=column_type.to_clickhouse_type(),
                            is_nullable=False,
                        ),
                        parent_field_oddrn=parent_oddrn,
                        owner=None,
                    )
                )
                _build_dataset_fields("Key", column_type.key_type, oddrn)
                _build_dataset_fields("Value", column_type.value_type, oddrn)
            elif isinstance(column_type, Nested) or isinstance(column_type, NamedTuple):
                generated_dataset_fields.append(
                    DataSetField(
                        oddrn=oddrn,
                        name=column_name,
                        type=DataSetFieldType(
                            type=Type.TYPE_STRUCT,
                            logical_type=column_type.to_clickhouse_type(),
                            is_nullable=False,
                        ),
                        owner=None,
                        parent_field_oddrn=parent_oddrn,
                    ),
                )
                for field_name, field_type in column_type.fields.items():
                    _build_dataset_fields(field_name, field_type, oddrn)
            elif isinstance(column_type, Tuple):
                generated_dataset_fields.append(
                    DataSetField(
                        oddrn=oddrn,
                        name=column_name,
                        type=DataSetFieldType(
                            type=Type.TYPE_STRUCT,
                            logical_type=column_type.to_clickhouse_type(),
                            is_nullable=False,
                        ),
                        owner=None,
                        parent_field_oddrn=parent_oddrn,
                    ),
                )
                for count, subtype in enumerate(column_type.types):
                    _build_dataset_fields(str(count), subtype, oddrn)
            else:
                odd_type = type_to_oddrn_type(column_type)
                logger.debug(
                    f"Column {column_name} has ODD type {odd_type} and logical type {column_type.to_clickhouse_type()}"
                )
                generated_dataset_fields.append(
                    DataSetField(
                        oddrn=oddrn,
                        name=column_name,
                        type=DataSetFieldType(
                            type=odd_type,
                            logical_type=column_type.to_clickhouse_type(),
                            is_nullable=False,
                        ),
                        owner=None,
                        parent_field_oddrn=parent_oddrn,
                    )
                )

    for column in columns:
        type_tree = parser.parse(column.type)
        column_type = traverse_tree(type_tree)

        _build_dataset_fields(column.name, column_type)

    return generated_dataset_fields

def type_to_oddrn_type(column_type: ParseType) -> Type:
    if isinstance(column_type, Array):
        return Type.TYPE_LIST
    elif isinstance(column_type, Nested):
        return Type.TYPE_STRUCT
    elif isinstance(column_type, Map):
        return Type.TYPE_MAP
    elif isinstance(
        column_type,
        (BasicType, DateTime, DateTime64, LowCardinality, AggregateFunction),
    ):
        return TYPES_SQL_TO_ODD.get(column_type.type_name, Type.TYPE_UNKNOWN)
    elif isinstance(column_type, str):
        return TYPES_SQL_TO_ODD.get(column_type, Type.TYPE_UNKNOWN)
    elif isinstance(column_type, Tuple):
        return Type.TYPE_STRUCT
    elif isinstance(column_type, NamedTuple):
        return Type.TYPE_STRUCT
    else:
        return Type.TYPE_UNKNOWN


import traceback, functools, itertools, cmath, math, collections, re, operator

# 2020 question 10
n = '.\Concrete\Concrete'
fail = ''

def split(x):
    return x.split('\n')

def parse(x):
    # convert to list of ints
    x = x.split(', ')
    x = list(map(lambda a: int(a), x))
    return x

def solve(x):
    # pretty much just applying the formulas as they said to
    # we initially forgot the ceil (round up to nearest int) and floor (round down to nearest int)
    weight, width = x
    w = math.ceil(weight / width * 1.75)
    d = math.floor(weight/w + width/2)
    a = math.ceil(w * w * d / (12 ** 3) / .45)
    return w, d, a

def format(x):
    return ', '.join(map(lambda s: str(s), x))

def join(x):
    return '\n'.join(x)

sols = list()
for case in split(open(n + 'In.txt').read()):
    try:
        temp = solve(parse(case))
        sol = (format(temp), fail)[temp == None]
    except:
        print('Err on ' + str(case))
        print(traceback.format_exc())
        sol = fail
    else:
        print(sol)
    sols.append(sol)
open(n + 'Out.txt', 'w').write(join(sols))


from libsvm.svmutil import *
from libsvm.svm import *
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib as mpl
import seaborn as sns

mpl.rcParams['font.sans-serif'] = ['Microsoft YaHei']  # 指定默认字体
mpl.rcParams['axes.unicode_minus'] = False  # 解决保存图像时负号'-'显示为方块的问题

def list_of_dict_to_list_of_list(list_of_dict: list) -> list:
    """
    将元素为字典的列表转换成元素为列表的列表，仅取value

    Args:
        list_of_dict (list): 元素为字典的列表

    Returns:
        list: 元素为列表的列表
    """
    list_of_list = [[v for v in d.values()] for d in list_of_dict]
    return list_of_list

def get_dividing_point(y: list):
    """
    找出不同样例的分界点

    Args:
        y (list): 数据标签

    Returns:
        int: -1表示全部相同，否则表示分界点

    """
    last = y[0]
    for i, yi in enumerate(y):
        if yi != last:
            return i
        else:
            last = yi
    return -1

def scatter_training_set(x: list, y: list, axes):
    """
    绘制训练集散点图

    Args:
        x (list): 数据特征
        y (list): 数据标签
        axes (matplotlib.axes._base._AxesBase): 要绘图的Axes实例

    Returns:
        None
    """
    x_array = np.array(list_of_dict_to_list_of_list(x))
    x1 = x_array[:, 0]
    x2 = x_array[:, 1]
    dividing_point = get_dividing_point(y)
    axes.scatter(x1[:dividing_point], x2[:dividing_point])
    axes.scatter(x1[dividing_point:], x2[dividing_point:])

def leave_one_out(x: list, y: list, param_str: str):
    """
    进行留一交叉验证

    Args:
        x (list): 数据特征
        y (list): 数据标签
        param_str (str): SVM参数指令

    Returns:
        留一交叉验证精度
    """
    param_str += " -v " + str(len(y))
    accuracy = svm_train(y, x, param_str)
    return accuracy

def solve_predict(x: list, y: list, param_str: str):
    """
    训练模型SVM并用于分类

    Args:
        x (list): 数据特征
        y (list): 数据标签
        param_str (str): SVM参数指令

    Returns:
        p_label, p_acc, p_val, model
    """
    prob = svm_problem(y, x)
    param = svm_parameter(param_str)
    model = svm_train(prob, param)
    p_label, p_acc, p_val = svm_predict(y, x, model)
    return p_label, p_acc, p_val, model

def tuning_gauss(x: list, y: list, c_range: np.ndarray, g_range: np.ndarray):
    """
    SVM高斯核调参

    Args:
        x (list): 数据特征
        y (list): 数据标签
        c_range (np.ndarray): c参数所有取值
        g_range (np.ndarray): g参数所有取值

    Returns:
        best_result (dict): 调参的最优结果，包含精度和c、g取值
        result_frame (pd.DataFrame): 调参过程中所有c、g和对应精度
    """
    best_result = {"Accuracy": -1, "c": -1, "g": -1}
    result_file_name = "best_result.txt"
    result_array = []
    clear_file(result_file_name)
    for c in c_range:
        for g in g_range:
            param_str = '-q -t 2 -c ' + str(c) + ' -g ' + str(g)
            accuracy = leave_one_out(x, y, param_str)
            result_array.append([float(format(c, '.6f')), float(format(g, '.6f')), accuracy])
            if accuracy >= best_result["Accuracy"]:
                best_result["Accuracy"] = accuracy
                best_result["c"] = c
                best_result["g"] = g
                append_dict_to_file(result_file_name, best_result)
    result_frame = pd.DataFrame(result_array, columns=['c', 'g', 'Accuracy'])
    return best_result, result_frame

def clear_file(filename: str):
    """
    清空文件

    Args:
        filename (str): 文件名

    Returns:
        None
    """
    with open(filename, mode='r+', encoding='UTF-8') as file_object:
        file_object.truncate()

def append_dict_to_file(filename: str, content: dict):
    """
    将字典内容写入文件

    Args:
        filename (str): 文件名
        content (dict): 要写入的字典

    Returns:
        None
    """
    newline = ''  # 要写入的内容
    for k, v in content.items():
        newline += str(k) + ': ' + str(v) + '\t'
    newline += '\n'
    append_to_file(filename, newline)

def append_to_file(filename: str, content: str):
    """
    将字符串写入文件

    Args:
        filename (str): 文件名
        content (str): 要写入的字符串

    Returns:
        None
    """
    with open(filename, mode='r+', encoding='UTF-8') as file_object:
        file_object.seek(0, 2)
        file_object.writelines(content)

def plot_tuning_result(result_frame: pd.DataFrame):
    """
    绘制调参结果的热力图

    Args:
        result_frame (pd.DataFrame): 调参结果

    Returns:
        None
    """
    fig, ax = plt.subplots(figsize=(10, 10))
    # sns.set()
    result_frame = result_frame.pivot("c", "g", "Accuracy")
    hm = sns.heatmap(result_frame, ax=ax, cmap="YlGnBu")
    hm.set_xlabel(hm.get_xlabel(), labelpad=0, rotation=0)
    plt.yticks(rotation=0)
    plt.savefig('parameter heat map.png', dpi=260)

def calculate_laplace_kernel(x: list, y: list, gamma: float, result_file_name: str):
    """
    计算拉普拉斯核并写入文件

    Args:
        x (list): 数据特征
        y (list): 数据标签
        gamma (float): gamma参数
        result_file_name (str): 要写入的文件名

    Returns:
        None
    """
    x_array = np.array(list_of_dict_to_list_of_list(x))
    clear_file(result_file_name)
    for i in range(len(y)):
        kernels = []
        for j in range(len(y)):
            x_dif = x_array[i, :] - x_array[j, :]  # 可以利用传播性质优化计算
            x_distance = np.power(np.sum(np.power(x_dif, 2)), 0.5)
            kernel = np.exp(-gamma * x_distance)
            kernels.append(kernel)
        content = str(y[i]) + " 0:" + str(i + 1)
        for k in range(len(y)):
            content += ' ' + str(k + 1) + ':' + str(kernels[k])
        content += '\n'
        append_to_file(result_file_name, content)

def use_laplace(x, y, c: float):
    """
    使用拉普拉斯核进行留一交叉验证和分类

    Args:
        x (list): 数据特征
        y (list): 数据标签
        c (float): c参数

    Returns:
        accuracy, p_label, p_acc, p_val, model
    """
    param_str = '-q -t 4 -c ' + str(c)
    accuracy = leave_one_out(x, y, param_str)
    p_label, p_acc, p_val, model = solve_predict(x, y, param_str)
    return accuracy, p_label, p_acc, p_val, model

def tuning_laplace(x: list, y: list, kernel_file_name: str, c_range: np.ndarray, g_range: np.ndarray):
    """
    SVM拉普拉斯核调参

    Args:
        x (list): 数据特征
        y (list): 数据标签
        kernel_file_name (str): 要写入拉普拉斯核的文件名
        c_range (np.ndarray): c参数所有取值
        g_range (np.ndarray): g参数所有取值

    Returns:
        best_result (dict): 调参的最优结果，包含精度和c、g取值
        result_frame (pd.DataFrame): 调参过程中所有c、g和对应精度
    """
    best_result = {"Accuracy": -1, "c": -1, "g": -1}
    result_file_name = "best_laplace_result.txt"
    result_array = []
    clear_file(result_file_name)
    for g in g_range:
        calculate_laplace_kernel(x, y, g, kernel_file_name)
        ly, lx = svm_read_problem(kernel_file_name)
        for c in c_range:
            param_str = '-q -t 4 -c ' + str(c)
            accuracy = leave_one_out(lx, ly, param_str)
            result_array.append([float(format(c, '.2f')), float(format(g, '.2f')), accuracy])
            # result_array.append([c, g, accuracy])
            if accuracy >= best_result["Accuracy"]:
                best_result["Accuracy"] = accuracy
                best_result["c"] = c
                best_result["g"] = g
                append_dict_to_file(result_file_name, best_result)
    result_frame = pd.DataFrame(result_array, columns=['c', 'g', 'Accuracy'])
    return best_result, result_frame

def plot_sv(model, customed_model: bool, axes, x: np.ndarray = np.array([])):
    """
    在图中标注支持向量

    Args:
        model (): SVM模型
        customed_model (bool): 是否使用自定义核（拉普拉斯核）
        axes (matplotlib.axes._base._AxesBase): 要绘图的Axes实例
        x (np.ndarray): 使用自定义核时的原始数据

    Returns:
        None
    """
    if not customed_model:
        sv_dict = model.get_SV()
        sv = np.array(list_of_dict_to_list_of_list(sv_dict))
    else:
        if x.size == 0:
            raise Exception("x数据缺失")
        sv_indices = np.array(model.get_sv_indices(), dtype=np.int32) - 1
        sv = x[sv_indices]
    x1 = sv[:, 0]
    x2 = sv[:, 1]
    plt.scatter(x1, x2, marker='o', facecolor='none', edgecolors='black', s=200)

def plot_data_and_sv(x, y, model, customed_model: bool, title: str, fig_file_name: str = "data and SV"):
    """
    绘制原始数据并标注支持向量

    Args:
        x (list): 数据特征
        y (list): 数据标签
        model (): SVM模型
        customed_model (bool): 是否使用自定义核（拉普拉斯核）
        title (str): 绘图标题
        fig_file_name (str): 保存图片的文件名

    Returns:
        None
    """
    fig, axes = plt.subplots(1, 1)
    scatter_training_set(x, y, axes)
    x = np.array(list_of_dict_to_list_of_list(x))
    plot_sv(model=model, customed_model=customed_model, axes=axes, x=x)
    props = {'xlabel': '密度', 'ylabel': '含糖率', 'title': title}
    axes.set(**props)
    axes.set_ylabel(axes.get_ylabel(), labelpad=20, rotation=0)
    plt.savefig(fig_file_name + ".png", dpi=260)

if __name__ == '__main__':
    param_str = '-q -t 2 -c 1.4 -g 110'
    y, x = svm_read_problem('training set.txt')
    '''高斯'''
    accuracy = leave_one_out(x, y, param_str)
    p_label, p_acc, p_val, gauss_model = solve_predict(x, y, param_str)
    plot_data_and_sv(x=x, y=y, model=gauss_model, customed_model=False, title="SVM-高斯核, C=1.4, γ=110",
                     fig_file_name="gauss data and SV")
    # best_gauss_result, gauss_result_frame = tuning_gauss(x, y, np.linspace(1, 10, int((10 - 1) * 1) + 1),
    #                                                      np.linspace(0, 128, int((128 - 0) * 1) + 1))
    # best_gauss_result, gauss_result_frame = tuning_gauss(x, y, np.logspace(-4, 4, num=513, base=10),
    #                                                      np.logspace(-4, 4, num=513, base=10))
    # plot_tuning_result(gauss_result_frame)
    '''拉普拉斯'''
    calculate_laplace_kernel(x, y, gamma=9, result_file_name="laplace_kernel.txt")
    ly, lx = svm_read_problem("laplace_kernel.txt")
    l_accuracy, l_p_label, l_p_acc, l_p_val, laplace_model = use_laplace(lx, ly, c=0.8)
    plot_data_and_sv(x=x, y=y, model=laplace_model, customed_model=True,
                     title="SVM-拉普拉斯核, C=0.8, γ=9",
                     fig_file_name="laplace data and SV")
    # best_laplace_result, laplace_result_frame = tuning_laplace(x, y, "laplace_kernel.txt",
    #                                                            np.logspace(-4, 4, num=129, base=10),
    #                                                            np.logspace(-4, 4, num=129, base=10))
    # best_laplace_result, laplace_result_frame = tuning_laplace(x, y, "laplace_kernel.txt",
    #                                                            np.linspace(0.2, 1.4, int((1.4 - 0.2) * 10) + 1),
    #                                                            np.linspace(0, 40, int((40 - 0) * 10) + 1))
    # plot_tuning_result(laplace_result_frame)
    plt.show()


import pandas as pd
import altair as alt

# import theme_alberta.py file with functions
from hueniversitypy.theme_alberta import *

# creating dummy dataframe
data = pd.melt(pd.DataFrame({"A": [1, 86, 62, 29, 16, 42, 69],
                            "B": [21, 41, 97, 14, 75, 7, 32],
                            "C": [57, 90, 98, 67, 9, 46, 87]}))

# create test plot
alberta_plot = alt.Chart(data).mark_point().encode(
    x="count()",
    y="value",
    color="variable"
).properties(title="Test")

def test_chart_object_alberta():
    """Tests if an altair chart object is created"""

    # call the theme function to enforce theme on all subsequent plots
    alt.themes.register("theme_alberta", theme_alberta)
    alt.themes.enable("theme_alberta")

    assert str(type(alberta_plot)) == f"<class 'altair.vegalite.v{alt.__version__[0]}.api.Chart'>"

def test_colours_alberta():
    """Tests if colours from the Alberta theme has been applied to chart"""

    # call the theme function to enforce theme on all subsequent plots
    alt.themes.register("theme_alberta", theme_alberta)
    alt.themes.enable("theme_alberta")

    plot_dict = alberta_plot.to_dict()
    assert plot_dict['config']['range']['category'] == ["#007C41", "#FFDB05", "#7D9AAA", "#A8B400", "#A79E70"]

def test_font_type_alberta():
    """Tests if font type from the Alberta theme has been applied to chart"""

    # call the theme function to enforce theme on all subsequent plots
    alt.themes.register("theme_alberta", theme_alberta)
    alt.themes.enable("theme_alberta")

    plot_dict = alberta_plot.to_dict()
    assert plot_dict['config']['title']['font'] == "Arial"
    assert plot_dict['config']['axisX']['labelFont'] == "Arial"
    assert plot_dict['config']['axisX']['titleFont'] == "Arial"
    assert plot_dict['config']['axisY']['labelFont'] == "Arial"
    assert plot_dict['config']['axisY']['titleFont'] == "Arial"

def test_font_size_alberta():
    """Tests if font size from the Alberta theme has been applied to chart"""

    # call the theme function to enforce theme on all subsequent plots
    alt.themes.register("theme_alberta", theme_alberta)
    alt.themes.enable("theme_alberta")

    plot_dict = alberta_plot.to_dict()
    assert plot_dict['config']['title']['fontSize'] == 18
    assert plot_dict['config']['axisX']['labelFontSize'] == 12
    assert plot_dict['config']['axisX']['titleFontSize'] == 12
    assert plot_dict['config']['axisY']['labelFontSize'] == 12
    assert plot_dict['config']['axisY']['titleFontSize'] == 12


import csv
from pprint import pprint

def parse_csv(filename, select=None, types=None,
              has_headers=True, delimiter=',',
              silence_errors=False):
    """
    Parse a CSV file into a list of records
    """

    if select and has_headers is False:
        raise RuntimeError('Select needs column headers')

    with open(filename) as f:
        data = csv.reader(f, delimiter=delimiter)
        if has_headers:
            headers = next(data)
        else:
            headers = []

        records = []
        indexes = None

        if select:
            indexes = [headers.index(colname) for colname in select]

        for linenum, line in enumerate(data):
            if not line:
                continue
            if indexes:
                line = [line[i] for i in indexes]
                if types:
                    line = [f(val) for f, val in zip(types, line)]
                record = dict(zip(select, line))
            else:
                if has_headers:
                    if types:
                        try:
                            line = [f(val) for f, val in zip(types, line)]
                        except ValueError as e:
                            if silence_errors:
                                pass
                            else:
                                print(
                                    f'Line: {linenum} Unable to convert {line}')
                                print(f'Line: {linenum} Reason {e}')
                    record = dict(zip(headers, line))
                else:
                    if types:
                        record = tuple([f(val) for f, val in zip(types, line)])
                    else:
                        record = tuple(line)

            records.append(record)

    return records

# pprint(parse_csv('Work/Data/prices.csv',
#                  types=[str, float], has_headers=False))

# pprint(parse_csv('Work/Data/prices.csv', has_headers=False))

pprint(parse_csv('Work/Data/missing.csv', types=[str, int, float]))
pprint(parse_csv('Work/Data/missing.csv',
                 types=[str, int, float], silence_errors=True))
# pprint(parse_csv('Work/Data/portfolio.csv',
#                  select=['name', 'price', 'shares'], types=[str, float, int]))

# pprint(parse_csv('Work/Data/portfolio.csv',
#                  select=['name', 'price', 'shares']))

# pprint(parse_csv('Work/Data/portfolio.dat',
#                  types=[str, int, float], delimiter=' '))


'''
Time limit: 1.00 s Memory limit: 512 MB
Given a string, your task is to reorder its letters in such a way that it becomes a palindrome
(i.e., it reads the same forwards and backwards).

Input

The only input line has a string of length n consisting of characters A–Z.

Output

Print a palindrome consisting of the characters of the original string.
You may print any valid solution. If there are no solutions, print "NO SOLUTION".

Constraints
1≤n≤106
Example

Input:
AAAACACBA

Output:
AACABACAA
'''

def solution_12():
    s = input()
    temp = set()
    res = list()
    for e in s:
        if e in temp:
            res.append(e)
            temp.remove(e)
        else:
            temp.add(e)
    if len(temp) > 1:
        print('NO SOLUTION')
    else:
        if temp:
            result = ''.join(res) + temp.pop() + ''.join(res[::-1])
        else:
            result = ''.join(res) + ''.join(res[::-1])
        print(result)

solution_12()


import pytest
from db.server import start_postgres

@pytest.fixture(scope='session', autouse=True)
def pg_instance():
    instance = None
    try:
        instance = start_postgres()
        yield instance
    except Exception as err:
        pytest.skip("Postgres not available ({err})".format(**locals()))
    if instance:
        instance.destroy()


from __future__ import annotations
import numpy as np
from typing import Literal

from coords_array.typing import CoordinateLike

from .array import CoordsArray

def wraps(npfunc):
    def _wraps(ipfunc):
        ipfunc.__doc__ = npfunc.__doc__
        return ipfunc
    return _wraps

def __getattr__(name: str):
    npfunc = getattr(np.random, name)
    @wraps(npfunc)
    def _func(*args, **kwargs) -> CoordsArray:
        coords = kwargs.pop("coords", None)
        out = npfunc(*args, **kwargs)
        return CoordsArray(out, coords=coords)
    return _func

@wraps(np.random.random)
def random(
    size,
    *,
    coords: CoordinateLike | None = None,
) -> CoordsArray:
    return CoordsArray(np.random.random(size), coords=coords)

@wraps(np.random.normal)
def normal(
    loc: float = 0.0,
    scale: float = 1.0,
    size=None,
    *,
    coords: CoordinateLike | None = None,
) -> CoordsArray:
    return CoordsArray(np.random.normal(loc, scale, size), coords=coords)

def random_uint8(
    size: int | tuple[int],
    *,
    coords: CoordinateLike | None = None,
) -> CoordsArray:
    """
    Return a random uint8 image, ranging 0-255.

    Parameters
    ----------
    size : int or tuple of int
        Image shape.
    axes : str, optional
        Image axes.

    Returns
    -------
    CoordsArray
        Random Image in dtype ``np.uint8``.
    """
    arr = np.random.randint(0, 255, size, dtype=np.uint8)
    return CoordsArray(arr, coords=coords)

def random_uint16(
    size,
    *,
    coords: CoordinateLike | None = None,
) -> CoordsArray:
    """
    Return a random uint16 image, ranging 0-65535.

    Parameters
    ----------
    size : int or tuple of int
        Image shape.
    axes : str, optional
        Image axes.

    Returns
    -------
    CoordsArray
        Random Image in dtype ``np.uint16``.
    """
    arr = np.random.randint(0, 65535, size, dtype=np.uint16)
    return CoordsArray(arr, coords=coords)

def default_rng(seed) -> ImageGenerator:
    return ImageGenerator(np.random.default_rng(seed))

class ImageGenerator:
    def __init__(self, rng: np.random.Generator):
        self._rng = rng

    def standard_normal(
        self,
        size: int | tuple[int, ...] | None = None,
        dtype = None,
        *,
        coords: CoordinateLike | None = None,
    ) -> CoordsArray:
        arr = self._rng.standard_normal(size=size, dtype=dtype)
        if np.isscalar(arr):
            return arr
        return CoordsArray(arr, coords=coords)

    def standard_exponential(
        self,
        size: int | tuple[int, ...] | None = None,
        dtype = None,
        method: Literal["zig", "inv"] = None,
        *,
        coords: CoordinateLike | None = None,
    ) -> CoordsArray:
        arr = self._rng.standard_exponential(size=size, dtype=dtype, method=method)
        if np.isscalar(arr):
            return arr
        return CoordsArray(arr, coords=coords)

    def random(
        self,
        size: int | tuple[int, ...] | None = None,
        dtype = None,
        *,
        coords: CoordinateLike | None = None,
    ) -> CoordsArray:
        arr = self._rng.random(size=size, dtype=dtype)
        if np.isscalar(arr):
            return arr
        return CoordsArray(arr, coords=coords)

    def normal(
        self,
        loc: float | np.ndarray = 0.,
        scale: float | np.ndarray = 1.,
        size: int | tuple[int, ...] | None = None,
        *,
        coords: CoordinateLike | None = None,
    ) -> CoordsArray:
        arr = self._rng.normal(loc=loc, scale=scale, size=size)
        if np.isscalar(arr):
            return arr
        return CoordsArray(arr, coords=coords)

    def poisson(
        self,
        lam: float,
        size: int | tuple[int, ...] | None = None,
        *,
        coords: CoordinateLike | None = None,
    ) -> CoordsArray:
        arr = self._rng.poisson(lam=lam, size=size)
        if np.isscalar(arr):
            return arr
        return CoordsArray(arr, coords=coords)

    def random_uint8(
        self,
        size: int | tuple[int],
        *,
        coords: CoordinateLike | None = None,
    ) -> CoordsArray:
        arr = self._rng.integers(0, 255, size, dtype=np.uint8)
        return CoordsArray(arr, coords=coords)

    def random_uint16(
        self,
        size,
        *,
        coords: CoordinateLike | None = None,
    ) -> CoordsArray:
        arr = self._rng.integers(0, 65535, size, dtype=np.uint16)
        return CoordsArray(arr, coords=coords)

del wraps


from print_progress import print_progress
import os
import unittest

class Files:
    def __init__(self, directory="./"):
        file_names = list(filter(lambda name: ("." in name) and (not name.startswith(".")), os.listdir(directory)))
        self.files = list(map(lambda file_name: os.path.join(directory, file_name), file_names))
        self.num_files = len(self.files)

        if self.num_files == 0:
            print("No file in given directory: {}".format(directory))
            exit(-1)

        self.index = 0
        self.opened_file = open(self.files[self.index], "rb")

    def __del__(self):
        if self.opened_file is not None:
            self.opened_file.close()

    def set_next_file(self):
        print_progress(self.index + 1, self.num_files)
        # All files read
        if self.index >= self.num_files - 1:
            self.opened_file.close()
            self.opened_file = None
            return

        self.opened_file.close()
        self.index += 1
        self.opened_file = open(self.files[self.index], "rb")

    def read_fragment(self, size):
        fragment = self.opened_file.read(size)

        while len(fragment) < size:
            self.set_next_file()
            if self.opened_file is None:
                return None

            fragment = self.opened_file.read(size)

        return fragment

    def reset(self):
        self.index = 0
        self.opened_file = open(self.files[self.index], "rb")

class FilesUnitTest(unittest.TestCase):
    def setUp(self):
        self.files = Files()

    def test_read(self):
        size = 4096
        fragment = self.files.read_fragment(size)
        while fragment is not None:
            print(fragment)
            fragment = self.files.read_fragment(size)

        self.files.reset()
        print(self.files.read_fragment(size))


from pafy import new
url = input("Enter you link     :  ")
video= new(url)
audio = video.audiostreams
print(video)
hv = video.getbest()
stream = video.streams
print("          HIGH quality  chosess number 1 ")
print("          LOW qulality  chosess number 0     ")
print("          audio    chosess 2 ")
dl = input("Enter qulty :  ")
while dl == "1":
    hv.download()
while dl == "0":
    stream[0].download()
while dl == "2" :
    audio[0].download()


import collections

class FrequencyTracker:

    def __init__(self):
        self.counter = collections.defaultdict(int)
        self.cnt_to_num = collections.defaultdict(set)

    def add(self, number: int) -> None:
        if number not in self.counter:
            self.counter[number] = 0
        freq = self.counter[number]
        self.counter[number] += 1

        if number in self.cnt_to_num[freq]:
            self.cnt_to_num[freq].remove(number)
        self.cnt_to_num[freq + 1].add(number)

    def deleteOne(self, number: int) -> None:
        if number not in self.counter:
            return None
        freq = self.counter[number]
        self.counter[number] -= 1
        if self.counter[number] == 0:
            del self.counter[number]

        if number in self.cnt_to_num[freq]:
            self.cnt_to_num[freq].remove(number)
        self.cnt_to_num[freq - 1].add(number)

    def hasFrequency(self, frequency: int) -> bool:
        if frequency in self.cnt_to_num:
            return len(self.cnt_to_num[frequency]) > 0
        return False

frequencyTracker = FrequencyTracker();
frequencyTracker.add(1)
frequencyTracker.deleteOne(1)
print(frequencyTracker.hasFrequency(1))


import plotly.express as px
import plotly.graph_objects as go
import pandas as pd
import plotly as py

# interactive map bscc locations

# load data
df = pd.read_csv('data/locations_sorted.tsv', sep='\t')

# change long to lng
df = df.rename(columns={'long': 'lng'})

# change country codes to country names
df['country'] = df['country'].replace({'GB': 'Great Britain', 'CH': 'Switzerland'})

print(df)

fig = px.scatter_geo(df, lat='lat', lon='lng', hover_name='name', color='country', projection='natural earth',
                     size_max=10, opacity=0.5, title='BSCC Locations',
                     labels={'name': 'Name'},
                     hover_data={'Unnamed: 0': False, 'lat': False, 'lng': False, 'id': False, 'country': False, 'count': True})

fig.show()

# interactive map bscc atlas locations

# load data
df = pd.read_csv('data/bscc_atlas_locations.tsv', sep='\t')

# rename columns
df.columns = ['name', 'gnd', 'lat', 'lng', 'address', 'country', 'country_code', 'country_gnd', 'continent_code']

#insert for missing values in continent_code NA
df['continent_code'] = df['continent_code'].fillna('NA')

# change continent codes to continent names
df['continent_code'] = df['continent_code'].replace({'NA': 'North America (3)', 'SA': 'South America (5)', 'EU': 'Europe (15)', 'AS': 'Asia (29)', 'AF': 'Africa (5)', 'OC': 'Oceania'})

# remove unnecessary columns
df2 = df.drop(['gnd', 'address', 'country_code', 'country_gnd'], axis=1)

fig = px.scatter_geo(df2, lat='lat', lon='lng', hover_name='name', color='continent_code', projection='natural earth',
                     size_max=10, opacity=0.5, title='BSCC Atlas Locations',
                     labels={'name': 'Name'},
                     hover_data={'lat': False, 'lng': False, 'continent_code': False, 'country': False})

fig.update_traces(textposition='top center', mode='markers+text', textfont_size=8)

fig.update_traces(marker=dict(size=10))

fig.show()