# -*- coding: utf-8 -*-
# NOTES
# ALl mask related mathematics happens assuming (and only after conversion to) the mask image as a 2D array [... x ...]
# No channels=1 are used for the mask. Ofcourse while reading, it is read as [.. x .. x 1];

import os, cv2, pickle as pk, numpy as np
import params
from clustering import dominant_clusters

###########################################################################################################
def simply_erode_opencv(inp_mask, adj_labels_to_erode):
    mask = inp_mask.copy();
    kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))
    for label in adj_labels_to_erode:
        # print(label)
        # Pick the partial_mask
        partial_mask = np.zeros(mask.shape); partial_mask[mask==label] = 1;
        mask[mask==label] = 0;
        er_partial_mask = cv2.erode(partial_mask, kernel, iterations = 2);
        mask[er_partial_mask==1] = label;
    return mask;
def get_bw_mask(mask_path, k_gap_erode=4):
    ###############################################################
    # Collects all masks from the org folder and erodes any two
    # masks thata re close by.
    ###############################################################
    mask_files = os.listdir(mask_path);
    mask, partial_mask_label = [], 1;
    adj_labels_to_erode, k_gap = [], k_gap_erode;
    for mask_file in mask_files:
        partial_mask = cv2.imread(os.path.join(mask_path,mask_file), cv2.IMREAD_GRAYSCALE);
        partial_mask[partial_mask>0] = partial_mask_label;
        partial_mask_inds = np.where(partial_mask==partial_mask_label)
        try:
            mask+=partial_mask;
        except:
            mask = partial_mask;
        found_something_close_by = 0;
        for p in range(partial_mask_inds[0].shape[0]):
            row = partial_mask_inds[0][p]; col = partial_mask_inds[1][p];
            if row-k_gap>=0 and row+k_gap<partial_mask.shape[0] and col-k_gap>=0 and col+k_gap<partial_mask.shape[1]:
                window = mask[row-k_gap:row+k_gap, col-k_gap:col+k_gap];
                other_labels = window[(window>0) & (window!=partial_mask_label)]
                for label in other_labels:
                    if label not in adj_labels_to_erode:
                        #print(partial_mask_label, label, row, col);
                        adj_labels_to_erode.append(label);
                        found_something_close_by = 1;
        if found_something_close_by:
            #print(partial_mask_label);
            adj_labels_to_erode.append(partial_mask_label);
        # Continue adding more partial_masks
        partial_mask_label+=1;
    for ind, lab in enumerate(adj_labels_to_erode):
        adj_labels_to_erode[ind] = int(lab)
    # Simply erode these label clusters
    new_mask = simply_erode_opencv(mask, adj_labels_to_erode);
    # bw_mask =  cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY);
    bw_mask = new_mask.copy(); bw_mask[bw_mask>0] = 255;
    if len(adj_labels_to_erode)>0:
        print('These many masks were found closeby; Eroded Brutally!!', len(adj_labels_to_erode));
    return bw_mask
#############################################################################################################
def thisPatch(image, bw_mask, curr_row, curr_col, base_name, vertical_flip, horizontal_flip, rotation_90s, zoomIn):
    # Desired values
    row_length, col_length, channels = params.image_patch_rows, params.image_patch_cols, params.image_patch_channels;
    # make new images
    new_image = image[curr_row:curr_row+row_length,curr_col:curr_col+col_length,:channels].copy();
    new_mask = bw_mask[curr_row:curr_row+row_length,curr_col:curr_col+col_length].copy();
    new_name = base_name;
    # Random Operations
    if vertical_flip and np.random.uniform(0,1)>=0.5:
        new_image = np.flip(new_image,axis=0);
        new_mask = np.flip(new_mask,axis=0);
        new_name = new_name+'_vflip';
    if horizontal_flip and np.random.uniform(0,1)>=0.5:
        new_image = np.flip(new_image,axis=1);
        new_mask = np.flip(new_mask,axis=1);
        new_name = new_name+'_hflip';
    if rotation_90s and np.random.uniform(0,1)>=0.5 and new_image.shape[0]==new_image.shape[1]:
        # Using OpenCV, input must be SQUARE else bizzare results can be seen
        rows,cols,_ = new_image.shape
        M = cv2.getRotationMatrix2D((cols/2,rows/2),90*(np.random.randint(3)+1),1)
        new_image = cv2.warpAffine(new_image,M,(cols,rows))
        new_mask = cv2.warpAffine(new_mask,M,(cols,rows))
        new_name = new_name+'_r90';
    if zoomIn and np.random.uniform(0,1)>=0.5:
        # Up-Size the image and do rotation and capture 256*256 size
        new_image_big = cv2.resize(new_image, (2*new_image.shape[1], 2*new_image.shape[0]), interpolation = cv2.INTER_LINEAR)
        new_mask_big = cv2.resize(new_mask, (2*new_mask.shape[1], 2*new_mask.shape[0]), interpolation = cv2.INTER_LINEAR)
        start_row = np.random.randint(new_image_big.shape[0]-row_length)
        start_col = np.random.randint(new_image_big.shape[1]-col_length)
        new_image = new_image_big[start_row:start_row+row_length,start_col:start_col+col_length,:];
        new_mask = new_mask_big[start_row:start_row+row_length,start_col:start_col+col_length];
        new_name = new_name+'_zoomin';
    return new_image, new_mask, new_name
def extract_patches_and_save(item, image, bw_mask, vertical_flip, horizontal_flip, rotation_90s, zoomIn):
    # Desired values
    row_length, col_length = params.image_patch_rows, params.image_patch_cols;
    # Other Initializations
    extracted_images, extracted_masks, extracted_names = [], [], [];
    img_rows, img_cols, img_channels = image.shape;
    # raise Exception('Channels<Desired Channels') if(img_channels<channels) else print('Shapes of Input Read: ', image.shape, bw_mask.shape)
    # Generate
    curr_gen_count=1;
    curr_row = 0;
    while(curr_row+row_length<=img_rows):
        curr_col = 0;
        while(curr_col+col_length<=img_cols):
            base_name = str(item)+'_'+str(row_length)+'x'+str(col_length)+'_'+str(curr_gen_count);
            new_image, new_mask, new_gen_name = thisPatch(image, bw_mask, curr_row, curr_col, base_name, vertical_flip, horizontal_flip, rotation_90s, zoomIn);
            if (np.sum(new_mask==0)/(new_mask.shape[0]*new_mask.shape[1]))<params.max_non_mask_pixel_percent or len(extracted_names)<1:
                extracted_images.append(new_image); extracted_masks.append(new_mask); extracted_names.append(new_gen_name);
                curr_gen_count+=1;
            curr_col+=params.win_shift_cols;
        # Saving a last patch in the given set of fixed rows and varying col number
        if curr_col>0 and curr_col<img_cols and curr_col+col_length>img_cols and (img_cols-col_length)%params.win_shift_cols!=0: #Dont go to one of earlier indices
            curr_col = img_cols-col_length;
            base_name = str(item)+'_'+str(row_length)+'x'+str(col_length)+'_'+str(curr_gen_count);
            new_image, new_mask, new_gen_name = thisPatch(image, bw_mask, curr_row, curr_col, base_name, vertical_flip, horizontal_flip, rotation_90s, zoomIn);
            if (np.sum(new_mask==0)/(new_mask.shape[0]*new_mask.shape[1]))<params.max_non_mask_pixel_percent or len(extracted_names)<1:
                extracted_images.append(new_image); extracted_masks.append(new_mask); extracted_names.append(new_gen_name);
                curr_gen_count+=1;
            curr_col+=params.win_shift_cols;
        curr_row+=params.win_shift_rows;
    # Saving a last patch in the given set of varying row number and varying col number
    if curr_row>0 and curr_row<img_rows and curr_row+row_length>img_rows and (img_rows-row_length)%params.win_shift_rows!=0: #Dont go to one of earlier indices
        curr_row = img_rows-row_length;
        curr_col = 0;
        while(curr_col+col_length<=img_cols):
            base_name = str(item)+'_'+str(row_length)+'x'+str(col_length)+'_'+str(curr_gen_count);
            new_image, new_mask, new_gen_name = thisPatch(image, bw_mask, curr_row, curr_col, base_name, vertical_flip, horizontal_flip, rotation_90s, zoomIn);
            if (np.sum(new_mask==0)/(new_mask.shape[0]*new_mask.shape[1]))<params.max_non_mask_pixel_percent or len(extracted_names)<1:
                extracted_images.append(new_image); extracted_masks.append(new_mask); extracted_names.append(new_gen_name);
                curr_gen_count+=1;
            curr_col+=params.win_shift_cols;
        # Saving a last patch in the given set of fixed rows and varying col number
        if curr_col>0 and curr_col<img_cols and curr_col+col_length>img_cols and (img_cols-col_length)%params.win_shift_cols!=0: #Dont go to one of earlier indices
            curr_col = img_cols-col_length;
            base_name = str(item)+'_'+str(row_length)+'x'+str(col_length)+'_'+str(curr_gen_count);
            new_image, new_mask, new_gen_name = thisPatch(image, bw_mask, curr_row, curr_col, base_name, vertical_flip, horizontal_flip, rotation_90s, zoomIn);
            if (np.sum(new_mask==0)/(new_mask.shape[0]*new_mask.shape[1]))<params.max_non_mask_pixel_percent or len(extracted_names)<1:
                extracted_images.append(new_image); extracted_masks.append(new_mask); extracted_names.append(new_gen_name);
                curr_gen_count+=1;
            curr_col+=params.win_shift_cols;
    return extracted_images, extracted_masks, extracted_names
#############################################################################################################
def generate_train_data_with_augmentation(target_folder): # Patches with FLIPS, ROTATIONS, ZOOMIN
    # Sanity check for files of requirement
    with open(params.hsv_clustering_data,'rb') as openFile:
        hsv_clustering = pk.load(openFile);
        clt_model = hsv_clustering['clt']
        print("HSV Cluster Centers: ", np.array(hsv_clustering['cluster_centers_'], dtype='int'));
        del hsv_clustering;
    # Other initializations
    org_names, gen_names, gen_names_ind, gen_names_ind_cnt = [], [], [], []; #gen_names_individual
    for item in os.listdir(params.train_folder_org):
        # Get Paths & Load image,masks
        org_names+=[item]; print(len(org_names));
        image_org_path = os.path.join(params.train_folder_org,item+'/images');
        mask_org_path = os.path.join(params.train_folder_org,item+'/masks');
        image = cv2.imread(os.path.join(image_org_path,os.listdir(image_org_path)[0]));
        bw_mask = get_bw_mask(mask_org_path);
        # Know to which clustre this image belongs to!
        hsv_image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV);
        thisCenter, _, _ = dominant_clusters(hsv_image, n_clusters=1);
        centerMapped = clt_model.predict(thisCenter);
        n_iters = 1; vertical_flip=True; horizontal_flip=True; rotation_90s=True; zoomIn=False;
        if centerMapped==1 or centerMapped==3:
            n_iters = 4; zoomIn=True;
        for _ in range(n_iters):
            # Patches with FLIPS, ROTATIONS, ZOOMIN
            extracted_images, extracted_masks, extracted_names = extract_patches_and_save(item, image, bw_mask,
                                                                                vertical_flip, horizontal_flip, rotation_90s, zoomIn);
            # Write images to folder of interest
            print('No.of Files Generated: {}'.format(len(extracted_names)))
            for ind, name in enumerate(extracted_names):
                cv2.imwrite(os.path.join(target_folder, name+'.png'), extracted_images[ind]);
                cv2.imwrite(os.path.join(target_folder, name+'_mask.png'), extracted_masks[ind]);
            # Save data for future reference and proceed
            gen_names+=extracted_names;
            gen_names_ind+=[extracted_names];
            gen_names_ind_cnt+=[len(extracted_names)];
    with open(os.path.join(target_folder,'org_names.pickle'),'wb') as opfile:
        pk.dump(org_names, opfile); opfile.close();
    with open(os.path.join(target_folder,'gen_names.pickle'),'wb') as opfile:
        pk.dump(gen_names, opfile); opfile.close();
    print('Training Data generated success...');
    return org_names, gen_names, gen_names_ind, gen_names_ind_cnt
def generate_train_data_only_resize(target_folder): # Rotations+Patches
    org_names, gen_names = [], []; #gen_names_individual
    for item in os.listdir(params.train_folder_org):
        # Get Paths & Load image,masks
        org_names+=[item]; print(len(org_names));
        image_org_path = os.path.join(params.train_folder_org,item+'/images');
        mask_org_path = os.path.join(params.train_folder_org,item+'/masks');
        image = cv2.imread(os.path.join(image_org_path,os.listdir(image_org_path)[0]));
        bw_mask = get_bw_mask(mask_org_path);
        # Desired values
        row_length, col_length = params.image_patch_rows, params.image_patch_cols;
        # Resize to desired size
        image = cv2.resize(image, (col_length, row_length), interpolation = cv2.INTER_LINEAR);
        bw_mask = cv2.resize(bw_mask, (col_length, row_length), interpolation = cv2.INTER_LINEAR);
        for _ in range(2):
            # Do FLIPS, ROTATIONS, ZOOMIN
            new_image, new_mask, new_name = thisPatch(image, bw_mask, 0, 0, item);
            # Write images to folder of interest
            cv2.imwrite(os.path.join(target_folder, new_name+'.png'), new_image);
            cv2.imwrite(os.path.join(target_folder, new_name+'_mask.png'), new_mask);
            # Save data for future reference and proceed
            gen_names+=[new_name];
    with open(os.path.join(target_folder,'org_names.pickle'),'wb') as opfile:
        pk.dump(org_names, opfile); opfile.close();
    with open(os.path.join(target_folder,'gen_names.pickle'),'wb') as opfile:
        pk.dump(gen_names, opfile); opfile.close();
    print('Training Data generated success...');
    return org_names, gen_names
############################################################################################################
def load_train_list_with_augmentation(target_folder):
    with open(os.path.join(target_folder,'gen_names.pickle'),'rb') as opfile:
        tr_list = pk.load(opfile);
        opfile.close();
    return tr_list
def load_test_list(target_folder):
    with open(os.path.join(target_folder,'org_names.pickle'),'rb') as opfile:
        ts_list = pk.load(opfile);
        opfile.close();
    return ts_list
############################################################################################################
def generate_original_copies_train_data(source_folder, target_folder):
    org_names = [];
    for item in os.listdir(source_folder):
        org_names+=[item]; print(len(org_names));
        # Get Path and load image
        image_path = os.path.join(source_folder,item+'/images');
        image_file = os.listdir(image_path)[0];
        image = cv2.imread(os.path.join(image_path,image_file));
        cv2.imwrite(os.path.join(target_folder, item+'.png'), image);
    with open(os.path.join(target_folder,'org_names.pickle'),'wb') as opfile:
        pk.dump(org_names, opfile); opfile.close();
    print('Training Data generated success...');
    return org_names
def generate_original_copies_test_data(source_folder, target_folder):
    org_names = [];
    for item in os.listdir(source_folder):
        org_names+=[item]; print(len(org_names));
        # Get Path and load image
        image_path = os.path.join(source_folder,item+'/images');
        image_file = os.listdir(image_path)[0];
        image = cv2.imread(os.path.join(image_path,image_file));
        cv2.imwrite(os.path.join(target_folder, item+'.png'), image);
    with open(os.path.join(target_folder,'org_names.pickle'),'wb') as opfile:
        pk.dump(org_names, opfile); opfile.close();
    print('Training Data generated success...');
    return org_names
############################################################################################################
#from train_m3 import prep_image_to_unet
#def make_patches_and_predict(model, bgr_image, threshold_type='global', print_images=False): #'global','otsu','adap+otsu'
#    # Create patch->Predict->Save in Mask->Increment each_pixel_cnt for resp. patch
#    img_rows, img_cols, channels = bgr_image.shape;
#    row_length, col_length = params.image_patch_rows, params.image_patch_cols; # Desired values
#    cnt_matrix = np.zeros((bgr_image.shape[0],bgr_image.shape[1],1));
#    mask_matrix = np.zeros((bgr_image.shape[0],bgr_image.shape[1],1));
#    if(channels<3):
#        raise Exception('Channels<Desired Channels')
#    curr_gen_count =  1;
#    #Patches
#    curr_row = 0;
#    while(curr_row+row_length<=img_rows):
#        curr_col = 0;
#        while(curr_col+col_length<=img_cols):
#            # newImage and predict\
#            #new_bgr_image = bgr_image[curr_row:curr_row+row_length,curr_col:curr_col+col_length,:channels].copy();
#            new_bgr_image = bgr_image;
#            new_bgr_image, new_ycrcb_image = prep_image_to_unet(None, new_bgr_image);
#            new_bgr_image = np.expand_dims(new_bgr_image, axis=0);
#            new_ycrcb_image = np.expand_dims(new_ycrcb_image, axis=0)
#            pred_mask = model.predict([new_ycrcb_image,new_bgr_image])[0];
#            # save details
#            mask_matrix[curr_row:curr_row+row_length,curr_col:curr_col+col_length,:1]+= pred_mask;
#            cnt_matrix[curr_row:curr_row+row_length,curr_col:curr_col+col_length,:1]+= 1;
#            # Increment count and continue
#            curr_gen_count+=1;
#            curr_col+=params.win_shift_cols;
#        # Saving a last patch in the given set of fixed rows and varying col number
#        if curr_col>0 and curr_col<img_cols and curr_col+col_length>img_cols and (img_cols-col_length)%params.win_shift_cols!=0: #Dont go to one of earlier indices
#            curr_col = img_cols-col_length;
#            # newImage and predict\
#            new_bgr_image = bgr_image[curr_row:curr_row+row_length,curr_col:curr_col+col_length,:channels].copy();
#            new_bgr_image, new_ycrcb_image = prep_image_to_unet(None, new_bgr_image);
#            new_bgr_image = np.expand_dims(new_bgr_image, axis=0);
#            new_ycrcb_image = np.expand_dims(new_ycrcb_image, axis=0)
#            pred_mask = model.predict([new_ycrcb_image,new_bgr_image])[0];
#            # save details
#            mask_matrix[curr_row:curr_row+row_length,curr_col:curr_col+col_length,:1]+= pred_mask;
#            cnt_matrix[curr_row:curr_row+row_length,curr_col:curr_col+col_length,:1]+= 1;
#            # Increment count and continue
#            curr_gen_count+=1;
#        curr_row+=params.win_shift_rows;
#    # Saving a last patch in the given set of varying row number and varying col number
#    if curr_row>0 and curr_row<img_rows and curr_row+row_length>img_rows and (img_rows-row_length)%params.win_shift_rows!=0: #Dont go to one of earlier indices
#        curr_row = img_rows-row_length;
#        curr_col = 0;
#        while(curr_col+col_length<=img_cols):
#            # newImage and predict\
#            new_bgr_image = bgr_image[curr_row:curr_row+row_length,curr_col:curr_col+col_length,:channels].copy();
#            new_bgr_image, new_ycrcb_image = prep_image_to_unet(None, new_bgr_image);
#            new_bgr_image = np.expand_dims(new_bgr_image, axis=0);
#            new_ycrcb_image = np.expand_dims(new_ycrcb_image, axis=0)
#            pred_mask = model.predict([new_ycrcb_image,new_bgr_image])[0];
#            # save details
#            mask_matrix[curr_row:curr_row+row_length,curr_col:curr_col+col_length,:1]+= pred_mask;
#            cnt_matrix[curr_row:curr_row+row_length,curr_col:curr_col+col_length,:1]+= 1;
#            # Increment count and continue
#            curr_gen_count+=1;
#            curr_col+=params.win_shift_cols;
#        # Saving a last patch in the given set of fixed rows and varying col number
#        if curr_col>0 and curr_col<img_cols and curr_col+col_length>img_cols and (img_cols-col_length)%params.win_shift_cols!=0: #Dont go to one of earlier indices
#            curr_col = img_cols-col_length;
#            # newImage and predict\
#            new_bgr_image = bgr_image[curr_row:curr_row+row_length,curr_col:curr_col+col_length,:channels].copy();
#            new_bgr_image, new_ycrcb_image = prep_image_to_unet(None, new_bgr_image);
#            new_bgr_image = np.expand_dims(new_bgr_image, axis=0);
#            new_ycrcb_image = np.expand_dims(new_ycrcb_image, axis=0)
#            pred_mask = model.predict([new_ycrcb_image,new_bgr_image])[0];
#            # save details
#            mask_matrix[curr_row:curr_row+row_length,curr_col:curr_col+col_length,:1]+= pred_mask;
#            cnt_matrix[curr_row:curr_row+row_length,curr_col:curr_col+col_length,:1]+= 1;
#            # Increment count and continue
#            curr_gen_count+=1;
#    if np.min(cnt_matrix)==0: # Safe Check
#        raise Exception('At least one pixel is not in any of the patches! Use np.where() to find it.')
#    # Threshold the pixels
#    mask_matrix/=cnt_matrix; # Average ##### mask_matrix = (mask_matrix > 0.5).astype(np.uint8) ######
#    if threshold_type=='global':
#        temp = mask_matrix.copy();
#        pred_image_thres = 255*(temp > 0.5);
#        pred_image_thres = pred_image_thres.astype(np.uint8);
#    elif threshold_type=='otsu':
#        temp = mask_matrix.copy();
#        pred_image_255 = 255*temp;
#        pred_image_255_uint8 = pred_image_255.astype(np.uint8)
#        _ , pred_image_thres = cv2.threshold(pred_image_255_uint8, 127, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
#    elif threshold_type=='adap+otsu':
#        #OTSU
#        temp = mask_matrix.copy();
#        pred_image_255 = 255*temp;
#        pred_image_255_uint8 = pred_image_255.astype(np.uint8)
#        _ , pred_image_thres1 = cv2.threshold(pred_image_255_uint8, 127, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
#        # Adaptive Thresholding
#        temp = mask_matrix.copy();
#        pred_image_255 = 255*temp;
#        pred_image_255_uint8 = pred_image_255.astype(np.uint8)
#        pred_image_thres2 = cv2.adaptiveThreshold(pred_image_255_uint8, 255,
#                                                  adaptiveMethod=cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
#                                                  thresholdType=cv2.THRESH_BINARY, blockSize=13, C=0)
#        # Global Thresholding AND Adaptive Thresholding
#        pred_image_thres = np.logical_or(pred_image_thres1==255,pred_image_thres2==255);
#        pred_image_thres = pred_image_thres.astype(np.uint8)
#        pred_image_thres = 255*pred_image_thres;
#    else:
#        print('Required threshold_type unavailable!');
#    # Print thye images
#    if print_images:
#        cv2.imshow( "{0}".format('ThisImage'), bgr_image);
#        cv2.imshow( "{0}".format('ThisMask'), pred_image_thres);
#        cv2.waitKey(0);
#        cv2.destroyAllWindows();
#    return pred_image_thres #, mask_matrix

if __name__=="__main__":
    #generate_original_copies_train_data(params.train_folder_org, params.train_folder_gen);
    #generate_original_copies_test_data(params.test_folder_org, params.test_folder_gen);
    #generate_original_copies_test_data(params.test2_folder_org, params.test2_folder_gen);

    #org_names, gen_names, gen_names_ind, gen_names_ind_cnt = generate_train_data_with_augmentation(params.train_folder_gen_m3); #Uses global variable
    #org_names, gen_names = generate_train_data_only_resize(params.train_folder_gen_resize)

    #tr_list = load_train_list_with_augmentation(params.train_folder_gen);
    #ts_list = load_test_list(params.test_folder_gen)
    print('Execution Complete. Please check respective folders as mentioned in params.')


#!/usr/bin/env python

import os
import ADC0832
import multiLED
import RPi.GPIO as GPIO
import time
import math
from decimal import *

def init():
    GPIO.setmode(GPIO.BOARD)        # Numbers GPIOs by physical location
    ADC0832.setup()

    #PWM pin settings
    GPIO.setup(7, GPIO.OUT)
    GPIO.setup(11, GPIO.OUT)
    GPIO.setup(12, GPIO.OUT)

if __name__ == '__main__':
    init()
    try:
        light = 0.0
        p7 = GPIO.PWM(7, 25)
        p11 = GPIO.PWM(11, 50)
        p12 = GPIO.PWM(12, 75)

        p7.start(1)
        p11.start(1)
        p12.start(1)

        while True:
            dat = ADC0832.getResult()
            light = round((Decimal(dat)/255)*100, 2)
            os.system('clear')
            print("light(delez):", light)
            print("data:", dat)
            print("res:", dat*39)
            p7.ChangeDutyCycle(light)
            p11.ChangeDutyCycle(light)
            p12.ChangeDutyCycle(light)

            time.sleep(0.2)

    except KeyboardInterrupt:
        p7.stop()
        p11.stop()
        p12.stop()

        GPIO.cleanup()
        print("The end !")


from src.common.read_input import read_input

# bit_position is index from the left side of the number
def most_common_value(digits, bit_position):
    num_lines = len(digits)
    num_ones = sum(list(zip(*digits))[bit_position])
    return num_ones >= num_lines/2

def least_common_value(digits, bit_position):
    return not most_common_value(digits, bit_position)

def bits_to_decimal(bits):
    binary_str = ''.join(map(lambda bit: str(int(bit)), bits))
    decimal = int(binary_str, 2)
    return decimal

def calculate_rating(digits, bit_criteria):
    for bit_position in range(num_digits):
        digits = [number for number in digits
                  if number[bit_position] == int(bit_criteria(digits, bit_position))]
        if len(digits) == 1:
            break
    rating = bits_to_decimal(digits[0])
    return rating

input = read_input('input.txt', 2021, 3)

num_digits = len(input[0])
digits = [tuple(int(digit) for digit in line) for line in input]
oxygen_generator_rating = calculate_rating(digits, most_common_value)
co2_scrubber_rating = calculate_rating(digits, least_common_value)

print(oxygen_generator_rating * co2_scrubber_rating)


import os
from matplotlib.pyplot import imread
import random
import numpy as np

# set seed:
seed_value = 1
os.environ['PYTHONHASHSEED']=str(seed_value)
random.seed(seed_value)
np.random.seed(seed_value)

def getListOfFiles(dirName):
    # create a list of file and sub directories
    # names in the given directory
    listOfFile = os.listdir(dirName)
    allFiles = list()
    # Iterate over all the entries
    for entry in listOfFile:
        # Create full path
        fullPath = os.path.join(dirName, entry)
        # If entry is a directory then get the list of files in this directory
        if os.path.isdir(fullPath):
            allFiles = allFiles + getListOfFiles(fullPath)
        elif fullPath.endswith('.png'):
            allFiles.append(fullPath)
    return allFiles

def main(dir):
    all_files = getListOfFiles(dir)
    random.shuffle(all_files)
    n = len(all_files)
    data = []
    # sub sample 1/3 of the database
    for i in range(n//3):
        im = imread(all_files[i])[:,:,:3]
        data.append(im)
    return data


# https://leetcode.com/problems/number-of-1-bits/

class Solution:
    def hammingWeight(self, n: int) -> int:
        x = (bin(n)[2:])
        l = x.split("0")
        sum = 0
        for y in l:
            sum = sum+len(y)

        return sum


# =========================================================================
# Copyright (C) 2022. Huawei Technologies Co., Ltd. All rights reserved.
#
# 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 collections import OrderedDict
import io
import os
import logging
import json

class FeatureMap(object):
    def __init__(self, dataset_id, data_dir):
        self.data_dir = data_dir # must keep to be used in embedding layer for pretrained emb
        self.dataset_id = dataset_id
        self.num_fields = 0
        self.total_features = 0
        self.input_length = 0
        self.features = OrderedDict()
        self.labels = []
        self.column_index = dict()
        self.group_id = None
        self.default_emb_dim = None

    def load(self, json_file, params):
        logging.info("Load feature_map from json: " + json_file)
        with io.open(json_file, "r", encoding="utf-8") as fd:
            feature_map = json.load(fd) #, object_pairs_hook=OrderedDict
        if feature_map["dataset_id"] != self.dataset_id:
            raise RuntimeError("dataset_id={} does not match feature_map!".format(self.dataset_id))
        self.num_fields = feature_map["num_fields"]
        self.labels = feature_map.get("labels", [])
        self.total_features = feature_map.get("total_features", 0)
        self.input_length = feature_map.get("input_length", 0)
        self.group_id = feature_map.get("group_id", None)
        self.default_emb_dim = params.get("embedding_dim", None)
        self.features = OrderedDict((k, v) for x in feature_map["features"] for k, v in x.items())
        if params.get("use_features", None):
            self.features = OrderedDict((x, self.features[x]) for x in params["use_features"])
        if params.get("feature_specs", None):
            self.update_feature_specs(params["feature_specs"])
        self.set_column_index()

    def update_feature_specs(self, feature_specs):
        for col in feature_specs:
            namelist = col["name"]
            if type(namelist) != list:
                namelist = [namelist]
            for name in namelist:
                for k, v in col.items():
                    if k != "name":
                        self.features[name][k] = v

    def save(self, json_file):
        logging.info("Save feature_map to json: " + json_file)
        os.makedirs(os.path.dirname(json_file), exist_ok=True)
        feature_map = OrderedDict()
        feature_map["dataset_id"] = self.dataset_id
        feature_map["num_fields"] = self.num_fields
        feature_map["total_features"] = self.total_features
        feature_map["input_length"] = self.input_length
        feature_map["labels"] = self.labels
        if self.group_id is not None:
            feature_map["group_id"] = self.group_id
        feature_map["features"] = [{k: v} for k, v in self.features.items()]
        with open(json_file, "w") as fd:
            json.dump(feature_map, fd, indent=4)

    def get_num_fields(self, feature_source=[]):
        if type(feature_source) != list:
            feature_source = [feature_source]
        num_fields = 0
        for feature, feature_spec in self.features.items():
            if feature_spec["type"] == "meta":
                continue
            if len(feature_source) == 0 or feature_spec.get("source") in feature_source:
                num_fields += 1
        return num_fields

    def sum_emb_out_dim(self, feature_source=[]):
        if type(feature_source) != list:
            feature_source = [feature_source]
        total_dim = 0
        for feature, feature_spec in self.features.items():
            if feature_spec["type"] == "meta":
                continue
            if len(feature_source) == 0 or feature_spec.get("source") in feature_source:
                total_dim += feature_spec.get("emb_output_dim",
                                              feature_spec.get("embedding_dim",
                                                               self.default_emb_dim))
        return total_dim

    def set_column_index(self):
        logging.info("Set column index...")
        idx = 0
        for feature, feature_spec in self.features.items():
            if "max_len" in feature_spec:
                col_indexes = [i + idx for i in range(feature_spec["max_len"])]
                self.column_index[feature] = col_indexes
                idx += feature_spec["max_len"]
            else:
                self.column_index[feature] = idx
                idx += 1
        self.input_length = idx
        for label in self.labels:
            self.column_index[label] = idx
            idx += 1

    def get_column_index(self, feature):
        if feature not in self.column_index:
            self.set_column_index()
        return self.column_index[feature]


# -*- coding: utf-8 -*-
"""
Created on Wed Nov 29 21:18:31 2017

@author: jagan
"""

#Import Library
import matplotlib.pyplot as plt
import numpy as np

#Main Function
def main():
    N= 5
    width = 0.35

    #Data for the bar chart
    men_score=(75,70,98,62,55)
    wom_score=(65,77,98,85,63)

    ind = np.arange(N)

    p1=plt.bar(ind,men_score,width)
    p2=plt.bar(ind,wom_score,width)

    #label axis
    plt.title("Matplot Class - Bar Chart") # Adds title to graph
    plt.xlabel("Number")
    plt.ylabel("Score")
    plt.legend((p1[0],p2[0]),('Men','Women'))
    plt.show()

if __name__=="__main__":
    main()


class cipher:
    """ Class used to cipher/decipher a message, using the vigenere cipher. """

    def __init__(self, key = "a"):
        """
        key: the key used to cipher/decipher the message
        """
        self.change_key(key)

        self.SPECIAL_CHAR = -1

    def change_key(self, key):
        """ Changes the key used in the class. """
        key = key.upper()

        # Converting the string into a integers list
        self.key = list(map(lambda char: ord(char) - 65, key))
        self.key_idx = 0

    def __get_key_idx__(self):
        """ Returns the actual index of the string. This increments the value of the internal index.
        """
        key_idx = self.key_idx
        self.key_idx = (self.key_idx + 1) % len(self.key)

        return key_idx

    def __treat_special_chars__(self, text, converted_list):
        """ Given a list of integers the and a text, treats the special characters in the list.

        converted_list: a list of integers, keeping the Unicode points of every char in the text

        text: a string, the message that generated converted_list
        """
        filtered_list = []

        i = 0
        for c in text:
            if ord(c) < ord('A') or ord(c) > ord('Z'):
               converted_list[i] = self.SPECIAL_CHAR
            i += 1

        filtered_list = converted_list

        return filtered_list

    def encrypt(self, plain_text):
        """ Cipher the given text. Returns a ciphered message, using the stored key.

        plain_text: a string, the message that will be ciphered.
        """
        self.key_idx = 0
        plain_text = plain_text.upper()

        # Converts the string into a list of integers, the indexes of every char in the alphabet
        converted_list = list(map(lambda char: ord(char) - 65, plain_text))

        converted_list = self.__treat_special_chars__(text = plain_text, converted_list = converted_list)

        encrypted_list = []

        i = 0
        # Encrypting
        for val in converted_list:
            if val != self.SPECIAL_CHAR:
                val = (val + self.key[self.__get_key_idx__()]) % 26 + 65
            else:
                val = ord(plain_text[i])

            i += 1
            encrypted_list.append(val)

        # Transforming the encrypted list into string
        encrypted_string = (map(chr, encrypted_list))
        encrypted_string = ''.join(encrypted_string)

        return encrypted_string.lower()

    def decrypt(self, crypted_text):
        """ Given a ciphered text, decipher it. Uses the key stored.

        crypted_text: a string, the ciphered text that will be deciphered.
        """
        self.key_idx = 0;
        crypted_text = crypted_text.upper()

        # Transforming the string into a list of integers, the indexes of chars in the alphabet
        crypted_list = list(map(lambda char: ord(char) - 65, crypted_text))

        crypted_list = self.__treat_special_chars__(text = crypted_text, converted_list = crypted_list)

        i = 0
        # Deciphering
        decrypted_list = []
        for val in crypted_list:
            if val != self.SPECIAL_CHAR:
                val = (val - self.key[self.__get_key_idx__()]) % 26 + 65
            else:
                val = ord(crypted_text[i])

            i += 1
            decrypted_list.append(val)

        # Getting the string from the deciphered list
        decrypted_string = map(chr, decrypted_list)
        decrypted_string = ''.join(decrypted_string).lower()

        # Captalizing
        temp_list = decrypted_string.split('.')
        decrypted_string = '. '.join(map(lambda s : s.lstrip().capitalize(), temp_list))

        return decrypted_string


# -*- coding: utf-8 -*-
"""
@author: Florian Koch
@license: All rights reserved
"""
import pandas as pd
import json

with open('../../data/Öffentliche Beleuchtung der Stadt Zürich/beleuchtung.json') as data_file:
  data = json.load(data_file)
  df = pd.io.json.json_normalize(data, ['features', ['geometry', 'coordinates']],['name', ])
  df.columns = ['E', 'N', 'name']
  df.name = 'illumination'

df.to_csv('../../data/prepared/illumination.csv')


import math
import os
from pathlib import Path
from typing import Any, Optional, Tuple, Union
from warnings import warn

import torch

from renate.types import NestedTensors

def mmap_tensor(
    filename: str, size: Union[int, Tuple[int, ...]], dtype: torch.dtype
) -> torch.Tensor:
    """Creates or accesses a memory-mapped tensor."""
    t = torch.from_file(
        filename,
        shared=True,
        size=math.prod(size) if isinstance(size, tuple) else size,
        dtype=dtype,
        device="cpu",
    )
    return t.view(size)

class Storage(torch.utils.data.Dataset):
    """An abstract class for permanent storage of datasets."""

    def __init__(self, directory: str) -> None:
        self._directory = directory

    def __len__(self) -> int:
        return self._length

    def __getitem__(self, idx: int) -> Any:
        raise NotImplementedError()

    def dump_dataset(self, ds: torch.utils.data.Dataset) -> None:
        raise NotImplementedError()

    def load_dataset(self, directory: Union[str, Path]):
        raise NotImplementedError()

class MemoryMappedTensorStorage(Storage):
    """A class implementing permanent storage of nested tensor datasets.

    This implements storage for `length` data points consisting of nested tensors of fixed types
    and shapes. `Storage` implements `__len__` and `__getitem__` and therefore can be used as a
    torch `Dataset`. To populate the storage, it also implements `dump_dataset`. It does _not_ keep
    track which slots have or have not been populated.

    `Storage` is given a path to a directory, where it creates (or accesses, if they already exist)
    memory-mapped tensor files.

    Args:
        directory: Path to a directory.
        data_point: Prototypical datapoint from which to infer shapes/dtypes.
        length: Number of items to be stored.
    """

    def __init__(self, directory: str) -> None:
        warn(
            f"""{self.__class__.__name__} will be deprecated very soon. Use FileTensorStorage
            instead. {self.__class__.__name__} is currently not fully functional, as some of the
            necessary parts of the interface have been modified and simplified. """,
            DeprecationWarning,
            stacklevel=2,
        )
        super().__init__(directory)
        self._storage: Optional[NestedTensors] = None

    @staticmethod
    def _create_mmap_tensors(path: str, data_point: NestedTensors, length: int) -> NestedTensors:
        if isinstance(data_point, torch.Tensor):
            os.makedirs(os.path.dirname(path), exist_ok=True)
            filename = f"{path}.pt"
            return mmap_tensor(filename, size=(length, *data_point.size()), dtype=data_point.dtype)
        elif isinstance(data_point, tuple):
            return tuple(
                MemoryMappedTensorStorage._create_mmap_tensors(
                    os.path.join(path, f"{i}.pt"), data_point[i], length
                )
                for i in range(len(data_point))
            )
        elif isinstance(data_point, dict):
            return {
                key: MemoryMappedTensorStorage._create_mmap_tensors(
                    os.path.join(path, f"{key}.pt"), data_point[key], length
                )
                for key in data_point
            }
        else:
            raise TypeError(f"Expected nested tuple/dict of tensors, found {type(data_point)}.")

    @staticmethod
    def _get(storage: NestedTensors, idx: int) -> NestedTensors:
        if isinstance(storage, torch.Tensor):
            return storage[idx]
        elif isinstance(storage, tuple):
            return tuple(MemoryMappedTensorStorage._get(t, idx) for t in storage)
        elif isinstance(storage, dict):
            return {key: MemoryMappedTensorStorage._get(t, idx) for key, t in storage.items()}
        else:
            raise TypeError(f"Expected nested tuple/dict of tensors, found {type(storage)}.")

    def __getitem__(self, idx: int) -> NestedTensors:
        """Read the item stored at index `idx`."""
        return self._get(self._storage, idx)

    @staticmethod
    def _set(storage: NestedTensors, idx: int, data_point: NestedTensors) -> None:
        if isinstance(storage, torch.Tensor):
            assert isinstance(data_point, torch.Tensor)
            assert data_point.dtype is storage.dtype
            storage[idx] = data_point
        elif isinstance(storage, tuple):
            assert isinstance(data_point, tuple)
            assert len(data_point) == len(storage)
            for i in range(len(storage)):
                MemoryMappedTensorStorage._set(storage[i], idx, data_point[i])
        elif isinstance(storage, dict):
            assert isinstance(data_point, dict)
            assert set(data_point.keys()) == set(storage.keys())
            for key in storage:
                MemoryMappedTensorStorage._set(storage[key], idx, data_point[key])
        else:
            raise TypeError(f"Expected nested tuple/dict of tensors, found {type(storage)}.")

    def dump_dataset(self, ds):
        self._length = len(ds)
        self._storage = self._create_mmap_tensors(self._directory, ds[0], self._length)
        for idx in range(len(self)):
            self._set(self._storage, idx, ds[idx])

class FileTensorStorage(Storage):
    """A class implementing permanent storage of nested tensor datasets to disk as pickle files.

    This implements storage for `length` data points consisting of nested tensors of fixed types
    and shapes. `Storage` implements `__len__` and `__getitem__` and therefore can be used as a
    torch `Dataset`. To populate the storage, it also implements `dump_dataset`. It does _not_ keep
    track which slots have or have not been populated.

    `Storage` is given a path to a directory, where it creates (or accesses, if they already exist)
    pickle files one for each point in the dataset.

    Args:
        directory: Path to a directory.
    """

    def __init__(self, directory: str) -> None:
        super().__init__(directory)

    def dump_dataset(self, ds: torch.utils.data.Dataset) -> None:
        for i in range(len(ds)):
            torch.save(ds[i], self._compose_file_path_from_index(i))

    def __getitem__(self, idx: int) -> Any:
        if not hasattr(self, "_length"):
            self.load_dataset(None)
        return torch.load(self._compose_file_path_from_index(idx))

    def load_dataset(self, directory: Union[str, Path]):
        self._length = len([x for x in os.listdir(self._directory) if x.endswith(".pt")])

    def _compose_file_path_from_index(self, idx: int) -> str:
        return os.path.join(self._directory, f"{idx}.pt")


#PE-FA MRM Generator 2.0
import pandas as pd

fatty_acids = ['14:0', '14:1', '16:0', '16:1', '18:0', '18:1', '18:2', '18:3', '20:0', '20:1', '20:2', '20:3', '20:4', '20:5', '22:4', '22:5', '22:6']      # FAs pulled from Lipidyzer

def mrm_output(fa1):

    carbon = 12.000000
    hydrogen = 1.007825
    oxygen = 15.994915
    phosphorus = 30.973762
    nitrogen = 14.003074

    fa_carbon_no = []
    fa_desat_no = []
    fa_desat_no_mass = []

    # converting string to int for calculations below
    for i in fa1:
        fa_carbon_no.append(int(i[:2]))
        fa_desat_no.append(int(i[-1]))
        fa_desat_no_mass.append(int(i[-1]))

    pe_carbon = []
    pe_desat = []
    pe_desat_mass = []

    # to get the total fa carbon number
    while fa_carbon_no != []:
        for i in fa_carbon_no:
            pe_carbon += [fa_carbon_no[0] + i]

        fa_carbon_no.remove(fa_carbon_no[0])

    # to get the total fa desat number for label
    while fa_desat_no != []:
        for i in fa_desat_no:
            pe_desat += [fa_desat_no[0] + i]

        fa_desat_no.remove(fa_desat_no[0])

    # to get the total fa desat number for mass calculation
    while fa_desat_no_mass != []:
        for i in fa_desat_no_mass:
            pe_desat_mass += [fa_desat_no_mass[0] + i]

        fa_desat_no_mass.remove(fa_desat_no_mass[0])

    # to output the pe id (i.e. PE-(fa C no.):(fa desat no.))
    pe_id = []
    pe_M1_mass = []

    id_counter = len(pe_carbon)
    id_number = len(pe_carbon)

    while id_counter != 0:
        pe_id += ["PE-" + str(pe_carbon[id_number - id_counter]) + ":" + str(pe_desat[id_number - id_counter])]

        pe_M1_mass += [(carbon * (pe_carbon[id_number - id_counter] + 5)) + (hydrogen * ((pe_carbon[id_number - id_counter] * 2) - (pe_desat_mass[id_number - id_counter] * 2) + 10)) + (oxygen * 8) + nitrogen + phosphorus - hydrogen]

        id_counter -= 1

    # to output the FA combinations for each PE (this is the same as the original TAG/FA combinator)
    pe = []

    while fa1 != []:
        for i in fa1:
            pe += [fa1[0] + '/' + i]

        fa1.remove(fa1[0])

    # calculating each possible MRM transition (Ac adducts)
    fatty_acid_1 = []
    fatty_acid_2 = []
    fatty_acid_combo = []

    M3_fa1 = []
    M3_fa2 = []

    for i in pe:
        fatty_acid_combo = i.split('/')
        fatty_acid_1 += [fatty_acid_combo[0]]
        fatty_acid_2 += [fatty_acid_combo[1]]
        fatty_acid_combo.clear()

    pe_M1_mass_counter = len(pe_M1_mass)
    pe_M1_mass_number = len(pe_M1_mass)
    for i in fatty_acid_1:
        M3_fa1 += [((int(i[0:2]) * carbon) + (hydrogen * ((int(i[0:2]) * 2) - (int(i[-1]) * 2))) + (oxygen * 2) - hydrogen)]

        pe_M1_mass_counter -= 1

    pe_M1_mass_counter = len(pe_M1_mass)
    pe_M1_mass_number = len(pe_M1_mass)
    for i in fatty_acid_2:
        M3_fa2 += [((int(i[0:2]) * carbon) + (hydrogen * ((int(i[0:2]) * 2) - (int(i[-1]) * 2))) + (oxygen * 2) - hydrogen)]

        pe_M1_mass_counter -= 1

    # Final MRM table output
    all_M3_transitions = M3_fa1 + M3_fa2
    all_fatty_acids = fatty_acid_1 + fatty_acid_2
    all_pe_id = pe_id + pe_id
    all_pe_M1_mass = pe_M1_mass + pe_M1_mass
    all_pe_FA_label = []

    pe_FA_label_counter = len(all_pe_id)
    pe_FA_label_number = len(all_pe_id)

    for i in all_pe_id:
        all_pe_FA_label += [i + '-FA' + all_fatty_acids[pe_FA_label_number - pe_FA_label_counter]]

        pe_FA_label_counter -= 1

    MRM_table = pd.DataFrame({'PE ID': pe_id, 'FA composition': pe, 'M1 mass (-H)': pe_M1_mass, 'M3 -FA1 mass': M3_fa1, 'M3 -FA2 mass': M3_fa2})
    print(MRM_table)
    MRM_table.to_csv('MRM_table.csv')

    MRM_condensed_table = pd.DataFrame({'PE ID': all_pe_id, 'FA loss': all_fatty_acids, 'PE-FA label': all_pe_FA_label, 'M1 mass (-H)': all_pe_M1_mass, 'M3 -FA mass': all_M3_transitions})
    MRM_condensed_table_unique = MRM_condensed_table.drop_duplicates()

    print(MRM_condensed_table)
    print(MRM_condensed_table_unique)

    MRM_condensed_table.to_csv('MRM_condensed_table.csv')
    MRM_condensed_table_unique.to_csv('MRM_condensed_table_unique.csv')

mrm_output(fatty_acids)


from django.shortcuts import render, get_object_or_404
from django.shortcuts import redirect
from allauth.socialaccount.models import SocialAccount
from .models import Repository, Milestone, Task
import requests
from .scripts import sync_repos
from .forms import MilestoneForm, TaskForm

def homepage(request):
    return render(request, 'roadmap/home.html')

def create_new_roadmap_subsite(request):
    if not request.user.is_authenticated:
        return render(request, 'roadmap/create_new_roadmap.html')

    username = SocialAccount.objects.get(user=request.user)
    url = f"https://api.github.com/users/{username}/repos"
    response = requests.get(url)

    if response.status_code == 200:
        repos = response.json()
        sync_repos.sync(repos)
    else:
        repos = []

    context = {"repos": repos}

    return render(request, 'roadmap/create_new_roadmap.html', context)

def create_new_roadmap(request, repository_id):
    repository = get_object_or_404(Repository, git_id=repository_id)
    milestones = Milestone.objects.filter(repository=repository)
    tasks = Task.objects.filter(repository=repository)

    milestone_form = MilestoneForm()
    task_form = TaskForm(repository=repository)

    context = {
        'milestone_form': milestone_form,
        'milestones': milestones,
        'task_form': task_form,
        'tasks': tasks,
        'repository': repository,
    }

    if request.method == 'POST':
        milestone_form = MilestoneForm(request.POST)
        task_form = TaskForm(request.POST, repository=repository)

        if 'milestoneform' in request.POST:
            if milestone_form.is_valid():
                milestone = milestone_form.save(commit=False)
                milestone.repository = repository
                milestone.save()

        if 'taskform' in request.POST:
            if task_form.is_valid():
                task = task_form.save(commit=False)
                task.repository = repository
                task.save()

    return render(request, 'roadmap/create_roadmap.html', context)

def my_roadmaps_subsite(request):
    if not request.user.is_authenticated:
        return render(request, 'roadmap/my_roadmaps.html')

    username = SocialAccount.objects.get(user=request.user)
    url = f"https://api.github.com/users/{username}/repos"
    response = requests.get(url)

    if response.status_code == 200:
        repos = response.json()
        sync_repos.sync(repos)
    else:
        repos = []

    context = {"repos": repos}

    return render(request, 'roadmap/my_roadmaps.html', context)

def roadmap(request, repository_id):
    repository = get_object_or_404(Repository, git_id=repository_id)
    milestones = Milestone.objects.filter(repository=repository)

    context = {
        'milestones' : milestones,
        'repository' : repository,
    }

    return render(request, 'roadmap/roadmap.html', context)

def mark_task_done(request, task_id):
    task = get_object_or_404(Task, pk=task_id)
    task.isdone = True
    task.save()
    repository_git_id = task.repository.git_id
    return redirect(f'http://localhost:8000/roadmaps/{repository_git_id}/')

def mark_task_undone(request, task_id):
    task = get_object_or_404(Task, pk=task_id)
    task.isdone = False
    task.save()
    repository_git_id = task.repository.git_id
    return redirect(f'http://localhost:8000/roadmaps/{repository_git_id}/')

def delete_task(request, task_id):
    task = get_object_or_404(Task, id=task_id)
    repository_git_id = task.repository.git_id
    task.delete()
    return redirect(f'http://localhost:8000/create_new_roadmap/{repository_git_id}/')

def delete_milestone(request, milestone_id):
    milestone = get_object_or_404(Milestone, id=milestone_id)
    repository_git_id = milestone.repository.git_id
    milestone.delete()
    return redirect(f'http://localhost:8000/create_new_roadmap/{repository_git_id}/')


from unidecode import unidecode
import unittest

class Event:
    def __init__(self, name, player, quantity):
        self.name = name
        self.player = player
        self.quantity = quantity

    def __str__(self):
        return ', '.join([self.name, unidecode(self.player), str(self.quantity)])

    def __eq__(self, other):
        return self.__dict__ == other.__dict__

    @staticmethod
    def GetEventUpdates(oldEvents, newEvents):

        result = []
        newSavesEvents = filter(lambda x: x.name == "Saves", newEvents)
        if len(newSavesEvents) > 0:
            oldSavesEvents = filter(lambda x: x.name == "Saves", oldEvents)
            if len(oldSavesEvents) > 0:
                for newSavesEvent in newSavesEvents:
                    oldSavesEvent = next((x for x in oldSavesEvents if x.player == newSavesEvent.player), None)
                    if not oldSavesEvent or (oldSavesEvent and oldSavesEvent.quantity/3 < newSavesEvent.quantity/3):
                        result.append(newSavesEvent)
            else:
                result.extend(newSavesEvents)
        result.extend(filter(lambda x: x not in oldEvents and x.name != "Saves", newEvents))
        return result

class TestEvent(unittest.TestCase):
    def test_onePlayerNoSavesIncrement(self):
        e1 = Event("Saves", u"Cech", 3)
        e2 = Event("Saves", u"Cech", 3)
        events = Event.GetEventUpdates([e1], [e2])
        self.assertEqual(len(events), 0)

    def test_onePlayerMinorSavesIncrement(self):
        e1 = Event("Saves", u"Cech", 3)
        e2 = Event("Saves", u"Cech", 5)
        events = Event.GetEventUpdates([e1], [e2])
        self.assertEqual(len(events), 0)

    def test_onePlayerSavesDecrement(self):
        e1 = Event("Saves", u"Cech", 3)
        e2 = Event("Saves", u"Cech", 2)
        events = Event.GetEventUpdates([e1], [e2])
        self.assertEqual(len(events), 0)

    def test_onePlayerValidSavesIncrement(self):
        e1 = Event("Saves", u"Cech", 3)
        e2 = Event("Saves", u"Cech", 6)
        events = Event.GetEventUpdates([e1], [e2])
        self.assertEqual(len(events), 1)
        self.assertEqual(events[0], e2)

    def test_onePlayerValidSavesIncrement(self):
        e1 = Event("Saves", u"Cech", 3)
        e2 = Event("Saves", u"Cech", 14)
        events = Event.GetEventUpdates([e1], [e2])
        self.assertEqual(len(events), 1)
        self.assertEqual(events[0], e2)

    def test_onePlayerNewSaves(self):
        e1 = Event("Foo", u"Cech", 0)
        e2 = Event("Saves", u"Cech", 14)
        events = Event.GetEventUpdates([e1], [e2])
        self.assertEqual(len(events), 1)
        self.assertEqual(events[0], e2)

    def test_onePlayerOldSaves(self):
        e1 = Event("Saves", u"Cech", 3)
        e2 = Event("Foo", u"Cech", 14)
        events = Event.GetEventUpdates([e1], [e2])
        self.assertEqual(len(events), 1)
        self.assertEqual(events[0].name, "Foo")

    def test_twoPlayersNoSavesIncrement(self):
        e1 = Event("Saves", u"Cech", 3)
        e2 = Event("Saves", u"Cech", 3)
        e3 = Event("Saves", u"Guzan", 5)
        e4 = Event("Saves", u"Guzan", 5)
        events = Event.GetEventUpdates([e1, e3], [e2, e4])
        self.assertEqual(len(events), 0)

    def test_twoPlayersMinorSavesIncrement(self):
        e1 = Event("Saves", u"Cech", 3)
        e2 = Event("Saves", u"Cech", 5)
        e3 = Event("Saves", u"Guzan", 6)
        e4 = Event("Saves", u"Guzan", 8)
        events = Event.GetEventUpdates([e1, e3], [e2, e4])
        self.assertEqual(len(events), 0)

    def test_twoPlayersValidSavesIncrement(self):
        e1 = Event("Saves", u"Cech", 3)
        e2 = Event("Saves", u"Cech", 6)
        e3 = Event("Saves", u"Guzan", 7)
        e4 = Event("Saves", u"Guzan", 9)
        events = Event.GetEventUpdates([e1, e3], [e2, e4])
        self.assertEqual(len(events), 2)
        self.assertEqual(events[0], e2)
        self.assertEqual(events[1], e4)

    def test_twoPlayersOnePlayerValidSavesIncrement(self):
        e1 = Event("Saves", u"Cech", 3)
        e2 = Event("Saves", u"Cech", 5)
        e3 = Event("Saves", u"Guzan", 7)
        e4 = Event("Saves", u"Guzan", 9)
        events = Event.GetEventUpdates([e1, e3], [e2, e4])
        self.assertEqual(len(events), 1)
        self.assertEqual(events[0], e4)

    def test_twoPlayersNewSaves(self):
        e1 = Event("Foo", u"Cech", 0)
        e2 = Event("Saves", u"Cech", 14)
        e3 = Event("Saves", u"Guzan", 7)
        events = Event.GetEventUpdates([e1], [e2, e3])
        self.assertEqual(len(events), 2)
        self.assertEqual(events[0], e2)
        self.assertEqual(events[1], e3)

    def test_twoPlayersOnePlayerNewSaves(self):
        e1 = Event("Saves", u"Cech", 14)
        e2 = Event("Saves", u"Cech", 14)
        e3 = Event("Saves", u"Guzan", 7)
        events = Event.GetEventUpdates([e1], [e2, e3])
        self.assertEqual(len(events), 1)
        self.assertEqual(events[0], e3)

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


import argparse
from pwm import main as pwm_main
from pwm import *

'''
-m pour le fichier contenant la matrice (option longue --pfm, pas de valeur par défaut) ;
-t pour le seuil de score de matrice (option longue --threshold, pas de valeur par défaut) ;
-l pour la longueur du promoteur (option longue --promotor-length, par défaut 1000) ;
-w pour la longueur de la fenêtre glissante (option longue --window-size, par défaut 40) ;
-s pour le seuil de score de fenêtre (option longue --window-threshold, pas de valeur par défaut) ;
-p pour la valeur du pseudo-poids (option longue --pseudocount, valeur par défaut 0.1).
'''
def main(args):
    parser = argparse.ArgumentParser()
    parser.parse_args()

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("-m", "--pfm", help="le fichier contenant la matrice")
    parser.add_argument("-t", "--threshold", help="The threshold of the results", type=int)
    parser.add_argument("-l", "--promotor-length", help="The lengh of the promotor", type=int, default=1000)
    parser.add_argument("-w", "--window-size", help="the size of the sliding window", type=int, default=40)
    parser.add_argument("-s", "--window-threshold", type=int)
    parser.add_argument("-p", "--pseudocount", help="le seuil de poids", type=int, default=0.1)

    parser.add_argument("-v", "--verbosity", help="increases the verbosity", action="store_true")
    args = parser.parse_args()
    if (args.verbosity):
        print("verbosity turned on")

    nb_occurences = scan_sequence()
    score_de_fenetre = score_window()

    pwm_main()


import numpy as np
import chainer
import argparse
import csv

import chainer.functions as F
import chainer.links as L
from chainer import cuda
from chainer import serializers

from fix_data import OneDimSensorData

"""
    LSTMを書いて, 訓練するクラス
"""
class LSTM(chainer.Chain):
    def __init__(self):
        super().__init__(
            l1=L.Linear(1, 5),
            l2=L.LSTM(5, 30),
            l3=L.Linear(30, 1),
            l4=L.Linear(1, 2)
        )

    def predictor(self, x):
        # テストデータでの評価用途
        self.l2.reset_state()
        row = x.shape[0]
        col = x.shape[1]
        for i in range(col):
            h = self.l1(xp.array(x[:, i].reshape(row, 1), dtype=xp.float32))
            h = self.l2(h)
            h = self.l3(h)
            h = self.l4(h)
        return [0 if data[0] > data[1] else 1 for data in h.data] # WATCH: あとでmapできるようにかきかえる

    def __call__(self, x, t):
        # ひとつのデータごとに誤差を計算する
        self.l2.reset_state()
        row = x.shape[0]
        col = x.shape[1]
        accum_loss = None
        for i in range(col):
            h = self.l1(xp.array(x[:, i].reshape(row, 1), dtype=xp.float32))
            h = self.l2(h)
            h = self.l3(h)
            if i != col-1:
                loss = F.mean_squared_error(h, xp.array(x[:, i+1].reshape(row, 1), dtype=xp.float32))
                accum_loss = loss if accum_loss is None else accum_loss + loss
            h = self.l4(h)
        accum_loss += F.softmax_cross_entropy(h, xp.array(t, dtype=xp.int32))
        # print(loss.data)

        return accum_loss

# gpu
parser = argparse.ArgumentParser()
parser.add_argument('--gpu', '-g', default=-1, type=int,
                    help='GPU ID')
args = parser.parse_args()

# 学習データとテストデータ
one_dim_sensor = OneDimSensorData()
one_dim_sensor.load_csv()
one_dim_sensor.shuffle()
train, train_label, test, test_label, one_label_counts = one_dim_sensor.divide_train_and_test()

# model
model = LSTM()
optimizer = chainer.optimizers.Adam()
optimizer.setup(model)

# for cuda
xp = cuda.cupy if args.gpu >= 0 else np
if args.gpu >= 0:
    cuda.get_device(args.gpu).use()
    model.to_gpu()

# training loop
display = 1000
total_loss = 0
epoch = 500
n_size = len(train)
batch_size = 1000
# question_num = len(test)

loss_plt_ary = []
accuracy_plt_ary = []
recall_plt_ary = []

for i in range(epoch):
    sffindx = np.random.permutation(n_size)
    for j in range(0, n_size, batch_size):
        x = train[sffindx[j:(j+batch_size) if (j+batch_size) < n_size else n_size]]
        y = train_label[sffindx[j:(j+batch_size) if (j+batch_size) < n_size else n_size]]
        loss = model(x, y)
        # print(loss.data)
        model.zerograds()
        loss.backward()
        optimizer.update()
        if j%display == 0:
            print("{} epoch {} number, loss {}".format(i, j, loss.data))
        last_loss = loss.data

    # テストデータでチェック
    answer_num = 0
    recall = 0
    for t_d, t_l in zip(test, test_label):
        answers = model.predictor(t_d)
        bool_ans = (answers==t_l)
        for bool in bool_ans:
            if bool:
                answer_num += 1
        for answer, tl in zip(answers, t_l):
            if answer == tl and answer:
                recall += 1
    print('main/loss {}, accuracy rate {}, recall rate {}, one_counts {}'.format(last_loss, answer_num/7410, recall/one_label_counts, one_label_counts))
    loss_plt_ary.append(last_loss)
    accuracy_plt_ary.append(answer_num/7410)
    recall_plt_ary.append(recall/one_label_counts)

serializers.save_npz("fixed_lstm_model_2", model)

def write_csv(path, ary):
    with open('results/lstm_fixed_result/%s.csv' % path, 'w') as f:
        writer = csv.writer(f, lineterminator='\n')
        writer.writerow(ary)

write_csv('loss', loss_plt_ary)
write_csv('accuracy', accuracy_plt_ary)
write_csv('recall', recall_plt_ary)

# csvにデータを書き込み
with open('results/lstm_fixed_result/loss.csv', 'w') as f:
    writer = csv.writer(f, lineterminator='\n')
    writer


#MODULO 1
#EJERCICIO 1

nombre = input("¿Cual es su nombre? ")
print('Hello {}'.format(nombre))

#EJERCICO 2

import string

print(string.ascii_lowercase)

a = input("Ingrese el abecedario alterado que desea: ")

s = input("Ingrese oracion que quiere encriptar con el abecedario anteriormente proporcionado: ")

a = a.lower()

s=s.lower()

acumulador=[]

for i in s:
    for j in string.ascii_lowercase:
        indice = string.ascii_lowercase.index(j)
        if i == j:

            for k in a:
                indice1 = a.index(k)
                if j == k:
                    acumulador.append(indice1)

acumuladora=[]
for i in acumulador:
    acumuladora = acumuladora + [i]

g = ""

for i in acumuladora:
    g = g + string.ascii_lowercase[i]
print (g)

#PROBLEMAS DIVERSOS
#1
inversion= float(input("Introduce la inversión inicial: "))
interes = 0.04
balance1 = inversion * (1 + interes)
print("Balance tras el primer año:" + str(round(balance1, 2)))
balance2 = balance1 * (1 + interes)
print("Balance tras el segundo año:" + str(round(balance2, 2)))
balance3 = balance2 * (1 + interes)
print("Balance tras el tercer año:" + str(round(balance3, 2)))

#2
from math import sqrt
A = int(input("Ingrese el coeficiente de la variable cuadrática "))
B = int(input("Ingrese el coeficiente de la variable lineal"))
C = int(input("Ingrese el término independiente"))
if ((B**2)-4*A*C) < 0:
  print("La solución de la ecuación es con numeros complejos")
else:
  x1 = (-B+sqrt(B**2-(4*A*C)))/(2*A)
  x2 = (-B-sqrt(B**2-(4*A*C)))/(2*A)
  print("Las soluciones de la ecuación son:")
  print(x1)
  print(x2)


from ansible.module_utils.basic import AnsibleModule
from PyPowerStore.utils.exception import PowerStoreException
from ansible.module_utils import dellemc_ansible_utils as utils
import logging
from uuid import UUID

__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.0',
                    'status': ['preview'],
                    'supported_by': 'community'
                    }

DOCUMENTATION = r'''
---
module: dellemc_powerstore_volumegroup
version_added: '2.6'
short_description: Manage volume groups on PowerStore Storage System
description:
- Managing volume group on PowerStore Storage System includes
  creating new volume group, adding volumes to volume
  group, removing volumes from volume group, renaming volume group,
  modifying volume group and deleting volume group.
author:
- Akash Shendge (akash.shendge@dell.com)
- Arindam Datta (arindam.datta@dell.com)
extends_documentation_fragment:
  - dellemc.dellemc_powerstore
options:
  vg_name:
    description:
    - The name of the volume group.
    required: False
  vg_id:
    description:
    - The id of the volume group.
    - It can be used only for Modify, Add/Remove or Delete operation.
    required: False
  volumes:
    description:
    - This is a list of volumes.
    - Either the volume ID or name must be provided for adding/removing
      existing volumes from volume group.
    - If volumes are given, then vol_state should also be specified.
  vol_state:
    description:
    - String variable , describes the state of volumes inside VG
    - If volume are given, then vol_state should also be specified.
    choices: [present-in-group , absent-in-group]
  new_vg_name:
    description:
     - The new name of the volume group.
  description:
    description:
    - Description about the volume group.
  protection_policy:
    description:
    - String variable, represents Protection policy id or name
      used for volume group.
    - Specifying an empty string or "" removes the existing
      protection policy from Volume Group.
    required: false
  is_write_order_consistent:
    description:
    - A boolean flag to indicate whether snapshot sets of the volume group will be write-order consistent.
    - If this parameter is not specified, the array by default sets it to true.
    required: false
  state:
    description:
    - Define whether the volume group should exist or not.
    choices: [absent, present]
    required: true
Notes:
- vol_state is mandatory if volumes are provided.
- A protection policy can be specified either for an volume group, or
  for the individual volumes inside the volume group.
- A volume can be a member of at most one volume group.
- Specifying "protection_policy" as empty string or "" removes the existing
  protection policy from a Volume Group.

'''

EXAMPLES = r'''
- name: Create volume group without protection policy
  dellemc_powerstore_volumegroup:
    array_ip: "{{array_ip}}"
    verifycert: "{{verifycert}}"
    user: "{{user}}"
    password: "{{password}}"
    vg_name: "{{vg_name}}"
    description: "This volume group is for ansible"
    state: "present"

 - name: Get details of volume group
   dellemc_powerstore_volumegroup:
     array_ip: "{{array_ip}}"
     verifycert: "{{verifycert}}"
     user: "{{user}}"
     password: "{{password}}"
     vg_name: "{{vg_name}}"
     state: "present"

 - name: Add volumes to volume group
   dellemc_powerstore_volumegroup:
     array_ip: "{{array_ip}}"
     verifycert: "{{verifycert}}"
     user: "{{user}}"
     password: "{{password}}"
     vg_name: "{{vg_name}}"
     state: "present"
     volumes:
       - "7f879569-676c-4749-a06f-c2c30e09b295"
       - "68e4dad5-5de5-4644-a98f-6d4fb916e169"
       - "Ansible_Testing"
     vol_state: "present-in-group"

- name: Remove volumes from volume group
  dellemc_powerstore_volumegroup:
    array_ip: "{{array_ip}}"
    verifycert: "{{verifycert}}"
    user: "{{user}}"
    password: "{{password}}"
    vg_name: "{{vg_name}}"
    state: "present"
    volumes:
      - "7f879569-676c-4749-a06f-c2c30e09b295"
      - "Ansible_Testing"
    vol_state: "absent-in-group"

- name: Rename volume group and change is_write_order_consistent flag
  dellemc_powerstore_volumegroup:
    array_ip: "{{array_ip}}"
    verifycert: "{{verifycert}}"
    user: "{{user}}"
    password: "{{password}}"
    vg_name: "{{vg_name}}"
    new_vg_name: "{{new_vg_name}}"
    is_write_order_consistent: False
    state: "present"

- name: Get details of volume group by ID
  dellemc_powerstore_volumegroup:
    array_ip: "{{array_ip}}"
    verifycert: "{{verifycert}}"
    user: "{{user}}"
    password: "{{password}}"
    vg_id: "{{vg_id}}"
    state: "present"

- name: Delete volume group
  dellemc_powerstore_volumegroup:
    array_ip: "{{array_ip}}"
    verifycert: "{{verifycert}}"
    user: "{{user}}"
    password: "{{password}}"
    name: "{{new_vg_name}}"
    state: "absent"

'''

RETURN = r'''
'''

LOG = utils.get_logger('dellemc_powerstore_volumegroup',
                       log_devel=logging.INFO)

py4ps_sdk = utils.has_pyu4ps_sdk()
HAS_PY4PS = py4ps_sdk['HAS_Py4PS']
IMPORT_ERROR = py4ps_sdk['Error_message']

py4ps_version = utils.py4ps_version_check()
IS_SUPPORTED_PY4PS_VERSION = py4ps_version['supported_version']
VERSION_ERROR = py4ps_version['unsupported_version_message']

# Application type
APPLICATION_TYPE = 'Ansible/1.0'

class PowerStoreVolumeGroup(object):
    """Class with Volume Group operations"""

    def __init__(self):
        """Define all the parameters required by this module"""
        self.module_params = utils.get_powerstore_management_host_parameters()
        self.module_params.update(get_powerstore_volume_group_parameters())

        # initialize the Ansible module
        self.module = AnsibleModule(
            argument_spec=self.module_params,
            supports_check_mode=True
        )

        LOG.info('HAS_PY4PS = {0} , IMPORT_ERROR = {1}'.format(
                 HAS_PY4PS, IMPORT_ERROR))
        if HAS_PY4PS is False:
            self.module.fail_json(msg=IMPORT_ERROR)
        LOG.info('IS_SUPPORTED_PY4PS_VERSION = {0} , '
                 'VERSION_ERROR = {1}'.format(
                  IS_SUPPORTED_PY4PS_VERSION, VERSION_ERROR))
        if IS_SUPPORTED_PY4PS_VERSION is False:
            self.module.fail_json(msg=VERSION_ERROR)

        self.conn = utils.get_powerstore_connection(self.module.params,
          application_type=APPLICATION_TYPE)
        self.provisioning = self.conn.provisioning
        LOG.info('Got Py4ps instance for provisioning on PowerStore {0}'.
                 format(self.conn))
        self.protection = self.conn.protection
        LOG.info('Got Py4ps instance for protection on PowerStore {0}'.
                 format(self.protection))

    def get_volume_group_details(self, vg_id=None, name=None):
        """Get volume group details"""
        try:
            LOG.info("Getting VG Details {0} {1}".format(vg_id, name))

            if vg_id:
                resp = self.provisioning.get_volume_group_details(vg_id)
                LOG.info("Successfully Got VG with id {0}".format(vg_id))
                if len(resp) > 0:
                    return resp
                else:
                    return None

            if name:
                resp = self.provisioning.get_volume_group_by_name(name)
                if resp and len(resp) > 0:
                    id = resp[0]['id']
                    vg_details = self.provisioning.\
                        get_volume_group_details(id)
                    LOG.info("Successfully Got VG with name {0}".format(name))
                    return vg_details

            return None

        except Exception as e:

            id_or_name = vg_id if vg_id else name
            errormsg = "Failed to get volume group {0} with error {1}". \
                format(id_or_name, str(e))
            LOG.error(errormsg)

    def delete_volume_group(self, volume_group_id):
        """Delete volume group"""
        try:
            self.provisioning.delete_volume_group(volume_group_id)
            return True

        except PowerStoreException as pe:
            errormsg = "Failed to delete volume group {0} with error {1}". \
                format(volume_group_id, str(pe))
            LOG.error(errormsg)
            self.module.fail_json(msg=errormsg)

        except Exception as e:
            errormsg = "Failed to delete volume group {0} with error {1}".\
                format(volume_group_id, str(e))
            LOG.error(errormsg)
            self.module.fail_json(msg=errormsg)

    def get_volume_id_by_name(self, vol_name):
        """Get the details of a volume by name"""

        try:
            resp = self.provisioning.get_volume_by_name(vol_name)
            if len(resp) > 0:
                return resp[0]['id']
            else:
                return None

        except Exception as e:
            msg = "Failed to get the volume with name {0} with " \
                  "error {1}".format(vol_name, str(e))
            LOG.error(msg)

    def get_volume_details_by_id(self, volume_id):
        """Get the details of a volume by name"""

        try:
            LOG.info("getting volume with id {0}".format(volume_id))
            resp = self.provisioning.get_volume_details(volume_id)
            if len(resp) > 0:
                LOG.info("got volume with id {0} is {1}".format(volume_id, resp))
                return resp['id']
            else:
                return None

        except Exception as e:
            msg = "Failed to get the volume with id {0} with " \
                  "error {1}".format(volume_id, str(e))
            LOG.error(msg)

    def remove_volumes_from_volume_group(self, vg_id, vol_list):
        """Remove volumes from volume group"""

        vol_group_details = self.get_volume_group_details(vg_id=vg_id)
        existing_volumes_in_vg = vol_group_details['volumes']
        LOG.debug("Existing Volumes: {0}".format(existing_volumes_in_vg))

        existing_vol_ids = []
        for vol in existing_volumes_in_vg:
            if vol:
                existing_vol_ids.append(vol['id'])

        LOG.debug("Existing Volume IDs {0}".format(existing_vol_ids))

        ids_to_remove = []

        vol_name_list = []
        vol_id_list = []

        for each_vol in vol_list:
            if each_vol:
                identifier_type = self.name_or_id(each_vol)
                if identifier_type == "ID" and not (each_vol in vol_id_list):
                    vol_id_list.append(each_vol)
                elif identifier_type == "NAME" and not (each_vol in vol_name_list):
                    vol_name_list.append(each_vol)

        """remove by name"""
        for vol in vol_name_list:
            id = self.get_volume_id_by_name(vol)
            if id and (id in existing_vol_ids):
                if id not in ids_to_remove:
                    ids_to_remove.append(id)
            else:
                msg = "Unable to remove volume name {0} since is not " \
                      "present in volume group {1}".format(vol, vg_id)
                LOG.warn(msg)
                self.module.fail_json(msg=msg)

        """remove by id"""
        for vol in vol_id_list:
            if vol in existing_vol_ids:
                if vol not in ids_to_remove:
                    ids_to_remove.append(vol)
                else:
                    msg = "Unable to remove volume id {0} since is not " \
                          "present in volume group {1}".format(vol, vg_id)
                    LOG.warn(msg)
                    self.module.fail_json(msg=msg)

        LOG.debug("Volume IDs to Remove {0}".format(ids_to_remove))

        if len(ids_to_remove) == 0:
            return False

        try:
            self.provisioning.remove_members_from_volume_group(
                vg_id, ids_to_remove)

            return True

        except PowerStoreException as pe:
            errormsg = "Remove existing volume(s) from volume group {0} " \
                       "failed with error {1}".format(vg_id, str(pe))
            LOG.error(errormsg)
            self.module.fail_json(msg=errormsg)

        except Exception as e:
            errormsg = "Remove existing volume(s) from volume group {0} " \
                       "failed with error {1}".format(vg_id, str(e))
            LOG.error(errormsg)
            self.module.fail_json(msg=errormsg)

    def add_volumes_to_volume_group(self,vg_id, vol_list):
        """adds volumes to volume group"""

        vol_group_details = self.get_volume_group_details(vg_id=vg_id)
        existing_volumes_in_vg = vol_group_details['volumes']
        LOG.debug("Existing Volumes: {0}".format(existing_volumes_in_vg))
        existing_vol_ids = []
        for vol in existing_volumes_in_vg:
            if vol:
                existing_vol_ids.append(vol['id'])

        LOG.debug("Existing Volume IDs {0}".format(existing_vol_ids))

        ids_to_add = []
        vol_name_list = []
        vol_id_list = []

        for each_vol in vol_list:
            if each_vol:
                identifier_type = self.name_or_id(each_vol)
                if identifier_type == "ID" and not (each_vol in vol_id_list):
                    vol_id_list.append(each_vol)
                elif identifier_type == "NAME" and not (each_vol in vol_name_list):
                    vol_name_list.append(each_vol)

        """add volume by name"""
        for vol in vol_name_list:
            id = self.get_volume_id_by_name(vol)
            if id and (id not in existing_vol_ids):
                if id not in ids_to_add:
                    ids_to_add.append(id)
            else:
                msg = "Unable to add volume name {0}, either it doesn't" \
                      " exist or already in volume group ".format(vol)
                LOG.warn(msg)
                self.module.fail_json(msg=msg)

        """add volume by id"""
        for vol in vol_id_list:
            """verifying if volume id exists in array"""
            vol_by_id = self.get_volume_details_by_id(volume_id=vol)

            if vol_by_id not in existing_vol_ids:
                if vol_by_id not in ids_to_add:
                    ids_to_add.append(vol_by_id)
            else:
                msg = "Unable to add volume id {0}, either it doesn't" \
                      " exist or already in volume group ".format(vol)
                LOG.warn(msg)
                self.module.fail_json(msg=msg)

        LOG.debug("Volume IDs to add {0}".format(ids_to_add))

        if len(ids_to_add) == 0:
            return False

        try:
            self.provisioning.add_members_to_volume_group(
                vg_id, ids_to_add)

            return True
        except PowerStoreException as pe:
            errormsg = "Add existing volumes to volume group {0} " \
                       "failed with error {1}".format(vg_id, str(pe))
            LOG.error(errormsg)
            self.module.fail_json(msg=errormsg)

        except Exception as e:
            errormsg = "Add existing volumes to volume group {0} " \
                       "failed with error {1}".format(vg_id, str(e))
            LOG.error(errormsg)
            self.module.fail_json(msg=errormsg)

    def modify_volume_group(self, vg_id, vg_name, description,
                            is_write_order_consistent,
                            protection_policy_id):
        """Modify volume group"""
        try:
            LOG.info("Modifying volume group: {0}".format(
                vg_id))

            self.provisioning.modify_volume_group(
                vg_id, vg_name, description, is_write_order_consistent,
                protection_policy_id)

            LOG.info("Successfully modified volume group: {0}".format(
                vg_id))

            return True

        except PowerStoreException as pe:
            errormsg = "Modify volume group {0} failed with error {1}". \
                format(vg_id, str(pe))
            LOG.error(errormsg)
            self.module.fail_json(msg=errormsg)

        except Exception as e:
            errormsg = "Modify volume group {0} failed with error {1}".\
                format(vg_id, str(e))
            LOG.error(errormsg)
            self.module.fail_json(msg=errormsg)

    def is_volume_group_modified(self, volume_group,protection_policy):
        """Check if the desired volume group state is different from existing
        volume group"""
        modified = False

        if(('name' in volume_group and self.module.params['new_vg_name']
            is not None) and (volume_group['name'].lower() !=
                              self.module.params['new_vg_name'].lower())):
            modified = True
        elif((volume_group['description'] is not None and self.module.params[
            'description'] is not None and volume_group['description'].lower()
              != self.module.params['description'].lower()) or
             (volume_group['description'] is None and
              self.module.params['description'] is not None and
              self.module.params['description'].lower() != 'none')):
            modified = True
        elif(('protection_policy_id' in volume_group and
              protection_policy is not None and
              volume_group['protection_policy_id'] !=
              protection_policy) or
                ('protection_policy_id' not in volume_group and
                 protection_policy is not None and
                 protection_policy.lower() != 'none')):
            modified = True
        elif('is_write_order_consistent' in volume_group and
                self.module.params['is_write_order_consistent'] is not None
                and volume_group['is_write_order_consistent'] !=
                self.module.params['is_write_order_consistent']):
            modified = True

        return modified

    def create_volume_group(self, vg_name,
                            description,
                            protection_policy_id,
                            is_write_order_consistent):
        """Create a volume group"""
        try:
            LOG.info('Creating empty volume group {0} '.format(vg_name))
            resp = self.provisioning.create_volume_group(
                vg_name, description,
                protection_policy_id=protection_policy_id,
                is_write_order_consistent=is_write_order_consistent)
            return True, resp

        except PowerStoreException as pe:
            errormsg = "Failed to create volume group {0} with error {1}". \
                format(vg_name, str(pe))
            LOG.error(errormsg)
            self.module.fail_json(msg=errormsg)

        except Exception as e:
            errormsg = "Failed to create volume group {0} with error {1}".\
                format(vg_name, str(e))
            LOG.error(errormsg)
            self.module.fail_json(msg=errormsg)

    def get_protection_policy_id_by_name(self, name):
        """Get protection policy by name"""
        try:
            LOG.info('Getting the details of protection policy '
                     '{0}'.format(name))
            resp = self.protection.get_protection_policy_by_name(name)
            if None is resp or len(resp) <= 0:
                msg = 'No protection policy present with name {0}'.format(
                    name)
                LOG.error(msg)
                self.module.fail_json(msg=msg)
            else:
                LOG.info('Successfully got the protection policy '
                         'name {0}'.format(name))
                return resp[0]['id']

        except Exception as e:
            msg = 'Get details of protection policy name: {0} failed' \
                  ' with error : {1} '.format(name, str(e))
            LOG.error(msg)
            self.module.fail_json(msg=msg)

    def get_protection_policy_details_by_id(self, policy_id):
        """Get protection policy details by id"""

        try:
            LOG.info('Getting the details of protection policy by id'
                     ' {0}'.format(policy_id))
            resp = self.protection.get_protection_policy_details(
                policy_id=policy_id)
            if resp and len(resp) > 0:
                LOG.info('Successfully got the details of '
                         'protection policy id {0}'.format(policy_id))

                return resp['id']
            else:
                msg = 'No protection policy present with id {0}'.format(
                    policy_id)
                LOG.error(msg)
                self.module.fail_json(msg=msg)

        except Exception as e:
            msg = 'Get details of protection policy id: {0} failed' \
                  ' with error {1}'.format(policy_id, str(e))
            LOG.error(msg)
            self.module.fail_json(msg=msg)

    def name_or_id(self, val):
        """Determines if the string is a name or id"""
        try:
            UUID(str(val))
            LOG.info('{0} is a ID'.format(val))
            return "ID"
        except ValueError:
            LOG.info('{0} is a NAME'.format(val))
            return "NAME"

    def perform_module_operation(self):
        """
        Perform different actions on volume group based on user parameter
        chosen in playbook
        """

        vg_id = self.module.params['vg_id']
        state = self.module.params['state']
        vg_name = self.module.params['vg_name']
        volumes = self.module.params['volumes']
        vol_state = self.module.params['vol_state']
        new_vg_name = self.module.params['new_vg_name']
        description = self.module.params['description']
        protection_policy = self.module.params['protection_policy']
        is_write_order_consistent = self.module.params[
            'is_write_order_consistent']

        volume_group = None

        if not vg_name and not vg_id:
            self.module.fail_json(msg='Specify volume group name or '
                                      'volume group id')
        elif vg_name and vg_id:
            self.module.fail_json(msg='Specify volume group name or '
                                      'volume group id, not both')

        volume_group = self.get_volume_group_details(vg_id=vg_id, name=vg_name)
        LOG.debug('volume_group details: {0}'.format(volume_group))

        if protection_policy:
            prot_pol_identifier_type = self.name_or_id(protection_policy)
            if prot_pol_identifier_type == "ID":
                protection_policy = self.get_protection_policy_details_by_id(
                    protection_policy)
            if prot_pol_identifier_type == "NAME":
                protection_policy = self.get_protection_policy_id_by_name(
                    protection_policy)

        modified = False

        if volume_group:
            modified = self.is_volume_group_modified(volume_group,protection_policy)
            LOG.debug('Modified Flag: {0}'.format(modified))
        else:
            if not vg_name:
                self.module.fail_json(msg="vg_name is required to "
                                          "create a Volume Group")
            if new_vg_name:
                self.module.fail_json(msg="Invalid argument, "
                                          "new_vg_name is not required")
        if volumes and not vol_state:
            msg="vol_state must also be specified along with Volumes"
            LOG.error(msg)
            self.module.fail_json(msg=msg)

        if vg_id is None and volume_group:
            vg_id = volume_group['id']
        if vg_name is None and volume_group:
            vg_name = volume_group['name']

        result = dict(
            changed=False,
            create_vg='',
            modify_vg='',
            add_vols_to_vg='',
            remove_vols_from_vg='',
            delete_vg='',
            volume_group_details='',
        )

        if state == 'present' and not volume_group:
            LOG.info('Creating volume group {0}'.format(vg_name))
            result['create_vg'], resp = self.\
                create_volume_group(vg_name, description,
                                    protection_policy,
                                    is_write_order_consistent)
            result['volume_group_details'] = resp
            volume_group = self.get_volume_group_details(vg_id=resp['id'])
            vg_id = volume_group['id']
        elif state == 'absent' and volume_group:
            LOG.info('Deleting volume group {0}'.format(vg_id))
            result['delete_vg'] = self.delete_volume_group(vg_id)

        if state == 'present' and vol_state == 'present-in-group' and \
                volume_group and volumes:
            result['add_vols_to_vg'] = self.add_volumes_to_volume_group(
                vg_id, volumes)
        elif state == 'present' and vol_state == 'absent-in-group' and \
                volume_group and volumes:
            LOG.info('Remove existing volume(s) from volume group {0}'.
                     format(vg_id))
            result['remove_vols_from_vg'] = self.\
                remove_volumes_from_volume_group(vg_id, volumes)

        if state == 'present' and volume_group and modified:
            LOG.info("From Modify : {0}".format(protection_policy))
            result['modify_vg'] = self.modify_volume_group(
                 vg_id, new_vg_name, description, is_write_order_consistent,
                 protection_policy)

        if state == 'present' and volume_group:
            updated_vg = self.get_volume_group_details(vg_id=vg_id)
            result['volume_group_details'] = updated_vg

        if result['create_vg'] or result['modify_vg'] or result[
            'add_vols_to_vg'] or result['remove_vols_from_vg'] or \
                result['delete_vg']:
            result['changed'] = True

        self.module.exit_json(**result)

def get_powerstore_volume_group_parameters():
    return dict(
        vg_name=dict(required=False, type='str'),
        vg_id=dict(required=False, type='str'),
        new_vg_name=dict(required=False, type='str'),
        volumes=dict(required=False, type='list'),
        vol_state=dict(required=False, choices=['absent-in-group',
                                                'present-in-group'],
                       type='str'),
        state=dict(required=True, choices=['present', 'absent'], type='str'),
        description=dict(required=False, type='str'),
        is_write_order_consistent=dict(required=False, type='bool'),
        protection_policy=dict(required=False, type='str')
    )

def main():
    """Create PowerStore volume group object and perform action on it
        based on user input from playbook"""
    obj = PowerStoreVolumeGroup()
    obj.perform_module_operation()

if __name__ == '__main__':
    main()


import fileinput
from multiprocessing import Process
import os
import shutil
import sys

from node import Node
from observer import Observer
from utils import pipeName, Pipes

def createNode(node_id, money):
    n = Node(node_id, money)
    n.listen()

def createObserver():
    obs = Observer()
    obs.listen()
    pass

class Master:
    def __init__(self):
        self.nodes = dict()
        self.pipes = Pipes()
        self.observer = None

    def startMaster(self):
        # Setup pipes
        shutil.rmtree('./pipes', ignore_errors=True)
        os.mkdir('./pipes')

        # Create pipe between master and observer
        os.mkfifo(pipeName('master', 'observer'))
        os.mkfifo(pipeName('observer', 'master'))
        self.pipes.createPipe('master', 'observer', write=True, blocking=True)
        self.pipes.createPipe('observer', 'master', write=False, blocking=True)

        # Start observer
        self.observer = Process(target=createObserver)
        self.observer.start()

    def killAll(self):
        self.observer.terminate()
        for node in self.nodes.values():
            node.terminate()
        shutil.rmtree('./pipes', ignore_errors=True)
        sys.exit()

    def createNode(self, node_id, money):
        # Create pipe between master and node
        os.mkfifo(pipeName('master', node_id))
        os.mkfifo(pipeName(node_id, 'master'))
        self.pipes.createPipe('master', node_id, write=True, blocking=True)
        self.pipes.createPipe(node_id, 'master', write=False, blocking=True)

        # Create pipe from observer to node
        os.mkfifo(pipeName('observer', node_id))
        os.mkfifo(pipeName(node_id, 'observer')) # TODO not needed but need to change createPipe to be asymmetric

        # Start process
        p = Process(target=createNode, args=(node_id, money))
        p.start()

        # Create inter-node pipes
        msg = 'CreateNode {}'.format(node_id)
        self.pipes.sendMessage('master', 'observer', msg)

        response = self.pipes.receiveMessage('observer', 'master')
        if (response != 'ack'):
            raise RuntimeError('Expected \'ack\', received {}'.format(response))

        for neighbor_id in self.nodes.keys():
            os.mkfifo(pipeName(node_id, neighbor_id))
            os.mkfifo(pipeName(neighbor_id, node_id))

            msg = 'CreateNode {}'.format(node_id)
            self.pipes.sendMessage('master', neighbor_id, msg)

            response = self.pipes.receiveMessage(neighbor_id, 'master')
            if (response != 'ack'):
                raise RuntimeError('Expected \'ack\', received {}'.format(response))

            msg = 'CreateNode {}'.format(neighbor_id)
            self.pipes.sendMessage('master', node_id, msg)

            response = self.pipes.receiveMessage(node_id, 'master')
            if (response != 'ack'):
                raise RuntimeError('Expected \'ack\', received {}'.format(response))

        self.nodes[node_id] = p

    def send(self, send_id, recv_id, val):
        msg = 'Send {} {}'.format(recv_id, val)
        self.pipes.sendMessage('master', send_id, msg)

        response = self.pipes.receiveMessage(send_id, 'master')
        if (response != 'ack'):
            raise RuntimeError('Expected \'ack\', received {}'.format(response))

    def receive(self, recv_id, send_id=''):
        msg = 'Receive {}'.format(send_id)
        self.pipes.sendMessage('master', recv_id, msg)

        response = self.pipes.receiveMessage(recv_id, 'master')
        if (response != 'ack'):
            raise RuntimeError('Expected \'ack\', received {}'.format(response))

    def receiveAll(self):
        msg = 'ReceiveAll'
        received = True
        while received:
            received = False
            for node_id in sorted(self.nodes.keys()):
                self.pipes.sendMessage('master', node_id, msg)
                response = self.pipes.receiveMessage(node_id, 'master')

                if ('ack' not in response):
                    raise RuntimeError('Expected \'ack\', received {}'.format(response))
                if 'True' in response:
                    received = True

    def beginSnapshot(self, node_id):
        msg = 'BeginSnapshot {}'.format(node_id)
        self.pipes.sendMessage('master', 'observer', msg)

        response = self.pipes.receiveMessage('observer', 'master')
        if (response != 'ack'):
            raise RuntimeError('Expected \'ack\', received {}'.format(response))

        self.receive(node_id, send_id='observer')

    def collectState(self):
        msg = 'CollectState'
        self.pipes.sendMessage('master', 'observer', msg)

        # TODO sort?
        for node_id in sorted(self.nodes.keys()):
            response = self.pipes.receiveMessage('observer', 'master')
            if (response != f'ack {node_id}'):
                raise RuntimeError('Expected \'ack {}\', received {}'.format(node_id, response))
            self.receive(node_id, send_id='observer')

        response = self.pipes.receiveMessage('observer', 'master')
        if (response != 'ack'):
            raise RuntimeError('Expected \'ack\', received {}'.format(response))

    def printSnapshot(self):
        msg = 'PrintSnapshot'
        self.pipes.sendMessage('master', 'observer', msg)

        response = self.pipes.receiveMessage('observer', 'master')
        if (response != 'ack'):
            raise RuntimeError('Expected \'ack\', received {}'.format(response))

def run(master):
    for line in fileinput.input():
        args = line.split()
        cmd = args[0]
        for idx in range(1, len(args)):
            args[idx] = int(args[idx])

        if cmd == 'StartMaster':
            master.startMaster()
        elif cmd == 'KillAll':
            master.killAll()
        elif cmd == 'CreateNode':
            node_id = args[1]
            money = args[2]
            master.createNode(node_id, money)
        elif cmd == 'Send':
            send_id = args[1]
            recv_id = args[2]
            money = args[3]
            master.send(send_id, recv_id, money)
        elif cmd == 'Receive':
            recv_id = args[1]
            send_id = args[2] if len(args) > 2 else ''
            master.receive(recv_id, send_id)
        elif cmd == 'ReceiveAll':
            master.receiveAll()
        elif cmd == 'BeginSnapshot':
            node_id = args[1]
            master.beginSnapshot(node_id)
        elif cmd == 'CollectState':
            master.collectState()
        elif cmd == 'PrintSnapshot':
            master.printSnapshot()
        else:
            raise ValueError('Command not supported: ' + line)

if __name__ == '__main__':
    master = Master()
    run(master)