"""
Find tags from:
    - a static image
    - a pre-recorded video
    - a web cam (opencv)
    - a picamera (on a pi)

Allow setting of detector parameters from command line
find_tags.py <source:fn, opencv:n, picamera>
    {-p parametername=value}  # detection parameters
    {-s setting=value}  # camera settings [only for picamera]
    {-h}  # run headless [no gui, wait for end of frames or KeyboardInterrupt]

Print out stats:
    - how many tags found (% of frames)
    - size distribution of tags
    - time to detect tags
"""

import argparse
import time

import cv2
import numpy

try:
    import picamera
    import picamera.array
    has_picamera = True
except ImportError:
    has_picamera = False

class Source:
    def __iter__(self):
        return

class ImageSource(Source):
    def __init__(self, fn):
        self.fn = fn

    def __iter__(self):
        yield cv2.imread(self.fn, cv2.IMREAD_GRAYSCALE)

class VideoSource(Source):
    def __init__(self, video_id):
        self.cap = cv2.VideoCapture(video_id)

    def __iter__(self):
        while True:
            r, im = self.cap.read()
            if not r:
                break
            yield cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)

def convert_resolution(v):
    if isinstance(v, str):
        for sep in ',xX \t':
            tks = v.split(sep)
            if len(tks) == 2:
                break
        if len(tks) != 2:
            raise ValueError("Unknown resolution format: %s" % v)
        w, h = int(tks[0]), int(tks[1])
    else:
        w, h = v
    if (w % 32) or (h % 16):
        w = (w // 32) * 32
        h = (h // 16) * 16
    return w, h

class PiCameraSource(Source):
    _special_settings = {
        'resolution': convert_resolution,
    }
    def __init__(self):
        if not has_picamera:
            raise RuntimeError("picamera is not available")
        self.cam = picamera.PiCamera()

    def configure(self, **settings):
        if not len(settings):
            return
        print("Setting picamera settings...")
        for k in settings:
            if k in self._special_settings:
                v = self._special_settings[k](settings[k])
            else:
                t = type(getattr(self.cam, k))
                v = t(settings[k])  # convert new setting to correct type
            print("\t%s = %s" % (k, v))
            setattr(self.cam, k, v)

    def __iter__(self):
        # make destination buffer
        w, h = self.cam.resolution
        im = numpy.empty((h, w, 3), dtype='uint8')
        while True:
            self.cam.capture(im, 'yuv', use_video_port=True)
            yield im[:, :, 0]

def make_source(source):
    if '.' in source:  # fn: image or video
        ext = source.split('.')[-1].lower()
        if ext in ('avi', 'mjpeg', 'mjpg', 'mpg', 'h264'):
            return VideoSource(source)
        else:
            return ImageSource(source)
    elif source == 'picamera':  # picamera
        if not has_picamera:
            raise RuntimeError("picamera is not available")
        return PiCameraSource()
    elif 'camera' in source:  # opencv cap
        if ':' in source:
            _, vid_id = source.split(':')
            vid_id = int(vid_id)
        else:
            vid_id = -1
        return VideoSource(vid_id)
    else:  # unknown source
        raise ValueError("Unknown source: %s" % source)

class TagFinder:
    def __init__(self, tag_dictionary=None, **kwargs):
        if tag_dictionary is None:
            tag_dictionary = '4X4_50'
        if isinstance(tag_dictionary, str):
            if 'DICT' not in tag_dictionary:
                tag_dictionary = "DICT_%s" % tag_dictionary
            tag_dictionary = tag_dictionary.upper()
            if not hasattr(cv2.aruco, tag_dictionary):
                raise ValueError("Unknown tag dictionary: %s" % tag_dictionary)
            tag_dictionary = getattr(cv2.aruco, tag_dictionary)
        self.aruco_dict = cv2.aruco.getPredefinedDictionary(tag_dictionary)
        self.aruco_params = cv2.aruco.DetectorParameters_create()
        if len(kwargs):
            print("Setting parameters...")
        for kw in kwargs:
            if not hasattr(self.aruco_params, kw):
                raise ValueError("Unknown parameter: %s" % kw)
            t = type(getattr(self.aruco_params, kw))  # get type to convert to
            v = t(kwargs[kw])
            setattr(self.aruco_params, kw, v)
            print("\t%s to %s" % (kw, v))
        self.reset_stats()

    def reset_stats(self):
        self.n_frames = 0
        self.dts = 0
        self.n_tags = 0
        self.areas_min = numpy.inf
        self.areas_max = -numpy.inf
        self.areas_sum = 0

    def process_grayscale_image(self, im):
        #im = a[:, :, 0]  # take y component
        t0 = time.monotonic()
        self.tags_results = cv2.aruco.detectMarkers(
            im, self.aruco_dict, parameters=self.aruco_params)
        t1 = time.monotonic()
        self.dts += t1 - t0
        nt = len(self.tags_results[0])
        if nt:
            self.n_tags += nt
            # compute tag areas
            areas = numpy.array([
                cv2.contourArea(tag_pts) for tag_pts in self.tags_results[0]])
            self.areas_sum += numpy.sum(areas)
            self.areas_min = min(self.areas_min, areas.min())
            self.areas_max = max(self.areas_max, areas.max())
        self.n_frames += 1

    def print_stats(self, short=False):
        if not short:
            print("Parameters:")
            for attr in sorted(dir(self.aruco_params)):
                if attr[0] == '_' or attr == 'create':
                    continue
                print("\t%s=%s" % (attr, getattr(self.aruco_params, attr)))
            print("===")
        print("Processed %s frames" % (self.n_frames, ))
        if self.n_frames == 0:
            return
        print("Averages...")
        print("\t%0.4f seconds to detect tags" % (self.dts / self.n_frames, ))
        print("\t%0.2f average tags per frame" % (self.n_tags / self.n_frames, ))
        if self.n_tags:
            print("\t%0.2f minimum tag area" % (self.areas_min, ))
            print("\t%0.2f maximum tag area" % (self.areas_max, ))
            print("\t%0.2f average tag area" % (self.areas_sum / self.n_tags, ))

def draw_tags(im, tags_results):
    canvas = cv2.cvtColor(im, cv2.COLOR_GRAY2BGR)
    # candidate tags
    for pts in tags_results[2]:
        cv2.polylines(canvas, pts.astype('int32'), False, (0, 0, 255), 3)
    if not len(tags_results[0]):
        return canvas
    # mark tags
    cv2.aruco.drawDetectedMarkers(canvas, tags_results[0], tags_results[1])
    return canvas

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument(
        "source",
        help="Video/image source, can be: 'camera', 'picamera', or a filename")
    parser.add_argument(
        "-d", "--downsample", default=1, type=int,
        help="Downsample image by selecting every N-th pixel before display")
    parser.add_argument(
        "-H", "--headless", default=False, action="store_true",
        help="Run without GUI to show images and tag finding results")
    parser.add_argument(
        "-p", "--parameter", default=[], action="append",
        help="Detection parameters as key=value (ie detectInvertedMarker=True)")
    parser.add_argument(
        "-s", "--setting", default=[], action="append",
        help="picamera specific settings as key=value, where key is an attribute of the PiCamera class")
    parser.add_argument(
        "-t", "--tag_dictionary", default=None, type=str,
        help="Tag dictionary (as it appears in cv2.aruco)")

    args = parser.parse_args()

    # make image source
    source = make_source(args.source)
    if isinstance(source, PiCameraSource) and len(args.setting):
        settings = {}
        for s in args.setting:
            if "=" not in s:
                raise ValueError("Invalid setting missing '=': %s" % s)
            k, v = s.split("=")
            settings[k] = v
        source.configure(**settings)

    # make detector
    parameters = {}
    for p in args.parameter:
        if "=" not in p:
            raise ValueError("Invalid parameter missing '=': %s" % p)
        k, v = p.split("=")
        parameters[k] = v
    tf = TagFinder(args.tag_dictionary, **parameters)

    try:
        for im in source:
            tf.process_grayscale_image(im)
            if args.headless:
                if tf.n_frames % 5 == 0:
                    tf.print_stats(short=True)
            else:
                canvas = draw_tags(im, tf.tags_results)
                cv2.imshow('win', canvas[::args.downsample, ::args.downsample])
                k = cv2.waitKey(30)
                if k == ord('q'):
                    raise KeyboardInterrupt
                elif k == ord('r'):
                    print("Resetting stats")
                    tf.reset_stats()
                elif k == ord('p'):
                    tf.print_stats()
        # no images left, sit on last frame after printing stats
        tf.print_stats()
        while True:
            if cv2.waitKey(30) == ord('q'):
                raise KeyboardInterrupt
    except KeyboardInterrupt:
        tf.print_stats()

if __name__ == '__main__':
    main()


"""
1) Write code that asks the user for their name,
then opens a file called "name.txt" and writes
that name to it. Remember to close your file.

2) Write code that opens "name.txt" and reads the
name (as above) then prints, "Your name is Bob"
(or whatever the name is in the file)

3) Create a text file called numbers.txt and save
it in your prac directory. Put the following three
numbers on separate lines in the file and save it:
17
42
400
Write code that opens "numbers.txt", reads only the
first two numbers and adds them together then prints
the result, which should be... 59.

4) Now write a fourth block of code that prints the
total for all lines in numbers.txt or a file with
any number of numbers.
"""

# Task 1
FILENAME = "name.txt"
name = input("Enter your name: ")
out_file = open(FILENAME, "w")

# Task 2
print(f"Your name is: {name}", file=out_file)
out_file.close()

# Task 3
in_file = open("numbers.txt", "r")
number1 = int(in_file.readline())
number2 = int(in_file.readline())
print(number1 + number2)

in_file.close()


#Resumen del py :
#1. Leer datos: Leer archivo .csv (origen de datos)
#2. Extraer el resumen solicitado, para este caso es la cantidad de valores unicos de todas las columnas
#3. Guardar el resumen en formato csv.

from pkgutil import get_data

import numpy as np
import pandas as pd
import os
from pathlib import Path
from dateutil.parser import parse
bucket='gs://hd_bucket_llamadas123/'
import logging

def main():
    #Configuracion logs:
    log_fmt = '%(asctime)s - %(name)s - %(levelname)s - [%(filename)s:%(lineno)d] - %(message)s'
    logging.captureWarnings(True)
    logging.basicConfig(level=logging.INFO, format=log_fmt, filename='/home/jupyter/ESEIT2022_BDATA_2022b/data/logs/etl_llamadas.log')

    #Leer Archivo
    data=get_data("llamadas123_agosto_2022.csv")
    #Hacerle tratamiento
    df_archivo = tratamiento(data)
    #Guardar Resumen
    save_data(df_archivo, filename="llamadas123_agosto_2022.csv")

    logging.info ('DONE!!!')

def save_data(df, filename):
    #root_dir=Path(".").resolve()
    out_name = 'limpio_' + filename
    out_path = os.path.join(bucket, 'data','processed',out_name)
    df.to_csv(out_path)

    #Guardar Tabla en BigQuery
    print("Cargando archivo :",filename)
    df.to_gbq(destination_table='espbigdata.llamadas_123', if_exists='append')

def convertir_fecha(str_fecha):
    date_fecha=parse(str_fecha, dayfirst =True)
    return date_fecha

def corregir_fecha (data):
    list_fechas = list()
    n_filas = data.shape[0]
    for i in range(0, n_filas):
        str_fecha = data["RECEPCION"][i]
        try:
            val_datetime = convertir_fecha(str_fecha= str_fecha)
            list_fechas.append(val_datetime)
        except Exception as e:
            list_fechas.append(str_fecha)
        continue

    data["RECEPCION_CORREGIDA"] = list_fechas
    data["RECEPCION_CORREGIDA"] = pd.to_datetime(data["RECEPCION_CORREGIDA"], errors = "coerce")
    data["RECEPCION"] = data["RECEPCION_CORREGIDA"]
    data = data.drop(["RECEPCION_CORREGIDA"], axis=1)

def tratamiento(data):
    #Borrando duplicados
    df_data = data.drop_duplicates()
    #Reemplace en la columna unidad los nulos por SIN_DATO (columna NaN)
    df_data['UNIDAD'].fillna('SIN DATO').value_counts(dropna=False)
    #Reemplazar SIN_DATO por un nulo de tipo numerico
    df_data['EDAD'].replace({'SIN_DATO' : np.nan}).value_counts
    # Convertir columna en formato fecha
    col = "FECHA_INICIO_DESPLAZAMIENTO_MOVIL"
    data[col] = pd.to_datetime(data[col], errors = "coerce")
    #Reemplazar las localidades que tienen caracteres especiales
    data['LOCALIDAD']= data['LOCALIDAD'].replace(['Fontib¢n','Engativ ',"Ciudad Bol¡var","Usaqun","San Crist¢bal","Los M rtires","Antonio Nari¤o"],['Fontibon','Engativa',"Ciudad Bolivar","Usaquen","San Cristobal", "Los Martires","Antonio Nariño"])
    #corregir la fecha de recepcion
    corregir_fecha(data)
    return df_data

def get_data (filename):
    logger=logging.getLogger('get_data')
    #data_dir = 'raw'
    #root_dir=Path(".").resolve()
    #file_path=os.path.join(root_dir,"data",data_dir,filename)
    dir_data= os.path.join(bucket,"data","raw")
    logger.info(f'Reading File: {dir_data}')
    data = pd.read_csv(os.path.join(dir_data,filename), encoding='latin-1', sep =';')
    logger.info(f'La Tabla contiene: {data.shape[0]} filas y {data.shape[1]} columnas')
    return data

if __name__ == '__main__':
    main()


from openerp import models, fields, api
from datetime import datetime, timedelta
from dateutil.relativedelta import relativedelta

class TrobzPayrollWageHistoryReport(models.TransientModel):

    _name = 'trobz.payroll.wage.history.report'
    _description = 'Trobz Payroll Wage History Report'

    to_date = fields.Date(string='To Date', default=fields.Date.today())
    from_date = fields.Date(string='From Date',
                            default=lambda g:
                            (datetime.now() +
                             relativedelta(months=-12)).strftime('%Y-%m-%d'))
    department_id = fields.Many2one('hr.department', string='Department')
    job_id = fields.Many2one('hr.job', string='Job Title')
    # for one or many Employees
    employee_ids = fields.Many2many('hr.employee', string='Employee')
    order_by = fields.Selection(string='Order By',
                                selection=[('effective_date DESC',
                                            'Effective Date Descending'),
                                           ('cur_wage DESC',
                                            'Current Wage Descending'),
                                           ('percentage DESC',
                                            'Percentage Descending'),
                                           ],
                                default='cur_wage DESC')

    @api.multi
    def get_print_report(self):
        domain = [('effective_date', '>=', self.from_date),
                  ('effective_date', '<=', self.to_date),
                  ('employee_id', 'in', self.employee_ids.ids),
                  ('department_id', '=', self.department_id.id),
                  ('job_id', '=', self.job_id.id)]
        for report in self:
            """
                context is frozendict -> skip_invert = False to insert new Val
            """
            list_view = self.env.ref(
                'trainingwagekp.payroll_wage_hist_wizard_tree_view')
            self.env.context = self.with_context(skip_invert=False).env.context
            context = self._context.copy()
            if not context:
                context = {}
    #       Passing context value for Return Action window
            context.update({'group_by': ['department_id', 'job_id'],
                            'order_by': report.order_by})

    #         recordset = self.with_context(context)

            action = {'name': 'Wage History Report',
                      'type': 'ir.actions.act_window',
                      'view_type': 'form',
                      'view_mode': 'tree',
                      'view_id': list_view.id,
                      'res_model': 'trobz.payroll.wage.history',
                      'context': context,
                      'domain': domain,
                      }
            return action


"""Simulates the 'Ride the Bus' Game"""

import carddeck

def rtb_round1():
    """Round one of Ride the Bus: Black or Red"""
    global win_state
    card = deck.cards.pop()
    #   Assign a color based on suit
    if card.suit == 'spades' or card.suit == 'clubs':
        color = 'black'
    else:
        color = 'red'
    #   Play round
    active = True
    while active:
        guess = input("Guess a color: Black or Red? \n\t")
        guess = guess.lower()
        if guess != 'black' and guess != 'red':
            print("That's not a valid entry. Please guess again.")
        elif guess == color:
            card.show()
            print("That's right! Moving on...")
            round_cards.append(card)
            win_state = True
            active = False
        elif guess != color:
            card.show()
            print("That's incorrect. Restarting...")
            active = False

def rtb_round2():
    """Round two of Ride the Bus: Higher or Lower"""
    global win_state
    card = deck.cards.pop()
    print("Round 2:")
    active = True
    #   Play round
    while active:
        guess = input(f"Higher or lower than {round_cards[0].value}?\n\t")
        guess = guess.lower()
        if guess != 'lower' and guess != 'higher':
            print("That's not a valid entry. Please guess again.")
        elif (guess == 'lower' and card.value < round_cards[0].value or
                guess == 'higher' and card.value > round_cards[0].value):
            card.show()
            print("Correct! Moving on...")
            round_cards.append(card)
            active = False
        elif card.value == round_cards[0].value:
            card.show()
            print("It's a tie! You lose. Restarting...")
            win_state = False
            active = False
        else:
            card.show()
            print("Incorrect! Restarting...")
            win_state = False
            active = False

def rtb_round3():
    """Round three of Ride the Bus: In Between or Outside"""
    global win_state
    card = deck.cards.pop()
    #   Build a list of values from rounds 1 and 2
    c_values = []
    for c in round_cards:
        c_values.append(c.value)
    #   Make sure list is low - high
    c_values = sorted(c_values)
    print("Round 3:")
    #   Play round
    active = True
    while active:
        guess = input(f"Inside or outside of {c_values[0]} and {c_values[1]}\n\t")
        guess = guess.lower()
        if guess != 'inside' and guess != 'outside':
            print("That's not a valid entry. Please guess again.")
        elif (guess == 'inside' and card.value > c_values[0] and
                card.value < c_values[1]):
            card.show()
            print("Correct! Moving on...")
            round_cards.append(card)
            active = False
        elif (guess == 'outside' and card.value < c_values[0] or
                card.value > c_values[1]):
            card.show()
            print("Correct! Moving on...")
            round_cards.append(card)
            active = False
        else:
            card.show()
            print("Incorrect! Restarting...")
            win_state = False
            active = False

def rtb_round4():
    """Round 4 of Ride the Bus: Suit"""
    global win_state
    card = deck.cards.pop()
    print("Round 4:")
    #   Play round
    active = True
    while active:
        guess = input("Guess a suit.\n\t")
        guess = guess.lower()
        if guess not in ['spades', 'hearts', 'clubs', 'diamonds']:
            print("That's not a valid entry. Please guess again")
        elif guess == card.suit:
            card.show()
            print("Correct!")
            round_cards.append(card)
            active = False
        elif guess != card.suit:
            card.show()
            print("Incorrect! Restarting...")
            win_state = False
            active = False

deck = carddeck.Deck()
deck.shuffle()
round_cards = []
win_state = False
rtb_round1()
if win_state == True:
    rtb_round2()
else:
    pass
if win_state == True:
    rtb_round3()
else:
    pass
if win_state == True:
    rtb_round4()
else:
    pass
if win_state == True:
    print("Congratulations! You won!")


import itertools

piles=[2,4,1,2,7,8]

def maxCoins(piles):
    #sorting
    piles=sorted(piles, reverse=True)
    l=len(piles)

    #num of choices
    cnt=l//3
    ans=0

    for i in range(cnt):
        print(piles[(2*i)+1])
        ans+=piles[(2*i)+1]
    return ans

print(maxCoins(piles))


file = open('geek.txt','w')
file.write("This is the write command")
file.write("\nIt allows us to write in a particular file")
file.close()

# Python code to illustrate append() mode
file = open('geek.txt','a')
file.write("\nThis will add this line")
file.close()

# Python code to illustrate split() function
with open("geek.txt", "r") as file:
    data = file.readlines()
    for line in data:
        word = len(line)
        print (word)
file.close()


import os
import io
import csv
import re

########################################################
#                                                      #
#                Author: Noel Conlisk                  #
#               Email: noecon@gmail.com                #
#    Script function: Using Stress data and model      #
#         geometry information this script builds a    #
#    vtk version of the model with stresses included   #
#                                                      #
#    Prerequisites: An .rpt file with stresses and     #
#   the corresponding Abaqus .inp format model file    #
#                                                      #
########################################################

# Find all Abaqus .odb files in the directory and put them in a list
path = 'F:\\Modelling_files\\SoFIA3\\test_conversion'
# path = raw_input('input path to .odb file: ')
target_files = [f for f in os.listdir(path) if f.endswith('edited.inp')]
a = int(len(target_files))

# Load up .csv file and creates a dictionary where patient name is the key
# and a tuple of the x, y, z coordinates is the value
custom_offsets_file = 'F:\\Modelling_files\\origin_offsets2.csv'
custom_offsets = open((custom_offsets_file), 'r')
lines = csv.reader(custom_offsets, delimiter='\t')
offset = {}

for l in lines:
    pat_id = l[0]
    delta_x = l[1]
    delta_y = l[2]
    delta_z = l[3]
    offset[pat_id] = delta_x, delta_y, delta_z

# Main loop

for i in range(0, a):
    jobfile = target_files[i]
    patient_ID = jobfile.split('.inp')[0]
    filename = path+'\\'+jobfile

    # THIS SECTION PLACES EACH LINE OF THE FILE CORRESPONDING TO THE NODAL
    # COORDINATES INTO A LIST:
    nodes = []
    elements = []
    with open(filename, 'r') as file:
        for lines in file:
            #this next line uses a regular expression to extract the line
            # featuring the current node only when it conforms to the following
            # pattern node id, x, y, z. note that \s* matches zero or more
            # whitespaces,\d matches digits, \d+\.\d+ matches floats. This
            # eliminates the program accidently picking up occurances of the
            # node later when connectivity is being described.
            nodal_lines=re.match(r'^\s*\d+,+\s+\d+\.\d+,+\s+\S+\s+\S+\s+$',lines)
            #could simplify this expression
            if nodal_lines:
                nodes.append(lines)
            # as with the nodes \s* matches zero or more whitespace values.
            element_lines = re.match(r'\s*\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+$',lines)
            if element_lines:
                elements.append(lines)
    file.close()

# The above code will give both nodal and element definitions from a .inp file.
# however, regional part labels are not preserved and so the .vtk file will be
# a single continuous mesh. - NEXT GOAL IS PRESERVE LABELS.

# This is format to get rid of first column "nodes[0].split(',')[1:]"
# Similarly to get first column to use as ID "nodes[0].strip().split(',')[0]"

    with open(patient_ID + '_realigned.vtk', 'w') as outFile:
        # write vtk header
        outFile.write('# vtk DataFile Version 3.0')
        outFile.write('\nvtk output')
        outFile.write('\nASCII')
        outFile.write('\nDATASET UNSTRUCTURED_GRID')

        # write points

        numNodesTotal = len(nodes)

        outFile.write('\n\nPOINTS ' + str(numNodesTotal) + ' float\n')

        # Checks if the current patient id is in the dictionary and if so
        # retrives the correct offset values in each direction and converts
        # them to a float.

        current_pat_id = patient_ID.split('_')[0]

        if current_pat_id in offset:
            delta_x = float(offset[current_pat_id][0])
            delta_y = (float(offset[current_pat_id][1]))/10.
            # Divides by 10 to correct y offset.
            delta_z = float(offset[current_pat_id][2])

        # Extracts and reformats nodes applying above offsets.
        for i in range(len(nodes)):
            curNode = nodes[i]
            node_coords = curNode.split(',')[1:]
            for a in range(3):
                if a == 0:
                    # this block inverts sign of y coordinates
                    # and corrects translations from vascops export error.
                    current_value = float(node_coords[a])
                    new_coord = current_value + delta_x
                    fix_x_direction = new_coord*1
                    coords_new = str(fix_x_direction)
                    node_coords1 = '     '+coords_new+''
                    outFile.write(node_coords1)
                elif a == 1:
                    current_value = float(node_coords[a])
                    new_coord = current_value + delta_y
                    fix_y_direction = new_coord*-1
                    coords_new = str(fix_y_direction)
                    node_coords1 = '     '+coords_new+''
                    outFile.write(node_coords1)
                else:
                    current_value = float(node_coords[a])
                    new_coord = current_value + delta_z
                    fix_z_direction = new_coord*1
                    coords_new = str(fix_z_direction)
                    node_coords1 = '     '+coords_new+'\n'
                    outFile.write(node_coords1)

        # write cells

        numElementsTotal = len(elements)
        # eltype = len(elements[0])

        eltype = 8
        # COULD IMPROVE BY LETTING SCRIPT AUTOMATICALLY DETECT ELEMENT TYPE.

        if eltype == 4:
            # linear tet
            vtk_el_ID = 10

        elif eltype == 10:
            # quad tet
            vtk_el_ID = 24

        elif eltype == 8:
            # quad brick
            vtk_el_ID = 12

        param = eltype + 1

        outFile.write('\n\nCELLS ' + str(numElementsTotal) + ' ' + str(numElementsTotal * param)+'\n')

        for j in range(len(elements)):
            # following line removes whitespace in the string
            el_no_space = "".join(elements[j].split())
            # this line searches the string for possible integers
            el_list = [int(i) for i in el_no_space.split(',')]
            # this line takes all ints except for the first row
            # which is the element ID
            curElement = el_list[1:]
            # this line writes out the vtk element ID as the first row
            outFile.write(str(eltype)+' ')
            # this loop then writes out the connetivity as the remaining rows
            for i in range(eltype):
                el_number = curElement[i] - 1
                # minus 1 as node numbering from 0 in vtk and 1 in abaqus
                outFile.write(str(el_number)+' ')
            outFile.write('\n')

        # cell types

        outFile.write('\n\nCELL_TYPES ' + str(numElementsTotal))

        for i in range(numElementsTotal):
            cell_type = '\n' + str(vtk_el_ID)
            outFile.write(cell_type)

        # write cell data

        outFile.write('\n\nCELL_DATA ' + str(numElementsTotal))

        # write point data

        outFile.write('\n\nPOINT_DATA ' + str(numNodesTotal))

        # UPDATE BELOW SECTION TO IMPORT STRESS VALUES FROM MODIFIED RPT FILE
        # REPLACE PARAMS WITH REGEX TO FILTER RPT FILE TO JUST VALUES
        # THEN USE CSV READER TO IMPORT COLUMNS
        # ALSO ADJUST NODES TO VTK FORMAT

        # The next line sets up an empty dictionary for the
        # extracted stress values.
        stress_values = {}

        nodal_file = patient_ID + '_unique_nodal.rpt'
        with open(path + '\\' + nodal_file, 'r') as stresses_rpt:
            for lines in stresses_rpt:
                value_lines = re.match(r'^\s*\d+\s+\S+\s+$', lines)
                # issue is handling exponential numbers
            if value_lines:
                node = lines.split()[0]
                key = int(node) - 1
                # convert node numbering to vtk from abaqus
                value = lines.split()[1]
                stress_values.setdefault(key, [])
                stress_values[key].append(value)
            else:
                print('no values found')
        stresses_rpt.close()

        # Converting dict contents to VTK format and add point data header.

        print(patient_ID)

        size = len(stress_values)
        print(size)

        outFile.write('\nSCALARS MISES double')
        outFile.write('\nLOOKUP_TABLE default\n')
        for i in range(0, size):
            key_label = i
            print(key_label)
        if len(stress_values[key_label]) == 1:
            nodal_mises_stress = stress_values[key_label][0]
            outFile.write(str(nodal_mises_stress) + ' ')
        else:
            new_value1 = stress_values[key_label][0]
            new_value2 = stress_values[key_label][1]
            avg_stress = (float(new_value1) + float(new_value2))/2.0
            outFile.write(str(avg_stress) + ' ')

        # Need to modify the above to allow multiple values to be recognised
        # as belonging to a single point.
        # Can we just write out a list association as point data?

        outFile.close()


from typing import Optional

import copy
import re
import sys
import gzip
import traceback

import six
import orjson
import jsonschema
from oslo_config import cfg
from six.moves import http_client
from mongoengine.queryset.visitor import Q

from st2api.controllers.base import BaseRestControllerMixin
from st2api.controllers.resource import ResourceController
from st2api.controllers.resource import BaseResourceIsolationControllerMixin
from st2api.controllers.v1.execution_views import ExecutionViewsController
from st2api.controllers.v1.execution_views import SUPPORTED_FILTERS
from st2common import log as logging
from st2common.constants import action as action_constants
from st2common.exceptions import actionrunner as runner_exc
from st2common.exceptions import apivalidation as validation_exc
from st2common.exceptions import param as param_exc
from st2common.exceptions import trace as trace_exc
from st2common.models.api.action import LiveActionAPI
from st2common.models.api.action import LiveActionCreateAPI
from st2common.models.api.base import cast_argument_value
from st2common.models.api.execution import ActionExecutionAPI
from st2common.models.db.auth import UserDB
from st2common.persistence.liveaction import LiveAction
from st2common.persistence.execution import ActionExecution
from st2common.persistence.execution import ActionExecutionOutput
from st2common.router import abort
from st2common.router import Response
from st2common.router import NotFoundException
from st2common.services import action as action_service
from st2common.services import executions as execution_service
from st2common.services import trace as trace_service
from st2common.util import isotime
from st2common.util import action_db as action_utils
from st2common.util import param as param_utils
from st2common.util.jsonify import try_loads
from st2common.rbac.types import PermissionType
from st2common.rbac.backends import get_rbac_backend

__all__ = ["ActionExecutionsController"]

LOG = logging.getLogger(__name__)

# Note: We initialize filters here and not in the constructor
SUPPORTED_EXECUTIONS_FILTERS = copy.deepcopy(SUPPORTED_FILTERS)
SUPPORTED_EXECUTIONS_FILTERS.update(
    {"timestamp_gt": "start_timestamp.gt", "timestamp_lt": "start_timestamp.lt"}
)

MONITOR_THREAD_EMPTY_Q_SLEEP_TIME = 5
MONITOR_THREAD_NO_WORKERS_SLEEP_TIME = 1

class ActionExecutionsControllerMixin(BaseRestControllerMixin):
    """
    Mixin class with shared methods.
    """

    model = ActionExecutionAPI
    access = ActionExecution

    # Those two attributes are mandatory so we can correctly determine and mask secret execution
    # parameters
    mandatory_include_fields_retrieve = [
        "action.parameters",
        "action.output_schema",
        "runner.runner_parameters",
        "runner.output_key",
        "parameters",
        # Attributes below are mandatory for RBAC installations
        "action.pack",
        "action.uid",
        # Required when rbac.permission_isolation is enabled
        "context",
    ]

    # A list of attributes which can be specified using ?exclude_attributes filter
    # NOTE: Allowing user to exclude attribute such as action and runner would break secrets
    # masking
    valid_exclude_attributes = ["result", "trigger_instance", "status"]

    def _handle_schedule_execution(
        self, liveaction_api, requester_user, context_string=None, show_secrets=False
    ):
        """
        :param liveaction: LiveActionAPI object.
        :type liveaction: :class:`LiveActionAPI`
        """
        if not requester_user:
            requester_user = UserDB(name=cfg.CONF.system_user.user)

        # Assert action ref is valid
        action_ref = liveaction_api.action
        action_db = action_utils.get_action_by_ref(action_ref)

        if not action_db:
            message = 'Action "%s" cannot be found.' % (action_ref)
            LOG.warning(message)
            abort(http_client.BAD_REQUEST, message)

        # Assert the permissions
        permission_type = PermissionType.ACTION_EXECUTE
        rbac_utils = get_rbac_backend().get_utils_class()
        rbac_utils.assert_user_has_resource_db_permission(
            user_db=requester_user,
            resource_db=action_db,
            permission_type=permission_type,
        )

        # Validate that the authenticated user is admin if user query param is provided
        user = liveaction_api.user or requester_user.name
        rbac_utils.assert_user_is_admin_if_user_query_param_is_provided(
            user_db=requester_user, user=user
        )

        try:
            return self._schedule_execution(
                liveaction=liveaction_api,
                requester_user=requester_user,
                user=user,
                context_string=context_string,
                show_secrets=show_secrets,
                action_db=action_db,
            )
        except ValueError as e:
            LOG.exception("Unable to execute action.")
            abort(http_client.BAD_REQUEST, six.text_type(e))
        except jsonschema.ValidationError as e:
            LOG.exception("Unable to execute action. Parameter validation failed.")
            abort(
                http_client.BAD_REQUEST,
                re.sub("u'([^']*)'", r"'\1'", getattr(e, "message", six.text_type(e))),
            )
        except trace_exc.TraceNotFoundException as e:
            abort(http_client.BAD_REQUEST, six.text_type(e))
        except validation_exc.ValueValidationException as e:
            raise e
        except Exception as e:
            LOG.exception("Unable to execute action. Unexpected error encountered.")
            abort(http_client.INTERNAL_SERVER_ERROR, six.text_type(e))

    def _schedule_execution(
        self,
        liveaction,
        requester_user,
        action_db,
        user=None,
        context_string=None,
        show_secrets=False,
    ):
        # Initialize execution context if it does not exist.
        if not hasattr(liveaction, "context"):
            liveaction.context = dict()

        liveaction.context["user"] = user
        liveaction.context["pack"] = action_db.pack

        LOG.debug("User is: %s" % liveaction.context["user"])

        # Retrieve other st2 context from request header.
        if context_string:
            context = try_loads(context_string)
            if not isinstance(context, dict):
                raise ValueError(
                    "Unable to convert st2-context from the headers into JSON"
                    f" (was {type(context)})."
                )
            liveaction.context.update(context)

        # Include RBAC context (if RBAC is available and enabled)
        if cfg.CONF.rbac.enable:
            user_db = UserDB(name=user)
            rbac_service = get_rbac_backend().get_service_class()
            role_dbs = rbac_service.get_roles_for_user(
                user_db=user_db, include_remote=True
            )
            roles = [role_db.name for role_db in role_dbs]
            liveaction.context["rbac"] = {"user": user, "roles": roles}

        # Schedule the action execution.
        liveaction_db = LiveActionAPI.to_model(liveaction)
        runnertype_db = action_utils.get_runnertype_by_name(
            action_db.runner_type["name"]
        )

        try:
            liveaction_db.parameters = param_utils.render_live_params(
                runnertype_db.runner_parameters,
                action_db.parameters,
                liveaction_db.parameters,
                liveaction_db.context,
            )
        except param_exc.ParamException:
            # We still need to create a request, so liveaction_db is assigned an ID
            liveaction_db, actionexecution_db = action_service.create_request(
                liveaction=liveaction_db,
                action_db=action_db,
                runnertype_db=runnertype_db,
                validate_params=False,
            )

            # By this point the execution is already in the DB therefore need to mark it failed.
            _, e, tb = sys.exc_info()
            action_service.update_status(
                liveaction=liveaction_db,
                new_status=action_constants.LIVEACTION_STATUS_FAILED,
                result={
                    "error": six.text_type(e),
                    "traceback": "".join(traceback.format_tb(tb, 20)),
                },
            )
            # Might be a good idea to return the actual ActionExecution rather than bubble up
            # the exception.
            raise validation_exc.ValueValidationException(six.text_type(e))

        # The request should be created after the above call to render_live_params
        # so any templates in live parameters have a chance to render.
        liveaction_db, actionexecution_db = action_service.create_request(
            liveaction=liveaction_db, action_db=action_db, runnertype_db=runnertype_db
        )

        _, actionexecution_db = action_service.publish_request(
            liveaction_db, actionexecution_db
        )
        mask_secrets = self._get_mask_secrets(requester_user, show_secrets=show_secrets)
        execution_api = ActionExecutionAPI.from_model(
            actionexecution_db, mask_secrets=mask_secrets
        )

        return Response(json=execution_api, status=http_client.CREATED)

    def _get_result_object(self, id):
        """
        Retrieve result object for the provided action execution.

        :param id: Action execution ID.
        :type id: ``str``

        :rtype: ``dict``
        """
        fields = ["result"]
        action_exec_db = (
            self.access.impl.model.objects.filter(id=id).only(*fields).get()
        )
        return action_exec_db.result

    def _get_children(
        self, id_, requester_user, depth=-1, result_fmt=None, show_secrets=False
    ):
        # make sure depth is int. Url encoding will make it a string and needs to
        # be converted back in that case.
        depth = int(depth)
        LOG.debug("retrieving children for id: %s with depth: %s", id_, depth)
        descendants = execution_service.get_descendants(
            actionexecution_id=id_, descendant_depth=depth, result_fmt=result_fmt
        )

        mask_secrets = self._get_mask_secrets(requester_user, show_secrets=show_secrets)

        return [
            self.model.from_model(descendant, mask_secrets=mask_secrets)
            for descendant in descendants
        ]

class BaseActionExecutionNestedController(
    ActionExecutionsControllerMixin, ResourceController
):
    # Note: We need to override "get_one" and "get_all" to return 404 since nested controller
    # don't implement thos methods

    # ResourceController attributes
    query_options = {}
    supported_filters = {}

    def get_all(self):
        abort(http_client.NOT_FOUND)

    def get_one(self, id):
        abort(http_client.NOT_FOUND)

class ActionExecutionChildrenController(BaseActionExecutionNestedController):
    def get_one(
        self, id, requester_user, depth=-1, result_fmt=None, show_secrets=False
    ):
        """
        Retrieve children for the provided action execution.

        :rtype: ``list``
        """

        if not requester_user:
            requester_user = UserDB(name=cfg.CONF.system_user.user)

        from_model_kwargs = {
            "mask_secrets": self._get_mask_secrets(
                requester_user, show_secrets=show_secrets
            )
        }

        execution_db = self._get_one_by_id(
            id=id,
            requester_user=requester_user,
            from_model_kwargs=from_model_kwargs,
            permission_type=PermissionType.EXECUTION_VIEW,
        )
        id = str(execution_db.id)

        return self._get_children(
            id_=id,
            depth=depth,
            result_fmt=result_fmt,
            requester_user=requester_user,
            show_secrets=show_secrets,
        )

class ActionExecutionAttributeController(BaseActionExecutionNestedController):
    valid_exclude_attributes = [
        "action__pack",
        "action__uid",
    ] + ActionExecutionsControllerMixin.valid_exclude_attributes

    def get(self, id, attribute, requester_user):
        """
        Retrieve a particular attribute for the provided action execution.

        Handles requests:

            GET /executions/<id>/attribute/<attribute name>

        :rtype: ``dict``
        """
        fields = [attribute, "action__pack", "action__uid"]

        try:
            fields = self._validate_exclude_fields(fields)
        except ValueError:
            valid_attributes = ", ".join(
                ActionExecutionsControllerMixin.valid_exclude_attributes
            )
            msg = 'Invalid attribute "%s" specified. Valid attributes are: %s' % (
                attribute,
                valid_attributes,
            )
            raise ValueError(msg)

        action_exec_db = (
            self.access.impl.model.objects.filter(id=id).only(*fields).get()
        )

        permission_type = PermissionType.EXECUTION_VIEW
        rbac_utils = get_rbac_backend().get_utils_class()
        rbac_utils.assert_user_has_resource_db_permission(
            user_db=requester_user,
            resource_db=action_exec_db,
            permission_type=permission_type,
        )

        result = getattr(action_exec_db, attribute, None)
        return Response(json=result, status=http_client.OK)

class ActionExecutionRawResultController(BaseActionExecutionNestedController):
    def get(
        self, id, requester_user, download=False, compress=False, pretty_format=False
    ):
        """
        Retrieve raw action execution result object as a JSON string or optionally force result
        download as a (compressed) file.

        This is primarily to be used in scenarios where executions contain large results and JSON
        loading and parsing it can be slow (e.g. in the st2web) and we just want to display raw
        result.

        :param compress: True to compress the response using gzip (may come handy for executions
                         with large results).
        :param download: True to force downloading result to a file.
        :param pretty_format: True to pretty format returned JSON data - this adds quite some
                              overhead compared to the default behavior where we don't pretty
                              format the result.

        Handles requests:

            GET /executions/<id>/result[?download=1][&compress=1]

        TODO: Maybe we should also support pre-signed URLs for sharing externally with other
        people?

        It of course won't contain all the exection related data, but just sharing the result can
        come handy in many situations.

        :rtype: ``str``
        """
        # NOTE: Here we intentionally use as_pymongo() to avoid mongoengine layer even for old style
        # data
        try:
            result = (
                self.access.impl.model.objects.filter(id=id)
                .only("result")
                .as_pymongo()[0]
            )
        except IndexError:
            raise NotFoundException("Execution with id %s not found" % (id))

        if isinstance(result["result"], dict):
            # For backward compatibility we also support old non JSON field storage format
            if pretty_format:
                response_body = orjson.dumps(
                    result["result"], option=orjson.OPT_INDENT_2
                )
            else:
                response_body = orjson.dumps(result["result"])
        else:
            # For new JSON storage format we just use raw value since it's already JSON serialized
            # string
            response_body = result["result"]

            if pretty_format:
                # Pretty format is not a default behavior since it adds quite some overhead (e.g.
                # 10-30ms for non pretty format for 4 MB json vs ~120 ms for pretty formatted)
                response_body = orjson.dumps(
                    orjson.loads(result["result"]), option=orjson.OPT_INDENT_2
                )

        response = Response()
        response.headers["Content-Type"] = "text/json"

        if download:
            filename = "execution_%s_result.json" % (id)

            if compress:
                filename += ".gz"

            response.headers["Content-Disposition"] = "attachment; filename=%s" % (
                filename
            )

        if compress:
            response.headers["Content-Type"] = "application/x-gzip"
            response.headers["Content-Encoding"] = "gzip"
            response_body = gzip.compress(response_body)

        response.body = response_body
        return response

class ActionExecutionOutputController(
    ActionExecutionsControllerMixin, ResourceController
):
    supported_filters = {"output_type": "output_type"}
    exclude_fields = []

    def get_one(
        self,
        id,
        output_type="all",
        output_format="raw",
        existing_only=False,
        requester_user=None,
        show_secrets=False,
    ):
        # Special case for id == "last"
        if id == "last":
            execution_db = ActionExecution.query().order_by("-id").limit(1).first()

            if not execution_db:
                raise ValueError("No executions found in the database")

            id = str(execution_db.id)

        if not requester_user:
            requester_user = UserDB(name=cfg.CONF.system_user.user)

        from_model_kwargs = {
            "mask_secrets": self._get_mask_secrets(
                requester_user, show_secrets=show_secrets
            )
        }

        execution_db = self._get_one_by_id(
            id=id,
            requester_user=requester_user,
            from_model_kwargs=from_model_kwargs,
            permission_type=PermissionType.EXECUTION_VIEW,
        )
        execution_id = str(execution_db.id)

        query_filters = {}
        if output_type and output_type != "all":
            query_filters["output_type"] = output_type

        def existing_output_iter():
            # Consume and return all of the existing lines
            # pylint: disable=no-member
            output_dbs = ActionExecutionOutput.query(
                execution_id=execution_id, **query_filters
            )

            output = "".join([output_db.data for output_db in output_dbs])
            yield six.binary_type(output.encode("utf-8"))

        def make_response():
            app_iter = existing_output_iter()
            res = Response(content_type="text/plain", app_iter=app_iter)
            return res

        res = make_response()
        return res

class ActionExecutionReRunController(
    ActionExecutionsControllerMixin, ResourceController
):
    supported_filters = {}
    exclude_fields = ["result", "trigger_instance"]

    class ExecutionSpecificationAPI(object):
        def __init__(self, parameters=None, tasks=None, reset=None, user=None):
            self.parameters = parameters or {}
            self.tasks = tasks or []
            self.reset = reset or []
            self.user = user

        def validate(self):
            if (self.tasks or self.reset) and self.parameters:
                raise ValueError(
                    "Parameters override is not supported when "
                    "re-running task(s) for a workflow."
                )

            if self.parameters:
                if not isinstance(self.parameters, dict):
                    raise TypeError(
                        f"The parameters needs to be a dictionary (was {type(self.parameters)})."
                    )

            if self.tasks:
                if not isinstance(self.tasks, list):
                    raise TypeError(
                        f"The tasks needs to be a list (was {type(self.tasks)})."
                    )

            if self.reset:
                if not isinstance(self.reset, list):
                    raise TypeError(
                        f"The reset needs to be a list (was {type(self.reset)})."
                    )

            if list(set(self.reset) - set(self.tasks)):
                raise ValueError(
                    "List of tasks to reset does not match the tasks to rerun."
                )

            return self

    def post(self, spec_api, id, requester_user, no_merge=False, show_secrets=False):
        """
        Re-run the provided action execution optionally specifying override parameters.

        Handles requests:

            POST /executions/<id>/re_run
        """

        if (spec_api.tasks or spec_api.reset) and spec_api.parameters:
            raise ValueError(
                "Parameters override is not supported when "
                "re-running task(s) for a workflow."
            )

        if spec_api.parameters:
            if not isinstance(spec_api.parameters, dict):
                raise TypeError(
                    f"The parameters needs to be a dictionary (was {type(spec_api.parameters)})."
                )

        if spec_api.tasks:
            if not isinstance(spec_api.tasks, list):
                raise TypeError(
                    f"The tasks needs to be a list (was {type(spec_api.tasks)})."
                )

        if spec_api.reset:
            if not isinstance(spec_api.reset, list):
                raise TypeError(
                    f"The reset needs to be a list (was {type(spec_api.reset)})."
                )

        if list(set(spec_api.reset) - set(spec_api.tasks)):
            raise ValueError(
                "List of tasks to reset does not match the tasks to rerun."
            )

        delay = None

        if hasattr(spec_api, "delay") and isinstance(spec_api.delay, int):
            delay = spec_api.delay

        no_merge = cast_argument_value(value_type=bool, value=no_merge)
        existing_execution = self._get_one_by_id(
            id=id,
            exclude_fields=self.exclude_fields,
            requester_user=requester_user,
            permission_type=PermissionType.EXECUTION_VIEW,
        )

        if spec_api.tasks and existing_execution.runner["name"] != "orquesta":
            raise ValueError("Task option is only supported for Orquesta workflows.")

        # Merge in any parameters provided by the user
        new_parameters = {}
        if not no_merge:
            new_parameters.update(getattr(existing_execution, "parameters", {}))
        new_parameters.update(spec_api.parameters)

        # Create object for the new execution
        action_ref = existing_execution.action["ref"]

        # Include additional option(s) for the execution
        context = {
            "re-run": {
                "ref": id,
            }
        }

        if spec_api.tasks:
            context["re-run"]["tasks"] = spec_api.tasks

        if spec_api.reset:
            context["re-run"]["reset"] = spec_api.reset

        # Add trace to the new execution
        trace = trace_service.get_trace_db_by_action_execution(
            action_execution_id=existing_execution.id
        )

        if trace:
            context["trace_context"] = {"id_": str(trace.id)}

        new_liveaction_api = LiveActionCreateAPI(
            action=action_ref,
            context=context,
            parameters=new_parameters,
            user=spec_api.user,
            delay=delay,
        )

        return self._handle_schedule_execution(
            liveaction_api=new_liveaction_api,
            requester_user=requester_user,
            show_secrets=show_secrets,
        )

class ActionExecutionsController(
    BaseResourceIsolationControllerMixin,
    ActionExecutionsControllerMixin,
    ResourceController,
):
    """
    Implements the RESTful web endpoint that handles
    the lifecycle of ActionExecutions in the system.
    """

    # Nested controllers
    views = ExecutionViewsController()

    children = ActionExecutionChildrenController()
    attribute = ActionExecutionAttributeController()
    re_run = ActionExecutionReRunController()

    # ResourceController attributes
    query_options = {"sort": ["-start_timestamp", "action.ref"]}
    supported_filters = SUPPORTED_EXECUTIONS_FILTERS
    filter_transform_functions = {
        "timestamp_gt": lambda value: isotime.parse(value=value),
        "timestamp_lt": lambda value: isotime.parse(value=value),
    }

    def get_all(
        self,
        requester_user,
        exclude_attributes=None,
        sort=None,
        offset=0,
        limit=None,
        show_secrets=False,
        include_attributes=None,
        advanced_filters=None,
        **raw_filters,
    ):
        """
        List all executions.

        Handles requests:
            GET /executions[?exclude_attributes=result,trigger_instance]

        :param exclude_attributes: List of attributes to exclude from the object.
        :type exclude_attributes: ``list``
        """
        # Use a custom sort order when filtering on a timestamp so we return a correct result as
        # expected by the user
        query_options = None
        if raw_filters.get("timestamp_lt", None) or raw_filters.get("sort_desc", None):
            query_options = {"sort": ["-start_timestamp", "action.ref"]}
        elif raw_filters.get("timestamp_gt", None) or raw_filters.get("sort_asc", None):
            query_options = {"sort": ["+start_timestamp", "action.ref"]}

        from_model_kwargs = {
            "mask_secrets": self._get_mask_secrets(
                requester_user, show_secrets=show_secrets
            )
        }
        return self._get_action_executions(
            exclude_fields=exclude_attributes,
            include_fields=include_attributes,
            from_model_kwargs=from_model_kwargs,
            sort=sort,
            offset=offset,
            limit=limit,
            query_options=query_options,
            raw_filters=raw_filters,
            advanced_filters=advanced_filters,
            requester_user=requester_user,
        )

    def get_one(
        self,
        id,
        requester_user,
        exclude_attributes=None,
        include_attributes=None,
        show_secrets=False,
        max_result_size=None,
    ):
        """
        Retrieve a single execution.

        Handles requests:
            GET /executions/<id>[?exclude_attributes=result,trigger_instance]

        :param exclude_attributes: List of attributes to exclude from the object.
        :type exclude_attributes: ``list``
        """
        exclude_fields = self._validate_exclude_fields(
            exclude_fields=exclude_attributes
        )
        include_fields = self._validate_include_fields(
            include_fields=include_attributes
        )

        from_model_kwargs = {
            "mask_secrets": self._get_mask_secrets(
                requester_user, show_secrets=show_secrets
            )
        }

        max_result_size = self._validate_max_result_size(
            max_result_size=max_result_size
        )

        # Special case for id == "last"
        if id == "last":
            execution_db = (
                ActionExecution.query().order_by("-id").limit(1).only("id").first()
            )

            if not execution_db:
                raise ValueError("No executions found in the database")

            id = str(execution_db.id)

        return self._get_one_by_id(
            id=id,
            exclude_fields=exclude_fields,
            include_fields=include_fields,
            requester_user=requester_user,
            from_model_kwargs=from_model_kwargs,
            permission_type=PermissionType.EXECUTION_VIEW,
            get_by_id_kwargs={"max_result_size": max_result_size},
        )

    def post(
        self, liveaction_api, requester_user, context_string=None, show_secrets=False
    ):
        return self._handle_schedule_execution(
            liveaction_api=liveaction_api,
            requester_user=requester_user,
            context_string=context_string,
            show_secrets=show_secrets,
        )

    def put(self, id, liveaction_api, requester_user, show_secrets=False):
        """
        Updates a single execution.

        Handles requests:
            PUT /executions/<id>

        """
        if not requester_user:
            requester_user = UserDB(name=cfg.CONF.system_user.user)

        from_model_kwargs = {
            "mask_secrets": self._get_mask_secrets(
                requester_user, show_secrets=show_secrets
            )
        }

        execution_api = self._get_one_by_id(
            id=id,
            requester_user=requester_user,
            from_model_kwargs=from_model_kwargs,
            permission_type=PermissionType.EXECUTION_STOP,
        )

        if not execution_api:
            abort(http_client.NOT_FOUND, "Execution with id %s not found." % id)

        liveaction_id = execution_api.liveaction["id"]
        if not liveaction_id:
            abort(
                http_client.INTERNAL_SERVER_ERROR,
                "Execution object missing link to liveaction %s." % liveaction_id,
            )

        try:
            liveaction_db = LiveAction.get_by_id(liveaction_id)
        except:
            abort(
                http_client.INTERNAL_SERVER_ERROR,
                "Execution object missing link to liveaction %s." % liveaction_id,
            )

        if liveaction_db.status in action_constants.LIVEACTION_COMPLETED_STATES:
            abort(http_client.BAD_REQUEST, "Execution is already in completed state.")

        def update_status(liveaction_api, liveaction_db):
            status = liveaction_api.status
            result = getattr(liveaction_api, "result", None)
            liveaction_db = action_service.update_status(
                liveaction_db, status, result, set_result_size=True
            )
            actionexecution_db = ActionExecution.get(
                liveaction__id=str(liveaction_db.id)
            )
            return (liveaction_db, actionexecution_db)

        try:
            if (
                liveaction_db.status == action_constants.LIVEACTION_STATUS_CANCELING
                and liveaction_api.status == action_constants.LIVEACTION_STATUS_CANCELED
            ):
                if action_service.is_children_active(liveaction_id):
                    liveaction_api.status = action_constants.LIVEACTION_STATUS_CANCELING
                liveaction_db, actionexecution_db = update_status(
                    liveaction_api, liveaction_db
                )
            elif (
                liveaction_api.status == action_constants.LIVEACTION_STATUS_CANCELING
                or liveaction_api.status == action_constants.LIVEACTION_STATUS_CANCELED
            ):
                liveaction_db, actionexecution_db = action_service.request_cancellation(
                    liveaction_db, requester_user.name or cfg.CONF.system_user.user
                )
            elif (
                liveaction_db.status == action_constants.LIVEACTION_STATUS_PAUSING
                and liveaction_api.status == action_constants.LIVEACTION_STATUS_PAUSED
            ):

                if action_service.is_children_active(liveaction_id):
                    liveaction_api.status = action_constants.LIVEACTION_STATUS_PAUSING
                liveaction_db, actionexecution_db = update_status(
                    liveaction_api, liveaction_db
                )
            elif (
                liveaction_api.status == action_constants.LIVEACTION_STATUS_PAUSING
                or liveaction_api.status == action_constants.LIVEACTION_STATUS_PAUSED
            ):
                liveaction_db, actionexecution_db = action_service.request_pause(
                    liveaction_db, requester_user.name or cfg.CONF.system_user.user
                )
            elif liveaction_api.status == action_constants.LIVEACTION_STATUS_RESUMING:
                liveaction_db, actionexecution_db = action_service.request_resume(
                    liveaction_db, requester_user.name or cfg.CONF.system_user.user
                )
            else:
                liveaction_db, actionexecution_db = update_status(
                    liveaction_api, liveaction_db
                )
        except runner_exc.InvalidActionRunnerOperationError as e:
            LOG.exception(
                "Failed updating liveaction %s. %s", liveaction_db.id, six.text_type(e)
            )
            abort(
                http_client.BAD_REQUEST,
                "Failed updating execution. %s" % six.text_type(e),
            )
        except runner_exc.UnexpectedActionExecutionStatusError as e:
            LOG.exception(
                "Failed updating liveaction %s. %s", liveaction_db.id, six.text_type(e)
            )
            abort(
                http_client.BAD_REQUEST,
                "Failed updating execution. %s" % six.text_type(e),
            )
        except Exception as e:
            LOG.exception(
                "Failed updating liveaction %s. %s", liveaction_db.id, six.text_type(e)
            )
            abort(
                http_client.INTERNAL_SERVER_ERROR,
                "Failed updating execution due to unexpected error.",
            )

        mask_secrets = self._get_mask_secrets(requester_user, show_secrets=show_secrets)
        execution_api = ActionExecutionAPI.from_model(
            actionexecution_db, mask_secrets=mask_secrets
        )

        return execution_api

    def delete(self, id, requester_user, show_secrets=False):
        """
        Stops a single execution.

        Handles requests:
            DELETE /executions/<id>

        """
        if not requester_user:
            requester_user = UserDB(name=cfg.CONF.system_user.user)

        from_model_kwargs = {
            "mask_secrets": self._get_mask_secrets(
                requester_user, show_secrets=show_secrets
            )
        }
        execution_api = self._get_one_by_id(
            id=id,
            requester_user=requester_user,
            from_model_kwargs=from_model_kwargs,
            permission_type=PermissionType.EXECUTION_STOP,
        )

        if not execution_api:
            abort(http_client.NOT_FOUND, "Execution with id %s not found." % id)

        liveaction_id = execution_api.liveaction["id"]
        if not liveaction_id:
            abort(
                http_client.INTERNAL_SERVER_ERROR,
                "Execution object missing link to liveaction %s." % liveaction_id,
            )

        try:
            liveaction_db = LiveAction.get_by_id(liveaction_id)
        except:
            abort(
                http_client.INTERNAL_SERVER_ERROR,
                "Execution object missing link to liveaction %s." % liveaction_id,
            )

        if liveaction_db.status == action_constants.LIVEACTION_STATUS_CANCELED:
            LOG.info(
                'Action %s already in "canceled" state; \
                returning execution object.'
                % liveaction_db.id
            )
            return execution_api

        if liveaction_db.status not in action_constants.LIVEACTION_CANCELABLE_STATES:
            abort(
                http_client.OK,
                "Action cannot be canceled. State = %s." % liveaction_db.status,
            )

        try:
            (liveaction_db, execution_db) = action_service.request_cancellation(
                liveaction_db, requester_user.name or cfg.CONF.system_user.user
            )
        except:
            LOG.exception(
                "Failed requesting cancellation for liveaction %s.", liveaction_db.id
            )
            abort(http_client.INTERNAL_SERVER_ERROR, "Failed canceling execution.")

        return ActionExecutionAPI.from_model(
            execution_db, mask_secrets=from_model_kwargs["mask_secrets"]
        )

    def _validate_max_result_size(
        self, max_result_size: Optional[int]
    ) -> Optional[int]:
        """
        Validate value of the ?max_result_size query parameter (if provided).
        """
        # Maximum limit for MongoDB collection document is 16 MB and the field itself can't be
        # larger than that obviously. And in reality due to the other fields, overhead, etc,
        # 14 is the upper limit.
        if not max_result_size:
            return max_result_size

        if max_result_size <= 0:
            raise ValueError("max_result_size must be a positive number")

        if max_result_size > 14 * 1024 * 1024:
            raise ValueError(
                "max_result_size query parameter must be smaller than 14 MB"
            )

        return max_result_size

    def _get_by_id(
        self,
        resource_id,
        exclude_fields=None,
        include_fields=None,
        max_result_size=None,
    ):
        """
        Custom version of _get_by_id() which supports ?max_result_size pre-filtering and not
        returning result field for executions which result size exceeds this threshold.

        This functionality allows us to implement fast and efficient retrievals in st2web.
        """
        exclude_fields = exclude_fields or []
        include_fields = include_fields or []

        if not max_result_size:
            # If max_result_size is not provided we don't perform any prefiltering and directly
            # call parent method
            execution_db = super(ActionExecutionsController, self)._get_by_id(
                resource_id=resource_id,
                exclude_fields=exclude_fields,
                include_fields=include_fields,
            )
            return execution_db

        # Special query where we check if result size is smaller than pre-defined or that field
        # doesn't not exist (old executions) and only return the result if the condition is met.
        # This allows us to implement fast and efficient retrievals of executions on the client
        # st2web side where we don't want to retrieve and display result directly for executions
        # with large results
        # Keep in mind that the query itself is very fast and adds almost no overhead for API
        # operations which pass this query parameter because we first filter on the ID (indexed
        # field) and perform projection query with two tiny fields (based on real life testing it
        # takes less than 3 ms in most scenarios).
        execution_db = self.access.get(
            Q(id=resource_id)
            & (Q(result_size__lte=max_result_size) | Q(result_size__not__exists=True)),
            only_fields=["id", "result_size"],
        )

        # if result is empty, this means that execution either doesn't exist or the result is
        # larger than threshold which means we don't want to retrieve and return result to
        # the end user to we set exclude_fields accordingly
        if not execution_db:
            LOG.debug(
                "Execution with id %s and result_size < %s not found. This means "
                "execution with this ID doesn't exist or result_size exceeds the "
                "threshold. Result field will be excluded from the retrieval and "
                "the response." % (resource_id, max_result_size)
            )

            if include_fields and "result" in include_fields:
                include_fields.remove("result")
            elif not include_fields:
                exclude_fields += ["result"]

        # Now call parent get by id with potentially modified include / exclude fields in case
        # result should not be included
        execution_db = super(ActionExecutionsController, self)._get_by_id(
            resource_id=resource_id,
            exclude_fields=exclude_fields,
            include_fields=include_fields,
        )
        return execution_db

    def _get_action_executions(
        self,
        exclude_fields=None,
        include_fields=None,
        sort=None,
        offset=0,
        limit=None,
        advanced_filters=None,
        query_options=None,
        raw_filters=None,
        from_model_kwargs=None,
        requester_user=None,
    ):
        """
        :param exclude_fields: A list of object fields to exclude.
        :type exclude_fields: ``list``
        """

        if limit is None:
            limit = self.default_limit

        limit = int(limit)

        LOG.debug(
            "Retrieving all action executions with filters=%s,exclude_fields=%s,"
            "include_fields=%s",
            raw_filters,
            exclude_fields,
            include_fields,
        )
        return super(ActionExecutionsController, self)._get_all(
            exclude_fields=exclude_fields,
            include_fields=include_fields,
            from_model_kwargs=from_model_kwargs,
            sort=sort,
            offset=offset,
            limit=limit,
            query_options=query_options,
            raw_filters=raw_filters,
            advanced_filters=advanced_filters,
            requester_user=requester_user,
        )

action_executions_controller = ActionExecutionsController()
action_execution_output_controller = ActionExecutionOutputController()
action_execution_rerun_controller = ActionExecutionReRunController()
action_execution_attribute_controller = ActionExecutionAttributeController()
action_execution_children_controller = ActionExecutionChildrenController()
action_execution_raw_result_controller = ActionExecutionRawResultController()


from django.urls import reverse
from django.test import Client
from rest_framework import status
from rest_framework.test import APITestCase

from manage_urls.models import Url

class CreateUrlTest(APITestCase):
    """
    Test cases for the `create` method of the `UrlViewSet` class.
    """
    def setUp(self):
        """
        Set up test data for the test cases.
        """
        # A valid URL
        self.valid_url = 'https://www.google.com'
        # An invalid URL
        self.invalid_url = 'invalid'
        # A client with the `HTTP_HOST` header set to 'localhost'
        self.costume_client = Client(HTTP_HOST='localhost')

    def test_create_valid_url(self):
        """
        Test that a new URL object can be created with a valid original_url.
        """
        # Data to be sent with the request
        data = {'original_url': self.valid_url}
        # Make a POST request to the `url-create` endpoint
        response = self.costume_client.post(reverse('url-create'), data, format='json')
        # Check that the response status code is 201 Created
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        # Check that there is only 1 URL object in the database
        self.assertEqual(Url.objects.count(), 1)
        # Check that the original_url of the URL object in the database is the valid URL
        self.assertEqual(Url.objects.last().original_url, self.valid_url)

    def test_create_invalid_url(self):
        """
        Test that attempting to create a new url object with an invalid original_url results in a 400 Bad Request response.
        Additionally, ensure that no new url object is created in the database.
        """
        # Create a request data dictionary with an invalid url
        data = {'original_url': self.invalid_url}
        # Send a POST request to the url-create endpoint with the invalid url data
        response = self.costume_client.post(reverse('url-create'), data, format='json')
        # Assert that the response status code is a 400 Bad Request
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        # Assert that the Url model's objects count is 0 (no new object was created)
        self.assertEqual(Url.objects.count(), 0)

class RedirectUrlTest(APITestCase):
    def setUp(self):
        # Create a new Url object with an original_url of 'https://www.google.com' and a tiny_url of '55ae07f8'
        self.url = Url.objects.create(original_url='https://www.google.com', tiny_url='55ae07f8')
        # Create a new Client instance with the HTTP_HOST header set to 'localhost'
        self.costume_client = Client(HTTP_HOST='localhost')

    def test_redirect_url(self):
        # Make a GET request to the view with the slug of the Url object
        response = self.costume_client.get(f'/shorturls/{self.url.tiny_url}')
        # Assert that the response status code is a redirect (status code 302)
        self.assertEqual(response.status_code, status.HTTP_302_FOUND)
        # Assert that the response contains the correct Location header
        self.assertEqual(response['Location'], self.url.original_url)

    def test_redirect_url_not_exist(self):
        # Make a GET request to the view with a slug that doesn't match any Url objects
        response = self.costume_client.get(f'/shorturls/some-invalid-slug')
        # Assert that the response status code is a 404 Not Found
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)


def compress(word, k):
  #set start and stop index var
  #set len var
  #set counter

  #loop from start
  #if word[start] is

  stack = []

  for ch in word:
    if stack and stack[-1][0] == ch:
      stack[-1][1] += 1
      print(stack[-1][1])
      if stack[-1][1] == k:
        stack.pop()
        print(stack)

    else:
      stack.append([ch, 1])
      print(stack)
  return ''.join([a * b for a,b in stack])

if __name__ == "__main__":
  print(compress('abbcccb', 3))


import psycopg2
from db_config import init_db
from flask_jwt_extended import jwt_required, get_jwt_identity

class Parcels():
    """The methods defined in this class represent methods that users
    will use to manipulate parcels in the database"""

    def __init__(self):
        self.db = init_db()

    def create_parcel(self, parcel_name, recipient_name, pickup_location,
                      destination, weight):
        """This method handles requests for creating parcel delivery orders"""

        user_data = get_jwt_identity()
        self.parcel_name = parcel_name
        self.sender_email = user_data["email"]
        self.recipient_name = recipient_name
        self.destination = destination
        self.pickup_location = pickup_location
        self.current_location = pickup_location
        self.weight = int(weight)
        self.price = int(weight) * 3
        self.status = "pending"

        parcel_info = {
            "parcel_name": parcel_name,
            "sender_email": self.sender_email,
            "recipient_name": recipient_name,
            "pickup_location": pickup_location,
            "current_location": self.current_location,
            "destination": destination,
            "weight": int(weight),
            "price": int(self.price),
            "status": self.status
        }

        save_parcel = """
        INSERT INTO parcels (parcel_name, sender_email, recipient_name,
        pickup_location, current_location, destination, weight, price, status)
        VALUES (%(parcel_name)s, %(sender_email)s, %(recipient_name)s,
        %(pickup_location)s, %(current_location)s, %(destination)s, %(weight)s,
        %(price)s, %(status)s)"""
        try:
            cursor = self.db.cursor()
            print("Successfully created cursor. Saving parcel to database...")
            cursor.execute(save_parcel, parcel_info)
        except (Exception, psycopg2.Error) as error:
            print("Could not save the parcel to database: ", error)
            return error
        else:
            self.db.commit()
            print("Successfully saved the order to database")
            return 201

    def change_destination(self, parcel_id, destination):
        """This method will handle requests to the database to change the destination
        of a parcel delivery order."""

        user_data = get_jwt_identity()
        parcel = self.get_parcel_by_id(parcel_id)
        if not parcel:
            return 404
        elif parcel[2] != user_data["email"]:
            return 401
        elif parcel[9] != "pending":
            return 400
        else:
            update_destination = """UPDATE parcels SET destination = '{}'
            WHERE parcel_id = {}""".format(destination, parcel_id)
        try:
            cursor = self.db.cursor()
            print("Successfully created cursor. Updating destination for parcel number {} ...".format(
                parcel_id))
            cursor.execute(update_destination)
            self.db.commit()
            count = cursor.rowcount
            print("Destination successfully changed for parcel {}. {} rows affected".format(
                parcel_id, count))
            return 204
        except (Exception, psycopg2.Error) as error:
            print("Error. Could not update destination of parcel: ", error)
            return error

    def get_parcel_by_id(self, parcel_id):
        """We have to validate a parcel exists before we can begin to make
        changes on it."""

        get_parcel = """SELECT * FROM parcels WHERE parcel_id = {}
        """.format(parcel_id)
        try:
            cursor = self.db.cursor()
            print("Successfully created cursor. Getting parcel {} ...".format(parcel_id))
            cursor.execute(get_parcel)
            parc = cursor.fetchone()
            if not parc:
                return False
            else:
                return parc
        except (Exception, psycopg2.Error) as error:
            print ("Could not get parcel {}... ".format(parcel_id), error)
            return error

    @jwt_required
    def get_all_parcels(self):
        """This will be called if the admin wishes to see all parcels
        in the database"""

        user_data = get_jwt_identity()
        if user_data["is_admin"] is True:
            admin = True
            admin_get_all = """
                SELECT * FROM parcels
                ORDER BY parcel_id"""
        else:
            admin = False
            user_get_all = """
            SELECT * FROM parcels
            WHERE sender_email = '{}'
            ORDER BY parcel_id
            """.format(user_data["email"])

        try:
            cursor = self.db.cursor()
            print("Successfully created cursor. Getting all parcels ...")

            if admin is True:
                cursor.execute(admin_get_all)
            else:
                cursor.execute(user_get_all)

            data = cursor.fetchall()
            if data == []:
                return 404
            res = []

            for parcel, parcels in enumerate(data):
                parcel_id, parcel_name, sender_email, recipient_name, pickup_location, current_location, destination, weight, price, status = parcels
                structured_response = dict(
                    parcel_id=parcel_id,
                    parcel_name=parcel_name,
                    sender_email=sender_email,
                    recipient_name=recipient_name,
                    pickup_location=pickup_location,
                    current_location=current_location,
                    destination=destination,
                    weight=int(weight),
                    price=int(price),
                    status=status)
                res.append(structured_response)
            return res

        except (Exception, psycopg2.Error) as error:
            print("Could not get any parcels from database: ", error)
            return error

    def change_status(self, parcel_id, status):
        """This method handles requests to change the status of an order"""
        parcel = self.get_parcel_by_id(parcel_id)

        if not parcel:
            return 404
        elif parcel[9] == "delivered" or parcel[9] == "cancelled":
            return 400
        else:
            change_status = """
            UPDATE parcels SET status = '{}' WHERE parcel_id = {}""".format(status, parcel_id)
        try:
            cursor = self.db.cursor()
            print("Successfully created cursor. Changing the status of parcel number {} ...".format(
                parcel_id))
            cursor.execute(change_status)
            self.db.commit()
            count = cursor.rowcount
            print("Successfully changed the status parcel {}. {} rows affected.".format(
                parcel_id, count))
            return 204
        except (Exception, psycopg2.Error) as error:
            print("Could not change the status of the order: ", error)
            return error, 400

    def change_location(self, parcel_id, current_location):
        """This method handles requests to change the location of a delivery in transit"""

        parcel = self.get_parcel_by_id(parcel_id)

        if not parcel:
            return 404
        elif parcel[9] != "transit":
            return 400
        else:
            update_location = """
            UPDATE parcels SET current_location = '{}'
            WHERE parcel_id = {}""".format(current_location, parcel_id)

        try:
            cursor = self.db.cursor()
            print("Successfully created cursor. Updating current location for parcel \
                number {} ...".format(parcel_id))
            cursor.execute(update_location)
            self.db.commit()
            print("Location successfully changed")
            return 204
        except (Exception, psycopg2.Error) as error:
            print("Could not change destinaion of parcel: ", error)
            return error

    @jwt_required
    def cancel_parcel(self, parcel_id):
        """User can only cancel orders they create so long as they are not yet
        'delivered'"""
        user_data = get_jwt_identity()
        get_parcel = self.get_parcel_by_id(parcel_id)

        if get_parcel is False:
            return 404
        elif user_data["email"] != get_parcel[2]:
            return 401
        elif get_parcel[9] == "cancelled" or get_parcel[9] == "delivered":
            return 400
        else:
            cancel_query = """UPDATE parcels
            SET status = 'cancelled' WHERE parcel_id = {}""".format(parcel_id)

        try:
            cursor = self.db.cursor()
            print("Successfully created cursor. Cancelling parcel number {} ...".format(
                parcel_id))
            cursor.execute(cancel_query)
            self.db.commit()
            count = cursor.rowcount
            print("Successfully changed the status parcel {}. {} rows affected.".format(
                parcel_id, count))
            return 204
        except (Exception, psycopg2.Error) as error:
            print("Could not change the status of the parcel: ", error)
            return error


# Copyright 2023 Google LLC
#
# 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
#
#    https://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.
"""IP Control Module"""
from common import logger
from common import util
import re

LOGGER = logger.get_logger('ip_ctrl')

class IPControl:
  """IP Control"""

  def __init__(self):
    """Initialize the IPControl object"""

  def add_link(self, interface_name, peer_name):
    """Create an ip link with a peer"""
    success = util.run_command('ip link add ' + interface_name +
                               ' type veth peer name ' + peer_name)
    return success

  def add_namespace(self, namespace):
    """Add a network namespace"""
    exists = self.namespace_exists(namespace)
    LOGGER.info('Namespace exists: ' + str(exists))
    if exists:
      return True
    else:
      success = util.run_command('ip netns add ' + namespace)
      return success

  def delete_link(self, interface_name):
    """Delete an ip link"""
    success = util.run_command('ip link delete ' + interface_name)
    return success

  def delete_namespace(self, interface_name):
    """Delete an ip namespace"""
    success = util.run_command('ip netns delete ' + interface_name)
    return success

  def link_exists(self, link_name):
    links = self.get_links()
    return link_name in links

  def namespace_exists(self, namespace):
    """Check if a namespace already exists"""
    namespaces = self.get_namespaces()
    return namespace in namespaces

  def get_links(self):
    result = util.run_command('ip link list')
    links = result[0].strip().split('\n')
    netns_links = []
    for link in links:
      match = re.search(r'\d+:\s+(\S+)', link)
      if match:
        interface_name = match.group(1)
        name_match = re.search(r'(.*)@', interface_name)
        if name_match:
          interface_name = name_match.group(1)
        netns_links.append(interface_name.strip())
    return netns_links

  def get_namespaces(self):
    result = util.run_command('ip netns list')
    #Strip ID's from the namespace results
    namespaces = re.findall(r'(\S+)(?:\s+\(id: \d+\))?', result[0])
    return namespaces

  def set_namespace(self, interface_name, namespace):
    """Attach an interface to a network namespace"""
    success = util.run_command('ip link set ' + interface_name + ' netns ' +
                               namespace)
    return success

  def rename_interface(self, interface_name, namespace, new_name):
    """Rename an interface"""
    success = util.run_command('ip netns exec ' + namespace +
                               ' ip link set dev ' + interface_name + ' name ' +
                               new_name)
    return success

  def set_interface_mac(self, interface_name, namespace, mac_addr):
    """Set MAC address of an interface"""
    success = util.run_command('ip netns exec ' + namespace +
                               ' ip link set dev ' + interface_name +
                               ' address ' + mac_addr)
    return success

  def set_interface_ip(self, interface_name, namespace, ipaddr):
    """Set IP address of an interface"""
    success = util.run_command('ip netns exec ' + namespace + ' ip addr add ' +
                               ipaddr + ' dev ' + interface_name)
    return success

  def set_interface_up(self, interface_name, namespace=None):
    """Set the interface to the up state"""
    if namespace is None:
      success = util.run_command('ip link set dev ' + interface_name + ' up')
    else:
      success = util.run_command('ip netns exec ' + namespace +
                                 ' ip link set dev ' + interface_name + ' up')
    return success

  def clean_all(self):
    """Cleanup all existing test run interfaces and namespaces"""

    # Delete all namesapces that start with tr
    namespaces = self.get_namespaces()
    for ns in namespaces:
      if 'tr' in ns:
        self.delete_namespace(ns)

    # Delete all namespaces that start with tr
    links = self.get_links()
    for link in links:
      if 'tr' in link:
        self.delete_link(link)

  def cleanup(self, interface=None, namespace=None):
    """Cleanup existing link and namespace if they still exist"""

    link_clean = True
    if interface is not None:
      if self.link_exists(interface):
        link_clean = self.delete_link(interface)

    ns_clean = True
    if namespace is not None:
      if self.namespace_exists(namespace):
        ns_clean = self.delete_namespace
    return link_clean and ns_clean

  def configure_container_interface(self,
                                    bridge_intf,
                                    container_intf,
                                    namespace_intf,
                                    namespace,
                                    mac_addr,
                                    container_name=None,
                                    ipv4_addr=None,
                                    ipv6_addr=None):

    # Cleanup old interface and namespaces
    self.cleanup(bridge_intf, namespace)

    # Create interface pair
    self.add_link(bridge_intf, container_intf)

    if container_name is not None:
      # Get PID for running container
      # TODO: Some error checking around missing PIDs might be required
      container_pid = util.run_command('docker inspect -f {{.State.Pid}} ' +
                                       container_name)[0]
      if not container_pid.isdigit():
        LOGGER.error(f'Failed to resolve pid for {container_name}')
        return False

      # Create symlink for container network namespace
      if not util.run_command('ln -sf /proc/' + container_pid +
                              '/ns/net /var/run/netns/' + namespace,
                              output=False):
        LOGGER.error(
            f'Failed to link {container_name} to namespace {namespace_intf}')
        return False

    # Attach container interface to container network namespace
    if not self.set_namespace(container_intf, namespace):
      LOGGER.error(f'Failed to set namespace {namespace} for {container_intf}')
      return False

    # Rename container interface name
    if not self.rename_interface(container_intf, namespace, namespace_intf):
      LOGGER.error((f'Failed to rename container interface {container_intf} ' +
                    'to {namespace_intf}'))
      return False

    # Set MAC address of container interface
    if not self.set_interface_mac(namespace_intf, namespace, mac_addr):
      LOGGER.error(
          f'Failed to set MAC address for {namespace_intf} to {mac_addr}')
      return False

    # Set IP address of container interface
    if ipv4_addr is not None:
      if not self.set_interface_ip(namespace_intf, namespace, ipv4_addr):
        LOGGER.error(
            f'Failed to set IPv4 address for {namespace_intf} to {ipv4_addr}')
        return False
    if ipv6_addr is not None:
      if not self.set_interface_ip(namespace_intf, namespace, ipv6_addr):
        LOGGER.error(
            f'Failed to set IPv6 address for {namespace_intf} to {ipv6_addr}')
        return False

    # Set interfaces up
    if not self.set_interface_up(bridge_intf):
      LOGGER.error(f'Failed to set interface up {bridge_intf}')
      return False
    if not self.set_interface_up(namespace_intf, namespace):
      LOGGER.error(f'Failed to set interface up {namespace_intf}')
      return False
    return True


# 6198

import sys

count = int(sys.stdin.readline().rstrip())

buildings = []
answers = [0] * count
stack = []
for i in range(count):
    h = int(sys.stdin.readline().rstrip())
    buildings.append(h)

buildings.append(sys.maxsize)
for i, cur in enumerate(buildings):
    while stack and cur >= buildings[stack[-1]]:
        last = stack.pop()
        answers[last] = i - last - 1
    stack.append(i)

print(sum(answers))


#!/usr/bin/env python
# -*- coding: utf-8 -*-

# built-in modules

# third-party modules

# own modules
from common.db import db

Permission = db.get_model('Permission')
UserPermission = db.get_model('UserPermission')

def has_permission(user_id, permission_name):
    permission = db.session.query(UserPermission) \
        .join(Permission, Permission.id == UserPermission.permission_id) \
        .filter(Permission.permission_name == permission_name)\
        .filter(UserPermission.user_id == user_id)\
        .first()
    return permission.allow if permission is not None else True


from os import listdir
import pandas as pd
from datetime import datetime as dt
import shutil
new_path ='/disk/data/share/s1931563/msc_project/src/collected_tweets/'

old_path = '/disk/data/share/s1931563/tweet_data/'

cities = ['joh','lon','nyc','ran']

for city in cities:
   old_tweets = listdir(old_path+'tweets_'+city)
   new_tweets = listdir(new_path+city)

   intersec = set.intersection(set(old_tweets), set(new_tweets))
   intersec = sorted(intersec)
   for user_csv in intersec:
       new_csv_path = new_path + city + '/' + user_csv
       old_csv_path = old_path + 'tweets_'+city +'/'+ user_csv

       try:

           new = pd.read_csv(new_csv_path)
           old = pd.read_csv(old_csv_path)

           if dt.strptime(str(new.created_at.iloc[-1]), "%Y-%m-%d %H:%M:%S") >= dt.strptime("2019-01-01 06:23:04", "%Y-%m-%d %H:%M:%S"):
               merged = pd.concat([new,old])
               merged.to_csv(new_csv_path,index=False)

       except:
           print('skip the user {}'.format(user_csv))

# for city in cities:
#     df = pd.read_csv('/disk/data/share/s1931563/msc_project/src/user_data/' + city+'.csv')
#     all_ids = df.user_id.tolist()
#
#     ideal_tweets = [str(id)+'_tweets.csv' for id in all_ids]
#     old_tweets = listdir(old_path+'tweets_'+city)
#     new_tweets = listdir(new_path + city)
#
#
#
#     to_be_moved = set.intersection(set(ideal_tweets),set(old_tweets)) - set(new_tweets)
#     print(len(to_be_moved))
#     for user_csv in to_be_moved:
#         new_csv_path = new_path + city + '/' + user_csv
#         old_csv_path = old_path + 'tweets_' + city + '/' + user_csv
#         shutil.copyfile(old_csv_path,new_csv_path)


#!/usr/bin/python3
'''
Alx interview question
'''

def canUnlockAll(boxes):
    """
     a method that determines if all the boxes can be opened.
    :param boxes:
    :return: True or False
    """
    if not boxes or type(boxes) is not list:
        return False

    unlocked = [0]
    for n in unlocked:
        for key in boxes[n]:
            if key not in unlocked and key < len(boxes):
                unlocked.append(key)
    if len(unlocked) == len(boxes):
        return True
    return False