import json
import random
import time

from common.transaction import auto_meta_sync
from conf.dataapi_settings import BATCH_IP_RESULT_TABLE_ID
from django.utils.translation import ugettext as _

from dataflow.flow import exceptions as Errors
from dataflow.flow.api_models import ResultTable
from dataflow.flow.exceptions import FlowError
from dataflow.flow.handlers.link_rules import NodeInstanceLink
from dataflow.flow.handlers.node_factory import NODE_FACTORY
from dataflow.flow.handlers.node_utils import NodeUtils
from dataflow.flow.models import FlowInfo, FlowNodeInfo, FlowNodeInstance
from dataflow.flow.node_types import NodeTypes
from dataflow.shared.log import flow_logger as logger
from dataflow.shared.meta.project.project_helper import ProjectHelper

def call_func_with_rollback(func, params, rollback_func_info_list=None, retry=3):
    """
    调用某个指定函数，若失败则进行回滚调用
    @param func: 待调用函数引用
    @param params: 待调用函数参数，dict类型
    @param rollback_func_info_list: 回滚函数信息，按顺序回滚 e.g. [{'func': xxx, 'params': {}}], 若为空表示不用回滚
    @param retry: 重试次数
    @return:
    """
    if not rollback_func_info_list:
        rollback_func_info_list = []
    try:
        if params is None:
            return func()
        elif type(params).__name__ == "dict":
            return func(**params)
        else:
            return func(params)
    except Exception as e:
        # 回滚前先打印所有回滚信息
        logger.exception(e)
        for rollback_func_info in rollback_func_info_list:
            rollback_func = rollback_func_info["func"]
            rollback_func_name = getattr(rollback_func, "__name__")
            rollback_params = rollback_func_info["params"]
            logger.info("rollback_func_name: ({}), rollback_params: ({})".format(rollback_func_name, rollback_params))
        # 标记回滚整体是否成功
        rollback_result = True
        for rollback_func_info in rollback_func_info_list:
            rollback_func = rollback_func_info["func"]
            rollback_func_name = getattr(rollback_func, "__name__")
            rollback_params = rollback_func_info["params"]
            current_retry = 0
            # 当前回滚步骤是否成功的标记
            current_func_rollback_result = False
            logger.info(_("开始回滚: %s") % rollback_func_name)
            rollback_exception_message = ""
            while current_retry < retry and not current_func_rollback_result:
                try:
                    if rollback_params is None:
                        rollback_func()
                    else:
                        rollback_func(**rollback_params)
                    current_func_rollback_result = True
                    logger.info(_("回滚成功: %s") % rollback_func_name)
                except FlowError as rollback_exception:
                    time.sleep(1)
                    current_retry = current_retry + 1
                    rollback_exception_message = rollback_exception.message
            if current_retry >= retry:
                # 按顺序回滚，失败则停止回滚，因为回滚操作可能有依赖关系
                rollback_result = False
                logger.exception(
                    _("回滚调用(%(func_name)s)失败-%(message)s")
                    % {
                        "func_name": rollback_func_name,
                        "message": rollback_exception_message,
                    }
                )
                # 回滚列表中一个回滚失败即整体回滚失败
                break
        raise Errors.APIRollbackError(
            _("%(msg1)s%(msg2)s") % {"msg1": "" if rollback_result else "【回滚失败】", "msg2": "{}".format(e)}
        )

class NodeHandler(object):
    """
    节点控制类，所有节点的父节点，继承须知
    1. 必须重载的属性列表 [node_type, node_form, config_attrs]，
    2. 必须重载的方法列表 [build_output]
    """

    # 子类需重载属性
    node_type = None
    node_form = None
    config_attrs = []
    # TODO 这三个变量以后都优化或者删除
    storage_type = None
    default_storage_type = None
    channel_storage_type = None

    def __init__(self, node_id=None, current_node_type=None):
        if node_id is not None:
            node_id = int(node_id)
        self.node_id = node_id
        # 内部变量初始化
        self._node_info = None
        # TODO 元数据操作移到控制内
        self._meta_api_operate_list = {}
        # 标签信息
        self._manage_tags = None

    # ------------------------------- 节点核心操作流程 ------------------------------- #
    def add_node_info(self, username, flow_id, from_links, form_data, frontend_info=None):
        """
        添加节点流程
        """
        from_node_ids = [link["source"]["node_id"] for link in from_links]
        build_form_data = self.build_before(from_node_ids, form_data)

        c_params = self.build_create_params(username, flow_id, build_form_data, frontend_info)

        node = FlowNodeInfo.objects.create(**c_params)
        self.node_id = node.node_id
        self.node_info.create_or_update_link(from_links)
        # 返回表单参数，供控制类使用
        return build_form_data

    def update_node_info(self, username, from_node_ids=None, form_data=None, frontend_info=None):
        """
        更新节点流程
        """
        build_form_data = self.build_before(from_node_ids, form_data, False)
        u_params = self.build_update_params(username, build_form_data, frontend_info)
        for _k, _v in list(u_params.items()):
            setattr(self.node_info, _k, _v)
        self.node_info.save()
        return build_form_data

    def remove_node_info(self):
        """
        删除节点
        """
        self.node_info.delete()
        self._clear_node()

    def to_dict(self, add_has_modify=False, add_result_table_ids=True, add_related_flow=False):
        """
        获取节点信息
        """
        status = self.status
        if add_has_modify:
            has_modify = self.has_modify()
            if has_modify and status in FlowInfo.PROCESS_STATUS:
                status = FlowInfo.STATUS.WARNING
        else:
            has_modify = False

        node_dict = {
            "flow_id": self.flow_id,
            "node_id": self.node_id,
            "node_name": self.name,
            "node_config": self.get_config(),
            "node_type": self.node_type,
            "status": status,
            # 'version': self.version,      # 有性能下降，先忽略
            "version": "",
            "frontend_info": self.node_info.get_frontend_info(),
            "has_modify": has_modify,
        }

        if add_result_table_ids:
            node_dict["result_table_ids"] = self.result_table_ids
        if add_related_flow:
            node_dict["related_flow"] = {
                "status": self.flow.status,
                "flow_name": self.flow.flow_name,
                "project_id": self.flow.project_id,
            }
        return node_dict

    # ------------------------------- 节点通用继承函数 ------------------------------- #
    def build_before(self, from_node_ids, form_data, is_create=True):
        """
        创建、更新节点前的操作，等于 add_before 和 update_before，取决于 is_create 参数
        主要用途：
        1. 参数校验
        2. 部分节点需要从外部获取参数，并更新到 form_data
        """
        # 连线校验
        self.link_rules_check(from_node_ids, form_data, is_create)
        # 静态关联校验
        NodeHandler.kv_source_check(from_node_ids, form_data)
        # 更新节点时判断节点是否有 rt
        if not is_create:
            result_table_ids_num = len(self.result_table_ids)
            if result_table_ids_num == 0:
                raise Errors.NodeError(_("节点(id=%(node_id)s)对应的结果表不存在.") % {"node_id": self.node_id})
        return form_data

    def add_after(self, username, from_node_ids, form_data):
        """
        钩子函数，节点成功添加后回调
        @param {string} username 操作人
        @param {dict} form_data 经过校验清洗后的数据，结构与 self.config_attrs 保持一致
        @param {list} from_node_ids 父节点列表
        """
        return None

    def update_after(self, username, from_node_ids, form_data, prev=None, after=None):
        """
        钩子函数，节点成功更新后回调
        @param {dict} form_data 经过校验清洗后的数据，结构与 self.config_attrs 保持一致
        @param {list} from_node_ids 父节点列表
        @param {dict} prev 变更前的节点数据
        @param {dicr} after 变更后的节点数据
        """
        return None

    def remove_before(self, username):
        """
        钩子函数，节点删除前回调
        """
        pass

    def update_node_metadata_relation(self, bk_biz_id, result_table_ids, heads=None, tails=None):
        """
        更新节点与rt、processing等实体的关联关系
        @param bk_biz_id:
        @param result_table_ids:
        @param heads: 只有计算节点有 heads，tails 参数
        @param tails:
        """
        raise NotImplementedError("节点类型（%s）未定义update_node_relation方法." % self.node_type)

    # ------------------------------- 节点通用普通函数 ------------------------------- #
    def get_config(self, loading_latest=True):
        """
        获取节点当前配置
        """
        return self.clean_config(self.node_info.load_config(loading_latest), False)

    def build_create_params(self, username, flow_id, form_data, frontend_info=None):
        """
        组装节点的新建参数
        """
        node_type = self.node_type

        c_params = {
            "flow_id": flow_id,
            "node_name": form_data["name"],
            "node_type": node_type,
            "status": "no-start",
            "node_config": json.dumps(form_data),
            "latest_version": NodeUtils.gene_version(),
            "frontend_info": json.dumps(frontend_info),
            "created_by": username,
            "updated_by": username,
            "description": "",
        }
        return c_params

    def build_update_params(self, username, form_data, frontend_info=None):
        """
        组装节点的更新参数
        """
        u_params = {
            "node_id": self.node_id,
            "node_config": json.dumps(form_data),
            "frontend_info": json.dumps(frontend_info),
            "updated_by": username,
        }
        return u_params

    @classmethod
    def init_by_node(cls, node, current_node_type=None):
        node_handler = cls(node.node_id, current_node_type)
        node_handler._node_info = node
        return node_handler

    def get_node_type_display(self):
        """
        获取节点类型名称
        """
        if self.node_type in NodeTypes.DISPLAY:
            return NodeTypes.DISPLAY[self.node_type]
        else:
            return self.node_type

    def clean_config(self, config, is_create):
        """
        按照 cls.config_attrs 返回约定结构，可以设置部分字段的默认值，未来可以在结构中定义
        类型、默认值等属性，结合这个方法来规整 config 的返回
        """
        form = self.node_form(config, is_create=is_create)
        if not form.is_valid():
            _err_msg = "[Node Error] invalid node config, node_id={}, error={},".format(self.node_id, form.errors)
            if hasattr(form, "format_errmsg"):
                _err_msg = form.format_errmsg()
            logger.error(_err_msg)
            raise Errors.NodeValidError(_err_msg)

        form_data = form.cleaned_data

        # 避免 Form 表单解析，丢了部分关键字段，此处做了 None 值补全
        return {
            _attr: form_data[_attr] if _attr in form_data else None
            # for _attr in get_all_fields_from_form(form)
            for _attr in self.config_attrs
        }

    @classmethod
    def kv_source_check(cls, from_node_ids, form_data):
        from_node_ids_num = len(from_node_ids)
        if from_node_ids_num > 0:
            from_nodes = NodeUtils.list_from_nodes_handler(from_node_ids)
            bk_biz_ids = []
            for _n in from_nodes:
                # 除了以下两种情况，暂不支持不同业务的数据关联操作
                # 1. 上游为 kv_source 且是公有的
                # 2. 上游为 IP 库的离线数据源(TODO: 支持离线关联数据源后可能需要取消)
                if not (
                    (_n.node_type == NodeTypes.BATCH_SOURCE and _n.result_table_id in BATCH_IP_RESULT_TABLE_ID)
                    or (_n.node_type in NodeTypes.ALL_KV_SOURCE_CATEGORY and ResultTable(_n.result_table_id).is_public)
                ):
                    bk_biz_ids.append(_n.get_config(False)["bk_biz_id"])
            # 暂不支持仅公有静态关联结果表的数据关联操作
            # 即上游都是公有(1个或多个)静态关联是不允许的，不区分跨不跨业务
            # 这种情形恰好包含了 591_iplib 和 591_ipv6lib 单独作为上游离线静态关联数据源的情况
            # TODO: 到时若有结果表从私有上升为公有需要调整逻辑
            if len(set(bk_biz_ids)) < 1:
                raise Errors.NodeValidError(_("暂不支持仅公开数据的计算操作"))
            # 暂不支持所有情况下多个私有业务的数据关联操作
            if len(set(bk_biz_ids)) > 1:
                raise Errors.NodeValidError(_("暂不支持不同业务的数据关联操作"))
            # 将原始数据节点的业务 ID 传递
            # 下游业务必须继承私有的关联节点业务或普通节点业务
            # TODO: 目前公开数据只可能是 591 业务的数据，若之后出现非 591 业务的公有数据，可能需要调整逻辑
            if form_data["bk_biz_id"] not in bk_biz_ids:
                raise Errors.NodeValidError(_("出现非法业务ID(%(bk_biz_id)s)") % {"bk_biz_id": form_data["bk_biz_id"]})

    def link_rules_check(self, from_node_ids, form_data, is_create):
        node_type = self.node_type
        from_nodes = NodeUtils.list_from_nodes_handler(from_node_ids)
        from_result_table_ids = NodeUtils.get_from_result_table_ids(node_type, form_data)
        graph_from_result_table_ids = []
        if len(from_nodes) > len(from_result_table_ids):
            # 若用户为某个支持多个父节点的节点增加具有相同输入 RT 的上游节点，可能绕过下一步的校验
            # 这里确保节点数量大于上游 RT 的数量
            raise Errors.NodeValidError(_("连线配置错误，当前修改了上游节点，需要重新保存"))
        for _n in from_nodes:
            # 【2.2校验】
            _n_from_result_table_ids = _n.result_table_ids
            # 上游任意一个节点的所有rt必须至少有一个作为当前节点的接入rt
            judge_num = len(set(_n_from_result_table_ids) & set(from_result_table_ids))
            if judge_num == 0:
                raise Errors.NodeValidError(
                    _("节点(%(node_name)s)连线错误，其上游节点(%(from_node_name)s)的结果表应被当前节点指定使用%(message)s")
                    % {
                        "from_node_name": _n.name,
                        "node_name": form_data["name"],
                        "message": "" if is_create else _("，请检查节点连线配置并重新保存"),
                    }
                )
            # 收集当前节点在画布离线的所有上游节点的rt
            graph_from_result_table_ids.extend(_n_from_result_table_ids)
        # 2. 此时from_result_table_ids为旧信息，因此需要考虑两种情况
        # 2.1 当前画布连线rt列表需包含from_result_table_ids，设想一下用户删除了上游节点，然后直接启动
        if node_type not in NodeTypes.SOURCE_CATEGORY and len(
            set(graph_from_result_table_ids) & set(from_result_table_ids)
        ) < len(set(from_result_table_ids)):
            raise Errors.NodeValidError(
                _("连线错误，节点不可使用未经连线的父结果表，请重新保存节点(%(node_name)s)") % {"node_name": form_data["name"]}
            )
        # 3. 校验连线规则
        for _n in from_nodes:
            # 1. 校验上游节点可否连接到当前节点
            # 2. 校验上游节点数量、以及上游节点的下游节点数量是否符合要求
            # 取交集，只取出这个节点有用的 rt 输出, 考虑到可能会有多输出 rt，但只有其中某些被用到的情况
            _n_from_result_table_ids = list(set(_n.result_table_ids) & set(from_result_table_ids))
            NodeInstanceLink.validate_node_link(_n, self, _n_from_result_table_ids, from_nodes, is_create)

    def get_frontend_info(self):
        return self.node_info.get_frontend_info()

    def get_from_nodes_handler(self):
        return [NODE_FACTORY.get_node_handler(_id) for _id in self.from_node_ids]

    def get_to_nodes_handler(self):
        return [NODE_FACTORY.get_node_handler(_id) for _id in self.to_node_ids]

    @auto_meta_sync(using="default")
    def set_status(self, status):
        """
        设置节点状态
        @todo 设置 running 状态是，需要把当前的版本标记为 running_version
        """
        if status in [FlowInfo.STATUS.RUNNING]:
            self.node_info.running_version = self.node_info.latest_version

        self.node_info.status = status
        self.node_info.save()

    def is_new_version(self):
        """
        节点是否是增加的未启动的节点
        @return:
        """
        return not self.running_version

    def is_modify_version(self, ignore_running=False):
        """
        节点是否修改了配置，比较的标准
            1. 当前处于运行过程而与当前记录的最新版本号不同。或者由于节点使用的udf发布了新的版本，则当前节点为修改状态
            2. 节点运行过程中的上游连线发生增减(该情况不存在，因为运行节点及运行节点间连线不允许修改)
        @param ignore_running: 是否忽略节点的的运行状态比对是否是新版本
        @return:
        """
        # 检查标准1
        if (ignore_running or self.status in [FlowInfo.STATUS.RUNNING]) and (
            self.running_version != self.latest_version
            or (
                self.node_type
                in [
                    NodeTypes.STREAM,
                    NodeTypes.BATCH,
                    NodeTypes.BATCHV2,
                ]
                and NodeUtils.is_modify_dp_node_with_udf(self.processing_id)
            )
        ):
            return True
        # 检查标准2
        # 一种比较复杂的判断方式：
        #   通过获取当前节点运行版本对应的所有 version_ids，关联 reversion 获取当时的连线与现在的进行对比
        # 采用一种简单的方式：
        #   获取节点的 from_result_table_ids，与当前上游进行对比(对比方式为 from_result_table_ids 必须各属于上游节点)
        #   若 from_result_table_ids 多了表明删除了上游连线，少了表明增加了上游连线
        if ignore_running or self.status in [FlowInfo.STATUS.RUNNING]:
            from_nodes = self.get_from_nodes_handler()
            # 一条连线只能有一个输入
            len_from_nodes = len(from_nodes)
            if (
                self.node_type in NodeTypes.SOURCE_CATEGORY
                and self.node_type not in NodeTypes.NEW_FROM_RESULT_TABLE_IDS_CATEGORY
            ):
                len_from_nodes = len_from_nodes + 1
            if len(self.from_result_table_ids) != len_from_nodes:
                return True
            current_from_node_rts = []
            for from_node in from_nodes:
                current_from_node_rts.append(from_node.result_table_ids)
            for current_from_node_rt in current_from_node_rts:
                # 小于等于0是考虑上游节点可能是多输出，当前节点又是多输入
                if len(set(current_from_node_rt) & set(self.from_result_table_ids)) != 1:
                    return True
        return False

    def has_modify(self):
        """
        节点是否在运行状态下，修改了配置未重启
        """
        if self.status in [FlowInfo.STATUS.RUNNING] and self.running_revision_version is not None:
            # 比较运行版本和当前节点版本对应的 reversion_version 记录的 object_id 是否一致
            # 查看包含udf的node节点是否改为修改状态

            return self.running_revision_version != self.revision_version or (
                self.node_type
                in [
                    NodeTypes.STREAM,
                    NodeTypes.BATCH,
                    NodeTypes.BATCHV2,
                ]
                and NodeUtils.is_modify_dp_node_with_udf(self.processing_id)
            )
        return False

    def _clear_node(self):
        self.node_id = None
        self._node_info = None

    def _reset_node(self):
        self._node_info = None

    @staticmethod
    def _gene_default_link_id(node_id=None):
        """
        生成连线的端点id
        据悉，对于APP画布而言，初始化节点的时候node_id还没生成，需要一个id，之后有node_id后就不用这个id
        对于FlowAPI，可以不用生成这个id，这里为保证结构一致，也返回一个id，应尽量保持不冲突
        @param node_id:
        @return:
        """
        if node_id:
            return "ch_%s" % node_id
        else:
            return "ch_r%s" % str(random.randint(0, 9999)).zfill(4)

    def get_downstream_nodes(self, filter_node_types=None):
        """
        获取节点的所有下游节点
        @param filter_node_types: 指定特定节点类型
        @return:
        """
        arr = [self]
        nodes = {self.node_id: self}
        # 这里采用循环，主要是为了同时避免环的存在导致死循环，不建议使用递归
        arr_num = len(arr)
        while arr_num > 0:
            _n = arr.pop()
            for _to_node in _n.get_to_nodes_handler():
                if _to_node.node_id in nodes:
                    continue
                if filter_node_types and _to_node.node_type not in filter_node_types:
                    continue
                nodes[_to_node.node_id] = _to_node
                arr.append(_to_node)
        return list(nodes.values())

    def validate_upstream_config(self):
        from_result_table_ids = self.from_result_table_ids
        from_nodes = self.get_from_nodes_handler()
        if len(from_result_table_ids) < len(from_nodes):
            return False
        _from_nodes_rts = []
        for from_node in from_nodes:
            _from_node_rts = from_node.result_table_ids
            _from_nodes_rts.extend(_from_node_rts)
            # 若上游节点的 RT 不在当前节点的 from_result_table_ids 中, 增加了连线未保存
            if len(set(_from_node_rts) & set(from_result_table_ids)) == 0:
                return False
        # 若当前节点存在上游节点没有的 result_table_id, 删除了连线未保存
        if set(from_result_table_ids) - set(_from_nodes_rts):
            return False
        return True

    def get_job(self):
        """
        获取节点对应的job object
        :return:
        """
        # 一个节点对应的job，对应多个必定有问题
        _job_set = self.node_info.job_set
        if _job_set:
            if len(_job_set) > 1:
                raise Errors.NodeError(_("节点不可对应多个任务."))
            return _job_set[0]
        else:
            return None

    # ------------------------------- 通用类属性函数 ------------------------------- #

    @property
    def node_info(self):
        if self._node_info is None:
            self._node_info = FlowNodeInfo.objects.get(node_id=self.node_id)

        return self._node_info

    @property
    def flow_id(self):
        return self.node_info.flow_id

    @property
    def manage_tags(self):
        if self._manage_tags is None:
            manage_tags = ProjectHelper.get_project(self.project_id).get("tags").get("manage", {})
            self._manage_tags = manage_tags
        return self._manage_tags

    @property
    def geog_area_codes(self):
        tag_codes = [_info["code"] for _info in self.manage_tags.get("geog_area", [])]
        if not tag_codes:
            raise Errors.NodeError(_("当前任务所属项目地域信息不存在"))
        if len(tag_codes) > 1:
            raise Errors.NodeError(_("当前任务所属项目地域信息不唯一"))
        return tag_codes

    @property
    def project_id(self):
        return self.flow.project_id

    @property
    def flow(self):
        return self.node_info.flow

    @property
    def from_node_ids(self):
        return self.node_info.from_node_ids

    @property
    def to_node_ids(self):
        return self.node_info.to_node_ids

    @property
    def result_table_ids(self):
        return self.node_info.get_tail_rts()

    @property
    def from_nodes_info(self):
        """
        返回当前节点所有上游节点连线信息
        @return:
            [
                {
                    'id': 3,
                    'from_result_table_ids': ['1_xxxx']
                }
            ]
        """
        _from_nodes_info = []
        from_result_table_ids = set(self.from_result_table_ids)
        for from_node in self.get_from_nodes_handler():
            _from_nodes_info.append(
                {
                    "id": from_node.node_id,
                    "from_result_table_ids": list(set(from_node.result_table_ids) & from_result_table_ids),
                }
            )
        return _from_nodes_info

    @property
    def from_result_table_ids(self):
        """
        获取当前节点的源rt列表
        @return:
        """
        return NodeUtils.get_from_result_table_ids(self.node_type, self.get_config(False))

    @property
    def head_result_table_id(self):
        """
        获取当前节点的头部RT
        @return:
        """
        return self.node_info.get_head_rts()[0]

    @property
    def name(self):
        """
        默认取节点中文名称
        """
        _config = self.get_config(False)
        if "name" in _config:
            return _config["name"]

        return self.node_info.node_name

    @property
    def latest_version(self):
        """
        Flow 生成的特定版本号
        @return:
        """
        return self.node_info.latest_version

    @property
    def running_version(self):
        """
        Flow 生成的特定版本号
        @return:
        """
        return self.node_info.running_version

    @property
    def revision_version(self):
        """
        返回 revision 记录的版本号，即主键ID
        @return:
        """
        return self.node_info.revision_version

    @property
    def running_revision_version(self):
        """
        返回 revision 记录的版本号，即主键ID
        @return:
        """
        return self.node_info.running_revision_version

    @property
    def status(self):
        return self.node_info.status

    @property
    def display_status(self):
        if self.status == FlowInfo.STATUS.FAILURE or not self.validate_upstream_config():
            return FlowInfo.STATUS.FAILURE
        return self.status

    @property
    def is_support_debug(self):
        """
        是否支持调试
        """
        return FlowNodeInstance.get_node_instance(self.node_type)["support_debug"]

    @property
    def frontend_info(self):
        return self.node_info.get_frontend_info()

    @frontend_info.setter
    @auto_meta_sync(using="default")
    def frontend_info(self, info):
        """
        更新节点前端配置

        @param {Dict} info 新的前端配置
        """
        self.node_info.frontend_info = json.dumps(info)
        self.node_info.save(update_fields=["frontend_info"])

    @property
    def is_batch_node(self):
        """
        特指可拥有默认 HDFS 存储的节点，不包括离线数据源
        @return:
        """
        return self.node_type in [
            NodeTypes.BATCH,
            NodeTypes.BATCHV2,
            NodeTypes.MODEL_APP,
            NodeTypes.DATA_MODEL_BATCH_INDICATOR,
        ] or (
            self.node_type
            in [
                NodeTypes.MODEL,
                NodeTypes.PROCESS_MODEL,
                NodeTypes.MODEL_TS_CUSTOM,
            ]
            and self.serving_mode == "offline"
        )

    @property
    def channel_mode(self):
        """
        获取当前节点要运行起来所需要的 channel_mode
        @return:
        """
        channel_mode = "stream"
        # 当前 channel mode 用于 databus 区分是实时还是离线类型，用于判断是否创建对应的 DT(HDFS -> kafka)
        # 可认为离线 TDW 节点是需要创建这个 DT 的，因此这里若上游为离线 TDW 节点，传的是 stream
        if self.node_type == NodeTypes.BATCH_SOURCE or self.is_batch_node:
            channel_mode = "batch"
        elif self.node_type in NodeTypes.SOURCE_CATEGORY:
            # 对于数据源而言，channel_mode 设置为其它
            channel_mode = "other"
        return channel_mode

    @property
    def is_belong_to_topology_job(self):
        """
        标识当前节点若启动时，是否属于拓扑作业
        @return:
        """
        return False

    @property
    def count_freq(self):
        """
        当前节点统计频率，默认为 None
        @return:
        """
        return None

    @property
    def freq_seconds(self):
        """
        当前节点按秒的统计频率，默认为 None
        @return:
        """
        return None

    @property
    def delay_time(self):
        return 0


import streamlit  as st
import pickle
import numpy as np
pipe=pickle.load(open("pipe.pkl","rb"))
df=pickle.load(open("df.pkl","rb"))

st.title("Laptop Price Predictor")

#brand
company=st.selectbox("Brand", df["Company"].unique())

#type of laptop
type=st.selectbox("Type of laptop",df["TypeName"].unique())

#Ram
ram=st.selectbox("Ram",[2,4,6,8,12,16,24,32,64])

#Weight
weight=st.number_input("Weight of the laptop")

#Touchsecreen
touchscreen=st.selectbox("TouchScreen",["Yes","NO"])

#ips'
ips=st.selectbox("IPS",["YES","No"])

screen_size=st.number_input("Screen Size")

#Resoltution
resolution=st.selectbox("ScreenResolution",["1920*1080","1366*768","1600*900","3840*2160","3200*1800","2880*1800"
                                                                                "2560*1600"])

cpu=st.selectbox("CPU",df["CPU Brand"].unique())

hdd=st.selectbox("HDD in(GB",[0,128,256,512,1024,2048])

ssd=st.selectbox("SSD in(GB",[0,8,128,256,512,1024,1024])

Gpu=st.selectbox("GPU",df["GPU Brand"].unique())

os=st.selectbox("OS",df["OS"].unique())

if st.button("Predict Price"):
    ppi=None
    if touchscreen== "Yes":
        touchscreen=1
    else :
        touchscreen=0

    if ips=="Yes":
        ips=1
    else:
        ips=0

    x_res=int(resolution.split("*")[0])
    y_res=int(resolution.split("*")[1])
    ppi=((x_res**2)+(y_res**2))**0.5/screen_size

    quary=np.array([company,type,ram,weight,touchscreen,ips,ppi,hdd,ssd,Gpu,os,cpu])

    quary=quary.reshape(1,12)
    st.title("The Predicted Price For this Configuration is "+str(int(np.exp(pipe.predict(quary)[0]))))


import numpy as np
import torch
import torch.autograd as autograd
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torch.autograd import Variable
from torch.nn import Parameter
import math
from collections import OrderedDict
import time
import random

class load_data():
    def __init__(self, args):

        self.batch_size = args.batch
        self.data_size = args.data_size
        self.label_map = args.label_map

        self.vocab = np.load(args.source+args.vocab).item()

        fname = args.source+args.source_file
        self.source = open(fname, 'r')

        self.end_of_data = False
        self.skips = args.skips
        self.labels = args.label_map.keys()

        self.count = 0

    def reset(self):
        self.source.seek(0)
        self.count = 0
        raise StopIteration

    def __iter__(self):
        return(self)

    def __next__(self):

        data = []
        count = 0

        while True:
            line = self.source.readline()

            if line == '':
                print("end of file!")
                self.reset()
                break

            self.count += 1
            line = line.strip().split('\t')

            label = line[0]
            if len(line) < 2:
                continue
            else:
                text = line[1]

            text_list = text.split(" ")

            if len(text_list) < self.skips * 2 + 1:
                continue

            elif label in self.labels:
                count += 1

            for i in range(self.skips, len(text_list) - self.skips):

                out_text = text_list[i-self.skips:i] + text_list[i+1:i+self.skips+1]

                in_text = text_list[i]

                data.append((label, in_text, out_text))

            if count >= self.batch_size:
                break

        in_idxs, out_idxs, covars = self.create_batch(data, self.vocab)

        return in_idxs, out_idxs, covars

    def create_batch(self, raw_batch, vocab):

        #input                                                                                \

        all_txt = list(zip(*raw_batch))
        idxs = list(map(lambda w: vocab[w], all_txt[1]))
        in_idxs = Variable(torch.LongTensor(idxs).view(len(raw_batch),1), requires_grad=False)

        #output                                                                                \

        idxs = list(map(lambda output: [vocab[w] for w in output], all_txt[2]))
        out_idxs = Variable(torch.LongTensor(idxs).view(len(raw_batch), -1), requires_grad=False)

        #covariates                                                                             \

        cvrs =  list(map(lambda c: self.label_map[c], all_txt[0]))
        cvrs = Variable(torch.LongTensor(cvrs).view(len(raw_batch), -1))
        return in_idxs, out_idxs, cvrs


import discord
import os
import datetime

from dotenv import load_dotenv
from discord.ext import commands

if not os.path.exists('Polls'):
    os.makedirs('Polls')

if not os.path.exists('Giveaways'):
    os.makedirs('Giveaways')

dir_path = os.path.dirname(os.path.realpath(__file__))
load_dotenv()

def main():
    bot = commands.Bot(
        command_prefix=os.environ.get('BOT_PREFIX'),
        intents=discord.Intents.all(),
        owner_id=int(os.environ.get('BOT_OWNER_ID')),
        self_bot=False,
        activity=discord.Activity(type=1, name=f"My prefix - {os.environ.get('BOT_PREFIX')}"),
        case_insensitive=True,
        )
    bot.remove_command('help')
    for filename in os.listdir():
        if filename.endswith('.py'):
            if filename.startswith("__init__") or filename.startswith("__main__") or filename.startswith("Structure"):
                continue
            else:
                bot.load_extension(filename[:-3])
    bot.run(os.environ.get("BOT_TOKEN"))

if __name__.startswith("__main__"):
    main()
    print(datetime.datetime.now(), " Loading...")


# my task solution
def two_sort(array):
    return '***'.join((sorted(array))[0])

print(
    two_sort([
        "bitcoin", "take", "over", "the", "world", "maybe", "who", "knows",
        "perhaps"
    ]))
print(
    two_sort([
        "turns", "out", "random", "test", "cases", "are", "easier", "than",
        "writing", "out", "basic", "ones"
    ]))
print(
    two_sort(
        ["lets", "talk", "about", "javascript", "the", "best", "language"]))

# codewars task best solution
def two_sort(lst):
    return '***'.join(min(lst))

# codewars task best solution
def two_sort(a):
    a = sorted(a)
    result = "***".join(a[0])
    return result


import math
import collections
import itertools
import sys
import bisect
from heapq import heappop,heappush
sys.setrecursionlimit(10**6)
def MAP(): return list(map(int,input().split()))
def INT(): return int(input())
def FLOAT(): return float(input())
MOD = 10**9+7

n,m = MAP()
a = [INT() for _ in range(m)]

# 高速版
def fib(n):
    if n <= 1:
        return n
    result = [1, 0, 0, 1]
    matrix = [1, 1, 1, 0]
    while n > 0:
        if n % 2:
            result = mul(matrix, result)
        matrix = mul(matrix, matrix)
        n //= 2
    return result[2]

def mul(a, b):
    return [a[0]*b[0] + a[1]*b[2],
            a[0]*b[1] + a[1]*b[3],
            a[2]*b[0] + a[3]*b[2],
            a[2]*b[1] + a[3]*b[3]]

start = 0
ans = 1

for k in a:
    tmp = k-start
    if tmp==0:
        print(0)
        exit(0)
    ans *= fib(tmp)
    ans%=MOD
    start = k+1

ans*=fib(n-start+1)
ans%=MOD

print(ans)


import datetime
import pytz
import requests
import lxml.etree
from tv_schedule import schedule, dateutil

def need_channel_code():
    return False

_URL = 'http://rbctv.rbc.ru/tvprogram/%Y/%m/%d'

_source_tz = pytz.timezone('Europe/Moscow')
_daydelta = datetime.timedelta(1)

_parser = lxml.etree.HTMLParser(encoding='utf-8')

def _fetch(url):
    resp = requests.get(url)
    doc = lxml.etree.fromstring(resp.content, _parser)
    return doc[1][0][2][2][0][2][0][0]

def get_schedule(channel, tz):
    if channel != 'РБК':
        return []

    today = dateutil.tv_date_now(_source_tz, 0)
    weekday_now = today.weekday()
    sched = schedule.Schedule(tz, _source_tz)

    d = today
    for i in range(weekday_now, 7):
        sched.set_date(d)
        for row in _fetch(d.strftime(_URL)):
            sched.set_time(row[0].text)
            ev = row[1]
            title = ev.text
            a = ev[0]
            if title is None:
                title = a.text
            sched.set_title(title)
        d += _daydelta
    return sched.pop()


# №4

noun = input("Enter a noun:")
verb = input("Enter a verb:")
adjective = input("Enter an adjective:")
adverb = input("Enter an adverb:")

print("Do you", verb, "your", adjective, noun, adverb, "?", "That's hilarious!")

# Enter a noun: dog
# Enter a verb: walk
# Enter an adjective: blue
# Enter an adverb: quickly
# Do you walk your blue dog quickly? That's hilarious!


from sqlalchemy import create_engine

from tables import Base
from tables.food_entry import FoodEntry
from tables.food import Food
from tables import Session

def main():
    engine = create_engine('postgresql://emily@0.0.0.0/my_metrics')
    Base.metadata.create_all(engine)
    Session.configure(bind=engine)

    session = Session()
    foods = session.query(Food)
    foods_by_name = {}
    for food in foods:
        foods_by_name[food.name] = food

    food_entries = session.query(FoodEntry).order_by(FoodEntry.date)
    for entry in food_entries:
        food = foods_by_name[entry.name]
        entry.food = food
    session.commit()

if __name__ == '__main__':
    main()


import requests
from bs4 import BeautifulSoup
import urllib.request
import pandas as pd

def get_characterInfo(name):
    streamerName, characterName = name
    url1 = f'https://maplestory.nexon.com/N23Ranking/World/Total?c={characterName}&w=0'
    url2 = f'https://maplestory.nexon.com/N23Ranking/World/Union?c={characterName}&w=0'

    response = requests.get(url1)
    soup = BeautifulSoup(response.text, 'html.parser')
    profile = soup.select_one('.search_com_chk')

    if not profile:
        return

    className = profile.select_one('td > dl > dd').text
    level = profile.select_one('td:nth-child(3)').text.replace('Lv.', '')
    experience = profile.select_one('td:nth-child(4)').text.replace(',', '')
    popularity = profile.select_one('td:nth-child(5)').text.replace(',', '')
    image_url = profile.select_one('td > span > img:nth-child(1)')['src']
    urllib.request.urlretrieve(image_url, f'./assets/images/character/{characterName}.png')

    response = requests.get(url2)
    soup = BeautifulSoup(response.text, 'html.parser')
    profile = soup.select_one('.search_com_chk')

    if not profile:
        return

    union = profile.select_one('td:nth-child(3)').text.replace(',', '')

    character_data = {
        'streamer': streamerName,
        'nickname': characterName,
        'class': className,
        'level': int(level),
        'experience': int(experience),
        'popularity': int(popularity),
        'union': int(union),
        'image': image_url
    }

    return character_data

def gather_members(members):
    member_data_list = []
    for member in members.items():
        member_data = get_characterInfo(member)
        if member_data:
            member_data_list.append(member_data)
            print(f'{member_data["streamer"]:7} {member_data["nickname"]:7} {member_data["class"]:6} {member_data["level"]:3} {member_data["popularity"]:4} {member_data["union"]}')
        else:
            print(f'{member[0]:6} {member[1]:7} 캐럭터 정보가 없습니다')

    df_members = pd.DataFrame(data=member_data_list)
    df_members = df_members.sort_values(by=['level', 'experience'], ascending=[False, False])

    return df_members

if __name__ == '__main__':
    get_characterInfo(('삼식', '도적삼식'))


# -*- coding:utf8 -*-
print("程序运行中...")
import re
from urllib import request
import  urllib
import requests
import os
from pprint import pprint
from time import sleep
import random

from bs4 import BeautifulSoup

rooturl = "http://www.xgyw.cc/"

#获取分类连接
def getclass():
    headers = {'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8'
        ,'Host':'www.xgyw.cc','User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36'}
    header = {
        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
        "Accept-Encoding": "utf-8",
        "Accept-Language": "zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3",
        "Connection": "keep-alive",
        "Host": "www.xgyw.cc",
        "Referer": "http://www.xgyw.cc/",
        "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.90 Safari/537.36 2345Explorer/9.3.2.17331",
        "Upgrade-Insecure-Requests":"1"
    }
    #rec = re.compile('''class=lm10>\(.+)\''')
    rec = re.compile(r"class=lm10>(.+)<\/a>")
    try:
        urllib.request.Request(rooturl,headers=header)
        txt = request.urlopen(rooturl).read().decode("gbk")

        #soup = BeautifulSoup(txt)
        #li = soup.find_all("a",class_=re.compile("lm10"))

        fl = rec.findall(txt)
    except Exception as ex :
        print("错误",ex)
        sleep(2)

    print("分类：")
    pprint(fl)
    return fl

fenlei = getclass()  # 下载所有分类下的图片

#只下载推女郎
# fenlei=[getclass()[-1]]
fenlei =[fenlei[2]]

print("推女郎开始下载:"+str(fenlei))

def getpagelist():
    plist = []

    for f, n in fenlei:
        f = f.replace('\"','')
        rec = re.compile('''(/[a-zA-Z]+/page_\d+?\.html)'''.format(f))
        try:
            txt = request.urlopen(rooturl + f).read().decode("gbk")
            t = sorted(set(rec.findall(txt) + [f]))
            plist += t
        except Exception as ex:
            print("错误", ex)
            sleep(3)

    # print("page_list:")
    # pprint(plist)
    return plist

pagelist = getpagelist()
pagelist

def getalbumlist():
    albumlist = []
    for r in pagelist:
        print(rooturl + r)
        try:
            txt = request.urlopen(rooturl + r).read().decode("gbk")
            for x in re.findall(r'''href=(/(\w+)/(\2)\d+.html)''', txt):
                albumlist += [x[0]]
        except Exception as ex:
            print("getalbumlist错误",ex)
            sleep(3)
    return albumlist

albumlist = getalbumlist()

def getfphoto():
    header = {
        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
        "Accept-Encoding": "gzip, deflate, br-8",
        "Accept-Language": "zh-CN,zh;q=0.9",
        "Connection": "keep-alive",
        "Host": "www.xgyw.cc",
        "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36",
        "Upgrade-Insecure-Requests": "1",
        "Pragma":"no-cache",
        "Cache-Control":"no-cache"
    }

    for r in albumlist:
        try:
            txt = request.urlopen(rooturl + r).read().decode("gbk")
            result = re.findall(r'''(/(\w+)/(\2)\d+_?\d*.html)''', txt)
            result = tuple(set(result))
        except Exception as ex:
            print("错误：",ex)
            sleep(1)

            pass
        for x in result:
            try:
                html = request.urlopen(rooturl + x[0]).read().decode("gbk")
                jpgresult = re.findall('''src=\"(/uploadfile.*?\d+/\w+\.jpg)\"''', html)
                print(jpgresult)
            except Exception as ex:
                print("错误：",ex)
                sleep(1)
            download(jpgresult)
            # for h in jpgresult:
            #     try:
            #         urllib.request.Request(rooturl+ h, headers=header)
            #         request.urlretrieve(rooturl + h, os.path.basename(h))
            #     except Exception as ex:
            #         print("下载错误：",ex)
            #         sleep(3)

def mkdir(path):
    # 引入模块
    import os

    # 去除首位空格
    path = path.strip()
    # 去除尾部 \ 符号
    path = path.rstrip("\\")

    # 判断路径是否存在
    # 存在     True
    # 不存在   False
    isExists = os.path.exists(path)

    # 判断结果
    if not isExists:
        # 如果不存在则创建目录
        # 创建目录操作函数
        os.makedirs(path)

        print(path + ' 创建成功')
        return True
    else:
        # 如果目录存在则不创建，并提示目录已存在
        print
        path + ' 目录已存在'
        return False

robot='D:/pic/'
def download(List):
    for url in List:
        try:
            #创建中间目录
            mkdir(robot + url.split('/')[-2])
            #拼路径
            path=robot+url.split('/')[-2]+"/"+url.split('/')[-1]+url.split('/')[-1]+random.randint(0,999999).__str__()
            path = path.replace('.','')+".jpg"
            url=url.replace('\\','')
            r=requests.get(rooturl+url,timeout=30)
            r.raise_for_status()
            r.encoding=r.apparent_encoding
            if not os.path.exists(robot):
                os.makedirs(robot)
            if not os.path.exists(path):
                with open(path,'wb') as f:
                    f.write(r.content)
                    f.close()
                    print(path+' 文件保存成功')
            else:
                print('文件已经存在')
        except Exception as ex:
            print(ex)
            continue

getfphoto()


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Thu Apr  8 09:37:55 2021

@author: omartin
"""

import numpy as np
from astropy.table import Table
import matplotlib.pyplot as plt

def estimateLoopDelay(hdr):

    wssmprg  = int(hdr['WSSMPRG'])
    _,aoMode = getStagePositionWFS(hdr)

    if wssmprg == 0:
        t0 = 8000e-6
    if wssmprg == 1:
        t0 = 2600e-6
    if wssmprg == 2:
        t0 = 850e-6
    if wssmprg == 3:
        t0 = 700e-6
    if wssmprg == 4:
        t0 = 28000e-6
    if wssmprg == 5:
        t0 = 9500e-6
    if wssmprg == 6:
        t0 = 2000e-6
    if wssmprg == 7:
        t0 = 1350e-6

    # Total delays
    t8    = 40e-6
    delay = t0+t8

    if aoMode == 'NGS':
        t9        = 1e-6
        t10       = 2e-6
        textra_tt = 200e-6 # retrieved from rejection transfer function fit
        delay_tt  = t0 + t9 + t10 + textra_tt
    else:
        delay_tt  = 1e-3 #STRAP

    return delay, delay_tt

def getScale(hdr):
    """
    Returns the instrument pixel scale in mas
    """
    instName = getInstName(hdr)
    if instName == 'NIRC2':
        # Setup NIRC2 plate scales
        scales = {"NARROW": 9.942,
              "MEDIUM": 19.829,
              "WIDE": 39.686}
        return scales[hdr['CAMNAME'].upper()]

    elif instName == 'OSIRIS':
        return 9.95
    else:
        return None

def getPA(hdr):
    #theta = float(hdr['ROTPOSN']) - float(hdr['EL']) - getInstAngle(hdr)
    theta = float(hdr['ROTPOSN']) - getInstAngle(hdr)
    return theta

def getPupilMask(hdr):
    return hdr['PMSNAME']

def getTelescopeAirmass(hdr):
    el = float(hdr['EL'])
    zenithAngle = 90 - el
    airmass      = 1/np.cos(zenithAngle*np.pi/180)
    return zenithAngle,airmass

def getInstAngle(hdr):
    """
    Returns the instrument pupil position in degrees
    """
    instName = getInstName(hdr)
    if instName == 'NIRC2':
        return float(hdr['INSTANGL'])
    elif instName == 'OSIRIS':
        return float(hdr['INSTANGL']) - 42.5
    else:
        return 0

def getInstName(hdr):
    return hdr['CURRINST']

def getCentralWavelength(hdr):
    """
    Returns the central wavelength in meters
    """
    return float(hdr['CENWAVE'])*1e-6

def getGain(hdr):
    return hdr['DETGAIN']

def getFilterName(hdr):
    instName = getInstName(hdr)
    if instName == 'NIRC2':
        filter1 = hdr['fwiname']
        filter2 = hdr['fwoname']
        filt = filter1
        if (filter1.startswith('PK')):
            filt = filter2

        return filt
    elif instName == 'OSIRIS':
        f = hdr['ifilter']
        return f.split('-')[0]
    else:
        return None

def getFilterProfile(path_filter,spectral_filter):
    """
    Returns the wavelength (in microns) and the transmission for
    the specified NIRC2 filter.

    Example:
    (wave, trans) = nirc2.photometry.get_filter_profile('Kp')
    py.clf()
    py.plot(wave, trans)
    py.xlabel('Wavelength (microns)')
    py.ylabel('Transmission')
    """
    spectral_filter = spectral_filter.replace('_','')

    filters = ['J', 'H', 'K', 'Kcont', 'Kp', 'Ks', 'Lp', 'Ms',
               'Hcont', 'Brgamma', 'FeII']

    filters_upper = [x.upper() for x in filters]

    if spectral_filter.upper() not in filters_upper:
        print( 'Could not find profile for filter %s.' % spectral_filter)
        print( 'Choices are: ', filters)
        return

    spectral_filter = filters[filters_upper.index(spectral_filter.upper())]
    table = Table.read(path_filter + spectral_filter + '.dat', format='ascii')

    wavelength = table[table.colnames[0]]
    transmission = table[table.colnames[1]]

    # Lets fix wavelength array for duplicate values
    diff = np.diff(wavelength)
    idx = np.where(diff <= 0)[0]
    wavelength[idx+1] += 1.0e-7

    # Get rid of all entries with negative transmission
    idx = np.where(transmission > 1)[0]
    wavelength = wavelength[idx]
    transmission = transmission[idx] / 100.0 # convert from % to ratio

    return (wavelength*1e-6, transmission)

def getDate(hdr):
    return hdr['DATE-OBS']

def getNCPAstr(hdr):
    """
    """
    date = getDate(hdr)
    numMonth = date[5:7]
    strMonth = ''
    strYear = date[0:4]
    if numMonth == '01': pass
    elif numMonth == '02':
        strMonth = 'Feb'
    elif numMonth == '03':
        strMonth = 'March'
        strDay = date [8:10]
        NCPAstr = strDay+ strMonth + strYear + '_PD1'
    elif numMonth == '04': pass
    elif numMonth == '05': pass
    elif numMonth == '06': pass
    elif numMonth == '07': pass
    elif numMonth == '08':
        strMonth = 'Aug'
    elif numMonth == '09':
        strMonth = 'Sept'
    elif numMonth == '10': pass
    elif numMonth == '11': pass
    elif numMonth == '12': pass

    if numMonth != '03':
        NCPAstr = strMonth + '_' + strYear

    return 'NCPA_Keck_' + NCPAstr + '.fits'

def getExposureConfig(hdr):

    ittime   = hdr['ITIME']
    coadds   = hdr['COADDS']
    sampmode = hdr['SAMPMODE']
    numreads = hdr['MULTISAM']
    gain     = hdr['GAIN']
    if sampmode == 2:
        ron = 60
    else:
        ron = 15.0 * (16.0 / numreads)**0.5

    return ittime,coadds,sampmode,numreads,ron,gain

def samplingFilterProfile(path_filter,hdr,nWvl=3,thresold=0.9,bwMin = 100e-9,display=False):
    """
    """
    # reading the .dat file
    instName = getInstName(hdr)
    (wvl_all,tr_all)= getFilterProfile(path_filter,getFilterName(hdr))
    # fitting the transmission curve
    id_f    = tr_all > thresold*tr_all.max()
    tr_f    = tr_all[id_f]
    wvl_f   = wvl_all[id_f]
    # linear regression
    p       = np.polyfit(wvl_f,tr_f,1)
    tr_f    = np.polyval(p,wvl_f)
    # compressing the profile for PSF fitting; more bins means longer PSF model computation
    wvlMin = wvl_f.min()
    wvlMax = wvl_f.max()
    bw     = wvlMax - wvlMin
    # consider a monochromatic filter if the bandwith is smaller than the threshold
    if bw <= bwMin:
        nWvl = 1
    # perform the linear regression on the desired wavelengths
    if nWvl > 1:
        wvl_c  = np.linspace(wvlMin,wvlMax,nWvl)

    elif nWvl <=1:
         wvl_c  = np.array([getCentralWavelength(hdr)])
         bw     = 0.0
    tr_c   = np.polyval(p,wvl_c)

    # assumption : no chromatic dispersion
    disp = [list(np.zeros(nWvl)),list(np.zeros(nWvl))]

    if display:
        # plotting
        plt.figure(figsize=(7,7))
        plt.plot(wvl_all*1e6,tr_all,'b',label='True profile')
        plt.plot(wvl_f*1e6,tr_f,'r',label='Fitted profile')
        plt.plot(wvl_c*1e6,tr_c,'ks',label='Compressed profile')
        plt.xlabel('Wavelength [µm]')
        plt.ylabel('Transmission')
        plt.title(instName+' filter transmission')
        plt.legend()

    return wvl_c, bw, tr_c, disp

def getSaturationLevel(instName):
        """
        Set to the 95% saturation threshold in DN.
        """
        if instName == 'NIRC2':
            return 12000.0
        elif instName == 'OSIRIS':
            return 20000.0
        else:
            return np.inf

def getStagePositionWFS(hdr):
    """

    """
    OBWF   = float(hdr['OBWF'])
    LSPROP = hdr['LSPROP'].upper()
    if LSPROP == 'YES':
        aoMode = 'LGS'
        AOFCLGFO    = float(hdr['AOFCLGFO'])*1e3 #mm
        zstage_defocus = abs(OBWF - AOFCLGFO)
    else:
        aoMode = 'NGS'
        AOFCNGFO    = float(hdr['AOFCNGFO'])*1e3
        zstage_defocus = abs(OBWF - AOFCNGFO)

    return zstage_defocus, aoMode

def getWFSwavelength(hdr):
    return float(hdr['GUIDWAVE'])*1e-6


# 将输入的句子反转
def sentencewordreverse(sentence):
    # 切分单词到列表
    word_token = sentence.split()
    # 列表反转
    word_token.reverse()
    # 列表转化成句子
    sentencerevesed = ' '.join(word_token)
    return sentencerevesed

if __name__ == '__main__':
    sentence = 'Today is Tuesday'
    print(sentencewordreverse(sentence))


import sys

file = open(sys.argv[1] , 'r' , encoding = 'big5hkscs')
dictionary = dict()
for line in file:
	temp = line.split()
	character = temp[0]
	Zhuyin_list = temp[1].split('\\')
	for Zhuyin in Zhuyin_list:
		if Zhuyin[0] not in dictionary:
			dictionary[Zhuyin[0]] = set()
		dictionary[Zhuyin[0]].add(character)

file = open(sys.argv[2] , 'w' , encoding = 'big5hkscs')
for (Zhuyin , character_set) in dictionary.items():
	character_list = list(character_set)
	print(Zhuyin + '\t' + ' '.join(character_list) , file = file)
	for character in character_list:
		print(character + '\t' + character , file = file)


from sympy import *

def deriv(func):
    x = Symbol('x')
    y = x ** 3
    derivative_y = y.diff(x)
    new_f = lambdify(x, derivative_y)
    return lambda res: func(new_f(res))

print(deriv(lambda x: x)(5))


from string import ascii_lowercase
from string import ascii_uppercase
from string import ascii_letters

import itertools
import statistics
from statistics import mode

with open ('day3_input.txt') as file:
    data = file.read().split("\n")

#print (data)
match=[]

for line in data:
    half = len(line)//2  #find half

    left = set (line[:half])  # left half, distinct letters
    right = set (line[half:]) # right half, distinct letters

    for i in left:
        if i in right :
            match.append(i)
            #print (match)

def alphabet_position_lower(letter):
    nums = [str(ord(x) - 96) for x in letter.lower() if x >= 'a' and x <= 'z']
    match_letter_sum.append(nums)
    return " ".join(nums)

def alphabet_position_upper(letter):
    nums = [str(ord(x) - 64 + 26) for x in letter.upper() if x >= 'A' and x <= 'Z']
    match_letter_sum.append(nums)
    return " ".join(nums)

listToStr = ' '.join([str(elem) for elem in match]) #convert list into string so we can pass it to the function

#print(alphabet_position(listToStr))
#print(alphabet_position_upper('P'))

match_letter_sum=[]

for i in listToStr:
    if i.isupper():
        alphabet_position_upper(i)
    else:
        alphabet_position_lower(i)

#print (match_letter_sum)

def flatten(l):
    flatList = []
    for elem in l:
        # if an element of a list is a list
        # iterate over this list and add elements to flatList
        if type(elem) == list:
            for e in elem:
                flatList.append(e)
        else:
            flatList.append(elem)
    return flatList

total=0

for ele in flatten(match_letter_sum):
    total   += int(ele)

# printing total value
print("Part 1 answer: ", total)

#Part2

#create a group. first three lines is one group
j=3
total=0

for i in range (0, len(data),3):
    rucksacs = data [i:j]
    j+=3
    for priority, char in enumerate(ascii_letters):
        if char in rucksacs[0] and char in rucksacs[1] and char in rucksacs[2]:
            total +=priority+1

print("Part 2 answer: ", total)


import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MinMaxScaler
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from bokeh.plotting import figure, show
from bokeh.io import output_file

data = pd.DataFrame({'Moleküler Ağırlık': [18.015, 44.01, 16.042, 28.97, 2.016, 32.00],
                     'Yoğunluk': [0.998, 1.977, 0.717, 1.429, 0.0899, 1.429],
                     'Kaynama Noktası (K)': [373.15, 216.58, 111.66, 59.15, 20.28, 161.49]})

X = data[['Moleküler Ağırlık', 'Yoğunluk']].values
y = data['Kaynama Noktası (K)'].values

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

scaler = MinMaxScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

model = Sequential()
model.add(Dense(32, activation='relu', input_shape=(2,)))
model.add(Dense(16, activation='relu'))
model.add(Dense(1))

model.compile(optimizer='adam', loss='mean_squared_error')

model.fit(X_train_scaled, y_train, epochs=500, batch_size=4,verbose=0)

y_pred = model.predict(X_test_scaled)

output_file("Tensorflow Library for Boiling Point.html")
p = figure(title="Gerçek Kaynama Noktası ve Tahminleri",
           x_axis_label="Gerçek Kaynama Noktası (K)",
           y_axis_label="Tahmin Edilen Kaynama Noktası (K)",
           width=600, height=400)

p.circle(y_test, y_pred[:, 0], size=8, color="blue", legend_label="Tahminler")
p.line([0, 400], [0, 400], color="red", legend_label="Ideal Çizgi")

p.legend.location = "top_left"
show(p)


import telebot
from telebot import types
import psycopg2
import os
import json
import keyB
conn = psycopg2.connect(host='',
                        dbname='',
                        user='',
                        password='')
curs = conn.cursor()

bot = telebot.TeleBot("")

####################################находится ли id в определённом состоянии################################
def check(conditions, my_id):
	try:
		curs.execute("SELECT cond FROM users WHERE user_id = %s;",(my_id,))
		if (curs.fetchall()[0][0]) == conditions:
			return True
	except:
		pass

	return False
##################################есть ли данные###########################################################
def if_NULL(my_id):
	try:
		curs.execute("SELECT struc FROM users WHERE user_id = %s;",(my_id,))
		if curs.fetchone()[0] == '':
			return True
	except:
		return True
	return False

##########################################существует ли запись с таким id###################################
def exist(my_id):
	try:
		curs.execute("SELECT cond FROM users WHERE user_id = %s;",(my_id,))
		if curs.fetchone() == None:
			return False
		return True
	except:
		return False
#############################################приветствие####################################################
@bot.message_handler(commands=["start", "старт"])
def hello(message):
	bot.send_message(message.chat.id, """Привет, человек. Я помогу тебе составить программу тренировок.
		\nИспользуй клавиатуру\nЕё можно вызвать, воспользовавшись данной икнонкой.""",reply_markup=keyB.fkey())
	bot.send_photo(message.chat.id,'AgADAgADqqoxG70o6UktvVCAeVodcOjAtw4ABMgBwsHs5MEc6bIAAgI')

# @bot.message_handler(commands=['test'])
# def find_file_ids(message):
#     for file in os.listdir('img/'):
#         if file.split('.')[-1] == 'jpg':
#             f = open('img/'+file, 'rb')
#             msg = bot.send_photo(message.chat.id, f, None)
#             bot.send_message(message.chat.id, msg.photo, reply_to_message_id=msg.message_id)
#         time.sleep(3)

#####################################добавление данных в бд#################################################
@bot.message_handler(func=lambda message:  True and message.text == 'Добавить данные', content_types = ['text'])
def add_date1(message):
	if if_NULL(message.chat.id) == True:
		bot.send_message(message.chat.id,"""следующее твоё сообщение будет добавлено в базу данных\nВведи вес: """)
		curs.execute("INSERT INTO users VALUES (%s,%s,%s,%s,%s,%s,%s);",([message.chat.id,'NULL','NULL','NULL','NULL','NULL','weight']))
		conn.commit()
	else:
		bot.send_message(message.chat.id,"твои данные уже существуют, просто обнови их")

@bot.message_handler(func=lambda message: check('weight',message.chat.id), content_types = ['text'])
def add_date2(message):
	if message.text.isdecimal() == True:
		#тут нужно сделать проверку на нормальность данных
		curs.execute("UPDATE users SET weight = %s WHERE user_id = %s;",(message.text, message.chat.id))
		conn.commit()
		curs.execute("UPDATE users SET cond = %s WHERE user_id = %s;",('height', message.chat.id))
		conn.commit()
		bot.send_message(message.chat.id,"""Окей, теперь введи рост""")
	else:
		bot.send_message(message.chat.id,"""Просто введи цифру""")

@bot.message_handler(func=lambda message: check('height',message.chat.id), content_types = ['text'])
def add_date3(message):
	if message.text.isdecimal() == True:
		#тут нужно сделать проверку на нормальность данных
		curs.execute("UPDATE users SET height = %s WHERE user_id = %s;",(message.text, message.chat.id))
		conn.commit()
		curs.execute("UPDATE users SET cond = %s WHERE user_id = %s;",('age', message.chat.id))
		conn.commit()
		bot.send_message(message.chat.id,"""Окей, теперь введи возраст""")
	else:
		bot.send_message(message.chat.id,"""Просто введи цифру""")
@bot.message_handler(func=lambda message: check('age',message.chat.id), content_types = ['text'])
def add_date4(message):
	if message.text.isdecimal() == True:
		#тут нужно сделать проверку на нормальность данных
		curs.execute("UPDATE users SET age = %s WHERE user_id = %s;",(message.text, message.chat.id))
		conn.commit()
		curs.execute("UPDATE users SET cond = %s WHERE user_id = %s;",('gender', message.chat.id))
		conn.commit()
		bot.send_message(message.chat.id,"""Окей, теперь введи свой пол - М или Ж""")
	else:
		bot.send_message(message.chat.id,"""Просто введи цифру""")

@bot.message_handler(func=lambda message: check('gender',message.chat.id), content_types = ['text'])
def add_date5(message):
	if message.text in ['М','Ж']:
		#тут нужно сделать проверку на нормальность данных
		curs.execute("UPDATE users SET gender = %s WHERE user_id = %s;",(message.text, message.chat.id))
		conn.commit()
		curs.execute("UPDATE users SET cond = %s WHERE user_id = %s;",('struc', message.chat.id))
		conn.commit()
		bot.send_message(message.chat.id,"""окей теперь укажи телосложение - Эктоморф, Мезоморф или Эндоморф""")
		bot.send_photo(message.chat.id, 'AgADAgADIqkxG3uG6UlV_1oyJvtIUUhPqw4ABOPJmzjzR-ZIFzUDAAEC')
	else:
		bot.send_message(message.chat.id,"""Введи данные правильно \n- М или Ж  """)

@bot.message_handler(func=lambda message: check('struc',message.chat.id), content_types = ['text'])
def add_date6(message):
	if message.text in ['Эктоморф','Мезоморф','Эндоморф']:
	#тут нужно сделать проверку на нормальность данных
		curs.execute("UPDATE users SET struc = %s WHERE user_id = %s;",(message.text, message.chat.id))
		conn.commit()
		curs.execute("UPDATE users SET cond = %s WHERE user_id = %s;",('zero', message.chat.id))
		conn.commit()
		bot.send_message(message.chat.id,"""Готово, все твои данные созданы, ты можешь посмотреть их в основном меню""")
	else:
		bot.send_message(message.chat.id,"""Введи данные правильно \n- Эктоморф, Мезоморф или Эндоморф""")

# #################################обновление даннных в бд###################################################
@bot.message_handler(func=lambda message:  True and message.text == 'Обновить мои данные', content_types = ['text'])
def update1(message):
	if exist(message.chat.id) == True:

		keyboard = types.InlineKeyboardMarkup()
		row = []
		row.append(types.InlineKeyboardButton(text="вес", callback_data="weight"))
		row.append(types.InlineKeyboardButton(text="рост", callback_data="height"))
		row.append(types.InlineKeyboardButton(text="возраст", callback_data="age"))
		row.append(types.InlineKeyboardButton(text="пол", callback_data="gender"))
		row.append(types.InlineKeyboardButton(text="ничего", callback_data="zero"))
		row.append(types.InlineKeyboardButton(text="телосложение", callback_data="struc"))

		keyboard.add(*row)
		bot.send_message(message.chat.id, "что будем обновлять?", reply_markup=keyboard)

	else:
		bot.send_message(message.chat.id,"""тебе нечего обновлять, добавь данные""")

@bot.callback_query_handler(func=lambda call: True)
def callback_inline(call):
	if call.message:
		if call.data == "weight":
			bot.edit_message_text(chat_id=call.message.chat.id, message_id=call.message.message_id, text="""введи новый вес""")
			curs.execute("UPDATE users SET cond = %s WHERE user_id = %s;",('update_w', call.message.chat.id))
			conn.commit()
		elif call.data == "height":
			bot.edit_message_text(chat_id=call.message.chat.id, message_id=call.message.message_id, text="""введи новый рост""")
			curs.execute("UPDATE users SET cond = %s WHERE user_id = %s;",('update_h', call.message.chat.id))
			conn.commit()
		elif call.data == "age":
			bot.edit_message_text(chat_id=call.message.chat.id, message_id=call.message.message_id, text="""введи новый возраст""")
			curs.execute("UPDATE users SET cond = %s WHERE user_id = %s;",('update_a', call.message.chat.id))
			conn.commit()
		elif call.data == "struc":
			bot.edit_message_text(chat_id=call.message.chat.id, message_id=call.message.message_id, text="""введи новое телосложение""")
			bot.send_photo(call.message.chat.id, 'AgADAgADIqkxG3uG6UlV_1oyJvtIUUhPqw4ABOPJmzjzR-ZIFzUDAAEC', None)
			curs.execute("UPDATE users SET cond = %s WHERE user_id = %s;",('update_s', call.message.chat.id))
			conn.commit()
		elif call.data == "gender":
			bot.edit_message_text(chat_id=call.message.chat.id, message_id=call.message.message_id, text="""введи новый пол (ты просто ошибся, когда заполнял данные, да?)""")
			curs.execute("UPDATE users SET cond = %s WHERE user_id = %s;",('update_g', call.message.chat.id))
			conn.commit()
		elif call.data == "zero":
			bot.edit_message_text(chat_id=call.message.chat.id, message_id=call.message.message_id, text="""Окей, что-то ещё?""")
			curs.execute("UPDATE users SET cond = %s WHERE user_id = %s;",('zero', call.message.chat.id))
			conn.commit()

@bot.message_handler(func=lambda message: check('update_w',message.chat.id), content_types = ['text'])
def update_2(message):
	if message.text.isdecimal() == True:
		curs.execute("UPDATE users SET weight = %s WHERE user_id = %s;",(message.text, message.chat.id))
		conn.commit()
		curs.execute("UPDATE users SET cond = %s WHERE user_id = %s;",('zero', message.chat.id))
		conn.commit()
		bot.send_message(message.chat.id,"""Отлично, мы обновили твой вес""")
	else:
		bot.send_message(message.chat.id,"""Просто введи цифру""")
@bot.message_handler(func=lambda message: check('update_h',message.chat.id), content_types = ['text'])
def update_3(message):
	if message.text.isdecimal() == True:
		curs.execute("UPDATE users SET height = %s WHERE user_id = %s;",(message.text, message.chat.id))
		conn.commit()
		curs.execute("UPDATE users SET cond = %s WHERE user_id = %s;",('zero', message.chat.id))
		conn.commit()
		bot.send_message(message.chat.id,"""Отлично, мы обновили твой рост""")
	else:
		bot.send_message(message.chat.id,"""Просто введи цифру""")

@bot.message_handler(func=lambda message: check('update_a',message.chat.id), content_types = ['text'])
def update_4(message):
	if message.text.isdecimal() == True:
		curs.execute("UPDATE users SET age = %s WHERE user_id = %s;",(message.text, message.chat.id))
		conn.commit()
		curs.execute("UPDATE users SET cond = %s WHERE user_id = %s;",('zero', message.chat.id))
		conn.commit()
		bot.send_message(message.chat.id,"""Отлично, мы обновили твой возраст""")
	else:
		bot.send_message(message.chat.id,"""Просто введи цифру""")

@bot.message_handler(func=lambda message: check('update_s',message.chat.id), content_types = ['text'])
def update_5(message):
	if message.text in ['Эктоморф','Мезоморф','Эндоморф']:
		curs.execute("UPDATE users SET struc = %s WHERE user_id = %s;",(message.text, message.chat.id))
		conn.commit()
		curs.execute("UPDATE users SET cond = %s WHERE user_id = %s;",('zero', message.chat.id))
		conn.commit()
		bot.send_message(message.chat.id,"""Отлично, мы обновили твоё телосложение""")
	else:
		bot.send_message(message.chat.id,"""Введи данные правильно \n- Эктоморф, Мезоморф или Эндоморф""")

@bot.message_handler(func=lambda message: check('update_g',message.chat.id), content_types = ['text'])
def update_6(message):
	if message.text in ['М','Ж']:
		curs.execute("UPDATE users SET gender = %s WHERE user_id = %s;",(message.text, message.chat.id))
		conn.commit()
		curs.execute("UPDATE users SET cond = %s WHERE user_id = %s;",('zero', message.chat.id))
		conn.commit()
		bot.send_message(message.chat.id,"""Мы обновили твой пол...""")
	else:
		bot.send_message(message.chat.id,"""Введи данные правильно \n- М или Ж  """)

@bot.message_handler(func = lambda message: True and message.text == 'Показать мои данные', content_types = ['text'])
def show1(message):
	if if_NULL(message.chat.id) == False:
		curs.execute("SELECT weight, height, age, gender, struc from users WHERE user_id = %s;",(message.chat.id,))
		date = curs.fetchone()
		bot.send_message(message.chat.id,"Твои данные:\n\n"+"вес: "+str(date[0])+"\n"+"рост: "+str(date[1])+"\n"+"возраст: "+str(date[2])+"\n"+"пол: "+str(date[3])+"\n"+
										 "телосложение: "+str(date[4])+"\n")
	else:
		bot.send_message(message.chat.id,"твои данных ещё не существует, используй /add или /update")

@bot.message_handler(func=lambda message:  check('zero',message.chat.id) and message.text == 'Найти программу', content_types = ['text'])
def find_program(message):
	curs.execute("SELECT gender, struc from users WHERE user_id = %s;",(message.chat.id,))
	date = curs.fetchone()
	json_date  = []

	path_to_json = 'prog/'+date[0]+"/"+date[1]+"/"
	if  os.listdir(path_to_json) !=[]:
		json_files = [ x for x in os.listdir(path_to_json) if x.endswith("json") ]
		json_data = list()
		for json_file in json_files:
			json_file_path = os.path.join(path_to_json, json_file)
			with open (json_file_path, "r", encoding='utf-8') as f:
				bot.send_message(message.chat.id,  json.load(f)['text'])
	else:
		bot.send_message(message.chat.id,"Пока для таких параметров нет программы, попробуй использовать что-то ещё")

@bot.message_handler(func=lambda message:  check('zero',message.chat.id) and message.text == 'Как пользоваться ботом?', content_types = ['text'])
def hepl(message):
	keyboard = types.InlineKeyboardMarkup()
	row = []
	row.append(types.InlineKeyboardButton(text="поодержать в QIWI", url = 'https://qiwi.me/3282c84e-7c67-4f14-8037-9d770ff3d56b'))
	keyboard.add(*row)
	bot.send_message(message.chat.id, """Добавь в бота данные о себе и найди программу тренировок!\nДля связи с ботом ты можешь использовать клавиатуру, которая вызывается соответсвующей икнокой (рядом со скрепочкой над клавиатурой) некоторые разделы бота до сих пор находится в разработке. \n\nЕсли у тебя есть идеи или пожелания - пиши: @Nickolas_510\n\n
		Если ты хочешь поодержать проект деньгами""",reply_markup=keyboard)

#############################################################################################################
#Добавить статистику прогресса из json-бэкапов

if __name__ == "__main__":
    bot.polling(none_stop=True)


"""
Your goal in this kata is to implement a difference function, which subtracts one list from another and returns the result.

It should remove all values from list a, which are present in list b keeping their order.
"""

def array_diff(a: list, b: list):
    new_list = []
    for num in a:
        if len(a) == 0 and len(b) != 0:
            return []
        elif len(a) != 0 and len(b) == 0:
            return a
        if num in b:
            continue
        new_list.append(num)
    return new_list

print(array_diff([1, 2], [1]))


import csv
import time_utils
import networkx as nx

def graph_establishments(sampleSize, graph):
    # open the file distance data file
    print("Parsing establishment data...")
    with open('data/establishments.csv', encoding="utf8") as csvEstablishments:
        # read the file
        reader = csv.reader(csvEstablishments)
        # skip the header
        next(reader, None)
        # read the rest of the data
        acc = 0
        for row in reader:
            if acc > sampleSize-1:
                break
            acc+=1
            graph.add_node(
                int(row[0]),
                pred= -1,
                district=row[1],
                county=row[2],
                parish=row[3],
                address=row[4],
                latitude=float(row[5]),
                longitude=float(row[6]),
                inspectionUtility=float(row[7]), # urgência --> para desempate
                inspectionDuration=float(row[8])*60, # minutes to seconds
                openingHours=row[9]
            )

    print("Parsing distance data...")
    with open('data/distances.csv', encoding="utf8") as csvDistances:
        # read the file
        reader = csv.reader(csvDistances)

        for i, row in enumerate(reader):
            if i == 0:
                continue
            if i > sampleSize:
                break
            node1 = i-1  # Get the first node id
            for j, val in enumerate(row[1:]):
                if j > sampleSize - 1:
                    break
                else:
                    node2 = j  # Get the second node id
                    travelTime = float(val) # seconds
                    graph.add_edge(node1, node2, travelTime= time_utils.seconds_to_string(travelTime))  #! os travel times sao guardados como string, usar time_utils.time_to_seconds() para converter para segundos
    print("Data parsed successfully!")
    return 0


# -*- coding: utf-8 -*-

__author__ = 'Douglas Uba'
__email__  = 'douglas.uba@inpe.br'

import goes, goes.downloader
from PyQt5 import uic
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import s3fs

class Downloader(QWidget):
    def __init__(self):
        super(Downloader, self).__init__()
        # Load user-interface from ui file
        uic.loadUi('./ui/downloader.ui', self)

        # Setup buckets
        for bucket in goes.BUCKETS:
            self.satelliteComboBox.addItem(bucket)

        # Define default bucket
        self.bucket = goes.BUCKETS['GOES-16']

        # Populate hours
        for hour in goes.HOURS:
            item = QListWidgetItem(hour, self.hourListWidget, Qt.ItemIsUserCheckable);
            item.setCheckState(Qt.Checked)

        # Populate channels
        for channel in goes.CHANNELS:
            item = QListWidgetItem(channel, self.channelListWidget, Qt.ItemIsUserCheckable);
            item.setCheckState(Qt.Checked)

        # Flag that indicates if selected product is channel-separated
        self.hasChannels = True

        # Setup initial dates
        now = QDate.currentDate()
        self.startDateTimeEdit.setDate(now)
        self.endDateTimeEdit.setMaximumDate(now)
        self.endDateTimeEdit.setDate(now)

        # Setup output directory
        self.outputDirectoryLineEdit.setText(QDir.currentPath())

        # Signals & slots
        self.satelliteComboBox.currentTextChanged[str].connect(self.__onSatelliteComboBoxChanged)
        self.productsCheckBox.stateChanged.connect(self.__onProductsCheckBoxChanged)
        self.hoursCheckBox.stateChanged.connect(self.__onHoursCheckBoxChanged)
        self.channelsCheckBox.stateChanged.connect(self.__onChannelsCheckBoxChanged)
        self.outputDirectoryPushButton.released.connect(self.__onOutputDirectoryPushButtonReleased)
        self.downloadPushButton.released.connect(self.__onDownloadPushButtonReleased)

        # Connection with S3 GOES-16 AWS file system
        self.fs = s3fs.S3FileSystem(anon=True)

        # Fill product list
        self.__fillProducts()

    def __fillProducts(self):
        self.productListWidget.clear()
        for product in self.fs.ls(self.bucket):
            if 'index.html' not in product:
                item = QListWidgetItem(product, self.productListWidget, Qt.ItemIsUserCheckable);
                item.setCheckState(Qt.Unchecked)
        self.productListWidget.setCurrentRow(0)

    def __onSatelliteComboBoxChanged(self, satellite):
        self.bucket = goes.BUCKETS[satellite]
        self.__fillProducts()

    def __onProductsCheckBoxChanged(self, state):
        for i in range(self.hourListWidget.count()):
            self.productListWidget.item(i).setCheckState(state)

    def __onHoursCheckBoxChanged(self, state):
        for i in range(self.hourListWidget.count()):
            self.hourListWidget.item(i).setCheckState(state)

    def __onChannelsCheckBoxChanged(self, state):
        for i in range(self.channelListWidget.count()):
            self.channelListWidget.item(i).setCheckState(state)

    def __onOutputDirectoryPushButtonReleased(self):
        self.outputDirectoryLineEdit.setText(
            QFileDialog.getExistingDirectory(self, 'Output Directory', '.')
        )

    def __onDownloadPushButtonReleased(self):
        # Verify selected products
        products = self.__getSelectedItems(self.productListWidget)
        if not products:
            QMessageBox.information(self, 'Information',
                'Please, select at least one product.'
            )
            self.productListWidget.setFocus()
            return

        # Verify selected hours
        hours = self.__getSelectedItems(self.hourListWidget)
        if not hours:
            QMessageBox.information(self, 'Information',
                'Please, select at least one hour.'
            )
            self.hourListWidget.setFocus()
            return

        # Verify selected channels
        channels = self.__getSelectedItems(self.channelListWidget)
        if self.hasChannels and not channels:
            QMessageBox.information(self, 'Information',
                'Please, select at least one channel.'
            )
            self.channelListWidget.setFocus()
            return

        # Verify output directory
        output =  self.outputDirectoryLineEdit.text()
        if not output:
            QMessageBox.information(self, 'Information',
                'Please, select a directory to save files.'
            )
            self.outputDirectoryLineEdit.setFocus()
            return

        # Get selected dates
        start = self.startDateTimeEdit.date().toPyDate()
        end = self.endDateTimeEdit.date().toPyDate()

        progress = ProgressDialog(self)

        # Start search and download
        download = ProcessRunnable(target=goes.downloader.download,
                        args=(self.bucket, products, start, end, hours, channels, output, progress))

        download.start()

        progress.exec()

    def __getSelectedItems(self, listWidget):
        values = []
        for i in range(listWidget.count()):
            item = listWidget.item(i)
            if item.checkState():
                values.append(item.text())
        return values

class ProgressDialog(QDialog):
    def __init__(self, parent=None):
        super(ProgressDialog, self).__init__(parent=parent)
        # Load user-interface from ui file
        uic.loadUi('./ui/progress.ui', self)
        # Flag that indicates if process was canceled
        self.canceled = False
        # Signal & slots
        self.cancelPushButton.released.connect(self.onCancelPushButtonReleased)

    @pyqtSlot(int)
    def onStartDownloadTask(self, numberOfFiles):
        self.progressBar.setMaximum(numberOfFiles)
        self.progressBar.setValue(0)

    @pyqtSlot(str)
    def onStartFileDownload(self, file):
        self.__appendText(('- Downloading {}'.format(file.split('/')[-1])))

    @pyqtSlot(str)
    def onEndFileDownload(self, file):
        self.__appendText(('* Finished -> {}'.format(file)))
        self.progressBar.setValue(self.progressBar.value() + 1)

    @pyqtSlot()
    def onEndDownloadTask(self):
        self.__appendText('Done!')
        self.progressBar.setValue(self.progressBar.maximum())
        QApplication.restoreOverrideCursor()

    def onCancelPushButtonReleased(self):
        self.canceled = True
        self.__appendText('\n*** Aborting. Please, wait... ***')
        self.cancelPushButton.setDisabled(True)
        QApplication.setOverrideCursor(Qt.WaitCursor)

    def wasCanceled(self):
        return self.canceled

    def __appendText(self, text):
        self.notificationPlainTextEdit.appendPlainText(text)
        scrool = self.notificationPlainTextEdit.verticalScrollBar()
        scrool.setValue(scrool.maximum())

class ProcessRunnable(QRunnable):
    def __init__(self, target, args):
        QRunnable.__init__(self)
        self.t = target
        self.args = args
        self.setAutoDelete(True)

    def __del__(self):
        QThreadPool.globalInstance().waitForDone()

    def run(self):
        self.t(*self.args)

    def start(self):
        QThreadPool.globalInstance().start(self)


from PyQt4 import QtGui, QtCore

from forms.ulam.form import Ui_FormUlam
from forms.sacks.form import Ui_FormSacks
from forms.cloud.form import Ui_FormCloud
from forms.pcomplex.form import Ui_FormComplex
from forms.simple_grid.form import Ui_FormSimpleGrid
from forms.wireframe.form import Ui_FormWireframe

import forms.ulam.handler as ulam_handler
import forms.sacks.handler as sacks_handler
import forms.cloud.handler as cloud_handler
import forms.pcomplex.handler as complex_handler
import forms.simple_grid.handler as sg_handler
import forms.wireframe.handler as wireframe_handler

class FormWrapper(QtGui.QWidget):
    """Wrapper class for setting up a form as a Qt widget and tying it to a name.

    Extends QWidget.
    """
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)
        self.name = None
        self.form = None

    def set_form(self, name, form):
        self.name = name
        self.form = form
        self.form.setupUi(self)

class FormHandler():
    """Handles the forms for all of the different visualisations.

    The reasoning  was that since each  visualisation has differing settings, it
    seemed pertinent to dynamically load individual forms for each one.
    This class can set up forms, call a connection function from individual form
    handlers which sets up Slots/Signals for the form itself, retrieve data from
    these forms and remove the forms from the parent ui element.
    Each form itself has a corresponding module with a form.py file, which holds
    the boilerplate for the widget itself, and a handler.py which each contain a
    connection and retrieve function. These two functions  are both very similar
    throughout  all  different forms, and therefore the   functionality of these
    modules is implicit based on documentation in this class.

    Arguments:
        parent -- A Qt widget in which to place the form

    Attributes:
        form_handles -- A dictionary of handles to the form widgets themselves.
        form_wrapper -- The wrapper around whatever the  current form happens to
                        to be.
    """
    def __init__(self, parent):
        self.parent = parent
        self.form_handles = {"ulam": Ui_FormUlam(),
                             "sacks": Ui_FormSacks(),
                             "cloud": Ui_FormCloud(),
                             "complex": Ui_FormComplex(),
                             "simplegrid": Ui_FormSimpleGrid(),
                             "wireframe": Ui_FormWireframe()}
        self.form_wrapper = None

    def setup_form(self, name):
        """Sets up a form to be displayed in the main ui and then shows it.

        Arguments:
            name -- the name of the  form to be  displayed (this  corresponds to
                    whatever name  is  used  for  the  form  in the form_handles
                    instance variable.
        """
        self.form_wrapper = FormWrapper()
        self.form_wrapper.set_form(name, self.form_handles[name])
        self.form_wrapper.setParent(self.parent)
        self.setup_connections(name)
        self.form_wrapper.show()

    def setup_connections(self, name):
        """Sets up Qt slogs/signals for a given form.

        This is useful for  enabling/disabling elements within  the form itself,
        and bears some correspondance  to the `set_specifics' function  found in
        some (or all) Generators.

        Arguments:
            name -- the name of the form to set up connections for.
        """
        if name == "ulam":
            ulam_handler.conn(self.form_wrapper.form)
        elif name == "sacks":
            sacks_handler.conn(self.form_wrapper.form)
        elif name == "cloud":
            cloud_handler.conn(self.form_wrapper.form)
        elif name == "complex":
            complex_handler.conn(self.form_wrapper.form)
        elif name == "simplegrid":
            sg_handler.conn(self.form_wrapper.form)
        elif name == "wireframe":
            wireframe_handler.conn(self.form_wrapper.form)

    def retrieve_data(self):
        """Retrieves data from the currently loaded form.

        This is done by calling the retrieve function found in the respective
        form handle module.

        Returns:
            All the data held in the current form.
        """
        ret = None
        if self.form_wrapper:
            form = self.form_wrapper.form
            if self.form_wrapper.name == "ulam":
                ret = ulam_handler.retrieve(form)
            elif self.form_wrapper.name == "sacks":
                ret = sacks_handler.retrieve(form)
            elif self.form_wrapper.name == "cloud":
                ret = cloud_handler.retrieve(form)
            elif self.form_wrapper.name == "complex":
                ret = complex_handler.retrieve(form)
            elif self.form_wrapper.name == "simplegrid":
                ret = sg_handler.retrieve(form)
            elif self.form_wrapper.name == "wireframe":
                ret = wireframe_handler.retrieve(form)
        return ret

    def remove_form(self):
        """Removes the current form from the ui."""
        if self.form_wrapper:
            self.form_wrapper.setParent(None)
            del self.form_wrapper
            self.form_wrapper = None


import os.path

class KosarajuSCC():
    def __init__(self, file):
        dirname = os.path.dirname(__file__)
        filename = os.path.join(dirname, file)
        self.graph = dict()
        with open(filename) as f:
            for line in f:
                start, end = map(int, line.split())
                if self.graph.get(start):
                    self.graph[start].append(end)
                else:
                    self.graph[start] = [end]

    def find_scc(self):
        magical_order = self.find_magical_order()
        self.marked = [False] * (875714+1)
        self.sid = [0] * (875714+1)

        self.count = 0
        for v in magical_order:
            if not self.marked[v]:
                self.count += 1
                self.dfs_scc(self.graph, v)

        scc_size = dict()
        for cid in self.sid[1:]:
            if scc_size.get(cid):
                scc_size[cid] += 1
            else:
                scc_size[cid] = 1

        return sorted(scc_size.values(), reverse=True)[:5]

    def dfs_scc(self, graph, s):
        stack = [s]

        while len(stack) != 0:
            v = stack.pop()
            self.marked[v] = True
            self.sid[v] = self.count

            for w in graph.get(v, []):
                if not self.marked[w]:
                    stack.append(w)

    def find_magical_order(self):
        reverse_graph = self.get_reverse_graph()
        self.reverse_post_order = []
        self.marked = [False] * (875714+1)

        for vertex in reverse_graph:
            if not self.marked[vertex]:
                self.dfs(reverse_graph, vertex)

        return list(reversed(self.reverse_post_order))

    def dfs(self, graph, s):
        stack = [s]
        while len(stack) != 0:
            v = stack.pop()
            if self.marked[v]:
                self.reverse_post_order.append(v)
            else:
                self.marked[v] = True
                stack.append(v)
                for w in graph.get(v, []):
                    if not self.marked[w]:
                        stack.append(w)

    def get_reverse_graph(self):
        reverse_graph = dict()
        for start in self.graph:
            for end in self.graph[start]:
                if reverse_graph.get(end):
                    reverse_graph[end].append(start)
                else:
                    reverse_graph[end] = [start]
        return reverse_graph

if __name__ == '__main__':
    file = 'data/scc.txt'
    kosaraju = KosarajuSCC(file)
    scc = kosaraju.find_scc()
    print(scc)


# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

import logging
from odoo import api, models, _
_logger = logging.getLogger(__name__)

class ExternalSaleOrder(models.Model):
    _inherit = 'external.sale.order'

    @api.multi
    def action_crm_lead_create(self):
        self.ensure_one()
        return_item = super(ExternalSaleOrder, self).action_crm_lead_create()
        # lead_id
        if self.lead_id:
            # external_customer_id
            if self.external_customer_id and self.external_customer_id.partner_id:
                ec_p = self.external_customer_id.partner_id
                self.lead_id.ar_qt_activity_type = ec_p.ar_qt_activity_type
                self.lead_id.ar_qt_customer_type = ec_p.ar_qt_customer_type
            else:
                self.lead_id.ar_qt_activity_type = 'arelux'
                self.lead_id.ar_qt_customer_type = 'particular'
        # return
        return return_item

    @api.multi
    def action_so_done_error_esa_id_without_country_id(self):
        self.ensure_one()
        _logger.info(
            _('No se puede confirmar el pedido %s porque la direccion de envio del '
              'cliente NO tiene PAIS mapeado')
            % self.sale_order_id.name
        )

    @api.multi
    def action_so_done_error_esa_id_without_country_state_id(self):
        self.ensure_one()
        _logger.info(
            _('No se puede confirmar el pedido %s porque la direccion de envio del '
              'cliente NO tiene PROVINCIA mapeada')
            % self.sale_order_id.name
        )

    @api.multi
    def action_sale_order_done(self):
        self.ensure_one()
        # antes
        if self.sale_order_id:
            if self.sale_order_id.state in ['draft', 'sent']:
                weight_total = 0
                for line in self.sale_order_id.order_line:
                    if line.product_id:
                        if line.product_uom_qty > 0:
                            if line.product_id.weight > 0:
                                weight = line.product_id.weight*line.product_uom_qty
                                weight_total += weight
                # operations
                if self.external_source_id:
                    es = self.external_source_id
                    if es.external_sale_order_carrier_id:
                        es_esoc = es.external_sale_order_carrier_id
                        if weight_total <= 10:
                            self.sale_order_id.carrier_id = es_esoc.id
        # check country_id and state_id
        allow_confirm = True
        if self.external_shipping_address_id:
            # check_country_id
            if self.external_shipping_address_id.country_id.id == 0:
                self.action_so_done_error_esa_id_without_country_id()
                allow_confirm = False
            if self.external_shipping_address_id.country_state_id.id == 0:
                self.action_so_done_error_esa_id_without_country_state_id()
                allow_confirm = False
        # allow_confirm
        if allow_confirm:
            return super(ExternalSaleOrder, self).action_sale_order_done()


# This script reads the original FoF files and compress them into a single file.
# This helps reducing the size of the files and make its reading much faster
from mpi4py import MPI
import numpy as np
import sys,os
import readfof

###### MPI DEFINITIONS ######
comm   = MPI.COMM_WORLD
nprocs = comm.Get_size()
myrank = comm.Get_rank()

root = '/mnt/ceph/users/fvillaescusa/Quijote/nwLH'
################################## INPUT ##########################################
snapnums     = '0 1 2 3 4'
realizations = 2000
###################################################################################ls

# find the numbers that each cpu will work with
numbers = np.where(np.arange(realizations)%nprocs==myrank)[0]

# do a loop over the different realizations
for i in numbers:

    print('realization:',i)
    snapdir = '%s/%d/'%(root,i)
    os.system('FoF_reductor %s %s --no_read_ids'%(snapdir, snapnums))

    # make a consistent check
    for snapnum in snapnums.split():
        fin = '%s/groups_%03d/'%(snapdir,int(snapnum))
        file_num = len(os.listdir(fin))
        if file_num!=1:  raise Exception('%d %s %d'%(i,snapnum,file_num))

comm.Barrier()


from database import db_session
from tests.base_test import BaseTest
from models.service import Service
from models.stop import Stop

class AssociationsTest(BaseTest):

    def make_random_stop(self):
        new_stop = Stop()
        new_stop.name = "Stop 23"
        new_stop.latitude = 2.144
        new_stop.longitude = -1.222

        return new_stop

    def make_random_service(self):
        new_service = Service()
        new_service.name = "Service 45"
        new_service.description = "Much service"
        new_service.service_type = "night"
        new_service.route = "[{'destination':'Gyle Centre','points':[{'latitude':55.93879,'longitude':-3.104563},{'latitude':55.93862,'longitude':-3.105503}]}]"

        return new_service

    # Adding stops to services
    def test_service_has_stops(self):
        new_service = self.make_random_service()
        new_stop = self.make_random_stop()
        new_service.stops.append(new_stop)

        db_session.add(new_service)
        db_session.add(new_stop)
        db_session.commit()
        db_session.flush()

        service = Service.query.all()[0]

        self.assertEquals(len(service.stops), 1)

    # Adding services to stops
    def test_stop_has_services(self):
        new_stop = self.make_random_stop()
        new_service = self.make_random_service()
        new_stop.services.append(new_service)

        db_session.add(new_stop)
        db_session.add(new_service)
        db_session.commit()
        db_session.flush()

        stop = Stop.query.all()[0]

        self.assertEquals(len(stop.services), 1)


#1        1
#12      21
#123    321
#1234  4321
#1234554321

n=int(input())
i=1
n1=n
n2=2*n

while i<=n1:
    j=1
    while j<=i:
        print(j,end='')
        j=j+1
    while j<=n2:
        if((n2-j)<=i):
            if((n2-j+1)>i):
                print(" ",end='')
            else:
             print(n2-j+1,end='')
        else:
         print(" ",end='')
        j=j+1
    print()
    i=i+1

#   1
#  212
# 32123
#4321234
row=int(input())
i=1
while i<=row:
    j=1
    while j<=(row-i):
        print(" ",end='')
        j=j+1
    j=i
    while j>=1:
        print(j,end='')
        j=j-1
    j=2
    while j<=i:
        print(j,end='')
        j=j+1
    print()
    i=i+1

#OR
n=int(input())
for i in range (1,n+1,1):
    for s in range(n-i):
        print(" ",end='')
    for j in range (i, 2*i,1):
        print(j,end='')
    for j in range (2*i-2,i-1,-1):
        print(j,end='')
    print()


def backTraking(index,sum):
    global minAns
    global maxAns
    if index==N-1:
        if minAns > sum: minAns = sum
        if maxAns < sum: maxAns = sum
        return #인덱스가 N-1 마지막 즉 함수를 종료해야함

    for i in range(4): #+,-,%,*
        temp = sum
        if operator[i]==0:continue
        if i==0: sum+=numArr[index+1]
        elif i==1: sum -=numArr[index+1]
        elif i==2: sum *=numArr[index+1]
        else:
            if sum<0 : sum = abs(sum)//numArr[index+1]*-1
            else: sum//=numArr[index+1]
        operator[i] -=1
        backTraking(index+1,sum)
        operator[i] +=1
        sum = temp
N = int(input())  #n을 입력받는다
numArr = list(map(int, input().split())) #수를 입력받는다
operator = list(map(int, input().split())) #연산자를 입력받는다
minAns =float('Inf') #최솟값 설정
maxAns = float('-Inf') #최댓값 설정

backTraking(0,numArr[0]) #인덱스, 수의 첫값 numArr[0]
print(maxAns) #maxAns, minAns 출력
print(minAns)


# https://leetcode.com/problems/longest-consecutive-sequence/

#! Solution1 by definition is not a O(n) because sort is O(nlog(n))
#! even tough it runs really fast in python

class Solution1:
    def longestConsecutive(self, nums: list[int]) -> int:
        if len(nums) == 0:
            return 0

        nums_set = [*set(nums)]
        nums_set.sort()

        current = 1
        longest = 1
        for i in range(len(nums_set)-1):
            if nums_set[i] + 1 != nums_set[i+1]:
                current = 1
            else:
                current += 1

            if current > longest:
                longest = current

        return longest

#? Altough solution 2 is technically O(n), it runs way slower in practice

class Solution2:
    def longestConsecutive(self, nums: list[int]) -> int:
        numSet = set(nums)
        longest = 0

        for n in nums:
            # check if its the start of a sequence
            if (n - 1) not in numSet:
                length = 1
                while (n + length) in numSet:
                    length += 1
                longest = max(length, longest)
        return longest

#? Variation of Solution2 but runs much fast, on par with Solution1

class Solution3:
    def longestConsecutive(self, nums: list[int]) -> int:
        nums = set(nums)
        best = 0
        for x in nums:
            if x - 1 not in nums:
                y = x + 1
                while y in nums:
                    y += 1
                best = max(best, y - x)
        return best


import datetime as date
from dataclasses import dataclass

@dataclass
class dag_info:
    yesterday: date = date.date.today() - date.timedelta(1)
    airflow_home: str = None
    backend_url: str = ''
    dag_id: str = None
    owner: str = 'chequer'
    start_date: str = None
    catchup = 'False'
    schedule_interval: str = '@once'
    csv_files_directory: str = None

@dataclass
class db_info:
    db_type: int = None
    host: str = None
    port: str = None
    account: str = None
    id: str = None
    pwd: str = None
    warehouse: str = None
    option: str = None
    role: str = None

@dataclass
class user_data_carrier:
    columns: list = None
    pk: list = None
    updated: list = None
    schema: list = None
    dag_ids: list = None
    status: list = None
    upsert_rule: list = None
    tables: list = None
    status: list = None
    database: list = None
    schema: list = None

@dataclass
class user_all_data:
    def __init__(self, dag_id, id, pwd, columns, pk, updated, upsert_rule, tables, database,
                 csv_file_directory, warehouse='', option='', role='', schema=[], host='', port='',account=''):
        self.dag_id = dag_id
        self.host = host
        self.port = port
        self.id = id
        self.pwd = pwd
        self.columns = columns
        self.pk = pk
        self.updated = updated
        self.upsert_rule = upsert_rule
        self.tables = tables
        self.database = database
        self.csv_files_directory = csv_file_directory
        self.warehouse = warehouse
        self.option = option
        self.role = role
        self.schema = schema
        self.account = account

    dag_id: str = None
    host: str = None
    port: str = None
    account: str = None
    id: str = None
    pwd: str = None
    warehouse: str = None
    option: str = None
    role: str = None
    columns: list = None
    pk: list = None
    updated: list = None
    schema: list = None
    upsert_rule: list = None
    tables: list = None
    database: list = None
    csv_files_directory: str = None


"""Base defines a common contract for connecting, closing, managing context for clients."""
import abc
from typing import Container, ContextManager, TypeVar, Union, cast

from tentaclio import protocols, urls

T = TypeVar("T")

class BaseClient(ContextManager[T], metaclass=abc.ABCMeta):
    """Abstract base class for clients, wrapping a connection.

    Offers context managing, connecting and closing functionalities.
    """

    url: urls.URL
    conn: protocols.Closable
    allowed_schemes: Container[str] = []
    closed: bool = True

    def __init__(self, url: Union[urls.URL, str]) -> None:
        """Create a new client based on a URL object or a string containing a url."""
        if isinstance(url, str):
            url = urls.URL(url)
        self.url = url
        if self.url.scheme not in self.allowed_schemes:
            raise ValueError(
                f"Allowed schemes for {type(self).__name__} are {self.allowed_schemes}; "
                f"found '{self.url.scheme}'"
            )

    # Context manager:

    def __enter__(self) -> T:
        """Connect to the resource when entering the context."""
        self.conn = self.connect()
        return cast(T, self)

    def __exit__(self, *args) -> None:
        """Close the connection when leaving the context."""
        self.close()

    # Connection methods:

    def connect(self) -> protocols.Closable:
        """Connect to the resource when entering the context."""
        self.closed = False
        return self._connect()

    @abc.abstractmethod
    def _connect(self) -> protocols.Closable:
        """Connect to the resource. This method needs to be overwritten by child classes."""
        ...

    def close(self) -> None:
        """Close the client connection."""
        if not self.closed:
            self.conn.close()
            self.closed = True