from about.models import OfficerEmailListAndPositionMapping
from csss.setup_logger import Loggers
from csss.views.views import ERROR_MESSAGES_KEY
from csss.views_helper import there_are_multiple_entries
from resource_management.models import OfficerPositionGithubTeam

GITHUB_TEAM__ID_KEY = "github_mapping__id"
SAVED_GITHUB_MAPPINGS = 'github_teams'

OFFICER_POSITION_AVAILABLE_FOR_GITHUB_MAPPINGS = 'github_position_mapping'

POSITION_INDEX_KEY = 'position_index'

SAVED_OFFICER_POSITIONS = 'saved_officer_positions'

DELETE_GITHUB_MAPPING = 'delete_github_mapping'
GITHUB_MAPPING_SELECTED_OFFICER_POSITIONS = 'github_mapping_selected_officer_positions'
OFFICER_EMAIL_LIST_AND_POSITION_MAPPING__ID = "officer_email_list_and_position_mapping__id"
OFFICER_EMAIL_LIST_AND_POSITION_MAPPING__POSITION_INDEX = "officer_email_list_and_position_mapping__position_index"
OFFICER_EMAIL_LIST_AND_POSITION_MAPPING__POSITION_NAME = "officer_email_list_and_position_mapping__position_name"
OFFICER_EMAIL_LIST_AND_POSITION_MAPPING__EMAIL_LIST_ADDRESS = \
    "officer_email_list_and_position_mapping__email_list_address"
OFFICER_EMAIL_LIST_AND_POSITION_MAPPING__DISCORD_ROLE_NAME = \
    "officer_email_list_and_position_mapping__discord_role_name"
OFFICER_EMAIL_LIST_AND_POSITION_MAPPING__GITHUB_ACCESS = 'officer_email_list_and_position_mapping__github_access'
OFFICER_EMAIL_LIST_AND_POSITION_MAPPING__GOOGLE_DRIVE_ACCESS = \
    'officer_email_list_and_position_mapping__google_drive_access'
OFFICER_EMAIL_LIST_AND_POSITION_MAPPING__ELECTED_VIA_ELECTION_OFFICER = \
    "officer_email_list_and_position_mapping__elected_via_election_officer"
OFFICER_EMAIL_LIST_AND_POSITION_MAPPING__EXECUTIVE_OFFICER = \
    'officer_email_list_and_position_mapping__executive_officer'
OFFICER_EMAIL_LIST_AND_POSITION_MAPPING__ELECTION_OFFICER = \
    'officer_email_list_and_position_mapping__election_officer'
OFFICER_EMAIL_LIST_AND_POSITION_MAPPING__SFSS_COUNCIL_REP = \
    'officer_email_list_and_position_mapping__sfss_council_representative'
OFFICER_EMAIL_LIST_AND_POSITION_MAPPING__FROSH_WEEK_CHAIR = \
    'officer_email_list_and_position_mapping__frosh_week_chair'
OFFICER_EMAIL_LIST_AND_POSITION_MAPPING__DISCORD_MANAGER = 'officer_email_list_and_position_mapping__discord_manager'
OFFICER_EMAIL_LIST_AND_POSITION_MAPPING__NUMBER_OF_TERMS = 'officer_email_list_and_position_mapping__number_of_terms'
OFFICER_EMAIL_LIST_AND_POSITION_MAPPING__STARTING_MONTH = 'officer_email_list_and_position_mapping__starting_month'

OFFICER_EMAIL_LIST_AND_POSITION_MAPPING__DELETE_STATUS = \
    "officer_email_list_and_position_mapping__delete_status"
GITHUB_TEAM__TEAM_NAME_KEY = "github_mapping__team_name"
GITHUB_TEAM_RELEVANT_PREVIOUS_TERM_KEY = "github_mapping__relevant_previous_terms"
TEAM_NAME_KEY = 'team_name'

def update_context(context):
    context.update({
        'OFFICER_EMAIL_LIST_AND_POSITION_MAPPING__ID': OFFICER_EMAIL_LIST_AND_POSITION_MAPPING__ID,
        'OFFICER_EMAIL_LIST_AND_POSITION_MAPPING__POSITION_INDEX':
            OFFICER_EMAIL_LIST_AND_POSITION_MAPPING__POSITION_INDEX,
        'OFFICER_EMAIL_LIST_AND_POSITION_MAPPING__POSITION_NAME':
            OFFICER_EMAIL_LIST_AND_POSITION_MAPPING__POSITION_NAME,
        'OFFICER_EMAIL_LIST_AND_POSITION_MAPPING__EMAIL_LIST_ADDRESS':
            OFFICER_EMAIL_LIST_AND_POSITION_MAPPING__EMAIL_LIST_ADDRESS,
        'OFFICER_EMAIL_LIST_AND_POSITION_MAPPING__ELECTED_VIA_ELECTION_OFFICER':
            OFFICER_EMAIL_LIST_AND_POSITION_MAPPING__ELECTED_VIA_ELECTION_OFFICER,
        'GITHUB_TEAM__ID_KEY': GITHUB_TEAM__ID_KEY,
        'GITHUB_TEAM__TEAM_NAME_KEY': GITHUB_TEAM__TEAM_NAME_KEY,
        'NUMBER_OF_TERMS': OfficerEmailListAndPositionMapping.number_of_terms_choices_to_display_on_html(),
        'STARTING_MONTHS': OfficerEmailListAndPositionMapping.starting_month_choices_to_display_on_html()
    })

    position_mapping_for_selected_officer = \
        OfficerEmailListAndPositionMapping.objects.all().order_by('position_index')
    if len(position_mapping_for_selected_officer) > 0:
        context[SAVED_OFFICER_POSITIONS] = position_mapping_for_selected_officer

    position_mapping_for_selected_officer = OfficerEmailListAndPositionMapping.objects.all().order_by(
        'position_index').exclude(marked_for_deletion=True)
    if len(position_mapping_for_selected_officer) > 0:
        context[OFFICER_POSITION_AVAILABLE_FOR_GITHUB_MAPPINGS] = position_mapping_for_selected_officer

    github_position_mappings = OfficerPositionGithubTeam.objects.all().order_by('id')
    if len(github_position_mappings) > 0:
        github_team_mappings = []
        for github_position_mapping in github_position_mappings:
            github_team_mapping = {
                'team_id': github_position_mapping.id,
                TEAM_NAME_KEY: github_position_mapping.team_name,
                'marked_for_deletion': github_position_mapping.marked_for_deletion,
                'relevant_previous_terms': github_position_mapping.relevant_previous_terms,
                'positions': []
            }
            selected_positions_for_mapping = [
                position_mapped_to_github_team.officer_position_mapping.position_index for
                position_mapped_to_github_team in
                github_position_mapping.officerpositiongithubteammapping_set.all()
            ]
            for position in position_mapping_for_selected_officer:
                github_team_mapping['positions'].append(
                    {
                        'id': position.id,
                        "position_name": position.position_name,
                        POSITION_INDEX_KEY: position.position_index,
                        "checked": position.position_index in selected_positions_for_mapping
                    }
                )
            github_team_mappings.append(github_team_mapping)
        context[SAVED_GITHUB_MAPPINGS] = github_team_mappings

    if ERROR_MESSAGES_KEY in context:
        error_experienced = False
        for error in context[ERROR_MESSAGES_KEY]:
            if error is not None and len(error) > 0:
                error_experienced = True

        if not error_experienced or len(context[ERROR_MESSAGES_KEY]) == 0:
            del context[ERROR_MESSAGES_KEY]

    return context

def validate_position_index(position_index, submitted_position_indices=None):
    """
    Validates the new inputted position index

    Keyword Argument
    position_index -- the new position index
    submitted_position_indexes -- other indexes specified by the user so far
     if they are submitting multiple positions at once

    Return
    success -- True or False if the new position index is not already used
    error_message -- an error_message if the index was already used
    """
    logger = Loggers.get_logger()
    if submitted_position_indices is None:
        submitted_position_indices = []
    if len(OfficerEmailListAndPositionMapping.objects.all().filter(
            position_index=position_index)) > 0 or position_index in submitted_position_indices:
        logger.info(f"[about/position_mapping_helper.py validate_position_index()] validate for position index "
                    f"{position_index} was unsuccessful")
        return False, f"Another Position already has an index of {position_index}"
    logger.info(f"[about/position_mapping_helper.py validate_position_index()] validate for position index "
                f"{position_index} was successful")
    return True, None

def validate_position_name(position_name, submitted_position_names=None):
    """
    Validates the new inputted position name

    Keyword Argument
    position_name -- the new position name
    submitted_position_names -- other names specified by the user so far if they
     are submitting multiple positions at once

    Return
    success -- True or False if the new position name is not already used
    error_message -- an error_message if the name was already used
    """
    logger = Loggers.get_logger()
    if submitted_position_names is None:
        submitted_position_names = []
    if len(OfficerEmailListAndPositionMapping.objects.all().filter(
            position_name=position_name)) > 0 or position_name in submitted_position_names:
        logger.info(f"[about/position_mapping_helper.py validate_position_name()] validate for position name "
                    f"{position_name} was unsuccessful")
        return False, f"the position of {position_name} already exists"
    logger.info(f"[about/position_mapping_helper.py validate_position_name()] validate for position name "
                f"{position_name} was successful")
    return True, None

def validate_elected_via_election_officer_status(elected_via_election_officer_status):
    """
    Validates the status selected for the attribute of elected via election officer

    Keyword Argument
    elected_via_election_officer_status -- the atribute that indicates if the position is elected via election officer

    Return
    success -- True or False if the attribute of elected via election officer is valid
    error_message -- an error_message if the attribute is not one of the valid options
    """
    logger = Loggers.get_logger()
    if not (elected_via_election_officer_status == 'True' or elected_via_election_officer_status == 'False'):
        logger.info("[about/position_mapping_helper.py validate_elected_via_election_officer_status()] "
                    "validating for if the position is elected via election officer "
                    f"{elected_via_election_officer_status} was unsuccessful")
        return False, f"the option of elected_via_election_officer which is set to" \
                      f" {elected_via_election_officer_status} is invalid"
    return True, None

def validate_executive_officer_status(executive_officer_status):
    """
    Validates the status selected for the attribute of whether the officer is an executive officer

    Keyword Argument
    executive_officer_status -- the attribute that indicates if the position is an executive position

    Return
    success -- True or False if the attribute of whether the officer is an executive officer is valid
    error_message -- an error_message if the attribute is not one of the valid options
    """
    logger = Loggers.get_logger()
    if not (executive_officer_status == 'True' or executive_officer_status == 'False'):
        logger.info("[about/position_mapping_helper.py validate_executive_status()] "
                    "validating for if the position is for an executive officer "
                    f"{executive_officer_status} was unsuccessful")
        return False, f"the option of executive_officer_status which is set to" \
                      f" {executive_officer_status} is invalid"
    return True, None

def validate_election_officer_status(election_officer_status):
    """
    Validates the status selected for the attribute of whether the officer is an election officer

    Keyword Argument
    election_officer_status -- the attribute that indicates if the position is an election officer position

    Return
    success -- True or False if the attribute of whether the officer is an election officer is valid
    error_message -- an error_message if the attribute is not one of the valid options
    """
    logger = Loggers.get_logger()
    if not (election_officer_status == 'True' or election_officer_status == 'False'):
        logger.info("[about/position_mapping_helper.py validate_election_officer_status()] "
                    "validating for if the position is for an election officer "
                    f"{election_officer_status} was unsuccessful")
        return False, f"the option of election_officer_status which is set to" \
                      f" {election_officer_status} is invalid"
    return True, None

def validate_sfss_council_representative_status(sfss_council_representative_status):
    """
    Validates the status selected for the attribute of whether the officer is the SFSS Council Representative

    Keyword Argument
    sfss_council_representative_status -- the attribute that indicates if the position is an SFSS Council
     Representative

    Return
    success -- True or False if the attribute of whether the officer is an SFSS Council Representative is valid
    error_message -- an error_message if the attribute is not one of the valid options
    """
    logger = Loggers.get_logger()
    if not (sfss_council_representative_status == 'True' or sfss_council_representative_status == 'False'):
        logger.info("[about/position_mapping_helper.py validate_sfss_council_representative_status()] "
                    "validating for if the position is for an SFSS Council Representative "
                    f"{sfss_council_representative_status} was unsuccessful")
        return False, f"the option of sfss_council_representative_status which is set to" \
                      f" {sfss_council_representative_status} is invalid"
    return True, None

def validate_frosh_week_chair_status(frosh_week_chair_status):
    """
    Validates the status selected for the attribute of whether the officer is the frosh week chair

    Keyword Argument
    frosh_week_chair_status -- the attribute that indicates if the position is the frosh week chair position

    Return
    success -- True or False if the attribute of whether the officer is the frosh week chair is valid
    error_message -- an error_message if the attribute is not one of the valid options
    """
    logger = Loggers.get_logger()
    if not (frosh_week_chair_status == 'True' or frosh_week_chair_status == 'False'):
        logger.info("[about/position_mapping_helper.py validate_frosh_week_chair_status()] "
                    "validating for if the position is for the frosh week chair "
                    f"{frosh_week_chair_status} was unsuccessful")
        return False, f"the option of frosh_week_chair_status which is set to" \
                      f" {frosh_week_chair_status} is invalid"
    return True, None

def validate_discord_manager_status(discord_manager_status):
    """
    Validates the status selected for the attribute of whether the officer is the discord manager

    Keyword Argument
    discord_manager_status -- the attribute that indicates if the position is for the discord manager

    Return
    success -- True or False if the attribute of whether the officer is the discord manager is valid
    error_message -- an error_message if the attribute is not one of the valid options
    """
    logger = Loggers.get_logger()
    if not (discord_manager_status == 'True' or discord_manager_status == 'False'):
        logger.info("[about/position_mapping_helper.py validate_discord_manager_status()] "
                    "validating for if the position is for the discord manager "
                    f"{discord_manager_status} was unsuccessful")
        return False, f"the option of discord_manager_status which is set to" \
                      f" {discord_manager_status} is invalid"
    return True, None

def validate_github_access(github_access):
    """
    Validates the status selected for the attribute of github access

    Keyword Argument
    github_access -- the atribute that indicates if the position has github access

    Return
    success -- True or False if the attribute of github access is valid
    error_message -- an error_message if the attribute is not one of the valid options
    """
    logger = Loggers.get_logger()
    if not (github_access == 'True' or github_access == 'False'):
        logger.info("[about/position_mapping_helper.py validate_github_access()] "
                    "validating for if the position has github access "
                    f"{github_access} was unsuccessful")
        return False, f"the option of github access which is set to" \
                      f" {github_access} is invalid"
    return True, None

def validate_google_drive_access(google_drive_access):
    """
    Validates the status selected for the attribute of google drive access

    Keyword Argument
    google_drive_access -- the atribute that indicates if the position has google drive access

    Return
    success -- True or False if the attribute of google drive access is valid
    error_message -- an error_message if the attribute is not one of the valid options
    """
    logger = Loggers.get_logger()
    if not (google_drive_access == 'True' or google_drive_access == 'False'):
        logger.info("[about/position_mapping_helper.py validate_google_drive_access()] "
                    "validating for if the position has google drive access "
                    f"{google_drive_access} was unsuccessful")
        return False, f"the option of google drive access which is set to" \
                      f" {google_drive_access} is invalid"
    return True, None

GITHUB_MAPPING_SELECTED_OFFICER_POSITION_KEY = 'github_mapping_selected_officer_position'

def extract_valid_officers_positions_selected_for_github_team(post_dict):
    """
    extracts the officer position indices that have been selected to add to a github team

    Keyword Argument
    post_dict -- the dictionary created from the POST object that has the selected position indices
     mapped to the value "github_mapping_selected_officer_position"

    Return
    success - a bool, True if position indices were found
    error_message -- the error message if not successful, otherwise None
    officer_position_indices -- an int list of officer position indices that have been selected, if any were selected
    """
    logger = Loggers.get_logger()
    if not (GITHUB_MAPPING_SELECTED_OFFICER_POSITION_KEY in post_dict):
        error_message = "Did not find any positions that were selected"
        logger.info("[about/position_mapping_helper.py extract_valid_officers_positions_selected_for_github_team()]"
                    f" {error_message}")
        return False, error_message, None

    if there_are_multiple_entries(post_dict, GITHUB_MAPPING_SELECTED_OFFICER_POSITION_KEY):
        officer_positions = [
            f"{officer_position_index}".strip()
            for officer_position_index in post_dict[GITHUB_MAPPING_SELECTED_OFFICER_POSITION_KEY]
            if len(f"{officer_position_index}".strip()) > 0
        ]
        success = len(officer_positions) > 0
        logger.info(
            "[about/position_mapping_helper.py extract_valid_officers_positions_selected_for_github_team()] found "
            "multiple officer positions. Transformed "
            f"{post_dict[GITHUB_MAPPING_SELECTED_OFFICER_POSITION_KEY]} to {officer_positions}"
            f" which has of {len(officer_positions)}"
        )
    else:
        officer_positions = f"{post_dict[GITHUB_MAPPING_SELECTED_OFFICER_POSITION_KEY]}".strip()
        success = len(officer_positions) > 0
        officer_positions = [officer_positions]
        logger.info(
            "[about/position_mapping_helper.py extract_valid_officers_positions_selected_for_github_team()] found a "
            "single officer position index. Transformed "
            f"{post_dict[GITHUB_MAPPING_SELECTED_OFFICER_POSITION_KEY]} to {officer_positions},"
            f" and has a success of {success}"
        )
    if not success:
        error_message = "No valid officer position indices detected"
        logger.info(f"[about/position_mapping_helper.py extract_valid_officers_positions_selected_for_github_team()]"
                    f" {error_message}")
        return False, error_message, None

    return True, None, officer_positions

def validate_position_names_for_github_team(officer_position_names):
    """
    Validates the position names that were specified in the user's POST call

    Keyword Argument
    officer_position_names -- the names that are in the user's POST call

    Return
    success -- bool that is true or false depending on if all the officer position names are valid
    error_message -- an error message if one of the position names are invalid
    """
    logger = Loggers.get_logger()
    for officer_position_name in officer_position_names:
        if len(OfficerEmailListAndPositionMapping.objects.all().filter(position_name=officer_position_name)) == 0:
            error_message = f"There is no position mapped to the position name of {officer_position_name}"
            logger.info(
                "[about/position_mapping_helper.py "
                f"_validate_position_names_and_team_name_for_new_github_team()] {error_message}"
            )
            return False, error_message
    return True, None

def validate_number_of_terms(number_of_terms):
    """
    Validates the number of terms that were specified in the user's POST call

    Keyword Argument
    number_of_terms -- the number of terms that are in the user's POST call

    Return
    success -- bool that is true or false depending on if all the number of terms are valid
    error_message -- an error message if one of the number of terms are invalid
    """
    logger = Loggers.get_logger()
    if number_of_terms not in OfficerEmailListAndPositionMapping.number_of_terms_choices_dict():
        error_message = f"Invalid number of terms of {number_of_terms} specified"
        logger.info(
            "[about/position_mapping_helper.py "
            f"validate_number_of_terms()] {error_message}"
        )
        return False, error_message
    return True, None

def validate_starting_month(starting_month):
    """
    Validates the starting months that were specified in the user's POST call

    Keyword Argument
    starting_month -- the starting months that are in the user's POST call

    Return
    success -- bool that is true or false depending on if all the starting months are valid
    error_message -- an error message if one of the starting months are invalid
    """
    logger = Loggers.get_logger()
    if starting_month not in OfficerEmailListAndPositionMapping.starting_month_choices_dict():
        error_message = f"Invalid starting month of {starting_month} specified"
        logger.info(
            "[about/position_mapping_helper.py "
            f"validate_starting_month()] {error_message}"
        )
        return False, error_message
    return True, None


# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import migrations, models

class Migration(migrations.Migration):

    dependencies = [
        ('sap_success_factors', '0015_auto_20180510_1259'),
    ]

    operations = [
        migrations.AddField(
            model_name='sapsuccessfactorsenterprisecustomerconfiguration',
            name='additional_locales',
            field=models.TextField(default='', help_text='A comma-separated list of additional locales.', verbose_name='Additional Locales', blank=True),
        ),
    ]


import random

def adding_numbers_to_coordinates(x, y):
    x += random.randint(0, 5)
    y += random.randint(0, 10)
    return x / y

def subtract_the_numbers(x, y):
    x -= random.randint(0, 5)
    y -= random.randint(0, 10)
    return y / x

try:
    with open('coordinates.txt', 'r') as file_coordinates, open('result.txt', 'w') as file_answer:
        for line in file_coordinates:
            nums_list = line.split()
            result_adding = adding_numbers_to_coordinates(int(nums_list[0]), int(nums_list[1]))
            result_subtract = subtract_the_numbers(int(nums_list[0]), int(nums_list[1]))
            number = random.randint(0, 100)
            my_list = sorted([result_adding, result_subtract, number])
            file_answer.write(''.join(str(my_list)))
            file_answer.write('\n')
except ZeroDivisionError as exc:
    print(exc, type(exc))


#!/cma/g3/wangdp/usr/local/bin/python3
import subprocess
import re
import datetime
import json
from collections import defaultdict

import click

def get_system_from_path(path):
    if path == "/":
        return None
    if not path.startswith('/'):
        return None
    index = path.find('/', 1)
    return path[1: index]

def run_command(command):
    pipe = subprocess.Popen([command], stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
    output, error_output = pipe.communicate()
    output_string = None
    if output is not None:
        output_string = output.decode()
    error_output_string = None
    if error_output is not None:
        error_output_string = error_output.decode()
    return output_string, error_output_string

def parse_error_log(log_string):
    p = re.compile('^\[(.*)\]\[(.*)\](.*): (.*) (.*) (.*) (.*)$')
    m = p.match(log_string)
    date_string = m.group(1)
    command = m.group(2)
    message = m.group(3)
    job_script = m.group(4)
    path = m.group(5)
    total_tries = m.group(6)
    current_try_no = m.group(7)
    record = dict()
    record['date'] = datetime.datetime.strptime(date_string, '%Y-%m-%dT%H:%M:%S%Z')
    record['command'] = command
    record['message'] = message
    record['info'] = {
        'job_script': job_script,
        'path': path,
        'total_tries': total_tries,
        'current_try_no': current_try_no
    }
    return record

def get_record_field_value(record, name):
    def get_date_hour(x):
        cur_datetime = x['date']
        cur_date = cur_datetime.date()
        zero_time = datetime.time(cur_datetime.hour)
        cur_hour = datetime.datetime.combine(cur_date, zero_time)
        return cur_hour.strftime("%Y-%m-%d %H:%M:%S")

    field_mapper = {
        'month': lambda x: x['date'].strftime("%Y-%m"),
        'date': lambda x: x['date'].strftime("%Y-%m-%d"),
        'weekday': lambda x: x['date'].weekday(),
        'system': lambda x: get_system_from_path(x['info']['path']),
        'date-hour': get_date_hour,
        'hour': lambda x: x['date'].hour,
    }

    if name in field_mapper:
        return field_mapper[name](record)
    else:
        raise Exception('name unsupported', name)

@click.group()
def cli():
    """
DESCRIPTION
    Analytic llsubmit4 error log."""
    pass

@cli.command('info', help='get log file info')
@click.option('-f', '--file', 'log_file_path', required=True, help="log file path")
@click.option("--pretty-print/--no-pretty-print", default=False, help="print pretty result.")
def info(log_file_path, pretty_print):
    """
    get log file info
    """

    command = "head -n 1 {log_file_path}".format(log_file_path=log_file_path)
    output_string, error_string = run_command(command)
    if len(error_string) > 0:
        result = {
            'app': 'llsubmit4_error_analyzer',
            'type': 'range',
            'timestamp': datetime.datetime.now().timestamp(),
            'error': 'head_command_error',
            'data': {
                'error_message': 'error in executing head command.',
                'output': {
                    'std_out': output_string,
                    'std_err': error_string
                },
                'request': {
                    'log_file_path': log_file_path,
                }
            }
        }

        if pretty_print:
            print(json.dumps(result, indent=4))
        else:
            print(json.dumps(result))
        return

    record = parse_error_log(output_string)
    start_date = record['date']

    command = "tail -n 1 {log_file_path}".format(log_file_path=log_file_path)
    output_string, error_string = run_command(command)
    if len(error_string) > 0:
        result = {
            'app': 'llsubmit4_error_analyzer',
            'type': 'range',
            'timestamp': datetime.datetime.now().timestamp(),
            'error': 'tail_command_error',
            'data': {
                'error_message': 'error in executing tail command.',
                'output': {
                    'std_out': output_string,
                    'std_err': error_string
                },
                'request': {
                    'log_file_path': log_file_path,
                }
            }
        }

        if pretty_print:
            print(json.dumps(result, indent=4))
        else:
            print(json.dumps(result))
        return

    record = parse_error_log(output_string)
    end_date = record['date']

    command = "wc -l {log_file_path}".format(log_file_path=log_file_path)
    output_string, error_string = run_command(command)
    if len(error_string) > 0:
        result = {
            'app': 'llsubmit4_error_analyzer',
            'type': 'range',
            'timestamp': datetime.datetime.now().timestamp(),
            'error': 'tail_command_error',
            'data': {
                'error_message': 'error in executing wc command.',
                'output': {
                    'std_out': output_string,
                    'std_err': error_string
                },
                'request': {
                    'log_file_path': log_file_path,
                }
            }
        }

        if pretty_print:
            print(json.dumps(result, indent=4))
        else:
            print(json.dumps(result))

        return

    line_count = int(output_string.strip().split(' ')[0])

    # with open(log_file_path, 'r') as log_file:
    #     for line in log_file:
    #         record = parse_error_log(line)
    #         print(record['date'])

    result = {
        'app': 'llsubmit4_error_analyzer',
        'type': 'info',
        'timestamp': datetime.datetime.now().timestamp(),
        'data': {
            'range': {
                'start_date_time': start_date.strftime('%Y-%m-%dT%H:%M:%S%Z'),
                'end_date_time': end_date.strftime('%Y-%m-%dT%H:%M:%S%Z'),
                'count': line_count
            },
            'request': {
                'log_file_path': log_file_path,
            }
        }
    }
    if pretty_print:
        print(json.dumps(result, indent=4))
    else:
        print(json.dumps(result))

@cli.command('count', help='count errors in error log file.')
@click.option("-f", "--file", "log_file_path", required=True, help="log file path")
@click.option("--begin-date", help="begin date, YYYY-MM-DD")
@click.option("--end-date", help="end date, YYYY-MM-DD")
@click.option("--begin-time", help="begin time, hh:mm:ss")
@click.option("--end-time", help="end time, hh:mm:ss")
@click.option("--type", "count_type", required=True,
              type=click.Choice(['month', 'date', 'weekday', 'date-hour', 'hour', 'system']),
              help="count type", )
@click.option("--pretty-print/--no-pretty-print", default=False, help="print pretty result.")
def count(log_file_path, begin_date, end_date, begin_time, end_time, count_type, pretty_print):
    """
    count errors in error log file.
    """
    if begin_date:
        begin_date = datetime.datetime.strptime(begin_date, "%Y-%m-%d")
    if end_date:
        end_date = datetime.datetime.strptime(end_date, "%Y-%m-%d")

    count_result = defaultdict(int)
    try:
        with open(log_file_path, 'r') as log_file:
            for line in log_file:
                record = parse_error_log(line)
                # check date
                if begin_date:
                    if record['date'].date() < begin_date.date():
                        continue
                if end_date:
                    if record['date'].date() >= end_date.date():
                        continue

                count_result[get_record_field_value(record, count_type)] += 1

    except FileNotFoundError as e:
        result = {
            'app': 'llsubmit4_error_analyzer',
            'type': 'count',
            'error': 'file_not_found',
            'timestamp': datetime.datetime.now().timestamp(),
            'data': {
                'error_message': 'file is not found',
                'request': {
                    'log_file_path': log_file_path,
                    'begin_date': begin_date.strftime('%Y-%m-%d'),
                    'end_date': end_date.strftime('%Y-%m-%d'),
                    'count_type': count_type
                }
            }
        }
        if pretty_print:
            print(json.dumps(result, indent=4))
        else:
            print(json.dumps(result))
        return

    result = {
        'app': 'llsubmit4_error_analyzer',
        'type': 'count',
        'timestamp': datetime.datetime.now().timestamp(),
        'data': {
            # 'count_type': count_type,
            # 'begin_date': begin_date.strftime('%Y-%m-%d'),
            # 'end_date': end_date.strftime('%Y-%m-%d'),
            # 'count_result': count_result,
            'request': {
                'log_file_path': log_file_path,
                'begin_date': begin_date.strftime('%Y-%m-%d'),
                'end_date': end_date.strftime('%Y-%m-%d'),
                'count_type': count_type
            },
            'response': {
                'count_result': count_result,
            }
        }
    }

    if pretty_print:
        print(json.dumps(result, indent=4))
    else:
        print(json.dumps(result))

@cli.command('grid', help='get grid result.')
@click.option("-f", "--file", "log_file_path", required=True, help="log file path")
@click.option("--begin-date", help="begin date, YYYY-MM-DD")
@click.option("--end-date", help="end date, YYYY-MM-DD")
@click.option("--begin-time", help="begin time, hh:mm:ss")
@click.option("--end-time", help="end time, hh:mm:ss")
@click.option("--x-type", "x_type", required=True,
              type=click.Choice(['hour', 'weekday']),
              help="x axis type")
@click.option("--y-type", "y_type", required=True,
              type=click.Choice(['weekday', 'system', 'date']),
              help="y axis type")
@click.option("--pretty-print/--no-pretty-print", default=False, help="print pretty result.")
def grid(log_file_path, begin_date, end_date, begin_time, end_time, x_type, y_type, pretty_print):
    """
    get grid result.
    """
    if begin_date:
        begin_date = datetime.datetime.strptime(begin_date, "%Y-%m-%d")
    if end_date:
        end_date = datetime.datetime.strptime(end_date, "%Y-%m-%d")

    grid_result = dict()
    try:
        with open(log_file_path, 'r') as log_file:
            for line in log_file:
                record = parse_error_log(line)
                # check date
                if begin_date:
                    if record['date'].date() < begin_date.date():
                        continue
                if end_date:
                    if record['date'].date() >= end_date.date():
                        continue

                x_value = get_record_field_value(record, x_type)
                y_value = get_record_field_value(record, y_type)

                if x_value not in grid_result:
                    grid_result[x_value] = dict()
                if y_value not in grid_result[x_value]:
                    grid_result[x_value][y_value] = 0
                grid_result[x_value][y_value] += 1

    except FileNotFoundError:
        result = {
            'app': 'llsubmit4_error_analyzer',
            'type': 'grid',
            'error': 'file_not_found',
            'timestamp': datetime.datetime.now().timestamp(),
            'data': {
                'error_message': 'file is not found',
                'request': {
                    'log_file_path': log_file_path,
                }
            }
        }
        if pretty_print:
            print(json.dumps(result, indent=4))
        else:
            print(json.dumps(result))
        return

    result = {
        'app': 'llsubmit4_error_analyzer',
        'type': 'grid',
        'timestamp': datetime.datetime.now().timestamp(),
        'data': {
            'response': {
                'grid_result': grid_result,
            },
            'request': {
                'log_file_path': log_file_path,
                'x_type': x_type,
                'y_type': y_type,
                'begin_date': begin_date.strftime('%Y-%m-%d'),
                'end_date': end_date.strftime('%Y-%m-%d'),
            }
        }
    }

    if pretty_print:
        print(json.dumps(result, indent=4))
    else:
        print(json.dumps(result))

if __name__ == "__main__":
    cli()


import os
os.environ['USE_PYGEOS'] = '0'
from owslib.wfs import WebFeatureService
from owslib.wms import WebMapService
import geopandas as gpd
import json
import fiona

import os

# # Get the absolute path of the current file
# absolute_path = os.path.abspath(__file__)

# # Get the directory name of the current file
# directory_name = os.path.dirname(absolute_path)

# # Get the relative path of the current file
# relative_path = os.path.relpath(absolute_path)

# print("Absolute path:", absolute_path)
# print("Directory name:", directory_name)
# print("Relative path:", relative_path)

data_informations_path = "./data/data_informations.json"

def create_data_informations_file():
    """ Fonction to instantiate data_informations.json file """

    data_informations = {
        "services" : {
            "data.grandlyon_wfs": "https://download.data.grandlyon.com/wfs/grandlyon?SERVICE=WFS&VERSION=2.0.0",
            "data.grandlyon_wms" : "https://download.data.grandlyon.com/wms/grandlyon?VERSION=1.3.0&SERVICE=WMS"
        },
        "osm": {
            "network_parameters": {
            }
        },
        "data_wfs" : {
            "fontaines_potables": {
                "name": "Fontaines potables",
                "wfs_key": "ms:epo_eau_potable.epobornefont",
                "service": "data.grandlyon_wfs",
                "marker_option": {
                "iconUrl": "droplet.svg",
                "iconRetinaUrl": "droplet.svg",
                "popupAnchor":  [-0, -0],
                "iconSize": [40,40],
                "clusterCountStyle" : "position:absolute;top:20px;left:-9px;color:white;font-weight:bold;"
                }
            },
            "toilettes_publiques": {
                "name": "Toilettes publiques",
                "wfs_key": "ms:adr_voie_lieu.adrtoilettepublique_latest",
                "service": "data.grandlyon_wfs",
                "marker_option": {
                "iconUrl": "toilet.svg",
                "iconRetinaUrl": "toilet.svg",
                "popupAnchor":  [-0, -0],
                "iconSize": [40,40],
                "clusterCountStyle" : "position:absolute;top:48px;left:-6px;color:black;font-weight:bold;"
                }
            },
            "fontaines_ornementales": {
                "name": "Fontaines ornementales",
                "wfs_key": "ms:adr_voie_lieu.adrfontaineornem_latest",
                "service": "data.grandlyon_wfs",
                "marker_option": {
                "iconUrl": "fountain.svg",
                "iconRetinaUrl": "fountain.svg",
                "popupAnchor":  [-0, -0],
                "iconSize": [40,40],
                "clusterCountStyle" : "position:absolute;top:48px;left:0px;color:black;font-weight:bold;"
            }
            },
            "parcs_jardins_metropole": {
                "name": "Parcs et jardins",
                "wfs_key": "ms:com_donnees_communales.comparcjardin_1_0_0",
                "service": "data.grandlyon_wfs",
            },
            "bancs": {
                "name": "Bancs",
                "wfs_key": "ms:adr_voie_lieu.adrbanc_latest",
                "service": "data.grandlyon_wfs",
                "marker_option": {
                "iconUrl": "bench.svg",
                "iconRetinaUrl": "bench.svg",
                "popupAnchor":  [-0, -0],
                "iconSize": [25,25],
                "clusterCountStyle": "position:absolute;top:0px;left:-10px;color:black;font-weight:bold;"
            }
            },
            # "arbres_alignement": {
            #     "wfs_key": "ms:abr_arbres_alignement.abrarbre",
            #     "service": "data.grandlyon_wfs",
            # },
            # à mettre dans un second temps
            # "hauteur_batiment": {
            #     "wfs_key": "ms:fpc_fond_plan_communaut.fpctoit_2018",
            #     "service": "data.grandlyon_wfs"
            # }

        },
        "data_wms": {
            "vegetation_stratifie" : {
                "wms_key": "MNC_class_2022_INT1U",
                "service" : "data.grandlyon_wms",
                "width" : 3500,
                "height": 3640,
                "format" : "png",
                "transparent" : True,
                "srs": "EPSG:4171"
            }
        },
        "data_raw" : {
            # "vegetation_stratifie_raw" : {
            #     "name": "Végétation stratifiée",
            #     "gpkg_path": "./backend/script_python/data/raw_data/vegetation_stratifie.gpkg"
            # },
            "temp_surface_road_raw": {
                "name": "Température de surface",
                "gpkg_path": "./raw_data/temp_surface.gpkg"
            },
        #     "joined_if": {
        #         "name" : "Calque fraîcheur",
        #         "gpkg_path": "./backend/script_python/data/raw_data/joined_if_3946.gpkg",
        # }
        }
    }

    with open(data_informations_path, "w") as f:
        json.dump(data_informations, f, indent=4)

def create_folder(folder_path):
    exist = os.path.exists(folder_path)
    if not exist:
        os.makedirs(folder_path)
        print(f"{folder_path} created")

def connection_wfs(url, service_name, version):
    """ Return a wfs object after connecting to a service thanks the url provided """
    print(f"Connecting {service_name} WFS ... ")
    wfs=None
    try:
        wfs = WebFeatureService(url, version)
        print(f"SUCCESS : Connected to {service_name}")
    except NameError:
        print(f"Error while connecting to {service_name} ... : {NameError}")

    return wfs

def connection_wms(url, service_name, version):
    """ Return a wms object after connecting to a service thanks the url provided """
    print(f"Connecting {service_name} WMS ... ")
    wms=None
    try:
        wms = WebMapService(url, version)
        print(f"SUCCESS : Connected to {service_name}")
    except NameError:
        print(f"Error while connecting to {service_name} ... : {NameError}")

    return wms

def download_data_wfs(service_name, version, path):
    """ load a list of data from one specific service
        the data are stored in a json file as a dictionnary wich elements have the folowing form :

        "data_name" : {
            "wfs_key" : 'key',
            "service" : 'service_name',
            "download_path": "path/file.gml"
        }
    """

    with open(data_informations_path, "r") as f:
        data_informations = json.load(f)

    data_wfs = data_informations["data_wfs"]
    services = data_informations["services"]

    wfs = connection_wfs(services[f"{service_name}"], service_name, version)

    for d_name, d_info in data_wfs.items():
        if(d_info["service"] == service_name):

            print(f"### {d_name} ###")

            # the boundingBox define the area where the data should belong to
            box = wfs.contents[f"{d_info['wfs_key']}"].boundingBoxWGS84

            print(f"fetching {d_name} ..")
            try:
                new_data = wfs.getfeature(typename=f"{d_info['wfs_key']}", bbox=box)
                print(f"SUCCESS")
            except NameError:
                print(f"Error while fetching {d_name} from {service_name}... : {NameError}")

            print(f"writing {d_name} GML file into {path} \n")

            #write file into given folder (path)
            file = open(f"{path}/{d_name}.gml", "wb")
            file.write(new_data.read())
            file.close()

            #store download path into data_informations.json
            data_informations["data_wfs"][d_name]["gml_path"] = f"{path}/{d_name}.gml"

    # re-write data_informations.json => store all download path
    with open(data_informations_path, "w") as f:
        json.dump(data_informations, f, indent=4)

def download_data_wms(service_name, version, path):
    """ load a list of data from one specific service
        the data are stored in a json file as a dictionnary wich elements have the folowing form :

        "data_name" : {
            "wfs_key" : 'key',
            "service" : 'service_name',
            "download_path": "path/file.gml"
        }
    """

    with open(data_informations_path, "r") as f:
        data_informations = json.load(f)

    data_wms = data_informations["data_wms"]
    services = data_informations["services"]

    wms = connection_wms(services[f"{service_name}"], service_name, version)

    for d_name, d_info in data_wms.items():
        if(d_info["service"] == service_name):

            print(f"### {d_name} ###")

            # the boundingBox define the area where the data should belong to
            box = wms.contents[f"{d_info['wms_key']}"].boundingBoxWGS84

            print(f"fetching {d_name} ..")
            print(d_info['wms_key'])
            try:
                img = wms.getmap(layers=[f"{d_info['wms_key']}"], bbox=box, size=(d_info["width"], d_info["height"]), srs=d_info["srs"], format=f"image/{d_info['format']}" , transparent=d_info["transparent"])
                print(f"SUCCESS")
            except NameError:
                print(f"Error while fetching {d_name} from {service_name}... : {NameError}")

            print(f"writing {d_name} Raster file into {path} \n")

            #write file into given folder (path)
            file = open(f"{path}/{d_name}.{d_info['format']}", "wb")
            file.write(img.read())
            file.close()

            #store download path into data_informations.json
            data_informations["data_wms"][d_name][f"{d_info['format']}_path"] = f"{path}/{d_name}.{d_info['format']}"

    # re-write data_informations.json => store all download path
    with open(data_informations_path, "w") as f:
        json.dump(data_informations, f, indent=4)

def convert_file(input_path, output_path, driver, input_extension = "gml", output_extension='gpkg', folder=False):
    """Convert file type
    If folder = TRUE, all of the files of the given folder are converted to the desired format.
    Careful about the path : either a folder or a file one.
    """
    print("converting ... ")
    if(folder):
        for filename in os.listdir(input_path):
            print(f"filename : {filename}")
            if filename.endswith(input_extension):
                # Read input GML file into a GeoDataFrame
                gdf = gpd.read_file(os.path.join(input_path, filename))

                if(driver == "GeoJSON"):
                    # 4326 is crs of OSM => used to project data on leaflet
                    gdf = gdf.to_crs(epsg=4326)
                    print("CRS of GEOJSON: ", gdf.crs)

                if(driver == "GPKG"):
                    gdf = gdf.to_crs(epsg=3946)

                # Set output file path and name
                output_name = filename.replace(input_extension, output_extension)
                new_output_path = os.path.join(output_path, output_name)

                # Write GeoDataFrame to output Shapefile
                gdf.to_file(new_output_path, driver=driver)

                print("Done, all GML files converted into GPKG")
    else:

        gdf = gpd.read_file(input_path)
        if(driver == "GeoJSON"):
            # 4326 is crs of OSM => used to project data on leaflet
            gdf = gdf.to_crs(epsg=4326)
        if(driver == "GPKG"):
            gdf = gdf.to_crs(epsg=3946)
        gdf.to_file(output_path, driver=driver)
        print(f"Done, {input_path} converted into {output_extension}")

def convert_all(output_path_folder, input_extension, output_extension, driver, connection_type="wfs"):

    """Convert all data stored in data_informations from input format to ouput format"""

    with open(data_informations_path, "r") as f:
        data_informations = json.load(f)

    data = data_informations[f'data_{connection_type}']
    for d_name, d_info in data.items():
        download_path = d_info[f"{input_extension}_path"]
        if(download_path.endswith(input_extension)):
            new_path = f"{output_path_folder}{d_name}.{output_extension}"
            convert_file(download_path, new_path, input_extension=input_extension, output_extension=output_extension, driver=driver)
            if(driver == "GeoJSON"):
                data_informations[f"data_{connection_type}"][d_name][f"geo{output_extension}_path"] = new_path
            else:
                data_informations[f"data_{connection_type}"][d_name][f"{output_extension}_path"] = new_path

    with open(data_informations_path, "w") as f:
        json.dump(data_informations, f, indent=4)

def points_to_polygon(point_path, polygon_path):
    """
        Computes the convex hull of a point shapefile and converts it to a polygon shapefile
    """

    points = gpd.read_file(point_path)

    # change temporarily the CRS (projection system) because buffering need meter
    # points.to_crs(epsg=3857)

    # Create a buffer around each point
    buffered_points = points.buffer(points["buffer_size"])

    # Convert the buffered points to polygons
    polygons = buffered_points.geometry.apply(lambda x: x.convex_hull)

    # Create a new GeoDataFrame with the polygon geometry and any additional attributes from the original points shapefile
    polygon_gdf = gpd.GeoDataFrame(points.drop('geometry', axis=1), geometry=polygons, crs=3946)

    # final_polygon = polygon_gdf.to_crs(epsg=4171)

    polygon_gdf.to_file(polygon_path, driver="GPKG")

def convert_all_points_into_polygons(output_path_folder):
    """ Convert all shapefile with Points Type into Polygons """

    with open(data_informations_path, "r") as f:
        data_informations = json.load(f)

    for d_name, d_info in data_informations["data_wfs"].items():
        original_gpkg_file = gpd.read_file(d_info["cleaned_data_path"])
        #if(original_gpkg_file.geom_type[0] == "Point"):
        buffered_path = f"{output_path_folder}{d_name}_buffered.gpkg"

        print(f"Converting {d_name} into Polygons ... ")

        points_to_polygon(d_info["cleaned_data_path"], buffered_path)
        data_informations["data_wfs"][d_name]["buffered_path"] = buffered_path

    with open(data_informations_path, "w") as f:
        json.dump(data_informations, f, indent=4)

def get_attributes_list(file_path):
    file = gpd.read_file(file_path)
    attribute_list = list(file.columns)
    return(attribute_list)

def write_all_atributes():
    """ Write into data_informations.json all attributes of the layer """

    print("Writing all attributes into data_informations.json file ...")

    with open(data_informations_path, "r") as f:
        data_informations = json.load(f)

    data_wfs = data_informations['data_wfs']
    for d_name, d_info in data_wfs.items():
        #the shape file is the original file containing all attributes
        file_path = data_wfs[d_name]["gpkg_path"]
        attribute_list = get_attributes_list(file_path)
        #print(f"{d_name} = {attribute_list}")
        data_informations["data_wfs"][d_name]["all_attributes"] = attribute_list

    with open(data_informations_path, "w") as f:
        json.dump(data_informations, f, indent=4)

    print("DONE")

def write_attributes_to_add_and_remove(data_name, attributes_to_add, attributes_to_remove):
    """ Write into data_informations.json all attributes to add or remove for one data
        attributes_to_add is a dictionnary with the pair key, values,
        attributes_to_remove is a list of attributes

        attributes_to_add = {
            attribute1 : default_value1
            attribute2 : default_value2
        }
        attributes_to_remove = ["attribute1", "attribute2"]
    """

    with open(data_informations_path, "r") as f:
        data_informations = json.load(f)

    data_informations['data_wfs'][data_name]['attributes_to_remove'] = attributes_to_remove
    data_informations['data_wfs'][data_name]['attributes_to_add'] = attributes_to_add

    with open(data_informations_path, "w") as f:
        json.dump(data_informations, f, indent=4)

def remove_attributes(input_path, output_path, attributes_to_remove):
    file = gpd.read_file(input_path)
    file = file.drop(attributes_to_remove, axis=1)
    file.to_file(output_path)

def add_attributes(input_path, output_path, attributes_to_add):
    """attributes_to_add should be a dictionnary with the following structure :

    attributes_to_add = {
        'new_attribute1': [1, 2, 3],
        'new_attribute2': ['a', 'b', 'c']
    }

    This function can be used to update the attributes

    """
    file = gpd.read_file(input_path)

    for attribute_name, values in attributes_to_add.items():
        file[attribute_name] = values

    file.to_file(output_path)

def remove_and_add_attributes(output_path_folder):
    """ """

    with open(data_informations_path, "r") as f:
        data_informations = json.load(f)

    data_wfs = data_informations["data_wfs"]
    for d_name, d_info in data_wfs.items():
        print(f"Remove and Add attributes for {d_name}")
        input_path = d_info["gpkg_path"]
        output_path = f"{output_path_folder}{d_name}_cleaned.gpkg"
        remove_attributes(input_path, output_path, d_info["attributes_to_remove"])
        add_attributes(output_path, output_path, d_info["attributes_to_add"])

        data_informations["data_wfs"][d_name]["cleaned_data_path"] = output_path

    with open(data_informations_path, "w") as f:
        json.dump(data_informations, f, indent=4)

def print_layers_name(folder_path):
    for filename in os.listdir(folder_path):
        if filename.endswith(".gpkg"):
            file_path = os.path.join(folder_path, filename)
            print(file_path)
            with fiona.open(file_path) as gpkg:
                layer_names = fiona.listlayers(file_path)
                print(f"{filename} : {layer_names}")

def extract_attributes(gdf, index):
    attributes = {}
    for column in gdf.columns:
        if column != "geometry":
            attributes[column] = gdf.loc[index, column]
    return attributes

def filter_dictionnary(dictionnary, filter):
    """the filter is a string contains or not into the dictionnary keys"""
    return {k:v for k,v in dictionnary.items() if filter in k}

def convert_gpkg_into_geojson(input_path, output_path):
    gdf = gpd.read_file(input_path)

    # 4326 is crs of OSM => used to project data on leaflet
    gdf = gdf.to_crs(epsg=4326)

    print("Converting GPKG into GeoJSON")
    gdf.to_file(output_path, driver='GeoJSON')
    print("Done")

# create_folder("./data/geojson")
#convert_gpkg_into_geojson("./data/osm/shortest_path/big_shortest_path_IF_3946.gpkg", "./data/geojson/sp_IF_3946.json")
#convert_gpkg_into_geojson("./data/raw_data/joined_if_3946.gpkg", "./pocwa-init/src/data/joined_if_3946.json")

# convert_gpkg_into_geojson("./data/gpkg/bancs.gpkg", "./data/geojson/bancs.json")

# convert_gpkg_into_geojson("./data/gpkg/fontaines_ornementales.gpkg", "./data/geojson/fontaines_ornementales.json")

# convert_gpkg_into_geojson("./data/gpkg/fontaines_potables.gpkg", "./data/geojson/fontaines_potables.json")

# convert_gpkg_into_geojson("./data/gpkg/parcs_jardins_metropole.gpkg", "./data/geojson/parcs_jardins_metropole.json")

# convert_gpkg_into_geojson("./data/gpkg/toilettes_publiques.gpkg", "./data/geojson/toilettes_publiques.json")


from logMonitor import logger
import glob,os,sys

#Open the control file and get its contents based on seprator
def readTheFileBasedonSeperator(tempFileName):
	try:
		logger.info("RECEIVED Controller File Name :: {0}".format(tempFileName))
		with open(tempFileName) as file:
			data = file.read()
		controlFileData =  (filter(None, data.split('\n')))
		logger.info("PROCESSED Controller File Name :: SUCCESS")
		return controlFileData
	except Exception as ex:
		print("Error occurred :: {0}\tLine No:: {1}".format(ex, sys.exc_info()[2].tb_lineno))
		logger.error("Error occurred :: {0}\tLine No:: {1}".format(ex, sys.exc_info()[2].tb_lineno))
		sys.exit()

#To fetch the map of metadatafilename and its record count i.e {metadatafilename : record_count}
def getMetadataFileRecordCount(tempMetadataContent):
	try:
		logger.info("Received Non-MetaData FileName to get the RecordCound :: {0}".format(tempMetadataContent))
		metadataContentMap = {}
		for lineIndex, line in enumerate(tempMetadataContent):
			if lineIndex!= 0:
				if line !="\r":
					if line.split('\t')[8] != '""':
						recordCount = int(line.split('\t')[8].strip('"'))
						metadataContentMap[line.split('\t')[0].strip('"')] = recordCount
					else:
						recordCount = 0
						metadataContentMap[line.split('\t')[0].strip('"')] = recordCount
		logger.info("PROCESSED tempMetadataContent :: {0}".format(metadataContentMap))
		return metadataContentMap
	except Exception as ex:
		print("Error occurred :: {0}\tLine No:: {1}".format(ex, sys.exc_info()[2].tb_lineno))
		logger.error("Error occurred :: {0}\tLine No:: {1}".format(ex, sys.exc_info()[2].tb_lineno))
		sys.exit()

#To fetch the total number of records in each non metadatafile.
def getNonMetadataFileRecordCount(nonMetadataFileName):
	try:
		logger.info("Received Non-MetaData FileName to get the RecordCound :: {0}".format(nonMetadataFileName))
		totalLines = sum(1 for line in open(nonMetadataFileName))
		logger.info("Fetched RecordCount SUCCESS -:: {0}".format(totalLines))
		return totalLines
	except Exception as ex:
		print("Error occurred :: {0}\tLine No:: {1}".format(ex, sys.exc_info()[2].tb_lineno))
		logger.error("Error occurred :: {0}\tLine No:: {1}".format(ex, sys.exc_info()[2].tb_lineno))
		sys.exit()

#To compare the record counts between metadatafile and non metadatafile
def compareRecordCounts(metadataContentMap,nonMetadataContentMap):
	try:
		logger.info ("For Comparision Received MetaDataConentMap :: {0}".format(metadataContentMap))
		logger.info ("For Comparision Received NonMetaDataConentMap :: {0}".format(nonMetadataContentMap))
		for metaDataItemName, metaDataRecordCount in metadataContentMap.items():
			if metaDataItemName.endswith(".gz"):
				metaDataItemName = metaDataItemName.strip(".gz")
			if metaDataItemName in nonMetadataContentMap.keys():
				if metaDataRecordCount == nonMetadataContentMap[metaDataItemName]:
					print ("MATCHED_RECORD_COUNT :: [METADATA-FILE] {0}, {1} <==> [SOURCE] {2}, {3}".format(metaDataItemName, metaDataRecordCount, metaDataItemName, nonMetadataContentMap[metaDataItemName]))
					logger.info("MATCHED_RECORD_COUNT :: [METADATA-FILE] {0}, {1} <==> [SOURCE] {2}, {3}".format(metaDataItemName, metaDataRecordCount, metaDataItemName, nonMetadataContentMap[metaDataItemName]))

				else:
					print ("NOT_MATCHED_RECORD_COUNT :: [METADATA-FILE] {0}, {1} <==> [SOURCE]  {2}, {3}".format(metaDataItemName, metaDataRecordCount, metaDataItemName, nonMetadataContentMap[metaDataItemName]))
					logger.error("NOT_MATCHED_RECORD_COUNT :: [METADATA-FILE] {0}, {1} <==> [SOURCE]  {2}, {3}".format(metaDataItemName, metaDataRecordCount, metaDataItemName, nonMetadataContentMap[metaDataItemName]))

			else:
				print ("FILE_NOTAVAILALBE_TO_FETCH_RECORD_COUNT :: [METADATA-FILE] {0}, {1} <==> in [SOURCE] NA ".format(metaDataItemName, metaDataRecordCount))
				logger.error ("FILE_NOTAVAILALBE_TO_FETCH_RECORD_COUNT :: [METADATA-FILE] {0}, {1} <==> in [SOURCE] NA ".format(metaDataItemName, metaDataRecordCount))

	except Exception as ex:
		print("Error occurred :: {0}\tLine No:: {1}".format(ex, sys.exc_info()[2].tb_lineno))
		logger.error("Error occurred :: {0}\tLine No:: {1}".format(ex, sys.exc_info()[2].tb_lineno))
		sys.exit()

def comparisionDecider(tmpFeedTypeBasePath,metaDataFileName):
	try:
		logger.info("Received FeedTypeBasePath :: {0}".format(tmpFeedTypeBasePath))
		print("Checking FeedTypeBasePath  for :: {0}".format(tmpFeedTypeBasePath))
		nonMetadataFileNames = 	[nonMetadataFileName for nonMetadataFileName in glob.glob(tmpFeedTypeBasePath+"/*") if nonMetadataFileName]
		# nonMetadataFileNames = 	[nonMetadataFileName for nonMetadataFileName in glob.glob(tmpFeedTypeBasePath+"\*") if nonMetadataFileName]
		logger.info("nonMetadataFileNames :: {0}".format(nonMetadataFileNames))
		metadataContent = (readTheFileBasedonSeperator(metaDataFileName))
		metadataContentMap = getMetadataFileRecordCount(metadataContent)
		nonMetadataContentMap = {}
		for nonMetadataItem in nonMetadataFileNames:
			_, nonMetadataFileName = os.path.split(nonMetadataItem)
			if not nonMetadataFileName.startswith("metadata_"):
				nonMetadataContentMap[nonMetadataFileName] = getNonMetadataFileRecordCount(nonMetadataItem)
		return compareRecordCounts(metadataContentMap,nonMetadataContentMap)
	except Exception as ex:
		print("Error occurred :: {0}\tLine No:: {1}".format(ex, sys.exc_info()[2].tb_lineno))
		logger.error("Error occurred :: {0}\tLine No:: {1}".format(ex, sys.exc_info()[2].tb_lineno))
		sys.exit()

def feedRunner(currentFeedValidationDirName):
	try:
		logger.info ("currentFeedValidationDirName :: {0}".format(currentFeedValidationDirName))
		metadataBasePath = currentFeedValidationDirName+"metadata_*"
		logger.info("metadataBasePath :: {0}".format(metadataBasePath))
		metaDataFileName = glob.glob(metadataBasePath)
		if len(metaDataFileName) !=0:
			logger.info("metaDataFileName :: {0}".format(metaDataFileName[0]))
			#PASS THE FEED TYPE PATH[DEED/ASMT]
			comparisionDecider(currentFeedValidationDirName,metaDataFileName[0])

		else:
			print("MetaData File doesnt Exists [Path] :: {0}".format(currentFeedValidationDirName))
			logger.error("MetaData File doesnt Exists [Path] :: {0}".format(currentFeedValidationDirName))
	except Exception as ex:
		print("Error occurred :: {0}\tLine No:: {1}".format(ex, sys.exc_info()[2].tb_lineno))
		logger.error("Error occurred :: {0}\tLine No:: {1}".format(ex, sys.exc_info()[2].tb_lineno))
		sys.exit()


#Kmeans clustering

#importing libraries
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import KMeans

#read dataset
dataset = pd.read_csv('Mall_Customers.csv')
X = dataset.iloc[:, [3,4]].values
y = dataset.iloc[:, 4].values

#splitting datasets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=.2, random_state=0)

wcss = []
for i in range(1,11):
    KCluster = KMeans(n_clusters=i, random_state=0, init='k-means++', max_iter=300, n_init=10)
    KCluster.fit(X)
    wcss.append(KCluster.inertia_)

#visualizing dataset
#plt.plot(range(1,11), wcss)
#plt.title('ELBOW METHOD')
#plt.xlabel('# of clusters')
#plt.ylabel('# of Sum Squared Distance')
#plt.show()

#applying kmeans to mall dataset
KCluster = KMeans(n_clusters=5, init='k-means++', random_state=0, max_iter=300, n_init=10)
y_kmeans = KCluster.fit_predict(X)

#visualizing clusters
plt.scatter(X[y_kmeans==0, 0], X[y_kmeans==0, 1], s=100, c='red', label='CLUSTER 1')
plt.scatter(X[y_kmeans==1, 0], X[y_kmeans==1, 1], s=100, c='blue', label='CLUSTER 2')
plt.scatter(X[y_kmeans==2, 0], X[y_kmeans==2, 1], s=100, c='green', label='CLUSTER 3')
plt.scatter(X[y_kmeans==3, 0], X[y_kmeans==3, 1], s=100, c='cyan', label='CLUSTER 4')
plt.scatter(X[y_kmeans==4, 0], X[y_kmeans==4, 1], s=100, c='magenta', label='CLUSTER 5')
plt.scatter(KCluster.cluster_centers_[:,0], KCluster.cluster_centers_[:, 1], s=300, c='yellow', label='centroid')
plt.title('Clusters of clients')
plt.xlabel('Annual income')
plt.ylabel('Spending income')
plt.legend()
plt.show()


import os
import sys
import re
import base
import random

from utils import hcf_auth
from utils import hcf_organisations
from utils import hcf_marketplace
from utils import hcf_space

class TestHcfMarketplace(base.BaseTest):

    """
    SetupClass prepares the following preconditions for
    Marketplace tests
    * Connect to the cluster URI target
    """

    @classmethod
    def setUpClass(cls):
        super(TestHcfMarketplace, cls).setUpClass()

        # Connect to the cluster URI target
        hcf_auth.connect_target(cls.cluster_url,
                                optional_args={'--skip-ssl-validation': ' '})
        # Log into Cluster using creds
        hcf_auth.login(optional_args={'-u': cls.username, '-p': cls.password})
        # Create organisation
        cls.setup_org = 'og_test_org' + str(random.randint(1024, 4096))
        out, err = hcf_organisations.create_org(cls.setup_org)
        out, err = hcf_auth.target(optional_args={'-o': cls.setup_org})
        # Create Space
        cls.setup_space = 'sp_test_space' + str(random.randint(1024, 4096))
        out, err = hcf_space.create_space(cls.setup_space)
        out, err = hcf_auth.target(optional_args={'-o': cls.setup_org,
                                                  '-s': cls.setup_space})

    @classmethod
    def tearDownClass(cls):
        super(TestHcfMarketplace, cls).tearDownClass()
        hcf_organisations.delete_org(cls.setup_org, input_data=b'yes\n')
        hcf_auth.logout(cls.cluster_url)

    def test_hcf_marketplace(self):
        # List all offerings
        out, err = hcf_marketplace.marketplace()
        self.verify("OK", out)
        self.verify(
            "Getting services from marketplace in org " + self.setup_org + ""
            " / space " + self.setup_space, out)

if __name__ == '__main__':
    base.unittest.main(verbosity=2)


#     Работас файлами

# № 1

# with open('text.txt', 'w', encoding = 'utf-8') as myfile: # открой файл 'text.txt', запииши в него - команда 'w, кодкодировкой - utf-8; результат назвать переменной f
#     myfile.write('Hello, world!\n')
#     myfile.write('\tеще раз')
#

# № 2 чтение и вывод
#
# with open('text.txt', 'r', encoding = 'utf-8') as myfile:
#     text = myfile.read()
#     print(text)

# № 3 Чтение файла построчно - лучший вариант для чтения - ест меньше памяти для больших текстов

with open('text.txt', 'r', encoding = 'utf-8') as f:
    for line in f:
        line = line.upper()
        line = line.replace("\n", "") # заменяем перевод строки на пустоту
        print(line)


import cv2
import numpy as np
import configparser

from utils import to_int, COLORS_HSV_VALUES, DRAWING_COLORS

drawingPoints = []  # x-coordinate, y-coordinate, drawingColorIndex in `DRAWING_COLORS` list

def get_contours_top_center_point(img):
    """
    Returns top center coordinates of the detected contour
    Optionally can show contour too
    """
    contours, heirarchy = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) # image, retrieval method, approximation-(where you can request for all info or we can request for compressed info)
    # RETR_EXTERNAL retrieves extremes outer contours, there are other retrieval methods too
    x, y, w, h = 0, 0, 0, 0
    # contours are saved in contours variable above
    for cnt in contours:
        area = cv2.contourArea(cnt) # Find area of contour
        # Now to neglect smaller shapes, if any
        if area > 500:
            # This will draw a blue line on the imgFinal image
            # cv2.drawContours(imgFinal, cnt, -1, (255, 0, 0), 3) # Draw the contours, params: img, contour, contour_index(-1 means all the contours), color, thickness

            # Now we will calculate curve length, it will help us approximate corners of our shape
            peri = cv2.arcLength(cnt, True)  # params: curve, closed or not
            corner_points = cv2.approxPolyDP(cnt, 0.02*peri, True) # contour, resolution(play around with to get good results), closed or not
            # Now we create bounding box around detected object
            # To draw bounding box, we need x and y and also width and height
            x, y, w, h = cv2.boundingRect(corner_points)
    # Now we want to draw from tip of object
    return x+w//2, y # Center coordinate and top point

def paintCanvas(drawingPoints, imgFinal):
    """
    Paints the image when the color is moved on the screen
    Looping is done as more than one can color can be present
    """
    for point in drawingPoints:
        cv2.circle(imgFinal, (point[0], point[1]), 7, DRAWING_COLORS[point[2]], cv2.FILLED) # params: image, center points, radius, color, thickness

def detect_color(img, imgFinal):
    """
    Here more than single color can be detected
    :return coordinates and index of drawingColor
    """
    # Convert to HSV, as it is easier to represent a color in it than in BGR color-space
    imgHSV = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
    counter = 0
    # To store current color details
    curr_points = []
    # Looping to detect all the colors mentioned in list
    for color in COLORS_HSV_VALUES:
        # Now we will used these values to filter out image, so we can get image in that particular color in that range
        lower_limit = np.array(color[0:3]) # First three
        upper_limit = np.array(color[3:6]) # Last three
        # This will filter out
        mask = cv2.inRange(imgHSV, lower_limit, upper_limit)
        # cv2.imshow(str(color[0]), mask) # As we can not have a generic name so we for now we just write Hue Min Value
        # Now we can also draw a boundary around the captured color
        x, y = get_contours_top_center_point(mask)
        # Draw a circle on the center on the top of the contour
        cv2.circle(imgFinal, (x, y), 7, DRAWING_COLORS[counter], cv2.FILLED) # params: image, center points, radius, color, thickness
        # If we have detected color and received it's top's center coordinates
        if x and y:
            # Append the details of the current color
            curr_points.append([x,y, counter])
        counter += 1
    return curr_points, imgFinal

def capture_and_paint():
    """
    Captures a video to perform futher operations
    Looping is done as video is just a sequence of images, so we need while loop to go through each frame
    """
    #
    while True:
        # Read each frame
        ret, frame = cap.read()
        # Make a copy original image, on which we can draw
        imgFinal = frame.copy()
        # Now detect color shown on screen
        curr_points, imgF = detect_color(frame, imgFinal) # Returns coordinates and index of the color
        if curr_points:
            # As more than one colors can be shown on the screen
            for point in curr_points:
                drawingPoints.append(point)
        if drawingPoints:
            paintCanvas(drawingPoints, imgF)

        # Now display the painted frame
        cv2.imshow("Result", imgFinal)

        # Now add delay and also add `q` button press to exit
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break

if __name__ == '__main__':
    config = configparser.ConfigParser()
    configFilePath = "/home/shantanu/stuff/projects/virtual-paint/config.ini"
    # Read config file
    config.read(configFilePath)
    frameWidth = to_int(config['video']['frameWidth'])
    frameHeight = to_int(config['video']['frameWidth'])
    brightness = to_int(config['video']['brightness'])

    # Capture using webcam
    cap = cv2.VideoCapture(0)
    # Set width and height of frame
    cap.set(3, frameHeight) # First param is Property Identifer for the video
    # Read here: https://docs.opencv.org/2.4/modules/highgui/doc/reading_and_writing_images_and_video.html#videocapture-get
    # Or refer propID.txt
    cap.set(4, frameWidth)
    # Set the brightness
    cap.set(10, brightness)
    # Call the processing function
    capture_and_paint()


# Module: default
# Author: jurialmunkey
# License: GPL v.3 https://www.gnu.org/copyleft/gpl.html
from tmdbhelper.lib.script.method.decorators import is_in_kwargs, choose_tmdb_id

@is_in_kwargs({'tmdb_type': ['movie', 'tv']})
@choose_tmdb_id
def add_to_library(tmdb_type=None, tmdb_id=None, **kwargs):
    from tmdbhelper.lib.update.library import add_to_library
    add_to_library(info=tmdb_type, tmdb_id=tmdb_id)

@is_in_kwargs({'user_list': True})
def add_user_list(user_list=None, user_slug=None, **kwargs):
    from tmdbhelper.lib.update.library import add_to_library
    user_slug = user_slug or 'me'
    add_to_library(info='trakt', user_slug=user_slug, list_slug=user_list, confirm=True, allow_update=True, busy_spinner=True)

def run_autoupdate(**kwargs):
    from xbmcgui import Dialog
    from tmdbhelper.lib.update.userlist import library_autoupdate
    from tmdbhelper.lib.addon.plugin import get_localized
    if kwargs.get('force') == 'select':
        choice = Dialog().yesno(
            get_localized(32391),
            get_localized(32392),
            yeslabel=get_localized(32393),
            nolabel=get_localized(32394))
        if choice == -1:
            return
        kwargs['force'] = True if choice else False
    library_autoupdate(
        list_slugs=kwargs.get('list_slug', None),
        user_slugs=kwargs.get('user_slug', None),
        busy_spinner=True if kwargs.get('busy_dialog', False) else False,
        force=kwargs.get('force', False))


import math
import numpy as np
from statistics import median
from collections import Counter

def euclidean_distance(x1, x2):
    return np.sqrt(np.sum((x1-x2)**2))

# def predict(self, X):
#     predictions = [self._predict(x)for x in X]
#     return np.array(predictions)

def get_RDOS(p,x, y_train, k ):
    distance = [euclidean_distance(p, i)for i in x]

    k_indices = np.argsort(distance)[:k]
    # print(k_indices)
    k_nearest_labels = [y_train[i]for i in k_indices]

    # most_common = Counter(k_nearest_labels).most_common(1)
    # it returns the most commmon item in form of tuple
    # return most_common[0][0]

    # finding the forward density
    sorted_distance = sorted(distance)
    sorted_distance = list(filter(lambda a: a != 0.00, sorted_distance))
    fd_list = []
    for i in range(k):
        forward_density = (i+1)/sorted_distance[i]
        fd_list.append(forward_density)
    # finding the ranking of x by q
    N_x = []
    for k in k_indices:
        N_x.append(x[k])

    reverse_list = []
    for s in N_x:
        count, R = 0, 0
        if s in x:
            distance2 = [euclidean_distance(
                s, x_train)for x_train in x]
        distance2 = sorted(distance2)
        distance2 = list(filter(lambda a: a != 0.00, distance2))
        for dis in distance2:
            if dis < sorted_distance[count]:
                R += 1
        reverse_list.append(R)
        count += 1
    # calculating the RDOS values
    count = 0
    RDOS = []
    for i in range(4):
        count += 1
        RDOS.append((reverse_list[i]-count)/fd_list[i])

    return median(RDOS)

def delta(i,j,x, y_train, k):
    return abs(get_RDOS(i,x, y_train, k)-get_RDOS(j,x, y_train, k))

def infodist(x, y_train, k):
    dist = []
    answer = []
    for i in x:
        k_indices = []
        dist = []
        for j in x:
            dist.append(euclidean_distance(i,j)*(1+math.log(1+delta(i,j,x, y_train, k))))

        k_indices = np.argsort(dist)[:k]

        #print(k_indices)

        k_nearest_labels = []

        for i in k_indices:
            k_nearest_labels.append(y_train[i])

        most_common = Counter(k_nearest_labels).most_common(1)
            # it returns the most commmon item in form of tuple
        answer.append(most_common[0][0])

    return answer


from direct.directnotify import DirectNotifyGlobal
from toontown.estate.DistributedFurnitureItemAI import DistributedFurnitureItemAI
from direct.distributed.ClockDelta import *
import BankGlobals

class DistributedBankAI(DistributedFurnitureItemAI):
    notify = DirectNotifyGlobal.directNotify.newCategory("DistributedBankAI")

    def __init__(self, air, furnitureMgr, item):
        DistributedFurnitureItemAI.__init__(self, air, furnitureMgr, item)
        self.avId = None
        self.movie = BankGlobals.BANK_MOVIE_CLEAR

    def avatarEnter(self):
        avId = self.air.getAvatarIdFromSender()
        if not self.avId:
            if not self.furnitureMgr.ownerId:
                self.b_setMovie(BankGlobals.BANK_MOVIE_NO_OWNER, avId, globalClockDelta.getRealNetworkTime())
                return
            elif self.furnitureMgr.ownerId != avId:
                self.b_setMovie(BankGlobals.BANK_MOVIE_NOT_OWNER, avId, globalClockDelta.getRealNetworkTime())
                return
            else:
                self.avId = avId
                self.b_setMovie(BankGlobals.BANK_MOVIE_GUI, avId, globalClockDelta.getRealNetworkTime())
                return
        else:
            if avId == self.avId:
                self.air.writeServerEvent('suspicious', avId=avId, issue='Tried to use bank while already using it!')
            self.sendUpdateToAvatarId(avId, 'freeAvatar', [])

    def freeAvatar(self):
        pass

    def setMovie(self, mode, avId, time):
        self.movie = mode
        if self.movie != BankGlobals.BANK_MOVIE_CLEAR:
            taskMgr.doMethodLater(2.0, self.clearMovie, 'clear-movie-%d' % self.getDoId())

    def clearMovie(self, task):
        self.b_setMovie(BankGlobals.BANK_MOVIE_CLEAR, 0, globalClockDelta.getRealNetworkTime())

    def b_setMovie(self, mode, avId, time):
        self.setMovie(mode, avId, time)
        self.d_setMovie(mode, avId, time)

    def d_setMovie(self, mode, avId, time):
        self.sendUpdate('setMovie', [mode, avId, time])

    def transferMoney(self, amount):
        avId = self.air.getAvatarIdFromSender()
        if avId != self.avId:
            self.air.writeServerEvent('suspicious', avId=avId, issue='Tried to transfer money while not using a bank!')
            return
        av = self.air.doId2do.get(avId)
        if not av:
            self.air.writeServerEvent('suspicious', avId=avId, issue='Tried to transfer money while not on the AI!')
            return
        if amount == 0: # No transfer needed.
            self.b_setMovie(BankGlobals.BANK_MOVIE_NO_OP, avId, globalClockDelta.getRealNetworkTime())
        elif amount > 0:
            self.b_setMovie(BankGlobals.BANK_MOVIE_DEPOSIT, avId, globalClockDelta.getRealNetworkTime())
            if av.money < amount:
                self.air.writeServerEvent('suspicious', avId=avId, issue='Toon tried to deposit more money than they have!')
            else:
                av.b_setMoney(av.money - amount)
                av.b_setBankMoney(av.bankMoney + amount)
        else:
            self.b_setMovie(BankGlobals.BANK_MOVIE_WITHDRAW, avId, globalClockDelta.getRealNetworkTime())
            if av.bankMoney + amount < 0:
                self.air.writeServerEvent('suspicious', avId=avId, issue='Toon tried to withdraw more money than they have!')
            else:
                av.b_setMoney(av.money - amount)
                av.b_setBankMoney(av.bankMoney + amount)

        self.avId = None


import os

import pytest
from _decimal import Decimal

from blockapi.v2.api import PerpetualApi, perp_contract_address
from blockapi.v2.base import ApiException
from blockapi.v2.models import FetchResult

@pytest.fixture
def perp_api():
    return PerpetualApi('http://localhost:2048/')

test_address = '0x134089B387E22f52b1e06CC80d9a5F622032EF74'

def test_perp_contract_address():
    contract = perp_contract_address('PERP')
    assert contract == '0xbC396689893D065F41bc2C6EcbeE5e0085233447'

def test_perp_invalid_contract_raises():
    with pytest.raises(ValueError, match='Invalid contract name.'):
        perp_contract_address("abc")

def test_perp_has_coin(perp_api):
    assert perp_api.coin.symbol == 'PERP'

def filter_infura_key(request):
    if 'infura.io' in request.host:
        request.uri = 'https://mainnet.infura.io/v3/API_KEY_FILTERED'
    return request

@pytest.mark.integration
def test_fetch():
    key = os.environ.get('INFURA_API_KEY')
    api = PerpetualApi(f'https://mainnet.infura.io/v3/{key}')
    raw = api.fetch_balances(test_address)
    assert raw.data

@pytest.mark.integration
def test_fetch_error():
    api = PerpetualApi(f'https://mainnet.infura.io/v3/no-key')
    raw = api.fetch_balances(test_address)
    assert raw.status_code == 401
    assert (
        raw.errors[0]
        == '401 Client Error: Unauthorized for url: https://mainnet.infura.io/v3/no-key'
    )

def test_fetch_error_raises_from_get_balances():
    api = PerpetualApi(f'https://mainnet.infura.io/v3/no-key')
    with pytest.raises(ApiException) as exc:
        api.get_balance(test_address)

    assert exc.match('401 Client Error: Unauthorized for url')

def test_parse(perp_api):
    raw = FetchResult(
        status_code=200,
        data=dict(
            staking_claimable='1.10',
            vesting_claimable='2.02',
            vesting_locked='3.30',
        ),
    )

    parsed = perp_api.parse_balances(raw)

    assert parsed.data[0].balance == Decimal('3.12')
    assert parsed.data[1].balance == Decimal('3.30')


import sys
import queue

input = sys.stdin.readline

def solve():
    n, m, D = map(int, input().split())
    edges = [[] for _ in range(n)]
    for _ in range(m):
        v, u = map(int, input().split())
        edges[v - 1].append(u - 1)
        edges[u - 1].append(v - 1)

    if len(edges[0]) > D:
        print('NO')
        return

    q = queue.Queue()
    q.put(0)
    visited = [False] * n
    visited[0] = True
    res = []
    while not q.empty():
        v = q.get()
        for u in edges[v]:
            if not visited[u]:
                visited[u] = True
                q.put(u)
                res.append((v + 1, u + 1))

    if len(res) == n - 1:
        print('YES')
        for v, u in res:
            print(v, u)
    else:
        print('NO')

if __name__ == '__main__':
    solve()


import cv2
import time
import serial #导入模块
import serial.tools.list_ports

face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
eye_cascade = cv2.CascadeClassifier('haarcascade_eye.xml')
count = 0
count2 = 0
count3 = 0
state = 1
#1 = waiting for food
#2 = food is ready
#3 = dangerous
#4 = got food

ports = list(serial.tools.list_ports.comports())
print (ports)
for p in ports:
    print (p[1])
    if "SERIAL" in p[1] or"UART" in p[1] or "Arduino" in p[1] :
	    ser=serial.Serial(port=p[0])
	    break
    else :
	    print ("No Arduino Device was found connected to the computer")
time.sleep(5)
'''
def response(inp_data):
    if 'foodready' in inp_data:
        print('food is ready')
        state = 2
'''

cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_FPS, 30)
while state == 1:
    input_data = ser.readline()
    inp_data = str(input_data)
    ret, frame = cap.read()
    frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    faces = face_cascade.detectMultiScale(frame, 1.3, 5)
    for (x,y,w,h) in faces:
        frame = cv2.rectangle(frame,(x,y),(x+w,y+h),(255,0,0),2)

    if len(faces) != 0:
        count += 1
        frame = cv2.circle(frame,(20,20),5,(0,0,255),5)
    else:
        count2 += 1

    if count2 >= 30:
        frame = cv2.circle(frame,(20,20),5,(0,255,0),5)
        print('delivery man is away')
        count = 0
        count2 = 0
        time.sleep(1)
        ser.write('0'.encode())
        time.sleep(1)

        if 'foodready' in inp_data:
            print('food is ready')
            state = 2
    elif count >= 30:
        print('alarm')
        count = 0
        count2 = 0
        count3 += 1
        #ser.write('1'.encode())
        time.sleep(1)

    elif count3 >= 3:
        print('dangerous situation')
        #ser.write('danger'.encode()) ###############

    print(count2)
    cv2.imshow('img',frame)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break
    time.sleep(.5)

while state == 2:
    input_data = ser.readline()
    inp_data = str(input_data)
    print('come and get your food')
    time.sleep(3)
    if 'something' in inp_data:          ############
        print('user taken the food')
        state = 4
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

while state == 4:
    input_data = ser.readline()
    inp_data = str(input_data)
    #ser.write('gotfood'.encode())        ##########
    if 'something' in inp_data:    ###############
        print('close the cover')
        time.sleep(10)
        break
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()


import random
import os
import glob
import argparse

# Find all files in dir with extension (to exclude other files)
def find_files_in(path, with_extension = ""):
    pattern = path + "/*." + with_extension
    return glob.glob(pattern)

# Makes directories
def make_dirs(path, train_dir_name = 'train', test_dir_name = 'test'):
    for dir_name in [train_dir_name, test_dir_name]:
        try:
            os.mkdir(path + "/" + dir_name)
        except OSError:
            print ("Creation of the directory %s failed" % path + "/" + dir_name)
        else:
            print ("Successfully created the directory %s " % path + "/" + dir_name)

# Selects randomly the files according to a preset policy
# Moves the files
def random_select(list_of_files, percentage_split, train_dir_path, test_dir_path):
    for file in list_of_files:
        path, filename = os.path.split(file)

        choices = ['test'] * int((percentage_split * 100)) + ['train'] * int(((1 - percentage_split) * 100))

        choice = random.choice(choices)

        is_training = choice == 'train'

        # Search for similar files to move them as well
        pattern = path + "/" + os.path.splitext(filename)[0] +".*"
        files = glob.glob(pattern)
        for file_i in files:
            _ , filename_i = os.path.split(file_i)
            if is_training:
                os.rename(file_i, train_dir_path + "/" + filename_i)
            else:
                os.rename(file_i, test_dir_path + "/" + filename_i)

def main(path, train_dir_name = "train", test_dir_name = "test", file_extension = "jpg", split_strategy = 0.5):
    file_paths = find_files_in(path, file_extension)
    make_dirs(path,train_dir_name, test_dir_name)
    random_select(file_paths, split_strategy, path + "/" + test_dir_name, path + "/" + train_dir_name)

if __name__ == '__main__':

    parser = argparse.ArgumentParser()

    parser.add_argument(
        '--path', type=str,
        help='path to images ',
        default=os.getcwd()
    )

    parser.add_argument(
        '--train_dir_name', type=str,
        help='Name of train data directory name ',
        default='train'
    )

    parser.add_argument(
        '--test_dir_name', type=str,
        help='Name of test data directory name ',
        default='test'
    )

    parser.add_argument(
        '--file_extension', type=str,
        help='The extension of the file you want to get handled ',
        default='jpg'
    )

    parser.add_argument(
        '--split_strategy', type=float,
        help='Percentage of split strategy to split training and test data ',
        default=0.5
    )

    args = vars(parser.parse_args())

    main(args["path"],args["train_dir_name"], args["test_dir_name"], args["file_extension"],
         args["split_strategy"])


class Voc:
    def __init__(self):
        self.trimmed = None
        self.PAD_token = 0  # Used for padding short sentences
        self.word2index = {"PAD": self.PAD_token}  # mapping from words to indexes
        self.word2count = {"PAD": 0}  # count of each word
        self.index2word = {self.PAD_token: "PAD"}  # reverse mapping of indexes to words
        self.num_words = 1  # Count SOS, EOS, PAD

    def addSentences(self, sentences):
        """Add all words in a list sentence to the vocabulary"""
        for line in sentences:
            self.addSentence(line)

    def addSentence(self, sentence):
        """Add all words of a sentence to the vocabulary"""
        for word in sentence.split(' '):
            self.addWord(word)

    def addWord(self, word):
        """Add one word to the vocabulary"""
        if word not in self.word2index:
            self.word2index[word] = self.num_words
            self.word2count[word] = 1
            self.index2word[self.num_words] = word
            self.num_words += 1
        else:
            self.word2count[word] += 1

    def trim(self, min_count):
        """Remove words below a certain count threshold"""

        self.trimmed = min_count
        keep_words = []
        for k, v in self.word2count.items():
            if v >= min_count:
                keep_words.append(k)
        print('keep_words {} / {} = {:.4f}'.format(
            len(keep_words), len(self.word2index), len(keep_words) / len(self.word2index)
        ))
        # Reinitialize dictionaries
        self.word2index = {"PAD": self.PAD_token}
        self.word2count = {"PAD": 0}
        self.index2word = {self.PAD_token: "PAD"}
        self.num_words = 1  # Count default tokens
        for word in keep_words:
            self.addWord(word)

    def indexesFromSentence(self, sentence):
        """Convert words of a sentence to their indexes"""
        return [self.word2index[word] for word in sentence.split(' ') if word in self.get_words()]

    def pad_sentences(self, sentences, max_length, pad_direction='right'):
        """Pad all sentences in a list of lines"""
        padded_sentences = []
        for line in sentences:
            padded_sentences.append(self.pad_sentence(line, max_length, pad_direction))
        return padded_sentences

    def pad_sentence(self, sentence, max_length, pad_direction='right'):
        """Pad a sentence on the left or on the right"""
        indices = self.indexesFromSentence(sentence)
        if max_length - len(indices) > 0:
            padding = [self.PAD_token] * (max_length - len(indices))
            if pad_direction == 'right':
                return indices + padding
            if pad_direction == 'left':
                return padding + indices
        return indices[:max_length]

    def get_words(self):
        """Get all words in the vocabulary (includes PAD)"""
        return self.word2index.keys()

    def fix_sentences(self, sentences):
        """Remove words not present in the vocabulary from a list of sentences"""
        fixed_sentences = []
        for line in sentences:
            fixed_sentences.append(self.fix_sentence(line))
        return fixed_sentences

    def fix_sentence(self, sentence):
        """Remove words not present in the vocabulary from a sentence"""
        words = sentence.split()
        words = [w for w in words if w in self.get_words()]
        fixed_sentence = " ".join(words)
        return fixed_sentence