import math
import time
from collections import deque

class Video_flow():
    def __init__(self, finger_list, tuple_list, video_url='', mitm_path='', streamID=-1,
                 state_transition_matrix='') -> None:
        # 指纹列表
        self.finger_list = finger_list
        # 传输使用的五元组列表
        self.tuple_list = tuple_list
        # 视频对应的URL
        self.video_url = video_url
        self.mitm_path = mitm_path
        self.state_transition_matrix = state_transition_matrix
        self.streamID = streamID

class Offline_Process():
    def __init__(self, offline_file, offline_audio_thd=700000) -> None:
        self.offline_file = offline_file
        self.offline_audio_thd = offline_audio_thd
        self.offline_chunk_list = []
        self.get_offline_finger()
        self.small_chunk_clean(self.offline_chunk_list, offline_audio_thd)

    # 获取离线指纹
    def get_offline_finger(self):
        offline_file = open(self.offline_file, mode='r', encoding='utf-8')
        offline_data = offline_file.read()
        offline_datas = offline_data.split('\n')
        streamID = -1
        for lines in offline_datas:
            if lines == '':
                continue
            vals = lines.split(',')
            video_url = vals[3]  # 视频URL
            stream_type = vals[2]  # video or audio
            finger = vals[4].split('/')[1:]  # 指纹
            tuples = vals[5].split('/')[1:]  # 五元组
            mitm_path = vals[0]  # mitm_path路径
            if stream_type == 'video':
                streamID += 1
                video_flow = Video_flow(list(map(int, finger)), tuples, video_url, mitm_path, streamID)
                self.offline_chunk_list.append(video_flow)
            if stream_type == 'audio':
                pass

    # 过滤掉指纹序列中小于阈值的块
    def small_chunk_clean(self, chunk_list, audio_thd):
        for chunk in chunk_list:
            clean_finger = []
            for val in chunk.finger_list:
                if val > audio_thd:
                    clean_finger.append(val)
            chunk.finger_list = clean_finger

class Markov_alg():
    def __init__(self, online_chunk_list, offline_file, offline_audio_thd, high_orders, high_bins_count, high_win_size,
                 low_orders, low_bins_count, low_win_size) -> None:

        self.video_chunk_size_max = 2200000.0
        self.video_chunk_size_min = offline_audio_thd
        # 获取指纹数据
        finger_data = Offline_Process(offline_file, offline_audio_thd)
        self.offline_chunk_list = finger_data.offline_chunk_list
        self.online_chunk_list = online_chunk_list

        self.high_glabal_state_transition_table = self.state_transition_calculate(high_bins_count, high_orders)
        self.high_state_transition_table = self.state_transition_table_generate(high_orders)
        self.low_glabal_state_transition_table = self.state_transition_calculate(low_bins_count, low_orders)
        self.low_state_transition_table = self.state_transition_table_generate(low_orders)

        self.pred_stream = None
        self.zero_prob = 0
        self.online_match(high_orders, high_bins_count, high_win_size, 0)
        self.streamID2video_flow_class()
        self.online_match(low_orders, low_bins_count, low_win_size, 1)
        self.streamID2video_flow_class()

    # 记录指纹库的所有转移概率
    def state_transition_calculate(self, bins_count, orders):
        global_tran_prob_table = {}
        word_count = 0
        orders += 1
        # 计算离线指纹的order阶概率转移矩阵
        index_i = -1
        bin_size = (self.video_chunk_size_max - self.video_chunk_size_min) / bins_count
        for offline_chunk in self.offline_chunk_list:
            index_i += 1
            self.offline_chunk_list[index_i].state_transition_matrix = ''
            # 用一个队列记录n阶的桶关系
            bin_relation_que = deque()
            state_transition_dict = {}
            for chunk in offline_chunk.finger_list:
                # 离线 等分分桶
                # 获得桶的编号
                if chunk >= self.video_chunk_size_max:
                    bin_index_cur = bins_count - 1
                elif chunk <= self.video_chunk_size_min:
                    bin_index_cur = 0
                else:
                    bin_index_cur = int((chunk - self.video_chunk_size_min) / bin_size)
                # 记录转移序列
                bin_relation_que.append(bin_index_cur)
                if len(bin_relation_que) < orders:
                    continue
                relation_key = ''
                for val in bin_relation_que:
                    relation_key += str(val) + '-'
                if relation_key not in state_transition_dict:
                    state_transition_dict[relation_key] = 1
                else:
                    state_transition_dict[relation_key] += 1

                # 全局概率
                if relation_key not in global_tran_prob_table:
                    global_tran_prob_table[relation_key] = 1
                else:
                    global_tran_prob_table[relation_key] += 1
                word_count += 1

                bin_relation_que.popleft()
            self.offline_chunk_list[index_i].state_transition_matrix = state_transition_dict

        for transition, transition_prob in global_tran_prob_table.items():
            prob = math.log(word_count / (transition_prob + 1))
            global_tran_prob_table[transition] = prob
        return global_tran_prob_table

    # 生成指纹库的转移概率表
    def state_transition_table_generate(self, orders):
        state_transition_table = {}
        for offline_chunk in self.offline_chunk_list:
            cur_state_transition_dict = offline_chunk.state_transition_matrix
            off_chunk_len = len(offline_chunk.finger_list)
            if cur_state_transition_dict == '' or len(cur_state_transition_dict) == 0:
                continue
            cur_streamID = offline_chunk.streamID
            for transition, transition_prob in cur_state_transition_dict.items():
                transition_prob = transition_prob / (off_chunk_len + 1 - orders)
                if transition in state_transition_table:
                    state_transition_table[transition].append([cur_streamID, transition_prob])
                else:
                    state_transition_table[transition] = [[cur_streamID, transition_prob]]
        return state_transition_table

    # 在线匹配
    def online_match(self, orders, bins_count, win_size, mutil_order_flag):
        time_sum = 0
        time_count = 0
        orders += 1
        bin_size = (self.video_chunk_size_max - self.video_chunk_size_min) / bins_count
        # 长度太短而不参与匹配的在线指纹数量
        if mutil_order_flag == 0:
            state_transition_table = self.high_state_transition_table
            # global
            global_state_transition_table = self.high_glabal_state_transition_table
        else:
            state_transition_table = self.low_state_transition_table
            # global
            global_state_transition_table = self.low_glabal_state_transition_table

        # 马尔可夫降阶
        if mutil_order_flag == 1:
            if self.zero_prob == 0:
                return 0
        else:
            self.pred_stream = None

        online_chunk = self.online_chunk_list
        online_bin_relation_que = deque()
        online_state_transition_dict = {}
        # 长度太短而不参与匹配,+n则保证至少有n次转移
        if len(online_chunk) < orders + 1:
            return 0
        time_start = time.time()
        ##在线指纹预处理：计算转移过程
        on_chunk_count = 0
        for on_chunk in online_chunk:
            # 动态偏置
            chunk_bias = on_chunk * 0.97214644 - 1145.44281353
            if chunk_bias >= self.video_chunk_size_max:
                bin_index_cur = bins_count - 1
            elif chunk_bias <= self.video_chunk_size_min:
                bin_index_cur = 0
            else:
                bin_index_cur = int((chunk_bias - self.video_chunk_size_min) / bin_size)

            # 记录转移序列
            online_bin_relation_que.append(bin_index_cur)
            if len(online_bin_relation_que) < orders:
                continue
            relation_key = ''
            for val in online_bin_relation_que:
                relation_key += str(val) + '-'
            if relation_key not in online_state_transition_dict:
                online_state_transition_dict[relation_key] = 1
            else:
                online_state_transition_dict[relation_key] += 1
            online_bin_relation_que.popleft()
            # 控制在线匹配指纹的长度
            on_chunk_count += 1
            if on_chunk_count >= win_size:
                break

        # 计算最大概率值对应的streamID
        state_dict = {}
        for on_key, on_val in online_state_transition_dict.items():
            if on_key in state_transition_table:
                for val in state_transition_table[on_key]:
                    if val[0] in state_dict:
                        # state_dict[val[0]] += on_val * val[1]
                        # state_dict[val[0]] +=on_val*val[1]*global_state_transition_table[on_key]
                        state_dict[val[0]] += on_val * val[1] + global_state_transition_table[on_key] * 100
                    else:
                        # state_dict[val[0]] = on_val * val[1]
                        # state_dict[val[0]]=on_val*val[1]*global_state_transition_table[on_key]
                        state_dict[val[0]] = on_val * val[1] + global_state_transition_table[on_key] * 100

        max_prob = 0
        target_id = -1
        if len(state_dict) == 0:
            self.zero_prob = 1
        else:
            for stream_id, prob in state_dict.items():
                if prob > max_prob:
                    max_prob = prob
                    target_id = stream_id
        self.pred_stream = target_id
        time_end = time.time()
        time_sum += time_end - time_start
        time_count += 1

    # 在线匹配过程中streamID与指纹库类的对应关系
    def streamID2video_flow_class(self):
        if self.pred_stream == -1:
            return 0
        for offline_chunk in self.offline_chunk_list:
            if offline_chunk.streamID == self.pred_stream:
                self.pred_stream = offline_chunk


import argparse
import os
import random
import time
import torch
import torch.nn as nn
import torch.nn.parallel
import torch.backends.cudnn as cudnn
import torch.optim as optim
import torch.utils.data
import torchvision.datasets as dset
import torchvision.transforms as transforms
import torchvision.utils as vutils
import einops as ein

from FID.InceptionNet import model as inception_model
from FID.FID import calculate_fretchet

# Needed to download datasets on sites without ssl/https
import ssl
ssl._create_default_https_context = ssl._create_unverified_context

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument('--dataset', required=True, help='cifar10 | lsun | mnist |imagenet | folder | lfw | fake')
    parser.add_argument('--dataroot', required=False, help='path to dataset')
    parser.add_argument('--workers', type=int, help='number of data loading workers', default=2)
    parser.add_argument('--batchSize', type=int, default=64, help='input batch size')
    parser.add_argument('--imageSize', type=int, default=64, help='the height / width of the input image to network')
    parser.add_argument('--ngf', type=int, default=64)
    parser.add_argument('--niter', type=int, default=25, help='number of epochs to train for')
    parser.add_argument('--lr', type=float, default=0.0002, help='learning rate, default=0.0002')
    parser.add_argument('--beta1', type=float, default=0.5, help='beta1 for adam. default=0.5')
    parser.add_argument('--cuda', action='store_true', help='enables cuda')
    parser.add_argument('--dry-run', action='store_true', help='check a single training cycle works')
    parser.add_argument('--ngpu', type=int, default=1, help='number of GPUs to use')
    parser.add_argument('--netG', default='', help="path to netG (to continue training)")
    parser.add_argument('--outf', default='.', help='folder to output images and model checkpoints')
    parser.add_argument('--manualSeed', type=int, help='manual seed')
    parser.add_argument('--classes', default='bedroom', help='comma separated list of classes for the lsun data set')

    opt = parser.parse_args()
    print(opt)

    try:
        os.makedirs(opt.outf)
    except OSError:
        pass

    if opt.manualSeed is None:
        opt.manualSeed = random.randint(1, 10000)
    print("Random Seed: ", opt.manualSeed)
    random.seed(opt.manualSeed)
    torch.manual_seed(opt.manualSeed)

    cudnn.benchmark = True

    if torch.cuda.is_available() and not opt.cuda:
        print("WARNING: You have a CUDA device, so you should probably run with --cuda")

    if opt.dataroot is None and str(opt.dataset).lower() != 'fake':
        raise ValueError("`dataroot` parameter is required for dataset \"%s\"" % opt.dataset)

    if opt.dataset in ['imagenet', 'folder', 'lfw']:
        # folder dataset
        dataset = dset.ImageFolder(root=opt.dataroot,
                                transform=transforms.Compose([
                                    transforms.Resize(opt.imageSize),
                                    transforms.CenterCrop(opt.imageSize),
                                    transforms.ToTensor(),
                                    transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)),
                                ]))
        nc=3
    elif opt.dataset == 'lsun':
        classes = [ c + '_train' for c in opt.classes.split(',')]
        dataset = dset.LSUN(root=opt.dataroot, classes=classes,
                            transform=transforms.Compose([
                                transforms.Resize(opt.imageSize),
                                transforms.CenterCrop(opt.imageSize),
                                transforms.ToTensor(),
                                transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)),
                            ]))
        nc=3
    elif opt.dataset == 'cifar10':
        dataset = dset.CIFAR10(root=opt.dataroot, download=True,
                            transform=transforms.Compose([
                                transforms.Resize(opt.imageSize),
                                transforms.ToTensor(),
                                transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)),
                            ]))
        nc=3

    elif opt.dataset == 'mnist':
            dataset = dset.MNIST(root=opt.dataroot, download=True,
                            transform=transforms.Compose([
                                transforms.Resize(opt.imageSize),
                                transforms.RandomHorizontalFlip(),
                                transforms.RandomRotation(30, interpolation=transforms.InterpolationMode.BILINEAR),
                                transforms.ToTensor(),
                                transforms.Normalize((0.5,), (0.5,)),
                            ]))
            nc=1

    elif opt.dataset == 'fake':
        dataset = dset.FakeData(image_size=(3, opt.imageSize, opt.imageSize),
                                transform=transforms.ToTensor())
        nc=3

    assert dataset
    dataloader = torch.utils.data.DataLoader(dataset, batch_size=opt.batchSize,
                                            shuffle=True, num_workers=int(opt.workers))

    device = torch.device("cuda:0" if opt.cuda else "cpu")
    ngpu = int(opt.ngpu)
    ngf = int(opt.ngf)
    z_res = 4

    # custom weights initialization called on netG and netD
    def weights_init(m):
        classname = m.__class__.__name__
        if classname.find('Conv') != -1:
            torch.nn.init.normal_(m.weight, 0.0, 0.02)
        elif classname.find('BatchNorm') != -1:
            torch.nn.init.normal_(m.weight, 1.0, 0.02)
            torch.nn.init.zeros_(m.bias)

    class Generator(nn.Module):
        def __init__(self):
            super(Generator, self).__init__()
            self.main = nn.Sequential(
                # nn.Linear(z_res**2, z_res**2),
                # nn.Linear(z_res**2, z_res**2),

                nn.Unflatten(1, (z_res**2, 1, 1)),

                # input is Z, going into a convolution
                nn.ConvTranspose2d(     z_res**2, ngf * 8, 4, 1, 0, bias=False),
                nn.BatchNorm2d(ngf * 8),
                nn.ReLU(True),
                # state size. (ngf*8) x 4 x 4
                nn.ConvTranspose2d(ngf * 8, ngf * 4, 4, 2, 1, bias=False),
                nn.BatchNorm2d(ngf * 4),
                nn.ReLU(True),
                # state size. (ngf*4) x 8 x 8
                nn.ConvTranspose2d(ngf * 4, ngf * 2, 4, 2, 1, bias=False),
                nn.BatchNorm2d(ngf * 2),
                nn.ReLU(True),
                # state size. (ngf*2) x 16 x 16
                nn.ConvTranspose2d(ngf * 2,     ngf, 4, 2, 1, bias=False),
                nn.BatchNorm2d(ngf),
                nn.ReLU(True),
                # state size. (ngf) x 32 x 32
                nn.ConvTranspose2d(    ngf,      nc, 4, 2, 1, bias=False),
                nn.Tanh()
                # state size. (nc) x 64 x 64
            )

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

    netG = Generator().to(device)
    netG.apply(weights_init)
    if opt.netG != '':
        netG.load_state_dict(torch.load(opt.netG))
    # print(netG)
    print("# of parameters in G:", sum(p.numel() for p in netG.parameters() if p.requires_grad))

    inception_model = inception_model.to(device)

    criterion = nn.L1Loss()

    fixed_noise = torch.randn(opt.batchSize, z_res**2, device=device)
    real_label = 1
    fake_label = 0

    # setup optimizer
    optimizerG = optim.Adam(netG.parameters(), lr=opt.lr, betas=(opt.beta1, 0.999))

    if opt.dry_run:
        opt.niter = 1

    r = torch.randperm(z_res**2)
    r2 = torch.randperm((z_res**2)**2)
    rand = torch.rand([z_res**2])

    for epoch in range(opt.niter):
        for i, data in enumerate(dataloader, 0):
            input = data[0].to(device)
            # input = ein.reduce(input, "b c (h i) (w j) -> b (h w)", "mean", i=opt.imageSize//z_res, j=opt.imageSize//z_res) # Avg pool to 8x8 then to z

            # # NOTE: Maybe shuffle here?
            # input = input[:,r]

            netG.zero_grad()
            # output = netG(input)

            with torch.no_grad():
                t = input.flatten(1)[:, r2]
                t = ein.reduce(t, "b (n i) -> b n", "mean", i=z_res**2)
                t = t.argsort(1)
                t = rand[t]

            output = netG(t)
            errG = criterion(output, input)
            errG.backward()
            optimizerG.step()

            if i % 100 == 0:
                print('[%d/%d][%d/%d] Loss_G: %.4f '
                    % (epoch, opt.niter, i, len(dataloader), errG.item()))
                vutils.save_image(data[0],
                        '%s/real_samples.png' % opt.outf,
                        normalize=True)
                with torch.no_grad():
                    fake = netG(fixed_noise)
                vutils.save_image(fake.detach(),
                        '%s/fake_samples_epoch_%03d_%03d.png' % (opt.outf, epoch, i),
                        normalize=True)

            if opt.dry_run:
                break
        # # Save FID
        # with torch.no_grad():
        #     if real_cpu.shape[1] == 1:
        #         real_cpu = real_cpu.expand(-1, 3, -1, -1)
        #         fake = fake.expand(-1, 3, -1, -1)
        #     fid = calculate_fretchet(real_cpu, fake, inception_model)
        # with open(f"{opt.outf}/fid.txt", "a+") as file:
        #     file.write(f"{epoch}, {i}, {round(time.time())}, {fid}\n")

        # do checkpointing
        torch.save(netG.state_dict(), '%s/netG_epoch_%d.pth' % (opt.outf, epoch))


from matplotlib import pyplot as plt
import numpy as np

datos = np.loadtxt("Copia_de_pulso_eco_tanque.csv",usecols=(1,2),skiprows=5,delimiter=',')

h = datos[:,0]

x = datos[:,1]

def correlacion(h,x):

    #Arreglo de salida de la correlacion
    rc = np.zeros(h.size + x.size - 1 )

    #Señal enviada con zeros al inicio y al final
    cx = np.insert(x,0,np.zeros(h.size - 1)) #zeros al inicio
    cx = np.insert(cx,cx.size,np.zeros(h.size - 1))#zeros al final

    #Ciclos for para calculo de valores
    for n in np.arange(rc.size):
        for j in np.arange(h.size):
            idcx = j + n
            rc[n]= rc[n] + h[j] * cx[idcx]

    return rc

result = np.correlate(x,h,'full')
print(result)
print(len(result))

#result = np.array(correlacion(h, x))

#Graficando informacion
fig = plt.figure(dpi=128, figsize=(10,6))
plt.plot(result, c= 'red')

plt.show()


import turtle
import pandas

screen = turtle.Screen()
screen.title("U.S. States Game")
image = "blank_states_img.gif"
screen.addshape(image)
turtle.shape(image)

text = turtle.Turtle()
text.hideturtle()
text.penup()

data = pandas.read_csv("50_states.csv")
states_list = data["state"].to_list()
x_list = data["x"].to_list()
y_list = data["y"].to_list()

game_continue = True

count = 0

while game_continue:
    answer_state = screen.textinput(title=f"Guess the State {count}/50", prompt="What's another state's name?").title()

    if answer_state == "Exit":
        break
    if answer_state in states_list:
        count += 1
        index = states_list.index(answer_state)
        text.goto(x_list[index], y_list[index])
        text.write(answer_state)
        states_list.remove(answer_state)

    if count == 50:
        game_continue = False

states_data_dict = pandas.DataFrame(states_list)

states_data_dict.to_csv("States_To_Learn.csv")

turtle.mainloop()


#store the encodings and names of all criminals in encoding.txt

import pickle

from set_mongo import criminal_records,candidate_records

def store():
    print("enter into store function")
    knownEncodings=[]
    knownNames=[]

    #get all criminal records from mongodb collection
    results=criminal_records.find({})
    for result in results:
      knownEncodings.append(result["encodings"])
      knownNames.append(result["name"])

    #using pickle to write data in binary mode.
    print("[INFO] serializing encodings...")
    data = {"encodings": knownEncodings, "names": knownNames}
    f = open("encoding.txt", "wb")
    f.write(pickle.dumps(data))
    f.close()

    print("encodings written to file")


"""
Definition of TreeNode:
class TreeNode:
    def __init__(self, val):
        self.val = val
        self.left, self.right = None, None
"""

class Solution:
    """
    @param root: the root of binary tree
    @return: the root of the maximum average of subtree
    """
    targetNode, targetAverage = None, 0

    def findSubtree2(self, root):
        # write your code here
        self.helper(root)
        return self.targetNode

    def helper(self, node):
        # return (sum, size)
        if not node:
            return (0, 0)

        # divide
        left_sum, left_size = self.helper(node.left)
        right_sum, right_size = self.helper(node.right)

        # conquer
        sum = left_sum + right_sum + node.val
        size = left_size + right_size + 1
        if not self.targetNode or self.targetAverage < sum * 1.0 / size:
            self.targetNode = node
            self.targetAverage = sum * 1.0 / size
        return sum, size

Company/Amazon/OA_2/6. Subtree Maximum average node/learning_solution.py


#!/usr/bin/env python3
# coding: utf-8

"""
Extract all subtitles streams of a given movie or directory of movies
[!] ffmpeg must be installed and in your $PATH
ex: extract_subs.py /path/to/movies/
"""

import os
import re
import argparse
from pathlib import Path
from queue import Queue
from collections import namedtuple
from shlex import quote
from utils import av, common, logger

LOGGER: logger.Logger

SubtitlesStreamInfo = namedtuple('SubtitlesStreamInfo', ['id', 'infos', 'extension', 'title'])

def get_subs_streams(infos: str) -> str:
    """Parse `ffmpeg -i` output to grab only subtitles streams"""
    maps = {
        'ssa': '.ass',
        'ass': '.ass',
        'subrip': '.srt',
        'pgs': '.pgs'
    }

    def sanitize_type(x: str) -> str:
        """clean extension"""
        return maps[x] if x in maps else x

    streams = re.findall(r'Stream #0:(\d+).*?Subtitle:\s*((\w*)\s*?.*?)\r?\n(?:\s*Metadata:\s*\r?\n\s*title\s*:\s*(.*?)\r?\n)?', infos)
    return [SubtitlesStreamInfo(int(x[0]), x[1].strip(), sanitize_type(x[2].replace(",", "").strip()), x[3].strip()) for x in streams]

def extract_subtitles(p_queue: Queue):
    """Extract thread"""
    while p_queue.empty() is False:
        infile: Path = p_queue.get()
        infos = av.get_file_infos(infile)
        streams = get_subs_streams(infos)
        for sub_stream in streams:
            outfile = f'{str(infile)}.{sub_stream.id}{sub_stream.extension}'
            cmd = f'ffmpeg -i {quote(str(infile))} -v quiet -map 0:{sub_stream.id} -c copy {quote(outfile)}'
            LOGGER.log(f"{common.COLOR_WHITE}[+] Extracting track {sub_stream.id} from {common.COLOR_YELLOW}{infile} with {common.COLOR_PURPLE}{cmd}{common.COLOR_WHITE}")
            os.system(cmd)
        p_queue.task_done()

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("input", type=Path, help="Path to directory or single video file")
    parser.add_argument("-v", "--verbose", dest="verbose", action="store_true", help="Verbose mode")
    args = parser.parse_args()
    LOGGER = logger.Logger(args.verbose)

    # Sanity checks
    common.ensure_exist(["ffmpeg"])
    if args.input.exists() is None:
        common.abort(parser.format_help())

    # Get a list of files
    files = common.list_directory(args.input.resolve())
    queue = common.as_queue(files)

    # Extract
    common.parallel(extract_subtitles, (queue,))


from django.shortcuts import render, get_object_or_404
from django.contrib.auth.decorators import login_required
from django.contrib.admin.views.decorators import staff_member_required
from django.core.paginator import Paginator
from django.db.models import Q
from django.utils.safestring import mark_safe
from django.http import HttpResponse
import datetime
import markdown
from .forms import AvailableTimeForm
from .models import AvailableTime, Event
from .utils import NUM_PERIODS, TIME_OPTIONS

# Create your views here.
def events(request):
    query = Q(date__gte=datetime.date.today()) | Q(date__isnull=True)
    events = Event.objects.filter(query).all()
    #print(Event.objects.all()[0])
    paginator = Paginator(events, 10)
    page_number = request.GET.get('page')
    if page_number is None:
        page_number = 1
    page_obj = paginator.get_page(page_number)
    return render(request, "times/events.html", {'page_obj': page_obj})

@login_required(login_url="/accounts/login")
def eventform(request, eventid):
    event = get_object_or_404(Event, id=eventid)
    form = AvailableTimeForm()
    errors = None
    success = False
    description = mark_safe(markdown.markdown(event.description))
    if request.method == "POST":
        avail = AvailableTimeForm(request.POST)
        if avail.is_valid():
            AvailableTime.objects.filter(user=request.user, event=event).delete()
            for t in avail.cleaned_data['times']:
                AvailableTime(user=request.user, time=t, event=event).save()
            form = AvailableTimeForm(initial={'times': avail.cleaned_data["times"]})
            success = True
        else:
            errors = True
            times = list(map(lambda x: x.time, AvailableTime.objects.filter(user=request.user, event=event)))
            form = AvailableTimeForm(initial={'times': times})
            # form needs to be populated with original values (run queries)
    else:
        times = list(map(lambda x: x.time, AvailableTime.objects.filter(user=request.user, event=event)))
        form = AvailableTimeForm(initial={'times': times})
        pass
    return render(request, "times/eventform.html", {'form': form,
                    'errors': errors, 'success': success, 'event': event, 'description': description})

@staff_member_required(login_url="/accounts/login")
def viewtimes(request, eventid):
    event = get_object_or_404(Event, id=eventid)
    times = list(filter(lambda x : len(x[1]) != 0, [
        (
            (period, TIME_OPTIONS[period-1]),
            AvailableTime.objects.filter(event=event, time=str(period)).all()
        )
        for period in range(1, NUM_PERIODS+1)
    ]))
    return render(request, 'times/viewtimes.html', {'times': times, 'event': event,})


from tensorflow.keras import layers
from tensorflow.keras.models import Model

def build_discriminator(inputs):
    """Build a Discriminator Model
    Stack of LeakyReLU-Conv2D to discriminate real from fake.
    The network does not converge with BN so it is not used here
    unlike in [1] or original paper.
    Arguments:
        inputs (Layer): Input layer of the discriminator (the image)
    Returns:
        discriminator (Model): Discriminator Model
    """
    kernel_size = 5
    layer_filters = [32, 64, 128, 256]

    x = inputs
    for filters in layer_filters:
        # first 3 convolution layers use strides = 2
        # last one uses strides = 1
        if filters == layer_filters[-1]:
            strides = 1
        else:
            strides = 2
        x = layers.LeakyReLU(alpha=0.2)(x)
        x = layers.Conv2D(filters=filters,
                   kernel_size=kernel_size,
                   strides=strides,
                   padding='same')(x)

    x = layers.Flatten()(x)
    x = layers.Dense(1)(x)
    x = layers.Activation('sigmoid')(x)
    discriminator = Model(inputs, x, name='discriminator')
    return discriminator


"""
utility functions to preprocess the dataset
"""

from scipy.io import loadmat
from datetime import datetime

import os
import time

from keras import Input, Model
from keras.applications import InceptionResNetV2
from keras.layers import Conv2D, Flatten, Dense, BatchNormalization, Reshape, concatenate, LeakyReLU, Lambda, \
    K, Activation, UpSampling2D, Dropout
from keras.callbacks import TensorBoard
from keras.optimizers import Adam
from keras.utils import to_categorical
from keras_preprocessing import image

import matplotlib.pyplot as plt
import numpy as np
import tensorflow as tf
from tqdm import tqdm

def load_data(wiki_dir, dataset='wiki'):
    # load the wiki.mat in the meta
    meta = loadmat(os.path.join(wiki_dir, "{}.mat".format(dataset)))

    # load the list of all files
    full_path = meta[dataset][0, 0]["full_path"][0]

    # list of matlab serial date numbers for the corresponding photo in the list
    dob = meta[dataset][0, 0]["dob"][0]

    # list of years when photo was taken
    photo_taken = meta[dataset][0, 0]["photo_taken"][0]

    # calculate age for all dobs
    age = [calculate_age(photo_taken[i], dob[i]) for i in range(len(dob))]

    # create a list of tuples containing a pair of an image path and age
    imgs = []
    age_list = []

    for i, img_path in enumerate(full_path):
        imgs.append(img_path[0])
        age_list.append(age[i])

    # return a list of all images and their respective age
    return imgs, age_list

# calculate the age of the person from the serial date number
# and the year the photo was taken
def calculate_age(taken, dob):
    birth = datetime.fromordinal(max(int(dob) - 366, 1))

    # assume the photo was taken in the middle of the year
    if birth.month < 7:
        return taken - birth.year
    else:
        return taken - birth.year - 1

# convert age numerical value to the age categogy
def age_to_category(age_list):
    age_list1 = []

    for age in age_list:
        if 0 < age <= 18:
            age_category = 0
        elif 18 < age <= 29:
            age_category = 1
        elif 29 < age <= 39:
            age_category = 2
        elif 39 < age <= 49:
            age_category = 3
        elif 49 < age <= 59:
            age_category = 4
        elif age >= 60:
            age_category = 5

        age_list1.append(age_category)
    return age_list1

# load images from data directory
def load_images(data_dir, image_paths, image_shape):
    images = None
    # pbar = tqdm(total=len(image_paths))

    print("[INFO] processing images...")

    for i, image_path in enumerate(tqdm(image_paths)):
        # print("[INFO] processing image {}/{}".format(i+1, len(image_paths)))
        try:
            # Load image
            loaded_image = image.load_img(os.path.join(data_dir, image_path), target_size=image_shape)

            # Convert PIL image to numpy ndarray
            loaded_image = image.img_to_array(loaded_image)

            # Add another dimension (Add batch dimension)
            loaded_image = np.expand_dims(loaded_image, axis=0)

            # Concatenate all images into one tensor
            if images is None:
                images = loaded_image
            else:
                images = np.concatenate([images, loaded_image], axis=0)

        except Exception as e:
            print("Error:", i, e)

    return images

# calculate euclidean distance loss
def euclidean_distance_loss(y_true, y_pred):
    return K.sqrt(K.sum(K.square(y_pred - y_true), axis=-1))

# write loss to tensorboard
def write_log(callback, name, value, batch_no):
    summary = tf.Summary()
    summary_value = summary.value.add()
    summary_value.simple_value = value
    summary_value.tag = name
    callback.writer.add_summary(summary, batch_no)
    callback.writer.flush()

# save an rgb image
def save_rgb_image(img, path):
    fig = plt.figure()
    ax = fig.add_subplot(1, 1, 1)
    ax.imshow(img)
    ax.axis("off")
    ax.set_title("Image")

    plt.savefig(path)
    plt.close()

# resize the image
def build_image_resizer():
    input_layer = Input(shape=(64, 64, 3))

    resized_images = Lambda(lambda x: K.resize_images(x, height_factor=3, width_factor=3,
                                                      data_format='channels_last'))(input_layer)

    model = Model(inputs=[input_layer], outputs=[resized_images])
    return model


from __future__ import annotations

import datetime
from datetime import timedelta
import pendulum
import pandas as pd
import numpy as np

from airflow import DAG
from airflow.decorators import task
from airflow.operators.empty import EmptyOperator
from airflow.operators.trigger_dagrun import TriggerDagRunOperator

from airflow.models import DagModel

from typing import Iterable

import json

#Permite saber la posicion de creación de un operador dado su nombre

# Info del excel
FILE_ID = '1NsPnYiHwqVLBHR8QwOXaXEj1WakJ_kko3MDg2_4U2ds'
SHEET_ID = '559945068'

URL = f'https://docs.google.com/spreadsheets/d/{FILE_ID}/export?format=xlsx&gid={SHEET_ID}'

#Info del ejecuta
info_ejecuta = pd.read_excel(URL,header=None,usecols=[0,1]).replace(np.nan,'').transpose()

header = info_ejecuta.iloc[0]
info_ejecuta.columns= header
info_ejecuta=info_ejecuta[1:]

tags_json= '{'+f'"tags": [{info_ejecuta["Tags"].to_string(index=False)}]'+'}'

tag_dict = json.loads(tags_json)
tag_list = tag_dict['tags']
tag_list.append(info_ejecuta["Grupo"].to_string(index=False))
tag_list.append(info_ejecuta["Unidad De Negocio O Transversales"].to_string(index=False))
tag_list.append(info_ejecuta["Área De Negocio O Transversales"].to_string(index=False))

#Lee el excel
#Cambia NaN a Null, ya que los NaN no son válidos en el typo json de la tabla serialized_dags
ctl_dags = pd.read_excel(URL,usecols=[3,4,5]).replace(np.nan,'')
ctl_dags = ctl_dags[ctl_dags["DAG"]!='']

#Si el dag anterior está vació por default se asigna el operador de inicio
ctl_dags["DAG Anterior"] = ctl_dags["DAG Anterior"].replace('','Inicio')

#Si el dag siguiente está vació por default se asigna el operador de fin
ctl_dags["DAG Siguiente"] = ctl_dags["DAG Siguiente"].replace('','Fin')

#Se guarda la información con el nombre de DAG como índice
params: Iterable[dict] = ctl_dags.set_index('DAG', drop=False).to_dict('records')

if info_ejecuta["Activo"][1]==True:
    with DAG(
            info_ejecuta["Ejecuta"][1],
            schedule=info_ejecuta["Schedule"][1],
            start_date=pendulum.from_format(f'{info_ejecuta["Fecha Inicio"][1]}','YYYY-MM-DD HH:mm:ss', tz="America/Mazatlan"),
            catchup=False,
            dagrun_timeout=datetime.timedelta(minutes=4),
            default_args={'owner':info_ejecuta['Owner'][1],
                            'retries':1,
                            'retry_delay':timedelta(minutes=0)},
            description= "Ejecuta una serie de dags",
            tags=tag_list

    ) as dag:

        Inicio = EmptyOperator(
                        task_id="Inicio",
                        trigger_rule="all_success",
                    )

        Fin = EmptyOperator(
                        task_id="Fin",
                        trigger_rule="all_success",
                    )

        ops_list=[]

        op_info= ("Inicio",0)
        ops_list.append(op_info)

        op_info= ("Fin",1)
        ops_list.append(op_info)

        ops=[]

        ops.append(Inicio)

        ops.append(Fin)

        i=2

        for param in params:
            op_info= (param["DAG"],i)
            ops_list.append(op_info)
            op= TriggerDagRunOperator(
                        task_id=param["DAG"],
                        trigger_dag_id=param["DAG"],
                        trigger_rule="all_success",
                        wait_for_completion=True,
                        poke_interval= 30,
                        dag=dag
                    )
            ops.append(op)
            i=i+1

        df_dags_posiciones =  pd.DataFrame.from_records(data=ops_list,columns=["DAG","Posicion"]).replace(np.nan,'')

        #Se guarda la información con el nombre de DAG como índice
        dags_posiciones: Iterable[dict] = df_dags_posiciones.set_index('DAG', drop=False).to_dict('index')

        for param in params:
            ops[dags_posiciones[param["DAG Anterior"]]["Posicion"]]>>ops[dags_posiciones[param["DAG"]]["Posicion"]]>>ops[dags_posiciones[param["DAG Siguiente"]]["Posicion"]]


"""
link: https://leetcode.com/problems/container-with-most-water/description/

You are given an integer array height of length n. There are n vertical lines drawn such that the two endpoints of
the ith line are (i, 0) and (i, height[i]).

Find two lines that together with the x-axis form a container, such that the container contains the most water.

Return the maximum amount of water a container can store.

"""

def mostWater(height):
    ans, left, right = 0, 0, len(height) - 1

    while left < right:
        if height[left] <= height[right]:
            res = height[left] * (right - left)
            left+=1
        else:
            res = height[right] * (right - left)
            right -=1

        if res > ans: ans = res
    return ans

height = [1,8,6,2,5,4,8,3,7]
res = mostWater(height)
print(f"Most water contained is {res}")


def solution(data):
    colours = {'red': 12, 'blue': 14, 'green': 13}
    game = 1
    sum = 0
    with open(data, 'r') as file:
        for line in file.readlines():
            idx = line.index(':')
            sets = line.strip()[idx + 1:].split(';')
            print(sets)

            for s in sets:
                cubes = s.strip().split(',')
                possible = True
                for cube in cubes:
                    tokens = cube.strip().split(' ')
                    print(tokens)
                    if int(tokens[0].strip()) > colours[tokens[1].strip()]:
                        possible = False
                        break
                if not possible:
                    break
            if possible:
                sum += game
            game += 1
    return sum

def solution2(data):
    colours = {'red': 0, 'blue': 0, 'green': 0}
    game = 1
    powers = {}
    with open(data, 'r') as file:
        for line in file.readlines():
            idx = line.index(':')
            sets = line.strip()[idx + 1:].split(';')
            # print(sets)

            for s in sets:
                cubes = s.strip().split(',')
                for cube in cubes:
                    tokens = cube.strip().split(' ')
                    # print(tokens)
                    colours[tokens[1].strip()] = max(int(tokens[0].strip()), colours[tokens[1].strip()])
            power = 1
            print(colours)
            for val in colours.values():
                # print(val)
                power *= val
                # print(power)
            powers[game] = power
            game += 1
            colours = {'red': 0, 'blue': 0, 'green': 0}
    return sum(powers.values())

print(solution('./data/sample2.txt'))
print(solution('./data/test2.txt'))

# print(solution2('./data/sample2.txt'))
# print(solution2('./data/test2.txt'))


# subst X: "D:\Technische Informatica\2020-2021\Project GTM\Python"

"""
Voor het eerste bedrijfsproject in de minor heeft GTM gevraagd of wij een systeem kunnen bouwen die trays met zonnecellen en een excelsheet accepteert en dat omzet naar gesorteerde trays met ieder een bepaalde klasse cellen. De robot zal initieel verbinding maken met de TCP server van de python pc en reageren op elk bericht dat de pc stuurt.
Gedurende het programma zal de robot vanuit de rustpositie wachten tot de pc uit de invoercamera beeld heeft ontvangen en de robot vertelt waar de ongesorteerde cellen liggen. De robot pakt dan een voor een elke ongesorteerde cel op en verplaatst deze boven de qrcamera. De robot zal de pc een bericht sturen dat deze op locatie is.
De pc zal het serienummer laten scannen door de qrcamera en koppelen aan deze cel in de eerste foto. Vervolgens wordt de klasse opgezocht in de excelsheet en stuurt de pc de klasse naar de robot. De robot verplaatst de cel dan naar de uitvoertray met cellen van die klasse. De robot verplaatst zich dan weer naar de rustpositie.
Mocht een uitvoertray vol zitten, laat de robot dit via de pc weten en stopt met verdergaan totdat hij expliciet te horen krijgt dat de uitvoertray is verwijderd. Dit gaat via de hmi. Vervolgens plaatst de robot een lege tray op de geleegde plek en vervolgt hij zijn programma.
Mocht de invoertray leeg zijn, dan vertelt de pc niet welke cel de robot moet pakken, maar dat de tray leeg is en vervangen moet worden. De robot verplaatst dan de lege tray en gaat terug naar de rustpositie. De robot laat vervolgens de pc vertellen waar de volgende cellen liggen en gaat deze een na een af.
"""

import re                               # Regular expressions
import os                               # File path functions, for exists and remove functions
import sys                              # System variables, like error values
import cv2                              # Opencv, for image extraction
import time                             # To measure time intervals
import socket                           # To connect to all devices with the TCP protocol
import numpy as np                      # Numpy is used for opencv image definition and alteration
from ftplib import FTP                  # FTP protocol to download images from the cameras
from queue import SimpleQueue           # Simple queue data type for storing the cell photos
from collections import namedtuple      # Datatype for easy access to device properties
from openpyxl import load_workbook      # Function to import Excel sheets
from openpyxl import cell as xlcell     # Compare and extract Excel cell properties

# Documentation for openpyxl: https://openpyxl.readthedocs.io/en/stable/
# Documentation for opencv:   https://docs.opencv.org/master/

# Path to Excel sheet and a dict for its contents (where (k, v) is (sid, grade))
xlsxPath = "80518_Measurement Data_Lot XXX.xlsx"
excelData = {}

# Socket properties
s_size = 255                # Can receive up to 255 bytes
s_ipv4 = socket.AF_INET     # Use ipv4 configuration
s_tcp = socket.SOCK_STREAM  # Use TCP configuration

# Other variables
timeout = 10                # Seconds
lastRefresh = time.time()   # Timestamp of last refresh
lastPickupInstruction = ""  # Last instruction sent to the robot to pickup a cell/tray
photos = SimpleQueue()      # Store the photos of ungraded cells in a queue

#####################
# HMI message class #
#####################

# HMI Message object for easy read/write access.
class HMImessage:
    """All fields in a HMImessage object retain their values
    // air [0, 1]: turn air pressure on/off [out]
    // light [0, 1]: turn led strip on/off [out]
    // excel [0, 1, 2, 3]: reserved [inout]
    // grade [7-10, 100]: the grade of the cell that has just been classified [inout]
    // outputTray [7-10, 100]: when that output tray needs replacement [inout]
    // trays [0, 1-6]: start signal, the amount of trays stacked on the input pile [in]
    // halt [0, 1]: whether the user asked for a soft stop via the HMI [in]
    // status [0, 1, 2]: either not started, started or finished [inout]
    // conn... [0, 1]: whether the connections with these devices are still live [out]
    """
    def __init__(self):
        self.air, self.light, self.excel, self.grade = 0, 0, 0, 100
        self.outputTray, self.trays, self.halt, self.status = 100, 0, 0, 0
        self.connRobot, self.connQRcam, self.connINcam = 0, 0, 0

    # Decodes and stores the received message
    def fromString(self, msg):
        (self.air, self.light, self.excel, self.grade, self.outputTray, self.trays, self.halt,
            self.status, self.connRobot, self.connQRcam, self.connINcam) = [ord(i) for i in msg]

    # Concatenate the properties of this object into a string (without encoding)
    def toString(self):
        return (chr(self.air) + chr(self.light) + chr(self.excel) + chr(self.grade) +
            chr(self.outputTray) + chr(self.trays) + chr(self.halt) + chr(self.status) +
                chr(self.connRobot) + chr(self.connQRcam) + chr(self.connINcam))

# Instantiate the class
HMImsg = HMImessage()

#################
# Counter class #
#################

class Counter:
    """Counter object that keeps track of the occupied output spaces"""
    def __init__(self):
        self.outputs = [1, 1, 1, 1]     # Index 0 refers to grade 7, index 3 to grade 10
        self.emptyHeight = 0
        self.inputHeight = 0

    # Increments the counter for the output tray of this grade and returns its value after incrementing
    def increment(self, grade):
        self.outputs[grade - 7] += 1
        return self.outputs[grade - 7]

    # Resets the counter for the output tray of this grade to 0
    def reset(self, grade):
        self.outputs[grade - 7] = 1

# Instantiate the class
counter = Counter()

#############
# Functions #
#############

def readExcel():
    """Read the Excel sheet and collect its data"""
    wb = load_workbook(filename = xlsxPath, data_only = True, read_only = True)
    ws = wb.active

    # Grab columns M, N and O (col M has grades, col O has serial numbers)
    rows = ws["M1:O500"]

    # Collect all serial numbers and their corresponding grades
    for row in rows:
        if type(row[0]) is not xlcell.read_only.EmptyCell and type(row[0].value) is int:
            grade = row[0].value
            sid = row[2].value
            excelData[sid] = grade
    wb.close()

def retrievePhoto():
    """FTP Retrieve photo function"""
    ftp = FTP(invoerCamera.ip, user="admin", timeout=3)
    with open("image.bmp", "wb") as imageBuffer:
        ftp.retrbinary("RETR image.bmp", imageBuffer.write)
        imageBuffer.close()
    ftp.quit()
    return cv2.imread("image.bmp")

def locateCells(img):
    """Opencv locate cells function"""
    kernel = np.ones((5, 5), np.uint8)
    result = []

    # Cut the image to isolate each cell
    cuts = [0]*12
    cuts[0] = img[165:279, :201]
    cuts[1] = img[165:279, 201:404]
    cuts[2] = img[165:279, 404:603]
    cuts[3] = img[165:279, 603:]
    cuts[4] = img[279:383, :201]
    cuts[5] = img[279:383, 201:404]
    cuts[6] = img[279:383, 404:603]
    cuts[7] = img[279:383, 603:]
    cuts[8] = img[383:497, :201]
    cuts[9] = img[383:497, 201:404]
    cuts[10] = img[383:497, 404:603]
    cuts[11] = img[383:497, 603:]

    # Decide for every spot if it is occupied by a cell
    for i in range(12):
        org = cuts[i]
        img = cv2.cvtColor(org, cv2.COLOR_BGR2GRAY)                         # Grayscale
        img = cv2.threshold(img, 128, 255, cv2.THRESH_BINARY)[1]            # BW
        img = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel, iterations=2)   # Close holes
        if cv2.countNonZero(img) < 15000:   # If there are less than 15000 pixels in this cut
            photos.put(org)                 # Temporarily store this image, until we know its grade
            result.append(i + 1)            # Cell 0 has position 1, cell 11 has position 12, etc.
    return result

def SavePhoto(sid):
    """Save the photo of this cell with its serial number as file name"""
    cv2.imwrite("Photos\\" + sid + ".png", photos.get(block=False))

def connect(device):
    """TCP Connect function"""
    device.socket.connect((device.ip, device.port))
    print(device.name, " connected at ", device.ip, ":", device.port, sep="")

def login(device):
    """TCP Login function"""
    if "User" not in device.socket.recv(s_size).decode():   # Welcome to In-Sight(tm)  7200C Session 0
        device.socket.recv(s_size)                          # User:
    device.socket.send(b"admin\r\n")
    device.socket.recv(s_size)                              # Password:
    device.socket.send(b"\r\n")
    device.socket.recv(s_size)                              # User Logged In
    print(device.name, "login success")

def disconnect(device):
    """TCP Disconnect function"""
    device.socket.close()

def handleError(device):
    """TCP Handle Errors function updates the connection info to display on the HMI and disconnects all devices"""
    if device is not None: print("TCP Error for device", device.name, sys.exc_info()[0])
    if device != robot: send(robot, "disconnect"); disconnect(robot)
    if device != qrCamera: disconnect(qrCamera)
    if device != invoerCamera: disconnect(invoerCamera)
    if device != plc:
        if device == robot: HMImsg.connRobot = 0
        elif device == qrCamera: HMImsg.connQRcam = 0
        elif device == invoerCamera: HMImsg.connINcam = 0
        if device is not None: send(plc, HMImsg.toString())
        time.sleep(1)
        disconnect(plc)
    exit(-1)

def send(device, msg, verbal = True):
    """TCP Send function"""
    try:
        if verbal: print("PC > ", device.name, ":\t", msg.encode(), sep="")
        device.socket.send(msg.encode())
    except:
        handleError(device)

def receive(device, index = None, verbal = True):
    """TCP Receive function. If index is provided, the received data will be split"""
    if device == plc:
        flush(plc)
    try:
        data = device.socket.recv(s_size)
        if verbal: print(device.name, " > PC:\t", data, sep="")
        data = data.decode()
        if index is not None:
            data = data.split("\r\n")[index]
        return data
    except:
        handleError(device)

def flush(device):
    """TCP flush function that empties its receive buffer to ensure actual data (e.g. HMI keeps sending data)"""
    try:
        while len(device.socket.recv(s_size)) == s_size:
            pass
    except:
        handleError(device)

def refresh():
    """TCP Refresh function"""
    global lastRefresh
    while True:
        # While within refresh timeout
        while time.time() - lastRefresh < timeout:
            HMImsg.fromString(receive(plc, verbal = False))

            # Return when the program is running, not halted, without full output trays and without excel errors
            if HMImsg.status and not HMImsg.halt and HMImsg.outputTray == 100 and not HMImsg.excel:
                return

            # If the user chooses to terminate the program due to an Excel error
            if HMImsg.excel == 4:
                robotReturnCell()

            # Print some debug messages while waiting for the user to acknowledge via the HMI
            if HMImsg.status != 1: print("Waiting for start acknowledge by user via HMI...")
            if HMImsg.halt != 0: print("Program halted. Waiting for user acknowledge via HMI...")
            if HMImsg.outputTray != 100: print("Waiting for user to acknowledge output tray removal via HMI...")
            if HMImsg.excel == 1: print("Waiting for user to acknowledge new excel sheet upload via HMI...")
            if HMImsg.excel == 2: print("Waiting for user response to serial number not being in excel sheet via HMI...")
            if HMImsg.excel == 3: print("Waiting for user response to unreadable data matrix via HMI...")

            time.sleep(0.5)

        # Refresh all other connections
        print("Refreshing devices")
        lastRefresh = time.time()
        send(robot, "refresh", verbal = False)
        receive(robot, verbal = False)
        send(qrCamera, "refresh\r\n", verbal = False)
        receive(qrCamera, verbal = False)
        send(invoerCamera, "refresh\r\n", verbal = False)
        receive(invoerCamera, verbal = False)

def robotReturnCell():
    """This function instructs the robot to return the cell to its last location and stops the program"""
    send(robot, lastPickupInstruction)
    receive(robot)                  # Robot has reached cell location

    HMImsg.fromString(receive(plc)) # Don't overwrite with cached data. No refresh, since halt (e.g.) corrupts robot movement
    HMImsg.air = 0
    send(plc, HMImsg.toString())    # Instruct the PLC to enable the vacuum generator
    time.sleep(0.1)                 # Give the PLC time to process

    send(robot, "neutral")          # Instruct the robot return to its neutral position
    receive(robot)                  # Robot has reached its destination

    handleError(None)

def robotMsg(instruction, heightGrade, celIndex):
    """Robot Message function for easy message creation using convention 'X-YY-ZZ'"""
    global lastPickupInstruction
    heightGrade = str(heightGrade) if heightGrade > 9 else "0" + str(heightGrade)
    celIndex = str(celIndex) if celIndex > 9 else "0" + str(celIndex)
    res = instruction + "-" + heightGrade + "-" + celIndex
    if res[0] == "I": lastPickupInstruction = res
    return res

def newSocket():
    """Function to create a new socket"""
    s = socket.socket(s_ipv4, s_tcp)
    s.settimeout(timeout)
    return s

#####################
# Device properties #
#####################

# Device object to enable named fields: camera.socket instead of camera[2]
Device = namedtuple("Device", "name, ip, port, socket")

# Properties of the connecting devices (Name, IP, Port, Client socket)
# The PLC and cameras always immediately respond, since their socket handling is non-blocking. The robot will not
plc = Device("PLC", "192.168.0.2", 2000, newSocket())  # Connect to the HMI via the PLC
robot = Device("Robot", "192.168.0.1", 10000, newSocket())
qrCamera = Device("QRcam", "192.168.0.10", 10000, newSocket())
invoerCamera = Device("INcam", "192.168.0.11", 10000, newSocket())

###################
# Connect devices #
###################

# Setup a client socket for the PLC and connect
print("Connecting to PLC...", end="\r", flush=True)
connect(plc)

# Setup a client socket for the Robot and connect
print("Connecting to Robot...", end="\r", flush=True)
connect(robot)
HMImsg.connRobot = 1
send(plc, HMImsg.toString(), verbal = False)

# Setup a client socket for the QR Camera, connect and login
print("Connecting to QR Camera...", end="\r", flush=True)
connect(qrCamera)
login(qrCamera)
HMImsg.connQRcam = 1
send(plc, HMImsg.toString(), verbal = False)

# Setup a client socket for the Invoer Camera, connect and login
print("Connecting to Invoer Camera...", end="\r", flush=True)
connect(invoerCamera)
login(invoerCamera)
HMImsg.connINcam = 1
send(plc, HMImsg.toString(), verbal = False)

####################################################
# Read Excel sheet and communicate errors with HMI #
####################################################

# Since refresh also blocks program flow if status is 0, temporarily change it to 8
HMImsg.status = 8
send(plc, HMImsg.toString(), verbal = False)

# Read Excel sheet and put the data in excelData
while True:
    try:
        print("Attempting to read Excelsheet...", end="\r")
        readExcel()
        print("Excel sheet has been read successfully")
        break
    except FileNotFoundError:
        HMImsg.excel = 1
        send(plc, HMImsg.toString())    # Show HMI warning and wait for response
        time.sleep(0.5)                 # Give the PLC time to process
        refresh()

# Reset the mocked status code
HMImsg.status = 0
send(plc, HMImsg.toString(), verbal = False)
time.sleep(1)                           # Give the PLC time to process

################
# Main program #
################

# Connections are established, so we wait for the user to start the program on the HMI
while HMImsg.status != 1:
    refresh()

# At this point, we received the amount of input trays from the HMI
HMImsg.fromString(receive(plc))
time.sleep(0.1)                         # Give the PLC time to process
counter.inputHeight = HMImsg.trays      # Start the size of the inputHeight at HMImsg.trays
send(robot, "neutral")                  # We then Instruct the robot to move to its neutral position
receive(robot)                          # Robot has reached its neutral position

# Repeat this loop while there are input trays left
while counter.inputHeight:
    refresh()                           # Revalidate all tcp connections
    send(invoerCamera, "sw8\r\n")       # Trigger a photo
    receive(invoerCamera, 0)            # Acknowledge
    time.sleep(0.3)
    locs = locateCells(retrievePhoto()) # Use FTP to retrieve the photo and locate all cells

    # If there are no cells in this tray, move it to the empty tray stack
    if locs == []:
        refresh()
        send(robot, robotMsg("I", counter.inputHeight, 0))
        counter.inputHeight -= 1        # Robot picks up the input tray
        receive(robot)                  # Robot has reached its destination

        HMImsg.fromString(receive(plc)) # Don't overwrite with cached data. No refresh, since halt (e.g.) corrupts robot movement
        HMImsg.air = 1
        send(plc, HMImsg.toString())    # Instruct the PLC to enable the vacuum generator
        time.sleep(0.1)                 # Give the PLC time to process

        refresh()
        counter.emptyHeight += 1        # Robot places tray on the stack at the new height
        send(robot, robotMsg("S", counter.emptyHeight, 0))
        receive(robot)                  # Robot has reached its destination

        HMImsg.fromString(receive(plc)) # Don't overwrite with cached data. No refresh, since halt (e.g.) corrupts robot movement
        HMImsg.air = 0
        send(plc, HMImsg.toString())    # Instruct the PLC to disable the vacuum generator
        time.sleep(0.1)                 # Give the PLC time to process

        refresh()
        send(robot, "neutral")          # Instruct the robot return to its neutral position
        receive(robot)                  # Robot has reached its neutral position

    # Pick up all of the cells on the locations found in the photo
    for i in locs:
        refresh()
        send(robot, robotMsg("I", counter.inputHeight, i))
        receive(robot)                  # Robot has reached cell location

        HMImsg.fromString(receive(plc)) # Don't overwrite with cached data. No refresh, since halt (e.g.) corrupts robot movement
        HMImsg.air = 1
        send(plc, HMImsg.toString())    # Instruct the PLC to enable the vacuum generator
        time.sleep(0.1)                 # Give the PLC time to process

        refresh()
        send(robot, "scan")             # Instruct the robot to move the cell to the QR camera for a scan
        receive(robot)                  # Robot has reached its destination

        HMImsg.fromString(receive(plc)) # Don't overwrite with cached data. No refresh, since halt (e.g.) corrupts robot movement
        HMImsg.light = 1
        send(plc, HMImsg.toString())    # Instruct the PLC to enable the lighting for the QR camera
        time.sleep(0.1)                 # Give the PLC time to process

        # Read the serial number (data matrix), retry ten times, if needed
        for _ in range(10):
            refresh()
            send(qrCamera, "sw8\r\n")       # Trigger a photo
            receive(qrCamera, 0)            # Acknowledge
            time.sleep(0.3)                 # Give the camera time to process the data matrix
            send(qrCamera, "gvb002\r\n")
            sid = receive(qrCamera, 1)      # Get the serial number from the camera

            # If this sid matches the format of "xxxxx xxxx xx" where all x are digits, get the grade
            if re.search("\d{5} \d{4} \d{2}", sid):
                try:
                    grade = excelData[sid]
                    SavePhoto(sid)
                    break
                # If the sid is not present in the Excel sheet
                except KeyError:
                    print("Excel sheet does not contain <", sid, ">", sep="")
                    refresh()
                    HMImsg.excel = 2
                    HMImsg.light = 0
                    send(plc, HMImsg.toString())    # Instruct the PLC to disable the lights and to show the error message
                    time.sleep(0.1)                 # Give the PLC time to process

                    refresh()                       # Wait for user to accept message on hmi
                    robotReturnCell()               # Return

        # If this else clause is executed, it means that the data matrix is not recognized after 10 retries
        else:
            print("Data matrix cannot be recognized")
            SavePhoto(time.strftime("unreadable cell on %Y-%m-%d %X GMT", time.gmtime()))

            refresh()
            HMImsg.excel = 3
            HMImsg.light = 0
            send(plc, HMImsg.toString())    # Instruct the PLC to disable the lights and to show the error message
            time.sleep(0.1)                 # Give the PLC time to process

            refresh()                       # Wait for user choice (if not quit, then move cell to spare box)
            send(robot, "box")              # Instruct the robot to place the cell there
            receive(robot)                  # Robot has reached its destination

            HMImsg.fromString(receive(plc)) # Don't overwrite with cached data. No refresh, since halt (e.g.) corrupts robot movement
            HMImsg.air = 0
            send(plc, HMImsg.toString())    # Instruct the PLC to disable the vacuum generator
            time.sleep(0.1)                 # Give the PLC time to process

            refresh()
            send(robot, "neutral")          # Instruct the robot return to its neutral position
            receive(robot)                  # Robot has reached its destination
            continue

        refresh()
        HMImsg.grade = grade            # Store this grade in the HMImsg object
        HMImsg.light = 0                # Also, the light can be turned off again
        send(plc, HMImsg.toString())    # Instruct the PLC to enable the lighting for the QR camera
        time.sleep(0.1)                 # Give the PLC time to process

        refresh()
        send(robot, "neutral")          # Instruct the robot return to its neutral position
        receive(robot)                  # Robot has reached its destination

        refresh()
        cell = counter.increment(grade) - 1     # Increment output tray cell counter and store free spot
        send(robot, robotMsg("Q", grade, cell)) # Instruct the robot to place the cell there
        receive(robot)                  # Robot has reached its destination

        HMImsg.fromString(receive(plc)) # Don't overwrite with cached data. No refresh, since halt (e.g.) corrupts robot movement
        HMImsg.air = 0
        send(plc, HMImsg.toString())    # Instruct the PLC to disable the vacuum generator
        time.sleep(0.1)                 # Give the PLC time to process

        refresh()
        send(robot, "neutral")          # Instruct the robot return to its neutral position
        receive(robot)                  # Robot has reached its neutral position

        refresh()
        HMImsg.grade = 100
        send(plc, HMImsg.toString())    # Instruct the PLC to remove the grade value from the HMI
        time.sleep(0.1)                 # Give the PLC time to process

        # If output tray is full, the 12th cell has just been placed in that output tray
        if cell == 12:
            refresh()
            counter.reset(grade)        # The user will physically remove the tray, reset counter to 0
            HMImsg.outputTray = grade
            send(plc, HMImsg.toString())    # Instruct the HMI to execute the tray replacement procedure
            time.sleep(0.1)                 # Give the PLC time to process

# Program finished
HMImsg.status = 4
send(plc, HMImsg.toString())
time.sleep(1)                       # Give the PLC time to process

######################
# Disconnect devices #
######################

send(robot, "disconnect")
disconnect(robot)
disconnect(plc)
disconnect(qrCamera)
disconnect(invoerCamera)


# populate.py
from mongoengine import connect, Document, EmbeddedDocument
from mongoengine.fields import EmbeddedDocumentField, StringField, ListField, IntField, DateTimeField
from datetime import datetime

connect('senderos', host='mongo')

class Comentarios(EmbeddedDocument):
    contenido = StringField(required=True)
    autor = StringField(max_length=120, required=True)
    fecha = DateTimeField(default=datetime.now())

class Excursion(Document):
    nombre = StringField(max_length=120, required=True)
    descripcion = StringField(required=True)
    likes = IntField(default=0)
    visitas = IntField(default=0)
    tags = ListField(StringField(max_length=20))
    duracion = StringField(max_length=20)
    comentarios = ListField(EmbeddedDocumentField(Comentarios))
    fotos = ListField(StringField(required=True))

comentarios = [
    {
        "contenido": 'Primer comentario',
        "autor": 'Yo'
    },
    {
        "contenido": 'Otro comentario',
        "autor": 'Pepito'
    }
]

excursion = Excursion(nombre="Alhama, la ciudad de los tajos", descripcion="Famosa por sus baños árabes explotados desde tiempos romanos,\
 la ciudad de Al-hamman (Alhama), importante plaza del reino nazarí, es un símbolo de la reconquista cristiana del Reino de Granada. \
 Su historia, marcada por la presencia musulmana, se encuentra indefectiblemente enmarcada en el paraje natural de los Tajos, apareciendo,\
  tal como escribiese el poeta Teóphile Gautier, “colgada sobre una enorme roca o pico, como un nido de águila”.", duracion="2,5h",
                      comentarios=comentarios, fotos=["img/alhama1.jpg", "img/alhama2.jpg"])
excursion.save()

excursion = Excursion(nombre="Barranco de La Fonfría y pino de La Señora", descripcion="El Parque Natural de la Sierra de Baza ofrece un \
refrescante recorrido por el arroyo de Baúl que permite contemplar uno de los mayores ejemplares de pino laricio de la provincia de Granada. \
La ruta circular comienza en el Centro de Visitantes de Narváez, ascendiendo en parte por el GR-7 y tomando un desvío en la cabecera del arroyo del Baúl.",
                      comentarios=comentarios, fotos=["img/fonfria1.jpg", "img/fonfria2.jpg", "img/fonfria3.jpg", "img/fonfria4.jpg", "img/fonfria5.jpg"], duracion="7,5h")
excursion.save()

excursion = Excursion(nombre="Acequia del Toril y dólmenes de Alicún", descripcion="Este corta y sencilla ruta permite contemplar los dólmenes \
situados junto al Balneario de Alicún de las Torres y la espectacular y extraña pared mineral que ha formado una acequia de aguas termales a través\
 de los siglos. La presencia de aguas termales a una temperatura de 35 grados, así como su posición estratégica entre dos valles, ha favorecido la\
     creación de asentamientos humanos desde la Prehistoria en este lugar. Prueba de ello es  la presencia de restos del Paleolítico Superior,\
          Neolítico, Edad del Cobre y Cultura del Argar.", comentarios=comentarios,
                      fotos=["img/acequia-alicun1.jpg", "img/acequia-alicun2.jpg", "img/acequia-alicun3.jpg", "img/acequia-alicun4.jpg", "img/acequia-alicun5.jpg", ], duracion="1h")
excursion.save()

excursion = Excursion(nombre="Prueba", descripcion="ruta 1", likes=1,
                      tags=['fácil'], comentarios=comentarios, fotos=["img/foto1.png"])
excursion.save()  # Para escribir en la BD

for excursion in Excursion.objects():
    print(excursion)


#!/usr/bin/env python3

from relative_paths import AUTHENTICATION_PATH, EXPORTS_PATH, PLAYLISTS_PATH
import requests
import json
import sys

usage = "Usage ./do_export.py <y/n for saved tracks> <y/n for saved albums> <y/n for playlists>"

if len(sys.argv) != 4:
    sys.exit(usage)

if sys.argv[1] == "y" or sys.argv[1] == "Y":
    do_export_saved_tracks = True
elif sys.argv[1] == "n" or sys.argv[1] == "N":
    do_export_saved_tracks = False
else:
    sys.exit(usage)

if sys.argv[2] == "y" or sys.argv[2] == "Y":
    do_export_saved_albums = True
elif sys.argv[2] == "n" or sys.argv[2] == "N":
    do_export_saved_albums = False
else:
    sys.exit(usage)

if sys.argv[3] == "y" or sys.argv[3] == "Y":
    do_export_playlists = True
elif sys.argv[3] == "n" or sys.argv[3] == "N":
    do_export_playlists = False
else:
    sys.exit(usage)

with open(AUTHENTICATION_PATH + "access_token.txt") as file:
    access_token = file.readline()

base_url = "https://api.spotify.com/v1"
per_get = 50

headers = {
    "Authorization" : "Bearer " + access_token,
    "Content-Type" : "application/json"
}

width = 30
lotta_spaces = " " * width + "\r"

def write_raw(raw, output):
    output.write(json.dumps(raw) + "\n\n")

def ms_to_min_and_sec(ms):
    mi, se = divmod(ms / 1000, 60)
    ro_se = int(round(se))
    return str(int(mi)) + ":" + ("0" if ro_se < 10 else "") + str(ro_se)

def strip_and_write_track(track, output, from_playlist):
    row = "\n" + track["track"]["name"]
    first = True
    for artist in track["track"]["artists"]:
        if first:
            row += ","
            first = False
        else:
            row += " "
        row += artist["name"]
    row += "," + track["track"]["album"]["name"]
    row += "," + track["added_at"]
    if from_playlist:
        first = True
        row += "," + track["added_by"]["id"]
        row += "," + ("yes" if track["is_local"] else "no")
    row += "," + ms_to_min_and_sec(track["track"]["duration_ms"])
    row += "," + ("yes" if track["track"]["explicit"] else "no")
    output.write(row)

def strip_and_write_album(album, output):
    row = "\n" + album["album"]["name"]
    first = True
    for artist in album["album"]["artists"]:
        if first:
            row += ","
            first = False
        else:
            row += " "
        row += artist["name"]
    row += "," + album["added_at"]
    output.write(row)

# Could really do a much job writing these methods and reduce redundant code, but who cares
def strip_and_write_playlist_metadata(playlist, output):
    row = "\n" + playlist["name"]
    row += "," + playlist["owner"]["id"]
    row += "," + ("yes" if playlist["collaborative"] else "no")
    row += "," + ("public" if playlist["public"] else "private")
    row += ',"' + playlist["description"] + '"' # high probability of " in description
    output.write(row)

def export_saved_tracks():
    total = requests.get(base_url + "/me/tracks", headers = headers).json()["total"]
    print("Number of saved tracks: " + str(total))
    st_raw_file = open(EXPORTS_PATH + "saved_tracks_raw.txt", "w")
    st_file = open(EXPORTS_PATH + "saved_tracks.csv", "w")
    st_file.write("name,artist(s),album,added_at,duration,explicit")

    for offset in range(0, total, per_get):
        payload = {
            "limit" : per_get,
            "offset" : offset
        }

        for saved_track in requests.get(base_url + "/me/tracks", headers = headers, params = payload).json()["items"]:
            print(lotta_spaces, end = "")
            print("Exporting " + saved_track["track"]["name"][:width - 10] + "\r", end = "")
            write_raw(saved_track, st_raw_file)
            strip_and_write_track(saved_track, st_file, False)

    st_raw_file.close()
    st_file.close()

def export_saved_albums():
    total = requests.get(base_url + "/me/albums", headers = headers).json()["total"]
    print("Number of saved albums: " + str(total))
    sa_raw_file = open(EXPORTS_PATH + "saved_albums_raw.txt", "w")
    sa_file = open(EXPORTS_PATH + "saved_albums.csv", "w")
    sa_file.write("name,artist(s),added_at")

    for offset in range(0, total, per_get):
        payload = {
            "limit" : per_get,
            "offset" : offset
        }

        for album in requests.get(base_url + "/me/albums", headers = headers, params = payload).json()["items"]:
            print(lotta_spaces, end = "")
            print("Exporting " + album["album"]["name"][:width - 10] + "\r", end = "")
            write_raw(album, sa_raw_file)
            strip_and_write_album(album, sa_file)

    sa_raw_file.close()
    sa_file.close()

def export_playlists():
    total = requests.get(base_url + "/me/playlists", headers = headers).json()["total"]
    print("Number of playlists: " + str(total))
    ap_raw_file = open(EXPORTS_PATH + "all_playlists_raw.txt", "w")
    ap_file = open(EXPORTS_PATH + "all_playlists.csv", "w")
    ap_file.write("name,owner,collaborative,public,description")
    # handling local files here correctly?

    for offset in range(0, total, per_get):
        payload = {
            "limit" : per_get,
            "offset" : offset
        }

        for playlist_link in requests.get(base_url + "/me/playlists", headers = headers, params = payload).json()["items"]:
            playlist = requests.get(base_url + "/playlists/" + playlist_link["id"], headers = headers, params = payload).json()
            write_raw(playlist, ap_raw_file)
            strip_and_write_playlist_metadata(playlist, ap_file)

            name = playlist["name"]
            print(lotta_spaces, end = "")
            print("Exporting " + name[:width - 10] + "\r", end = "")
            name = name.replace("/", "") # don't screw up directories

            p_raw_file = open(PLAYLISTS_PATH + name + "_raw.txt", "w")
            write_raw(playlist, p_raw_file)
            p_raw_file.close()

            p_file = open(PLAYLISTS_PATH + name + ".csv", "w")
            p_file.write("name,artist(s),album,added_at,added_by,is_local,duration,explicit")
            for track in playlist["tracks"]["items"]:
                strip_and_write_track(track, p_file, True)
            p_file.close()

    ap_raw_file.close()
    ap_file.close()

if do_export_saved_tracks:
    print("Starting saved tracks export")
    export_saved_tracks()
    print(lotta_spaces, end = "")
    print("Exported saved tracks\n")

if do_export_saved_albums:
    print("Starting saved albums export")
    export_saved_albums()
    print(lotta_spaces, end = "")
    print("Exported saved albums\n")

if do_export_playlists:
    print("Starting playlists export")
    export_playlists()
    print(lotta_spaces, end = "")
    print("Exported playlists")


from __future__ import print_function
from __future__ import division
from __future__ import absolute_import

import unittest

from mock import patch

from api import resource_name_converters as rnc
from api.v3 import projects_servicer
from api.v3 import converters
from api.v3.api_proto import projects_pb2
from api.v3.api_proto import project_objects_pb2
from api.v3.api_proto import issue_objects_pb2
from framework import exceptions
from framework import monorailcontext
from framework import permissions
from testing import fake
from services import service_manager

class ProjectsServicerTest(unittest.TestCase):

  def setUp(self):
    self.cnxn = fake.MonorailConnection()
    self.services = service_manager.Services(
        features=fake.FeaturesService(),
        issue=fake.IssueService(),
        project=fake.ProjectService(),
        config=fake.ConfigService(),
        user=fake.UserService(),
        template=fake.TemplateService(),
        usergroup=fake.UserGroupService())
    self.projects_svcr = projects_servicer.ProjectsServicer(
        self.services, make_rate_limiter=False)

    self.user_1 = self.services.user.TestAddUser('user_111@example.com', 111)

    self.project_1 = self.services.project.TestAddProject(
        'proj', project_id=789)
    self.template_1 = self.services.template.TestAddIssueTemplateDef(
        123, 789, 'template_1_name', content='foo bar', summary='foo')
    self.project_1_resource_name = 'projects/proj'
    self.converter = None

  def CallWrapped(self, wrapped_handler, mc, *args, **kwargs):
    self.converter = converters.Converter(mc, self.services)
    self.projects_svcr.converter = self.converter
    return wrapped_handler.wrapped(self.projects_svcr, mc, *args, **kwargs)

  def testListIssueTemplates(self):
    """We can list a project's IssueTemplates."""
    request = projects_pb2.ListIssueTemplatesRequest(
        parent=self.project_1_resource_name)
    mc = monorailcontext.MonorailContext(
        self.services, cnxn=self.cnxn, requester=self.user_1.email)
    response = self.CallWrapped(
        self.projects_svcr.ListIssueTemplates, mc, request)

    expected_issue = issue_objects_pb2.Issue(
        summary=self.template_1.summary,
        state=issue_objects_pb2.IssueContentState.Value('ACTIVE'),
        status=issue_objects_pb2.Issue.StatusValue(
            status=self.template_1.status,
            derivation=issue_objects_pb2.Derivation.Value('EXPLICIT')))
    expected_template = project_objects_pb2.IssueTemplate(
        name='projects/{}/templates/{}'.format(
            self.project_1.project_name, self.template_1.name),
        display_name=self.template_1.name,
        issue=expected_issue,
        summary_must_be_edited=False,
        template_privacy=project_objects_pb2.IssueTemplate.TemplatePrivacy
        .Value('PUBLIC'),
        default_owner=project_objects_pb2.IssueTemplate.DefaultOwner.Value(
            'DEFAULT_OWNER_UNSPECIFIED'),
        component_required=False)

    self.assertEqual(
        response,
        projects_pb2.ListIssueTemplatesResponse(templates=[expected_template]))

  @patch('project.project_helpers.GetThumbnailUrl')
  def testListProjects(self, mock_GetThumbnailUrl):
    """We can list Projects."""
    mock_GetThumbnailUrl.return_value = 'xyz'

    request = projects_pb2.ListProjectsRequest()

    mc = monorailcontext.MonorailContext(
        self.services, cnxn=self.cnxn, requester=self.user_1.email)
    response = self.CallWrapped(self.projects_svcr.ListProjects, mc, request)

    expected_project = project_objects_pb2.Project(
        name=self.project_1_resource_name,
        display_name=self.project_1.project_name,
        summary=self.project_1.summary,
        thumbnail_url='xyz')

    self.assertEqual(
        response,
        projects_pb2.ListProjectsResponse(projects=[expected_project]))


import json

import google.protobuf.json_format
from fds.protobuf.stach.v2.RowOrganized_pb2 import RowOrganizedPackage

from fds.protobuf.stach.extensions.v2.RowOrganizedStachExtension import RowOrganizedStachExtension

class RowStachExtensionBuilder:

    def set_package(self, pkg):
        """
        Sets the package to the stach extension builder. The input package can be instance of Package, or
        string or object representation of the Package.

        :param pkg: Package object in string or object form.
        :return: builder instance
        """
        if (type(pkg) is RowOrganizedPackage):
            self.package = pkg
        elif (type(pkg) is str):
            package = RowOrganizedPackage()
            google.protobuf.json_format.Parse(pkg, package, ignore_unknown_fields=True, descriptor_pool=None)
            self.package = package
        else:
            pkg = json.dumps(pkg)
            package = RowOrganizedPackage()
            google.protobuf.json_format.Parse(pkg, package, ignore_unknown_fields=True, descriptor_pool=None)
            self.package = package

        return self

    def add_table(self, id, table):
        """
        Adds the table to the builder for conversion.

        :param id: id of the table.
        :param table: the inuput table object to be converted.
        :return: builder instance
        """
        if (type(table) is RowOrganizedPackage.Table):
            # we are checking if self.package is available, so that we can add the given table to the existing package.
            # if self.package is not available, we do create a package and add table to it.
            if (not hasattr(self, "package")):
                self.package = RowOrganizedPackage()
            empty_table = self.package.tables.get_or_create(id)
            empty_table.CopyFrom(table)
            return self
        elif (type(table) is str):
            pass
        else:
            table = json.dumps(table)

        tableInstance = RowOrganizedPackage.Table()
        google.protobuf.json_format.Parse(table, tableInstance, ignore_unknown_fields=True, descriptor_pool=None)

        # we are checking if self.package is available, so that we can add the given table to the existing package.
        # if self.package is not available, we do create a package and add table to it.
        if (not hasattr(self, "package")):
            self.package = RowOrganizedPackage()
        empty_table = self.package.tables.get_or_create(id)
        empty_table.CopyFrom(tableInstance)

        return self

    def get_package(self):
        """
        Returns the RowOrganizedPackage object set for the builder

        :return: RowOrganizedPackage instance
        """
        if (not hasattr(self, "package")):
            return None
        return self.package

    def build(self):
        """
        Builds and returns the instance of ColumnOrganizedStachExtension class

        """
        return RowOrganizedStachExtension(self.package)


from ._btc import btc_new
from ._eth import eth_new

def new(currency:str)->bool:
    """创建一个账户密码对

    Args:
        currency (str): 指定哪种货币

    Returns:
        success (bool): 是否创建成功
    """
    if currency == "btc":
        result = btc_new()
    elif currency == "eth":
        result = eth_new()
    else:
        print("未知的货币")
        return False
    for k, v in result.items():
        print(f"{k}:{v}")
    return True