import copy
from firewall.core.base import SHORTCUTS, DEFAULT_ZONE_TARGET, SOURCE_IPSET_TYPES
from firewall.core.fw_transaction import FirewallTransaction
from firewall.core.io.policy import Policy
from firewall.core.logger import log
from firewall.core.rich import (
    Rich_ForwardPort,
    Rich_IcmpBlock,
    Rich_IcmpType,
    Rich_Mark,
    Rich_Masquerade,
    Rich_Port,
    Rich_Protocol,
    Rich_Rule,
    Rich_Service,
    Rich_SourcePort,
    Rich_Tcp_Mss_Clamp
)
from firewall.core.fw_nm import nm_get_bus_name
from firewall.functions import checkIPnMask, checkIP6nMask, check_mac
from firewall import errors
from firewall.errors import FirewallError

class FirewallZone:
    ZONE_POLICY_PRIORITY = 0

    def __init__(self, fw):
        self._fw = fw
        self._zones = { }
        self._zone_policies = { }

    def __repr__(self):
        return '%s(%r)' % (self.__class__, self._zones)

    def cleanup(self):
        self._zones.clear()
        self._zone_policies.clear()

    def new_transaction(self):
        t = FirewallTransaction(self._fw)
        t.add_pre(self._fw.full_check_config)
        return t

    def policy_name_from_zones(self, fromZone, toZone):
        return "zone_{fromZone}_{toZone}".format(fromZone=fromZone, toZone=toZone)

    # zones

    def get_zones(self):
        return sorted(self._zones.keys())

    def get_active_zones(self, append_default=True):
        active_zones = []
        for zone in self.get_zones():
            if self.list_interfaces(zone) or self.list_sources(zone):
                active_zones.append(zone)
        if append_default and self._fw._default_zone not in active_zones:
            active_zones.append(self._fw._default_zone)
        return active_zones

    def get_zone_of_interface(self, interface):
        interface_id = self.__interface_id(interface)
        for zone in self._zones:
            if interface_id in self._zones[zone].interfaces:
                # an interface can only be part of one zone
                return zone
        return None

    def get_zone_of_source(self, source):
        source_id = self.__source_id(source)
        for zone in self._zones:
            if source_id in self._zones[zone].sources:
                # a source_id can only be part of one zone
                return zone
        return None

    def get_zone(self, zone):
        z = self._fw.check_zone(zone)
        return self._zones[z]

    def policy_obj_from_zone_obj(self, z_obj, fromZone, toZone):
        p_obj = Policy()
        p_obj.derived_from_zone = z_obj.name
        p_obj.name = self.policy_name_from_zones(fromZone, toZone)
        p_obj.priority = self.ZONE_POLICY_PRIORITY
        p_obj.target = z_obj.target
        p_obj.ingress_zones = [fromZone]
        p_obj.egress_zones = [toZone]

        # copy zone permanent config to policy permanent config
        # WARN: This assumes the same attribute names.
        #
        for setting in ["services", "ports",
                        "masquerade", "forward_ports",
                        "source_ports",
                        "icmp_blocks", "icmp_block_inversion",
                        "rules_str", "protocols"]:
            if fromZone == z_obj.name and toZone == "HOST" and \
               setting in ["services", "ports", "source_ports", "icmp_blocks",
                           "icmp_block_inversion", "protocols"]:
                # zone --> HOST
                setattr(p_obj, setting, copy.deepcopy(getattr(z_obj, setting)))
            elif fromZone == "ANY" and toZone == z_obj.name and setting in ["masquerade"]:
                # any zone --> zone
                setattr(p_obj, setting, copy.deepcopy(getattr(z_obj, setting)))
            elif fromZone == z_obj.name and toZone == "ANY" and \
                 setting in ["forward_ports"]:
                # zone --> any zone
                setattr(p_obj, setting, copy.deepcopy(getattr(z_obj, setting)))
            elif setting in ["rules_str"]:
                p_obj.rules_str = []
                p_obj.rules = []
                for rule_str in z_obj.rules_str:
                    current_policy = self.policy_name_from_zones(fromZone, toZone)

                    rule = Rich_Rule(rule_str=rule_str)
                    if current_policy in self._rich_rule_to_policies(z_obj.name, rule):
                        p_obj.rules_str.append(rule_str)
                        p_obj.rules.append(rule)

        return p_obj

    def add_zone(self, obj):
        self._zones[obj.name] = obj
        self._zone_policies[obj.name] = []

        # Create policy objects, will need many:
        #   - (zone --> HOST) - ports, service, etc
        #   - (HOST --> zone) - tracking only, no zone features
        #   - (any zone --> zone) - masquerade
        #   - (zone --> any zone)
        #       - also includes forward-ports because it works on (nat,
        #       PREROUTING) and therefore applies to redirects to the local
        #       host or dnat to a different host.
        #       - also includes rich rule "mark" action for the same reason
        #
        for fromZone,toZone in [(obj.name, "HOST"), ("HOST", obj.name),
                                ("ANY", obj.name), (obj.name, "ANY")]:
            p_obj = self.policy_obj_from_zone_obj(obj, fromZone, toZone)
            self._fw.policy.add_policy(p_obj)
            self._zone_policies[obj.name].append(p_obj.name)

    def remove_zone(self, zone):
        obj = self._zones[zone]
        if obj.applied:
            self.unapply_zone_settings(zone)
        del self._zones[zone]
        del self._zone_policies[zone]

    def apply_zones(self, use_transaction=None):
        for zone in self.get_zones():
            z_obj = self._zones[zone]
            if len(z_obj.interfaces) > 0 or len(z_obj.sources) > 0:
                log.debug1("Applying zone '%s'", zone)
                self.apply_zone_settings(zone, use_transaction=use_transaction)

    def set_zone_applied(self, zone, applied):
        obj = self._zones[zone]
        obj.applied = applied

    # zone from chain

    def zone_from_chain(self, chain):
        if "_" not in chain:
            # no zone chain
            return None
        splits = chain.split("_")
        if len(splits) < 2:
            return None
        _chain = None
        for x in SHORTCUTS:
            if splits[0] == SHORTCUTS[x]:
                _chain = x
        if _chain is not None:
            # next part needs to be zone name
            if splits[1] not in self.get_zones():
                return None
            if len(splits) == 2 or \
               (len(splits) == 3 and splits[2] in [ "pre", "log", "deny", "allow", "post" ]):
                return (splits[1], _chain)
        return None

    def policy_from_chain(self, chain):
        x = self.zone_from_chain(chain)
        if x is None:
            return None

        (zone, _chain) = x
        # derived from _get_table_chains_for_zone_dispatch()
        if _chain in ["PREROUTING", "FORWARD"]:
            fromZone = zone
            toZone = "ANY"
        elif _chain in ["INPUT"]:
            fromZone = zone
            toZone = "HOST"
        elif _chain in ["POSTROUTING"]:
            fromZone = "ANY"
            toZone = zone
        else:
            raise FirewallError(errors.INVALID_CHAIN, "chain '%s' can't be mapped to a policy" % (chain))

        return (self.policy_name_from_zones(fromZone, toZone), _chain)

    def create_zone_base_by_chain(self, ipv, table, chain,
                                  use_transaction=None):

        # Create zone base chains if the chain is reserved for a zone
        if ipv in [ "ipv4", "ipv6" ]:
            x = self.policy_from_chain(chain)
            if x is not None:
                (policy, _chain) = self.policy_from_chain(chain)
                if use_transaction is None:
                    transaction = self.new_transaction()
                else:
                    transaction = use_transaction

                self._fw.policy.gen_chain_rules(policy, True, table, _chain,
                                                transaction)

                if use_transaction is None:
                    transaction.execute(True)

    def _zone_settings(self, enable, zone, transaction):
        for key in ["interfaces", "sources", "forward", "icmp_block_inversion"]:
            args_list = getattr(self.get_zone(zone), key)
            if isinstance(args_list, bool):
                args_list = [args_list]
            for args in args_list:
                if key == "interfaces":
                    self._interface(enable, zone, args, transaction)
                elif key == "sources":
                    ipv = self.check_source(args)
                    self._source(enable, zone, ipv, args, transaction)
                elif key == "icmp_block_inversion":
                    continue
                elif key in ["forward", "ingress_priority", "egress_priority"]:
                    # no need to call this when applying the zone as the rules
                    # will be generated when adding the interfaces/sources
                    pass
                else:
                    log.warning("Zone '%s': Unknown setting '%s:%s', "
                                "unable to apply", zone, key, args)
        # ICMP-block-inversion is always applied
        if enable:
            self._icmp_block_inversion(enable, zone, transaction)

    def apply_zone_settings(self, zone, use_transaction=None):
        _zone = self._fw.check_zone(zone)
        obj = self._zones[_zone]
        if obj.applied:
            return
        obj.applied = True

        if use_transaction is None:
            transaction = self.new_transaction()
        else:
            transaction = use_transaction

        for policy in self._zone_policies[_zone]:
            log.debug1("Applying policy (%s) derived from zone '%s'", policy, zone)
            self._fw.policy.apply_policy_settings(policy, use_transaction=transaction)

        self._zone_settings(True, _zone, transaction)

        if use_transaction is None:
            transaction.execute(True)

    def unapply_zone_settings(self, zone, use_transaction=None):
        _zone = self._fw.check_zone(zone)
        obj = self._zones[_zone]
        if not obj.applied:
            return

        if use_transaction is None:
            transaction = self.new_transaction()
        else:
            transaction = use_transaction

        for policy in self._zone_policies[_zone]:
            self._fw.policy.unapply_policy_settings(policy, use_transaction=transaction)

        self._zone_settings(False, _zone, transaction)

        if use_transaction is None:
            transaction.execute(True)

    def get_config_with_settings(self, zone):
        """
        :return: exported config updated with runtime settings
        """
        obj = self.get_zone(zone)
        conf_dict = self.get_config_with_settings_dict(zone)
        conf_list = []
        for i in range(16): # tuple based API has 16 elements
            if obj.IMPORT_EXPORT_STRUCTURE[i][0] not in conf_dict:
                # old API needs the empty elements as well. Grab it from the
                # class otherwise we don't know the type.
                conf_list.append(copy.deepcopy(getattr(obj, obj.IMPORT_EXPORT_STRUCTURE[i][0])))
            else:
                conf_list.append(conf_dict[obj.IMPORT_EXPORT_STRUCTURE[i][0]])
        return tuple(conf_list)

    def get_config_with_settings_dict(self, zone):
        """
        :return: exported config updated with runtime settings
        """
        permanent = self.get_zone(zone).export_config_dict()
        if permanent["target"] == DEFAULT_ZONE_TARGET:
            permanent["target"] = "default"
        runtime = { "services": self.list_services(zone),
                    "ports": self.list_ports(zone),
                    "icmp_blocks": self.list_icmp_blocks(zone),
                    "masquerade": self.query_masquerade(zone),
                    "forward_ports": self.list_forward_ports(zone),
                    "interfaces": self.list_interfaces(zone),
                    "sources": self.list_sources(zone),
                    "rules_str": self.list_rules(zone),
                    "protocols": self.list_protocols(zone),
                    "source_ports": self.list_source_ports(zone),
                    "icmp_block_inversion": self.query_icmp_block_inversion(zone),
                    "forward": self.query_forward(zone),
                    }
        return self._fw.combine_runtime_with_permanent_settings(permanent, runtime)

    def set_config_with_settings_dict(self, zone, settings, sender):
        # stupid wrappers to convert rich rule string to rich rule object
        def add_rule_wrapper(zone, rule_str, timeout=0, sender=None):
            self.add_rule(zone, Rich_Rule(rule_str=rule_str), timeout=0, sender=sender)
        def remove_rule_wrapper(zone, rule_str):
            self.remove_rule(zone, Rich_Rule(rule_str=rule_str))

        setting_to_fn = {
            "services": (self.add_service, self.remove_service),
            "ports": (self.add_port, self.remove_port),
            "icmp_blocks": (self.add_icmp_block, self.remove_icmp_block),
            "masquerade": (self.add_masquerade, self.remove_masquerade),
            "forward_ports": (self.add_forward_port, self.remove_forward_port),
            "interfaces": (self.add_interface, self.remove_interface),
            "sources": (self.add_source, self.remove_source),
            "rules_str": (add_rule_wrapper, remove_rule_wrapper),
            "protocols": (self.add_protocol, self.remove_protocol),
            "source_ports": (self.add_source_port, self.remove_source_port),
            "icmp_block_inversion": (self.add_icmp_block_inversion, self.remove_icmp_block_inversion),
            "forward": (self.add_forward, self.remove_forward),
        }

        # do a full config check on a temporary object before trying to make
        # the runtime changes
        old_obj = self.get_zone(zone)
        check_obj = copy.copy(old_obj)
        check_obj.import_config_dict(settings, self._fw.get_all_io_objects_dict())
        self._fw.full_check_config({"zones": [check_obj]})

        old_settings = self.get_config_with_settings_dict(zone)
        (add_settings, remove_settings) = self._fw.get_added_and_removed_settings(old_settings, settings)

        for key in remove_settings:
            if isinstance(remove_settings[key], list):
                for args in remove_settings[key]:
                    if isinstance(args, tuple):
                        setting_to_fn[key][1](zone, *args)
                    else:
                        setting_to_fn[key][1](zone, args)
            else: # bool
                setting_to_fn[key][1](zone)

        for key in add_settings:
            if isinstance(add_settings[key], list):
                for args in add_settings[key]:
                    if key in ["interfaces", "sources"]:
                        # no timeout arg
                        setting_to_fn[key][0](zone, args, sender=sender)
                    else:
                        if isinstance(args, tuple):
                            setting_to_fn[key][0](zone, *args, timeout=0, sender=sender)
                        else:
                            setting_to_fn[key][0](zone, args, timeout=0, sender=sender)
            else: # bool
                if key in ["icmp_block_inversion"]:
                    # no timeout arg
                    setting_to_fn[key][0](zone, sender=sender)
                else:
                    setting_to_fn[key][0](zone, timeout=0, sender=sender)

    # INTERFACES

    def check_interface(self, interface):
        self._fw.check_interface(interface)

    def __interface_id(self, interface):
        self.check_interface(interface)
        return interface

    def add_interface(self, zone, interface, sender=None,
                      use_transaction=None, allow_apply=True):
        self._fw.check_panic()
        _zone = self._fw.check_zone(zone)
        _obj = self._zones[_zone]

        interface_id = self.__interface_id(interface)

        if interface_id in _obj.interfaces:
            raise FirewallError(errors.ZONE_ALREADY_SET,
                                "'%s' already bound to '%s'" % (interface,
                                                                zone))
        zoi = self.get_zone_of_interface(interface)
        if zoi is not None:
            raise FirewallError(errors.ZONE_CONFLICT,
                                "'%s' already bound to '%s'" % (interface,
                                                                 zoi))

        log.debug1("Setting zone of interface '%s' to '%s'" % (interface,
                                                               _zone))

        if use_transaction is None:
            transaction = self.new_transaction()
        else:
            transaction = use_transaction

        if not _obj.applied and allow_apply:
            self.apply_zone_settings(zone,
                                     use_transaction=transaction)
            transaction.add_fail(self.set_zone_applied, _zone, False)

        if allow_apply:
            self._interface(True, _zone, interface, transaction)

        self.__register_interface(_obj, interface_id, zone, sender)
        transaction.add_fail(self.__unregister_interface, _obj,
                                  interface_id)

        if use_transaction is None:
            transaction.execute(True)

        return _zone

    def __register_interface(self, _obj, interface_id, zone, sender):
        _obj.interfaces.append(interface_id)
        if not zone or zone == "":
            self._fw._default_zone_interfaces.append(interface_id)
        if sender == nm_get_bus_name():
            self._fw._nm_assigned_interfaces.append(interface_id)

    def change_zone_of_interface(self, zone, interface, sender=None):
        self._fw.check_panic()
        _old_zone = self.get_zone_of_interface(interface)
        _new_zone = self._fw.check_zone(zone)

        if _new_zone == _old_zone:
            return _old_zone

        if _old_zone is not None:
            self.remove_interface(_old_zone, interface)

        _zone = self.add_interface(zone, interface, sender)

        return _zone

    def remove_interface(self, zone, interface,
                         use_transaction=None):
        self._fw.check_panic()
        zoi = self.get_zone_of_interface(interface)
        if zoi is None:
            raise FirewallError(errors.UNKNOWN_INTERFACE,
                                "'%s' is not in any zone" % interface)
        _zone = zoi if zone == "" else self._fw.check_zone(zone)
        if zoi != _zone:
            raise FirewallError(errors.ZONE_CONFLICT,
                                "remove_interface(%s, %s): zoi='%s'" % \
                                (zone, interface, zoi))

        if use_transaction is None:
            transaction = self.new_transaction()
        else:
            transaction = use_transaction

        _obj = self._zones[_zone]
        interface_id = self.__interface_id(interface)
        transaction.add_post(self.__unregister_interface, _obj, interface_id)
        self._interface(False, _zone, interface, transaction)

        if use_transaction is None:
            transaction.execute(True)

        return _zone

    def __unregister_interface(self, _obj, interface_id):
        if interface_id in _obj.interfaces:
            _obj.interfaces.remove(interface_id)
        if interface_id in self._fw._default_zone_interfaces:
            self._fw._default_zone_interfaces.remove(interface_id)
        if interface_id in self._fw._nm_assigned_interfaces:
            self._fw._nm_assigned_interfaces.remove(interface_id)

    def query_interface(self, zone, interface):
        return self.__interface_id(interface) in self.get_zone(zone).interfaces

    def list_interfaces(self, zone):
        return self.get_zone(zone).interfaces

    # SOURCES

    def check_source(self, source, applied=False):
        if checkIPnMask(source):
            return "ipv4"
        elif checkIP6nMask(source):
            return "ipv6"
        elif check_mac(source):
            return ""
        elif source.startswith("ipset:"):
            self._check_ipset_type_for_source(source[6:])
            if applied:
                self._check_ipset_applied(source[6:])
            return self._ipset_family(source[6:])
        else:
            raise FirewallError(errors.INVALID_ADDR, source)

    def __source_id(self, source, applied=False):
        self.check_source(source, applied=applied)
        return source

    def add_source(self, zone, source, sender=None, use_transaction=None,
                   allow_apply=True):
        self._fw.check_panic()
        _zone = self._fw.check_zone(zone)
        _obj = self._zones[_zone]

        if check_mac(source):
            source = source.upper()

        ipv = self.check_source(source, applied=allow_apply)
        source_id = self.__source_id(source, applied=allow_apply)

        if source_id in _obj.sources:
            raise FirewallError(errors.ZONE_ALREADY_SET,
                            "'%s' already bound to '%s'" % (source, _zone))
        if self.get_zone_of_source(source) is not None:
            raise FirewallError(errors.ZONE_CONFLICT,
                                "'%s' already bound to a zone" % source)

        if use_transaction is None:
            transaction = self.new_transaction()
        else:
            transaction = use_transaction

        if not _obj.applied and allow_apply:
            self.apply_zone_settings(zone,
                                     use_transaction=transaction)
            transaction.add_fail(self.set_zone_applied, _zone, False)

        if allow_apply:
            self._source(True, _zone, ipv, source_id, transaction)

        self.__register_source(_obj, source_id, zone, sender)
        transaction.add_fail(self.__unregister_source, _obj, source_id)

        if use_transaction is None:
            transaction.execute(True)

        return _zone

    def __register_source(self, _obj, source_id, zone, sender):
        _obj.sources.append(source_id)

    def change_zone_of_source(self, zone, source, sender=None):
        self._fw.check_panic()
        _old_zone = self.get_zone_of_source(source)
        _new_zone = self._fw.check_zone(zone)

        if _new_zone == _old_zone:
            return _old_zone

        if check_mac(source):
            source = source.upper()

        if _old_zone is not None:
            self.remove_source(_old_zone, source)

        _zone = self.add_source(zone, source, sender)

        return _zone

    def remove_source(self, zone, source,
                      use_transaction=None):
        self._fw.check_panic()
        if check_mac(source):
            source = source.upper()
        zos = self.get_zone_of_source(source)
        if zos is None:
            raise FirewallError(errors.UNKNOWN_SOURCE,
                                "'%s' is not in any zone" % source)
        _zone = zos if zone == "" else self._fw.check_zone(zone)
        if zos != _zone:
            raise FirewallError(errors.ZONE_CONFLICT,
                                "remove_source(%s, %s): zos='%s'" % \
                                (zone, source, zos))

        if use_transaction is None:
            transaction = self.new_transaction()
        else:
            transaction = use_transaction

        _obj = self._zones[_zone]
        ipv = self.check_source(source)
        source_id = self.__source_id(source)
        transaction.add_post(self.__unregister_source, _obj, source_id)
        self._source(False, _zone, ipv, source_id, transaction)

        if use_transaction is None:
            transaction.execute(True)

        return _zone

    def __unregister_source(self, _obj, source_id):
        if source_id in _obj.sources:
            _obj.sources.remove(source_id)

    def query_source(self, zone, source):
        if check_mac(source):
            source = source.upper()
        return self.__source_id(source) in self.get_zone(zone).sources

    def list_sources(self, zone):
        return self.get_zone(zone).sources

    def _interface_or_source_update_zone_termination(self, enable, zone, interface, source, transaction):
        self._interface_or_source_update_policies_derived_from_zone(enable, zone, interface, source, transaction, last=True)

    def _interface_or_source_update_policies_derived_from_zone(self, enable, zone, interface, source, transaction, last=False):
        # host <--> zone
        policy = self.policy_name_from_zones(zone, "HOST")
        self._fw.policy._ingress_egress_pair(enable, policy, zone, "HOST",
                                             interface, source, "", "",
                                             transaction, last=last)
        policy = self.policy_name_from_zones("HOST", zone)
        self._fw.policy._ingress_egress_pair(enable, policy, "HOST", zone,
                                             "", "", interface, source,
                                             transaction, last=last)
        # zone <--> zone
        _zoneB_list = set(self.get_active_zones() + [zone]) if interface != "+" else [self._fw._default_zone]
        for _zoneB in _zoneB_list:
            if _zoneB != zone and not self.get_zone(_zoneB).applied:
                continue

            _zoneB_interfaces = list(self.list_interfaces(_zoneB))
            _zoneB_sources = list(self.list_sources(_zoneB))
            if zone == _zoneB and interface and interface not in _zoneB_interfaces:
                # include the interface that's currently being activated
                _zoneB_interfaces.append(interface)
            if zone == _zoneB and source and source not in _zoneB_sources:
                _zoneB_sources.append(source)
            # Need to consider dispatch to the default zone as well.
            if interface == "+":
                _zoneB_interfaces = ["+"]
                _zoneB_sources = []
            elif _zoneB == self._fw._default_zone and "+" not in _zoneB_interfaces:
                _zoneB_interfaces.append("+")

            for _zoneB_interface in _zoneB_interfaces:
                policy = self.policy_name_from_zones(zone, "ANY")
                self._fw.policy._ingress_egress_pair(enable, policy, zone, _zoneB,
                                                     interface, source, _zoneB_interface, "",
                                                     transaction, last=last)
                policy = self.policy_name_from_zones("ANY", zone)
                self._fw.policy._ingress_egress_pair(enable, policy, _zoneB, zone,
                                                     _zoneB_interface, "", interface, source,
                                                     transaction, last=last)
                if interface != _zoneB_interface:
                    policy = self.policy_name_from_zones(_zoneB, "ANY")
                    self._fw.policy._ingress_egress_pair(enable, policy, _zoneB, zone,
                                                         _zoneB_interface, "", interface, source,
                                                         transaction, last=last)
                    policy = self.policy_name_from_zones("ANY", _zoneB)
                    self._fw.policy._ingress_egress_pair(enable, policy, zone, _zoneB,
                                                         interface, source, _zoneB_interface, "",
                                                         transaction, last=last)
            for _zoneB_source in _zoneB_sources:
                # must be same IPv4/IPv6 family!
                if source and self.check_source(source) != self.check_source(_zoneB_source):
                    continue
                policy = self.policy_name_from_zones(zone, "ANY")
                self._fw.policy._ingress_egress_pair(enable, policy, zone, _zoneB,
                                                     interface, source, "", _zoneB_source,
                                                     transaction, last=last)
                policy = self.policy_name_from_zones("ANY", zone)
                self._fw.policy._ingress_egress_pair(enable, policy, _zoneB, zone,
                                                     "", _zoneB_source, interface, source,
                                                     transaction, last=last)
                if source != _zoneB_source:
                    policy = self.policy_name_from_zones(_zoneB, "ANY")
                    self._fw.policy._ingress_egress_pair(enable, policy, _zoneB, zone,
                                                         "", _zoneB_source, interface, source,
                                                         transaction, last=last)
                    policy = self.policy_name_from_zones("ANY", _zoneB)
                    self._fw.policy._ingress_egress_pair(enable, policy, zone, _zoneB,
                                                         interface, source, "", _zoneB_source,
                                                         transaction, last=last)

    def _interface_or_source_update_policies(self, enable, zone, interface, source, transaction):
        # update policy dispatch for any policy using this zone as an
        # ingress-zone or egress-zone
        for policy in self._fw.policy.get_policies_not_derived_from_zone():
            if enable and not self._fw.policy.get_policy(policy).applied:
                transaction.add_post(self._fw.policy.try_apply_policy_settings, policy)
            elif self._fw.policy.get_policy(policy).applied:
                if not enable:
                    transaction.add_post(self._fw.policy.try_unapply_policy_settings, policy)

                ingress_zone_list = self._fw.policy.list_ingress_zones(policy)
                egress_zone_list = self._fw.policy.list_egress_zones(policy)

                if "ANY" in ingress_zone_list and "ANY" in egress_zone_list:
                    self._fw.policy._ingress_zone(enable, policy, zone, transaction,
                                                  ingressInterface=interface, ingressSource=source)
                    self._fw.policy._egress_zone(enable, policy, zone, transaction,
                                                 egressInterface=interface, egressSource=source)
                elif "ANY" in ingress_zone_list and "HOST" in egress_zone_list:
                    self._fw.policy._ingress_zone(enable, policy, zone, transaction,
                                                  ingressInterface=interface, ingressSource=source)
                elif "HOST" in ingress_zone_list and "ANY" in egress_zone_list:
                    self._fw.policy._egress_zone(enable, policy, zone, transaction,
                                                 egressInterface=interface, egressSource=source)
                elif zone in ingress_zone_list and "ANY" in egress_zone_list:
                    self._fw.policy._ingress_zone(enable, policy, zone, transaction,
                                                  ingressInterface=interface, ingressSource=source)
                    self._fw.policy._egress_zone(enable, policy, zone, transaction,
                                                 egressInterface=interface, egressSource=source)
                elif zone in ingress_zone_list and "HOST" in egress_zone_list:
                    self._fw.policy._ingress_zone(enable, policy, zone, transaction,
                                                  ingressInterface=interface, ingressSource=source)
                elif "ANY" in ingress_zone_list and zone in egress_zone_list:
                    self._fw.policy._ingress_zone(enable, policy, zone, transaction,
                                                  ingressInterface=interface, ingressSource=source)
                    self._fw.policy._egress_zone(enable, policy, zone, transaction,
                                                 egressInterface=interface, egressSource=source)
                elif "HOST" in ingress_zone_list and zone in egress_zone_list:
                    self._fw.policy._egress_zone(enable, policy, zone, transaction,
                                                 egressInterface=interface, egressSource=source)
                elif zone in ingress_zone_list and zone in egress_zone_list:
                    self._fw.policy._ingress_zone(enable, policy, zone, transaction,
                                                  ingressInterface=interface, ingressSource=source)
                    self._fw.policy._egress_zone(enable, policy, zone, transaction,
                                                 egressInterface=interface, egressSource=source)
                elif zone in ingress_zone_list:
                    self._fw.policy._ingress_zone(enable, policy, zone, transaction,
                                                  ingressInterface=interface, ingressSource=source)
                elif zone in egress_zone_list:
                    self._fw.policy._egress_zone(enable, policy, zone, transaction,
                                                 egressInterface=interface, egressSource=source)

    def _interface(self, enable, zone, interface, transaction):
        for backend in self._fw.enabled_backends():
            if not backend.policies_supported:
                continue
            if interface == "+":
                continue

            # intra zone forward
            policy = self.policy_name_from_zones(zone, "ANY")
            if self.get_zone(zone).forward:
                rules = backend.build_zone_forward_rules(enable, zone, policy, "filter", interface=interface)
                transaction.add_rules(backend, rules)

        self._interface_or_source_update_zone_termination(enable, zone, interface, "", transaction)
        self._interface_or_source_update_policies_derived_from_zone(enable, zone, interface, "", transaction)
        self._interface_or_source_update_policies(enable, zone, interface, "", transaction)

    # IPSETS

    def _ipset_family(self, name):
        if self._ipset_type(name) == "hash:mac":
            return None
        return self._fw.ipset.get_family(name, applied=False)

    def _ipset_type(self, name):
        return self._fw.ipset.get_type(name, applied=False)

    def _ipset_match_flags(self, name, flag):
        return ",".join([flag] * self._fw.ipset.get_dimension(name))

    def _check_ipset_applied(self, name):
        return self._fw.ipset.check_applied(name)

    def _check_ipset_type_for_source(self, name):
        _type = self._ipset_type(name)
        if _type not in SOURCE_IPSET_TYPES:
            raise FirewallError(
                errors.INVALID_IPSET,
                "ipset '%s' with type '%s' not usable as source" % \
                (name, _type))

    def _source(self, enable, zone, ipv, source, transaction):
        # For mac source bindings ipv is an empty string, the mac source will
        # be added for ipv4 and ipv6
        for backend in [self._fw.get_backend_by_ipv(ipv)] if ipv else self._fw.enabled_backends():
            if not backend.policies_supported:
                continue

            # intra zone forward
            policy = self.policy_name_from_zones(zone, "ANY")
            if self.get_zone(zone).forward:
                rules = backend.build_zone_forward_rules(enable, zone, policy, "filter", source=source)
                transaction.add_rules(backend, rules)

        self._interface_or_source_update_zone_termination(enable, zone, "", source, transaction)
        self._interface_or_source_update_policies_derived_from_zone(enable, zone, "", source, transaction)
        self._interface_or_source_update_policies(enable, zone, "", source, transaction)

    def add_service(self, zone, service, timeout=0, sender=None):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones(zone, "HOST")
        self._fw.policy.add_service(p_name, service, timeout, sender)
        return zone

    def remove_service(self, zone, service):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones(zone, "HOST")
        self._fw.policy.remove_service(p_name, service)
        return zone

    def query_service(self, zone, service):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones(zone, "HOST")
        return self._fw.policy.query_service(p_name, service)

    def list_services(self, zone):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones(zone, "HOST")
        return self._fw.policy.list_services(p_name)

    def add_port(self, zone, port, protocol, timeout=0, sender=None):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones(zone, "HOST")
        self._fw.policy.add_port(p_name, port, protocol, timeout, sender)
        return zone

    def remove_port(self, zone, port, protocol):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones(zone, "HOST")
        self._fw.policy.remove_port(p_name, port, protocol)
        return zone

    def query_port(self, zone, port, protocol):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones(zone, "HOST")
        return self._fw.policy.query_port(p_name, port, protocol)

    def list_ports(self, zone):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones(zone, "HOST")
        return self._fw.policy.list_ports(p_name)

    def add_source_port(self, zone, source_port, protocol, timeout=0, sender=None):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones(zone, "HOST")
        self._fw.policy.add_source_port(p_name, source_port, protocol, timeout, sender)
        return zone

    def remove_source_port(self, zone, source_port, protocol):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones(zone, "HOST")
        self._fw.policy.remove_source_port(p_name, source_port, protocol)
        return zone

    def query_source_port(self, zone, source_port, protocol):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones(zone, "HOST")
        return self._fw.policy.query_source_port(p_name, source_port, protocol)

    def list_source_ports(self, zone):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones(zone, "HOST")
        return self._fw.policy.list_source_ports(p_name)

    def _rich_rule_to_policies(self, zone, rule):
        zone = self._fw.check_zone(zone)
        if isinstance(rule.action, Rich_Mark):
            return [self.policy_name_from_zones(zone, "ANY")]
        elif isinstance(rule.element, (Rich_Service, Rich_Port, Rich_Protocol,
                                       Rich_SourcePort, Rich_IcmpBlock, Rich_IcmpType)):
            return [self.policy_name_from_zones(zone, "HOST")]
        elif isinstance(rule.element, Rich_ForwardPort):
            return [self.policy_name_from_zones(zone, "ANY")]
        elif isinstance(rule.element, Rich_Masquerade):
            return [self.policy_name_from_zones("ANY", zone)]
        elif isinstance(rule.element, Rich_Tcp_Mss_Clamp):
            return [self.policy_name_from_zones(zone, "ANY")]
        elif rule.element is None:
            return [self.policy_name_from_zones(zone, "HOST")]
        else:
            raise FirewallError(errors.INVALID_RULE, "Rich rule type (%s) not handled." % (type(rule.element)))

    def add_rule(self, zone, rule, timeout=0, sender=None):
        for p_name in self._rich_rule_to_policies(zone, rule):
            self._fw.policy.add_rule(p_name, rule, timeout, sender)
        return zone

    def remove_rule(self, zone, rule):
        for p_name in self._rich_rule_to_policies(zone, rule):
            self._fw.policy.remove_rule(p_name, rule)
        return zone

    def query_rule(self, zone, rule):
        ret = True
        for p_name in self._rich_rule_to_policies(zone, rule):
            ret = ret and self._fw.policy.query_rule(p_name, rule)
        return ret

    def list_rules(self, zone):
        zone = self._fw.check_zone(zone)
        ret = set()
        for p_name in [self.policy_name_from_zones(zone, "ANY"),
                       self.policy_name_from_zones(zone, "HOST"),
                       self.policy_name_from_zones("ANY", zone)]:
            ret.update(set(self._fw.policy.list_rules(p_name)))
        return list(ret)

    def add_protocol(self, zone, protocol, timeout=0, sender=None):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones(zone, "HOST")
        self._fw.policy.add_protocol(p_name, protocol, timeout, sender)
        return zone

    def remove_protocol(self, zone, protocol):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones(zone, "HOST")
        self._fw.policy.remove_protocol(p_name, protocol)
        return zone

    def query_protocol(self, zone, protocol):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones(zone, "HOST")
        return self._fw.policy.query_protocol(p_name, protocol)

    def list_protocols(self, zone):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones(zone, "HOST")
        return self._fw.policy.list_protocols(p_name)

    def add_masquerade(self, zone, timeout=0, sender=None):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones("ANY", zone)
        self._fw.policy.add_masquerade(p_name, timeout, sender)
        return zone

    def remove_masquerade(self, zone):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones("ANY", zone)
        self._fw.policy.remove_masquerade(p_name)
        return zone

    def query_masquerade(self, zone):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones("ANY", zone)
        return self._fw.policy.query_masquerade(p_name)

    def add_forward_port(self, zone, port, protocol, toport=None,
                         toaddr=None, timeout=0, sender=None):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones(zone, "ANY")
        self._fw.policy.add_forward_port(p_name, port, protocol, toport, toaddr,
                                         timeout, sender)
        return zone

    def remove_forward_port(self, zone, port, protocol, toport=None,
                            toaddr=None):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones(zone, "ANY")
        self._fw.policy.remove_forward_port(p_name, port, protocol, toport, toaddr)
        return zone

    def query_forward_port(self, zone, port, protocol, toport=None,
                           toaddr=None):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones(zone, "ANY")
        return self._fw.policy.query_forward_port(p_name, port, protocol, toport,
                                                  toaddr)

    def list_forward_ports(self, zone):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones(zone, "ANY")
        return self._fw.policy.list_forward_ports(p_name)

    def add_icmp_block(self, zone, icmp, timeout=0, sender=None):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones(zone, "HOST")
        self._fw.policy.add_icmp_block(p_name, icmp, timeout, sender)

        return zone

    def remove_icmp_block(self, zone, icmp):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones(zone, "HOST")
        self._fw.policy.remove_icmp_block(p_name, icmp)

        return zone

    def query_icmp_block(self, zone, icmp):
        zone = self._fw.check_zone(zone)
        p_name_host = self.policy_name_from_zones(zone, "HOST")
        return self._fw.policy.query_icmp_block(p_name_host, icmp)

    def list_icmp_blocks(self, zone):
        zone = self._fw.check_zone(zone)
        p_name_host = self.policy_name_from_zones(zone, "HOST")
        return sorted(set(self._fw.policy.list_icmp_blocks(p_name_host)))

    def add_icmp_block_inversion(self, zone, sender=None):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones(zone, "HOST")
        self._fw.policy.add_icmp_block_inversion(p_name, sender)

        return zone

    def _icmp_block_inversion(self, enable, zone, transaction):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones(zone, "HOST")
        self._fw.policy._icmp_block_inversion(enable, p_name, transaction)

    def remove_icmp_block_inversion(self, zone):
        zone = self._fw.check_zone(zone)
        p_name = self.policy_name_from_zones(zone, "HOST")
        self._fw.policy.remove_icmp_block_inversion(p_name)

        return zone

    def query_icmp_block_inversion(self, zone):
        zone = self._fw.check_zone(zone)
        p_name_host = self.policy_name_from_zones(zone, "HOST")
        return self._fw.policy.query_icmp_block_inversion(p_name_host)

    def _forward(self, enable, zone, transaction):
        p_name = self.policy_name_from_zones(zone, "ANY")

        for interface in self._zones[zone].interfaces:
            for backend in self._fw.enabled_backends():
                if not backend.policies_supported:
                    continue
                rules = backend.build_zone_forward_rules(enable, zone, p_name, "filter", interface=interface)
                transaction.add_rules(backend, rules)

        for source in self._zones[zone].sources:
            ipv = self.check_source(source)
            for backend in [self._fw.get_backend_by_ipv(ipv)] if ipv else self._fw.enabled_backends():
                if not backend.policies_supported:
                    continue
                rules = backend.build_zone_forward_rules(enable, zone, p_name, "filter", source=source)
                transaction.add_rules(backend, rules)

    def add_forward(self, zone, timeout=0, sender=None,
                    use_transaction=None):
        _zone = self._fw.check_zone(zone)
        self._fw.check_timeout(timeout)
        self._fw.check_panic()
        _obj = self._zones[_zone]

        if _obj.forward:
            raise FirewallError(errors.ALREADY_ENABLED,
                                "forward already enabled in '%s'" % _zone)

        if use_transaction is None:
            transaction = self.new_transaction()
        else:
            transaction = use_transaction

        if _obj.applied:
            self._forward(True, _zone, transaction)

        self.__register_forward(_obj, timeout, sender)
        transaction.add_fail(self.__unregister_forward, _obj)

        if use_transaction is None:
            transaction.execute(True)

        return _zone

    def __register_forward(self, _obj, timeout, sender):
        _obj.forward = True

    def remove_forward(self, zone, use_transaction=None):
        _zone = self._fw.check_zone(zone)
        self._fw.check_panic()
        _obj = self._zones[_zone]

        if not _obj.forward:
            raise FirewallError(errors.NOT_ENABLED,
                                "forward not enabled in '%s'" % _zone)

        if use_transaction is None:
            transaction = self.new_transaction()
        else:
            transaction = use_transaction

        if _obj.applied:
            self._forward(False, _zone, transaction)

        transaction.add_post(self.__unregister_forward, _obj)

        if use_transaction is None:
            transaction.execute(True)

        return _zone

    def __unregister_forward(self, _obj):
        _obj.forward = False

    def query_forward(self, zone):
        return self.get_zone(zone).forward


import plotly.graph_objects as go

import Layout
import pandas as pd
#_______________________________________________________________________________________________________________________________________________________

#________________________________________________________Balkendiagramm____________________________________________________________________________________
#_______________________________________________________________________________________________________________________________________________________

# Balkendiagramm durchschnittliche aufgeholte Zeit pro Flug
#X-Achse Kurzstrec kenflüge bis <= 1.000, Mittelstrecke >1000 und <= 3000, Langstrecke > 3000.
#Y-Achse durchschnittliche verspätung pro flug in Minuten
#Beim Drüber hovern soll die Airline angezeigt werden und an der Seite gibt es eine legende mit den Farben für kurz und langstrecke

# Filter durchschnitt, ankunft , verspätung

# Fertiges Datenset was in Datensets.py bearbeitet wurde einlesen
df = pd.read_csv("Abgabe/res/FertigesDatenset.csv")

df["DELAY"] = df["SCHEDULED_TIME"]-df["ELAPSED_TIME"]
avg_delay = df.groupby("AIRLINE")["DELAY"].mean()
airline_group = df["AIRLINE"].unique()

# Festlegen, ab welcher Distanz welche Art von Flug ist
short_haul = df[df["DISTANCE"] <= 1000]
medium_haul = df[(df["DISTANCE"] <= 3000) & (df["DISTANCE"] > 1000)]
long_haul = df[df["DISTANCE"] >3000]

# Berechnen der durchschnittlichen Verspätung pro Flug
short_haul_avg_delay = short_haul.groupby("AIRLINE")["DELAY"].mean()
medium_haul_avg_delay = medium_haul.groupby("AIRLINE")["DELAY"].mean()
long_haul_avg_delay = long_haul.groupby("AIRLINE")["DELAY"].mean()

fig1 = go.Figure()

# Balken für die Kurzstrecke
trace1 = go.Bar(
    x = airline_group,
    y = short_haul_avg_delay,
    name = "Kurzstrecke",
    marker_color='rgb(118, 204, 122)'
)

# Balken für die Mittelstrecke
trace2 = go.Bar(
    x = airline_group,
    y = medium_haul_avg_delay,
    name = "Mittelstrecke",
    marker_color= 'rgb(26, 118, 255)'

)

# Balken für die Langstrecke
trace3 = go.Bar(
    x = airline_group,
    y = long_haul_avg_delay,
    name = "Langstrecke",
    marker_color='rgb(55, 83, 109)',

)

# Style für das Balkendiagramm
layout = go.Layout(
    title = "Aufgeholte Zeit in der Luft",
    xaxis_tickfont_size=14,
    xaxis_title = "Fluggesellschaften",
    yaxis=dict(
        title='Aufgeholte Zeit in Minuten',
        titlefont_size=16,
        tickfont_size=14,
    ),
    legend=dict(
        x=0,
        y=1.0,
        bgcolor='rgba(255, 255, 255, 0)',
        bordercolor='rgba(255, 255, 255, 0)'
    ),
    barmode='group',
    bargap = 0.15, # Lücke zwischen den Balken der benachbarten Standortkoordinaten.
    bargroupgap=0.05 # Lücke zwischen Balken derselben Standortkoordinate.

)

fig1.add_trace(trace1)
fig1.add_trace(trace2)
fig1.add_trace(trace3)

fig1 = go.Figure(data=[trace1,trace2, trace3], layout= Layout.layout_Barchart)

fig1.update_layout(
    updatemenus = [
        dict(
            active = 0,
            buttons = list([
                dict(label = "Alle Flugarten",
                     method = "update",
                     args = [{"visible": [True, True, True]},
                             {"title": "Durchschnittliche aufgeholte Zeit pro Fluggesellschaft"}]),

                dict(label = "Kurzstrecke",
                     method = "update",
                     args = [{"visible": [True, False, False]},
                             {"title": "Durchschnittliche aufgeholte Zeit pro Fluggesellschaft nur Kurzstrecke"}],
                       ),
                dict(label = "Mittelstrecke",
                     method = "update",
                     args = [{"visible": [False, True, False]},
                             {"title": "Durchschnittliche aufgeholte Zeit pro Fluggesellschaft nur Mittelstrecke"}],
                       ),
                dict(label = "Langstrecke",
                     method = "update",
                     args = [{"visible": [False, False, True]},
                             {"title": "Durchschnittliche aufgeholte Zeit pro Fluggesellschaft nur Langstrecke"}],
                       )
        ])
             )
    ]
)

fig1.show()


def bfs(comp):
    visited = [1]
    queue = [1]

    while queue:
        node = queue.pop(0) # BFS uses Queue
        for i in comp[node - 1]:
            if i not in visited:
                visited.append(i)
                queue.append(i)

    return len(visited)-1

if __name__ == "__main__":
    n = int(input())
    m = int(input())
    comp = [[] for i in range(n)]

    i = 0
    for i in range(m):
        l1, l2 = map(int, input().split())
        comp[l1-1].append(l2)
        comp[l2-1].append(l1)

    print(bfs(comp))


import time
import picoscroll
import random
import _thread # used for multithreading so i can have a consistant fall speed

#initialise the board
picoscroll.init()

#Get the width and height of the board
# height and width flipped because normal board operation is landscape
height = picoscroll.get_width()
width = picoscroll.get_height()

# toned down so I don't burn out my retinas
shapebright = 50

# I'm going to start by getting shapes to light up on the screen
# first, practice getting a single pixel to fall down the screen

# global variables for my pixel starting point
pixy = 0
pixx = 3

# function for the pixel "shape"
def pix():
    # sets the initial position of the pixel
    global pixy
    global pixx
    picoscroll.set_pixel(pixy,pixx,shapebright) # (Height, Width, Brightness)
    picoscroll.update()

    # loop to listen for button presses
    while pixy <= 16:
        picoscroll.set_pixel(pixy,pixx,0)
        #pixy = pixy + 1
        picoscroll.set_pixel(pixy,pixx,shapebright)
        picoscroll.update()

        # move right when button X is pressed
        if picoscroll.is_pressed(picoscroll.BUTTON_X) == True and pixx > 0:
            picoscroll.set_pixel(pixy,pixx,0)
            pixx = pixx - 1
            picoscroll.set_pixel(pixy,pixx,shapebright)
            picoscroll.update()

        elif picoscroll.is_pressed(picoscroll.BUTTON_X) == True and pixx == 6:
            pixx = pixx
            picoscroll.set_pixel(pixy,pixx,shapebright)
            picoscroll.update()

        # move left when button Y is pressed
        elif picoscroll.is_pressed(picoscroll.BUTTON_Y) == True and pixx < 6:
            picoscroll.set_pixel(pixy,pixx,0)
            pixx = pixx + 1
            picoscroll.set_pixel(pixy,pixx,shapebright)
            picoscroll.update()

        elif picoscroll.is_pressed(picoscroll.BUTTON_Y) == True and pixx == 0:
            pixx = pixx
            picoscroll.set_pixel(pixy,pixx,shapebright)
            picoscroll.update()

        # min time between button presses
        time.sleep(0.1)

# seperate funtion to control the speed that shapes fall
def falling():
    global pixy
    global pixx
    while pixy < 16:

        time.sleep(1)
        pixy = pixy + 1

        # for loop turns off the LEDs on the board "behind" the falling shape
        for i in range(0, pixy):
            for j in range(0, width):
                picoscroll.set_pixel(i, j, 0)
        picoscroll.update()
        # printing variable for debugging purposes.
        print("height = " + str(height)," width = " + str(width) +"\n")
        print("x = " + str(pixx), " y = " + str(pixy))

# start the falling function
_thread.start_new_thread(falling,())

# start the shape function
while True:
    pix()


N, M = map(int, input().split())
board = [list(map(int, input().split())) for x in range(N)]

directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]

answer = 0
board_flag = True
for i in range(M):
    d, s = map(int, input().split())
    d -= 1
    break_x = N//2
    break_y = N//2
    for j in range(1, s+1):
        break_x += directions[d][1]
        break_y += directions[d][0]
        board[break_y][break_x] = -1
    print("board : ", board)
    # board를 1차원 배열로 바꿔야함
    cur = [N // 2, N // 2]
    directions2 = [(0, -1), (1, 0), (0, 1), (-1, 0)]
    marbles = []
    direction = 0
    cnt = 1
    two = 0
    flag = False
    while True:
        for i in range(1, cnt + 1):
            cur[1] += directions2[direction][1]
            cur[0] += directions2[direction][0]
            if not (0 <= cur[0] < N and 0 <= cur[1] < N):
                flag = True
                break
            if board[cur[0]][cur[1]] == 0:
                flag = True
                break
            if board[cur[0]][cur[1]] == -1:
                continue
            marbles.append(board[cur[0]][cur[1]])
        if flag:
            break
        direction = (direction + 1) % 4
        two += 1
        if two == 2:
            two = 0
            cnt += 1
    print("marbles : ", marbles)
    if len(marbles) == 0:
        break
    marble = 0
    cnt = 1
    while True:
        flag = True
        for idx in range(len(marbles)):
            if marbles[idx] == marble: #연속
                cnt += 1
            else: #불연속
                if cnt > 3: # 폭발
                    flag = False
                    marble = marbles[idx]
                    for _ in range(cnt):
                        print(idx, cnt)
                        marbles.pop(idx - cnt)
                    answer += marble * cnt
                    print(marble, cnt)
                    print(marble * cnt)
                    cnt = 1
                    break
                cnt = 1
                marble = marbles[idx]
        if flag:
            break
    marble = marbles[0]
    cnt = 1
    new_marbles = []
    for i in range(1, len(marbles)):
        if marbles[i] == marble: #연속
            cnt += 1
        else: # 불연속 개수, 번호
            new_marbles.append(cnt)
            new_marbles.append(marble)
            marble = marbles[i]
            cnt = 1
        if i == len(marbles)- 1:
            new_marbles.append(cnt)
            new_marbles.append(marble)

    new_board = [[0] * N for _ in range(N)]
    marble_index = 0

    cur = [N // 2, N // 2]
    direction = 0
    cnt = 1
    two = 0
    flag = False
    print("new_marbles : ", new_marbles)
    while True:
        for i in range(1, cnt + 1):
            cur_marble = new_marbles[marble_index]
            cur[1] += directions2[direction][1]
            cur[0] += directions2[direction][0]
            if not (0 <= cur[0] < N and 0 <= cur[1] < N):
                flag = True
                break
            new_board[cur[1]][cur[0]] = cur_marble
            marble_index += 1
            if marble_index >= len(new_marbles):
                flag = True
                break
        if flag:
            break
        direction = (direction + 1) % 4
        two += 1
        if two == 2:
            two = 0
            cnt += 1
    print("new_board : ", new_board)
    board = new_board

print(answer)


"""

This script runs an Magnetic Amplitude Inversion (MAI) from TMI data.
Magnetic amplitude data are weakly sensitive to the orientation of
magnetization, and can therefore better recover the location and geometry of
magnetic bodies in the presence of remanence. The algorithm is inspired from
Li & Shearer (2008), with an added iterative sensitivity weighting strategy to
counter the vertical streatchin that the old code had

This is done in three parts:

1- TMI data are inverted for an equivalent source layer.

2-The equivalent source layer is used to predict component data -> amplitude

3- Amplitude data are inverted in 3-D for an effective susceptibility model

Created on December 7th, 2016

@author: fourndo@gmail.com

"""
from SimPEG import Mesh, Directives, Maps, InvProblem, Optimization, DataMisfit, Inversion, Utils, Regularization
import SimPEG.PF as PF
import numpy as np
import matplotlib.pyplot as plt
import os

# # STEP 1: Setup and data simulation # #

# Magnetic inducing field parameter (A,I,D)
B = [50000, 90, 0]

# Create a mesh
dx = 5.
npad = 10
hxind = [(dx, npad, -1.3), (dx, 24), (dx, npad, 1.3)]
hyind = [(dx, npad, -1.3), (dx, 24), (dx, npad, 1.3)]
hzind = [(dx, npad, -1.3), (dx, 20)]

mesh = Mesh.TensorMesh([hxind, hyind, hzind], 'CC0')
mesh.x0[2] -= mesh.vectorNz[-1]
norms = [2, 2, 2, 2]
susc = 0.025
nX = 2

# Get index of the center of block
locx = [int(mesh.nCx/2)]#[int(mesh.nCx/2)-3, int(mesh.nCx/2)+3]
midy = int(mesh.nCy/2)
midz = -6

# Lets create a simple flat topo and set the active cells
[xx, yy] = np.meshgrid(mesh.vectorNx, mesh.vectorNy)
zz = np.ones_like(xx)*mesh.vectorNz[-1]
topo = np.c_[Utils.mkvc(xx), Utils.mkvc(yy), Utils.mkvc(zz)]

# Go from topo to actv cells
actv = Utils.surface2ind_topo(mesh, topo, 'N')
actv = np.asarray([inds for inds, elem in enumerate(actv, 1) if elem],
                  dtype=int) - 1

# Create active map to go from reduce space to full
actvMap = Maps.InjectActiveCells(mesh, actv, -100)
nC = int(len(actv))

# Create and array of observation points
xr = np.linspace(-50., 50., 10)
yr = np.linspace(-50., 50., 10)
X, Y = np.meshgrid(xr, yr)

# Move the observation points 5m above the topo
Z = np.ones_like(X) * mesh.vectorNz[-1] + 2*dx

# Create a MAGsurvey
rxLoc = np.c_[Utils.mkvc(X.T), Utils.mkvc(Y.T), Utils.mkvc(Z.T)]
rxLoc = PF.BaseMag.RxObs(rxLoc)
srcField = PF.BaseMag.SrcField([rxLoc], param=(B[0], B[1], B[2]))
survey = PF.BaseMag.LinearSurvey(srcField)

# We can now create a susceptibility model and generate data
# Here a simple block in half-space
model = np.zeros((mesh.nCx, mesh.nCy, mesh.nCz))
for midx in locx:
    model[(midx-nX):(midx+nX+1), (midy-nX):(midy+nX+1), (midz-nX):(midz+nX+1)] = susc
model = Utils.mkvc(model)
model = model[actv]

# We create a magnetization model different than the inducing field
# to simulate remanent magnetization. Let's do something simple [45,90]
M = PF.Magnetics.dipazm_2_xyz(np.ones(nC) * 90., np.ones(nC) * 0.)
#M = PF.Magnetics.dipazm_2_xyz(np.ones(nC) * B[1], np.ones(nC) * B[2])

# Create active map to go from reduce set to full
actvMap = Maps.InjectActiveCells(mesh, actv, -100)

# Create reduced identity map
idenMap = Maps.IdentityMap(nP=nC)

# Create the forward problem (forwardOnly)
prob = PF.Magnetics.MagneticIntegral(mesh, chiMap=idenMap, actInd=actv,
                                     M=M, silent=True)

# Pair the survey and problem
survey.pair(prob)

prob.forwardOnly = True
d_TMI = prob.Intrgl_Fwr_Op(m=model, recType='tmi')

ndata = survey.nD

# Add noise and uncertainties
# We add some random Gaussian noise (1nT)
floor = d_TMI.max()*0.05
d_TMI += np.random.randn(len(d_TMI))*floor
wd = np.ones(len(d_TMI))*floor  # Assign flat uncertainties
survey.dobs = d_TMI
survey.std = wd

rxLoc = survey.srcField.rxList[0].locs

# For comparison, let's run the inversion assuming an induced response
M = PF.Magnetics.dipazm_2_xyz(np.ones(nC) * B[1], np.ones(nC) * B[2])

# Reset the magnetization
prob.M = M
prob.forwardOnly = False
prob._F = None

fig = plt.figure(figsize=(12, 6))

exp = np.linspace(2, -8, 6)
eps = 10**exp

eps[-1] = 0.
for ii in range(6):

    # Create a regularization function, in this case l2l2
    wr = (np.sum(prob.F**2. + eps[ii]**2., axis=0))**0.5
    # wr = (wr/np.max(wr))

    # Create a regularization
    reg_Susc = Regularization.Sparse(mesh, indActive=actv, mapping=idenMap)
    reg_Susc.cell_weights = wr
    reg_Susc.norms = [2, 2, 2, 2]
    reg_Susc.alpha_x = 0
    reg_Susc.alpha_y = 0
    reg_Susc.alpha_z = 0
    # Data misfit function
    dmis = DataMisfit.l2_DataMisfit(survey)
    dmis.W = 1/wd

    # Add directives to the inversion
    opt = Optimization.ProjectedGNCG(maxIter=100, lower=0., upper=1.,
                                     maxIterLS=20, maxIterCG=10, tolCG=1e-3)
    invProb = InvProblem.BaseInvProblem(dmis, reg_Susc, opt)
    betaest = Directives.BetaEstimate_ByEig()

    # Here is where the norms are applied
    # Use pick a treshold parameter empirically based on the distribution of
    #  model parameters
    IRLS = Directives.Update_IRLS(f_min_change=1e-3, minGNiter=3)
    update_Jacobi = Directives.UpdatePreCond()
    inv = Inversion.BaseInversion(invProb,
                                  directiveList=[betaest, IRLS, update_Jacobi])

    # Run the inversion
    m0 = np.ones(nC)*1e-4  # Starting model
    mrec_sus = inv.run(m0)
    pred_sus = invProb.dpred

    #%% Plot models
    from matplotlib.patches import Rectangle
    ax2 = plt.subplot(2, 3, ii+1)
    contours = [0.01]
    xlim = 150.

    vmax = mrec_sus.max()
    vmin = -0.001
    # PF.Magnetics.plotModelSections(mesh, mrec_sus, normal='z', ind=-3, subFact=2, scale=0.25, xlim=[-xlim, xlim], ylim=[-xlim, xlim],
    #                       title="Esus Model", axs=ax3, vmin=0, vmax=vmax, contours = contours)
    # ax3.xaxis.set_visible(False)

    # out = PF.Magnetics.plot_obs_2D(rxLoc, d=pred_sus, fig=fig, ax=ax3,
    #                                )
    # ax3.set_xlabel('X (m)')
    # ax3.set_ylabel('Y (m)')

    # fig = plt.figure(figsize=(5, 2.5))
    # ax2 = plt.subplot()
    # PF.Magnetics.plotModelSections(mesh, model, normal='y', ind=midy, subFact=2, scale=0.25, xlim=[-xlim, xlim], ylim=[-xlim, 5],
    #                       axs=ax2, vmin=vmin, vmax=vmax, contours = contours)
    # for midx in locx:
    #     ax2.add_patch(Rectangle((mesh.vectorCCx[midx-nX]-dx/2.,mesh.vectorCCz[midz-nX]-dx/2.),(2*nX+1)*dx,(2*nX+1)*dx, facecolor = 'none', edgecolor='k'))
    # ax2.grid(color='w', linestyle='--', linewidth=0.5)
    # loc = ax2.get_position()
    # ax2.set_position([loc.x0+0.025, loc.y0+0.025, loc.width, loc.height])
    # ax2.set_xlabel('X (m)')
    # ax2.set_ylabel('Depth (m)')

    ax2, im2, cbar = PF.Magnetics.plotModelSections(mesh, mrec_sus, normal='y', ind=midy, subFact=2, scale=0.25, xlim=[-xlim, xlim], ylim=[-xlim, 5],
                          axs=ax2, vmin=vmin, vmax=vmax, contours = contours)
    cbar.remove()
    for midx in locx:
        ax2.add_patch(Rectangle((mesh.vectorCCx[midx-nX]-dx/2.,mesh.vectorCCz[midz-nX]-dx/2.),(2*nX+1)*dx,(2*nX+1)*dx, facecolor = 'none', edgecolor='k'))
    ax2.grid(color='w', linestyle='--', linewidth=0.5)
    loc = ax2.get_position()
    ax2.set_position([loc.x0, loc.y0, loc.width*1.2, loc.height*1.2])
    ax2.set_xlabel('X (m)')
    ax2.set_ylabel('Depth (m)')

    if ii < 5:
      ax2.set_title('$\epsilon=\;10^{' + str(exp[ii]) + '}$')
    else:
      ax2.set_title('$\epsilon=0$')

plt.show()


import numpy as np
import matplotlib.pyplot as plt

LR = 1

def activate_fn(n):
    return 1 if n>=0 else 0

def plot_tr(w_all):
    n = len(w_all)
    plt.figure()
    for i in range(2):
        plt.plot(list(range(n)), [w_all[j][i] for j in range(n)])
    plt.legend(['w0','w1'])
    plt.title('Parameters trajectory')
    plt.xlabel('Iteration')
    plt.ylabel('Weight')
    plt.show()

if __name__ == '__main__':
    w = np.random.uniform(-1, 1, size=2)
    w_rollout = []
    x = np.array([[1, 0], [1, 1]])
    y = np.array([1, 0])
    while True:
        w_rollout.append(w.copy())
        y_predict = np.squeeze(np.asarray([activate_fn(w.dot(x[i])) for i in range(2)]))
        err = y - y_predict
        delta_w = LR * np.array([err[i] * x[i] for i in range(2)])
        w += np.sum(delta_w, axis=0)
        if np.sum(np.square(err)) == 0:
            break
    print('Weights:{}\nNumber of iters:{}'.format(w, len(w_rollout)))
    plot_tr(w_rollout)


from flask import Blueprint, render_template, request, redirect
from app import db
from app.person.models import Person
from app.person.forms import PersonRegistrationForm

from datetime import datetime, date

person_blueprint = Blueprint('person', __name__)

@person_blueprint.route('/person', methods=['POST', 'GET'])
def person():
    personRegistration = PersonRegistrationForm()

    if request.method == 'POST':
        print('POST')
    else:
        print('Não POST')
    number = personRegistration.number.data  #Number
    print(type(number))
    if number == '' or number == 'sn':
        number = 0
    print("BD -> {}" .format(number))
    if personRegistration.validate_on_submit():
        #Person Identification
        document_type = personRegistration.document_type.data  #0 - PF || 1 - PJ
        registration_card = personRegistration.registration_card.data  #CPF/CNPJ
        identification =  str.upper(personRegistration.identification.data)  #Identification
        if identification == '':
            identification = None
        first_name = str.upper(personRegistration.first_name.data)  #Name
        second_name = str.upper(personRegistration.second_name.data)  #Second name
        birth_day = personRegistration.birth_day.data  #Birth day
        if birth_day == '':
            birth_day = datetime(1900, 1, 1).date()
        nick_name = str.upper(personRegistration.nick_name.data)  #Nickname
        if nick_name == '':
            nick_name = None
        father_name = str.upper(personRegistration.father_name.data)  #Father name
        if father_name == '':
            father_name = None
        mother_name = str.upper(personRegistration.mother_name.data)  #Mother name
        if mother_name == '':
            mother_name = None
        #Contact
        email = str.lower(personRegistration.email.data)  #E-mail
        phone_number = personRegistration.phone_number.data  #Phone
        if phone_number == '':
            phone_number = None
        cellphone_number = personRegistration.cellphone_number.data  #Cell phone

        #Address
        postal_code = personRegistration.postal_code.data  #Postal code
        if postal_code == '':
            postal_code = None
        street = str.upper(personRegistration.street.data)  #Street
        if street == '':
            street = None
        number = str.upper(personRegistration.number.data)  #Number
        if number == 'SN' or number == '':
            number = 0
        complement = str.upper(personRegistration.complement.data)  #Complement
        if complement == '':
            complement = None
        neighborhood = str.upper(personRegistration.neighborhood.data)  #Neighborhood
        if neighborhood == '':
            neighborhood = None
        city = str.upper(personRegistration.city.data)  #City
        if city == '':
            city = None
        state = str.upper(personRegistration.state.data)  #State
        if state == '':
            state = None
        country = str.upper(personRegistration.country.data)  #Country
        if country == '':
            country = None

        #Observations
        observations = personRegistration.observations.data
        if observations == '':
            observations = None

        #Action DateTime
        created_at = datetime.now()  #Created at
        updated_at = None  #Updated at  #Deleted(soft delete)
        deleted = 0  #Deleted(soft delete)
        deleted_at = None  #Deleted at(soft delete)

        print('BD: {} -> NN: {}'.format(birth_day, nick_name))
        new_person = Person(document_type=document_type, registration_card=registration_card, first_name=first_name, second_name=second_name, birth_day=birth_day, nick_name=nick_name, identification=identification, father_name=father_name, mother_name=mother_name, email=email, phone_number=phone_number, cellphone_number=cellphone_number, postal_code=postal_code, street=street, number=number, complement=complement, neighborhood=neighborhood, city=city, state=state, country=country, observations=observations, created_at=created_at, updated_at=updated_at, deleted=deleted, deleted_at=deleted_at)

        db.session.add(new_person)
        db.session.commit()
        # Criar listagem e fazer redirecionamento para ela.
        return redirect('../')
    else:
        #return personRegistration.errors
        print(personRegistration.errors)

    return render_template('person/form/personRegister.html', personRegistration = personRegistration)


# adapters are really powerful, but unfortunately, they are a bit tricky to use with automodels
# There are also some unfortunate incompatibilities between adpaters and the most recent version of transformers

import gft
import sys,os

from transformers import AutoTokenizer,AutoFeatureExtractor

from gft.gft_internals.gft_util import parse_base_model_specification

def get_config(fn):
    p = os.path.join(fn, 'config.json')
    if os.path.exists(p):
        with open(p, 'r') as fd:
            import json
            return json.loads(fd.read())
    return None

# DeltaHub looks similar to adapters, but more of a work in progress
# installation is harder than pip
# And it seems to be limited to tensorflow
#
# The documentation suggests you can say
#   pip install opendelta
#
# but I had to do this:
# git clone https://github.com/thunlp/OpenDelta.git
# cd OpenDelta
# python setup.py install
#
# According to https://huggingface.co/DeltaHub/lora_t5-base_mrpc,
# you should be able to do the following, but that is generating
# warnings about checksums not matching.
# Maybe opendelta is still too unstable for now.
#
# from transformers import AutoModelForSeq2SeqLM
# t5 = AutoModelForSeq2SeqLM.from_pretrained("t5-base")
# from opendelta import AutoDeltaModel
# delta = AutoDeltaModel.from_finetuned("DeltaHub/lora_t5-base_mrpc", backbone_model=t5)
# delta.log()

def my_get_adapter_info(adapter_key):
    try:
        import transformers.adapters.utils
        a = transformers.adapters.utils.get_adapter_info(adapter_key, 'hf')
        if a is None:
            a = transformers.adapters.utils.get_adapter_info(adapter_key, 'ah')
        # assert not a is None, 'bad adapter key: ' + str(adapter_key)
        return a
    except:
        if adapter_key.startswith('AdapterHub/'):
            import transformers
            assert hasattr(transformers, 'adapters'), 'adapters are not supported in newer version of transformers; tranformers.__version__ is %s; adapter_key is: %s' % (transformers.__version__, adapter_key)
        return None

# from gft_internals.my_auto_model_util import my_tokenizer

# ['FNetForSequenceClassification', 'GPTJForSequenceClassification',
#  'LayoutLMv2ForSequenceClassification',
#  'RemBertForSequenceClassification',
#  'CanineForSequenceClassification',
#  'RoFormerForSequenceClassification',
#  'BigBirdPegasusForSequenceClassification',
#  'BigBirdForSequenceClassification',
#  'ConvBertForSequenceClassification', 'LEDForSequenceClassification',
#  'DistilBertForSequenceClassification',
#  'AlbertForSequenceClassification',
#  'CamembertForSequenceClassification',
#  'XLMRobertaForSequenceClassification',
#  'MBartForSequenceClassification', 'BartForSequenceClassification',
#  'LongformerForSequenceClassification',
#  'RobertaForSequenceClassification',
#  'SqueezeBertForSequenceClassification',
#  'LayoutLMForSequenceClassification', 'BertForSequenceClassification',
#  'XLNetForSequenceClassification',
#  'MegatronBertForSequenceClassification',
#  'MobileBertForSequenceClassification',
#  'FlaubertForSequenceClassification', 'XLMForSequenceClassification',
#  'ElectraForSequenceClassification',
#  'FunnelForSequenceClassification',
#  'DebertaForSequenceClassification',
#  'DebertaV2ForSequenceClassification',
#  'GPT2ForSequenceClassification', 'GPTNeoForSequenceClassification',
#  'OpenAIGPTForSequenceClassification',
#  'ReformerForSequenceClassification', 'CTRLForSequenceClassification',
#  'TransfoXLForSequenceClassification',
#  'MPNetForSequenceClassification', 'TapasForSequenceClassification',
#  'IBertForSequenceClassification', 'XLMRobertaModelWithHeads',
#  'RobertaModelWithHeads', 'BertModelWithHeads',
#  'DistilBertModelWithHeads', 'BartModelWithHeads',
#  'MBartModelWithHeads', 'GPT2ModelWithHeads', 'T5ModelWithHeads'].

# sorted by length of model (to prefer longer matches over shorted ones)
base_models = ["bert-large-uncased-whole-word-masking-finetuned-squad",
               "bert-large-cased-whole-word-masking-finetuned-squad",
               "distilbert-base-uncased-finetuned-sst-2-english",
               "xlm-roberta-large-finetuned-conll03-english",
               "xlm-roberta-large-finetuned-conll02-dutch",
               "distilbert-base-uncased-distilled-squad",
               "bert-large-uncased-whole-word-masking",
               "bert-large-cased-whole-word-masking",
               "bert-base-multilingual-uncased",
               "bert-base-cased-finetuned-mrpc",
               "roberta-large-openai-detector",
               "distilbert-base-german-cased",
               "bert-base-multilingual-cased",
               "xlm-mlm-tlm-xnli15-1024",
               "distilbert-base-uncased",
               "distilbert-base-cased",
               "roberta-large-mnli",
               "distilroberta-base",
               "bert-large-uncased",
               "xlm-roberta-large",
               "xlm-mlm-enfr-1024",
               "xlm-mlm-ende-1024",
               "xlm-clm-enfr-1024",
               "xlm-clm-ende-1024",
               "bert-base-uncased",
               "bert-base-chinese",
               "albert-xxlarge-v2",
               "albert-xxlarge-v1",
               "xlnet-base-cased",
               "xlm-roberta-base",
               "transfo-xl-wt103",
               "bert-large-cased",
               "albert-xlarge-v2",
               "albert-xlarge-v1",
               "xlm-mlm-en-2048",
               "bert-base-cased",
               "albert-large-v2",
               "albert-large-v1",
               "camembert-base",
               "albert-base-v2",
               "albert-base-v1",
               "roberta-large",
               "roberta-base",
               "gpt2-medium",
               "gpt2-large",
               "distilgpt2",
               "t5-small",
               "t5-large",
               "t5-base",
               "gpt2",
               "ctrl",
               'bert-base-uncased',
               'roberta-base',
               'distilbert-base-uncased',
               'distilbert-base-cased',
               'roberta-base',
               'albert-base-v2',
               'xlnet-base-cased',
               'facebook/bart-large',
               'xlnet-large-cased',
               'bert-base-uncased' ]

# horrible hack: we will attempt to infer the base model from the model name
def my_tokenizer(model_key):
    print('my_tokenizer: ' + str(model_key), file=sys.stderr)
    try:
        return AutoTokenizer.from_pretrained(model_key)
    except:
        for base_model_key in base_models:
            if base_model_key in model_key:
                return AutoTokenizer.from_pretrained(base_model_key)
        config = get_config(model_key)
        if not config is None and "_name_or_path" in config:
            return AutoTokenizer.from_pretrained(config["_name_or_path"])
        else:
            print('Warning, cannot find tokenizer for: ' + str(model_key), file=sys.stderr)
            return None

# Here are some of the more important tasks to add
# egrep error `cat $pwd/errors.txt` | awk 'match($0,/task not supported/) {print substr($0, RSTART+RLENGTH+2)}'  | cut -f1 -d, | sort | uniq -c | sort -nr
     # 10 text-to-speech')
     # 10 audio-to-audio')
     #  9 text-to-image')
     #  5 structured-data-classification')
     #  4 sentence-similarity')
     #  2 voice-activity-detection')
     #  1 zero-shot-image-classification')
     #  1 speech-segmentation')
     #  1 protein-folding')

import transformers

# old_my_task_to_auto_class = {
#     'ASR'                            : transformers.AutoModelForCTC,
#     'MT'                             : transformers.AutoModelWithLMHead,
#     'QA'                             : transformers.AutoModelForQuestionAnswering,
#     'audio-classification'           : transformers.AutoModelForAudioClassification,
#     'automatic-speech-recognition'   : transformers.AutoModelForCTC,
#     'classify'                       : transformers.AutoModelForSequenceClassification,
#     'classify_spans'                 : transformers.AutoModelForQuestionAnswering,
#     'classify_tokens'                : transformers.AutoModelForTokenClassification,
#     'conversational'                 : transformers.AutoModelForCausalLM,
#     'default'                        : transformers.AutoModel,
#     'feature-extraction'             : transformers.AutoFeatureExtractor,
#     'fill-mask'                      : transformers.AutoModelForMaskedLM,
#     'image-classification'           : transformers.AutoModelForImageClassification,
#     'image-segmentation'             : transformers.AutoModelForImageSegmentation,
#     'image-to-text'                  : transformers.AutoModelForVision2Seq,
#     'ner'                            : transformers.AutoModelForTokenClassification,
#     'object-detection'               : transformers.AutoModelForObjectDetection,
#     'question-answering'             : transformers.AutoModelForQuestionAnswering,
#     'sentiment-analysis'             : transformers.AutoModelForSequenceClassification,
#     'speech-segmentation'            : transformers.AutoModelForCTC,
#     'summarization'                  : transformers.AutoModelForSeq2SeqLM,
#     'table-question-answering'       : transformers.AutoModelForTableQuestionAnswering,
#     'text-classification'            : transformers.AutoModelForSequenceClassification,
#     'text-generation'                : transformers.AutoModelForSequenceClassification,
#     'text-to-image'                  : transformers.AutoModelForSeq2SeqLM,
#     'text2text-generation'           : transformers.AutoModelForSeq2SeqLM,
#     'token-classification'           : transformers.AutoModelForTokenClassification,
#     'translation'                    : transformers.AutoModelWithLMHead,
#     'translation_xx_to_yy'           : transformers.AutoModelForSeq2SeqLM,
#     'zero-shot-classification'       : transformers.AutoModelForSequenceClassification,
#     None                             : transformers.AutoModelForSequenceClassification,
# }

# This convoluted approach makes it possible to use older versions of
# transformers that do not support all of these auto models

my_task_to_auto_class = {
    'ASR'                            : 'AutoModelForCTC',
    'MT'                             : 'AutoModelWithLMHead',
    'QA'                             : 'AutoModelForQuestionAnswering',
    'audio-classification'           : 'AutoModelForAudioClassification',
    'automatic-speech-recognition'   : 'AutoModelForCTC',
    'classify'                       : 'AutoModelForSequenceClassification',
    'classify_spans'                 : 'AutoModelForQuestionAnswering',
    'classify_tokens'                : 'AutoModelForTokenClassification',
    'conversational'                 : 'AutoModelForCausalLM',
    'default'                        : 'AutoModel',
    'feature-extraction'             : 'AutoFeatureExtractor',
    'fill-mask'                      : 'AutoModelForMaskedLM',
    'image-classification'           : 'AutoModelForImageClassification',
    'image-segmentation'             : 'AutoModelForImageSegmentation',
    'image-to-text'                  : 'AutoModelForVision2Seq',
    'ner'                            : 'AutoModelForTokenClassification',
    'object-detection'               : 'AutoModelForObjectDetection',
    'question-answering'             : 'AutoModelForQuestionAnswering',
    'sentiment-analysis'             : 'AutoModelForSequenceClassification',
    'speech-segmentation'            : 'AutoModelForCTC',
    'summarization'                  : 'AutoModelForSeq2SeqLM',
    'table-question-answering'       : 'AutoModelForTableQuestionAnswering',
    'text-classification'            : 'AutoModelForSequenceClassification',
    'text-generation'                : 'AutoModelForSequenceClassification',
    'text-to-image'                  : 'AutoModelForSeq2SeqLM',
    'text2text-generation'           : 'AutoModelForSeq2SeqLM',
    'token-classification'           : 'AutoModelForTokenClassification',
    'translation'                    : 'AutoModelWithLMHead',
    'translation_xx_to_yy'           : 'AutoModelForSeq2SeqLM',
    'zero-shot-classification'       : 'AutoModelForSequenceClassification',
    None                             : 'AutoModelForSequenceClassification',
}

# for k in my_task_to_auto_class:
#     v = my_task_to_auto_class[k]
#     if hasattr(transformers, v):
#         my_task_to_auto_class[k] = getattr(transformers,v)

# infer the appropriate automodel from args (and especially the task)
def auto_model_for_X(args):
    from gft.gft_internals.my_task import infer_task
    task = infer_task(args)

    print('task: ' + str(task), file=sys.stderr)
    # task_provider,task = parse_task_specification(args)

    if task in my_task_to_auto_class:
        v = my_task_to_auto_class[task]
        if hasattr(transformers, v):
            return getattr(transformers, v)

    assert False, 'auto_model_for_X, task not supported: ' + task

def old_auto_model_for_X(args):
    from gft.gft_internals.my_task import infer_task
    task = infer_task(args)
    # print('task: ' + str(task), file=sys.stderr)

    # task_provider,task = parse_task_specification(args)

    if task is None:
        from transformers import AutoModelForSequenceClassification
        return AutoModelForSequenceClassification

    if task == 'text-to-image':
        from transformers import AutoModelForSeq2SeqLM
        return AutoModelForSeq2SeqLM

    if task == 'speech-segmentation':
        from transformers import AutoModelForCTC
        return AutoModelForCTC

    if task == 'default':
        from transformers import AutoModel
        return AutoModel

    if task == "audio-classification":
        from transformers import AutoModelForAudioClassification
        return AutoModelForAudioClassification

    if task == "ASR" or task == "automatic-speech-recognition":
        # from transformers import AutoModelForSpeechSeq2Seq
        # return AutoModelForSpeechSeq2Seq
        from transformers import AutoModelForCTC
        return AutoModelForCTC

    if task == "conversational":
        from transformers import AutoModelForCausalLM
        return AutoModelForCausalLM
        # assert False, 'auto_model_for_X, task not supported: ' + task

    if task == "feature-extraction":
        from transformers import AutoFeatureExtractor
        return AutoFeatureExtractor

    if task == "fill-mask":
        from transformers import AutoModelForMaskedLM
        return AutoModelForMaskedLM
        # assert False, 'auto_model_for_X, task not supported: ' + task

    if task == "image-classification":
        from transformers import AutoModelForImageClassification
        return AutoModelForImageClassification

    if task == "QA" or task == "question-answering":
        from transformers import AutoModelForQuestionAnswering
        return AutoModelForQuestionAnswering

    if task == "table-question-answering":
        from transformers import AutoModelForTableQuestionAnswering
        return AutoModelForTableQuestionAnswering
        # assert False, 'auto_model_for_X, task not supported: ' + task

    if task == "image-segmentation":
        from transformers import AutoModelForImageSegmentation
        return AutoModelForImageSegmentation

    if task == "object-detection":
        from transformers import AutoModelForObjectDetection
        return AutoModelForObjectDetection

    if task == "text2text-generation":
        from transformers import AutoModelForSeq2SeqLM
        return AutoModelForSeq2SeqLM
        # assert False, 'auto_model_for_X, task not supported: ' + task

    if task == "text-classification" or task == "sentiment-analysis":
        from transformers import AutoModelForSequenceClassification
        return AutoModelForSequenceClassification

    if task == "text-generation":
        from transformers import AutoModelForSequenceClassification
        return AutoModelForSequenceClassification
        # assert False, 'auto_model_for_X, task not supported: ' + task

    if task == "token-classification" or task == "ner":
        from transformers import AutoModelForTokenClassification
        return AutoModelForTokenClassification

    if task == "MT" or task == "translation":
        from transformers import AutoModelWithLMHead
        return AutoModelWithLMHead
        # from transformers import AutoModelForSeq2SeqLM
        # return AutoModelForSeq2SeqLM

    # not sure this is the right automodel for summarization
    if task == "translation_xx_to_yy" or task == "summarization":
        from transformers import AutoModelForSeq2SeqLM
        return AutoModelForSeq2SeqLM

    # not sure this is the right automodel for image-to-text
    if task == "image-to-text":
        from transformers import AutoModelForVision2Seq
        return AutoModelForVision2Seq

    if task == "zero-shot-classification":
        from transformers import AutoModelForSequenceClassification
        return AutoModelForSequenceClassification

    assert False, 'auto_model_for_X, task not supported: ' + task

def my_load_model_tokenizer_and_extractor(args, keyword='model'):
    base_model_provider, base_model_key, model_provider, model_key = parse_base_model_specification(args)

    # model_provider,model_key = parse_model_specification(args, keyword=keyword)
    # base_model_provider,base_model_key = parse_model_specification(args, keyword='base_model')
    # print('model_provider: ' + str(model_provider), file=sys.stderr)

    if model_key is None: return None,None,None

    a = my_get_adapter_info(model_key)
    print('a: ' + str(a), file=sys.stderr)
    if a is None or a.model_name is None:

        print('model_provider: ' + str(model_provider), file=sys.stderr)
        print('model_key: ' + str(model_key), file=sys.stderr)

        base_model = auto_model_for_X(args)
        print('base_model: ' + str(base_model), file=sys.stderr)

        model = base_model.from_pretrained(model_key, return_dict=True)

        tokenizer = None
        extractor = None
        try:
            if not base_model_key is None: tokenizer = my_tokenizer(base_model_key)
            else:tokenizer = my_tokenizer(model_key)
        except:
            tokenizer=None
        try:
            extractor = AutoFeatureExtractor.from_pretrained(model_key)
        except:
            extractor=None
        return model,tokenizer,extractor

    # adaptors
    m = a.model_name
    tokenizer=None
    extractor=None
    try:
        tokenizer = AutoTokenizer.from_pretrained(a.model_name)
    except:
        tokenizer=None

    try:
        extractor = AutoFeatureExtractor.from_pretrained(a.model_name)
    except:
        extractor=None

    if 'distilbert' in a.model_name:
        from transformers import DistilBertModelWithHeads
        model = DistilBertModelWithHeads.from_pretrained(a.model_name)
    elif 'bart' in a.model_name:
        from transformers import BartModelWithHeads
        model = BartModelWithHeads.from_pretrained(a.model_name)
    elif 'roberta' in a.model_name:
        from transformers import RobertaModelWithHeads
        model = RobertaModelWithHeads.from_pretrained(a.model_name)
    elif 'bert' in a.model_name:
        from transformers import BertModelWithHeads
        model = BertModelWithHeads.from_pretrained(a.model_name)
    else:
        assert False, 'my_load_model_tokenizer_and_extractor: failed for model: ' + str(a.model_name)

    print('model_key: ' + str(model_key), file=sys.stderr)
    print('a.source: ' + str(a.source), file=sys.stderr)
    model.set_active_adapters(model.load_adapter(model_key, source=a.source))
    return model,tokenizer,extractor


#%% prime or not

import time

def is_prime_v1(n):
    if n ==1:
        return False
    elif n==2:
        return True
    for i in range(2,n):
        if n % i == 0:
            return False
    return True

t0 = time.time()
for n in range(1,50000):
    print(n, is_prime_v1(n))
t1 = time.time()
print("time required:", t1-t0)

#%% using square root
import math

def is_prime_v2(n):
    if n ==1:
        return False
    if n == 2:
        return True
    if n % 2 == 0:
        return False

    max_divisor = math.floor(math.sqrt(n))+1
    for i in range(3,max_divisor,2):
        if n % i == 0:
            #print(n, i, math.floor(math.sqrt(n))+1)
            return False
    return True

t0 = time.time()
for n in range(1,1000000):
    print(n, is_prime_v2(n))
t1 = time.time()
print("time required:", t1-t0)

#%%

for i in range(3,100,2):
    print(i)


'''4. As maçãs custam R$ 1,30 cada se forem compradas menos de uma dúzia, e R$ 1,00 se forem compradas pelo menos 12 unidades. Escreva um programa que leia o número de maçãs compradas, calcule e imprima o custo total da compra.'''

maca = int(input("Quantas maças irá comprar? "))

if maca < 12:
    preco_qntd = maca * 1.30
    print(f'{maca} maças será R${preco_qntd:.2f}')
else:
    preco_mais = maca * 1
    print(f'{maca} maça será R${preco_mais:.2f}')


from collections import deque

pizzas = deque(map(int, input().split(', ')))
employees = list(map(int, input().split(', ')))
pizzas_count = 0

while pizzas and employees:

    if pizzas[0] > 10 or pizzas[0] <= 0:
        pizzas.popleft()

    elif pizzas[0] <= employees[-1]:
        pizzas_count += pizzas[0]
        employees.pop()
        pizzas.popleft()

    elif pizzas[0] > employees[-1]:
        pizzas[0] -= employees[-1]
        pizzas_count += employees[-1]
        employees.pop()

if not pizzas:
    print("All orders are successfully completed!")
    print(f"Total pizzas made: {pizzas_count}")
    print(f"Employees: {', '.join(map(str, employees))}")
else:
    print("Not all orders are completed.")
    print(f"Orders left: {', '.join(map(str, pizzas))}")

Python Advanced - септември 2022/Python - Advanced/Exams/Exam 7 - Exercises/01_pizza_orders.py


from . import LOGGER, __pixels_per_inch__
from xml.parsers import expat

size_6 = float(6)
size_10 = float(10)
size_25_4 = float(25.4)
size_72 = float(72)

def get_xml_tag_value(node):
    'Returns the valid value of xml node'
    xml_str = node.toxml()
    start = xml_str.find('>')
    if start == -1:
        return
    end = xml_str.rfind('<')
    if end < start:
        return
    res = unescape(xml_str[start + 1:end])
    return res

def unescape(s):
    # want_unicode = False
    if not isinstance(s, str):
        s = s.encode("utf-8")
    # if isinstance(s, unicode):
    #     s = s.encode("utf-8")
    #     want_unicode = True

    # the rest of this assumes that `s` is UTF-8
    list = []

    # create and initialize a parser object
    p = expat.ParserCreate("utf-8")
    p.buffer_text = True
    # p.returns_unicode = want_unicode
    p.CharacterDataHandler = list.append

    # parse the data wrapped in a dummy element
    # (needed so the "document" is well-formed)
    p.Parse("<e>", 0)
    p.Parse(s, 0)
    p.Parse("</e>", 1)

    # join the extracted strings and return
    es = ""
    # if want_unicode:
    #     es = u""
    return es.join(list)

def inch_2_mm(inch):
    '''
    Converts inches to millimeters
    '''
    return float(inch * 25.4)

def dot_2_mm(dots, pixels_per_inch=__pixels_per_inch__):
    return (dots * size_25_4) / pixels_per_inch

def point_2_mm(points):
    return float((points * size_25_4) / size_72)

def get_size_in_unit(size, unit):
    unit = unit.strip().lower()
    if unit == 'mm':
        return size

    if unit == "in":
        return size / size_25_4
    elif unit == "cm":
        return size / size_10
    elif unit == "pt":
        return int((size / size_25_4) * size_72)
    elif unit == "pc":
        return int((size / size_25_4) * size_6)
    elif unit == "dot" or 'px':
        return int((size * __pixels_per_inch__) / size_25_4)

    LOGGER.error("Unknown unit '{0}'".format(unit), True)

def get_float_rgba(c):
    return float(c) / float(65535)


import pygame.camera
import time
import pygame
import cv2
import numpy as np
path = "/mnt/myshare/linuxshare/live_"
num = 0
def surface_to_string(surface):
	"""convert pygame surface into string"""
	return pygame.image.tostring(surface, 'RGB')
def pygame_to_cvimage(surface):
	"""conver pygame surface into  cvimage"""
	#cv_image = np.zeros(surface.get_size, np.uint8, 3)
	image_string = surface_to_string(surface)
	image_np = np.fromstring(image_string, np.uint8).reshape( 1080, 1920, 3)
	frame = cv2.cvtColor(image_np, cv2.COLOR_BGR2RGB)
	return image_np, frame
pygame.camera.init()#pygame的camera模块的初始化
pygame.camera.list_cameras()#显示当前可用的camera列表
cam = pygame.camera.Camera("/dev/video0", [ 1920, 1080], MJPG) #打开camera

cam.start()#开始捕捉画面
print ('start')
time.sleep(0.1)
while True:
	for i in range(3):
		image = cam.get_image()     #获取图片
	cv_image, frame = pygame_to_cvimage(image)
	cv2.imwrite(path+str(num)+'.jpg',frame)
	num+=1
	if num>20:
		break
	print ("pic",num)
	print ("write ok")
	time.sleep(2)
cam.stop()
#https://blog.csdn.net/guofangxiandaihua/article/details/78066323


import numpy as np
import face_recognition
import cv2
import os # search os and find the function of it
from datetime import datetime
path='images'
image=[]
className=[]
myList=os.listdir(path)
print(myList)
# myLIst = ['Director_sir.png', 'elon.png', 'Nilesh_sir.png']

for cl in myList:
    curImg=cv2.imread(f'{path}/{cl}')
    image.append(curImg)
    className.append(os.path.splitext(cl)[0])
print(className)
# className = ['Director_sir', 'elon', 'Nilesh_sir']
# print(image)

def findEncodings(image):
    encodeList=[]
    for img in image:
        img=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
        encode=face_recognition.face_encodings(img)[0]
        encodeList.append(encode)
    return encodeList


import uuid
from proxy import Proxy
from resource_manager import ResourceManager
from loadbalancer.loadbalancer import LoadBalancerType
from logger import Logger

import asyncio

class Pod(Logger):
    # Memory and Storage are in MB
    def __init__(self, id, application, service_registry, proxy_egress_lb_type: LoadBalancerType, memory = 512, cpu = 100, storage = 512):
        super().__init__()
        self.id = id
        self.inflight_requests = 0
        self.resource_manager = ResourceManager(cpu=cpu, memory=memory, storage=storage)

        self.setup_proxy(application, service_registry, proxy_egress_lb_type)

        self.pending_tasks = set()

    def setup_proxy(self, application, service_registry, proxy_egress_lb_type):
        id = f'{self.id}--{uuid.uuid4()}'

        self.proxy = Proxy(id, service_registry, proxy_egress_lb_type, application.get_dependencies())
        self.proxy.set_application(application)

    async def process_worker(self, request):
        self.inflight_requests += 1
        while True:
            if self.resource_manager.reserve_cpu(30):
                try:
                    response = await self.proxy.process_ingress(request)
                finally:
                    self.resource_manager.release_cpu(30)

                self.inflight_requests -= 1

                return response
            else:
                self.log.debug(f'Inflight requests: {self.inflight_requests} - {self.id}')
                await asyncio.sleep(0.01)

    async def process(self, request):
        task =  asyncio.create_task(self.process_worker(request))
        task.add_done_callback(self.pending_tasks.discard)

        await task

        return task.result()

    def get_inflight_requests(self):
        return len(self.pending_tasks)