# -*- coding: utf-8 -*-
import torch.nn as nn
import torch.nn.functional as F
import torchvision.models as models
import numpy as np
import torch

# SEGNET
class SegNet(nn.Module):
    def __init__(self,input_nbr,label_nbr):
        super(SegNet, self).__init__()

        batchNorm_momentum = 0.1

        self.conv11 = nn.Conv2d(input_nbr, 64, kernel_size=3, padding=1)
        self.bn11 = nn.BatchNorm2d(64, momentum= batchNorm_momentum)
        self.conv12 = nn.Conv2d(64, 64, kernel_size=3, padding=1)
        self.bn12 = nn.BatchNorm2d(64, momentum= batchNorm_momentum)

        self.conv21 = nn.Conv2d(64, 128, kernel_size=3, padding=1)
        self.bn21 = nn.BatchNorm2d(128, momentum= batchNorm_momentum)
        self.conv22 = nn.Conv2d(128, 128, kernel_size=3, padding=1)
        self.bn22 = nn.BatchNorm2d(128, momentum= batchNorm_momentum)

        self.conv31 = nn.Conv2d(128, 256, kernel_size=3, padding=1)
        self.bn31 = nn.BatchNorm2d(256, momentum= batchNorm_momentum)
        self.conv32 = nn.Conv2d(256, 256, kernel_size=3, padding=1)
        self.bn32 = nn.BatchNorm2d(256, momentum= batchNorm_momentum)
        self.conv33 = nn.Conv2d(256, 256, kernel_size=3, padding=1)
        self.bn33 = nn.BatchNorm2d(256, momentum= batchNorm_momentum)

        self.conv41 = nn.Conv2d(256, 512, kernel_size=3, padding=1)
        self.bn41 = nn.BatchNorm2d(512, momentum= batchNorm_momentum)
        self.conv42 = nn.Conv2d(512, 512, kernel_size=3, padding=1)
        self.bn42 = nn.BatchNorm2d(512, momentum= batchNorm_momentum)
        self.conv43 = nn.Conv2d(512, 512, kernel_size=3, padding=1)
        self.bn43 = nn.BatchNorm2d(512, momentum= batchNorm_momentum)

        self.conv51 = nn.Conv2d(512, 512, kernel_size=3, padding=1)
        self.bn51 = nn.BatchNorm2d(512, momentum= batchNorm_momentum)
        self.conv52 = nn.Conv2d(512, 512, kernel_size=3, padding=1)
        self.bn52 = nn.BatchNorm2d(512, momentum= batchNorm_momentum)
        self.conv53 = nn.Conv2d(512, 512, kernel_size=3, padding=1)
        self.bn53 = nn.BatchNorm2d(512, momentum= batchNorm_momentum)

        self.conv53d = nn.Conv2d(512, 512, kernel_size=3, padding=1)
        self.bn53d = nn.BatchNorm2d(512, momentum= batchNorm_momentum)
        self.conv52d = nn.Conv2d(512, 512, kernel_size=3, padding=1)
        self.bn52d = nn.BatchNorm2d(512, momentum= batchNorm_momentum)
        self.conv51d = nn.Conv2d(512, 512, kernel_size=3, padding=1)
        self.bn51d = nn.BatchNorm2d(512, momentum= batchNorm_momentum)

        self.conv43d = nn.Conv2d(512, 512, kernel_size=3, padding=1)
        self.bn43d = nn.BatchNorm2d(512, momentum= batchNorm_momentum)
        self.conv42d = nn.Conv2d(512, 512, kernel_size=3, padding=1)
        self.bn42d = nn.BatchNorm2d(512, momentum= batchNorm_momentum)
        self.conv41d = nn.Conv2d(512, 256, kernel_size=3, padding=1)
        self.bn41d = nn.BatchNorm2d(256, momentum= batchNorm_momentum)

        self.conv33d = nn.Conv2d(256, 256, kernel_size=3, padding=1)
        self.bn33d = nn.BatchNorm2d(256, momentum= batchNorm_momentum)
        self.conv32d = nn.Conv2d(256, 256, kernel_size=3, padding=1)
        self.bn32d = nn.BatchNorm2d(256, momentum= batchNorm_momentum)
        self.conv31d = nn.Conv2d(256,  128, kernel_size=3, padding=1)
        self.bn31d = nn.BatchNorm2d(128, momentum= batchNorm_momentum)

        self.conv22d = nn.Conv2d(128, 128, kernel_size=3, padding=1)
        self.bn22d = nn.BatchNorm2d(128, momentum= batchNorm_momentum)
        self.conv21d = nn.Conv2d(128, 64, kernel_size=3, padding=1)
        self.bn21d = nn.BatchNorm2d(64, momentum= batchNorm_momentum)

        self.conv12d = nn.Conv2d(64, 64, kernel_size=3, padding=1)
        self.bn12d = nn.BatchNorm2d(64, momentum= batchNorm_momentum)
        self.conv11d = nn.Conv2d(64, label_nbr, kernel_size=3, padding=1)

    def forward(self, x):
        # Stage 1
        x11 = F.relu(self.bn11(self.conv11(x)))
        x12 = F.relu(self.bn12(self.conv12(x11)))
        x1p, id1 = F.max_pool2d(x12,kernel_size=2, stride=2,return_indices=True)
        x12_s = x12.shape
        # Stage 2
        x21 = F.relu(self.bn21(self.conv21(x1p)))
        x22 = F.relu(self.bn22(self.conv22(x21)))
        x2p, id2 = F.max_pool2d(x22,kernel_size=2, stride=2,return_indices=True)
        x22_s = x22.shape
        # Stage 3
        x31 = F.relu(self.bn31(self.conv31(x2p)))
        x32 = F.relu(self.bn32(self.conv32(x31)))
        x33 = F.relu(self.bn33(self.conv33(x32)))
        x3p, id3 = F.max_pool2d(x33,kernel_size=2, stride=2,return_indices=True)
        x32_s = x32.shape
        # Stage 4
        x41 = F.relu(self.bn41(self.conv41(x3p)))
        x42 = F.relu(self.bn42(self.conv42(x41)))
        x43 = F.relu(self.bn43(self.conv43(x42)))
        x4p, id4 = F.max_pool2d(x43,kernel_size=2, stride=2,return_indices=True)
        x42_s = x42.shape
        # Stage 5
        x51 = F.relu(self.bn51(self.conv51(x4p)))
        x52 = F.relu(self.bn52(self.conv52(x51)))
        x53 = F.relu(self.bn53(self.conv53(x52)))
        x5p, id5 = F.max_pool2d(x53,kernel_size=2, stride=2,return_indices=True)
        x52_s = x52.shape
        # Stage 5d
        x5d = F.max_unpool2d(x5p, id5, kernel_size=2, stride=2,output_size=x52_s)
        x53d = F.relu(self.bn53d(self.conv53d(x5d)))
        x52d = F.relu(self.bn52d(self.conv52d(x53d)))
        x51d = F.relu(self.bn51d(self.conv51d(x52d)))
        # Stage 4d
        x4d = F.max_unpool2d(x51d, id4, kernel_size=2, stride=2,output_size=x42_s)
        x43d = F.relu(self.bn43d(self.conv43d(x4d)))
        x42d = F.relu(self.bn42d(self.conv42d(x43d)))
        x41d = F.relu(self.bn41d(self.conv41d(x42d)))
        # Stage 3d
        x3d = F.max_unpool2d(x41d, id3, kernel_size=2, stride=2,output_size=x32_s)
        x33d = F.relu(self.bn33d(self.conv33d(x3d)))
        x32d = F.relu(self.bn32d(self.conv32d(x33d)))
        x31d = F.relu(self.bn31d(self.conv31d(x32d)))
        # Stage 2d
        x2d = F.max_unpool2d(x31d, id2, kernel_size=2, stride=2,output_size=x22_s)
        x22d = F.relu(self.bn22d(self.conv22d(x2d)))
        x21d = F.relu(self.bn21d(self.conv21d(x22d)))
        # Stage 1d
        x1d = F.max_unpool2d(x21d, id1, kernel_size=2, stride=2,output_size=x12_s)
        x12d = F.relu(self.bn12d(self.conv12d(x1d)))
        x11d = self.conv11d(x12d)
        return x11d

# FCN
def get_upsampling_weight(in_channels, out_channels, kernel_size):
    factor = (kernel_size + 1) // 2
    if kernel_size % 2 == 1:
        center = factor - 1
    else:
        center = factor - 0.5
    og = np.ogrid[:kernel_size, :kernel_size]
    filt = (1 - abs(og[0] - center) / factor) * (1 - abs(og[1] - center) / factor)
    weight = np.zeros((in_channels, out_channels, kernel_size, kernel_size), dtype=np.float64)
    weight[list(range(in_channels)), list(range(out_channels)), :, :] = filt
    return torch.from_numpy(weight).float()

# This is implemented in full accordance with the original one (https://github.com/shelhamer/fcn.berkeleyvision.org)
class FCN8s(nn.Module):
    def __init__(self, num_classes, pretrained=False, caffe=False):
        super(FCN8s, self).__init__()
        vgg = models.vgg16()
        features, classifier = list(vgg.features.children()), list(vgg.classifier.children())

        '''
        100 padding for 2 reasons:
            1) support very small input size
            2) allow cropping in order to match size of different layers' feature maps
        Note that the cropped part corresponds to a part of the 100 padding
        Spatial information of different layers' feature maps cannot be align exactly because of cropping, which is bad
        '''
        features[0].padding = (100, 100)

        for f in features:
            if 'MaxPool' in f.__class__.__name__:
                f.ceil_mode = True
            elif 'ReLU' in f.__class__.__name__:
                f.inplace = True

        self.features3 = nn.Sequential(*features[: 17])
        self.features4 = nn.Sequential(*features[17: 24])
        self.features5 = nn.Sequential(*features[24:])

        self.score_pool3 = nn.Conv2d(256, num_classes, kernel_size=1)
        self.score_pool4 = nn.Conv2d(512, num_classes, kernel_size=1)
        self.score_pool3.weight.data.zero_()
        self.score_pool3.bias.data.zero_()
        self.score_pool4.weight.data.zero_()
        self.score_pool4.bias.data.zero_()

        fc6 = nn.Conv2d(512, 4096, kernel_size=7)
        fc6.weight.data.copy_(classifier[0].weight.data.view(4096, 512, 7, 7))
        fc6.bias.data.copy_(classifier[0].bias.data)
        fc7 = nn.Conv2d(4096, 4096, kernel_size=1)
        fc7.weight.data.copy_(classifier[3].weight.data.view(4096, 4096, 1, 1))
        fc7.bias.data.copy_(classifier[3].bias.data)
        score_fr = nn.Conv2d(4096, num_classes, kernel_size=1)
        score_fr.weight.data.zero_()
        score_fr.bias.data.zero_()
        self.score_fr = nn.Sequential(
            fc6, nn.ReLU(inplace=True), nn.Dropout(), fc7, nn.ReLU(inplace=True), nn.Dropout(), score_fr
        )

        self.upscore2 = nn.ConvTranspose2d(num_classes, num_classes, kernel_size=4, stride=2, bias=False)
        self.upscore_pool4 = nn.ConvTranspose2d(num_classes, num_classes, kernel_size=4, stride=2, bias=False)
        self.upscore8 = nn.ConvTranspose2d(num_classes, num_classes, kernel_size=16, stride=8, bias=False)
        self.upscore2.weight.data.copy_(get_upsampling_weight(num_classes, num_classes, 4))
        self.upscore_pool4.weight.data.copy_(get_upsampling_weight(num_classes, num_classes, 4))
        self.upscore8.weight.data.copy_(get_upsampling_weight(num_classes, num_classes, 16))

    def forward(self, x):
        x_size = x.size()
        pool3 = self.features3(x)
        pool4 = self.features4(pool3)
        pool5 = self.features5(pool4)
        score_fr = self.score_fr(pool5)
        upscore2 = self.upscore2(score_fr)
        score_pool4 = self.score_pool4(0.01 * pool4)
        upscore_pool4 = self.upscore_pool4(score_pool4[:, :, 5: (5 + upscore2.size()[2]), 5: (5 + upscore2.size()[3])]
                                           + upscore2)
        score_pool3 = self.score_pool3(0.0001 * pool3)
        upscore8 = self.upscore8(score_pool3[:, :, 9: (9 + upscore_pool4.size()[2]), 9: (9 + upscore_pool4.size()[3])]
                                 + upscore_pool4)
        return upscore8[:, :, 31: (31 + x_size[2]), 31: (31 + x_size[3])].contiguous()

# PSPNET

def initialize_weights(model):
        for module in model.modules():
            if isinstance(module, nn.Conv2d) or isinstance(module, nn.Linear):
                nn.init.kaiming_normal_(module.weight)
                if module.bias is not None:
                    module.bias.data.zero_()
            elif isinstance(module, nn.BatchNorm2d):
                module.weight.data.fill_(1)
                module.bias.data.zero_()

class _PyramidPoolingModule(nn.Module):
    def __init__(self, in_dim, reduction_dim, setting):
        super(_PyramidPoolingModule, self).__init__()
        self.features = []
        for s in setting:
            if s!=1:
                self.features.append(nn.Sequential(
                    nn.AdaptiveAvgPool2d(s),
                    nn.Conv2d(in_dim, reduction_dim, kernel_size=1, bias=False),
                    nn.BatchNorm2d(reduction_dim, momentum=.95),
                    nn.ReLU(inplace=True)
                ))
            if s==1:
                self.features.append(nn.Sequential(
                    nn.AdaptiveAvgPool2d(s),
                    nn.Conv2d(in_dim, reduction_dim, kernel_size=1, bias=False),
                    #nn.BatchNorm2d(reduction_dim, momentum=.95),
                    nn.ReLU(inplace=True)
                ))
        self.features = nn.ModuleList(self.features)

    def forward(self, x):
        x_size = x.size()
        out = [x]
        for f in self.features:
            out.append(F.upsample(f(x), x_size[2:], mode='bilinear'))
        out = torch.cat(out, 1)
        return out

class PSPNet(nn.Module):
    def __init__(self, num_classes, pretrained=False, use_aux=True):
        super(PSPNet, self).__init__()
        self.use_aux = use_aux
        resnet = models.resnet101(pretrained=True)
#        if pretrained:
#            resnet.load_state_dict(torch.load(res101_path))
        self.layer0 = nn.Sequential(resnet.conv1, resnet.bn1, resnet.relu, resnet.maxpool)
        self.layer1, self.layer2, self.layer3, self.layer4 = resnet.layer1, resnet.layer2, resnet.layer3, resnet.layer4

        for n, m in self.layer3.named_modules():
            if 'conv2' in n:
                m.dilation, m.padding, m.stride = (2, 2), (2, 2), (1, 1)
            elif 'downsample.0' in n:
                m.stride = (1, 1)
        for n, m in self.layer4.named_modules():
            if 'conv2' in n:
                m.dilation, m.padding, m.stride = (4, 4), (4, 4), (1, 1)
            elif 'downsample.0' in n:
                m.stride = (1, 1)

        self.ppm = _PyramidPoolingModule(2048, 512, (1, 2, 3, 6))
        self.final = nn.Sequential(
            nn.Conv2d(4096, 512, kernel_size=3, padding=1, bias=False),
            nn.BatchNorm2d(512, momentum=.95),
            nn.ReLU(inplace=True),
            nn.Dropout(0.1),
            nn.Conv2d(512, num_classes, kernel_size=1)
        )

        if use_aux:
            self.aux_logits = nn.Conv2d(1024, num_classes, kernel_size=1)
            #print(self.aux_logits)
            initialize_weights(self.aux_logits)

        initialize_weights(self.ppm)
        initialize_weights(self.final)

    def forward(self, x):
        x_size = x.size()

        x = self.layer0(x)

        x = self.layer1(x)

        x = self.layer2(x)

        x = self.layer3(x)

        if self.training and self.use_aux:
            aux = self.aux_logits(x)
        x = self.layer4(x)

        x = self.ppm(x)

        x = self.final(x)
        if self.training and self.use_aux:
            return F.upsample(x, x_size[2:], mode='bilinear'), F.upsample(aux, x_size[2:], mode='bilinear')
        return F.upsample(x, x_size[2:], mode='bilinear')

# TIRAMISU
class DenseLayer(nn.Sequential):
    def __init__(self, in_channels, growth_rate):
        super().__init__()
        self.add_module('norm', nn.BatchNorm2d(in_channels))
        self.add_module('relu', nn.ReLU(True))
        self.add_module('conv', nn.Conv2d(in_channels, growth_rate, kernel_size=3,
                                          stride=1, padding=1, bias=True))
        self.add_module('drop', nn.Dropout2d(0.2))

    def forward(self, x):
        return super().forward(x)

class DenseBlock(nn.Module):
    def __init__(self, in_channels, growth_rate, n_layers, upsample=False):
        super().__init__()
        self.upsample = upsample
        self.layers = nn.ModuleList([DenseLayer(
            in_channels + i*growth_rate, growth_rate)
            for i in range(n_layers)])

    def forward(self, x):
        if self.upsample:
            new_features = []
            #we pass all previous activations into each dense layer normally
            #But we only store each dense layer's output in the new_features array
            for layer in self.layers:
                out = layer(x)
                x = torch.cat([x, out], 1)
                new_features.append(out)
            return torch.cat(new_features,1)
        else:
            for layer in self.layers:
                out = layer(x)
                x = torch.cat([x, out], 1) # 1 = channel axis
            return x

class TransitionDown(nn.Sequential):
    def __init__(self, in_channels):
        super().__init__()
        self.add_module('norm', nn.BatchNorm2d(num_features=in_channels))
        self.add_module('relu', nn.ReLU(inplace=True))
        self.add_module('conv', nn.Conv2d(in_channels, in_channels,
                                          kernel_size=1, stride=1,
                                          padding=0, bias=True))
        self.add_module('drop', nn.Dropout2d(0.2))
        self.add_module('maxpool', nn.MaxPool2d(2))

    def forward(self, x):
        return super().forward(x)

class TransitionUp(nn.Module):
    def __init__(self, in_channels, out_channels):
        super().__init__()
        self.convTrans = nn.ConvTranspose2d(
            in_channels=in_channels, out_channels=out_channels,
            kernel_size=3, stride=2, padding=0, bias=True)

    def forward(self, x, skip):
        out = self.convTrans(x)
        out = center_crop(out, skip.size(2), skip.size(3))
        out = torch.cat([out, skip], 1)
        return out

class Bottleneck(nn.Sequential):
    def __init__(self, in_channels, growth_rate, n_layers):
        super().__init__()
        self.add_module('bottleneck', DenseBlock(
            in_channels, growth_rate, n_layers, upsample=True))

    def forward(self, x):
        return super().forward(x)

def center_crop(layer, max_height, max_width):
    _, _, h, w = layer.size()
    xy1 = (w - max_width) // 2
    xy2 = (h - max_height) // 2
    return layer[:, :, xy2:(xy2 + max_height), xy1:(xy1 + max_width)]

class FCDenseNet(nn.Module):
    def __init__(self, in_channels=3, down_blocks=(5,5,5,5,5),
                 up_blocks=(5,5,5,5,5), bottleneck_layers=5,
                 growth_rate=16, out_chans_first_conv=48, n_classes=12):
        super().__init__()
        self.down_blocks = down_blocks
        self.up_blocks = up_blocks
        cur_channels_count = 0
        skip_connection_channel_counts = []

        ## First Convolution ##

        self.add_module('firstconv', nn.Conv2d(in_channels=in_channels,
                  out_channels=out_chans_first_conv, kernel_size=3,
                  stride=1, padding=1, bias=True))
        cur_channels_count = out_chans_first_conv

        #####################
        # Downsampling path #
        #####################

        self.denseBlocksDown = nn.ModuleList([])
        self.transDownBlocks = nn.ModuleList([])
        for i in range(len(down_blocks)):
            self.denseBlocksDown.append(
                DenseBlock(cur_channels_count, growth_rate, down_blocks[i]))
            cur_channels_count += (growth_rate*down_blocks[i])
            skip_connection_channel_counts.insert(0,cur_channels_count)
            self.transDownBlocks.append(TransitionDown(cur_channels_count))

        #####################
        #     Bottleneck    #
        #####################

        self.add_module('bottleneck',Bottleneck(cur_channels_count,
                                     growth_rate, bottleneck_layers))
        prev_block_channels = growth_rate*bottleneck_layers
        cur_channels_count += prev_block_channels

        #######################
        #   Upsampling path   #
        #######################

        self.transUpBlocks = nn.ModuleList([])
        self.denseBlocksUp = nn.ModuleList([])
        for i in range(len(up_blocks)-1):
            self.transUpBlocks.append(TransitionUp(prev_block_channels, prev_block_channels))
            cur_channels_count = prev_block_channels + skip_connection_channel_counts[i]

            self.denseBlocksUp.append(DenseBlock(
                cur_channels_count, growth_rate, up_blocks[i],
                    upsample=True))
            prev_block_channels = growth_rate*up_blocks[i]
            cur_channels_count += prev_block_channels

        ## Final DenseBlock ##

        self.transUpBlocks.append(TransitionUp(
            prev_block_channels, prev_block_channels))
        cur_channels_count = prev_block_channels + skip_connection_channel_counts[-1]

        self.denseBlocksUp.append(DenseBlock(
            cur_channels_count, growth_rate, up_blocks[-1],
                upsample=False))
        cur_channels_count += growth_rate*up_blocks[-1]

        ## Softmax ##

        self.finalConv = nn.Conv2d(in_channels=cur_channels_count,
               out_channels=n_classes, kernel_size=1, stride=1,
                   padding=0, bias=True)
        self.softmax = nn.LogSoftmax(dim=1)

    def forward(self, x):
        #print("x ",x.size())
        out = self.firstconv(x)
        #print("out ",out.size())
        skip_connections = []
        #print("going in loop")
        for i in range(len(self.down_blocks)):
            out = self.denseBlocksDown[i](out)
            #print("out (dense blocks down) ",out.size())
            skip_connections.append(out)
            out = self.transDownBlocks[i](out)
            #print("out (trans down blocks) ",out.size())

        #print("out of loop")
        out = self.bottleneck(out)
        #print("out bottleneck ",out.size())

        #print("going in loop")
        for i in range(len(self.up_blocks)):
            skip = skip_connections.pop()
            out = self.transUpBlocks[i](out, skip)
            #print("out trans up block ",out.size())
            out = self.denseBlocksUp[i](out)
            #print("out dense block up ",out.size())
        #print("out of loop")
        out = self.finalConv(out)
        #print("out final conv",out.size())
        #out = self.softmax(out)
        #print("out softmax ",out.size())
        return out

def FCDenseNet57(n_classes):
    return FCDenseNet(
        in_channels=3, down_blocks=(4, 4, 4, 4, 4),
        up_blocks=(4, 4, 4, 4, 4), bottleneck_layers=4,
        growth_rate=12, out_chans_first_conv=48, n_classes=n_classes)

def FCDenseNet67(n_classes):
    return FCDenseNet(
        in_channels=3, down_blocks=(5, 5, 5, 5, 5),
        up_blocks=(5, 5, 5, 5, 5), bottleneck_layers=5,
        growth_rate=16, out_chans_first_conv=48, n_classes=n_classes)

def FCDenseNet103(n_classes):
    return FCDenseNet(
        in_channels=3, down_blocks=(4,5,7,10,12),
        up_blocks=(12,10,7,5,4), bottleneck_layers=15,
        growth_rate=16, out_chans_first_conv=48, n_classes=n_classes)

# U-NET

class UNetConvBlock(nn.Module):
    def __init__(self, in_size, out_size, kernel_size=3, activation=F.relu):
        super(UNetConvBlock, self).__init__()
        self.conv = nn.Conv2d(in_size, out_size, kernel_size, padding = kernel_size // 2)
        self.conv2 = nn.Conv2d(out_size, out_size, kernel_size, padding = kernel_size // 2)
        self.activation = activation

    def forward(self, x):
        out = self.activation(self.conv(x))
        out = self.activation(self.conv2(out))

        return out

class UNetUpBlock(nn.Module):
    def __init__(self, in_size, out_size, kernel_size=3, activation=F.relu, space_dropout=False):
        super(UNetUpBlock, self).__init__()
        self.up = nn.ConvTranspose2d(in_size, out_size, kernel_size= 2, stride=2)
        self.conv = nn.Conv2d(in_size, out_size, kernel_size, padding = kernel_size // 2)#1st parameter in_size
        self.conv2 = nn.Conv2d(out_size, out_size, kernel_size, padding = kernel_size // 2)
        self.activation = activation

    def center_crop(self, layer, target_size):

        batch_size, n_channels, layer_width, layer_height = layer.size()
        x1 = (layer_width - target_size[0]) // 2
        y1 = (layer_height - target_size[1]) // 2
        return layer[:, :, x1:(x1 + target_size[0]), y1:(y1 + target_size[1])]

    def forward(self, x, bridge):
        up = self.up(x,output_size=bridge.size())
        crop1 = self.center_crop(bridge, (up.size()[2],up.size()[3]))   # IMPROVEMENT + ALL PADDING
        out = torch.cat([up, crop1], 1)

        out = self.activation(self.conv(out))
        out = self.activation(self.conv2(out))

        return out

class UNet(nn.Module):
    def __init__(self,no_class):#
        super(UNet, self).__init__()
        #self.imsize = imsize
        self.activation = F.relu

        self.pool1 = nn.MaxPool2d(2)
        self.pool2 = nn.MaxPool2d(2)
        self.pool3 = nn.MaxPool2d(2)
        self.pool4 = nn.MaxPool2d(2)

        self.conv_block1_64 = UNetConvBlock(3, 64)#3--1
        self.conv_block64_128 = UNetConvBlock(64, 128)
        self.conv_block128_256 = UNetConvBlock(128, 256)
        self.conv_block256_512 = UNetConvBlock(256, 512)
        self.conv_block512_1024 = UNetConvBlock(512, 1024)

        self.up_block1024_512 = UNetUpBlock(1024, 512)
        self.up_block512_256 = UNetUpBlock(512, 256)
        self.up_block256_128 = UNetUpBlock(256, 128)
        self.up_block128_64 = UNetUpBlock(128, 64)

        self.last = nn.Conv2d(64, no_class, 1)#11--2

    def forward(self, x):
        block1 = self.conv_block1_64(x)
        pool1 = self.pool1(block1)

        block2 = self.conv_block64_128(pool1)
        pool2 = self.pool2(block2)

        block3 = self.conv_block128_256(pool2)
        pool3 = self.pool3(block3)

        block4 = self.conv_block256_512(pool3)
        pool4 = self.pool4(block4)

        block5 = self.conv_block512_1024(pool4)

        up1 = self.up_block1024_512(block5, block4)
        up2 = self.up_block512_256(up1, block3)
        up3 = self.up_block256_128(up2, block2)
        up4 = self.up_block128_64(up3, block1)

        return self.last(up4)

# DEEPLAB

affine_par = True
def outS(i):
    i = int(i)
    i = (i+1)/2
    i = int(np.ceil((i+1)/2.0))
    i = (i+1)/2
    i = int(i)
    #print('i',i)
    return i

def conv3x3(in_planes, out_planes, stride=1):
    "3x3 convolution with padding"
    return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride,
                     padding=1, bias=False)
class Bottleneck1(nn.Module):
    expansion = 4
    def __init__(self, inplanes, planes, stride=1, dilation_ = 1, downsample=None):
        super(Bottleneck1, self).__init__()
        self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, stride=stride, bias=False)
        self.bn1 = nn.BatchNorm2d(planes,affine = affine_par)
        for i in self.bn1.parameters():
            i.requires_grad = False
        padding = 1
        if dilation_ == 2:
            padding = 2
        elif dilation_ == 4:
            padding = 4
        self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=1, padding = padding, bias = False, dilation= dilation_)
        self.bn2 = nn.BatchNorm2d(planes,affine = affine_par)
        for i in self.bn2.parameters():
            i.requires_grad = False
        self.conv3 = nn.Conv2d(planes, planes * 4, kernel_size=1, bias=False)
        self.bn3 = nn.BatchNorm2d(planes * 4, affine = affine_par)
        for i in self.bn3.parameters():
            i.requires_grad = False
        self.relu = nn.ReLU(inplace=True)
        self.downsample = downsample
        self.stride = stride
    def forward(self, x):
        #print(x)
        residual = x
        out = self.conv1(x)
        out = self.bn1(out)
        out = self.relu(out)
        out = self.conv2(out)
        out = self.bn2(out)
        out = self.relu(out)
        out = self.conv3(out)
        out = self.bn3(out)
        if self.downsample is not None:
            residual = self.downsample(x)
        out += residual
        out = self.relu(out)
        #print(out)
        return out
class Classifier_Module(nn.Module):
    def __init__(self,dilation_series,padding_series,NoLabels):
        super(Classifier_Module, self).__init__()
        self.conv2d_list = []
        self.conv2d_list = nn.ModuleList()
        for dilation,padding in zip(dilation_series,padding_series):
            self.conv2d_list.append(nn.Conv2d(2048,NoLabels,kernel_size=3,stride=1, padding =padding, dilation = dilation,bias = True))
            for m in self.conv2d_list:
                m.weight.data.normal_(0, 0.01)
    def forward(self, x):
        out = self.conv2d_list[0](x)
        for i in range(len(self.conv2d_list)-1):
            out += self.conv2d_list[i+1](x)
        return out
class ResNet(nn.Module):
    def __init__(self, block, layers,NoLabels):
        self.inplanes = 64
        super(ResNet, self).__init__()
        self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3,bias=False)
        self.bn1 = nn.BatchNorm2d(64,affine = affine_par)
        for i in self.bn1.parameters():
            i.requires_grad = False
        self.relu = nn.ReLU(inplace=True)
        self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1, ceil_mode=True) # change
        self.layer1 = self._make_layer(block, 64, layers[0])
        self.layer2 = self._make_layer(block, 128, layers[1], stride=2)
        self.layer3 = self._make_layer(block, 256, layers[2], stride=1, dilation__ = 2)
        self.layer4 = self._make_layer(block, 512, layers[3], stride=1, dilation__ = 4)
        self.layer5 = self._make_pred_layer(Classifier_Module, [6,12,18,24],[6,12,18,24],NoLabels)
        for m in self.modules():
            if isinstance(m, nn.Conv2d):
                #n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels
                m.weight.data.normal_(0, 0.01)
            elif isinstance(m, nn.BatchNorm2d):
                m.weight.data.fill_(1)
                m.bias.data.zero_()
    def _make_layer(self, block, planes, blocks, stride=1,dilation__ = 1):
        downsample = None
        if stride != 1 or self.inplanes != planes * block.expansion or dilation__ == 2 or dilation__ == 4:
            downsample = nn.Sequential(nn.Conv2d(self.inplanes, planes * block.expansion,kernel_size=1, stride=stride, bias=False),nn.BatchNorm2d(planes * block.expansion,affine = affine_par))
        for i in downsample._modules['1'].parameters():
            i.requires_grad = False
        layers = []
        layers.append(block(self.inplanes, planes, stride,dilation_=dilation__, downsample = downsample ))
        self.inplanes = planes * block.expansion
        for i in range(1, blocks):
            layers.append(block(self.inplanes, planes,dilation_=dilation__))
        return nn.Sequential(*layers)
    def _make_pred_layer(self,block, dilation_series, padding_series,NoLabels):
        return block(dilation_series,padding_series,NoLabels)
    def forward(self, x):
        x = self.conv1(x)
        x = self.bn1(x)
        x = self.relu(x)
        x = self.maxpool(x)
        x = self.layer1(x)
        x = self.layer2(x)
        x = self.layer3(x)
        x = self.layer4(x)
        x = self.layer5(x)

        return x

class MS_Deeplab(nn.Module):
    def __init__(self,block,NoLabels):
	    super(MS_Deeplab,self).__init__()
	    self.Scale = ResNet(block,[3, 4, 23, 3],NoLabels)   #changed to fix #4
    def forward(self,x):
        input_size = x.size()[2]
        self.interp1 = nn.Upsample(size = (  int(input_size*0.75)+1,  int(input_size*0.75)+1  ),mode='bilinear')
        self.interp2 = nn.Upsample(size = (  int(input_size*0.5)+1,   int(input_size*0.5)+1   ),mode='bilinear')
        self.interp3 = nn.Upsample(size = (  outS(input_size),   outS(input_size)   ),mode='bilinear')
        out = []
        out1 = []
        x2 = self.interp1(x)
        x3 = self.interp2(x)
        a1 = self.Scale(x)
        a0 = F.softmax(self.Scale(x),1)
        out.append(a0)	# for original scale
        out1.append(self.Scale(x))
        y = self.Scale(x2)
        a2 = self.interp3(y)
        z1 = F.softmax(y,1)

        out.append(z1)#or 0.75x scale
        out1.append(y)
        a3 = self.Scale(x3)
        a4 = F.softmax(self.Scale(x3),1)
        out.append(a4)

        out1.append(self.Scale(x3))

        x2Out_interp = a2
        x3Out_interp = self.interp3(a3)
        temp1 = torch.max(a1,x2Out_interp)
        a5 = F.softmax(torch.max(temp1,x3Out_interp),1)
        out.append(a5)
        out1.append(torch.max(temp1,x3Out_interp))

        return out,out1

class Fire(nn.Module):

    def __init__(self, inplanes, squeeze_planes,
                 expand1x1_planes, expand3x3_planes):
        super(Fire, self).__init__()
        def conv_dw(inp, oup, stride):
            return nn.Sequential(
            nn.Conv2d(inp, inp, 3, stride, 1, groups=inp, bias=False),
            nn.BatchNorm2d(inp),
            nn.ReLU(inplace=True),

            nn.Conv2d(inp, oup, 1, 1, 0, bias=False),
            nn.BatchNorm2d(oup),
            nn.ReLU(inplace=True),
        )
        self.inplanes = inplanes

        self.bn1 = nn.BatchNorm2d(inplanes)#me

        self.squeeze = nn.Conv2d(inplanes, squeeze_planes, kernel_size=1)
        self.squeeze_activation = nn.ReLU(inplace=True)

        self.bn2 = nn.BatchNorm2d(squeeze_planes)#me
        self.expand1x1 = nn.Conv2d(squeeze_planes, expand1x1_planes,
                                   kernel_size=1)
        self.expand1x1_activation = nn.ReLU(inplace=True)

#        self.bn3 = nn.BatchNorm2d(squeeze_planes)#me
#        self.expand3x3 = nn.Conv2d(squeeze_planes, expand3x3_planes,
#                                   kernel_size=3, padding=1)
#        self.expand3x3_activation = nn.ReLU(inplace=True)
        self.expand3x3 = conv_dw(squeeze_planes, expand3x3_planes,1)

    def forward(self, x):
        x = self.squeeze_activation(self.squeeze(self.bn1(x)))
        return torch.cat([
            self.expand1x1_activation(self.expand1x1(self.bn2(x))),
            self.expand3x3(x)
        ], 1)

class UpBlock(nn.Module):
    def __init__(self, in_size, out_size, kernel_size=3, activation=F.relu, space_dropout=False):

        def conv_dw(inp, oup, stride):
            return nn.Sequential(
                nn.Conv2d(inp, inp, 3, stride, 1, groups=inp, bias=False),
                nn.BatchNorm2d(inp),
                nn.ReLU(inplace=True),

                nn.Conv2d(inp, oup, 1, 1, 0, bias=False),
                nn.BatchNorm2d(oup),
                nn.ReLU(inplace=True),
            )

        def tconv_dw(inp, oup, stride):
            return nn.Sequential(
                nn.ConvTranspose2d(inp, inp, 2, stride, groups=inp, bias=False),
                nn.BatchNorm2d(inp),
                nn.ReLU(inplace=True),

                nn.Conv2d(inp, oup, 1, 1, 0, bias=False),
                nn.BatchNorm2d(oup),
                nn.ReLU(inplace=True),
            )

        super(UpBlock, self).__init__()
        #self.up = nn.ConvTranspose2d(in_size, out_size, kernel_size= 2, stride=2)
        self.up = tconv_dw(in_size, out_size, 2)
        self.conv = conv_dw(in_size, out_size,1)
#        self.conv_extra = nn.Sequential(
#                nn.Conv2d(in_size, out_size, 1, 1, 0, bias=False),
#                nn.BatchNorm2d(out_size),
#                nn.ReLU(inplace=True),
#            )

    def forward(self, x, bridge):
        #print("x",x.size())
        #print("bridge",bridge.size())
        #if x.size()[2:] != bridge.size()[2:]:
        up = self.up(x)
        up = F.upsample(up,size=bridge.size()[2:],mode='bilinear',align_corners=True)
        #else:
         #    up = self.conv_extra(x)
        #print("up",up.size())
        crop1 = bridge
        out = torch.cat([up, crop1], 1)
        out = self.conv(out)
        return out

class SqueezeNet(nn.Module):

    def __init__(self, num_classes ,version=1.1 ):
        super(SqueezeNet, self).__init__()
        self.num_classes = num_classes

        self.mod1 = nn.Sequential(
            nn.Conv2d(3, 64, kernel_size=3, stride=2),
            nn.ReLU(inplace=True)
            )

        self.mod2 = nn.Sequential(
            nn.AvgPool2d(kernel_size=3, stride=2, ceil_mode=True),
            Fire(64, 16, 64, 64),
            Fire(128, 16, 64, 64),
            )

        self.mod3 = nn.Sequential(
                nn.AvgPool2d(kernel_size=3, stride=2, ceil_mode=True),
                Fire(128, 32, 128, 128),
                Fire(256, 32, 128, 128),
               )

        self.mod4 = nn.Sequential(
            nn.AvgPool2d(kernel_size=3, stride=2, ceil_mode=True),
            Fire(256, 48, 192, 192),
            Fire(384, 48, 192, 192),
            Fire(384, 64, 256, 256),
            Fire(512, 64, 256, 256),
            )

        self.up3 = UpBlock(512,256)
        self.up2 = UpBlock(256,128)
        self.up1 = UpBlock(128,64)
        self.last = nn.Conv2d(64, self.num_classes, 1)

#        final_conv = nn.Conv2d(64, self.num_classes, kernel_size=1)#512
#        self.classifier = nn.Sequential(
#            nn.Dropout(p=0.5),
#            final_conv,
##            nn.ReLU(inplace=True),
#            #nn.AvgPool2d(13, stride=1)
#        )

#        for m in self.modules():
#            if isinstance(m, nn.Conv2d):
#                if m is final_conv:
#                    init.normal_(m.weight, mean=0.0, std=0.01)
#                else:
#                    init.kaiming_uniform_(m.weight)
#                if m.bias is not None:
#                    init.constant_(m.bias, 0)

    def forward(self, x):
        #print(x.size())
        x1 = self.mod1(x)
        #print(x.size())
        x2 = self.mod2(x1)
        #print(x.size())
        x3 = self.mod3(x2)
        #print(x.size())
        x4 = self.mod4(x3)
        #print(x4.size())
        up3 = self.up3(x4,x3)
        #print(up3.size())
        up2 = self.up2(up3,x2)
        #print(up2.size())
        up1 = self.up1(up2,x1)
        #print(up1.size())

        #x = self.classifier(x)
        return F.upsample(self.last(up1),size=x.size()[2:],mode='bilinear',align_corners=True)

class UpBlock_mobile(nn.Module):
    def __init__(self, in_size, out_size, kernel_size=3, activation=F.relu):

        def conv_dw(inp, oup, stride):
            return nn.Sequential(
                nn.Conv2d(inp, inp, 3, stride, 1, groups=inp, bias=False),
                nn.BatchNorm2d(inp),
                nn.ReLU(inplace=True),

                nn.Conv2d(inp, oup, 1, 1, 0, bias=False),
                nn.BatchNorm2d(oup),
                nn.ReLU(inplace=True),
            )

        def tconv_dw(inp, oup, stride):
            return nn.Sequential(
                nn.ConvTranspose2d(inp, inp, 2, stride, groups=inp, bias=False),
                nn.BatchNorm2d(inp),
                nn.ReLU(inplace=True),

                nn.Conv2d(inp, oup, 1, 1, 0, bias=False),
                nn.BatchNorm2d(oup),
                nn.ReLU(inplace=True),
            )

        super(UpBlock_mobile, self).__init__()
        #self.up = nn.ConvTranspose2d(in_size, out_size, kernel_size= 2, stride=2)
        self.up = tconv_dw(in_size, out_size, 2)
        self.conv = conv_dw(in_size, out_size,1)

    def forward(self, x, bridge):
        #print("x",x.size())
        #print("bridge",bridge.size())
        up = self.up(x)
        #print("up",up.size())

        if bridge.size()[2:] != up.size()[2:]:
            crop1 = F.upsample(bridge,size=up.size()[2:],mode='bilinear', align_corners = True)
        else:
            crop1 = bridge

        out = torch.cat([up, crop1], 1)
        out = self.conv(out)
        return out

class MobileNet(nn.Module):
    def __init__(self,nc):
        super(MobileNet, self).__init__()

        def conv_bn(inp, oup, stride):
            return nn.Sequential(
                nn.Conv2d(inp, oup, 3, stride, 1, bias=False),
                nn.BatchNorm2d(oup),
                nn.ReLU(inplace=True)
            )

        def conv_dw(inp, oup, stride):
            return nn.Sequential(
                nn.Conv2d(inp, inp, 3, stride, 1, groups=inp, bias=False),
                nn.BatchNorm2d(inp),
                nn.ReLU(inplace=True),

                nn.Conv2d(inp, oup, 1, 1, 0, bias=False),
                nn.BatchNorm2d(oup),
                nn.ReLU(inplace=True),
            )

        self.num_classes = nc
        self.a = conv_bn(  3,  32, 2)
        self.b = conv_dw( 32,  64, 1)
        self.c = conv_dw( 64, 128, 2)
        self.d = conv_dw(128, 128, 1)
        self.e = conv_dw(128, 256, 2)
        self.f = conv_dw(256, 256, 1)
        self.g = conv_dw(256, 512, 2)
        self.h = conv_dw(512, 512, 1)
        self.i = conv_dw(512, 512, 1)
        self.j = conv_dw(512, 512, 1)
        self.k = conv_dw(512, 512, 1)
        self.l = conv_dw(512, 512, 1)
        self.m = conv_dw(512, 1024, 2)
        self.n = conv_dw(1024, 1024, 1)

        self.up3 = UpBlock_mobile(1024,512)
        self.up2 = UpBlock_mobile(512,256)
        self.up1 = UpBlock_mobile(256,128)
        self.up0 = UpBlock_mobile(128,64)
        self.last = nn.Conv2d(64, self.num_classes, 1)

    def forward(self, x):
        xa = self.a(x)
        #print(xa.size())
        xb = self.b(xa)
        #print(xb.size())

        xc = self.c(xb)
        #print(xc.size())
        xd = self.d(xc)
        #print(xd.size())

        xe = self.e(xd)
        #print(xe.size())
        xf = self.f(xe)
        #print(xf.size())

        xg = self.g(xf)
        #print(xg.size())
        xh = self.h(xg)
        #print(xh.size())
        xi = self.i(xh)
        #print(xi.size())
        xj = self.j(xi)
        #print(xj.size())
        xk = self.k(xj)
        #print(xk.size())
        xl = self.l(xk)
        #print(xl.size())

        xm = self.m(xl)
        #print(xm.size())
        xn = self.n(xm)
        #print(xn.size())

        up3 = self.up3(xn,xl)
        #print(up3.size())
        up2 = self.up2(up3,xf)
        #print(up2.size())
        up1 = self.up1(up2,xd)
        #print(up1.size())
        up0 = self.up0(up1,xb)
        #print(up0.size())
        return F.upsample(self.last(up0),size=x.size()[2:],mode='bilinear', align_corners = True)

def load_model(model_name,noc):
    if model_name == 'deeplab':
        model = MS_Deeplab(Bottleneck1,noc)
    if model_name=='fcn':
        model = FCN8s(noc)
    if model_name=='segnet':
        model = SegNet(3,noc)
    if model_name=='pspnet':
        model = PSPNet(noc)
    if model_name=='unet':
        model = UNet(noc)
    if model_name=='tiramisu':
        model = FCDenseNet103(noc)
    if model_name == 'squeezenet':
        model =  SqueezeNet(noc)
    if model_name == 'mobilenet':
        model =  MobileNet(noc)
    return model


from typing import Any

import pytest

from app.handlers import get_handler_from_string, get_handler_from_url
from app.handlers.base import ServiceHandler
from app.handlers.exceptions import HandlerNotFoundError
from app.services.ytdlp import AwaitingTranscodingError, FormatNotFoundError

def test_get_handler_from_url() -> None:
    """
    Tests the `get_handler_from_url` function.
    """
    url = "https://www.youtube.com/watch?v=1234567890"
    handler = get_handler_from_url(url=url)
    assert handler.__class__.__name__ == "YoutubeHandler"

    url = "https://www.rumble.com/v1234567890"
    handler = get_handler_from_url(url=url)
    assert handler.__class__.__name__ == "RumbleHandler"

    url = "https://www.bitchute.com/video/1234567890"
    with pytest.raises(HandlerNotFoundError):
        get_handler_from_url(url=url)

def test_get_handler_from_string() -> None:
    """
    Tests the `get_handler_from_string` function.
    """
    handler_string = "YoutubeHandler"
    handler = get_handler_from_string(handler_string=handler_string)
    assert handler.__class__.__name__ == "YoutubeHandler"

    handler_string = "RumbleHandler"
    handler = get_handler_from_string(handler_string=handler_string)
    assert handler.__class__.__name__ == "RumbleHandler"

    handler_string = "BitchuteHandler"
    with pytest.raises(HandlerNotFoundError):
        get_handler_from_string(handler_string=handler_string)

async def test_map_video_info_dict_entity_to_video_dict_format_id_keyerror(
    mocked_entry_info_dict: dict[str, Any]
) -> None:
    # Test missing format_id key
    with pytest.raises(FormatNotFoundError):
        entry_info_dict = mocked_entry_info_dict.copy()
        entry_info_dict.pop("format_id")
        ServiceHandler()._get_format_info_dict_from_entry_info_dict(entry_info_dict=entry_info_dict)  # type: ignore

    # Test missing formats key
    with pytest.raises(FormatNotFoundError):
        entry_info_dict = mocked_entry_info_dict.copy()
        entry_info_dict.pop("formats")
        ServiceHandler()._get_format_info_dict_from_entry_info_dict(entry_info_dict=entry_info_dict)  # type: ignore

    # Test missing formats key, but awaiting_transcoding is True
    with pytest.raises(AwaitingTranscodingError):
        entry_info_dict = mocked_entry_info_dict.copy()
        entry_info_dict.pop("formats")
        entry_info_dict["awaiting_transcoding"] = True
        ServiceHandler()._get_format_info_dict_from_entry_info_dict(entry_info_dict=entry_info_dict)  # type: ignore

    # Test m3u8 in url
    with pytest.raises(AwaitingTranscodingError):
        entry_info_dict = mocked_entry_info_dict.copy()
        entry_info_dict["formats"][0]["url"] = "https://somedomain.com/somepath.m3u8"
        ServiceHandler()._get_format_info_dict_from_entry_info_dict(entry_info_dict=entry_info_dict)  # type: ignore


# -*- coding: utf-8 -*-
"""
Created on Sun Dec  9 19:50:01 2018

@author: Adam
"""
import smtplib
def napismi():
    import smtplib
    content="Ahoj jak se máš"
    mail=smtplib.SMTP("smtp.gmail.com",587)
    mail.ehlo()
    mail.starttls()
    mail.login("zacpalweb@gmail.com","kavanata123")
    mail.sendmail("zacpalweb@gmail.com","adamzacpal@seznam.cz",content)
    mail.close()


import nltk
from nltk.corpus import stopwords
from nltk.stem import WordNetLemmatizer

# Baixe os recursos necessários
nltk.download('stopwords')
nltk.download('wordnet')

# Exemplo de texto
text = "Os gatos estão pulando sobre as cercas e correndo nos jardins"

# Tokenização
tokens = nltk.word_tokenize(text)

# Remoção de stopwords
stop_words = set(stopwords.words('portuguese'))
filtered_tokens = [token for token in tokens if token.lower() not in stop_words]

# Lematização
lemmatizer = WordNetLemmatizer()
lemmatized_tokens = [lemmatizer.lemmatize(token) for token in filtered_tokens]

# Resultados
print("Tokens originais:", tokens)
print("Tokens filtrados:", filtered_tokens)
print("Tokens lematizados:", lemmatized_tokens)


import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score, classification_report

# Load the dataset
data_url = "https://example.com/diabetes_dataset.csv"
df = pd.read_csv(data_url)

# Data preprocessing
X = df.drop("diabetes", axis=1)
y = df["diabetes"]

# Split the data into training and testing sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# Train a Random Forest classifier
rf_model = RandomForestClassifier(random_state=42)
rf_model.fit(X_train, y_train)

# Make predictions on the test set
y_pred = rf_model.predict(X_test)

# Evaluate the model
accuracy = accuracy_score(y_test, y_pred)
report = classification_report(y_test, y_pred)

# Print the results
print("Random Forest Classifier Results:")
print(f"Accuracy: {accuracy:.2f}")
print("Classification Report:")
print(report)


import datetime
from time import time

from Lab3.api import create_account, make_bet
from Lab3.mt import MersenneRng

def get_mt_generator(account_id, first_timestamp, second_timestamp):
    response = make_bet('Mt', account_id, 1, 0)
    seed = first_timestamp

    while True:
        generator = MersenneRng(seed)
        new_generated_value = generator.get_random_number()
        seed += 1
        if new_generated_value == response['realNumber'] or seed > second_timestamp + 1:
            break

    return generator

def crack_mt():
    first_timestamp = int(time()) - 1
    account = create_account()
    second_timestamp = int(time())

    generator = get_mt_generator(account['id'], first_timestamp, second_timestamp)

    money = 0
    while money < 1_000_000:
        response = make_bet('Mt', account['id'], 10, generator.get_random_number())
        money = response['account']['money']

if __name__ == "__main__":
    crack_mt()


import builtins
from collections import namedtuple
import inspect
from .. import context

AllVars = namedtuple('AllVars', 'nonlocals globals builtins')

def getallvars(obj):
    """
    Get the mapping of *all* variables to their current values.

    Returns a named tuple of dicts mapping the current nonlocal, global
    and builtin references as seen by the body of the function. A final
    set of unbound names that could not be resolved is also provided.
    """

    # FIXME:
    # `getclosurevars` doesn't capture type annotation, it is the reason that we use frame
    # to get all vars in `f_locals` but not those from func.__closure__ and code.__freevars__.
    # Also, `code.co_names` has the same issue that forbidding us to use `getclosurevars`.
    #
    # Commit fa090dbbabb99859afe701f736731104bce77d8e tried to use `getclosurevars` but failed
    # when trying to get Class definations in locals.
    #
    # This version is rather a redundent implementation to save all vars to module info. Anyone
    # can optimize it?

    frame = inspect.currentframe()
    while frame:
        if frame.f_locals.get(obj.__name__, None) is obj:
            break
        frame = frame.f_back

    if frame is None:
        nonlocal_vars = {}
    else:
        nonlocal_vars = frame.f_locals

    if inspect.isfunction(obj):
        global_ns = obj.__globals__
    elif frame is not None:
        global_ns = frame.f_globals
    else:
        global_ns = {}

    builtin_ns = global_ns.get("__builtins__", builtins.__dict__)
    if inspect.ismodule(builtin_ns):
        builtin_ns = builtin_ns.__dict__

    return AllVars(nonlocal_vars, global_ns, builtin_ns)

class ModuleAnalysis:

    def __init__(self) -> None:
        self.cls_ctx = None

    def run_impl(self, node: context.ASTNode):
        if node.module is None:
            # parser module info
            node.module = context.ModuleInfo()
            node.module.raw = inspect.getmodule(node.raw)

            global_syms = [o for o in inspect.getmembers(node.module.raw)]
            node.module.globals.update(global_syms)

            node.module.name = node.module.raw.__name__

            all_vars = getallvars(node.raw)
            node.module.globals.update(all_vars.builtins)
            node.module.globals.update(all_vars.nonlocals)
            node.module.globals.update(all_vars.globals)

            try:
                if inspect.isfunction(node.raw):
                    vars = inspect.getclosurevars(node.raw)
                    node.module.globals.update(vars.globals)
                    node.module.globals.update(vars.nonlocals)
                    node.module.globals.update(vars.builtins)
                elif inspect.isclass(node.raw):
                    try:
                        vars = inspect.getclosurevars(node.raw.__init__)
                        node.module.globals.update(vars.globals)
                        node.module.globals.update(vars.nonlocals)
                        node.module.globals.update(vars.builtins)
                    except:
                        pass

                    for func in inspect.getmembers(node.raw, inspect.isfunction):
                        if func.__name__ == '__init__':
                            continue
                        vars = inspect.getclosurevars(func)
                        node.module.globals.update(vars.globals)
                        node.module.globals.update(vars.nonlocals)
                        node.module.globals.update(vars.builtins)

            except:
                pass

            for name, obj in node.module.globals.items():
                try:
                    node.module.imports[name] = inspect.getabsfile(obj)
                except TypeError:
                    pass

    def run(self, sc_ctx: context.ScriptContext):
        self.run_impl(sc_ctx.main_node)
        for dep_node in sc_ctx.deps_node:
            self.run_impl(dep_node)


import cv2
import numpy as np

cap = cv2.VideoCapture('คงจะดีนะ.mp4')
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
vdo_writer = cv2.VideoWriter('out.mp4', fourcc, 30, (426, 240))
n_buffer = 10
buffer = None
iframe = 0
while True:
    ret, frame = cap.read()
    if not ret:
        break
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    if buffer is None:
        buffer = np.zeros((n_buffer, *gray.shape))
    buffer[iframe % n_buffer] = gray
    if iframe >= n_buffer:
        # M = np.mean(buffer, axis=0)
        M = np.median(buffer, axis=0)
        diff = cv2.absdiff(gray, np.uint8(M))
        fg = np.uint8((diff > .4 * np.max(diff)) * 255)
        cv2.imshow('fg', fg)
    cv2.imshow('frame', frame)
    if cv2.waitKey(1) == ord('q') or not ret:
        break
    iframe += 1
    vdo_writer.write(frame)

vdo_writer.release()


"""
Faça um programa que leia o peso
de cinco pessoas. No final, mostre qual
foi o maior e o menor peso lidos.
"""

maior = 0
menor = 0

for x in range(1, 6):
    peso = float(input(f"Informe o peso da {x}º pessoa: "))

    if x == 1:
        menor = peso
        maior = peso
    else:
        if peso > maior:
            maior = peso
        else:
            menor = peso

print(f"O maior peso digitado foi {maior:.2f} kg")
print(f"O menor peso digitado foi {menor:.2f} kg")


# importing the requests library
import requests

def testget(geturl,val):
    # defining a params dict for the parameters to be sent to the API
    PARAMS = {'ID':val}

    # sending get request and saving the response as response object
    r = requests.get(url = geturl, params = PARAMS)

    # extracting data in json format
    data = r.json()
    print('GET returned: {}'.format(data))
    #check the HTTP status code
    print('GET status: {}'.format(r.status_code))

def testpost(posturl,val1,val2):
    # defining a params dict for the parameters to be sent to the API
    PARAMS = {'name':val1, 'surName':val2}

    # sending get request and saving the response as response object
    r = requests.post(url = posturl, params = PARAMS)
    #nothing is returned, just check the HTTP status code
    print('POST status: {}'.format(r.status_code))

def main():
    url = 'http://localhost:8080/test/GetName'
    testget(url,'foo')
    url = 'http://localhost:8080/test/SaveName'
    testpost(url,'name1','name2')

if __name__ == '__main__':
  main()


class Solution(object):
    def removeDuplicates(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        left = 0
        count = 0
        for right in range(len(nums)):
            if right == 0:
                count += 1
                nums[left] = nums[right]
                left += 1
            elif nums[right] == nums[right-1]:
                if count == 2: continue
                count += 1
                nums[left] = nums[right]
                left += 1
            else:
                count = 1
                nums[left] = nums[right]
                left += 1

        return left

a = Solution()
lst = [1, 1, 1, 2, 2, 3]
a.removeDuplicates(lst)
print(lst)


#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
An incomplete sample script.

This is a bot to create list of articles about women from pagegenerator

Use global -simulate option for test purposes. No changes to live wiki
will be done.

The following parameters are supported:

-always           The bot won't ask for confirmation when putting a page

-text:            Use this text to be added; otherwise 'Test' is used

-replace:         Don't add text but replace it

-top              Place additional text on top of the page

-summary:         Set the action summary message for the edit.

All settings can be made either by giving option with the command line
or with a settings file which is scripts.ini by default. If you don't
want the default values you can add any option you want to change to
that settings file below the [basic] section like:

    [basic] ; inline comments starts with colon
    # This is a commend line. Assignments may be done with '=' or ':'
    text: A text with line break and
        continuing on next line to be put
    replace: yes ; yes/no, on/off, true/false and 1/0 is also valid
    summary = Bot: My first test edit with pywikibot

Every script has its own section with the script name as header.

In addition the following generators and filters are supported but
cannot be set by settings file:

&params;
"""
#
# (C) Pywikibot team, 2006-2020
#
# Distributed under the terms of the MIT license.
#
import pywikibot
from pywikibot import pagegenerators

from pywikibot.bot import (
    SingleSiteBot, ConfigParserBot, ExistingPageBot, NoRedirectPageBot,
    AutomaticTWSummaryBot)
from pywikibot.tools import PYTHON_VERSION

if PYTHON_VERSION >= (3, 9):
    Tuple = tuple
else:
    from typing import Tuple
import datetime

# This is required for the text that is shown when you run this script
# with the parameter -help.
docuReplacements = {'&params;': pagegenerators.parameterHelp}  # noqa: N816

class BasicBot(
    # Refer pywikobot.bot for generic bot classes
    SingleSiteBot,  # A bot only working on one site
    ConfigParserBot,  # A bot which reads options from scripts.ini setting file
    # CurrentPageBot,  # Sets 'current_page'. Process it in treat_page method.
    #                  # Not needed here because we have subclasses
    ExistingPageBot,  # CurrentPageBot which only treats existing pages
    NoRedirectPageBot,  # CurrentPageBot which only treats non-redirects
    AutomaticTWSummaryBot,  # Automatically defines summary; needs summary_key
):
    """
    An incomplete sample bot.

    @ivar summary_key: Edit summary message key. The message that should be
        used is placed on /i18n subdirectory. The file containing these
        messages should have the same name as the caller script (i.e. basic.py
        in this case). Use summary_key to set a default edit summary message.

    @type summary_key: str
    """

    summary_key = 'basic-changing'

    def __init__(self, generator, **kwargs) -> None:
        """
        Initializer.

        @param generator: the page generator that determines on which pages
            to work
        @type generator: generator
        """
        # Add your own options to the bot and set their defaults
        # -always option is predefined by BaseBot class
        self.available_options.update({
            'replace': False,  # delete old text and write the new text
            'summary': None,  # your own bot summary
            'text': 'Test',  # add this text from option. 'Test' is default
            'top': False,  # append text on top of the page
            'outpage': u'User:mastiBot/test',  # default output page
            'maxlines': 1000,  # default number of entries per page
            'test': False,  # print testoutput
            'progress': False,  # report progress
            'negative': False,  # if True negate behavior i.e. mark pages that DO NOT contain search string
        })

        # call initializer of the super class
        super().__init__(site=True, **kwargs)
        # assign the generator to the bot
        self.generator = generator

    def run(self):
        """TEST"""
        pywikibot.output(u'THIS IS A RUN METHOD')
        outputpage = self.getOption('outpage')
        pywikibot.output(u'OUTPUTPAGE:%s' % outputpage)

        # create structure for output
        arts = {}
        pagecounter = 0

        for p in self.generator:
            if self.getOption('test') or self.getOption('progress'):
                pywikibot.output(u'[%s] Treating #%i: %s' % (
                datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), pagecounter, p.title()))
                pagecounter += 1

            arts[p.title()] = self.treat(p)

        self.generateresultspage(arts, self.getOption('outpage'), '', '')

    def toMain(self, page):
        # return main namespace object
        #pywikibot.output("toMain NAMESPACE: %i" % page.namespace())
        if page.namespace() == 1:
            return (page.toggleTalkPage())
        else:
            return page

    def treat(self, page) -> None:
        """Load the given page, do some changes, and save it."""
        text = page.text

        ################################################################
        # NOTE: Here you can modify the text in whatever way you want. #
        ################################################################

        page = self.toMain(page)
        #pywikibot.output("NAMESPACE %i" % page.namespace())
        sex = self.checkWomen(page)
        pywikibot.output("PŁEĆ:%s" % sex)
        return(sex)

    def checkWomen(self, art):
        # check if the article is about woman
        # using WikiData
        try:
            d = art.data_item()

            dataItem = d.get()
            claims = dataItem['claims']
        except:
            return ("NO WIKIDATA")
        try:
            gender = claims["P21"]
        except:
            return ("NO GENDER")
        for c in gender:
            cjson = c.toJSON()
            genderclaim = cjson[u'mainsnak'][u'datavalue'][u'value'][u'numeric-id']
            if u'6581072' == str(genderclaim):
                if self.getOption('test'):
                    pywikibot.output(u'%s:Woman' % art.title())
                return ("woman")
            else:
                if self.getOption('test'):
                    pywikibot.output(u'%s:Man' % art.title())
                return ("other")
        return ("NO VALUE")

    def generateresultspage(self, redirlist, pagename, header, footer):
        """
        Generates results page from redirlist
        Starting with header, ending with footer
        Output page is pagename
        """
        finalpage = header
        # res = sorted(redirlist, key=redirlist.__getitem__, reverse=False)
        res = redirlist.keys()
        itemcount = 0

        for i in res:
            if redirlist[i] == 'woman':
                finalpage += '\n# [[%s]]' % i

        finalpage += footer

        outpage = pywikibot.Page(pywikibot.Site(), pagename)
        outpage.text = finalpage

        if self.getOption('test'):
            pywikibot.output(outpage.title())

        outpage.save(summary=self.getOption('summary'))

def main(*args: Tuple[str, ...]) -> None:
    """
    Process command line arguments and invoke bot.

    If args is an empty list, sys.argv is used.

    @param args: command line arguments
    """
    options = {}
    # Process global arguments to determine desired site
    local_args = pywikibot.handle_args(args)

    # This factory is responsible for processing command line arguments
    # that are also used by other scripts and that determine on which pages
    # to work on.
    gen_factory = pagegenerators.GeneratorFactory()

    # Parse command line arguments
    for arg in local_args:

        # Catch the pagegenerators options
        if gen_factory.handleArg(arg):
            continue  # nothing to do here

        # Now pick up your own options
        arg, sep, value = arg.partition(':')
        option = arg[1:]
        if option in ('summary', 'text'):
            if not value:
                pywikibot.input('Please enter a value for ' + arg)
            options[option] = value
        # take the remaining options as booleans.
        # You will get a hint if they aren't pre-defined in your bot class
        else:
            options[option] = True

    # The preloading option is responsible for downloading multiple
    # pages from the wiki simultaneously.
    gen = gen_factory.getCombinedGenerator(preload=True)
    if gen:
        # pass generator and private options to the bot
        bot = BasicBot(gen, **options)
        bot.run()  # guess what it does
    else:
        pywikibot.bot.suggest_help(missing_generator=True)

if __name__ == '__main__':
    main()


#!/opt/python/bin/python
#
# Wrapper around mediainfo that enables comparing two files side-by-side
#
# Known issues:
#    - It only compares the first video and audio stream it finds, 2nd+ are ignored,
#    - It outputs to three columns to provide a side-by-side view, but column widths aren't pretty
#    - Column width is set up the 'General:Complete_name' field, and field longer will get truncated
#      This affects the 'Video:Encoding_settings' and a few other fields. Is by design.
#    - It tries to keep the order, but fields in the 2nd file not present in the 1st get shuffled
#      to the bottom rather than injected into the middle. I'm not sure how to clean that up.
# Future ideas:
#    - only print out interesting fields, drop things like 'Encoding_settings'
#    - add a -t option that creates a tab-separated output instead of columns, won't need to truncate
#
from collections import OrderedDict
from collections import defaultdict
import subprocess
import lxml
import argparse
import xmltodict
import json
# Parse the command line arguments
#
parser = argparse.ArgumentParser(description='Wrapper for mediainfo to compare two files side-by-side')
parser.set_defaults(v=False)
parser.add_argument('-v', '--verbose', required=False,
                    dest='verbose', default=False, action='store_true',
                    help='include verbose debugging output')
parser.add_argument('file1',
                    help='the first media file')
parser.add_argument('file2',
                    help='the second media file')
args = parser.parse_args()
# logging output to validate arguments are read correctly
if args.verbose: print('file 1 = ' + args.file1)
if args.verbose: print('file 2 = ' + args.file2)
if args.verbose: print('')

# execute mediainfo against specified file
#
def exec_mediainfo(file):
    mediainfo_out = subprocess.Popen(['mediainfo','--output=XML',file],
                                     stdout=subprocess.PIPE,
                                     stderr=subprocess.STDOUT)
    returncode = mediainfo_out.wait()
    #logging output to validate mediainfo execution produced what we expected
    if args.verbose: print('mediainfo returned {0}'.format(returncode))
    if args.verbose: print('mediainfo for ' + file)# + ':\n' + mediainfo_out.stdout.read())
    # put the output in 'tracks', trim off the top layers of the tree
    output = mediainfo_out.stdout.read()
    x2dict = xmltodict.parse(output)
    tracks = x2dict['Mediainfo']['File']['track']
    # tracks is a list of dict, one list item per track with dict items per data point
    # next block converts the list to a dict using track id as the key
    # this allows us to compare files with different numbers of tracks
    if args.verbose: print('Converting XML to dict...')
    data = OrderedDict()
    for track in tracks:
        if track['@type'] == 'General':
            key = 'g'
        elif track['@type'] == 'Video':
            key = 'v' + str(track['ID'])
        elif track['@type'] == 'Audio':
            key = 'a' + str(track['ID'])
        elif track['@type'] == 'Text':
            key = 's' + str(track['ID'])
        else:
            if args.verbose: print('Im lost')
        if args.verbose: print('Processing track: ' + key)
        if args.verbose: print(str(track.items()))
        data[key] = track
    # now return the dict of dict with track data
    #if args.verbose: print('Returning this: ' + str(data))
    return data
#
# end of exec_mediainfo()

# merge two dicts where {k1:v1} + {k1:v2} = {k1:[v1,v2]}
#
def merge_dict(dict1,dict2):
    if args.verbose: print('dict1: ' + str(dict1))
    if args.verbose: print('dict2: ' + str(dict2))
    # prepare to catch
    dict3 = OrderedDict()
    # iterate through first dict, create all the keys and blanks for the other dict
    for k, v in dict1.iteritems():
        dict3[k] = [v,'']
    # iterate through second dict, update or add depending on if key already exists
    for k, v in dict2.iteritems():
        if k in dict3:
            dict3[k][1] = v
        else:
            dict3[k] = ['',v]
    return dict3
#
# end of merge_dict()

# get the data from both files into dictionaries
#
if args.verbose: print('Executing mediainfo...')
mediainfo1 = exec_mediainfo(args.file1)
mediainfo2 = exec_mediainfo(args.file2)

# merge the two dictionaries together
#
if args.verbose: print('Merging data...')
# setup a new dict to catch, with tracks in correct order
# if left on its own they got out of order, so hard coding them to force the order
bothinfo = OrderedDict()
bothinfo['g'] = ''
bothinfo['v1'] = ''
bothinfo['a2'] = ''
# step through each track, combining the two inputs
for tracks in bothinfo:
    track = merge_dict(mediainfo1[tracks],mediainfo2[tracks])
    bothinfo[tracks] = track
if args.verbose: print('Merged: ')
if args.verbose: print(json.dumps(bothinfo,indent=2))

# print out the results
#
if args.verbose: print('Output time...')
# set column widths using file name as the width to match
# painfully long lines (e.g. 'Unique_ID', 'Encoding_settings') get truncated
c1 = c2 = c3 = 20
for track in bothinfo:
    for key in bothinfo[track].keys():
        if len(key) > c1: c1 = len(key) + 2
c2 = len(bothinfo['g']['Complete_name'][0])
c3 = len(bothinfo['g']['Complete_name'][1])
for track in bothinfo:
    print('')
    if args.verbose: print('Column widths: ' + str(c1) + ', ' + str(c2) + ', ' + str(c3))
    for key, values in bothinfo[track].iteritems():
        print("{k:<{c1}}\t".format(k=key, c1=c1) +
              "{v1:<{c2}.{t2}}\t".format(v1=str(values[0]), c2=c2, t2=c2) +
              "{v2:<{c3}.{t3}}".format(v2=str(values[1]), c3=c3, t3=c3))


from django.shortcuts import render, redirect
from .forms import ServeursForms
from . import models
from django.http import HttpResponseRedirect
from fpdf import FPDF
from django.http import FileResponse

def ajout(request):
    form = ServeursForms
    return render(request, "adminsite/serveurs/ajout.html", {"form": form})
def traitement(request):
    form = ServeursForms(request.POST)
    if form.is_valid():
        donnees = form.save(commit=False)
        donnees.stockage_initial = donnees.stockage
        donnees.save()
        return HttpResponseRedirect("/adminsite/serveurs/")
    else:
        return render(request, "adminsite/serveurs/ajout.html", {"form": form})

def index(request):
    app = list(models.Serveurs.objects.all())
    return render(request, 'adminsite/serveurs/affiche.html',{"liste": app})

def delete(request, id):
    stream = models.Serveurs.objects.get(pk=id)
    stream.delete()
    return HttpResponseRedirect("/adminsite/serveurs/")

def update_traitement(request, id):
    serv = models.Serveurs.objects.get(pk=id)

    serv.stockage_initial = str(serv.stockage_initial)
    if serv.stockage_initial.endswith("Go"):
        serv.stockage_initial = float(serv.stockage_initial[:-2]) * 1_000

    elif serv.stockage_initial.endswith("To"):
        serv.stockage_initial = float(serv.stockage_initial[:-2]) * 1_000_000
    serv.stockage_initial= float(serv.stockage_initial)

    serv.stockage = str(serv.stockage)
    if serv.stockage.endswith("Go"):
        serv.stockage = float(serv.stockage[:-2]) * 1_000

    elif serv.stockage.endswith("To"):
        serv.stockage = float(serv.stockage[:-2]) * 1_000_000
    serv.stockage= float(serv.stockage)

    stockage_service = serv.stockage_initial - serv.stockage

    mform = ServeursForms(request.POST)
    if mform.is_valid():
        serveur = mform.save(commit=False)

        serveur.stockage = str(serveur.stockage)
        if serveur.stockage.endswith("Go"):
            serveur.stockage = float(serveur.stockage[:-2]) * 1_000

        elif serveur.stockage.endswith("To"):
            serveur.stockage = float(serveur.stockage[:-2]) * 1_000_000
        serveur.stockage = float(serveur.stockage)

        if serveur.stockage < stockage_service:
            return render(request, "adminsite/serveurs/update.html", {"form": mform, "error": "Erreur pas assez de stockage sur le serveur","id": id})
        else:
            serveur.stockage_initial = serveur.stockage
            serveur.stockage = serveur.stockage - stockage_service
            if serveur.stockage < 1_000_000:
                serveur.stockage = serveur.stockage / 1000
                serveur.stockage = int(serveur.stockage)
                serveur.stockage = str(serveur.stockage) + "Go"
            else:
                serveur.stockage = serveur.stockage / 1_000_000
                serveur.stockage = int(serveur.stockage)
                serveur.stockage = str(serveur.stockage) + "To"

            if serveur.stockage_initial < 1_000_000:
                serveur.stockage_initial = serveur.stockage_initial / 1000
                serveur.stockage_initial = int(serveur.stockage_initial)
                serveur.stockage_initial = str(serveur.stockage_initial) + "Go"
            else:
                serveur.stockage_initial = serveur.stockage_initial / 1_000_000
                serveur.stockage_initial = int(serveur.stockage_initial)
                serveur.stockage_initial = str(serveur.stockage_initial) + "To"
            serveur.id = id
            serveur.save()
        return HttpResponseRedirect("/adminsite/serveurs/")
    else:
        return render(request, "adminsite/serveurs/update_affiche.html", {"form": mform, "id": id})

def update(request, id):
    serv = models.Serveurs.objects.get(pk=id)
    x = serv.stockage_initial
    serv.stockage_initial = serv.stockage
    serv.stockage = x
    form = ServeursForms(serv.dico())
    return render(request,"adminsite/serveurs/update.html",{"form":form, "id": id})

def affiche(request, id):
    var = models.Serveurs.objects.get(pk=id)
    return render(request,"adminsite/serveurs/affiche.html",{"util": var, "id": id})

def serveur_pdf(request,id):
    serveur = models.Serveurs.objects.get(pk=id)
    pdf = FPDF()
    pdf.add_page()
    pdf.set_font("Arial", size=20)
    pdf.set_text_color(0, 0, 255)
    pdf.cell(200, 10,  ln=1, align='C')
    pdf.cell(200, 10, txt="RAPPORT SUR LE SERVEUR : " + serveur.nom, ln=1, align='C')
    pdf.cell(200, 10,  ln=1, align='C')
    pdf.set_font("Arial", size=15)
    pdf.cell(200, 10, txt="* Le serveur " + serveur.nom + " est un serveur de type " + models.Types.objects.get(
        pk=serveur.type.id).type, ln=2, align='L')
    pdf.cell(200, 10, txt="* Espace stockage: " + str(serveur.stockage_initial), ln=4, align='L')
    pdf.cell(200, 10, txt="* Espace restant: " + str(serveur.stockage), ln=5, align='L')
    pdf.cell(200, 10, txt="* Memoire vive: " + str(serveur.memoire), ln=6, align='L')
    pdf.cell(200, 10, txt="* Processeur: " + str(serveur.processeur), ln=8, align='L')
    line = 9
    pdf.cell(200, 10,  ln=1, align='C')
    if len(list(models.Applications.objects.filter(serveur=serveur))) == 0:
        pdf.cell(200, 10, txt="Il n'y a aucune application sur ce serveur.", ln=line, align='L')
        line = line + 1
    else:
        pdf.cell(200, 10, txt="* Les applications sur ce serveur:", ln=line, align='L')
        line = line + 1
        for i in list(models.Applications.objects.filter(serveur=serveur)):
            pdf.cell(200, 10, txt='         - ' +i.nom, ln=line, align='L')
            line = line + 1
    pdf.cell(200, 10,  ln=1, align='C')
    if len(list(models.Services.objects.filter(serveur_lancement=serveur))) == 0:
        pdf.cell(200, 10, txt="Il n'y a aucun service sur ce serveur.", ln=line, align='L')
        line = line + 1
    else:
        pdf.cell(200, 10, txt="* Les services sur ce serveur:", ln=line, align='L')
        line = line + 1
        for i in list(models.Services.objects.filter(serveur_lancement=serveur)):
            pdf.cell(200, 10, txt='         -'+i.nom, ln=line, align='L')
            line = line + 1
    pdf.output("Serveur-" + str(id) + ".pdf")
    response = FileResponse(open("Serveur-" + str(id) + ".pdf", 'rb'))
    return response


# -*- coding: utf-8 -*-
def my_sort(n):
    result_list = []
    for i in range(len(n)):
        for j in range(len(n)-1):
            if n[j] > n[j+1]:
                n[j], n[j+1] = n[j+1], n[j]

    while(True):
        a = n.pop(-1)
        result_list.append(a)
        b = n.pop(0)
        result_list.append(b)
        if len(result_list) == 10:
            break
    return result_list

T = int(input())
for t in range(1, T+1):
    N = int(input())
    N_list = list(map(int, input().split()))

    result = ' '.join(map(str, my_sort(N_list)))
    print('#{} {}'.format(t, result))


from typing import Any, Callable

class BinaryNode:
    value: Any
    left_child: 'BinaryNode'
    right_child: 'BinaryNode'

    def __init__(self, value: Any) -> None:
        self.value = value
        self.left_child = None
        self.right_child = None

    def min(self) -> 'BinaryNode':
        temp = self
        while temp.left_child is not None:
            temp = temp.left_child

    def traverse_in_order(self, visit: Callable[[Any], None]) -> None:
        if self.left_child is not None:
            self.left_child.traverse_in_order(visit)

        visit(self)

        if self.right_child is not None:
            self.right_child.traverse_in_order(visit)

f = print

def print(adres: Any) -> None:
    if isinstance(adres, BinaryNode):
        f(adres.value)
    else:
        f(adres)


"""
MIT License

Copyright (c) 2021 armaanbadhan

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""

import os
import discord
from discord.ext import commands
from keep_alive import keep_alive
from getpref import get_pref
import myembeds

print("Initializing...")

intents = discord.Intents.all()
client = commands.Bot(
    command_prefix=get_pref,
    intents=intents,
    case_insensitive=True,
    help_command=None,
    when_mentioned=True
)

@client.event
async def on_command_error(ctx, error):
    if isinstance(error, commands.CommandNotFound):
        return
    if isinstance(error, commands.MissingPermissions):
        await ctx.send(embed=myembeds.e_miss_perm_admin())
        return
    if isinstance(error, commands.CheckAnyFailure):
        await ctx.send(embed=myembeds.e_miss_perm_role())
        return
    if isinstance(error, commands.NotOwner):
        await ctx.send(embed=myembeds.e_miss_perm_owner())
        return
    print(error)

@client.command()
@commands.is_owner()
async def load(ctx, extension):
    client.load_extension(f"cogs.{extension}")
    await ctx.send(f"**Loaded {extension}**")

@client.command()
@commands.is_owner()
async def unload(ctx, extension):
    client.unload_extension(f"cogs.{extension}")
    await ctx.send(f"**Unloaded {extension}**")

@client.command()
@commands.is_owner()
async def reload(ctx, extension):
    client.reload_extension(f"cogs.{extension}")
    await ctx.send(f"**Reloaded {extension}**")

for filename in os.listdir("./cogs"):
    if filename.endswith(".py"):
        client.load_extension(f"cogs.{filename[:-3]}")

# Run the bot with the token
keep_alive()
client.run(os.getenv('TOKEN'))


from django.urls import path
from . import views

app_name = 'app'

urlpatterns = [
    path('', views.index, name='index'),
    path('contacts/', views.contacts, name='contacts'),
    path('register/', views.register, name='register'),
    path('logout/', views.logout_request, name='logout'),
    path('login/', views.login_request, name='login'),
]


import re

import cv2
import configparser
import json
import numpy as np
import threading
import gi

gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk, GdkPixbuf, Gio

class SettingsWindow(Gtk.Application):
    def __init__(self):
        super(SettingsWindow, self).__init__(application_id=None, flags=Gio.ApplicationFlags.FLAGS_NONE)
        self.coords_view_box = [[0.0, 0.0], [0.0, 0.0]]
        self.coords_analyse_box = [[0.0, 0.0], [0.0, 0.0]]
        self.img = GdkPixbuf.Pixbuf.new_from_file("example_img.png")
        self.load_area_data()

    def do_activate(self):
        builder = Gtk.Builder()
        builder.add_from_file("UI/settings_window.glade")
        builder.connect_signals(self)

        self.settings_window = builder.get_object("settings_window")
        self.radiobutton_camera = builder.get_object("radiobutton_from_camera")
        self.radiobutton_file = builder.get_object("radiobutton_from_file")
        self.spin_button = builder.get_object("camera_index_spin_button")
        self.file_chooser_button = builder.get_object("file_chooser_button")
        self.list_of_available_cameras = builder.get_object("list_available")
        self.list_of_working_cameras = builder.get_object("list_working")
        self.drawing_area = builder.get_object("mask_editor")
        self.toggle_view_box = builder.get_object("toggle_btn_choose_view_box")
        self.toggle_box_to_analyse = builder.get_object("toggle_btn_choose_box_to_analyse")

        self.area_accept_button = builder.get_object("area_accept_button")

        self.area_accept_button.connect("released", self.on_area_accept_button)
        self.toggle_view_box.connect("toggled", self.on_toggled, 1)
        self.toggle_box_to_analyse.connect("toggled", self.on_toggled, 2)
        self.toggle_box_to_analyse.set_active(True)

        self.drawing_area.add_events(Gdk.EventMask.BUTTON_PRESS_MASK)
        self.drawing_area.add_events(Gdk.EventMask.BUTTON1_MOTION_MASK)
        self.drawing_area.set_size_request(720, 576)
        self.drawing_area.queue_draw()
        self.load_settings()
        self.settings_window.show_all()

    def load_area_data(self):
        config = configparser.ConfigParser()
        config.read("settings.ini")
        self.coords_view_box = [[int(k) for k in i.split(", ")]
                                for i in config.get("area_coordinates", "coords_of_view_box")[2:-2].split("], [")]
        self.coords_analyse_box = [[int(k) for k in i.split(", ")]
                                   for i in
                                   config.get("area_coordinates", "coords_of_box_to_analyse")[2:-2].split("], [")]

    def on_area_accept_button(self, *_):
        config = configparser.ConfigParser()
        config.read("settings.ini")
        config.set("area_coordinates", "coords_of_view_box", str(self.coords_view_box))
        config.set("area_coordinates", "coords_of_box_to_analyse", str(self.coords_analyse_box))

        with open("settings.ini", 'w') as configfile:
            config.write(configfile)

    def on_toggled(self, obj, type_number):
        if type_number == 1 and self.toggle_view_box.get_active():
            self.toggle_box_to_analyse.set_active(False)
        elif type_number == 2 and self.toggle_box_to_analyse.get_active():
            self.toggle_view_box.set_active(False)

    def on_refresh_list_of_available_cameras(self, *_):
        is_working = True
        dev_port = 0
        working_ports = []
        available_ports = []
        while is_working and dev_port < 101:
            camera = cv2.VideoCapture(dev_port)
            if not camera.isOpened():
                is_working = False
            else:
                is_reading, img = camera.read()
                if is_reading:
                    working_ports.append(dev_port)
                else:
                    available_ports.append(dev_port)
            dev_port += 1

        if len(available_ports) == 0:
            self.list_of_available_cameras.set_text("None")
        else:
            tmp_str = ""
            for i in available_ports:
                tmp_str += str(i) + ' '
            self.list_of_available_cameras.set_text(tmp_str)

        if len(working_ports) == 0:
            self.list_of_working_cameras.set_text("None")
        else:
            tmp_str = ""
            for i in working_ports:
                tmp_str += str(i) + ' '
            self.list_of_working_cameras.set_text(tmp_str)

    def on_accept_changes(self, *_):
        config = configparser.ConfigParser()
        config.read("settings.ini")
        config.set("video_stream", "from_camera", str(self.radiobutton_camera.get_active()))
        config.set("video_stream", "from_file", str(self.radiobutton_file.get_active()))
        config.set("video_file", "video_file_name", str(self.file_chooser_button.get_filename()))
        config.set("video_camera", "video_camera_index", str(self.spin_button.get_value())[:-2])

        with open("settings.ini", 'w') as configfile:
            config.write(configfile)
        self.settings_window.destroy()

    def on_decline_changes(self, *_):
        self.settings_window.destroy()

    def load_settings(self):
        config = configparser.ConfigParser()
        config.read("settings.ini")

        if config["video_stream"]["from_camera"] == "True":
            self.radiobutton_camera.set_active(self)
        else:
            self.radiobutton_file.set_active(self)

        self.spin_button.set_value(int(config["video_camera"]["video_camera_index"]))
        self.file_chooser_button.set_filename(config["video_file"]["video_file_name"])

    def on_area_draw(self, widget, cr, *_):
        Gdk.cairo_set_source_pixbuf(cr, self.img, 0, 0)
        cr.paint()

        size_x = min(
            max(-self.coords_view_box[0][0], self.coords_view_box[1][0] - self.coords_view_box[0][0]),
            720 - self.coords_view_box[0][0]
        )
        size_y = min(
            max(-self.coords_view_box[0][1], self.coords_view_box[1][1] - self.coords_view_box[0][1]),
            576 - self.coords_view_box[0][1]
        )
        cr.set_source_rgba(0.0, 0.9, 0.0, 0.8)
        cr.rectangle(self.coords_view_box[0][0], self.coords_view_box[0][1], size_x, size_y)
        cr.stroke()

        size_x = min(
            max(-self.coords_analyse_box[0][0], self.coords_analyse_box[1][0] - self.coords_analyse_box[0][0]),
            720 - self.coords_analyse_box[0][0]
        )
        size_y = min(
            max(-self.coords_analyse_box[0][1], self.coords_analyse_box[1][1] - self.coords_analyse_box[0][1]),
            576 - self.coords_analyse_box[0][1]
        )
        cr.set_source_rgba(0.9, 0.9, 0.0, 0.8)
        cr.rectangle(self.coords_analyse_box[0][0], self.coords_analyse_box[0][1], size_x, size_y)
        cr.stroke()

    def on_area_pressed(self, widget, event):
        if event.type == Gdk.EventType.BUTTON_PRESS and event.button == 1:  # 1 == left mouse button
            if self.toggle_view_box.get_active():
                self.coords_view_box[0] = [int(event.x), int(event.y)]
            else:
                self.coords_analyse_box[0] = [int(event.x), int(event.y)]

    def on_area_motion_notify_event(self, widget, event):
        pos_x = min(max(0, int(event.x)), 720)
        pos_y = min(max(0, int(event.y)), 576)
        if self.toggle_view_box.get_active():
            self.coords_view_box[1] = [pos_x, pos_y]
        else:
            self.coords_analyse_box[1] = [pos_x, pos_y]
        self.drawing_area.queue_draw()


# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def hasCycle(self, head: ListNode) -> bool:
        a=head
        b=head
        while (a!=None):
            a=a.next;
            if (a==b):
                return True;
            if (a!=None):
                a=a.next;
            if (a==b):
                return True;
            b=b.next;
        return False;


# Not my solution.
# Imported from https://www.reddit.com/r/adventofcode/comments/rnejv5/comment/hpypzhp/?utm_source=share&utm_medium=web2x&context=3
# Code: https://pastebin.com/Q68bWTAV
file = "input/day24.txt"

digit_process = []

with open(file, 'r') as f:
    process = []
    for line in f:
        line = line.strip()

        if line.startswith("inp"):
            if process:
                digit_process.append(process)
            process = []

        process.append(line.split())
    digit_process.append(process)
N = len(digit_process)

class Number:
    def __init__(self, digit):
        self.digit = digit

    def __repr__(self):
        return f"Digit {self.digit}"

variables = {"x": [], "y": [], "z": [], "w": []}
constraints = []
for i in range(14):
    # Process each block and see what are the constraints
    block = digit_process[i]
    fulfilled_constraint = True
    for command in digit_process[i]:
        if len(command) == 0:
          continue
        print(command)
        instr = command[0]
        v1 = command[1]

        if instr == "inp":
            variables["w"] = [Number(i)]
            continue

        v2 = command[2]
        if v2 in variables:
            val2 = variables[v2]
        else:
            val2 = int(v2)

        if instr == "mul":
            if val2 == 0:
                variables[v1] = []
        elif instr == "add":
            if v1 == "x":
                if v2 == "z":
                    # We append the contents of z to x
                    variables[v1] += [_[:] for _ in variables[v2]]
                else:
                    variables[v1].append(val2)
            elif v1 == "y":
                if val2 == 25:
                    continue
                else:
                    if isinstance(val2, list):
                        variables[v1] += val2[:]
                    else:
                        variables[v1].append(val2)
            elif v1 == "z":
                if v2 == "y":
                    if fulfilled_constraint:
                        # Basically do nothing
                        pass
                    else:
                        variables[v1].append(variables[v2][:])
        elif instr == "mod":
            if val2 == 26:
                if variables[v1]:
                    variables[v1] = variables[v1][-1]
        elif instr == "div":
            if val2 == 1:
                continue
            elif val2 == 26:
                if v1 == "z":
                    variables[v1].pop()
        elif instr == "eql":
            if v1 == "x":
                if v2 == "w":
                    if variables[v1]:
                        _sum = 0
                        for el in variables[v1]:
                            if isinstance(el, list):
                                continue
                            if isinstance(el, Number):
                                continue
                            _sum += el

                        if _sum > 9:
                            fulfilled_constraint = False
                        if fulfilled_constraint:
                            # If we have a constraint
                            constraints.append([variables[v1][:], Number(i)])
                        variables[v1] = []
                elif val2 == 0:
                    # We do nothing because in the previous block we assume if
                    # we have a fulfilled constraint or not
                    #variables[v1] = []
                    pass

def get_serial_number(constraints, part=1):
    # For part one find the maximum possible digit
    serial_number = ["" for i in range(14)]

    for constraint in constraints:
        # Figure out which indexes to process
        # LHS
        lhs_index = None
        lhs_constraint = 0
        for content in constraint[0]:
            if isinstance(content, Number):
                lhs_index = content.digit
            else:
                lhs_constraint += content

        # RHS
        rhs_index = constraint[1].digit
        if part==1:
            # Get maximum number
            if lhs_constraint > 0:
                serial_number[lhs_index] = 9 - lhs_constraint
                serial_number[rhs_index] = 9
            else:
                serial_number[lhs_index] = 9
                serial_number[rhs_index] = 9 + lhs_constraint
        else:
            if lhs_constraint > 0:
                serial_number[lhs_index] = 1
                serial_number[rhs_index] = 1 + lhs_constraint
            else:
                serial_number[lhs_index] = abs(lhs_constraint) + 1
                serial_number[rhs_index] = 1
    return ''.join([str(_) for _ in serial_number])
print("Part 1: ", get_serial_number(constraints, 1))
print("Part 2: ", get_serial_number(constraints, 2))