import datetime
import json
import os
import random
import time
import xml.sax.saxutils as saxutils
from datetime import datetime

import azurelinuxagent.common.conf as conf
import azurelinuxagent.common.logger as logger
import azurelinuxagent.common.utils.textutil as textutil
from azurelinuxagent.common.datacontract import validate_param
from azurelinuxagent.common.event import add_periodic, WALAEventOperation, EVENTS_DIRECTORY
from azurelinuxagent.common.exception import ProtocolNotFoundError, \
    ResourceGoneError, ExtensionDownloadError, InvalidContainerError, ProtocolError, HttpError
from azurelinuxagent.common.future import httpclient, bytebuffer
from azurelinuxagent.common.protocol.goal_state import GoalState, TRANSPORT_CERT_FILE_NAME, TRANSPORT_PRV_FILE_NAME
from azurelinuxagent.common.protocol.hostplugin import HostPluginProtocol
from azurelinuxagent.common.protocol.imds import ComputeInfo
from azurelinuxagent.common.protocol.restapi import *
from azurelinuxagent.common.telemetryevent import TelemetryEventList
from azurelinuxagent.common.utils import fileutil, restutil
from azurelinuxagent.common.utils.archive import StateFlusher
from azurelinuxagent.common.utils.cryptutil import CryptUtil
from azurelinuxagent.common.utils.textutil import parse_doc, findall, find, \
    findtext, gettext, remove_bom, get_bytes_from_pem, parse_json
from azurelinuxagent.common.version import AGENT_NAME, CURRENT_VERSION

VERSION_INFO_URI = "http://{0}/?comp=versions"
HEALTH_REPORT_URI = "http://{0}/machine?comp=health"
ROLE_PROP_URI = "http://{0}/machine?comp=roleProperties"
TELEMETRY_URI = "http://{0}/machine?comp=telemetrydata"

WIRE_SERVER_ADDR_FILE_NAME = "WireServer"
INCARNATION_FILE_NAME = "Incarnation"
GOAL_STATE_FILE_NAME = "GoalState.{0}.xml"
HOSTING_ENV_FILE_NAME = "HostingEnvironmentConfig.xml"
SHARED_CONF_FILE_NAME = "SharedConfig.xml"
REMOTE_ACCESS_FILE_NAME = "RemoteAccess.{0}.xml"
EXT_CONF_FILE_NAME = "ExtensionsConfig.{0}.xml"
MANIFEST_FILE_NAME = "{0}.{1}.manifest.xml"

PROTOCOL_VERSION = "2012-11-30"
ENDPOINT_FINE_NAME = "WireServer"

SHORT_WAITING_INTERVAL = 1  # 1 second

MAX_EVENT_BUFFER_SIZE = 2 ** 16 - 2 ** 10

class UploadError(HttpError):
    pass

class WireProtocol(Protocol):
    """Slim layer to adapt wire protocol data to metadata protocol interface"""

    def __init__(self, endpoint):
        if endpoint is None:
            raise ProtocolError("WireProtocol endpoint is None")
        self.client = WireClient(endpoint)

    def detect(self):
        self.client.check_wire_protocol_version()

        trans_prv_file = os.path.join(conf.get_lib_dir(),
                                      TRANSPORT_PRV_FILE_NAME)
        trans_cert_file = os.path.join(conf.get_lib_dir(),
                                       TRANSPORT_CERT_FILE_NAME)
        cryptutil = CryptUtil(conf.get_openssl_cmd())
        cryptutil.gen_transport_cert(trans_prv_file, trans_cert_file)

        # Set the initial goal state
        logger.info('Initializing goal state during protocol detection')
        self.client.update_goal_state(forced=True)

    def update_goal_state(self):
        self.client.update_goal_state()

    def update_host_plugin_from_goal_state(self):
        self.client.update_host_plugin_from_goal_state()

    def get_endpoint(self):
        return self.client.get_endpoint()

    def get_vminfo(self):
        goal_state = self.client.get_goal_state()
        hosting_env = self.client.get_hosting_env()

        vminfo = VMInfo()
        vminfo.subscriptionId = None
        vminfo.vmName = hosting_env.vm_name
        vminfo.tenantName = hosting_env.deployment_name
        vminfo.roleName = hosting_env.role_name
        vminfo.roleInstanceName = goal_state.role_instance_id
        return vminfo

    def get_certs(self):
        certificates = self.client.get_certs()
        return certificates.cert_list

    def get_incarnation(self):
        return self.client.get_goal_state().incarnation

    def get_vmagent_manifests(self):
        goal_state = self.client.get_goal_state()
        ext_conf = self.client.get_ext_conf()
        return ext_conf.vmagent_manifests, goal_state.incarnation

    def get_vmagent_pkgs(self, vmagent_manifest):
        goal_state = self.client.get_goal_state()
        ga_manifest = self.client.get_gafamily_manifest(vmagent_manifest, goal_state)
        valid_pkg_list = ga_manifest.pkg_list
        return valid_pkg_list

    def get_ext_handlers(self):
        logger.verbose("Get extension handler config")
        goal_state = self.client.get_goal_state()
        ext_conf = self.client.get_ext_conf()
        # In wire protocol, incarnation is equivalent to ETag
        return ext_conf.ext_handlers, goal_state.incarnation

    def get_ext_handler_pkgs(self, ext_handler):
        logger.verbose("Get extension handler package")
        man = self.client.get_ext_manifest(ext_handler)
        return man.pkg_list

    def get_artifacts_profile(self):
        logger.verbose("Get In-VM Artifacts Profile")
        return self.client.get_artifacts_profile()

    def _download_ext_handler_pkg_through_host(self, uri, destination):
        host = self.client.get_host_plugin()
        uri, headers = host.get_artifact_request(uri, host.manifest_uri)
        success = self.client.stream(uri, destination, headers=headers, use_proxy=False)
        return success

    def download_ext_handler_pkg(self, uri, destination, headers=None, use_proxy=True):
        direct_func = lambda: self.client.stream(uri, destination, headers=None, use_proxy=True)
        # NOTE: the host_func may be called after refreshing the goal state, be careful about any goal state data
        # in the lambda.
        host_func = lambda: self._download_ext_handler_pkg_through_host(uri, destination)

        try:
            success = self.client.send_request_using_appropriate_channel(direct_func, host_func)
        except Exception:
            success = False

        return success

    def report_provision_status(self, provision_status):
        validate_param("provision_status", provision_status, ProvisionStatus)

        if provision_status.status is not None:
            self.client.report_health(provision_status.status,
                                      provision_status.subStatus,
                                      provision_status.description)
        if provision_status.properties.certificateThumbprint is not None:
            thumbprint = provision_status.properties.certificateThumbprint
            self.client.report_role_prop(thumbprint)

    def report_vm_status(self, vm_status):
        validate_param("vm_status", vm_status, VMStatus)
        self.client.status_blob.set_vm_status(vm_status)
        self.client.upload_status_blob()

    def report_ext_status(self, ext_handler_name, ext_name, ext_status):
        validate_param("ext_status", ext_status, ExtensionStatus)
        self.client.status_blob.set_ext_status(ext_handler_name, ext_status)

    def report_event(self, events):
        validate_param(EVENTS_DIRECTORY, events, TelemetryEventList)
        self.client.report_event(events)

def _build_role_properties(container_id, role_instance_id, thumbprint):
    xml = (u"<?xml version=\"1.0\" encoding=\"utf-8\"?>"
           u"<RoleProperties>"
           u"<Container>"
           u"<ContainerId>{0}</ContainerId>"
           u"<RoleInstances>"
           u"<RoleInstance>"
           u"<Id>{1}</Id>"
           u"<Properties>"
           u"<Property name=\"CertificateThumbprint\" value=\"{2}\" />"
           u"</Properties>"
           u"</RoleInstance>"
           u"</RoleInstances>"
           u"</Container>"
           u"</RoleProperties>"
           u"").format(container_id, role_instance_id, thumbprint)
    return xml

def _build_health_report(incarnation, container_id, role_instance_id,
                         status, substatus, description):
    # Escape '&', '<' and '>'
    description = saxutils.escape(ustr(description))
    detail = u''
    if substatus is not None:
        substatus = saxutils.escape(ustr(substatus))
        detail = (u"<Details>"
                  u"<SubStatus>{0}</SubStatus>"
                  u"<Description>{1}</Description>"
                  u"</Details>").format(substatus, description)
    xml = (u"<?xml version=\"1.0\" encoding=\"utf-8\"?>"
           u"<Health "
           u"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
           u" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">"
           u"<GoalStateIncarnation>{0}</GoalStateIncarnation>"
           u"<Container>"
           u"<ContainerId>{1}</ContainerId>"
           u"<RoleInstanceList>"
           u"<Role>"
           u"<InstanceId>{2}</InstanceId>"
           u"<Health>"
           u"<State>{3}</State>"
           u"{4}"
           u"</Health>"
           u"</Role>"
           u"</RoleInstanceList>"
           u"</Container>"
           u"</Health>"
           u"").format(incarnation,
                       container_id,
                       role_instance_id,
                       status,
                       detail)
    return xml

def ga_status_to_guest_info(ga_status):
    """
    Convert VMStatus object to status blob format
    """
    v1_ga_guest_info = {
        "computerName": ga_status.hostname,
        "osName": ga_status.osname,
        "osVersion": ga_status.osversion,
        "version": ga_status.version,
    }
    return v1_ga_guest_info

def ga_status_to_v1(ga_status):
    formatted_msg = {
        'lang': 'en-US',
        'message': ga_status.message
    }
    v1_ga_status = {
        "version": ga_status.version,
        "status": ga_status.status,
        "formattedMessage": formatted_msg
    }
    return v1_ga_status

def ext_substatus_to_v1(sub_status_list):
    status_list = []
    for substatus in sub_status_list:
        status = {
            "name": substatus.name,
            "status": substatus.status,
            "code": substatus.code,
            "formattedMessage": {
                "lang": "en-US",
                "message": substatus.message
            }
        }
        status_list.append(status)
    return status_list

def ext_status_to_v1(ext_name, ext_status):
    if ext_status is None:
        return None
    timestamp = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
    v1_sub_status = ext_substatus_to_v1(ext_status.substatusList)
    v1_ext_status = {
        "status": {
            "name": ext_name,
            "configurationAppliedTime": ext_status.configurationAppliedTime,
            "operation": ext_status.operation,
            "status": ext_status.status,
            "code": ext_status.code,
            "formattedMessage": {
                "lang": "en-US",
                "message": ext_status.message
            }
        },
        "version": 1.0,
        "timestampUTC": timestamp
    }
    if len(v1_sub_status) != 0:
        v1_ext_status['status']['substatus'] = v1_sub_status
    return v1_ext_status

def ext_handler_status_to_v1(handler_status, ext_statuses, timestamp):
    v1_handler_status = {
        'handlerVersion': handler_status.version,
        'handlerName': handler_status.name,
        'status': handler_status.status,
        'code': handler_status.code,
        'useExactVersion': True
    }
    if handler_status.message is not None:
        v1_handler_status["formattedMessage"] = {
            "lang": "en-US",
            "message": handler_status.message
        }

    if len(handler_status.extensions) > 0:
        # Currently, no more than one extension per handler
        ext_name = handler_status.extensions[0]
        ext_status = ext_statuses.get(ext_name)
        v1_ext_status = ext_status_to_v1(ext_name, ext_status)
        if ext_status is not None and v1_ext_status is not None:
            v1_handler_status["runtimeSettingsStatus"] = {
                'settingsStatus': v1_ext_status,
                'sequenceNumber': ext_status.sequenceNumber
            }
    return v1_handler_status

def vm_status_to_v1(vm_status, ext_statuses):
    timestamp = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())

    v1_ga_guest_info = ga_status_to_guest_info(vm_status.vmAgent)
    v1_ga_status = ga_status_to_v1(vm_status.vmAgent)
    v1_handler_status_list = []
    for handler_status in vm_status.vmAgent.extensionHandlers:
        v1_handler_status = ext_handler_status_to_v1(handler_status,
                                                     ext_statuses, timestamp)
        if v1_handler_status is not None:
            v1_handler_status_list.append(v1_handler_status)

    v1_agg_status = {
        'guestAgentStatus': v1_ga_status,
        'handlerAggregateStatus': v1_handler_status_list
    }
    v1_vm_status = {
        'version': '1.1',
        'timestampUTC': timestamp,
        'aggregateStatus': v1_agg_status,
        'guestOSInfo': v1_ga_guest_info
    }
    return v1_vm_status

class StatusBlob(object):
    def __init__(self, client):
        self.vm_status = None
        self.ext_statuses = {}
        self.client = client
        self.type = None
        self.data = None

    def set_vm_status(self, vm_status):
        validate_param("vmAgent", vm_status, VMStatus)
        self.vm_status = vm_status

    def set_ext_status(self, ext_handler_name, ext_status):
        validate_param("extensionStatus", ext_status, ExtensionStatus)
        self.ext_statuses[ext_handler_name] = ext_status

    def to_json(self):
        report = vm_status_to_v1(self.vm_status, self.ext_statuses)
        return json.dumps(report)

    __storage_version__ = "2014-02-14"

    def prepare(self, blob_type):
        logger.verbose("Prepare status blob")
        self.data = self.to_json()
        self.type = blob_type

    def upload(self, url):
        try:
            if not self.type in ["BlockBlob", "PageBlob"]:
                raise ProtocolError("Illegal blob type: {0}".format(self.type))

            if self.type == "BlockBlob":
                self.put_block_blob(url, self.data)
            else:
                self.put_page_blob(url, self.data)
            return True

        except Exception as e:
            logger.verbose("Initial status upload failed: {0}", e)

        return False

    def get_block_blob_headers(self, blob_size):
        return {
            "Content-Length": ustr(blob_size),
            "x-ms-blob-type": "BlockBlob",
            "x-ms-date": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
            "x-ms-version": self.__class__.__storage_version__
        }

    def put_block_blob(self, url, data):
        logger.verbose("Put block blob")
        headers = self.get_block_blob_headers(len(data))
        resp = self.client.call_storage_service(restutil.http_put, url, data, headers)
        if resp.status != httpclient.CREATED:
            raise UploadError(
                "Failed to upload block blob: {0}".format(resp.status))

    def get_page_blob_create_headers(self, blob_size):
        return {
            "Content-Length": "0",
            "x-ms-blob-content-length": ustr(blob_size),
            "x-ms-blob-type": "PageBlob",
            "x-ms-date": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
            "x-ms-version": self.__class__.__storage_version__
        }

    def get_page_blob_page_headers(self, start, end):
        return {
            "Content-Length": ustr(end - start),
            "x-ms-date": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
            "x-ms-range": "bytes={0}-{1}".format(start, end - 1),
            "x-ms-page-write": "update",
            "x-ms-version": self.__class__.__storage_version__
        }

    def put_page_blob(self, url, data):
        logger.verbose("Put page blob")

        # Convert string into bytes and align to 512 bytes
        data = bytearray(data, encoding='utf-8')
        page_blob_size = int((len(data) + 511) / 512) * 512

        headers = self.get_page_blob_create_headers(page_blob_size)
        resp = self.client.call_storage_service(restutil.http_put, url, "", headers)
        if resp.status != httpclient.CREATED:
            raise UploadError(
                "Failed to clean up page blob: {0}".format(resp.status))

        if url.count("?") <= 0:
            url = "{0}?comp=page".format(url)
        else:
            url = "{0}&comp=page".format(url)

        logger.verbose("Upload page blob")
        page_max = 4 * 1024 * 1024  # Max page size: 4MB
        start = 0
        end = 0
        while end < len(data):
            end = min(len(data), start + page_max)
            content_size = end - start
            # Align to 512 bytes
            page_end = int((end + 511) / 512) * 512
            buf_size = page_end - start
            buf = bytearray(buf_size)
            buf[0: content_size] = data[start: end]
            headers = self.get_page_blob_page_headers(start, page_end)
            resp = self.client.call_storage_service(
                restutil.http_put,
                url,
                bytebuffer(buf),
                headers)
            if resp is None or resp.status != httpclient.CREATED:
                raise UploadError(
                    "Failed to upload page blob: {0}".format(resp.status))
            start = end

def event_param_to_v1(param):
    param_format = '<Param Name="{0}" Value={1} T="{2}" />'
    param_type = type(param.value)
    attr_type = ""
    if param_type is int:
        attr_type = 'mt:uint64'
    elif param_type is str:
        attr_type = 'mt:wstr'
    elif ustr(param_type).count("'unicode'") > 0:
        attr_type = 'mt:wstr'
    elif param_type is bool:
        attr_type = 'mt:bool'
    elif param_type is float:
        attr_type = 'mt:float64'
    return param_format.format(param.name,
                               saxutils.quoteattr(ustr(param.value)),
                               attr_type)

def event_to_v1(event):
    params = ""
    for param in event.parameters:
        params += event_param_to_v1(param)
    event_str = ('<Event id="{0}">'
                 '<![CDATA[{1}]]>'
                 '</Event>').format(event.eventId, params)
    return event_str

class WireClient(object):

    def __init__(self, endpoint):
        logger.info("Wire server endpoint:{0}", endpoint)
        self._endpoint = endpoint
        self._goal_state = None
        self._host_plugin = None
        self.status_blob = StatusBlob(self)
        self.goal_state_flusher = StateFlusher(conf.get_lib_dir())

    def get_endpoint(self):
        return self._endpoint

    def call_wireserver(self, http_req, *args, **kwargs):
        try:
            # Never use the HTTP proxy for wireserver
            kwargs['use_proxy'] = False
            resp = http_req(*args, **kwargs)

            if restutil.request_failed(resp):
                msg = "[Wireserver Failed] URI {0} ".format(args[0])
                if resp is not None:
                    msg += " [HTTP Failed] Status Code {0}".format(resp.status)
                raise ProtocolError(msg)

        # If the GoalState is stale, pass along the exception to the caller
        except ResourceGoneError:
            raise

        except Exception as e:
            raise ProtocolError("[Wireserver Exception] {0}".format(
                ustr(e)))

        return resp

    def decode_config(self, data):
        if data is None:
            return None
        data = remove_bom(data)
        xml_text = ustr(data, encoding='utf-8')
        return xml_text

    def fetch_config(self, uri, headers):
        resp = self.call_wireserver(restutil.http_get,
                                    uri,
                                    headers=headers)
        return self.decode_config(resp.read())

    def fetch_cache(self, local_file):
        if not os.path.isfile(local_file):
            raise ProtocolError("{0} is missing.".format(local_file))
        try:
            return fileutil.read_file(local_file)
        except IOError as e:
            raise ProtocolError("Failed to read cache: {0}".format(e))

    def save_cache(self, local_file, data):
        try:
            fileutil.write_file(local_file, data)
        except IOError as e:
            fileutil.clean_ioerror(e, paths=[local_file])
            raise ProtocolError("Failed to write cache: {0}".format(e))

    @staticmethod
    def call_storage_service(http_req, *args, **kwargs):
        # Default to use the configured HTTP proxy
        if not 'use_proxy' in kwargs or kwargs['use_proxy'] is None:
            kwargs['use_proxy'] = True

        return http_req(*args, **kwargs)

    def fetch_manifest_through_host(self, uri):
        host = self.get_host_plugin()
        uri, headers = host.get_artifact_request(uri)
        response = self.fetch(uri, headers, use_proxy=False)
        return response

    def fetch_manifest(self, version_uris):
        logger.verbose("Fetch manifest")
        version_uris_shuffled = version_uris
        random.shuffle(version_uris_shuffled)

        for version in version_uris_shuffled:
            # GA expects a location and failoverLocation in ExtensionsConfig, but
            # this is not always the case. See #1147.
            if version.uri is None:
                logger.verbose('The specified manifest URL is empty, ignored.')
                continue

            direct_func = lambda: self.fetch(version.uri)
            # NOTE: the host_func may be called after refreshing the goal state, be careful about any goal state data
            # in the lambda.
            host_func = lambda: self.fetch_manifest_through_host(version.uri)

            try:
                response = self.send_request_using_appropriate_channel(direct_func, host_func)

                if response:
                    host = self.get_host_plugin()
                    host.update_manifest_uri(version.uri)
                    return response
            except Exception as e:
                logger.warn("Exception when fetching manifest. Error: {0}".format(ustr(e)))

        raise ExtensionDownloadError("Failed to fetch manifest from all sources")

    def stream(self, uri, destination, headers=None, use_proxy=None):
        success = False
        logger.verbose("Fetch [{0}] with headers [{1}] to file [{2}]", uri, headers, destination)

        response = self._fetch_response(uri, headers, use_proxy)
        if response is not None:
            chunk_size = 1024 * 1024  # 1MB buffer
            try:
                with open(destination, 'wb', chunk_size) as destination_fh:
                    complete = False
                    while not complete:
                        chunk = response.read(chunk_size)
                        destination_fh.write(chunk)
                        complete = len(chunk) < chunk_size
                success = True
            except Exception as e:
                logger.error('Error streaming {0} to {1}: {2}'.format(uri, destination, ustr(e)))

        return success

    def fetch(self, uri, headers=None, use_proxy=None, decode=True):
        logger.verbose("Fetch [{0}] with headers [{1}]", uri, headers)
        content = None
        response = self._fetch_response(uri, headers, use_proxy)
        if response is not None:
            response_content = response.read()
            content = self.decode_config(response_content) if decode else response_content
        return content

    def _fetch_response(self, uri, headers=None, use_proxy=None):
        resp = None
        try:
            resp = self.call_storage_service(
                restutil.http_get,
                uri,
                headers=headers,
                use_proxy=use_proxy)

            host_plugin = self.get_host_plugin()

            if restutil.request_failed(resp):
                error_response = restutil.read_response_error(resp)
                msg = "Fetch failed from [{0}]: {1}".format(uri, error_response)
                logger.warn(msg)

                if host_plugin is not None:
                    host_plugin.report_fetch_health(uri,
                                                    is_healthy=not restutil.request_failed_at_hostplugin(resp),
                                                    source='WireClient',
                                                    response=error_response)
                raise ProtocolError(msg)
            else:
                if host_plugin is not None:
                    host_plugin.report_fetch_health(uri, source='WireClient')

        except (HttpError, ProtocolError, IOError) as e:
            logger.verbose("Fetch failed from [{0}]: {1}", uri, e)
            if isinstance(e, ResourceGoneError) or isinstance(e, InvalidContainerError):
                raise
        return resp

    # Type of update performed by _update_from_goal_state()
    class _UpdateType(object):
        # Update the Host GA Plugin client (Container ID and RoleConfigName)
        HostPlugin = 0
        # Update the full goal state only if the incarnation has changed
        GoalState = 1
        # Update the full goal state unconditionally
        GoalStateForced = 2

    def update_host_plugin_from_goal_state(self):
        """
        Fetches a new goal state and updates the Container ID and Role Config Name of the host plugin client
        """
        self._update_from_goal_state(WireClient._UpdateType.HostPlugin)

    def update_goal_state(self, forced=False):
        """
        Updates the goal state if the incarnation changed or if 'forced' is True
        """
        self._update_from_goal_state(
            WireClient._UpdateType.GoalStateForced if forced else WireClient._UpdateType.GoalState)

    def _update_from_goal_state(self, refresh_type):
        """
        Fetches a new goal state and updates the internal state of the WireClient according to the requested 'refresh_type'
        """
        max_retry = 3

        for retry in range(1, max_retry + 1):
            try:
                if refresh_type == WireClient._UpdateType.HostPlugin:
                    goal_state = GoalState.fetch_goal_state(self)
                    self._update_host_plugin(goal_state.container_id, goal_state.role_config_name)
                    return

                if self._goal_state is None or refresh_type == WireClient._UpdateType.GoalStateForced:
                    new_goal_state = GoalState.fetch_full_goal_state(self)
                else:
                    new_goal_state = GoalState.fetch_full_goal_state_if_incarnation_different_than(self, self._goal_state.incarnation)

                if new_goal_state is not None:
                    self._goal_state = new_goal_state
                    self._save_goal_state()
                    self._update_host_plugin(new_goal_state.container_id, new_goal_state.role_config_name)

                return

            except IOError as e:
                logger.warn("IOError processing goal state (attempt {0}/{1}) [{2}]", retry, max_retry, ustr(e))

            except ResourceGoneError:
                logger.info("Goal state is stale, re-fetching (attempt {0}/{1})", retry, max_retry)

            except ProtocolError as e:
                logger.verbose("ProtocolError processing goal state (attempt {0}/{1}) [{2}]", retry, max_retry, ustr(e))

            except Exception as e:
                logger.verbose("Exception processing goal state (attempt {0}/{1}) [{2}]", retry, max_retry, ustr(e))

        raise ProtocolError("Exceeded max retry updating goal state")

    def _update_host_plugin(self, container_id, role_config_name):
        if self._host_plugin is not None:
            self._host_plugin.update_container_id(container_id)
            self._host_plugin.update_role_config_name(role_config_name)

    def _save_goal_state(self):
        try:
            self.goal_state_flusher.flush(datetime.utcnow())

        except Exception as e:
            logger.warn("Failed to save the previous goal state to the history folder: {0}", ustr(e))

        try:
            local_file = os.path.join(conf.get_lib_dir(), INCARNATION_FILE_NAME)
            self.save_cache(local_file, self._goal_state.incarnation)

            def save_if_not_none(goal_state_property, file_name):
                file_path = os.path.join(conf.get_lib_dir(), file_name)

                if goal_state_property is not None and goal_state_property.xml_text is not None:
                    self.save_cache(file_path, goal_state_property.xml_text)

            # NOTE: Certificates are saved in Certificate.__init__
            save_if_not_none(self._goal_state, GOAL_STATE_FILE_NAME.format(self._goal_state.incarnation))
            save_if_not_none(self._goal_state.hosting_env, HOSTING_ENV_FILE_NAME)
            save_if_not_none(self._goal_state.shared_conf, SHARED_CONF_FILE_NAME)
            save_if_not_none(self._goal_state.ext_conf, EXT_CONF_FILE_NAME.format(self._goal_state.incarnation))
            save_if_not_none(self._goal_state.remote_access, REMOTE_ACCESS_FILE_NAME.format(self._goal_state.incarnation))

        except Exception as e:
            logger.warn("Failed to save the goal state to disk: {0}", ustr(e))

    def _set_host_plugin(self, new_host_plugin):
        if new_host_plugin is None:
            logger.warn("Setting empty Host Plugin object!")
        self._host_plugin = new_host_plugin

    def get_goal_state(self):
        if self._goal_state is None:
            raise ProtocolError("Trying to fetch goal state before initialization!")
        return self._goal_state

    def get_hosting_env(self):
        if self._goal_state is None:
            raise ProtocolError("Trying to fetch Hosting Environment before initialization!")
        return self._goal_state.hosting_env

    def get_shared_conf(self):
        if self._goal_state is None:
            raise ProtocolError("Trying to fetch Shared Conf before initialization!")
        return self._goal_state.shared_conf

    def get_certs(self):
        if self._goal_state is None:
            raise ProtocolError("Trying to fetch Certificates before initialization!")
        return self._goal_state.certs

    def get_ext_conf(self):
        if self._goal_state is None:
            raise ProtocolError("Trying to fetch Extension Conf before initialization!")
        return self._goal_state.ext_conf

    def get_ext_manifest(self, ext_handler):
        if self._goal_state is None:
            raise ProtocolError("Trying to fetch Extension Manifest before initialization!")

        local_file = MANIFEST_FILE_NAME.format(ext_handler.name, self.get_goal_state().incarnation)
        local_file = os.path.join(conf.get_lib_dir(), local_file)

        try:
            xml_text = self.fetch_manifest(ext_handler.versionUris)
            self.save_cache(local_file, xml_text)
            return ExtensionManifest(xml_text)
        except Exception as e:
            raise ExtensionDownloadError("Failed to retrieve extension manifest. Error: {0}".format(ustr(e)))

    def get_remote_access(self):
        if self._goal_state is None:
            raise ProtocolError("Trying to fetch Remote Access before initialization!")
        return self._goal_state.remote_access

    def get_gafamily_manifest(self, vmagent_manifest, goal_state):
        local_file = MANIFEST_FILE_NAME.format(vmagent_manifest.family, goal_state.incarnation)
        local_file = os.path.join(conf.get_lib_dir(), local_file)

        try:
            xml_text = self.fetch_manifest(vmagent_manifest.versionsManifestUris)
            fileutil.write_file(local_file, xml_text)
            return ExtensionManifest(xml_text)
        except Exception as e:
            raise ProtocolError("Failed to retrieve GAFamily manifest. Error: {0}".format(ustr(e)))

    def check_wire_protocol_version(self):
        uri = VERSION_INFO_URI.format(self.get_endpoint())
        version_info_xml = self.fetch_config(uri, None)
        version_info = VersionInfo(version_info_xml)

        preferred = version_info.get_preferred()
        if PROTOCOL_VERSION == preferred:
            logger.info("Wire protocol version:{0}", PROTOCOL_VERSION)
        elif PROTOCOL_VERSION in version_info.get_supported():
            logger.info("Wire protocol version:{0}", PROTOCOL_VERSION)
            logger.info("Server preferred version:{0}", preferred)
        else:
            error = ("Agent supported wire protocol version: {0} was not "
                     "advised by Fabric.").format(PROTOCOL_VERSION)
            raise ProtocolNotFoundError(error)

    def send_request_using_appropriate_channel(self, direct_func, host_func):
        # A wrapper method for all function calls that send HTTP requests. The purpose of the method is to
        # define which channel to use, direct or through the host plugin. For the host plugin channel,
        # also implement a retry mechanism.

        # By default, the direct channel is the default channel. If that is the case, try getting a response
        # through that channel. On failure, fall back to the host plugin channel.

        # When using the host plugin channel, regardless if it's set as default or not, try sending the request first.
        # On specific failures that indicate a stale goal state (such as resource gone or invalid container parameter),
        # refresh the goal state and try again. If successful, set the host plugin channel as default. If failed,
        # raise the exception.

        # NOTE: direct_func and host_func are passed as lambdas. Be careful about capturing goal state data in them as
        # they will not be refreshed even if a goal state refresh is called before retrying the host_func.

        if not HostPluginProtocol.is_default_channel():
            ret = None
            try:
                ret = direct_func()

                # Different direct channel functions report failure in different ways: by returning None, False,
                # or raising ResourceGone or InvalidContainer exceptions.
                if not ret:
                    logger.periodic_info(logger.EVERY_HOUR, "[PERIODIC] Request failed using the direct channel, "
                                                            "switching to host plugin.")
            except (ResourceGoneError, InvalidContainerError) as e:
                logger.periodic_info(logger.EVERY_HOUR, "[PERIODIC] Request failed using the direct channel, "
                                                        "switching to host plugin. Error: {0}".format(ustr(e)))

            if ret:
                return ret
        else:
            logger.periodic_info(logger.EVERY_HALF_DAY, "[PERIODIC] Using host plugin as default channel.")

        try:
            ret = host_func()
        except (ResourceGoneError, InvalidContainerError) as e:
            host_plugin = self.get_host_plugin()
            old_container_id = host_plugin.container_id
            old_role_config_name = host_plugin.role_config_name

            msg = "[PERIODIC] Request failed with the current host plugin configuration. " \
                  "ContainerId: {0}, role config file: {1}. Fetching new goal state and retrying the call." \
                  "Error: {2}".format(old_container_id, old_role_config_name, ustr(e))
            logger.periodic_info(logger.EVERY_SIX_HOURS, msg)

            self.update_host_plugin_from_goal_state()

            new_container_id = host_plugin.container_id
            new_role_config_name = host_plugin.role_config_name
            msg = "[PERIODIC] Host plugin reconfigured with new parameters. " \
                  "ContainerId: {0}, role config file: {1}.".format(new_container_id, new_role_config_name)
            logger.periodic_info(logger.EVERY_SIX_HOURS, msg)

            try:
                ret = host_func()
                if ret:
                    msg = "[PERIODIC] Request succeeded using the host plugin channel after goal state refresh. " \
                          "ContainerId changed from {0} to {1}, " \
                          "role config file changed from {2} to {3}.".format(old_container_id, new_container_id,
                                                                             old_role_config_name, new_role_config_name)
                    add_periodic(delta=logger.EVERY_SIX_HOURS,
                                 name=AGENT_NAME,
                                 version=CURRENT_VERSION,
                                 op=WALAEventOperation.HostPlugin,
                                 is_success=True,
                                 message=msg,
                                 log_event=True)

            except (ResourceGoneError, InvalidContainerError) as e:
                msg = "[PERIODIC] Request failed using the host plugin channel after goal state refresh. " \
                      "ContainerId changed from {0} to {1}, role config file changed from {2} to {3}. " \
                      "Exception type: {4}.".format(old_container_id, new_container_id, old_role_config_name,
                                                    new_role_config_name, type(e).__name__)
                add_periodic(delta=logger.EVERY_SIX_HOURS,
                             name=AGENT_NAME,
                             version=CURRENT_VERSION,
                             op=WALAEventOperation.HostPlugin,
                             is_success=False,
                             message=msg,
                             log_event=True)
                raise

        if not HostPluginProtocol.is_default_channel():
            logger.info("Setting host plugin as default channel from now on. "
                        "Restart the agent to reset the default channel.")
            HostPluginProtocol.set_default_channel(True)

        return ret

    def upload_status_blob(self):
        ext_conf = self.get_ext_conf()

        if ext_conf.status_upload_blob is None:
            # the status upload blob is in ExtensionsConfig so force a full goal state refresh
            self.update_goal_state(forced=True)
            ext_conf = self.get_ext_conf()

        if ext_conf.status_upload_blob is None:
            raise ProtocolNotFoundError("Status upload uri is missing")

        blob_type = ext_conf.status_upload_blob_type
        if blob_type not in ["BlockBlob", "PageBlob"]:
            blob_type = "BlockBlob"
            logger.verbose("Status Blob type is unspecified, assuming BlockBlob")

        try:
            self.status_blob.prepare(blob_type)
        except Exception as e:
            raise ProtocolError("Exception creating status blob: {0}", ustr(e))

        # Swap the order of use for the HostPlugin vs. the "direct" route.
        # Prefer the use of HostPlugin. If HostPlugin fails fall back to the
        # direct route.
        #
        # The code previously preferred the "direct" route always, and only fell back
        # to the HostPlugin *if* there was an error. We would like to move to
        # the HostPlugin for all traffic, but this is a big change.  We would like
        # to see how this behaves at scale, and have a fallback should things go
        # wrong. This is why we try HostPlugin then direct.
        try:
            host = self.get_host_plugin()
            host.put_vm_status(self.status_blob, ext_conf.status_upload_blob, ext_conf.status_upload_blob_type)
            return
        except ResourceGoneError:
            # refresh the host plugin client and try again on the next iteration of the main loop
            self.update_host_plugin_from_goal_state()
            return
        except Exception as e:
            # for all other errors, fall back to direct
            msg = "Falling back to direct upload: {0}".format(ustr(e))
            self.report_status_event(msg, is_success=True)

        try:
            if self.status_blob.upload(ext_conf.status_upload_blob):
                return
        except Exception as e:
            msg = "Exception uploading status blob: {0}".format(ustr(e))
            self.report_status_event(msg, is_success=False)

        raise ProtocolError("Failed to upload status blob via either channel")

    def report_role_prop(self, thumbprint):
        goal_state = self.get_goal_state()
        role_prop = _build_role_properties(goal_state.container_id,
                                           goal_state.role_instance_id,
                                           thumbprint)
        role_prop = role_prop.encode("utf-8")
        role_prop_uri = ROLE_PROP_URI.format(self.get_endpoint())
        headers = self.get_header_for_xml_content()
        try:
            resp = self.call_wireserver(restutil.http_post,
                                        role_prop_uri,
                                        role_prop,
                                        headers=headers)
        except HttpError as e:
            raise ProtocolError((u"Failed to send role properties: "
                                 u"{0}").format(e))
        if resp.status != httpclient.ACCEPTED:
            raise ProtocolError((u"Failed to send role properties: "
                                 u",{0}: {1}").format(resp.status,
                                                      resp.read()))

    def report_health(self, status, substatus, description):
        goal_state = self.get_goal_state()
        health_report = _build_health_report(goal_state.incarnation,
                                             goal_state.container_id,
                                             goal_state.role_instance_id,
                                             status,
                                             substatus,
                                             description)
        health_report = health_report.encode("utf-8")
        health_report_uri = HEALTH_REPORT_URI.format(self.get_endpoint())
        headers = self.get_header_for_xml_content()
        try:
            # 30 retries with 10s sleep gives ~5min for wireserver updates;
            # this is retried 3 times with 15s sleep before throwing a
            # ProtocolError, for a total of ~15min.
            resp = self.call_wireserver(restutil.http_post,
                                        health_report_uri,
                                        health_report,
                                        headers=headers,
                                        max_retry=30,
                                        retry_delay=15)
        except HttpError as e:
            raise ProtocolError((u"Failed to send provision status: "
                                 u"{0}").format(e))
        if restutil.request_failed(resp):
            raise ProtocolError((u"Failed to send provision status: "
                                 u",{0}: {1}").format(resp.status,
                                                      resp.read()))

    def send_event(self, provider_id, event_str):
        uri = TELEMETRY_URI.format(self.get_endpoint())
        data_format = ('<?xml version="1.0"?>'
                       '<TelemetryData version="1.0">'
                       '<Provider id="{0}">{1}'
                       '</Provider>'
                       '</TelemetryData>')
        data = data_format.format(provider_id, event_str)
        try:
            header = self.get_header_for_xml_content()
            # NOTE: The call to wireserver requests utf-8 encoding in the headers, but the body should not
            #       be encoded: some nodes in the telemetry pipeline do not support utf-8 encoding.
            resp = self.call_wireserver(restutil.http_post, uri, data, header)
        except HttpError as e:
            raise ProtocolError("Failed to send events:{0}".format(e))

        if restutil.request_failed(resp):
            logger.verbose(resp.read())
            raise ProtocolError(
                "Failed to send events:{0}".format(resp.status))

    def report_event(self, event_list):
        buf = {}
        # Group events by providerId
        for event in event_list.events:
            if event.providerId not in buf:
                buf[event.providerId] = ""
            event_str = event_to_v1(event)
            if len(event_str) >= MAX_EVENT_BUFFER_SIZE:
                details_of_event = [ustr(x.name) + ":" + ustr(x.value) for x in event.parameters if x.name in
                                    ["Name", "Version", "Operation", "OperationSuccess"]]
                logger.periodic_warn(logger.EVERY_HALF_HOUR,
                                     "Single event too large: {0}, with the length: {1} more than the limit({2})"
                                     .format(str(details_of_event), len(event_str), MAX_EVENT_BUFFER_SIZE))
                continue
            if len(buf[event.providerId] + event_str) >= MAX_EVENT_BUFFER_SIZE:
                self.send_event(event.providerId, buf[event.providerId])
                buf[event.providerId] = ""
            buf[event.providerId] = buf[event.providerId] + event_str

        # Send out all events left in buffer.
        for provider_id in list(buf.keys()):
            if len(buf[provider_id]) > 0:
                self.send_event(provider_id, buf[provider_id])

    def report_status_event(self, message, is_success):
        from azurelinuxagent.common.event import report_event, \
            WALAEventOperation

        report_event(op=WALAEventOperation.ReportStatus,
                     is_success=is_success,
                     message=message,
                     log_event=not is_success)

    def get_header(self):
        return {
            "x-ms-agent-name": "WALinuxAgent",
            "x-ms-version": PROTOCOL_VERSION
        }

    def get_header_for_xml_content(self):
        return {
            "x-ms-agent-name": "WALinuxAgent",
            "x-ms-version": PROTOCOL_VERSION,
            "Content-Type": "text/xml;charset=utf-8"
        }

    def get_header_for_cert(self):
        trans_cert_file = os.path.join(conf.get_lib_dir(),
                                       TRANSPORT_CERT_FILE_NAME)
        content = self.fetch_cache(trans_cert_file)
        cert = get_bytes_from_pem(content)
        return {
            "x-ms-agent-name": "WALinuxAgent",
            "x-ms-version": PROTOCOL_VERSION,
            "x-ms-cipher-name": "DES_EDE3_CBC",
            "x-ms-guest-agent-public-x509-cert": cert
        }

    def get_host_plugin(self):
        if self._host_plugin is None:
            goal_state = GoalState.fetch_goal_state(self)
            self._set_host_plugin(HostPluginProtocol(self.get_endpoint(),
                                                     goal_state.container_id,
                                                     goal_state.role_config_name))
        return self._host_plugin

    def has_artifacts_profile_blob(self):
        ext_conf = self.get_ext_conf()
        return ext_conf and not \
            textutil.is_str_none_or_whitespace(ext_conf.artifacts_profile_blob)

    def get_artifacts_profile_through_host(self, blob):
        host = self.get_host_plugin()
        uri, headers = host.get_artifact_request(blob)
        profile = self.fetch(uri, headers, use_proxy=False)
        return profile

    def get_artifacts_profile(self):
        artifacts_profile = None

        if self.has_artifacts_profile_blob():
            blob = self.get_ext_conf().artifacts_profile_blob
            direct_func = lambda: self.fetch(blob)
            # NOTE: the host_func may be called after refreshing the goal state, be careful about any goal state data
            # in the lambda.
            host_func = lambda: self.get_artifacts_profile_through_host(blob)

            logger.verbose("Retrieving the artifacts profile")

            try:
                profile = self.send_request_using_appropriate_channel(direct_func, host_func)
            except Exception as e:
                logger.warn("Exception retrieving artifacts profile: {0}".format(ustr(e)))
                return None

            if not textutil.is_str_empty(profile):
                logger.verbose("Artifacts profile downloaded")
                try:
                    artifacts_profile = InVMArtifactsProfile(profile)
                except Exception:
                    logger.warn("Could not parse artifacts profile blob")
                    msg = "Content: [{0}]".format(profile)
                    logger.verbose(msg)

                    from azurelinuxagent.common.event import report_event, WALAEventOperation
                    report_event(op=WALAEventOperation.ArtifactsProfileBlob,
                                 is_success=False,
                                 message=msg,
                                 log_event=False)

        return artifacts_profile

class VersionInfo(object):
    def __init__(self, xml_text):
        """
        Query endpoint server for wire protocol version.
        Fail if our desired protocol version is not seen.
        """
        logger.verbose("Load Version.xml")
        self.parse(xml_text)

    def parse(self, xml_text):
        xml_doc = parse_doc(xml_text)
        preferred = find(xml_doc, "Preferred")
        self.preferred = findtext(preferred, "Version")
        logger.info("Fabric preferred wire protocol version:{0}",
                    self.preferred)

        self.supported = []
        supported = find(xml_doc, "Supported")
        supported_version = findall(supported, "Version")
        for node in supported_version:
            version = gettext(node)
            logger.verbose("Fabric supported wire protocol version:{0}",
                           version)
            self.supported.append(version)

    def get_preferred(self):
        return self.preferred

    def get_supported(self):
        return self.supported

class ExtensionManifest(object):
    def __init__(self, xml_text):
        if xml_text is None:
            raise ValueError("ExtensionManifest is None")
        logger.verbose("Load ExtensionManifest.xml")
        self.pkg_list = ExtHandlerPackageList()
        self._parse(xml_text)

    def _parse(self, xml_text):
        xml_doc = parse_doc(xml_text)
        self._handle_packages(findall(find(xml_doc,
                                           "Plugins"),
                                      "Plugin"),
                              False)
        self._handle_packages(findall(find(xml_doc,
                                           "InternalPlugins"),
                                      "Plugin"),
                              True)

    def _handle_packages(self, packages, isinternal):
        for package in packages:
            version = findtext(package, "Version")

            disallow_major_upgrade = findtext(package,
                                              "DisallowMajorVersionUpgrade")
            if disallow_major_upgrade is None:
                disallow_major_upgrade = ''
            disallow_major_upgrade = disallow_major_upgrade.lower() == "true"

            uris = find(package, "Uris")
            uri_list = findall(uris, "Uri")
            uri_list = [gettext(x) for x in uri_list]
            pkg = ExtHandlerPackage()
            pkg.version = version
            pkg.disallow_major_upgrade = disallow_major_upgrade
            for uri in uri_list:
                pkg_uri = ExtHandlerVersionUri()
                pkg_uri.uri = uri
                pkg.uris.append(pkg_uri)

            pkg.isinternal = isinternal
            self.pkg_list.versions.append(pkg)

# Do not extend this class
class InVMArtifactsProfile(object):
    """
    deserialized json string of InVMArtifactsProfile.
    It is expected to contain the following fields:
    * inVMArtifactsProfileBlobSeqNo
    * profileId (optional)
    * onHold (optional)
    * certificateThumbprint (optional)
    * encryptedHealthChecks (optional)
    * encryptedApplicationProfile (optional)
    """

    def __init__(self, artifacts_profile):
        if not textutil.is_str_empty(artifacts_profile):
            self.__dict__.update(parse_json(artifacts_profile))

    def is_on_hold(self):
        # hasattr() is not available in Python 2.6
        if 'onHold' in self.__dict__:
            return str(self.onHold).lower() == 'true'
        return False


'''
    https://projecteuler.net/problem=48

    The series, 11 + 22 + 33 + ... + 1010 = 10405071317.

    Find the last ten digits of the series, 11 + 22 + 33 + ... + 10001000.

    Just take the last 10 digits
'''
import time
import math
def getSumOfAllPrimeOfNumber(limit):
    sum = 0
    for i in range(0,limit+1):
        sum += pow(i,i)
    return sum - 1
def main():
    print(getSumOfAllPrimeOfNumber(1000))
if(__name__ == "__main__"):
    main()


# 백준 1790번 수 이어쓰기 2

# https://yeoooo.github.io/algorithm/BOJ1790/

# 입력 N 기준 최대 10억, 시간 제한은 7초
# 이어쓰기 방식으로 하면 시간이 부족함

# 이분 탐색을 이용한다.

# 먼저 k가 1 ~ 9의 범위 안에 있다면 자리수는 한자리이다. k가 10 ~ 99의 범위 안에 있다면 자리수는 두자리이다.
# 위와 같이 k에서 자리수에 자리수를 늘려가며 맞게끔 9 x 1, 90 x 2, 900 x 3 ... 을 빼준다.
# 이유는 1 ~ 9는 각 숫자마다 1자리씩이지만 10 ~ 99부터는 각 숫자마다 2자리 이상이기 때문이다.

# k에서 자리수에 맞게 빼주다 보면 더 이상 뺄 수 없는 값이 나온다.
# 이 때 k가 어느 수에 속하는지 알기 위해 k를 지금까지 세어온 자리 수 만큼으로 나눈 뒤
# 그 값을 더해준다. (k가 300인 경우 그 자리수인 3으로 나눠주면 원하는 값이 100) k로 원하는 수를 찾았으면 n과 대소비교 후 값을 낸다.

# cf) 10~99, 100~999 … 사이의 값은 89개가 아닌 90개이다.

import sys

input = sys.stdin.readline

n, k = map(int, input().split())

ans = 0
digit = 1 # 자리수
nine = 9 # 9까지 범위

while k > digit*nine:
    k = k - (digit * nine) # 자리수를 늘려가면서 k에서 빼주기
    ans = ans + nine
    digit += 1
    nine = nine * 10
    # print("ans : " + str(ans))
    # print("digit : " + str(digit))
    # print("nine : " + str(nine))
    # print("k : " + str(k))

ans = (ans+1) + (k-1) // digit # 연산 순서가 // 우선 그다음 +
# print("ans : " + str(ans))

if ans > n:
    print(-1)
else:
    print(str(ans)[(k-1)%digit]) # ans는 int형으로 16인데 str로 형변환 후 [(k-1)%digit : 1] , 즉 1번째 인덱스인 '6'이 나온다. 파이썬 문법


import discord
from discord.ext import commands
import logging
from datetime import datetime

class Logger(commands.Cog):
    def __init__(self, bot):
        self.bot = bot
        self.logger = logging.getLogger(__name__)  # Creating a logger for this cog
        self.setup_logger()

    def setup_logger(self):
        # Set up the logging format and level
        formatter = logging.Formatter('%(asctime)s:%(levelname)s:%(name)s: %(message)s')
        file_handler = logging.FileHandler('log.log')
        file_handler.setFormatter(formatter)
        self.logger.addHandler(file_handler)
        self.logger.setLevel(logging.INFO)

    @commands.Cog.listener()
    async def on_command(self, ctx):
        # Log every command invocation
        self.logger.info(f"Command used: {ctx.command} by {ctx.author} in {ctx.guild}")

    # Additional listeners for other events can be added here

async def setup(bot):
    await bot.add_cog(Logger(bot))
    print("Logger cog loaded")


class Player:
    def __init__(self, name, starting_stack=100):
        self.name = name
        self.hand = []
        self.stack = starting_stack  # Start with the specified starting stack
        self.rank = None  # Store the hand ranking

    def bet(self, current_bet):
        while True:
            try:
                bet_amount = int(input(f"{self.name}, your stack is {self.stack} BB. Enter your bet amount: "))
                if bet_amount >= current_bet and bet_amount <= self.stack:
                    self.stack -= bet_amount  # Update the player's stack after the bet
                    return bet_amount
                else:
                    print("Bet amount should be equal to or greater than the current bet and less than or equal to your stack.")
            except ValueError:
                print("Invalid input. Please enter a valid bet amount.")


import cv2
import glob

method = cv2.TM_SQDIFF_NORMED

# Read the images from the file
large_image = cv2.imread('red-team.png')
champions = glob.glob('test/*.png')
print(champions)
score = 100
scoreLoc = None

for champion in champions:
	small_image = cv2.imread(champion)

	result = cv2.matchTemplate(small_image, large_image, method)

	# We want the minimum squared difference
	mn,_,mnLoc,_ = cv2.minMaxLoc(result)
	if mn < score:
		score = mn
		scoreLoc = mnLoc
# Draw the rectangle:
# Extract the coordinates of our best match
MPx,MPy = scoreLoc

# Step 2: Get the size of the template. This is the same size as the match.
trows,tcols = small_image.shape[:2]

# Step 3: Draw the rectangle on large_image
cv2.rectangle(large_image, (MPx,MPy),(MPx+tcols,MPy+trows),(0,0,255),2)

# Display the original image with the rectangle around the match.
cv2.imshow('output',large_image)

# The image is only displayed if we call this
cv2.waitKey(0)


from tracardi.service.tracardi_http_client import HttpClient
from .send_event.model.config import MatomoPayload

class MatomoClientException(Exception):
    pass

class MatomoClient:

    def __init__(self, token: str, api_url: str):
        self.token = token
        self.api_url = api_url
        self.retries = 1

    def set_retries(self, retries: int) -> None:
        self.retries = retries

    async def send_event(self, matomo_payload: MatomoPayload):
        headers = {"X-FORWARDED-FOR": matomo_payload.cip} if matomo_payload.cip else None
        async with HttpClient(self.retries, 204, headers=headers) as client:
            params = {"token_auth": self.token, **matomo_payload.to_dict()}
            async with client.post(
                url=f"{self.api_url}/matomo.php",
                params=params
            ) as response:
                if response.status != 204:
                    raise MatomoClientException(await response.text())


#Игра кости. Играют 2 игрока, по очереди бросают по 2 игральных кубика.
# Победил тот, у кого больше очков. Ничья если очки равные.
##import random
##
##answer = 'д'
##while answer == 'д':
##    cube1 = random.randint(1,6)
##    cube2 = random.randint(1,6)
##    player1_score = cube1 + cube2
##    print("Первый игрок набрал", player1_score,"очков")
##    cube1 = random.randint(1,6)
##    cube2 = random.randint(1,6)
##    player2_score = cube1 + cube2
##    print("Второй игрок набрал", player2_score,"очков")
##    if player1_score > player2_score:
##        print("1-й выиграл")
##    elif player2_score > player1_score:
##        print("2-й выиграл")
##    elif player1_score == player2_score:
##        print("Ничья")
##    print("Играем ещё? Для продолжения введите букву д")
##    answer = input()

#Камень - ножницы - бумага с компьютером
##import random
##answer = 'д'
##while answer == 'д':
##    comp = random.randint(1,3)
##    if comp == 1:
##        comp = "камень"
##    elif comp == 2:
##        comp = "ножницы"
##    elif comp == 3:
##        comp = "бумага"
##
##    print("Введите свой выбор: 1 - для камень, 2 - для ножницы")
##    print("3 - для бумаги")
##    player = int(input())
##    if player == 1:
##        player = "камень"
##    elif player == 2:
##        player = "ножницы"
##    elif player == 3:
##        player = "бумага"
##    #выводим кто что загадал
##    print("У игрока", player, ", у компа", comp)
##    #проверка выигрыша, ничьи, проигрыша
##    if player == "камень" and comp == "ножницы":
##        print("Выиграл игрок")
##    elif player == "ножницы" and comp == "бумага":
##        print("Выиграл игрок")
##    elif player == "бумага" and comp == "камень":
##        print("Выиграл игрок")
##    elif player == comp:
##        print("Ничья")
##    else:
##        print("Выиграл комп")
##    print("Играем ещё? Для продолжения введите букву д")
##    answer = input()

#Array1. Дано целое число N (>0). Сформировать и вывести
#целочисленный список размера N,содержащий N первых положительных
#нечетных чисел: 1, 3, 5, ... .

### создание списка
##mas = []
##n = int(input())
##i = 1 # счетчик цикла
##k = 1 # первое нечетное число
##while i <= n: # повторять n раз
##    mas.append(k) # добавить нечетное число в список
##    k = k + 2 # вычислить следующее нечетное
##    i = i + 1 # изменили счетчик цикла
##print(*mas) # печать списка

#Array2. Дано целое число N (>0). Сформировать и вывести
#целочисленный массив размера N, содержащий степени двойки от
#первой до N-й: 2, 4, 8, 16, ... .
##mas = []
##n = int(input())
##k = 2
##i = 1
##while i <= n:
##    mas.append(k)
##    k = k * 2
##    i = i + 1
##print(mas)

#Series1◦. Даны десять вещественных чисел. Найти их сумму.
##import random
##mas = []
##n = int(input())
##for i in range(n):
##    mas.append(random.randint(-10,10))
##print(*mas)
##summa = 0
##for i in range(n):
##    summa += mas[i]
##print(summa)

#Series2. Даны десять вещественных чисел. Найти их произведение.
##import random
##mas = []
##n = 10
##for i in range(n):
##    mas.append(random.randint(1,5))
##print(*mas)
##p = 1
##for i in range(n):
##    p *= mas[i]
##print(p)

#Series3. Даны десять чисел.Найти их среднее арифметическое.
##import random
##mas = []
##n = 10
##for i in range(n):
##    mas.append(random.randint(-10,10))
##print(*mas)
##summa = 0
##for i in range(n):
##    summa += mas[i]
##print(summa/n)

#Распределительная шляпа
import random
students = ['Гарри','Рон','Гермиона','Драко','Симус','Фред',
            'Лаванда','Оливер']

print(students[0])

griffindor = []
hufflepuf = []
slizerin = []

for i in range(3):
    stud = random.choice(students)
    students.remove(stud)
    griffindor.append(stud)

for i in range(3):
    stud = random.choice(students)
    students.remove(stud)
    hufflepuf.append(stud)

for i in range(2):
    stud = random.choice(students)
    students.remove(stud)
    slizerin.append(stud)

print("Гриффиндор:", *griffindor)
print("Хаффлпаф:", *hufflepuf)
print("Cлизерин:", *slizerin)


from badchants import has_wrestling_cadence, make_chant
from mastodon import Mastodon
import json
import sys
import random

CELEBS_PATH = 'input/celebrities.json'

def load_names():
	celebs = ""
	with open(CELEBS_PATH) as f:
		file_data = f.read()
		celebs = json.loads(file_data)
	return celebs['celebrities']

def main():
	access_token = sys.argv[1]
	api = Mastodon(access_token = access_token, api_base_url = 'https://botsin.space')
	wrestling_names = list(filter(has_wrestling_cadence, load_names()))
	status_text = make_chant(random.choice(wrestling_names))
	print(status_text)
	status = api.status_post(status_text)
	print(f"status posted at {status['url']}")

if __name__ == '__main__':
	main()


import unittest
import io
import sys
import os
import datetime
from unittest.mock import patch

# Import the functions from your task manager program
from task import main, add_task, list_tasks, mark_completed, save_tasks

class test_task(unittest.TestCase):

    def setUp(self):
        self.task_file = "test_tasks.txt"
        sys.stdout = io.StringIO()  # Redirect stdout to capture print statements
        self.current_time = datetime.datetime.now()
        self.test_tasks = [{"name": "Task 1", "completed": False, "timestamp": self.current_time},
                          {"name": "Task 2", "completed": True, "timestamp": self.current_time}]

    def tearDown(self):
        sys.stdout = sys.stdout  # Restore normal stdout
        if os.path.exists(self.task_file):
            os.remove(self.task_file)

    def test_add_task(self):
        tasks = []
        input_data = "Test Task\n4"
        with patch('builtins.input', side_effect=input_data.split('\n')):
            with patch('task.datetime.datetime') as mock_datetime:
                mock_datetime.now.return_value = self.current_time
                add_task(tasks)
                self.assertEqual(tasks[0]["name"], "Test Task")

    def test_list_tasks(self):
        with patch('task.datetime.datetime') as mock_datetime:
            mock_datetime.now.return_value = self.current_time
            with patch('builtins.input', side_effect="4\n".split('\n')):
                with patch('task.sys.stdout', new_callable=io.StringIO):
                    add_task(self.test_tasks)
                    main()
        output = sys.stdout.getvalue()
        expected_output = "1. Task 1 - Not Completed (Added on {})\n2. Task 2 - Completed (Added on {})\n".format(self.current_time, self.current_time)
        self.assertEqual(output, expected_output)

    def test_mark_completed(self):
        tasks = self.test_tasks.copy()
        input_data = "1\n4"
        with patch('builtins.input', side_effect=input_data.split('\n')):
            with patch('task.datetime.datetime') as mock_datetime:
                mock_datetime.now.return_value = self.current_time
                mark_completed(tasks)
                self.assertTrue(tasks[0]["completed"])

    def test_save_tasks(self):
        tasks = self.test_tasks.copy()
        save_tasks(tasks)
        self.assertTrue(os.path.exists(self.task_file))
        with open(self.task_file, "r") as file:
            saved_data = file.read()
        expected_data = "Task 1,False,{}\nTask 2,True,{}\n".format(self.current_time, self.current_time)
        self.assertEqual(saved_data, expected_data)

if name == "main":
    unittest.main()


import sqlite3
conn = sqlite3.connect('coffee.db', check_same_thread=False)
cursor = conn.cursor()

def create_table():
    cursor.execute('''
        CREATE TABLE IF NOT EXISTS coffee_types (
            id INTEGER PRIMARY KEY,
            name TEXT NOT NULL,
            description TEXT,
            price REAL
        )
    ''')
    conn.commit()

def get_all_coffee():
    return cursor.execute('SELECT * FROM coffee_types').fetchall()

def remove_coffee(coffee_id):
    cursor.execute('DELETE FROM coffee_types WHERE id = ?', (coffee_id,))
    conn.commit()

def insert_data(name, description, price):
    cursor.execute('INSERT INTO coffee_types (name, description, price) VALUES (?, ?, ?)', (name, description, price))
    conn.commit()


#!/usr/bin/python3.6
# -*- coding: utf-8 -*-
'''
Задание 17.2

Создать функцию parse_sh_cdp_neighbors, которая обрабатывает
вывод команды show cdp neighbors.

Функция ожидает, как аргумент, вывод команды одной строкой (не имя файла).
Функция должна возвращать словарь, который описывает соединения между устройствами.

Например, если как аргумент был передан такой вывод:
R4>show cdp neighbors

Device ID    Local Intrfce   Holdtme     Capability       Platform    Port ID
R5           Fa 0/1          122           R S I           2811       Fa 0/1
R6           Fa 0/2          143           R S I           2811       Fa 0/0

Функция должна вернуть такой словарь:
{'R4': {'Fa0/1': {'R5': 'Fa0/1'},
        'Fa0/2': {'R6': 'Fa0/0'}}}

При этом интерфейсы могут быть записаны с пробелом Fa 0/0 или без Fa0/0.

Проверить работу функции на содержимом файла sh_cdp_n_sw1.txt
'''

from pprint import pprint
import re

def parse_sh_cdp_neighbors(output):
	output = output.strip().split('\n')
	dev_l2_map = {}
	for line in output:
		if '/' in line:
			r_dev, l_intf_type, l_intf_port, *other, r_intf_type,r_intf_port = line.split()
			dev_l2_map[device_name][l_intf_type + l_intf_port] = {r_dev : r_intf_type + r_intf_port}
			continue

		if 'cdp ne' in line:
			device_name = re.match('(\S+)[#>]',line)[1]
			dev_l2_map[device_name] = {}

	return dev_l2_map

with open ('sh_cdp_n_sw1.txt') as f:
	device_l2_map = parse_sh_cdp_neighbors(f.read())

pprint(device_l2_map)


# coding: utf-8
from django.contrib import admin, messages
from django.contrib.admin.options import TabularInline
# from django.core.exceptions import PermissionDenied
# from django import forms
# from django.template import RequestContext
from django.conf.urls import patterns
from django.shortcuts import render
from django.db.models import Q
# from django.utils import timezone

# from flexselect import FlexSelectWidget

import autocomplete_light
# import autocomplete_light_registry
import string

from protocolle.core.models import Status
from protocolle.auxiliar.models import Instituicao_User
from protocolle.protocolo.models import (Documento, DocumentoAnexo, Tramite,
                                         Tramite_Documento)

# import barcode
# from barcode.writer import ImageWriter

# from django.forms.widgets import HiddenInput

def get_superuser(request):
    return request.user.is_superuser

def get_instituicao_user(user):
    iu = Instituicao_User.objects.get(user_id=user)
    return iu

def get_status_id(status):
    s = Status.objects.get(nome=status)
    return s.pk

def atualiza_protocolo_num(self, request, queryset):
    """Corrige bug do ano no numero do protocolo"""
    for obj in queryset:
        obj.protocolo = string.replace(obj.protocolo, '2015', '2016')
        obj.save()
atualiza_protocolo_num.short_description = 'Atualiza Número do Protocolo'

def arquivar_doc(self, request, queryset):
    """
    Antes de arquivar o documento o sistema verifica se existe algum tramite
    para o documento
    - se existir: sera verificado se o ultimo destino do
    documento no tramite e igual a insituicao do usuario
    - se nao existir: sera verificado se o destino no cadastro do
    documento e igual a instituicao do usuario
    """
    for obj in queryset:
        iu = Instituicao_User.objects.get(user_id=request.user.pk)
        # print "doc id: %s" % obj.pk

        try:
            # se existir tramite
            td = Tramite_Documento.objects.filter(
                protocolo_id=obj.pk).order_by('-id')[0]
            # print "prot id: %s" % td.protocolo_id
            # print "tram id: %s" % td.tramite_id
            t = Tramite.objects.get(id=td.tramite_id)
            # print "tram dest: %s" % t.destino
            # print "inst user: %s" % iu.instituicao
            destiny = t.destino_id
            # print "try: %s" % destiny

        except:
            # se nao existir tramite
            destiny = obj.destino_id
            # print "except: %s" % destiny

        if iu.instituicao_id == destiny:
            if obj.status_id == get_status_id('Tramitando') \
               or obj.status_id == get_status_id('Parado'):
                queryset.update(status=get_status_id('Arquivado'))
                messages.success(request, 'O Documento foi arquivado com \
                                 sucesso.')
            else:
                messages.error(request, 'O Documento não está tramitando ou \
                               parado.')
        else:
            messages.error(request, 'O Documento não está nesta instituição.')
            arquivar_doc.short_description = "Arquivar documento"

def desarquivar_doc(self, request, queryset):
    """
    Antes de desarquivar o documento o sistema verifica se existe algum tramite
    para o documento
    - se existir: sera verificado se o ultimo destino do
    documento no tramite e igual a insituicao do usuario e
    o status sera alterado para 'Tramitando'
    - se nao existir: sera verificado se o destino no cadastro do
    documento e igual a instituicao do usuario e
    o status sera alterado para 'Parado'
    """
    for obj in queryset:
        iu = Instituicao_User.objects.get(user_id=request.user.pk)

        try:
            # se existir tramite
            td = Tramite_Documento.objects.filter(
                protocolo_id=obj.pk).order_by('-id')[0]
            t = Tramite.objects.get(id=td.tramite_id)
            destiny = t.destino_id

        except:
            # se nao existir tramite
            destiny = obj.destino_id

        if iu.instituicao_id == destiny:
            if obj.status_id == get_status_id('Arquivado'):
                if Tramite_Documento.objects.filter(protocolo_id=obj.pk):
                    # se existir tramite
                    sta = 'Tramitando'
                else:
                    # se nao existir tramite
                    sta = 'Parado'
                    queryset.update(status=get_status_id(sta))
                    messages.success(request, 'O Documento foi desarquivado com \
                                     sucesso.')
            else:
                messages.error(request, 'O Documento não está arquivado.')
        else:
            messages.error(request, 'O Documento não está arquivado nesta \
                           instituição.')
            desarquivar_doc.short_description = "Desarquivar documento"

def entregar_doc(self, request, queryset):
    for obj in queryset:
        iu = Instituicao_User.objects.get(user_id=request.user.pk)

        try:
            # se existir tramite
            td = Tramite_Documento.objects.filter(
                protocolo_id=obj.pk).order_by('-id')[0]
            t = Tramite.objects.get(id=td.tramite_id)
            destiny = t.destino_id

        except:
            # se nao existir tramite
            destiny = obj.destino_id

        if not iu.instituicao_id == destiny:
            if obj.status_id == get_status_id('Tramitando') \
               or obj.status_id == get_status_id('Parado'):
                queryset.update(status=get_status_id('Entregue'))
                messages.success(request, 'O Documento foi entregue com \
                                 sucesso.')
            else:
                messages.error(request, 'O Documento não está tramitando ou \
                               parado.')
        else:
            messages.error(request, 'O Documento está nesta instituição, \
                           então você deve arquivá-lo.')
            entregar_doc.short_description = "Documento Entregue"

class DocumentoAnexoInline(TabularInline):
    model = DocumentoAnexo
    fields = ('arquivo',)
    extra = 1

class DocumentoAdmin(admin.ModelAdmin):
    readonly_fields = ('status', 'protocolo',)
    list_per_page = 15
    list_filter = ('tipo_documento', 'carater', 'natureza', 'origem',
                   'destino', 'interessado', 'status')
    list_display = ('get_protocolo', 'get_data_recebimento', 'tipo_documento',
                    'numero', 'truncate_origem', 'truncate_remetente',
                    'status', 'operacao', 'get_anexos',
                    'action_link')
    search_fields = ('data_recebimento', 'protocolo',
                     'tipo_documento__nome', 'numero', 'carater__nome',
                     'natureza__nome', 'origem__nome', 'interessado__nome',
                     'status__nome', 'data_documento', 'data_validade',
                     'destino__nome', 'assunto', 'observacao')
    fieldsets = (
        (None, {
            'fields': (('operacao', 'protocolo', 'status'),
                       ('tipo_documento', 'numero'),
                       ('data_documento', 'data_validade', 'folhas'),
                       ('carater', 'natureza'), 'origem', 'assunto',
                       'interessado', 'observacao')
        }),
    )
    date_hierarchy = 'data_recebimento'
    raw_id_fields = ('origem', 'destino', 'interessado')

    autocomplete_lookup_fields = {
        'fk': ['origem', 'destino', 'interessado'],
    }

    inlines = [DocumentoAnexoInline]

    actions = [arquivar_doc, desarquivar_doc, entregar_doc]

    def save_model(self, request, obj, form, change):
        """
        Salva automaticamente o destino do documento igual a instituicao do
        usuario
        """
        iu = Instituicao_User.objects.get(user=request.user)
        obj.destino = iu.instituicao
        obj.save()

        if not obj.origem == iu.instituicao and obj.destino == iu.instituicao:
            messages.info(request, 'Não esqueça de arquivar o documento, \
                          caso não se faça nescessário uma tramitação.')
        else:
            messages.info(request, 'Não esqueça de atualizar o status do \
                          Documento.')

    def has_change_permission(self, request, obj=None):
        """
        Bloquear a edicao de documentos que estao com status diferente
        de 'Parado'
        E testa se é super usuário
        """
        if obj is not None and obj.status_id != get_status_id('Parado'):
            if not request.user.is_superuser:
                return False
            else:
                return True
        return super(DocumentoAdmin,
                     self).has_change_permission(request, obj=obj)

    # def get_list_display_links(self, request, list_display):
    #     """
    #     Remover link para edicao na lista
    #     """
    #     return []

    def get_actions(self, request):
        """
        Remover a acao de deletar na lista
        """
        actions = super(DocumentoAdmin, self).get_actions(request)
        # if request.user.username[0].upper() != 'J':
        if 'delete_selected' in actions:
            del actions['delete_selected']
            return actions

    def action_link(self, obj):
        """
        Adicionar os botoes de acao apenas nos documentos com status igual
        a 'Parado'
        """
        # app_name = obj._meta.app_label
        # url_name = obj._meta.module_name
        # data_id = obj.id

        action_buttons = """

        Editar
        Deletar

        """.format(obj._meta.app_label,
                   obj._meta.module_name,
                   obj.id,)

        if obj.status_id == get_status_id('Parado'):
            return action_buttons
        else:
            return ""
    action_link.allow_tags = True
    action_link.short_description = 'Ações'

    def get_protocolo(self, obj):
        if not obj.status_id == get_status_id('Parado'):
            return "%s" % obj.protocolo
        else:
            return obj.protocolo
    get_protocolo.allow_tags = True
    get_protocolo.short_description = 'Protocolo'
    get_protocolo.admin_order_field = 'protocolo'

    def get_data_recebimento(self, obj):
        # data_recebimento = timezone.localtime(obj.data_recebimento)
        data_recebimento = obj.data_recebimento
        return data_recebimento.strftime('%d/%m/%Y %H:%M')
    get_data_recebimento.allow_tags = True
    get_data_recebimento.short_description = 'Data do Recebimento'
    get_data_recebimento.admin_order_field = 'data_recebimento'

    def truncate_origem(self, obj):
        text = str(obj.origem).decode('utf8')
        return (text[:30] + '...') if len(text) > 30 else text
    truncate_origem.short_description = 'Instituição de Origem'
    truncate_origem.admin_order_field = 'origem'

    def truncate_destino(self, obj):
        text = str(obj.destino).decode('utf8')
        return (text[:30] + '...') if len(text) > 30 else text
    truncate_destino.short_description = 'Instituição de Destino'
    truncate_destino.admin_order_field = 'destino'

    def truncate_remetente(self, obj):
        text = str(obj.interessado).decode('utf8')
        return (text[:30] + '...') if len(text) > 30 else text
    truncate_remetente.short_description = 'Remetente'
    truncate_remetente.admin_order_field = 'interessado'

    def queryset(self, request):
        """
        filtra os documentos com destino igual ao do usuario ou
        documentos com tramite para para a instituicao do usuario
        """
        qs = super(DocumentoAdmin, self).queryset(request)
        if request.user.is_superuser:
            return qs
        # pega a insittuicao do usuario
        iu = Instituicao_User.objects.get(user=request.user)

        try:
            # busca os tramites relacionados a insituicao do usuario
            t = Tramite.objects.filter(
                Q(origem_id=iu.instituicao) | Q(destino_id=iu.instituicao)
            ).order_by('-id')
            # busca os documentos relacionados aos tramites
            td = Tramite_Documento.objects.filter(tramite=t).order_by('-id')

            return qs.filter(
                Q(origem_id=iu.instituicao) |
                Q(destino_id=iu.instituicao) |
                Q(pk__in=td.all().values('protocolo_id')))
        except:
            return qs.filter(
                Q(origem_id=iu.instituicao) |
                Q(destino_id=iu.instituicao))

class Tramite_DocumentoInline(admin.TabularInline):
    model = Tramite_Documento
    extra = 1
    form = autocomplete_light.modelform_factory(Tramite_Documento)
    # sortable_field_name = "order"
    fields = ['protocolo', 'folhas']

# class TramiteAdminForm(forms.ModelForm):
#     """
#     Funcao para filtrar os documentos com status diferente de 'Arquivado'
#     Nao funciona com o m2m do grappelli, por conta do raw_id_fields
#     Essa eh outra forma de fazer (mais intrusiva) criando um FormModel
#     """
#     protocolo = forms.ModelMultipleChoiceField(Documento.objects.all(),
#         widget=autocomplete_light.MultipleChoiceWidget(
#             'DocumentoAutocomplete'))

#     class Meta:
#         model = Tramite

#         widget = {
#             'protocolo': autocomplete_light.ChoiceWidget(
#                 'DocumentoAutocomplete')
#         }

#     def __init__(self, *args, **kwargs):
#         super(TramiteAdminForm, self).__init__(*args, **kwargs)
#         self.fields['protocolo'].queryset = Documento.objects.exclude(
#             status__nome='Arquivado')

# Funcao para customizar o widget m2m
# Mas nao deu certo!
#         super(TramiteAdminForm, self).__init__(*args, **kwargs)
#         wtf = Documento.objects.exclude(status__nome='Arquivado')
#         w = self.fields['protocolo'].widget
#         choices = []
#         for choice in wtf:
#             choices.append((choice.tipo_documento, choice.protocolo))
#         w.choices = choices

class TramiteAdmin(admin.ModelAdmin):
    list_filter = ('origem', 'origem_setor', 'destino', 'destino_setor')
    list_per_page = 15
    list_display = ('get_numero_guia', 'get_data_tramite', 'truncate_origem',
                    'truncate_origem_setor', 'truncate_destino',
                    'truncate_destino_setor', 'get_documentos', 'action_link')
    search_fields = ('id', 'data_tramite', 'origem__nome',
                     'origem_setor__nome', 'destino__nome',
                     'destino_setor__nome', 'protocolo__protocolo',)
    date_hierarchy = 'data_tramite'
    # filter_horizontal = ('protocolo',)
    raw_id_fields = ('origem', 'origem_setor', 'destino', 'destino_setor',)
    # 'protocolo',)

    # related_lookup_fields = {
    autocomplete_lookup_fields = {
        'fk': ['origem', 'origem_setor', 'destino', 'destino_setor'],
        # 'm2m': ['protocolo'],
    }

    # form = TramiteAdminForm
    form = autocomplete_light.modelform_factory(Tramite)

    inlines = [Tramite_DocumentoInline]

    # change_list_template = "admin/protocolle/change_list.html"
    # change_list_template = "admin/change_list_filter_sidebar.html"
    # review_template = 'admin/protocolo/detail_view.html'

    # def get_queryset(self):
    #     qs = self.model._default_manager.get_queryset()
    #     # try to find model admin queryset
    #     model_admin = self.GET.get("TramiteAdmin", None)
    #     if model_admin:
    #         module, classname = model_admin.split(",")
    #         ma = import_from(module, classname)
    #         # FIXME: we are not using the admin_site here, do we need it?
    #         qs = ma(self.model, None).get_queryset(self.request)
    #     qs = self.get_filtered_queryset(qs)
    #     print qs
    #     return qs

    # Funcao para filtrar os documentos com status diferente de 'Arquivado'
    # Nao funciona com o m2m do grappelli, por conta do raw_id_fields
    # def formfield_for_manytomany(self, db_field, request, **kwargs):
    #     print db_field.name
    #     if db_field.name == "protocolo":
    #         kwargs["queryset"] = Documento.objects.exclude(
    #             status__nome='Arquivado')
    #     return super(TramiteAdmin, self).formfield_for_manytomany(
    #         db_field, request, **kwargs)

    def has_change_permission(self, request, obj=None):
        """
        Bloquear a edicao de tramite
        E testa se é super usuário
        """
        if obj is not None:
            if not request.user.is_superuser:
                return False
            else:
                return True
        return super(TramiteAdmin,
                     self).has_change_permission(request, obj=obj)

    def get_urls(self):
        urls = super(TramiteAdmin, self).get_urls()
        my_urls = patterns(
            '',
            (r'(?P<id>[\d\+]+)/guia/$',
             self.admin_site.admin_view(self.guia)),
            (r'(?P<id>[\d\+]+)/etiqueta/$',
             self.admin_site.admin_view(self.etiqueta)),
        )
        return my_urls + urls

    def guia(self, request, id):
        tramite = Tramite.objects.get(pk=id)
        zero_id = '%08d' % (tramite.pk,)

        # EAN = barcode.get_barcode('Code39')
        # ean = EAN(zero_id)

        # ean = barcode.get('Code39',
        #                   zero_id,
        #                   writer=ImageWriter())
        # filename = ean.save('protocolle/core/static/ean13')

        # tramite_documento = tramite_documento.objects.get(pk=id)
        context = {
            'title': 'Review Tramite: %s' % tramite.data_tramite,
            'tramite': tramite,
            # 'codigo': filename.replace('protocolle/core', ''),
            'codigo_zero': zero_id,
            'instituicao': get_instituicao_user(request.user.pk)

            # 'opts': self.model._meta,
            # 'root_path': self.admin_site.root_path,
        }

        return render(request, 'protocolo/guia.html', context)

    def etiqueta(self, request, id):
        tramite = Tramite.objects.get(pk=id)
        zero_id = '%08d' % tramite.pk

        # EAN = barcode.get_barcode('Code39')
        # ean = EAN(zero_id)

        # ean = barcode.get('Code39',
        #                   zero_id,
        #                   writer=ImageWriter())
        # filename = ean.save('protocolle/core/static/ean13')

        # tramite_documento = tramite_documento.objects.get(pk=id)
        context = {
            'title': 'Review Tramite: %s' % tramite.data_tramite,
            'tramite': tramite,
            # 'codigo': filename.replace('protocolle/core', ''),
            'codigo_zero': zero_id,
            'instituicao': get_instituicao_user(request.user.pk)

            # 'opts': self.model._meta,
            # 'root_path': self.admin_site.root_path,
        }

        return render(request, 'protocolo/etiqueta.html', context)

    def action_link(self, obj):
        # app_name = obj._meta.app_label
        # url_name = obj._meta.module_name
        # data_id = obj.id

        # Editar
        return """

    Guia
     \
            Etiqueta
    Deletar

    """.format(obj._meta.app_label,
               obj._meta.module_name,
               obj.id,)
    action_link.allow_tags = True
    action_link.short_description = 'Ações'

    def get_numero_guia(self, obj):
        return '%08d' % obj.id
    get_numero_guia.allow_tags = True
    get_numero_guia.short_description = 'N. da Guia'
    get_numero_guia.admin_order_field = 'pk'

    def get_data_tramite(self, obj):
        # data_tramite = timezone.localtime(obj.data_tramite)
        data_tramite = obj.data_tramite
        return data_tramite.strftime('%d/%m/%Y %H:%M')
    get_data_tramite.allow_tags = True
    get_data_tramite.short_description = 'Data do Trâmite'
    get_data_tramite.admin_order_field = 'data_tramite'

    def truncate_origem(self, obj):
        text = str(obj.origem).decode('utf8')
        return (text[:30] + '...') if len(text) > 30 else text
    truncate_origem.short_description = 'Instituição de Origem'
    truncate_origem.admin_order_field = 'origem'

    def truncate_destino(self, obj):
        text = str(obj.destino).decode('utf8')
        return (text[:30] + '...') if len(text) > 30 else text
    truncate_destino.short_description = 'Instituição de Destino'
    truncate_destino.admin_order_field = 'destino'

    def truncate_origem_setor(self, obj):
        text = str(obj.origem_setor).decode('utf8')
        return (text[:30] + '...') if len(text) > 30 else text
    truncate_origem_setor.short_description = 'Setor Origem'
    truncate_origem_setor.admin_order_field = 'origem_setor'

    def truncate_destino_setor(self, obj):
        text = str(obj.destino_setor).decode('utf8')
        return (text[:30] + '...') if len(text) > 30 else text
    truncate_destino_setor.short_description = 'Setor Destino'
    truncate_destino_setor.admin_order_field = 'destino_setor'

    def queryset(self, request):
        """
        Filtrar apenas os tramites que o usuario esta envolvido, seja como
        origem ou como destino
        """
        qs = super(TramiteAdmin, self).queryset(request)
        if request.user.is_superuser:
            return qs
        # pega a instituicao do usuario
        iu = Instituicao_User.objects.get(user=request.user)
        # faz o filtro por qualquer relacionamento da insituicao com o tramite
        return qs.filter(Q(origem_id=iu.instituicao) |
                         Q(destino_id=iu.instituicao))

    # def action(self,form):
    #   return "view" % (form.id)
    # action.allow_tags = True

admin.site.register(Tramite, TramiteAdmin)
admin.site.register(Documento, DocumentoAdmin)


import time
from datetime import datetime as dt

# Had to import a few modules for this program to work.

hostsTemp = "hosts"
hostsPath = r"C:/Windows/System32/drivers/etc/hosts"
redirect = "127.0.0.1"
websiteList = ["www.facebook.com", "facebook.com"]

# Set up the hostsPath variable equal to the specific directory of the hosts file contained inside the System32 file. Set up my redirect variable equal to the IP address I want to redirect the user to when they try to access a blocked website. Set up my websiteLists as a list variable, where all blocked domains should be put. websiteLists and redirect will work together to "block" users from accessing certain websites.

# 8 and 15 reflect a normal school day schedule from 8:00 A.M. to 3:00 P.M.
# You can change it by just changing the two integers below to your school or work day schedule.

while True:
  if dt(dt.now().year,dt.now().month,dt.now().day,8) < dt.now() < dt(dt.now().year,dt.now().month,dt.now().day,15):
    print("School time...")
    with open(hostsPath,'r+') as file:
      content = file.read()
      for website in websiteList:
        if website in content:
          pass
        else:
          file.write(redirect+ " " + website + "\n")
  else:
    with open(hostsPath, 'r+') as file:
      content= file.readlines()
      file.seek(0)
      for line in content:
        if not any(website in line for website in websiteList):
          file.write(line)
      file.truncate()
    print("Leisure time...")
  time.sleep(5)

# Purpose of the while loop is pretty simple. It will check the time to see if it is a specified time at the moment or not. If it, it will keep the lines of code inside the hosts file, blocking the websites listed. If not, it will remove those lines from the hosts file, allowing the user to access any "blocked" websites.

# It should be noted that in order to access the hosts file, it must be ran through administrator access using a command line with your python program.

# R+ allows me to both read and write the hosts file under the hostsPath variable.

# readlines will produce a list with all the lines in the hosts file. Each line will be its own string.

# The if not any "loop" will check each item, or the website variable, from the websiteList, against each and every single line in the hosts file, checking if it is there or not.

# What this does is basically append all the lines of the hosts file EXCEPT the ones with the websites under the websiteList variabe, essentially creating the original hosts file again.

# This if not any "loop" creates a little bit of a messy problem, however. It loops twice and creates two new "blocks" of the same original hosts file. It repeats the original hosts file twice, and we only wanted it to repeat itself once. So we use file.trunate() to delete the second repetition and use file.seek() to put the first repetition above the original code blocking the websites (which still exists).


import matplotlib.pyplot as plt
import random
import pandas as pd
import numpy as np

df = pd.DataFrame()

df['y'] = [random.random() for _ in range(200)]

df['I'] =  [random.random() for _ in range(200)]

df['II'] = df['y']  + ( [random.random()/4 for _ in range(200)] )
df['IIa'] = np.where( df['II'] <1.0, df['II'], df['II']-0.2 )

df['II'] = (1-df['y'])  + ( [random.random()/4 for _ in range(200)] )
df['IIb'] = np.where( df['II'] <1.0, df['II'], df['II']-0.2 )

df['III'] =  np.where( df['IIa'] < 0.5, df['IIa'], 0.5+ (df['I']/2) )

df['IV'] =  np.where( df['y'] > 0.4, np.where( df['y'] < 0.6, 0.5, 0.5+(df['I']/2) ), 0.5-(df['I']/2) )

df['V'] =  df['y']*df['y']  + ( [random.random()/10 for _ in range(200)] )

df['VI'] = np.where( df['I'] < 0.5, 0.5 - (np.sqrt(df['y'])/2) + (df['I']/10 ), 0.5 + (np.sqrt(df['y'])/2) + (df['I']/10 ) )

df['VII'] = np.where( df['y'] < 0.3, 0.5 + pow(df['IIb'], 2)/4 , np.where( df['y'] > 0.7, 0.5+ pow(df['IIa'],2)/4, 0.7 - pow(df['IIa'],3) ) )

###############################
# Create Figure and Subplots

fig, axes = plt.subplots(4,2, figsize=(10,8), sharex=True, sharey=True, dpi=120)

axes[0,0].scatter(df['I'], df['y'], alpha=0.5)
axes[0,0].set_title('1 - Random')

axes[0,1].scatter(df['IIa'], df['y'], alpha=0.5)
axes[0,1].set_title('2a - Linear Correlation')

axes[1,0].scatter(df['IIb'], df['y'], alpha=0.5)
axes[1,0].set_title('2b - Linear Anticorrelation')

axes[1,1].scatter(df['III'], df['y'], alpha=0.5)
axes[1,1].set_title('3 - Partial Linear Correlation')

axes[2,0].scatter(df['IV'], df['y'], alpha=0.5)
axes[2,0].set_title('4 - Step Function')

axes[2,1].scatter(df['V'], df['y'], alpha=0.5)
axes[2,1].set_title('5 - Nonlinear Monotonic')

axes[3,0].scatter(df['VI'], df['y'], alpha=0.5)
axes[3,0].set_title('6 - Nonlinear Nonmonotonic')

axes[3,1].scatter(df['VII'], df['y'], alpha=0.5)
axes[3,1].set_title('7 - Nonbijective')

#plt.savefig('univariate_relationships.svg', format='svg', dpi=300)
plt.savefig('univariate_relationships.png',  dpi=300)
#plt.savefig('univariate_relationships.eps', format='eps')


file1 = open("file1.txt","r")
a = set()#
for line in file1:
    s = ""
    for c in line.strip():
        if c.lower() in "abcdefghijklmnopqrstuvwxyz":
            s += c.lower()
        else:
            s += ' '
    line = s.split()
    a.update(line)

file2 = open("file2.txt","r")
b = set()
for line in file2:
    s = ""
    for c in line.strip():
        if c.lower() in "abcdefghijklmnopqrstuvwxyz":
            s += c.lower()
        else:
            s += ' '
    line = s.split()
    b.update(line)

word = input().strip().lower()
if word in a and word in b:
    print("Found in both files")
elif word in a and word not in b:
    print("Found in file1 only")
elif word not in a and word in b:
    print("Found in file2 only")
else:
    print("Not found")


# Faça um Programa que leia um vetor de 10 caracteres, e diga quantas consoantes foram lidas. Imprima as consoantes.
from ast import Not

caract = list(input("insira os caracteres: ") for x in range(10))
conso = list()
vogais = ["A", "E", "I", "O", "U"]
cont = 0
for x in range(len(caract)):
    if caract[x].upper() not in vogais:
        conso.insert(1, caract[x])
        cont += 1
print("as consoantes digitadas ",conso)
print("o total de consoantes e ", cont)


import math

def test_of_frequency(nums_array):
  s=0
  for x in nums_array:
    if x==1: s+=1 #add 1 to s for every 1 bit in list of numbers
    else: s-=1  #subtract 1 to s for every 0 bit in list of numbers

  n= len(nums_array) # number of pseudo random numbers generated
  sqrt_n = math.sqrt(n)
  s_observed= abs(s)/sqrt_n # calculate absolute value of observed sum divided by square root of n

  p_value= math.erfc(s_observed/math.sqrt(2)) # calculate P-value using error function

  if p_value<0.01:
    print(f"The sequence does not appear random in FREQUENCY TEST since p-value : {p_value} < 0.01.") # if P-value if less than 0.01 then sequence is not random
  else:
    print(f"The sequence appears random FREQUENCY TEST since p-value : {p_value} >= 0.01.") # if P-value if more than 0.01 then sequence is random

def test_of_runs(nums_array):
  num = len(nums_array)  # size of the array of of pseudo random numbers

  # Calculate the number of runs in the list
  rhuns=0
  for i in range(num-1):
    if nums_array[i]!=nums_array[i+1]: rhuns+=1

  # Calculate the fraction of 1's in the bit list
  frac=0
  for x in nums_array:
    if x==1: frac+=1
  frac/=num

  numrtr= abs(rhuns-2*num*frac*(1-frac))  # |runs-2Nfrac(1-frac)|
  denotr= 2*math.sqrt(2*num)*frac*(1-frac) # (2*sqrt(2N)*frac(1-frac))

  p_value= math.erfc(numrtr/denotr) # p_value = erfc(|V_N(obs)-2Nπ(1-π)|/(2*sqrt(2N)*π(1-π)))

  if p_value<0.01:
    print(f"The sequence does not appear random in RUNS TEST since p-value : {p_value} < 0.01. ") # if P-value if less than 0.01 then sequence is not random
  else:
    print(f"The sequence appears random in RUNS TEST since p-value : {p_value} >= 0.01. ") # if P-value if more than 0.01 then sequence is random