# -*- coding:utf-8 -*-
# Coder: Yao Zhao
# Github: https://github.com/yyyzzzhao
# ==============================================================================
import torch
import torch.nn as nn
from torch.nn import init
import functools
from torch.optim import lr_scheduler
import torch.nn.functional as F
from models.normalization import SPADE
import torchvision
from torch.autograd import Variable

###############################################################################
# Helper Functions
###############################################################################

def get_norm_layer(norm_type='instance'):
    if norm_type == 'batch':
        norm_layer = functools.partial(nn.BatchNorm2d, affine=True)
    elif norm_type == 'instance':
        norm_layer = functools.partial(nn.InstanceNorm2d, affine=False, track_running_stats=True)
    elif norm_type == 'none':
        norm_layer = None
    else:
        raise NotImplementedError('normalization layer [%s] is not found' % norm_type)
    return norm_layer

def get_scheduler(optimizer, opt):
    """Return a learning rate scheduler

    Parameters:
        optimizer          -- the optimizer of the network
        opt (option class) -- stores all the experiment flags; needs to be a subclass of BaseOptions．
                              opt.lr_policy is the name of learning rate policy: linear | step | plateau | cosine

    For 'linear', we keep the same learning rate for the first <opt.niter> epochs
    and linearly decay the rate to zero over the next <opt.niter_decay> epochs.
    For other schedulers (step, plateau, and cosine), we use the default PyTorch schedulers.
    See https://pytorch.org/docs/stable/optim.html for more details.
    """
    if opt.lr_policy == 'linear':
        def lambda_rule(epoch):
            lr_l = 1.0 - max(0, epoch + opt.epoch_count - opt.niter) / float(opt.niter_decay + 1)
            return lr_l
        scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lambda_rule)
    elif opt.lr_policy == 'step':
        scheduler = lr_scheduler.StepLR(optimizer, step_size=opt.lr_decay_iters, gamma=0.1)
    elif opt.lr_policy == 'plateau':
        scheduler = lr_scheduler.ReduceLROnPlateau(optimizer, mode='min', factor=0.2, threshold=0.01, patience=5)
    elif opt.lr_policy == 'cosine':
        scheduler = lr_scheduler.CosineAnnealingLR(optimizer, T_max=opt.niter, eta_min=0)
    else:
        return NotImplementedError('learning rate policy [%s] is not implemented', opt.lr_policy)
    return scheduler

def init_weights(net, init_type='normal', init_gain=0.02):
    """Initialize network weights.

    Parameters:
        net (network)   -- network to be initialized
        init_type (str) -- the name of an initialization method: normal | xavier | kaiming | orthogonal
        init_gain (float)    -- scaling factor for normal, xavier and orthogonal.

    We use 'normal' in the original pix2pix and CycleGAN paper. But xavier and kaiming might
    work better for some applications. Feel free to try yourself.
    """
    def init_func(m):  # define the initialization function
        classname = m.__class__.__name__
        if hasattr(m, 'weight') and (classname.find('Conv') != -1 or classname.find('Linear') != -1):
            if init_type == 'normal':
                init.normal_(m.weight.data, 0.0, init_gain)
            elif init_type == 'xavier':
                init.xavier_normal_(m.weight.data, gain=init_gain)
            elif init_type == 'kaiming':
                init.kaiming_normal_(m.weight.data, a=0, mode='fan_in')
            elif init_type == 'orthogonal':
                init.orthogonal_(m.weight.data, gain=init_gain)
            else:
                raise NotImplementedError('initialization method [%s] is not implemented' % init_type)
            if hasattr(m, 'bias') and m.bias is not None:
                init.constant_(m.bias.data, 0.0)
        elif classname.find('BatchNorm2d') != -1:  # BatchNorm Layer's weight is not a matrix; only normal distribution applies.
            if hasattr(m, 'weight') and m.weight is not None:
                init.normal_(m.weight.data, 1.0, init_gain)
            if hasattr(m, 'bias') and m.bias is not None:
                init.constant_(m.bias.data, 0.0)

    print('initialize network with %s' % init_type)
    net.apply(init_func)  # apply the initialization function <init_func>

def init_net(net, init_type='normal', init_gain=0.02, gpu_ids=[]):
    if len(gpu_ids) > 0:
        assert(torch.cuda.is_available())
        net.to(gpu_ids[0])
        net = torch.nn.DataParallel(net, gpu_ids)
    init_weights(net, init_type, init_gain=init_gain)
    return net

def define_G(input_nc, output_nc, ngf, which_model_netG, norm='batch', use_dropout=False, init_type='normal', init_gain=0.02, gpu_ids=[]):
    netG = None
    norm_layer = get_norm_layer(norm_type=norm)

    if which_model_netG == 'resnet_9blocks':
        netG = ResnetGenerator(input_nc, output_nc, ngf, norm_layer=norm_layer, use_dropout=use_dropout, n_blocks=9)
    elif which_model_netG == 'resnet_6blocks':
        netG = ResnetGenerator(input_nc, output_nc, ngf, norm_layer=norm_layer, use_dropout=use_dropout, n_blocks=6)
    elif which_model_netG == 'unet_128':
        netG = UnetGenerator(input_nc, output_nc, 7, ngf, norm_layer=norm_layer, use_dropout=use_dropout)
    elif which_model_netG == 'unet_256':
        netG = UnetGenerator(input_nc, output_nc, 8, ngf, norm_layer=norm_layer, use_dropout=use_dropout)
    elif which_model_netG == 'multi_9blocks':
        netG = MultiGenerator(input_nc, output_nc, ngf, norm_layer=norm_layer, use_dropout=use_dropout, n_blocks=9)
    elif which_model_netG == 'multi_6blocks':
        netG = MultiGenerator(input_nc, output_nc, ngf, norm_layer=norm_layer, use_dropout=use_dropout, n_blocks=6)
    else:
        raise NotImplementedError('Generator model name [%s] is not recognized' % which_model_netG)
    return init_net(netG, init_type, init_gain, gpu_ids)

def define_G_multi(input_nc, ngf, which_model_netG, norm='batch', use_dropout=False, init_type='normal', init_gain=0.02, gpu_ids=[]):
	netG = None
	norm_layer = get_norm_layer(norm_type=norm)
	if which_model_netG == 'unet_128':
		netG = AaaGenerator(input_nc, 7, ngf, norm_layer=norm_layer)
	elif which_model_netG == 'unet_256':
		netG = AaaGenerator(input_nc, 8, ngf, norm_layer=norm_layer)
	else:
		raise NotImplementedError('Generator model name [%s] is not recognized' % which_model_netG)
	return init_net(netG, init_type, init_gain, gpu_ids)

def define_D(input_nc, ndf, which_model_netD, n_layers_D=3, norm='batch', init_type='normal', init_gain=0.02, gpu_ids=[], getIntermFeat=False):
    netD = None
    norm_layer = get_norm_layer(norm_type=norm)

    if which_model_netD == 'basic':
        netD = NLayerDiscriminator(input_nc, ndf, n_layers=3, norm_layer=norm_layer, getIntermFeat=getIntermFeat)
    elif which_model_netD == 'n_layers':
        netD = NLayerDiscriminator(input_nc, ndf, n_layers_D, norm_layer=norm_layer, getIntermFeat=getIntermFeat)
    elif which_model_netD == 'pixel':
        netD = PixelDiscriminator(input_nc, ndf, norm_layer=norm_layer)
    else:
        raise NotImplementedError('Discriminator model name [%s] is not recognized' %
                                  which_model_netD)
    return init_net(netD, init_type, init_gain, gpu_ids)

##############################################################################
# Classes
##############################################################################

# Defines the GAN loss which uses either LSGAN or the regular GAN.
# When LSGAN is used, it is basically same as MSELoss,
# but it abstracts away the need to create the target label tensor
# that has the same size as the input
class GANLoss(nn.Module):
    def __init__(self, gan_mode, target_real_label=1.0, target_fake_label=0.0,
                 tensor=torch.cuda.FloatTensor):
        super(GANLoss, self).__init__()
        self.real_label = target_real_label
        self.fake_label = target_fake_label
        self.real_label_var = None
        self.fake_label_var = None
        self.Tensor = tensor
        if gan_mode == 'lsgan':
            self.loss = nn.MSELoss()
        elif gan_mode == 'vanilla':
            self.loss = nn.BCEWithLogitsLoss()
        elif gan_mode in ['wgangp']:
            self.loss = None
        else:
            raise NotImplementedError('gan mode %s not implemented' % gan_mode)

    def get_target_tensor(self, input, target_is_real):
        target_tensor = None
        if target_is_real:
            create_label = ((self.real_label_var is None) or
                            (self.real_label_var.numel() != input.numel()))
            if create_label:
                real_tensor = self.Tensor(input.size()).fill_(self.real_label)
                self.real_label_var = Variable(real_tensor, requires_grad=False)
            target_tensor = self.real_label_var
        else:
            create_label = ((self.fake_label_var is None) or
                            (self.fake_label_var.numel() != input.numel()))
            if create_label:
                fake_tensor = self.Tensor(input.size()).fill_(self.fake_label)
                self.fake_label_var = Variable(fake_tensor, requires_grad=False)
            target_tensor = self.fake_label_var
        return target_tensor

    def __call__(self, input, target_is_real):
        if isinstance(input[0], list):
            loss = 0
            for input_i in input:
                pred = input_i[-1]
                target_tensor = self.get_target_tensor(pred, target_is_real)
                loss += self.loss(pred, target_tensor)
            return loss
        else:
            target_tensor = self.get_target_tensor(input[-1], target_is_real)
            return self.loss(input[-1], target_tensor)

# Defines the generator that consists of Resnet blocks between a few
# downsampling/upsampling operations.
# Code and idea originally from Justin Johnson's architecture.
# https://github.com/jcjohnson/fast-neural-style/
class ResnetGenerator(nn.Module):
    def __init__(self, input_nc, output_nc, ngf=64, norm_layer=nn.BatchNorm2d, use_dropout=False, n_blocks=6, padding_type='reflect'):
        assert(n_blocks >= 0)
        super(ResnetGenerator, self).__init__()
        self.input_nc = input_nc
        self.output_nc = output_nc
        self.ngf = ngf
        if type(norm_layer) == functools.partial:
            use_bias = norm_layer.func == nn.InstanceNorm2d
        else:
            use_bias = norm_layer == nn.InstanceNorm2d
        # pad --> conv --> norm --> relu
        model = [nn.ReflectionPad2d(3),
                 nn.Conv2d(input_nc, ngf, kernel_size=7, padding=0,
                           bias=use_bias),
                 norm_layer(ngf),
                 nn.ReLU(True)]

        n_downsampling = 2
        for i in range(n_downsampling):
            mult = 2**i
            model += [nn.Conv2d(ngf * mult, ngf * mult * 2, kernel_size=3,
                                stride=2, padding=1, bias=use_bias),
                      norm_layer(ngf * mult * 2),
                      nn.ReLU(True)]

        mult = 2**n_downsampling
        for i in range(n_blocks):
            model += [ResnetBlock(ngf * mult, padding_type=padding_type, norm_layer=norm_layer, use_dropout=use_dropout, use_bias=use_bias)]

        for i in range(n_downsampling):
            mult = 2**(n_downsampling - i)
            model += [nn.ConvTranspose2d(ngf * mult, int(ngf * mult / 2),
                                         kernel_size=3, stride=2,
                                         padding=1, output_padding=1,
                                         bias=use_bias),
                      norm_layer(int(ngf * mult / 2)),
                      nn.ReLU(True)]
        model += [nn.ReflectionPad2d(3)]
        model += [nn.Conv2d(ngf, output_nc, kernel_size=7, padding=0)]
        model += [nn.Tanh()]

        self.model = nn.Sequential(*model)

    def forward(self, input):
        return self.model(input)

# Define a resnet block
class ResnetBlock(nn.Module):
    def __init__(self, dim, padding_type, norm_layer, use_dropout, use_bias):
        super(ResnetBlock, self).__init__()
        self.conv_block = self.build_conv_block(dim, padding_type, norm_layer, use_dropout, use_bias)

    def build_conv_block(self, dim, padding_type, norm_layer, use_dropout, use_bias):
        conv_block = []
        p = 0
        if padding_type == 'reflect':
            conv_block += [nn.ReflectionPad2d(1)]
        elif padding_type == 'replicate':
            conv_block += [nn.ReplicationPad2d(1)]
        elif padding_type == 'zero':
            p = 1
        else:
            raise NotImplementedError('padding [%s] is not implemented' % padding_type)

        conv_block += [nn.Conv2d(dim, dim, kernel_size=3, padding=p, bias=use_bias),
                       norm_layer(dim),
                       nn.ReLU(True)]
        if use_dropout:
            conv_block += [nn.Dropout(0.5)]

        p = 0
        if padding_type == 'reflect':
            conv_block += [nn.ReflectionPad2d(1)]
        elif padding_type == 'replicate':
            conv_block += [nn.ReplicationPad2d(1)]
        elif padding_type == 'zero':
            p = 1
        else:
            raise NotImplementedError('padding [%s] is not implemented' % padding_type)
        conv_block += [nn.Conv2d(dim, dim, kernel_size=3, padding=p, bias=use_bias),
                       norm_layer(dim)]

        return nn.Sequential(*conv_block)

    def forward(self, x):
        out = x + self.conv_block(x)
        return out

# Defines the Unet generator.
# |num_downs|: number of downsamplings in UNet. For example,
# if |num_downs| == 7, image of size 128x128 will become of size 1x1
# at the bottleneck
class UnetGenerator(nn.Module):
    def __init__(self, input_nc, output_nc, num_downs, ngf=64,
                 norm_layer=nn.BatchNorm2d, use_dropout=False):
        super(UnetGenerator, self).__init__()

        # construct unet structure
        unet_block = UnetSkipConnectionBlock(ngf * 8, ngf * 8, input_nc=None, submodule=None, innermost=True)
        for i in range(num_downs - 5):
            unet_block = UnetSkipConnectionBlock(ngf * 8, ngf * 8, input_nc=None, submodule=unet_block, use_dropout=use_dropout)
        unet_block = UnetSkipConnectionBlock(ngf * 4, ngf * 8, input_nc=None, submodule=unet_block)
        unet_block = UnetSkipConnectionBlock(ngf * 2, ngf * 4, input_nc=None, submodule=unet_block)
        unet_block = UnetSkipConnectionBlock(ngf, ngf * 2, input_nc=None, submodule=unet_block)
        unet_block = UnetSkipConnectionBlock(output_nc, ngf, input_nc=input_nc, submodule=unet_block, outermost=True)

        self.model = unet_block

    def forward(self, x):
        """Standard forward"""
        return self.model(x)

class MultiGenerator(nn.Module):
    def __init__(self, input_nc, output_nc, ngf=64, norm_layer=nn.BatchNorm2d, use_dropout=False, n_blocks=6, padding_type='reflect'):
        assert(n_blocks >= 0)
        super(MultiGenerator, self).__init__()
        self.input_nc = input_nc
        self.output_nc = output_nc
        self.ngf = ngf
        if type(norm_layer) == functools.partial:
            use_bias = norm_layer.func == nn.InstanceNorm2d
        else:
            use_bias = norm_layer == nn.InstanceNorm2d
        # pad --> conv --> norm --> relu
        model = [nn.ReflectionPad2d(3),
                 nn.Conv2d(input_nc, ngf, kernel_size=7, padding=0,
                           bias=use_bias),
                 norm_layer(ngf),
                 nn.ReLU(True)]

        n_downsampling = 2
        for i in range(n_downsampling):
            mult = 2**i
            model += [nn.Conv2d(ngf * mult, ngf * mult * 2, kernel_size=3,
                                stride=2, padding=1, bias=use_bias),
                      norm_layer(ngf * mult * 2),
                      nn.ReLU(True)]

        mult = 2**n_downsampling
        for i in range(n_blocks):
            model += [ResnetBlock(ngf * mult, padding_type=padding_type, norm_layer=norm_layer, use_dropout=use_dropout, use_bias=use_bias)]

        for i in range(n_downsampling):
            mult = 2**(n_downsampling - i)
            model += [nn.ConvTranspose2d(ngf * mult, int(ngf * mult / 2),
                                         kernel_size=3, stride=2,
                                         padding=1, output_padding=1,
                                         bias=use_bias),
                      norm_layer(int(ngf * mult / 2)),
                      nn.ReLU(True)]
        # There the network apart two branches
        self.base = nn.Sequential(*model)
        # Reconstruction branch
        sec_branch = []
        sec_branch += [nn.ReflectionPad2d(3)]
        sec_branch += [nn.Conv2d(ngf, output_nc, kernel_size=7, padding=0)]
        sec_branch += [nn.Tanh()]
        self.sec_branch = nn.Sequential(*sec_branch)
        # Segmentation branch
        seg_branch = []
        seg_branch += [nn.ReflectionPad2d(3)]
        seg_branch += [nn.Conv2d(ngf, 1, kernel_size=7, padding=0)]
        seg_branch += [nn.Sigmoid()]
        self.seg_branch = nn.Sequential(*seg_branch)

    def forward(self, input):
        base = self.base(input)
        rec = self.sec_branch(base)
        seg = self.seg_branch(base)
        return rec, seg

class UnetGeneratorS(nn.Module):
    def __init__(self, input_nc, output_nc, num_downs, ngf=64,
                 norm_layer=nn.BatchNorm2d, use_dropout=False):
        super(UnetGenerator, self).__init__()

        # construct unet structure
        unet_block = UnetSkipConnectionBlockS(ngf * 8, ngf * 8, input_nc=None, submodule=None, innermost=True)
        for i in range(num_downs - 5):
            unet_block = UnetSkipConnectionBlockS(ngf * 8, ngf * 8, input_nc=None, submodule=unet_block, use_dropout=use_dropout)
        unet_block = UnetSkipConnectionBlockS(ngf * 4, ngf * 8, input_nc=None, submodule=unet_block)
        unet_block = UnetSkipConnectionBlockS(ngf * 2, ngf * 4, input_nc=None, submodule=unet_block)
        unet_block = UnetSkipConnectionBlockS(ngf, ngf * 2, input_nc=None, submodule=unet_block)
        unet_block = UnetSkipConnectionBlockS(output_nc, ngf, input_nc=input_nc, submodule=unet_block, outermost=True)

        self.model = unet_block

    def forward(self, x, seg):
        """Standard forward"""
        return self.model(x, seg)

class AaaGenerator(nn.Module):
	def __init__(self, input_nc, num_downs=7, ngf=64, norm_layer=nn.BatchNorm2d):
		super(AaaGenerator, self).__init__()
		self.num_downs = num_downs

		# construct unet encoder parts
		self.u_block_base = EncodeBlock(ngf*8, ngf*8, norm_layer=norm_layer, innermost=True)
		self.u_block_0 = EncodeBlock(ngf * 8, ngf * 8, norm_layer=norm_layer)
		self.u_block_1 = EncodeBlock(ngf * 8, ngf * 8, norm_layer=norm_layer)
		if self.num_downs == 8:
			self.u_block_2 = EncodeBlock(ngf * 8, ngf * 8, norm_layer=norm_layer)
		self.u_block_3 = EncodeBlock(ngf * 4, ngf * 8, norm_layer=norm_layer)
		self.u_block_4 = EncodeBlock(ngf * 2, ngf * 4, norm_layer=norm_layer)
		self.u_block_5 = EncodeBlock(ngf, ngf * 2, norm_layer=norm_layer)
		self.u_block_6 = EncodeBlock(input_nc, ngf, norm_layer=norm_layer, outermost=True)

		# construct two decoder
		# one is for generate rgb images
		self.gen_path0_0 = DecodeBlock(ngf*8, ngf*8, innermost=True, norm_layer=norm_layer)
		self.gen_path0_1 = DecodeBlock(ngf*8, ngf*8, norm_layer=norm_layer)
		self.gen_path0_2 = DecodeBlock(ngf*8, ngf*8, norm_layer=norm_layer)
		if self.num_downs == 8:
			self.gen_path0_3 = DecodeBlock(ngf*8, ngf*8, norm_layer=norm_layer)
		self.gen_path0_4 = DecodeBlock(ngf*8, ngf*4, norm_layer=norm_layer)
		self.gen_path0_5 = DecodeBlock(ngf*4, ngf*2, norm_layer=norm_layer)
		self.gen_path0_6 = DecodeBlock(ngf*2, ngf, norm_layer=norm_layer)
		self.gen_path0_7 = DecodeBlock(ngf, 3, outermost=True, norm_layer=norm_layer)

		# the second is for generate mask
		self.gen_path1_0 = DecodeBlock(ngf*8, ngf*8, innermost=True, norm_layer=norm_layer)
		self.gen_path1_1 = DecodeBlock(ngf*8, ngf*8, norm_layer=norm_layer)
		self.gen_path1_2 = DecodeBlock(ngf*8, ngf*8, norm_layer=norm_layer)
		if self.num_downs == 8:
			self.gen_path1_3 = DecodeBlock(ngf*8, ngf*8, norm_layer=norm_layer)
		self.gen_path1_4 = DecodeBlock(ngf*8, ngf*4, norm_layer=norm_layer)
		self.gen_path1_5 = DecodeBlock(ngf*4, ngf*2, norm_layer=norm_layer)
		self.gen_path1_6 = DecodeBlock(ngf*2, ngf, norm_layer=norm_layer)
		self.gen_path1_7 = DecodeBlock(ngf, 1, outermost=True, is_seg=True, norm_layer=norm_layer)

	def forward(self, x):
		# encoder
		x1 = self.u_block_6(x)
		x2 = self.u_block_5(x1)
		x3 = self.u_block_4(x2)
		x4 = self.u_block_3(x3)
		if self.num_downs == 8:
			x5 = self.u_block_2(x4)
			x6 = self.u_block_1(x5)
		else:
			x6 = self.u_block_1(x4)
		x7 = self.u_block_0(x6)
		base = self.u_block_base(x7)

		# decoder 1
		d_0_0 = self.gen_path0_0(base)
		d_0_1 = self.gen_path0_1(torch.cat([d_0_0, x7], 1))
		d_0_2 = self.gen_path0_2(torch.cat([d_0_1, x6], 1))
		if self.num_downs == 8:
			d_0_3 = self.gen_path0_3(torch.cat([d_0_2, x5], 1))
			d_0_4 = self.gen_path0_4(torch.cat([d_0_3, x4], 1))
		else:
			d_0_4 = self.gen_path0_4(torch.cat([d_0_2, x4], 1))
		d_0_5 = self.gen_path0_5(torch.cat([d_0_4, x3], 1))
		d_0_6 = self.gen_path0_6(torch.cat([d_0_5, x2], 1))
		rgb = self.gen_path0_7(torch.cat([d_0_6, x1], 1))

		# decoder 2
		d_1_0 = self.gen_path1_0(base)
		d_1_1 = self.gen_path1_1(torch.cat([d_1_0, x7], 1))
		d_1_2 = self.gen_path1_2(torch.cat([d_1_1, x6], 1))
		if self.num_downs == 8:
			d_1_3 = self.gen_path1_3(torch.cat([d_1_2, x5], 1))
			d_1_4 = self.gen_path1_4(torch.cat([d_1_3, x4], 1))
		else:
			d_1_4 = self.gen_path1_4(torch.cat([d_1_2, x4], 1))
		d_1_5 = self.gen_path1_5(torch.cat([d_1_4, x3], 1))
		d_1_6 = self.gen_path1_6(torch.cat([d_1_5, x2], 1))
		mask = self.gen_path1_7(torch.cat([d_1_6, x1], 1))

		return rgb, mask

# the EncodeBlock returns a skip connection tensor and a deeper layer interation
# while the innermost return a downconv tensor.
class EncodeBlock(nn.Module):
    def __init__(self, outer_nc, inner_nc, outermost=False, innermost=False, norm_layer=nn.BatchNorm2d, use_dropout=False):
        super(EncodeBlock, self).__init__()
        if type(norm_layer) == functools.partial:
            use_bias = norm_layer.func == nn.InstanceNorm2d
        else:
            use_bias = norm_layer == nn.InstanceNorm2d

        self.downconv = nn.Conv2d(outer_nc, inner_nc, kernel_size=4, stride=2, padding=1, bias=use_bias)
        self.downrelu = nn.LeakyReLU(0.2, True)
        self.downnorm = norm_layer(inner_nc)

        self.innermost = innermost
        self.outermost = outermost

    def forward(self, x):
        if self.innermost:
            x = self.downrelu(x)
            x = self.downconv(x)
            return x
        elif self.outermost:
            x = self.downconv(x)
            return x
        else:
            x = self.downrelu(x)
            x = self.downconv(x)
            x = self.downnorm(x)
            return x

class DecodeBlock(nn.Module):
	def __init__(self, inner_nc, outer_nc, innermost=False, outermost=False, is_seg=False, norm_layer=nn.BatchNorm2d):
		super(DecodeBlock, self).__init__()

		# uprelu = nn.ReLU(True)
		self.uprelu = nn.ReLU()
		self.upnorm = norm_layer(outer_nc)
		self.innermost = innermost
		self.outermost = outermost
		self.is_seg = is_seg
		if outermost:
			# if not is_seg:
			self.upconv = nn.ConvTranspose2d(inner_nc * 2, outer_nc, kernel_size=4, stride=2, padding=1)
				# up = [upconv, nn.Tanh()]
			# else:
				# self.upconv = nn.ConvTranspose2d(inner_nc * 2, outer_nc, kernel_size=4, stride=2, padding=1)
				# up = [upconv, nn.Sigmoid()]
		elif innermost:
			self.upconv = nn.ConvTranspose2d(inner_nc, outer_nc, kernel_size=4, stride=2, padding=1)
			# up = [uprelu, upconv, upnorm]
		else:
			self.upconv = nn.ConvTranspose2d(inner_nc * 2, outer_nc, kernel_size=4, stride=2, padding=1)
			# up = [uprelu, upconv, upnorm]

	def forward(self, x):
		if self.outermost:
			x = self.upconv(x)
			if self.is_seg:
				return nn.Sigmoid()(x)
			else:
				return nn.Tanh()(x)
		elif self.innermost:
			x = self.uprelu(x)
			x = self.upconv(x)
			x = self.upnorm(x)
			return x
		else:
			x = self.uprelu(x)
			x = self.upconv(x)
			x = self.upnorm(x)
			return x

class UnetSkipConnectionBlock(nn.Module):
    """Defines the Unet submodule with skip connection.
        X -------------------identity----------------------
        |-- downsampling -- |submodule| -- upsampling --|
    """

    def __init__(self, outer_nc, inner_nc, input_nc=None,
                 submodule=None, outermost=False, innermost=False, norm_layer=nn.BatchNorm2d, use_dropout=False):
        """Construct a Unet submodule with skip connections.

        Parameters:
            outer_nc (int) -- the number of filters in the outer conv layer
            inner_nc (int) -- the number of filters in the inner conv layer
            input_nc (int) -- the number of channels in input images/features
            submodule (UnetSkipConnectionBlock) -- previously defined submodules
            outermost (bool)    -- if this module is the outermost module
            innermost (bool)    -- if this module is the innermost module
            norm_layer          -- normalization layer
            user_dropout (bool) -- if use dropout layers.
        """
        super(UnetSkipConnectionBlock, self).__init__()
        self.outermost = outermost
        if type(norm_layer) == functools.partial:
            use_bias = norm_layer.func == nn.InstanceNorm2d
        else:
            use_bias = norm_layer == nn.InstanceNorm2d
        if input_nc is None:
            input_nc = outer_nc

        # spade_config_str = 'spadesyncbatch3x3'  # opt.norm_G.replace('spectral', '')

        downconv = nn.Conv2d(input_nc, inner_nc, kernel_size=4,
                             stride=2, padding=1, bias=use_bias)
        downrelu = nn.LeakyReLU(0.2, True)
        downnorm = norm_layer(inner_nc)
        # downnorm = SPADE(spade_config_str, inner_nc, 1)   ## opt.semantic_nc = 1
        uprelu = nn.ReLU(True)
        upnorm = norm_layer(outer_nc)
        # upnorm = SPADE(spade_config_str, outer_nc, 1)

        if outermost:
            upconv = nn.ConvTranspose2d(inner_nc * 2, outer_nc,
                                        kernel_size=4, stride=2,
                                        padding=1)
            down = [downconv]
            up = [uprelu, upconv, nn.Tanh()]
            model = down + [submodule] + up
        elif innermost:
            upconv = nn.ConvTranspose2d(inner_nc, outer_nc,
                                        kernel_size=4, stride=2,
                                        padding=1, bias=use_bias)
            down = [downrelu, downconv]
            up = [uprelu, upconv, upnorm]
            model = down + up
        else:
            upconv = nn.ConvTranspose2d(inner_nc * 2, outer_nc,
                                        kernel_size=4, stride=2,
                                        padding=1, bias=use_bias)
            down = [downrelu, downconv, downnorm]
            up = [uprelu, upconv, upnorm]

            if use_dropout:
                model = down + [submodule] + up + [nn.Dropout(0.5)]
            else:
                model = down + [submodule] + up

        self.model = nn.Sequential(*model)

    def forward(self, x):
        if self.outermost:
            return self.model(x)
        else:   # add skip connections
            return torch.cat([x, self.model(x)], 1)

class UnetSkipConnectionBlockS(nn.Module):
    """Defines the Unet submodule with skip connection.
        X -------------------identity----------------------
        |-- downsampling -- |submodule| -- upsampling --|
    """

    def __init__(self, outer_nc, inner_nc, input_nc=None,
                 submodule=None, outermost=False, innermost=False, use_dropout=False):
        """Construct a Unet submodule with skip connections.

        Parameters:
            outer_nc (int) -- the number of filters in the outer conv layer
            inner_nc (int) -- the number of filters in the inner conv layer
            input_nc (int) -- the number of channels in input images/features
            submodule (UnetSkipConnectionBlock) -- previously defined submodules
            outermost (bool)    -- if this module is the outermost module
            innermost (bool)    -- if this module is the innermost module
            norm_layer          -- normalization layer
            user_dropout (bool) -- if use dropout layers.
        """
        super(UnetSkipConnectionBlock, self).__init__()
        self.outermost = outermost
        use_bias = False
        if input_nc is None:
            input_nc = outer_nc

        spade_config_str = 'spadesyncbatch3x3'  # opt.norm_G.replace('spectral', '')

        self.downconv = nn.Conv2d(input_nc, inner_nc, kernel_size=4,
                             stride=2, padding=1, bias=use_bias)
        self.downrelu = nn.LeakyReLU(0.2, True)
        # downnorm = norm_layer(inner_nc)
        self.downnorm = SPADE(spade_config_str, inner_nc, 1)   ## opt.semantic_nc = 1
        self.uprelu = nn.ReLU(True)
        # upnorm = norm_layer(outer_nc)
        self.upnorm = SPADE(spade_config_str, outer_nc, 1)

        self.outermost = outermost
        self.innermost = innermost
        self.outer_nc = outer_nc
        self.inner_nc = inner_nc
        self.submodule = submodule
        self.use_dropout = use_dropout
        self.tan = nn.Tanh()

        if outermost:
            self.upconv = nn.ConvTranspose2d(inner_nc * 2, outer_nc,
                                        kernel_size=4, stride=2,
                                        padding=1)
        elif innermost:
            self.upconv = nn.ConvTranspose2d(inner_nc, outer_nc,
                                        kernel_size=4, stride=2,
                                        padding=1, bias=use_bias)
        else:
            self.upconv = nn.ConvTranspose2d(inner_nc * 2, outer_nc,
                                        kernel_size=4, stride=2,
                                        padding=1, bias=use_bias)

    def forward(self, x, seg):
        in_x = x
        if self.outermost:
            x = self.downconv(x)   # down
            x = self.submodule(x, seg)  # submodule
            x = self.uprelu(x)  #  up
            x = self.upconv(x)
            x = self.tan(x)
            return x
        elif self.innermost:
            x = self.downrelu(x)  # down
            x = self.downconv(x)
            x = self.uprelu(x)  # up
            x = self.upconv(x)
            x = self.upnorm(x, seg)
            return torch.cat([in_x, x], 1)
        else:

            x = self.downrelu(x)  # down
            x = self.downconv(x)
            x = self.downnorm(x, seg)
            x = self.submodule(x, seg)  # submodule
            x = self.uprelu(x)   # up
            x = self.upconv(x)
            x = self.upnorm(x, seg)
            if self.use_dropout:
                x = nn.Dropout(0.5)(x)
            return torch.cat([in_x, x], 1)

# Defines the PatchGAN discriminator with the specified arguments.
# class NLayerDiscriminator(nn.Module):
#     def __init__(self, input_nc, ndf=64, n_layers=3, norm_layer=nn.BatchNorm2d):
#         super(NLayerDiscriminator, self).__init__()
#         if type(norm_layer) == functools.partial:
#             use_bias = norm_layer.func == nn.InstanceNorm2d
#         else:
#             use_bias = norm_layer == nn.InstanceNorm2d

#         kw = 4
#         padw = 1
#         sequence = [
#             nn.Conv2d(input_nc, ndf, kernel_size=kw, stride=2, padding=padw),
#             nn.LeakyReLU(0.2, True)
#         ]

#         nf_mult = 1
#         nf_mult_prev = 1
#         for n in range(1, n_layers):
#             nf_mult_prev = nf_mult
#             nf_mult = min(2**n, 8)
#             sequence += [
#                 nn.Conv2d(ndf * nf_mult_prev, ndf * nf_mult,
#                           kernel_size=kw, stride=2, padding=padw, bias=use_bias),
#                 norm_layer(ndf * nf_mult),
#                 nn.LeakyReLU(0.2, True)
#             ]

#         nf_mult_prev = nf_mult
#         nf_mult = min(2**n_layers, 8)
#         sequence += [
#             nn.Conv2d(ndf * nf_mult_prev, ndf * nf_mult,
#                       kernel_size=kw, stride=1, padding=padw, bias=use_bias),
#             norm_layer(ndf * nf_mult),
#             nn.LeakyReLU(0.2, True)
#         ]

#         sequence += [nn.Conv2d(ndf * nf_mult, 1, kernel_size=kw, stride=1, padding=padw)]

#         self.model = nn.Sequential(*sequence)

#     def forward(self, input):
#         return self.model(input)
class NLayerDiscriminator(nn.Module):
    """Defines a PatchGAN discriminator"""

    def __init__(self, input_nc, ndf=64, n_layers=3, norm_layer=nn.BatchNorm2d, getIntermFeat=False):
        """Construct a PatchGAN discriminator

        Parameters:
            input_nc (int)  -- the number of channels in input images
            ndf (int)       -- the number of filters in the last conv layer
            n_layers (int)  -- the number of conv layers in the discriminator
            norm_layer      -- normalization layer
        """
        super(NLayerDiscriminator, self).__init__()
        self.getIntermFeat = getIntermFeat
        self.n_layers = n_layers
        if type(norm_layer) == functools.partial:  # no need to use bias as BatchNorm2d has affine parameters
            use_bias = norm_layer.func != nn.BatchNorm2d
        else:
            use_bias = norm_layer != nn.BatchNorm2d

        kw = 4
        padw = 1
        sequence = [[nn.Conv2d(input_nc, ndf, kernel_size=kw, stride=2, padding=padw), nn.LeakyReLU(0.2, True)]]
        nf_mult = 1
        nf_mult_prev = 1
        for n in range(1, n_layers):  # gradually increase the number of filters
            nf_mult_prev = nf_mult
            nf_mult = min(2 ** n, 8)
            sequence += [[
                nn.Conv2d(ndf * nf_mult_prev, ndf * nf_mult, kernel_size=kw, stride=2, padding=padw, bias=use_bias),
                norm_layer(ndf * nf_mult),
                nn.LeakyReLU(0.2, True)
            ]]

        nf_mult_prev = nf_mult
        nf_mult = min(2 ** n_layers, 8)
        sequence += [[
            nn.Conv2d(ndf * nf_mult_prev, ndf * nf_mult, kernel_size=kw, stride=1, padding=padw, bias=use_bias),
            norm_layer(ndf * nf_mult),
            nn.LeakyReLU(0.2, True)
        ]]

        sequence += [[nn.Conv2d(ndf * nf_mult, 1, kernel_size=kw, stride=1, padding=padw)]]  # output 1 channel prediction map

        if getIntermFeat:
            for n in range(len(sequence)):
                setattr(self, 'model'+str(n), nn.Sequential(*sequence[n]))
        else:
            sequence_stream = []
            for n in range(len(sequence)):
                sequence_stream += sequence[n]
            self.model = nn.Sequential(*sequence_stream)

    def forward(self, input):
        """Standard forward."""
        if self.getIntermFeat:
            res = [input]
            for n in range(self.n_layers+2):
                model = getattr(self, 'model'+str(n))
                res.append(model(res[-1]))
            return res[1:]
        else:
            return self.model(input)

class PixelDiscriminator(nn.Module):
    def __init__(self, input_nc, ndf=64, norm_layer=nn.BatchNorm2d, use_sigmoid=False):
        super(PixelDiscriminator, self).__init__()
        if type(norm_layer) == functools.partial:
            use_bias = norm_layer.func == nn.InstanceNorm2d
        else:
            use_bias = norm_layer == nn.InstanceNorm2d

        self.net = [
            nn.Conv2d(input_nc, ndf, kernel_size=1, stride=1, padding=0),
            nn.LeakyReLU(0.2, True),
            nn.Conv2d(ndf, ndf * 2, kernel_size=1, stride=1, padding=0, bias=use_bias),
            norm_layer(ndf * 2),
            nn.LeakyReLU(0.2, True),
            nn.Conv2d(ndf * 2, 1, kernel_size=1, stride=1, padding=0, bias=use_bias)]

        if use_sigmoid:
            self.net.append(nn.Sigmoid())

        self.net = nn.Sequential(*self.net)

    def forward(self, input):
        return self.net(input)


import cv2
import datetime
import time
from utils.motion import Movement
from utils.cameraTest import findMotion
from utils.CameraRawCapture import PiVideoStream
from utils.aws_utils import AWSPredator
from utils.CameraView import CameraView
from utils.fps import FPS

def camera_control(config):
    # Pi configuration and calibration
    movement = Movement()
    movement.calibrate()
    aws_predator = AWSPredator()
    video_stream = PiVideoStream(config).start()
    time.sleep(config["camera_warmup_time"])
    remember_frame = None
    start_time = None
    summary = None
    current_count = 0
    frame_count = 0
    found = False
    fps_counter = FPS()
    show_video = CameraView(config).start()
    while True:
        fps = fps_counter.fps()
        print(fps)
        image = video_stream.read_frame()

        if(current_count == 0):
            summary = None
        remember_frame, target, summary = findMotion(image, remember_frame, config,current_count,frame_count,summary,show_video)
        current_count += 1
        if target is not None:
            remember_frame = None
            start_time = None
            summary = None
            current_count = 0
            movement.laser_on()

            inBoundries = movement.move(target['angle_x'], target['angle_y'], multiplier=10)
            movement.laser_off()
            aws_predator.detected_movement(image)
            time.sleep(0.3)
            if inBoundries is False:
                movement.center()
                time.sleep(0.3)
            else:
                found = True
        elif found is True:
            if start_time is None:
                start_time = datetime.datetime.now()
            end_time = datetime.datetime.now()
            if (end_time - start_time).total_seconds() >= 1.5:
                print("Tracking failure detected")
            if (end_time - start_time).total_seconds() >= 5.0:
                movement.center()
                time.sleep(0.3)
                summary = None
                current_count = 0
                start_time = None
                remember_frame = None
                found = False
        current_count = current_count % (frame_count+1)
        show_video.show_image("Primary", image)
        key = cv2.waitKey(1) & 0xFF
        if key == ord("q"):
            break
    video_stream.stop()
    movement.clean_up()


from sanic import Sanic
from sanic_openapi.openapi import blueprint

# ------------------------------------------------------------ #
#  GET
# ------------------------------------------------------------ #

def test_get_docs():
    app = Sanic('test_get')

    app.blueprint(blueprint)

    request, response = app.test_client.get('/openapi/spec.json')
    print(next(response.json()))
    assert response.status == 200

test_get_docs()


#!/usr/bin/python

import sys
from hmmTools import Hmm, ViterbiHatSequenceAnalyzer

def main(argv):
    if len(argv) != 2:
        print("arguments : <hmm specification file> <observed sequence>\n")
        sys.exit(1)
    sa = ViterbiHatSequenceAnalyzer(Hmm.fromFile(argv[0]), argv[1])
    trace = sa.getTrace()
    ll = sa.logLikelihood(trace)
    print("Trace         : {}".format(trace))
    print("LogLikelihood : {}".format(ll))

if __name__ == "__main__":
   main(sys.argv[1:])


#######################################################
# !!! William Blount Proprietary and Confidential !!! #
#######################################################

# Cannon Angle Calculator - Calculates the angle required for a cannon with a given vₒ and yₒ to fire a projectile a
# given distance.

# Copyright: William Blount 2016

from math import (cos, sin, tan, sqrt, pi)
from numpy import linspace

# Returns the initial velocity of a projectile given its initial elevation, angle of elevation, and range.
def calculate_initial_velocity(yₒ, θ, r):
    g = 9.81
    return sqrt((g * r ** 2) / (2 * cos(θ) ** 2 * (tan(θ) * r + yₒ)))

# Returns the maximum range of a projectile given its initial velocity, initial elevation, and angle of elevation.
def calculate_projectile_range(vₒ, yₒ, θ):
    g = 9.81
    return (vₒ * cos(θ) / g) * (vₒ * sin(θ) + sqrt(vₒ ** 2 * (sin(θ) ** 2) + 2 * g * yₒ))

# Returns the optimal angle between start_angle and stop_angle.
# vₒ, yₒ, and R should all use the same distance unit.
# Both the start and stop angle must satisfy 0 <= θ <= 2π.
def optimize_angle(vₒ, yₒ, r, start_angle=0.0, stop_angle=pi/2, steps=1000000, n=2):
    if not 0 <= start_angle <= 2 * pi:
        raise ValueError("Start angle is out of bounds! 0 <= %s <= π/2 is False!" % start_angle)

    if not 0 <= stop_angle <= 2 * pi:
        raise ValueError("Stop angle is out of bounds! 0 <= %s <= π/2 is False!" % stop_angle)

    if r > calculate_projectile_range(vₒ, yₒ, pi/4):
        raise RuntimeError("Desired range is greater than the maximum possible range in the positive x!")

    if r < calculate_projectile_range(vₒ, yₒ, 3 * pi / 4):
        raise RuntimeError("Desired range is greater than tha maximum possible range in the negative x!")

    angles = linspace(start_angle, stop_angle, steps).tolist()
    errors = [abs(r - calculate_projectile_range(vₒ, yₒ, θ)) for θ in angles]

    # Find the n best angles.
    n_best_angles = [angles[errors.index(sorted(errors)[i])] for i in range(n)]

    return n_best_angles

if __name__ == "__main__":
    while False:
        yₒ = float(input("Initial Height, yₒ in m: "))
        θ = float(input("Angle of launcher in radians: "))
        r = float(input("Range, R in m: "))

        print("\nInitial Velocity (m/s): %s\n" % calculate_initial_velocity(yₒ, θ, r))

        print("<~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ RESTART ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>")

    while True:
        vₒ = float(input("Initial Velocity, vₒ in m/s: "))
        yₒ = float(input("Initial Height, yₒ in m: "))
        r = float(input("Desired Range, R in m: "))

        try:
            θ1, θ2 = optimize_angle(vₒ, yₒ, r)
            print("\nMost Optimal Angle: %s or %s°" % (θ1, θ1 * 180.0 / pi))
            print("Second Most Optimal Angle: %s or %s°\n" % (θ2, θ2 * 180.0 / pi))
        except RuntimeError as e:
            print("\n!!! Sanity Check Failure !!! - %s\n" % str(e))

        print("<~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ RESTART ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>")


import sys
data = [list(map(int, row)) for row in open(sys.argv[1], 'r').read().split('\n')[:-1]]
rows = len(data)
columns = len(data[0])
lows = []
for i in range(rows):
    for j in range(columns):
        if (j == columns - 1 or data[i][j] < data[i][j+1]) and \
           (j == 0 or data[i][j] < data[i][j-1]) and \
           (i == rows -1 or data[i][j] < data[i+1][j]) and \
           (i == 0 or data[i][j] < data[i-1][j]):
            lows.append(data[i][j])
print(sum([elem + 1 for elem in lows]))


import xml.etree.ElementTree as ET
from os import listdir
from os.path import isfile, join

shapes = ['capsule', 'diamond', 'freeform', 'hexagon', 'octagon', 'oval', 'pentagon',
          'rectangle', 'round', 'semi-circle', 'square', 'tear', 'trapezoid', 'triangle']
root_folder = 'images/full/'

chars_b = [chr(l) for l in range(65,91)]
chars_s = [chr(l) for l in range(97,123)]
nums = [str(l) for l in range(0,10)]
sp = ['-',',','(',')',':','+','.','/']

letters = {l:0 for l in chars_b}
for l in nums: letters[l]=0
for l in chars_s: letters[l]=0
for l in sp: letters[l]=0

for shape in shapes:
    files = [root_folder+shape+'/annotations/'+f for f in listdir(root_folder+shape+'/annotations/') if (isfile(join(root_folder+shape+'/annotations/', f)) and '.xml' in f)]
    for file in files:
        tree = ET.parse(file)
        root = tree.getroot()
        # print(root)
        for child in root:
            if child.tag == 'object':
                name = child[0].text.strip()
                # print(file)
                letters[name] += 1

output = ''
chars_b_count = [(l,letters[l]) for l in letters if l in chars_b]
chars_s_count = [(l,letters[l]) for l in letters if l in chars_s]
nums_count = [(l,letters[l]) for l in letters if l in nums]
sp_count = [(l,letters[l]) for l in letters if l in sp]

chars_b_count.sort(key=lambda x:x[1], reverse=True)
chars_s_count.sort(key=lambda x:x[1], reverse=True)
nums_count.sort(key=lambda x:x[1], reverse=True)
sp_count.sort(key=lambda x:x[1], reverse=True)

for a in chars_b_count: output += str(a[0]) + ':' + str(a[1]) + '\n'
output += '\n'
for a in chars_s_count: output += str(a[0]) + ':' + str(a[1]) + '\n'
output += '\n'
for a in nums_count: output += str(a[0]) + ':' + str(a[1]) + '\n'
output += '\n'
for a in sp_count: output += str(a[0]) + ':' + str(a[1]) + '\n'

file_write = open('all_letters_xml2.txt', 'w')
file_write.write(output)


import unittest

def get_pow(lst):
    """Task 4. Function return squares of given list items."""
    return [pow(x, 2) for x in lst]

def get_every_second_item(lst):
    """Task 5. Function return every second item of list."""
    return lst[1::2]

def get_pow_of_even_item_on_the_odd_position(lst):
    """Task 6. Function return square of item at odd position of list if this is even number."""
    return [pow(x, 2) for x in lst[::2] if x % 2 == 0]

class UnitTest(unittest.TestCase):

    def test_list_comprehensions(self):
        """Function for test of list comprehensions results."""
        self.assertEqual(get_pow([1, -2, 3]),
                         [1, 4, 9])
        self.assertEqual(get_every_second_item([x for x in xrange(10)]),
                         [1, 3, 5, 7, 9])
        self.assertEqual(get_every_second_item([x for x in xrange(1, 10)]),
                         [2, 4, 6, 8])
        self.assertEqual(get_pow_of_even_item_on_the_odd_position([x for x in xrange(10)]),
                         [0, 4, 16, 36, 64])
        self.assertEqual(get_pow_of_even_item_on_the_odd_position([1, 2, 5, 2, -2, -3, 3, 15, 8, 8]),
                         [4, 64])

if __name__ == '__main__':
    unittest.main()


# CTD9 SVL - M. Nebut - 03/2016
# property-based testing

import unittest

from hypothesis import given, assume, example
from hypothesis.strategies import floats

from banque import *

class TestTomCrediteUnCompte(unittest.TestCase):

    def test_echec_si_somme_negative_classique(self):
        compte = Compte()
        self.assertRaises(ValueError,
                            compte.crediter,
                            -10)

    @given(somme=floats(max_value=0.0))
    @example(somme=0.0)
    def test_echec_si_somme_negative(self, somme):
        compte = Compte()
        self.assertRaises(ValueError,
                            compte.crediter,
                            somme)

    @given(somme=floats(min_value=0.0))
    #@example(somme=float("inf"))
    def test_le_solde_est_augmente(self, somme):
        compte = Compte()

        assume(somme > 0)

        compte.crediter(somme)
        self.assertEqual(compte.montant, somme)

class TestDebiterUnCompte(unittest.TestCase):

    @given(somme=floats(max_value=0.0))
    @example(somme=0.0)
    def test_echec_si_somme_negative(self, somme):
        compte = Compte()
        self.assertRaises(ValueError,
                            compte.debiter,
                            somme)

    @given(somme=floats(min_value=0.0))
    def test_le_solde_est_diminue(self, somme):
        compte = Compte()
        assume(somme > 0)
        compte.debiter(somme)
        self.assertEqual(compte.montant, -somme)


# -*- coding:Utf8 -*-

"""
    Regroups all constants used inside bilan_reader.
    Can be used for air solar system newer than
    SolarSystem.Models.Systems.IGC_system.System.IGC_airVectorRecyclePassive_solar6.

    Note:
        - Taux de couverture met trop en valeur le solaire car une grande partie est
          perdu.
        - Le taux de couverture est sur les bar plots.
    Il est plus intéressant de voir comment évolue la part réelle de solaire au cours
    de l’année (voir `Production_solaire\nutile`).
"""

from Plotters.evaluation import *

# Collectors area
A_COL = {'IDMK25': 2.32, 'Cobralino': 1.926,
         'Radco308c': 2.193, 'Radco308cS': 2.32,
         'SkyPro12CPC58': 2.28, 'SkyPro': 2.28,
         'SkyProScaled12CPC58': 2.32, 'SkyProS': 2.32}

# Bar emphazis
emphs_dict = {'bar_cumA': ['Pertes_solaires'],
              'bar_cumC': ['Production_solaire\nutile'],
              'bar_supC': ['Production\nsolaire'],
              'bar_supDispo': [],
              'bar_cumD': [],
              'bar_cumH': []}

# Careful if update conv_dict, you have to update JSON_ENERGY_FIELDS constant too.
conv_dict = {'DrawingUp_Energy': 'Besoins_ECS_puisage',
             'SolarHeating_Energy': 'Chauffage_solaire_actif',
             'SolarDrawingUp_Energy': 'ECS\nsolaire',
             'Collector_Energy': 'Production\nsolaire',
             'CollectorPanel_Energy': 'Energie captable',
             'ElecDHW_Energy': 'Consommation\nElec_ECS',
             'ElecHeating_Energy': 'Chauffage\nelec',
             'InternalGains_Energy': 'Gains\ninternes',
             'HDifTil_collector': 'Diffus', 'HDirTil_collector': 'Direct',
             'DHWTankTotalLosses_Energy': 'Ballon_ECS_pertes',
             'DHWTankPassiveGain_Energy': 'Ballon_ECS_gains',
             'StorageTankTotalLosses_Energy': 'Ballon_stockage_pertes',
             'StorageTankPassiveGain_Energy': 'Ballon_stockage_gains',
             'PipesLosses_Energy': 'Pertes réseau'}

# Attention à bien faire la différence entre consommation et besoins
new_fields = (
              # Consommations
              ('Consommation\nappoint', 'Consommation\nElec_ECS',
               'Chauffage\nelec', '+'),
              ('Energie\nnécessaire', 'Production\nsolaire', 'Consommation\nappoint', '+'),
              ('Sanitaire_total', 'Consommation\nElec_ECS', 'ECS\nsolaire', '+'),
              # Répartition des pertes
              ('Apport_ballon_ECS', 'Consommation\nElec_ECS', 'ECS\nsolaire', '+'),
              ('ratio_solaire', 'ECS\nsolaire', 'Apport_ballon_ECS', '/'),
              ('ratio_elec', 'Consommation\nElec_ECS', 'Apport_ballon_ECS', '/'),
              # Pertes réelles (les pertes des ballons utiles à l’ambiance ne sont pas considérées)
              ('Stockage_pertes', 'Ballon_stockage_pertes', 'Ballon_stockage_gains', '-'),
              ('Sanitaire_pertes', 'Ballon_ECS_pertes', 'Ballon_ECS_gains', '-'),
              ('Sanitaire_pertes_solaires', 'Sanitaire_pertes', 'ratio_solaire', '*'),
              ('Pertes_elec', 'Sanitaire_pertes', 'ratio_elec', '*'),  # Pertes électrique du ballon ECS
              ('Ballons_pertes_solaires', 'Stockage_pertes', 'Sanitaire_pertes_solaires', '+'),
              ('Pertes_solaires', 'Ballons_pertes_solaires', 'Pertes réseau', '+'),
              ('Pertes', 'Pertes_solaires', 'Pertes_elec', '+'),
              # Productions solaires utiles
              ('Production_solaire\nutile', 'Production\nsolaire', 'Pertes_solaires', '-'),
              ('Production_elec\nutile', 'Consommation\nappoint', 'Pertes_elec', '-'),
              ('solaire_elecUtile', 'Production_elec\nutile', 'Production\nsolaire', '+'),
              ('Chauffage_solaire_passif', 'Ballon_ECS_gains', 'Ballon_stockage_gains', '+'),
              ('Chauffage\nsolaire', 'Chauffage_solaire_actif', 'Chauffage_solaire_passif', '+'),
              # Besoins
              ('Chauffage_direct', 'Chauffage\nelec', 'Chauffage_solaire_actif', '+'),  # Besoin hors apports solaire passif par les ballons.
              ('Besoins\nChauffage', 'Chauffage\nelec', 'Chauffage\nsolaire', '+'),     # Besoin chauffage totaux (élec + passifs + actifs)
              ('Besoins\nECS', 'Sanitaire_total', 'Ballon_ECS_pertes', '-'),            # Besoin puisage + maintient ballon ECS à température
              ('Besoins', 'Besoins\nECS', 'Besoins\nChauffage', '+'),
              # Rendements
              ('Taux de couverture', 'Production\nsolaire', 'Energie\nnécessaire', '/'),
              # (prod solaire - pertes) / (prod solaire + elec utile) --> Vraie part solaire
              ('Part solaire\nBesoins', 'Production_solaire\nutile', 'solaire_elecUtile', '/'),
              ('Part_solaire\nChauffage', 'Chauffage\nsolaire', 'Besoins\nChauffage', '/'),
              ('Part_solaire\nECS', 'ECS\nsolaire', 'Sanitaire_total', '/'),
              ('Rendement capteur', 'Production\nsolaire', 'Energie captable', '/'),
              ('Rendement solaire', 'Production_solaire\nutile', 'Energie captable', '/'),
              # Part_solaire non récupérée par les capteurs solaires.
              ('Solaire_non_capté', 'Energie captable', 'Production\nsolaire', '-'))

# Prepare Taux de couverture (list of formatted datas)
short_names = ['Jan', 'Feb', 'Mar', 'Apr', 'May',
               'Jun', 'Jul', 'Aug', 'Sept', 'Oct',
               'Nov', 'Dec']

# Create list of all values inside conv_dict
not_energy_but_rename = ("Diffus", "Direct")  # Used to avoid useless aggregations
conv_value_list = [value for value in conv_dict.values() if value not in (not_energy_but_rename)]

# Fields (to plot new type of graph add new fields here)
fields = {'box_Tbal': ['T3', 'T4', 'T5'],
          'box_Text': ['T9_ext'],
          'box_H': ['Diffus', 'Direct'],
          'box_HDir': ['HDirNor', 'Direct'],
          'box_S': ['Speed_S6', 'Speed_S5', 'Speed_S2'],
          'diag_B': [conv_value_list,
                     ['Besoins\nChauffage', 'Besoins\nECS', 'Pertes_solaires', 'Gains\ninternes', 'Pertes_elec']],
          'diag_P': [conv_value_list,
                     ['Consommation\nappoint', 'Production\nsolaire']],
          'diag_H': [conv_value_list,
                     ['Chauffage\nelec', 'Chauffage\nsolaire']],   # Part solaire sur les BESOINS de chauffage
          'diag_D': [conv_value_list,
                     ['Consommation\nElec_ECS', 'ECS\nsolaire']],  # Part solaire sur les BESOINS d’ECS
          'bar_cumC': [conv_value_list,
                       ['Besoins\nECS', 'Besoins\nChauffage', 'Pertes_solaires']],
          'bar_cumA': [conv_value_list,
                       ['Production\nsolaire', 'Consommation\nappoint']],
          'bar_cumH': [conv_value_list,
                       ['Chauffage\nsolaire', 'Chauffage\nelec']],
          'bar_cumD': [conv_value_list,
                       ['ECS\nsolaire', 'Consommation\nElec_ECS']],
          'bar_supC': [conv_value_list,
                       ['Besoins\nECS', 'Besoins\nChauffage', 'Pertes_solaires']],
          'bar_supDispo': [conv_value_list,
                           ['Energie captable', 'Production\nsolaire', 'Production_solaire\nutile']],
          # This plot return a cumulative evolution of Taux de couverture and Rendement.
          # We deal with energy not power so we don’t have taux de couverture and Rendement
          # at each time step.
          'area_E': ['Taux de couverture', 'Rendement capteur'],
          'area_P': ['Production\nsolaire', 'Pertes_solaires', 'Consommation\nappoint'],
          'area_EB': ['Besoins\nECS', 'Besoins\nChauffage', 'Pertes_solaires'],
          'line_E': ['Besoins\nECS', 'Production\nsolaire', 'Consommation\nappoint', 'Besoins\nChauffage'],
          'line_ES': ['Production\nsolaire', 'Energie captable'],
          'line_TE': ['T1', 'T3', 'T5'],
          'line_Tint': ['T12_house'],
          'line_T': ['T9_ext', "T13_exch_inlet", 'T13_exch_outlet', 'T14_blowing'],
          'line_H': ['Diffus', 'Direct'],
          'line_debA': ['Flow_S6', 'Flow_S5', 'Flow_S2'],
          'line_debSE': ['Flow_Collector', 'Flow_S5',
                         'Flow_ExchStorTank'],
          'line_debSCE': ['Flow_Collector', 'Flow_S2'],
          'line_Drawing': ['Flow_Drawing'],
          'line_V3V': ['Vsolar_state']}

col_dict = {'box': (('#268bd2', '#002b36', '#268bd2', '#268bd2', '#268bd2'),
                    ('#586e75', '#002b36', '#586e75', '#586e75', '#268bd2'),
                    ('#859900', '#002b36', '#859900', '#859900', '#268bd2')),
            'diag_B': ['#fdf6e3', '#268bd2', '#cb4b16', '#859900', '#cb4b16'],
            'diag_P': ['#d33682', 'orange'],
            'diag_H': ['#d33682', 'orange'],  # Part solaire sur les BESOINS de chauffage
            'diag_D': ['#d33682', 'orange'],  # Part solaire sur les BESOINS d’ECS
            'bar_cumA': {'Consommation\nappoint': '#fdf6e3', 'Production\nsolaire': 'orange',
                         'Pertes totales': '#cb4b16'},
            'bar_cumC': {'Consommation\nappoint': '#dc322f', 'Besoins\nChauffage': '#fdf6e3',
                         'Besoins\nECS': '#268bd2', 'Production_solaire\nutile': 'orange',
                         'Pertes_solaires': '#cb4b16'},
            'bar_cumD': {'Consommation\nElec_ECS': '#fdf6e3', 'ECS\nsolaire': 'orange'},
            'bar_cumH': {'Chauffage\nelec': '#fdf6e3', 'Chauffage\nsolaire': 'orange'},
            'bar_supDispo': {'Production\nsolaire': 'orange',
                             'Energie captable': '#fdf6e3',
                             'Production_solaire\nutile': '#859900'},
            'bar_supC': {'Consommation\nappoint': '#dc322f', 'Besoins\nChauffage': '#fdf6e3',
                         'Besoins\nECS': '#268bd2', 'Production\nsolaire': 'orange',
                         'Pertes_solaires': '#cb4b16'},
            'area_E': 'Accent', 'line_E': 'Accent', 'line_TE': 'Accent',
            'line_ES': 'Accent', 'line_Tint': 'Accent', 'line_H': 'Accent', 'line_debA': 'Accent',
            'line_debS': 'Accent', 'line_debC': 'Accent', 'line_T': 'Accent',
            'line_debSE': 'Accent', 'line_debCE': 'Accent', 'area_EB': 'Accent',
            'line_debSCE': 'Accent', 'line_V3V': 'Accent', 'area_P': 'Accent',
            'line_Drawing': 'Accent', 'line_Backup': 'Accent',
            'line_debSCEbuffer': 'Accent'}

# Titles
titles = {'title': 'Bilan de la simulation',
          'box_Tbal': 'Evolution mensuelle de la variation \n' +
                      'des températures des ballons',
          'box_Text': 'Evolution mensuelle de la variation \n' +
                      'dee la température etérieure',
          'box_H': 'Evolution mensuelle de la variation \n' +
                   'de l’irradiation sur les panneaux',
          'box_HDir': 'Evolution mensuelle de la variation \n' +
                      'du potentiel de l’irradiation directe sur les panneaux',
          'box_S': 'Evolution de la vitesse des pompes',
          'diag_B': 'Taux de couverture',
          'diag_P': 'Répartition de la production d’énergie\n chauffage + ECS',
          'diag_H': 'Part_solaire\nChauffage',  # Part solaire sur les BESOINS de chauffage
          'diag_D': 'Part_solaire\nECS',        # Part solaire sur les BESOINS d’ECS
          'bar_cumA': 'Evolution mensuelle des apports',
          'bar_cumC': "Evolution mensuelle de la production d'énergie\n(énergies cumulées)",
          'bar_cumD': "Evolution mensuelle de la production d'ECS\n(énergies cumulées)",
          'bar_cumH': "Evolution mensuelle de la production du chauffage\n(énergies cumulées)",
          'bar_supC': "Evolution mensuelle des apports et de la production d'énergie\n(énergies superposées)",
          'bar_supDispo': "Evolution mensuelle des gains et du rendement solaire\n(énergies superposées)",
          'area_E': 'Evolution des facteurs caractéristiques',
          'area_P': 'Evolution annuelle de la production en énergie',
          'area_EB': 'Evolution annuelle des besoins',
          'line_E': 'Evolution annuelle de la consommation en énergie',
          'line_ES': 'Evolution annuelle de la production solaire',
          'line_TE': 'Evolution des températures du système solaire',
          'line_Tint': 'Evolution de la température intérieure',
          'line_T': 'Evolution de la température dans le circuit d’air neuf ' +
                    '\net de la température intérieure',
          'line_H': 'Evolution annuelle de la puissance captée',
          'line_debA': 'Evolution des débits solaires et de chauffage',
          'line_debSE': 'Evolution des débits des équipements solaire',
          'line_debSCE': 'Evolution des débits dans le collecteur et radiateur',
          'line_V3V': 'Etat des vannes de régulation',
          'line_Drawing': 'Evolution du débit de puisage'}

# Field used as output for json energy file (check conv_dict to get correct names)
# Already monthly values when script create json structure.
# Careful if update conv_dict, you have to update this constant too.
# IF ADDED FIELD ALREADY IN `new_fields` REMOVE IT !!
JSON_ENERGY_FIELDS = ['Gains\ninternes', 'Chauffage_solaire_actif',
                      'Chauffage\nelec',
                      'Energie captable', 'ECS\nsolaire',
                      'Consommation\nElec_ECS',
                      'Production\nsolaire'] + [field[0] for field in new_fields]

# Field used as output for json energy file (check conv_dict to get correct names)
# These fields will be resampling before.
JSON_TEMP_FIELDS = ['T1', 'T3', 'T4', 'T5', 'T7', 'T8', 'T9_ext',
                    'T12_house', 'T14_blowing']

def time_info(frame, display=True):
    """
        frame must be an instance of EvalData class.
        if display is True :
          ---> print time informations about the frame simulation result.
        Return a dict of all time informations.
    """
    time_dict = OrdD()
    # Recup solar heating time
    chauff_sol, _ = frame.col_sum_map(frame.frame,
                                      debug=False,
                                      cols_map=['S2_state'],
                                      match_map=(100, ),
                                      start_sum=frame.frame.index[0])
    # Recup solar time TEST
    sol, _ = frame.col_sum_map_test(frame.frame,
                                    debug=False,
                                    cols_map=["Flow_Collector",
                                              "Vsolar_state"],
                                    start_sum=frame.frame.index[0])

    # Recup extra heating time with ugly function hack.
    chauff_app, _ = frame.col_sum_map_test(frame.frame,
                                           debug=False, second=False,
                                           cols_map=['ElecHeating_power'],
                                           start_sum=frame.frame.index[0])
    # Populate the time_dict
    time_dict['start_sim'] = frame.frame.index[0]
    time_dict['end_sim'] = frame.frame.index[-1]
    time_dict['solar_heating'] = chauff_sol
    time_dict['extra_heating'] = chauff_app
    time_dict['solar_working'] = sol
    if chauff_app > chauff_sol:
        time_dict['Difference'] = chauff_app - chauff_sol
    else:
        time_dict['Difference'] = chauff_sol - chauff_app
    # Display time informations
    if display is True:
        for key, item in time_dict.items():
            print('\n---> {} : {}'.format(key, item))
    return time_dict

def prepare_export(dico, name, mois):
    """
        Change format to prepare export to csv or json.
    """
    to_seconds = ('extra_heating', 'solar_heating',
                  'Difference', 'solar_working')
    dico[name][mois]['start_sim'] = str(dico[name][mois]['start_sim'])
    dico[name][mois]['end_sim'] = str(dico[name][mois]['end_sim'])
    for conv in to_seconds:
        dico[name][mois][conv] = dico[name][mois][conv].total_seconds()


import pyperclip
import webbrowser

dayType = input('Good morning, Josh! \nIs today a Schoolday, Workday, or Weekend?').lower()

workdayTasks = {
    'Prosser': '7:55am-10:35am',
    'Chick-Fil-A': '12:00pm-8:00pm'
    }
schooldayTasks = {
    'Prosser': '7:55am-10:35am',
    'Psychology 101': '1:00pm-2:15pm',
    'English 111': '2:30pm-3:45pm'
    }
weekendTasks = {}
adding = True
while adding:
    print('Your current tasks include: \n')

    if dayType == 'workday':
        for task, time in workdayTasks.items():
            print(task, time)
    elif dayType == 'schoolday':
        for task, time in schooldayTasks.items():
            print(task, time)
    elif dayType == 'weekend':
        for task, time in weekendTasks.items():
            print(task, time)

    cont = input('\nAre there any other tasks you would like to add?').lower()

    if cont == 'yes' or cont == 'y':
        newTask = input('Which task would you like to add?')
        newTime = input('What time period will ' + newTask + ' occupy?')

        if dayType == 'workday':
            workdayTasks[newTask] = newTime
        elif dayType == 'schoolday':
            schooldayTasks[newTask] = newTime
        elif dayType == 'weekend':
            weekendTasks[newTask] = newTime

    elif cont == 'no' or cont == 'n':
        adding = False

        copy = input('Do you want to copy your schedule to your clipboard?').lower()
        if copy == 'yes' or copy == 'y':
            if dayType == 'workday':
                clipboard = str(workdayTasks)
            elif dayType == 'schoolday':
                clipboard = str(schooldayTasks)
            elif dayType == 'weekend':
                clipboard = str(weekendTasks)

            censor = '{\'}'
            for char in censor:
                clipboard = clipboard.replace(char, '')
                clipboard = clipboard.replace(',', '\r\n')
                pyperclip.copy(clipboard)

        keep = input('Would you like to open Google Keep to Export your schedule?').lower()
        if keep == 'yes' or keep == 'y':
            print('Done. Have a nice day!')
            webbrowser.open('https://keep.google.com/')

        elif keep == 'no' or keep == 'n':
            print('Have a nice day!')

        else:
            print('Please respond with \'Yes\' or \'No.\'')


#
# @lc app=leetcode.cn id=680 lang=python3
#
# [680] 验证回文字符串 Ⅱ
#

# @lc code=start
class Solution:
    def validPalindrome(self, s: str) -> bool:
        def check(left, right):
            while left<right:
                if s[left]!=s[right]:
                    return False
                left += 1
                right -=1
            return True
        low = 0
        high = len(s)-1
        while low < high:
            if s[low] == s[high]:
                low += 1
                high -= 1
            else:
                return check(low+1, high) or check(low, high-1)
        return True

# @lc code=end

680.验证回文字符串-ⅱ.py


import time
import pandas as pd
import numpy as np
CITY_DATA = { 'chicago': 'chicago.csv',
              'new york city': 'new_york_city.csv',
              'washington': 'washington.csv' }

def get_filters():
    """
    Asks user to specify a city, month, and day to analyze.

    Returns:
        (str) city - name of the city to analyze
        (str) month - name of the month to filter by, or "all" to apply no month filter
        (str) day - name of the day of week to filter by, or "all" to apply no day filter
    """
    print('Hello! Let\'s explore some US bikeshare data!')
# TO DO: get user input for city (chicago, new york city, washington). HINT: Use a while loop to handle invalid inputs
    city_abbreviations = ['chi', 'ny', 'w']
    while True:
        city = input('Kindly specify a city by typing chicago or new york city or washington: \n\n').lower()
        if city in CITY_DATA.keys():
            break
        elif city.lower() == 'new york': #if the user forgot to add city to new york as it's a common mistake between users
            print('\nPlease notify that the city you typed called new york city, So retype it again right this time: \n')
        elif city in city_abbreviations: #if the user input was abbreviations of the name as it's a common mistake between users
            print('\nPlease notify that city abbreviation\'s is not allowed, Retype city full name!\n')
        elif city.lower() == 'newyorkcity': #if user's input was newyorkcity without any spaces as it's a common mistake between users
            print('\nPlease notify that the city you typed called new york city with spaces between words, So retype it again right this time: \n')
        else:                            #if user printed any other things like wrong name or used speical chracters like space _ + = ~
            print('\nThats invalid input....\n\nplease choose one of the three cities chicago or new york city or washington.\n')
# TO DO: get user input for month (all, january, february, ... , june)
    months = ['january', 'february', 'march', 'april', 'may', 'june', 'all']
    months_abbreviations = ['jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug']
    while True:
        month = input('\n\nTo filter data by a particuler month, please type the month or all for not filtering by month: \n-january\n-february\n-march\n-april\n-may\n-june\n-all\n\n').lower()
        if month in months:
            break
        elif month in months_abbreviations:
            print('\nPlease notify that months abbreviation\'s is not allowed, Retype month full name!\n')
        else:                            #if the user input was abbreviations of the name as it's a common mistake between users
            print('\nThats invalid input....\n\n\nplease choose one of the six  months listed to filter with or use no filter\n')
# TO DO: get user input for day of week (all, monday, tuesday, ... sunday)
    days = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday','saturday', 'sunday', 'all']
    days_abbreviations = ['mon', 'tu', 'tue', 'tues', 'wed', 'th', 'thu', 'thur', 'thurs', 'fri', 'sat', 'sun']
    while True:
        day = input('\n\nTo filter data by a particuler day, please type the day or all for not filtering by day: \n-saturday\n-sunday\n-monday\n-tuesday\n-wednesday\n-thursday\n-friday\n-all\n\n').lower()
        if day in days:
            break
        elif day in days_abbreviations:   #if the user input was abbreviations of the name as it's a common mistake between users
            print('\nPlease notify that day abbreviation\'s is not allowed, Retype day full name!\n')
        else:
            print('\nThats invalid input....\n\n\nplease choose one of the seven days listed to filter with or use no filter\n')
    print('-'*40)
    return city, month, day

def load_data(city, month, day):
    """
    Loads data for the specified city and filters by month and day if applicable.

    Args:
        (str) city - name of the city to analyze
        (str) month - name of the month to filter by, or "all" to apply no month filter
        (str) day - name of the day of week to filter by, or "all" to apply no day filter
    Returns:
        df - Pandas DataFrame containing city data filtered by month and day
    """
    #loading data of the city chosen by user into dataframe
    df = pd.read_csv(CITY_DATA[city])
    #converting the start time clomn from object (string) to datetime object so as we can use datetime  Attributes and methonds to extract month coulmn and day to filter with them
    df['Start Time'] = pd.to_datetime(df['Start Time'])
    #extracting month and day into new columns and days into new column 'month_name' and 'day_name' are methods in pandas datetime (https://pandas.pydata.org/pandas-docs/version/0.23/generated/pandas.DatetimeIndex.html) as it's in this link
    df['month'] = df['Start Time'].dt.month_name()
    df['day_of_week'] = df['Start Time'].dt.day_name()
    #filtering data city with user inputs filter by moth and day:
    if month != 'all':
        df = df[df['month'] == month.title()]
    if day != 'all':
        df = df[df['day_of_week'] == day.title()]

    return df

def time_stats(df):
    """Displays statistics on the most frequent times of travel."""

    print('\nCalculating statistics of The Most Frequent Times of Travel...\n')
    start_time = time.time()

    # TO DO: display the most common month
    most_common_month = df['month'].mode()[0]
    print('Most common Month is: ', most_common_month )
    # TO DO: display the most common day of week
    most_common_day = df['day_of_week'].mode()[0]
    print('Most common Day is: ', most_common_day)
    # TO DO: display the most common start hour
    df['hour'] = df['Start Time'].dt.hour
    most_common_hour = df['hour'].mode()[0]
    print('Most common Hour is: ', most_common_hour)
    print("\nThis took %s seconds." % (time.time() - start_time))
    print('-'*40)

def station_stats(df):
    """Displays statistics on the most popular stations and trip."""

    print('\nCalculating The Most Popular Stations and Trip...\n')
    start_time = time.time()

    # TO DO: display most commonly used start station
    popular_start_station = df['Start Station'].mode()[0]
    print('Most popular Start station is: ', popular_start_station)
    # TO DO: display most commonly used end station
    popular_end_station = df['End Station'].mode()[0]
    print('Most popular End Station is ', popular_end_station)
    # TO DO: display most frequent combination of start station and end station trip
    popular_trip_start_end = (df['Start Station'] + ' To ' + df['End Station']).mode()[0]
    print('Most popular Trip from star to end: ', popular_trip_start_end)
    print("\nThis took %s seconds." % (time.time() - start_time))
    print('-'*40)

def trip_duration_stats(df):
    """Displays statistics on the total and average trip duration."""

    print('\nCalculating Trip Duration...\n')
    start_time = time.time()

    # TO DO: display total travel time
    total_travel_time = df['Trip Duration'].sum()
    print('Total travel time in seconds is : ', total_travel_time)
    # TO DO: display mean travel time
    mean_travel_time = df['Trip Duration'].mean()
    print('Average travel time in seconds is : ', mean_travel_time)
    print("\nThis took %s seconds." % (time.time() - start_time))
    print('-'*40)

def user_stats(df):
    """Displays statistics on bikeshare users."""
    print('\nCalculating User Stats...\n')
    start_time = time.time()

    # TO DO: Display counts of user types
    user_type_count = df['User Type'].value_counts().to_frame()
    print(user_type_count)
    # TO DO: Display counts of gender
    try:
        most_common_gender = df['Gender'].value_counts().to_frame()
        print(most_common_gender)
    # TO DO: Display earliest, most recent, and most common year of birth
        earliest_birth_year = df['Birth Year'].min()
        print('\nEarliest birth year is : ', int(earliest_birth_year))
        most_recent_birth_year = df['Birth Year'].max()
        print('\nMost recent birth year is : ', int(most_recent_birth_year))
        most_common_birth_year = df['Birth Year'].mode()[0]
        print('\nMost common birth year is : ', int(most_common_birth_year))
    except KeyError:
        print('\nGender and Birth year data is only available in \'chicago\' and \'new york city\'')
    print("\nThis took %s seconds." % (time.time() - start_time))
    print('-'*40)

def display_raw_data(city):
    ''' Display raw data for users input based on his choice to see it or not'''
    print('\nRaw Data is available to be checked!\n')
    user_display_raw = input('Do you want to see the available raw data for the first 5 rows?\nPlease type Yes if you want to see or No\n').lower()
    while user_display_raw not in ('yes', 'no'):
        print('\nThat\'s invalid input, Please answer the question with Yes or No!')
        user_display_raw = input('\nDo you want to see the available raw data for the first 5 rows?\nPlease type Yes if you want to see or No\n').lower()
    while user_display_raw == 'yes':
        try:
            for chunk in pd.read_csv(CITY_DATA[city], chunksize = 5): #chunk in data frame info https://janakiev.com/blog/python-pandas-chunks/
                print(chunk)
                user_display_raw = input('\nDo you want to see the available raw data for the Next 5 rows?\nPlease type Yes if you want to see or No\n').lower()
                if user_display_raw == 'no':
                    print('\nSee you next time.')
                    break
                while user_display_raw not in ('yes', 'no'):
                    print('\nThat\'s invalid input, Please answer the question with Yes or No!')
                    user_display_raw = input('\nDo you want to see the available raw data for the Next 5 rows?\nPlease type Yes if you want to see or No\n').lower()
                if user_display_raw == 'no':
                    print('\nSee you next time.')
                    break
            break
        except KeyboardInterrupt:
            print('\nSee you next time.')

def main():
    while True:
        city, month, day = get_filters()
        print('You have selcted City: {}\nMonth filter: {}\nDay filter: {}\n\'Notify that all means no filter is used\''.format(city, month, day))
        df = load_data(city, month, day)
        time_stats(df)
        station_stats(df)
        trip_duration_stats(df)
        user_stats(df)
        display_raw_data(city)
        restart = input('\nWould you like to restart? Enter yes or no.\n')
        if restart.lower() != 'yes':
            break

if __name__ == "__main__":
	main()


from flask import Flask, request, jsonify
from pprint import pprint
import json, os

app = Flask(__name__)

@app.route('/webhooks/inbound-sms', methods=['GET', 'POST'])
def inbound_sms():
    if request.is_json:
        pprint(request.get_json())
    else:
        data = dict(request.form) or dict(request.args)
        with open('response.json', 'w') as outfile:
            json.dump(data, outfile)
        os.system("python3 execute.py")
        pprint(data)
    return ('', 204)
app.run(port=3000)


#СОЗДАНИЕ ПЕРВОЙ ФИГУРЫ
from bokeh.io import output_file
from bokeh.plotting import figure, show

# Рисунок будет отображен в статическом HTML-файле
output_file('Создание_первой_фигуры.html',
            title='Empty Bokeh Figure')

# Настроить общий объект figure()
fig = figure()

# Посмотрите, как это выглядит
show(fig)

#ПОДГОТОВКА ФИГУРЫ К ДАННЫМ
from bokeh.plotting import figure, show

output_file('Подготовка_фигуры_к_данным.html',
            title='Bokeh Figure')

fig = figure(background_fill_color='gray',
             background_fill_alpha=0.5,
             border_fill_color='blue',
             border_fill_alpha=0.25,
             plot_height=300,
             plot_width=500,
             x_axis_label='X Label',
             x_axis_type='datetime',
             x_axis_location='above',
             x_range=('2018-01-01', '2018-06-30'),
             y_axis_label='Y Label',
             y_axis_type='linear',
             y_axis_location='left',
             y_range=(0, 100),
             title='Example Figure',
             title_location='right',
             toolbar_location='below',
             tools='save')

show(fig)

#РИСОВАНИЕ ДАННЫХ С ПОМОЩЬЮ ГЛИФОВ
#Создание первых данных
from bokeh.io import output_file
from bokeh.plotting import figure, show

# Мои данные о координатах x-y
x = [1, 2, 1]
y = [1, 1, 2]

output_file('Рисование_данных_с_помощью_глифов1.html', title='First Glyphs')

# Создайте фигуру без панели инструментов и диапазонов осей
fig = figure(title='My Coordinates',
             plot_height=300, plot_width=300,
             x_range=(0, 3), y_range=(0, 3),
             toolbar_location=None)

# Нарисуйте координаты в виде кругов
fig.circle(x=x, y=y,
           color='green', size=10, alpha=0.5)

# Показать сюжет
show(fig)

#Создание вторых данных
import numpy as np
from bokeh.plotting import figure, show

# Мои данные о подсчете слов
day_num = np.linspace(1, 10, 10)
daily_words = [450, 628, 488, 210, 287, 791, 508, 639, 397, 943]
cumulative_words = np.cumsum(daily_words)

output_file('Рисование_данных_с_помощью_глифов2.html', title='First Glyphs')

# Создаем фигуру с осью x типа datetime
fig = figure(title='My Tutorial Progress',
             plot_height=400, plot_width=700,
             x_axis_label='Day Number', y_axis_label='Words Written',
             x_minor_ticks=2, y_range=(0, 6000),
             toolbar_location=None)

# Ежедневные слова будут представлены в виде вертикальных полос (столбцов)
fig.vbar(x=day_num, bottom=0, top=daily_words,
         color='blue', width=0.75,
         legend='Daily')

# Накопленная сумма будет линией тренда
fig.line(x=day_num, y=cumulative_words,
         color='gray', line_width=1,
         legend='Cumulative')

# Поместите легенду в левый верхний угол
fig.legend.location = 'top_left'

# Давайте проверим
show(fig)

#НЕБОЛЬШАЯ ЗАМЕТКА О ДАННЫХ
import pandas as pd
# Прочитать csv файлы
player_stats = pd.read_csv('2017-18_playerBoxScore.csv', parse_dates=['gmDate'])
team_stats = pd.read_csv('2017-18_teamBoxScore.csv', parse_dates=['gmDate'])
standings = pd.read_csv('2017-18_standings.csv', parse_dates=['stDate'])
print(player_stats)

#ИСПОЛЬЗОВАНИЕ ОБЪЕКТА ColumnDataSource
#Пример 1
west_top_2 = (standings[(standings['teamAbbr'] == 'HOU') | (standings['teamAbbr'] == 'GS')]
              .loc[:, ['stDate', 'teamAbbr', 'gameWon']]
             .sort_values(['teamAbbr','stDate']))
print(west_top_2.head())

from bokeh.plotting import figure, show
from bokeh.io import output_file
from bokeh.models import ColumnDataSource

# Output to file
output_file('west-top-2-standings-race1.html',
            title='Western Conference Top 2 Teams Wins Race')

# Isolate the data for the Rockets and Warriors
rockets_data = west_top_2[west_top_2['teamAbbr'] == 'HOU']
warriors_data = west_top_2[west_top_2['teamAbbr'] == 'GS']

# Create a ColumnDataSource object for each team
rockets_cds = ColumnDataSource(rockets_data)
warriors_cds = ColumnDataSource(warriors_data)

# Create and configure the figure
fig = figure(x_axis_type='datetime',
             plot_height=300, plot_width=600,
             title='Western Conference Top 2 Teams Wins Race, 2017-18',
             x_axis_label='Date', y_axis_label='Wins',
             toolbar_location=None)

# Render the race as step lines
fig.step('stDate', 'gameWon',
         color='#CE1141', legend='Rockets',
         source=rockets_cds)
fig.step('stDate', 'gameWon',
         color='#006BB6', legend='Warriors',
         source=warriors_cds)

# Move the legend to the upper left corner
fig.legend.location = 'top_left'

# Show the plot
show(fig)
#Пример 2
from bokeh.plotting import figure, show
from bokeh.io import output_file
from bokeh.models import ColumnDataSource, CDSView, GroupFilter

# Вывод в файл
output_file('west-top-2-standings-race2.html',
            title='Western Conference Top 2 Teams Wins Race')

# Создать ColumnDataSource
west_cds = ColumnDataSource(west_top_2)

# Создайте представления для каждой команды
rockets_view = CDSView(source=west_cds,
                       filters=[GroupFilter(column_name='teamAbbr', group='HOU')])
warriors_view = CDSView(source=west_cds,
                        filters=[GroupFilter(column_name='teamAbbr', group='GS')])

# Создаем и настраиваем фигуру
west_fig = figure(x_axis_type='datetime',
                  plot_height=300, plot_width=600,
                  title='Western Conference Top 2 Teams Wins Race, 2017-18',
                  x_axis_label='Date', y_axis_label='Wins',
                  toolbar_location=None)

# Отрисовываем гонку в виде ступенчатых линий
west_fig.step('stDate', 'gameWon',
              source=west_cds, view=rockets_view,
              color='#CE1141', legend='Rockets')
west_fig.step('stDate', 'gameWon',
              source=west_cds, view=warriors_view,
              color='#006BB6', legend='Warriors')

# Переместите легенду в верхний левый угол
west_fig.legend.location = 'top_left'

# Показать сюжет
show(west_fig)

#ОРГАНИЗАЦИЯ НЕСКОЛЬКИХ ВИЗУАЛИЗАЦИЙ С ПОМОЩЬЮ МАКЕТОВ
from bokeh.plotting import figure, show
from bokeh.io import output_file
from bokeh.models import ColumnDataSource, CDSView, GroupFilter

# Вывод в файл
output_file('Организация_нескольких_визуализаций_с_помощью_макетов.html',
            title='Eastern Conference Top 2 Teams Wins Race')

# Создать ColumnDataSource
standings_cds = ColumnDataSource(standings)

# Create views for each team
celtics_view = CDSView(source=standings_cds,
                      filters=[GroupFilter(column_name='teamAbbr',
                                           group='BOS')])
raptors_view = CDSView(source=standings_cds,
                      filters=[GroupFilter(column_name='teamAbbr',
                                           group='TOR')])

# Создаем и настраиваем фигуру
east_fig = figure(x_axis_type='datetime',
           plot_height=300, plot_width=600,
           title='Eastern Conference Top 2 Teams Wins Race, 2017-18',
           x_axis_label='Date', y_axis_label='Wins',
           toolbar_location=None)

# Отрисовываем гонку в виде ступенчатых линий
east_fig.step('stDate', 'gameWon',
              color='#007A33', legend='Celtics',
              source=standings_cds, view=celtics_view)
east_fig.step('stDate', 'gameWon',
              color='#CE1141', legend='Raptors',
              source=standings_cds, view=raptors_view)

# Переместите легенду в верхний левый угол
east_fig.legend.location = 'top_left'

# Показать сюжет
show(east_fig)

#ДОБАВЛЕНИЕ ВЗАИМОДЕЙСТВИЯ
#ВЫБОР ТОЧЕК ДАННЫХ
# Найдите игроков, которые сделали хотя бы 1 трехочковый бросок за сезон
three_takers = player_stats[player_stats['play3PA'] > 0]

# Убрать имена игроков, поместив их в один столбец
three_takers['name'] = [f'{p["playFNm"]} {p["playLNm"]}'
                        for _, p in three_takers.iterrows()]

# Суммируйте общее количество трехочковых попыток и количество попыток для каждого игрока
three_takers = (three_takers.groupby('name')
                            .sum()
                            .loc[:,['play3PA', 'play3PM']]
                            .sort_values('play3PA', ascending=False))

# Отфильтровать всех, кто не сделал хотя бы 100 трехочковых бросков
three_takers = three_takers[three_takers['play3PA'] >= 100].reset_index()

# Добавить столбец с рассчитанным трехбалльным процентом (выполнено / предпринято)
three_takers['pct3PM'] = three_takers['play3PM'] / three_takers['play3PA']
print(three_takers.sample(5))

# Выбор группы игроков в раздаче из полученного DataFrame, при этом отключить цвет глифов
from bokeh.plotting import figure, show
from bokeh.io import output_file
from bokeh.models import ColumnDataSource, NumeralTickFormatter

# Файл вывода
output_file('Выбор_точек_данных.html',
            title='Three-Point Attempts vs. Percentage')

# Сохраним данные в ColumnDataSource
three_takers_cds = ColumnDataSource(three_takers)

# Укажите инструменты выбора, которые будут доступны
select_tools = ['box_select', 'lasso_select', 'poly_select', 'tap', 'reset']

# Создание картинки
fig = figure(plot_height=400,
             plot_width=600,
             x_axis_label='Three-Point Shots Attempted',
             y_axis_label='Percentage Made',
             title='3PT Shots Attempted vs. Percentage Made (min. 100 3PA), 2017-18',
             toolbar_location='below',
             tools=select_tools)

# Отформатируйте метки делений оси Y в процентах
fig.yaxis[0].formatter = NumeralTickFormatter(format='00.0%')

# Добавить квадрат, представляющий каждого игрока
fig.square(x='play3PA',
           y='pct3PM',
           source=three_takers_cds,
           color='royalblue',
           selection_color='deepskyblue',
           nonselection_color='lightgray',
           nonselection_alpha=0.3)

# Показать результат
show(fig)

#ДОБАВЛЕНИЕ ДЕЙСТВИЙ ПРИ НАВЕДЕНИИ КУРСОРА
from bokeh.models import HoverTool

output_file('Добавление_действий_при_наведении_курсора.html',
            title='Three-Point Attempts vs. Percentage')

# Отформатируйте всплывающую подсказку
# Отформатируйте всплывающую подсказку
tooltips = [
            ('Player','@name'),
            ('Three-Pointers Made', '@play3PM'),
            ('Three-Pointers Attempted', '@play3PA'),
            ('Three-Point Percentage','@pct3PM{00.0%}'),
           ]

# Настроить рендерер, который будет использоваться при наведении
hover_glyph = fig.circle(x='play3PA', y='pct3PM', source=three_takers_cds,
                         size=15, alpha=0,
                         hover_fill_color='black', hover_alpha=0.5)

# Добавляем HoverTool к фигуре
fig.add_tools(HoverTool(tooltips=tooltips, renderers=[hover_glyph]))

# Показать
show(fig)

#ВЫДЕЛЕНИЕ ДАННЫХ С ПОМОЩЬЮ ЛЕГЕНДЫ
from bokeh.plotting import figure, show
from bokeh.io import output_file
from bokeh.models import ColumnDataSource, CDSView, GroupFilter
from bokeh.layouts import row

# Вывести в записной книжке
output_file('lebron-vs-durant.html',
            title='LeBron James vs. Kevin Durant')

# Хранить данные в ColumnDataSource
player_gm_stats = ColumnDataSource(player_stats)

# Создайте представление для каждого игрока
lebron_filters = [GroupFilter(column_name='playFNm', group='LeBron'),
                  GroupFilter(column_name='playLNm', group='James')]
lebron_view = CDSView(source=player_gm_stats,
                      filters=lebron_filters)

durant_filters = [GroupFilter(column_name='playFNm', group='Kevin'),
                  GroupFilter(column_name='playLNm', group='Durant')]
durant_view = CDSView(source=player_gm_stats,
                      filters=durant_filters)
# Объединить общие аргументы ключевых слов в dicts
common_figure_kwargs = {
    'plot_width': 400,
    'x_axis_label': 'Points',
    'toolbar_location': None,
}
common_circle_kwargs = {
    'x': 'playPTS',
    'y': 'playTRB',
    'source': player_gm_stats,
    'size': 12,
    'alpha': 0.7,
}
common_lebron_kwargs = {
    'view': lebron_view,
    'color': '#002859',
    'legend': 'LeBron James'
}
common_durant_kwargs = {
    'view': durant_view,
    'color': '#FFC324',
    'legend': 'Kevin Durant'
}

# Создайте две фигуры и нарисуйте данные
hide_fig = figure(**common_figure_kwargs,
                  title='Click Legend to HIDE Data',
                  y_axis_label='Rebounds')
hide_fig.circle(**common_circle_kwargs, **common_lebron_kwargs)
hide_fig.circle(**common_circle_kwargs, **common_durant_kwargs)

mute_fig = figure(**common_figure_kwargs, title='Click Legend to MUTE Data')
mute_fig.circle(**common_circle_kwargs, **common_lebron_kwargs,
                muted_alpha=0.1)
mute_fig.circle(**common_circle_kwargs, **common_durant_kwargs,
                muted_alpha=0.1)

# Добавляем интерактивности в легенду
hide_fig.legend.click_policy = 'hide'
mute_fig.legend.click_policy = 'mute'

# Визуализировать
show(row(hide_fig, mute_fig))


"""This module contains model that stores Robot Framework variables.

Copyright (c) 2021 http://reportportal.io .
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""

from os import getenv, path
from distutils.util import strtobool

from robot.libraries.BuiltIn import BuiltIn, RobotNotRunningError

from .exception import RobotServiceException

# This is a storage for the result visitor
_variables = {}

def get_variable(name, default=None):
    """Get Robot Framework variable.

    :param name:    Name of the variable
    :param default: Default value
    :return:        The value of the variable, otherwise default value
    """
    try:
        return BuiltIn().get_variable_value("${" + name + "}", default=default)
    except RobotNotRunningError:
        return _variables.get(name, default)

class Variables(object):
    """This class stores Robot Framework variables related to Report Portal."""

    def __init__(self):
        """Initialize instance attributes."""
        self._endpoint = None
        self._launch_name = None
        self._pabot_pool_id = None
        self._pabot_used = None
        self._project = None
        self._uuid = None
        self.attach_log = strtobool(get_variable(
            'RP_ATTACH_LOG', default='False'))
        self.attach_report = strtobool(get_variable(
            'RP_ATTACH_REPORT', default='False'))
        self.attach_xunit = strtobool(get_variable(
            'RP_ATTACH_XUNIT', default='False'))
        self.launch_attributes = get_variable(
            'RP_LAUNCH_ATTRIBUTES', default='').split()
        self.launch_id = get_variable('RP_LAUNCH_UUID')
        self.launch_doc = get_variable('RP_LAUNCH_DOC')
        self.log_batch_size = int(get_variable(
            'RP_LOG_BATCH_SIZE', default='20'))
        self.mode = get_variable('RP_MODE')
        self.pool_size = int(get_variable('RP_MAX_POOL_SIZE', default='50'))
        self.rerun = strtobool(get_variable(
            'RP_RERUN', default='False'))
        self.rerun_of = get_variable('RP_RERUN_OF', default=None)
        self.skip_analytics = getenv('AGENT_NO_ANALYTICS')
        self.skipped_issue = strtobool(get_variable(
            'RP_SKIPPED_ISSUE', default='True'))
        self.test_attributes = get_variable(
            'RP_TEST_ATTRIBUTES', default='').split()

    @property
    def endpoint(self):
        """Get Report Portal API endpoint.

        :raises: RobotServiceException if it is None
        :return: Report Portal API endpoint
        """
        self._endpoint = self._endpoint or get_variable('RP_ENDPOINT')
        if self._endpoint is None:
            raise RobotServiceException(
                'Missing parameter RP_ENDPOINT for robot run\n'
                'You should pass -v RP_ENDPOINT:<endpoint_value>')
        return self._endpoint

    @property
    def launch_name(self):
        """Get Report Portal launch name.

        :raises: RobotServiceException if it is None
        :return: Report Portal launch name
        """
        self._launch_name = self._launch_name or get_variable('RP_LAUNCH')
        if self._launch_name is None:
            raise RobotServiceException(
                'Missing parameter RP_LAUNCH for robot run\n'
                'You should pass -v RP_LAUNCH:<launch_name_value>')
        return self._launch_name

    @property
    def pabot_pool_id(self):
        """Get pool id for the current Robot Framework executor.

        :return: Pool id for the current Robot Framework executor
        """
        if not self._pabot_pool_id:
            self._pabot_pool_id = get_variable(name='PABOTEXECUTIONPOOLID')
        return self._pabot_pool_id

    @property
    def pabot_used(self):
        """Get status of using pabot in test execution.

        :return: Cached value of the Pabotlib URI
        """
        if not self._pabot_used:
            self._pabot_used = get_variable(name='PABOTLIBURI')
        return self._pabot_used

    @property
    def project(self):
        """Get Report Portal project name.

        :raises: RobotServiceException if it is None
        :return: Report Portal project name
        """
        self._project = self._project or get_variable('RP_PROJECT')
        if self._project is None:
            raise RobotServiceException(
                'Missing parameter RP_PROJECT for robot run\n'
                'You should pass -v RP_PROJECT:<project_name_value>')
        return self._project

    @property
    def uuid(self):
        """Get Report Portal API token UUID.

        :raises: RobotServiceException if it is None
        :return: Report Portal token UUID
        """
        self._uuid = self._uuid or get_variable('RP_UUID')
        if self._uuid is None:
            raise RobotServiceException(
                'Missing parameter RP_UUID for robot run\n'
                'You should pass -v RP_UUID:<uuid_value>')
        return self._uuid

    @property
    def verify_ssl(self):
        """Get value of the verify_ssl parameter for the client."""
        verify_ssl = get_variable('RP_VERIFY_SSL', default='True')
        if path.exists(verify_ssl):
            return verify_ssl
        return bool(strtobool(verify_ssl))


from lxml import etree
import requests
import re
import csv
import sys

movie_titles = []

with open('movies.csv','r') as csvfile:
	reader = csv.reader(csvfile, delimiter=',',quotechar='"', quoting=csv.QUOTE_ALL)
	for row in reader:
		movie_titles.append(row[0])

with open('movie_db.csv', 'w', newline='') as csvfile:
	writer = csv.writer(csvfile, delimiter=',',quotechar='"', quoting=csv.QUOTE_ALL)
	writer.writerow(["question","answer","second_answer"])
	for i,movie_title in enumerate(movie_titles):
		if (i%10==0):
			sys.stdout.write('.')
			sys.stdout.flush()
		splitted = str.split(movie_title)
		movie_plus = '+'.join(splitted)
		page = requests.get("http://www.omdbapi.com/?t="+ movie_plus +"&plot=full&r=xml")
		root = etree.fromstring(page.content)
		doc = etree.tostring(root, encoding='UTF-8')

		doc = doc.decode("utf-8")

		movie_name = re.compile('movie title="(.*)" year')
		match = re.findall(movie_name,doc)
		if match:
			title = match[0].lower()

		movie_plot = re.compile('plot="(.*)" language')
		match = re.findall(movie_plot,doc)
		if match:
			plot_long = match[0]

		page = requests.get("http://www.omdbapi.com/?t="+ movie_plus +"&r=xml")

		root = etree.fromstring(page.content)
		doc = etree.tostring(root, encoding='UTF-8')

		doc = doc.decode("utf-8")
		movie_plot = re.compile('plot="(.*)" language')
		match = re.findall(movie_plot,doc)
		if match:
			plot_short = match[0]

		writer.writerow([title, plot_long, plot_short])