#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
-----------------------------------------
@Created: 2021/02/14
------------------------------------------
@Modify: 2021/02/14
------------------------------------------
@Description:

"""
import os,sys,re
_PROJECT_NAME = 'VulnerabilityAnalysis'
_CURRENT_ABSPATH = os.path.abspath(__file__)
sys.path.insert(0, _CURRENT_ABSPATH[:_CURRENT_ABSPATH.find(_PROJECT_NAME) + len(_PROJECT_NAME) + 1])

from vulnerability_analysis import config
from vulnerability_analysis.utility import re_util
l1_split_str = config.L1_SPLITE_STR
l2_split_str = config.L2_SPLITE_STR

import urllib.parse

class Node:
    """
    class Node
    Attributes:
            type = None                         # range: source, root_node, issue_url, patch_url, common_github_url, common_url ...
            category_in_type = None             # category_in_type, issue: git_issue ..... , patch: git_commit, svn, diff_file ....
            formatted_url = None                # formatted URL
            formatted_id = None                 # formatted URL or CVEID
            original_content = None             # original_content as init input
            flag_travelled = False
    """

    def __init__(self, node_content_type, node_content):
        """
        input url with tags, which will be formatted and cleared its type
        :param
            node_type: url, cveid, issue_id, commit_id
        """
        self.type = None  # range: source, root_node, issue_url, patch_url, common_github_url, common_url ...
        self.category_in_type = None  # category_in_type, issue: git_issue ..... , patch: github_commit, svn_commit ....
        self.formatted_url = None  # formatted URL
        self.formatted_id = None  # formatted URL or CVEID
        self.original_content = None  # original_content as init input
        self.flag_travelled = False

        if node_content_type == 'url': # is url
            identification_res = Node.identify_the_type_of_url(node_content)
            if identification_res:
                self.type = identification_res['type']
                self.formatted_id = identification_res['formatted_id']
                self.formatted_url = identification_res['formatted_url']
                self.category_in_type = identification_res['category_in_type']
                self.original_content = node_content
        elif node_content_type == 'cveid': # is CVEID
            self.type = 'root_node'
            self.formatted_id = node_content
            self.original_content = node_content
        elif node_content_type == 'source':
            self.type = 'source'
            self.formatted_id = node_content
            self.original_content = node_content
        elif node_content_type == 'issue_id':
            pass
        elif node_content_type == 'commit_id':
            pass

    @staticmethod
    def identify_the_type_of_url(url):
        # range: source, root_node, issue_url, patch_url, common_github_url, common_url ...
        is_patch_res = Node.is_patch_url(url)
        if is_patch_res: return is_patch_res
        is_issue_res = Node.is_issue_url(url)
        if is_issue_res: return is_issue_res
        is_common_github_res = Node.is_common_github_url(url)
        if is_common_github_res: return is_common_github_res

        # common,
        formatted_result = {}
        formatted_result['type'] = 'common_url'
        formatted_result['category_in_type'] = None
        formatted_result['formatted_url'] = Node.format_url(url)
        formatted_result['formatted_id'] = formatted_result['formatted_url']
        return formatted_result

    @staticmethod
    def identify_target_types_of_nodes(url_list, target_types):
        """
        identify url nodes of differernt types by url
        :param
            url_list: [],
            target_types: issue_url, patch_url, root_node, github_repo_url
        :return: [ Nodes ]
        """

        # todo, format target_types
        if target_types=='all':
            target_types = ['issue_url', 'patch_url', 'github_repo_url','common_url','common_github_url']
        # identify
        identified_target_nodes = []
        for url_ele in url_list:
            url_node_obj = Node(node_content_type='url', node_content=url_ele)
            if url_node_obj.type in target_types and url_node_obj not in identified_target_nodes:
                identified_target_nodes.append(url_node_obj)
            else:
                # todo, 对象内存回收
                pass
        return identified_target_nodes

    @staticmethod
    def is_issue_url(url):
        if not re.search(r'http(s)?://(([\w-]+\.)+\w+(:\d{1,5})?)', url): return False # 说明连域名都没有，非url
        ref = url
        # 整理ref 格式
        # ref = ref.replace('%2F', '/').replace('%2F', '/')
        ref = urllib.parse.unquote(ref) # url解码

        result = {}
        flag = 0  # 用于判断改ref是否是 issue
        url_domian = re.search(r'http(s)?://(([\w-]+\.)+\w+(:\d{1,5})?)', url).group(2)
        issuekey = None

        # black list
        # https://bugzilla.mozilla.org/show_bug.cgi?id=1150351 属于 advisory，非issue
        # https://bugzilla.redhat.com/show_bug.cgi?id=CVE-2018-8014
        # bugs.debian.org/cgi-bin/bugreport.cgi?
        # https://bugs.gentoo.org/show_bug.cgi?id=317435
        # if 'bugzilla.mozilla.org/show_bug.cgi' in ref \
        #         or 'bugzilla.redhat.com/show_bug.cgi' in ref\
        #         or ('bugs.debian.org/' in ref and 'bugreport.cgi?' in ref) \
        #         or ('bugzilla.suse.com/' in ref and 'show_bug.cgi?' in ref) \
        #         or ('bugzilla.gnome.org/' in ref and 'show_bug.cgi?' in ref) \
        #         or ('bugs.gentoo.org/show_bug.cgi' in ref):
        if 'bugzilla.mozilla.org/show_bug.cgi' in ref\
                or 'bugzilla.redhat.com/' in ref\
                or ('bugs.debian.org/' in ref) \
                or ('bugzilla.suse.com/' in ref ) \
                or ('bugzilla.gnome.org/' in ref) \
                or ('bugs.gentoo.org/' in ref):
            return False

        """
         "https://bugs.eclipse.org/bugs/show_bug.cgi?id=535670"
         "https://bugzilla.readthedocs.org/en/5.0/using/understanding.html"
         "https://bugs.eclipse.org/bugs/request.cgi",
        """
        ## git_issue 规则
        # https://github.com/primefaces/primefaces/issues/5642
        if ('/issues/' in ref and '/github.com/' in ref):
            tem_ref = (ref.split(l1_split_str)[0].strip(')').strip(']'))
            can_issuekey = tem_ref.split('/issues/')[-1].split('/')[0].split('#')[0]
            if can_issuekey.isdigit():
                result['git_issue'] = tem_ref
                issuekey = can_issuekey
                flag = 1
        ## git_pull_request规则
        # https://github.com/unicode-org/icu/pull/971
        if ('/pull/' in ref and '/github.com/' in ref):
            tem_ref = (ref.split(l1_split_str)[0].strip(')').strip(']'))
            # 误报，'https://github.com/join?return_to=https://github.com/nodejs/node/pull/new/2227).&source=login/'
            if not tem_ref.split('/pull/')[-1].split('/')[0].isdigit(): return False # pull后紧跟ID号

            # 整理格式，https://github.com/tj/node-growl/pull/61/checks， https://github.com/tj/node-growl/pull/61/files
            format_ref = ''
            for ele in tem_ref.split('/'):
                if ele.isdigit():
                    format_ref +=ele + '/'
                    break
                else:
                    format_ref += ele + '/'
            result['git_pull_request'] = format_ref.strip('/')
            issuekey = format_ref.split('/pull/')[-1].split('/')[0].split('#')[0]
            flag = 1
        ## bugzilla规则
        if ('/bugzilla.' in ref or '/bugzilla/' in ref):
            if 'bugzilla.redhat.com' in ref: return False# https://bugzilla.redhat.com/show_bug.cgi?id=CVE-2018-10897, 不为issue
            # 整理格式
            # 需要有issueid
            tem_ref = ref
            if len(re.findall('[0-9]{2,}', tem_ref)) > 0: # 'https://bugzilla.readthedocs.org/en/5.0/using/understanding.html__fdse__Help'
                result['bugzilla'] = tem_ref
                flag = 1
                issuekeys = re.findall('[0-9]{2,}', tem_ref)
                if issuekeys: issuekey = issuekeys[-1]
            else:
                return False
            result['bugzilla'] = (ref.split(l1_split_str)[0].strip(')').strip(']'))
            flag = 1
        ## jira规则
        if ('/jira.' in ref or '/jira/' in ref):
            tem_ref = str(ref) # 防止不符合这一项，却对原ref造成破坏
            # 整理格式，https://issues.apache.org/jira/login.jsp?os_destination=%2Fbrowse%2FOLINGO-1409, 该链接是由https://issues.apache.org/jira/browse/OLINGO-1409包含的，所以，可直接删去
            # https://issues.apache.org/jira/browse/OLINGO-1409?focusedCommentId=17005245&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel
            tem_ref = (tem_ref.split(l1_split_str)[0].strip(')').strip(']'))
            tem_ref = tem_ref.split('?')[0]
            if len(re.findall('[A-Z]+-[0-9]+', tem_ref)) > 0:
                result['jira'] = tem_ref
                flag = 1
                issuekeys = re.findall('[A-Z]+-[0-9]+', tem_ref)
                if issuekeys: issuekey = issuekeys[-1]
            else:
                return False
        ## other_issue_tracker
        if flag == 0 and ('/issues.' in ref or '/issues/' in ref or '/issue.' in ref or '/issue/' in ref):
                tem_ref = str(ref)  # 防止不符合这一项，却对原ref造成破坏
                # 整理格式，'http://issues.apache.org/buglist.cgi?chfieldfrom=24h'
                tem_ref = (tem_ref.split(l1_split_str)[0].strip(')').strip(']'))
                if 'filter=' in tem_ref.split('?')[-1]: # for https://tracker.phpbb.com/issues/?filter=15193
                    pass
                else: tem_ref = tem_ref.split('?')[0]
                if len(re.findall('[A-Z]+-[0-9]+', tem_ref.split('/issue')[-1])) > 0:
                    result['other_issue_tracker'] = tem_ref
                    flag = 1
                    issuekeys = re.findall('[0-9]+', tem_ref.split('/issue')[-1])
                    if issuekeys: issuekey = issuekeys[-1]
                elif len(re.findall('[0-9]+', tem_ref.split('/issue')[-1])) > 0:
                    result['other_issue_tracker'] = tem_ref
                    flag = 1
                    issuekeys = re.findall('[0-9]+', tem_ref.split('/issue')[-1])
                    if issuekeys: issuekey = issuekeys[-1]
                else:
                    return False
        if flag == 0 and ('/bugs.' in ref or '/bugs/' in ref):
                if 'attachment' in ref: return False# 'https://bugs.gentoo.org/attachment.cgi?id=215643__fdse__attachment 215643'
                tem_ref = str(ref)  # 防止不符合这一项，却对原ref造成破坏
                # 整理格式，'http://issues.apache.org/buglist.cgi?chfieldfrom=24h'
                tem_ref = (tem_ref.split(l1_split_str)[0].strip(')').strip(']'))
                # tem_ref = tem_ref.split('?')[0] # for 'https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=733108'
                tem_ref = tem_ref.split('#')[0] # for 'https://bugs.gentoo.org/show_bug.cgi?id=352864#c11__fdse__Comment 11'
                if len(re.findall('[0-9]{2,}', tem_ref.split('/bug')[-1])) > 0:
                    result['other_issue_tracker'] = tem_ref
                    flag = 1
                    issuekeys = re.findall('[0-9]{2,}', tem_ref.split('/bug')[-1])
                    if issuekeys: issuekey = issuekeys[-1]
                else:
                    return False
        if flag == 0 and ('/tickets.' in ref or '/tickets/' in ref):
                tem_ref = str(ref)  # 防止不符合这一项，却对原ref造成破坏
                # 整理格式，'http://tickets.opscode.com/browse/CHEF-1289'
                tem_ref = (tem_ref.split(l1_split_str)[0].strip(')').strip(']'))
                tem_ref = tem_ref.split('?')[0]
                if len(re.findall('[A-Z]+[0-9]{0,2}-[0-9]+', tem_ref.split('/tickets')[
                    -1])) > 0:  # 特殊 re表达式，for 'https://tracker.phpbb.com/browse/PHPBB30-13551'
                    result['other_issue_tracker'] = tem_ref
                    flag = 1
                    issuekeys = re.findall('[A-Z]+[0-9]{0,2}-[0-9]+', tem_ref.split('/tickets')[-1])
                    if issuekeys: issuekey = issuekeys[-1]
                else:
                    return False
        if flag == 0 and ('/tracker.' in ref or '/tracker/' in ref):
                tem_ref = str(ref)  # 防止不符合这一项，却对原ref造成破坏
                # 整理格式，'http://tickets.opscode.com/browse/CHEF-1289'
                tem_ref = (tem_ref.split(l1_split_str)[0].strip(')').strip(']'))
                tem_ref = tem_ref.split('?')[0]
                if len(re.findall('[A-Z]+[0-9]{0,2}-[0-9]+', tem_ref.split('/tracker')[-1])) > 0: # 特殊 re表达式，for 'https://tracker.phpbb.com/browse/PHPBB30-13551'
                    result['other_issue_tracker'] = tem_ref
                    flag = 1
                    issuekeys = re.findall('[A-Z]+[0-9]{0,2}-[0-9]+', tem_ref.split('/tracker')[-1])
                    if issuekeys: issuekey = issuekeys[-1]
                else:
                    return False

        # TODO, 详细分类否？
        ## other_issue_tracker
        # https://svn.apache.org/viewvc?view=rev&rev=1777472 CVE-2016-8745
        # if flag == 0 and ('Issue Tracking' in ref):
        #     result['issue_tag'] = (ref.split(l1_split_str)[0].strip(')').strip(']'))
        #     flag = 1

        if flag==1 and result:
            formatted_result = {}
            formatted_result['type'] = 'issue_url'
            formatted_result['category_in_type'] = list(result.keys())[-1]
            url = result[formatted_result['category_in_type']]
            formatted_result['formatted_url'] = Node.format_url( url )
            if issuekey: formatted_result['formatted_id'] = url_domian + l1_split_str + issuekey
            else: formatted_result['formatted_id'] = formatted_result['formatted_url']
            """
            如果 issuekey可以有效提取出来：
            formatted_result['formatted_id'] = 域名 + issuekey/issueID, 防止重复，比如：
            'https://issues.apache.org/jira/si/jira.issueviews:issue-word/OLINGO-1409/OLINGO-1409.doc'
            'https://issues.apache.org/jira/si/com.atlassian.jira.plugins.jira-importers-plugin:issue-json/OLINGO-1409/OLINGO-1409.json'
            """
            return formatted_result
        else: return False

    @staticmethod
    def is_patch_url(url):
        ref = url.split(l1_split_str)[0]
        result = {}
        patch_formatted_id = None

        request_black_str_list = ['.zip', '.gz', '.tgz', '.google.', '.msi', '.exe', '.tar', '.iso', '.sha256', '.asc',
                                  '.xz', '.atom', '.pdf']
        # 去除奇奇怪怪的误识别
        for black_str in request_black_str_list :
            if black_str in ref: return False
        # 非url直接撤
        if len(re.findall('http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+', ref)) ==0: return False
        # issue 相关，直接撤
        # https://bugs.debian.org/cgi-bin/version.cgi?found=edid-decode/0.1~git20140128.afcf2a2e
        if 'https://bugs.debian.org/' in ref: return False
        # https://github.com/pypa/pip/issues/bca635a1
        if ( 'github' in ref and 'commit' not in ref ): return False

        # 整理ref 格式
        # ref = ref.replace('%2F', '/').replace('%3A', ':')
        ref = urllib.parse.unquote(ref)  # url解码

        flag_patch = 0
        # Todo
        ## git commit 规则
        """
            https://github.com/apache/tomcat/commit/40fa74c74822711ab878079d0a69f7357926723d
            https://github.com/zephyrproject-rtos/zephyr/pull/23821/commits/11b7a37d9a0b438270421b224221d91929843de4  / https://github.com/u-boot/u-boot/commits/master /'https://github.com/tj/node-growl/pull/61/commits'
            https://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commit;h=9333498794cde1d5cca518badf79533a24114b6f
            https://git.qemu.org/?p=qemu.git;a=commit;h=de0b1bae6461f67243282555475f88b2384a1eb9
            http://git.moodle.org/gw?p=moodle.git&a=search&h=HEAD&st=commit&s=MDL-68410
        """
        # blob "https://github.com/borgbackup/borg/blob/6916d1b3bc8d25d9e6f6254459abd3e21f4dc1e3"
        if ('/github.com/' in ref and 'blob/' in ref) or ( 'gist.' in ref): return False
        # https://github.com/pediapress/pyfribidi/issues/2
        if  ('/github.com/' in ref and 'issues/' in ref): return False
        # https://user-images.githubusercontent.com/39950310/49497761-2db59500
        if ('github' in ref and 'commit' not in ref): return False

        # https://source.codeaurora.org/quic/le/meta-qti-bsp/commit/?id=ecd2fb4ab9e2a6851add554af03cebe337345c44
        # 'https://lab.louiz.org/poezio/slixmpp/commit/7cd73b594e8122dddf847953fcfc85ab4d316416's
        if ('/commits/' in ref and '/bitbucket.org/' in ref and len(re.findall(r'(?![0-9]{6,40})(?![a-f]{6,40})[0-9a-f]{6,40}', ref))>0)\
                or ('/commit/' in ref and '/lab.louiz.org/' in ref and len(re.findall(r'(?![0-9]{6,40})(?![a-f]{6,40})[0-9a-f]{6,40}', ref))>0)\
                or ('/commit/' in ref and 'dulwich.io/' in ref and len(re.findall(r'(?![0-9]{6,40})(?![a-f]{6,40})[0-9a-f]{6,40}', ref))>0)\
                or ('/commit/' in ref and 'source.codeaurora.org/' in ref and len(re.findall(r'(?![0-9]{6,40})(?![a-f]{6,40})[0-9a-f]{6,40}', ref))>0):
            format_ref = 'http' + ref.split('http')[-1]  # 取最后http
            # commitID = re.findall('(?<![0-9a-f])(?![0-9]{6,40})(?![a-f]{6,40})([0-9a-f]{6,40})(?![0-9a-f])') # 用于网页中识别commit ID
            commitID = re.findall(r'(?![0-9]{6,40})(?![a-f]{6,40})[0-9a-f]{6,40}', format_ref)  # 用于url内部识别
            # commitID = re_util.extract_commitid_in_commit_url(format_ref)
            # commitID = [commitID]
            if not commitID:
                False
            else:
                result['git_commit'] = format_ref[:format_ref.find(commitID[0])] + commitID[0]
                flag_patch = 1
                patch_formatted_id = format_ref.split('commit')[0] + 'commit/' + commitID[0][:6]

        if ('/commits/' in ref and '/github.com/' in ref and '/pull/' in ref):
            format_ref = 'http' + ref.split('http')[-1]  # 取最后http
            format_ref = format_ref.split('?')[0].split('#')[0].split('&')[0]
            # commitID = re.findall('(?<![0-9a-f])(?![0-9]{6,40})(?![a-f]{6,40})([0-9a-f]{6,40})(?![0-9a-f])') # 用于网页中识别commit ID
            commitID = re.findall(r'(?![0-9]{6,40})(?![a-f]{6,40})[0-9a-f]{6,40}', format_ref)  # 用于url内部识别
            # commitID = re_util.extract_commitid_in_commit_url(format_ref)
            # commitID = [commitID]
            if not commitID:
                False
            else:
                result['git_commit'] = format_ref[:format_ref.find(commitID[0])] + commitID[0]
                flag_patch = 1
                # patch_formatted_id = format_ref.split('pull')[0] +'commit/' + commitID[0][:6]
                # repo_name = format_ref.split('/github.com/')[-1].split('/')[1]
                # patch_formatted_id = repo_name.lower() + '_' + commitID[0][:6]
                patch_formatted_id = commitID[0][:6]
        if ('/commit/' in ref and '/github.com/' in ref):
            # 'https://github.com/django/django/commit/d5d8942a160685c403d381a279e72e09de5489a9?branch=d5d8942a160685c403d381a279e72e09de5489a9&diff=unified__fdse__    Unified'
            # 'http://code.djangoproject.com/login?return_to=https%3A//github.com/django/django/commit/d5d8942a16'
            # 'https://github.com/django/django/commit/85207a245bf09fdebe486b4c7bbcb65300f2a693?branch=85207a245bf09fdebe486b4c7bbcb65300f2a693&diff=split'
            # 'https://github.com/django/django/commit/732198ed5c2a127249970e0cd4218d093a38e9a2?branch=732198ed5c2a127249970e0cd4218d093a38e9a2&diff=split'
            if 'http:' in ref:
                format_ref = 'http:' + ref.split('http:')[-1] # 取最后http
            if 'https:' in ref:
                format_ref = 'https:' + ref.split('https:')[-1]  # 取最后http
            format_ref = format_ref.split('?')[0].split('#')[0].split('&')[0]
            # commitID = re.findall('(?<![0-9a-f])(?![0-9]{6,40})(?![a-f]{6,40})([0-9a-f]{6,40})(?![0-9a-f])') # 用于网页中识别commit ID
            commitID = re.findall(r'(?![0-9]{6,40})(?![a-f]{6,40})[0-9a-f]{6,40}', format_ref) # 用于url内部识别
            # commitID = re_util.extract_commitid_in_commit_url( format_ref ) # 用于url内部识别
            # commitID = [commitID]
            if not commitID: False
            else:
                result['git_commit'] = format_ref[ :format_ref.find( commitID[0] )] + commitID[0]
                flag_patch = 1
                # patch_formatted_id = format_ref[ :format_ref.find( commitID[0] )] + commitID[0][:6]
                # repo_name = format_ref.split('/github.com/')[-1].split('/')[1]
                # patch_formatted_id = repo_name.lower() + '_' + commitID[0][:6]
                patch_formatted_id = commitID[0][:6]
        if flag_patch == 0 \
                and ( (';a=commit' in ref) or ('st=commit' in ref) or ('/commit' in ref and '/git' in ref) ):
            # 反例 https://git.openstack.org/cgit/openstack/neutron/commit?style=split
            commitID = re.findall(r'(?![0-9]{6,40})(?![a-f]{6,40})[0-9a-f]{6,40}', ref)  # 用于url内部识别
            if commitID:
                result['git_commit'] = (ref.split(l1_split_str)[0])
                flag_patch = 1
                # 针对 CVE-2015-5312， https://git.gnome.org/browse/libxml2/commit/?id=709a952110e98621c9b78c4f26462a9d8333102e
                # https://git.gnome.org/browse/libxml2/commit?id=709a952110e98621c9b78c4f26462a9d8333102e
                format_ref = ref.replace('/?', '?')
                patch_formatted_id = format_ref[:format_ref.find(commitID[0])] + commitID[0][:6]
            else:
                # http://git.openssl.org/gitweb/?p=openssl.git;a=commit;h=34628967f1e65dc8f34e000f0f5518e21afbfc7b
                for c in ref.split('commit')[-1].split(l1_split_str)[0]:
                    if c.isdigit():  # 说明有数字，有id号
                        result['git_commit'] = (ref.split(l1_split_str)[0])
                        flag_patch = 1
                        format_ref = ref.replace('/?', '?')
                        break
            # if flag_patch==1:
            #     format_ref = ref.replace('/?', '?')
            #     commitID = re.findall(r'(?![0-9]{6,40})(?![a-f]{6,40})[0-9a-f]{6,40}', format_ref)  # 用于url内部识别
            #     # commitID = re_util.extract_commitid_in_commit_url(format_ref)
            #     # commitID = [commitID]
            #     patch_formatted_id = format_ref[:format_ref.find(commitID[0])] + commitID[0][:6]
        # https://pagure.io/389-ds-base/c/9724e8bb1
        if flag_patch == 0 and re.search(r'/c/(?![0-9]{6,40})(?![a-f]{6,40})[0-9a-f]{6,40}',ref):
            format_ref = 'http' + ref.split('http')[-1]  # 取最后http
            format_ref = format_ref.split('?')[0].split('#')[0].split('&')[0]
            commitID = re.findall(r'(?![0-9]{6,40})(?![a-f]{6,40})[0-9a-f]{6,40}', format_ref)  # 用于url内部识别
            # commitID = re_util.extract_commitid_in_commit_url(format_ref)
            # commitID = [commitID]
            if not commitID:
                False
            else:
                result['git_commit'] = format_ref[:format_ref.find(commitID[0])] + commitID[0]
                flag_patch = 1
                patch_formatted_id = format_ref[:format_ref.find(commitID[0])] + commitID[0][:6]
        if flag_patch == 0 and ( 'git' in ref and re.search(r'(?![0-9]{6,40})(?![a-f]{6,40})[0-9a-f]{6,40}',ref) ):
            # https://user-images.githubusercontent.com/39950310/49497761-2db59500
            # https://lists.apache.org/thread.html/8a20e48acb2a40be5130df91cf9d39d8ad93181989413d4abcaa4914@<dev.tomcat.apache.org>#tomcat.git
            if not ref.split('git')[-1] or ref.split('git')[-1][0].isalnum(): return False # git 右边的字符是字母
            if 'http:' in ref:
                format_ref = 'http:' + ref.split('http:')[-1]  # 取最后http
            if 'https:' in ref:
                format_ref = 'https:' + ref.split('https:')[-1]  # 取最后http
            format_ref = format_ref.split('#')[0].split('&')[0]
            commitID = re.findall(r'(?![0-9]{6,40})(?![a-f]{6,40})[0-9a-f]{6,40}', format_ref)  # 用于url内部识别
            # commitID = re_util.extract_commitid_in_commit_url(format_ref)
            # commitID = [commitID]
            if not commitID:
                False
            else:
                result['git_commit'] = format_ref[:format_ref.find(commitID[0])] + commitID[0]
                flag_patch = 1
                patch_formatted_id = format_ref[:format_ref.find(commitID[0])] + commitID[0][:6]

        # TODO
        ## svn规则
        """
            https://svn.apache.org/viewvc?view=rev&rev=1777472 CVE-2016-8745
            "https://svn.apache.org/repos/asf/geronimo/server/tags/geronimo-2.1.6/RELEASE_NOTES-2.1.6.txt"
        """
        if ('/svn.' in ref and 'rev=' in ref) or ('/svn.' in ref and '/r' in ref.replace('repos', '_')) or (
                '/svn.' in ref and 'revision' in ref):
            svn_id = re_util.extract_commitid_in_svn_url(ref.split(l1_split_str)[0])
            if svn_id:
                result['svn'] = (ref.split(l1_split_str)[0])
                flag_patch = 1
                patch_formatted_id = 'svn_' + svn_id

        # TODO
        ## diff file规则
        # if ('.patch' in ref.lower()) or ('.diff' in ref.lower()):
        if ref.endswith('.patch') or ref.endswith('.diff'):
            result['diff_file'] = (ref.split(l1_split_str)[0])
            flag_patch = 1

        # redhat attachment, url 转换 及去重
        # https://bugzilla.redhat.com/attachment.cgi?id=14727&action=diff
        # https://bugzilla.mozilla.org/attachment.cgi?id=361765&action=edit
        # 'https://bugs.gentoo.org/attachment.cgi?id=215643__fdse__attachment 215643'
        if ('redhat.com/attachment' in ref and '&action=' in ref) \
                or ('mozilla.org/attachment' in ref and '&action=' in ref) \
                or ('bugs.gentoo.org/attachment' in ref and re.search('[0-9]{4,}', ref) )\
                or ('/attachment' in ref and '&action=' in ref):
            if l1_split_str in ref:
                ref = ref.split('&action=')[0] + l1_split_str + ref.split(l1_split_str)[1]
            else:
                ref = ref.split('&action=')[0]
            result['diff_file'] = (ref.split(l1_split_str)[0])
            flag_patch = 1

        if flag_patch==1 and result:
            formatted_result = {}
            formatted_result['type'] = 'patch_url'
            formatted_result['category_in_type'] = list(result.keys())[-1]
            url = result[formatted_result['category_in_type']]
            formatted_result['formatted_url'] = Node.format_url(url)
            formatted_result['formatted_id'] = patch_formatted_id if patch_formatted_id else formatted_result['formatted_url']
            return formatted_result
        else: return False

    @staticmethod
    def is_common_github_url(url):
        flag_common_github_url = 0
        ref = url
        result = {}

        ref = ref.split(l1_split_str)[0]
        if 'github.com/' in ref and len(ref.split('github.com/')[-1].split('/'))>1:
            flag_common_github_url = 1
            result['common_github_url'] = ref

        if flag_common_github_url == 1 and result:
            formatted_result = {}
            formatted_result['type'] = 'common_github_url'
            formatted_result['category_in_type'] = list(result.keys())[-1]
            url = result[formatted_result['category_in_type']]
            formatted_result['formatted_url'] = Node.format_url(url)
            formatted_result['formatted_id'] = formatted_result['formatted_url']
            return formatted_result
        else:
            return False

    @staticmethod
    def format_url(url):
        # 去除 分割符__fdse__ 以后内容
        formal_url = url.split(l1_split_str)[0]
        # 去除 ‘#’ 以后内容
        # ('https://github.com/marshyski/example/issues/251', 1, 'https://github.com/marshyski/example/issues/251#event-2321575465')
        formal_url = formal_url.split('#')[0]
        # 去除 ‘</link>’ 以后内容, </a></p></comment>
        # 'https://issues.apache.org/jira/browse/OLINGO-1409</link>'
        formal_url = formal_url.split('</')[0]
        return formal_url

def is_patch_test():
    # 正误
    print('Teste cases for: False')
    tcs = [
        'https://github.com/tj/node-growl/pull/61/commits',
        'https://github.com/tj/node-growl/pull/61/commits__fdse__      Commits\n\n  2',
        'https://svn.apache.org/repos/asf/geronimo/server/tags/geronimo-2.1.6/RELEASE_NOTES-2.1.6.txt',
        'https://svn.apache.org/repos/infra/websites/production/activemq/con=',
        'https://svn.apache.org/repos/asf/poi/tags/REL_4_1_1/KEYS',
        'https://planet.gentoo.org/',
        'https://github.com/jhy/jsoup/pull/582#ref-commit-4edb789',
        'https://issues.apache.org/jira/secure/attachment/12991357/image-2020-01-20-14-51-26-411.png',
        'https://gist.github.com/asanso/fa25685348051ef6a28d49aa0f27a4ae',
        'https://github.com/borgbackup/borg/blob/6916d1b3bc8d25d9e6f6254459abd3e21f4dc1e3',
        'https://github.com/pediapress/pyfribidi/issues/2',
        'https://user-images.githubusercontent.com/39950310/49497761-2db59500',
        'https://github.com/AFNetworking/AFNetworking/pull/1564/files/44ec25b01bfe8205d8bc585b437167db5bb3a051',
        'https://github.com/pypa/pip/issues/bca635a1',
        'https://github.com/pediapress/pyfribidi/issues/2',
        'https://user-images.githubusercontent.com/39950310/49497761-2db59500',
        'https://github.com/pypa/pip/issues/bca635a1',
        'https://github.com/idomic/cpython/commits/bpo-10572-testlibs/Lib/test/tkinter_test/test_tkinter/test_widgets.py'
    ]
    for tc in tcs:
        res = Node.is_patch_url(url=tc)
        print(res == False)

    print('Teste cases for: True')
    tcs = [
        "http://svn.apache.org/viewvc/kylin/site/docs/security.html?rev=1879879&r1=1879878&r2=1879879&view=diff",
        "http://svn.apache.org/viewvc/kylin/site/feed.xml?rev=1879879&r1=1879878&r2=1879879&view=diff",
        "http://svn.apache.org/viewvc?rev=1879879&view=rev",
        "https://svn.apache.org/viewvc?view=rev&rev=1809673",
        "https://svn.apache.org/viewvc?view=rev&rev=1725263",
        'https://pagure.io/389-ds-base/c/9724e8bb1',
        'https://gitweb.torproject.org/tor.git/commit/?id=43414eb98821d3b5c6c65181d7545ce938f82c8e',
        'http://git.gnome.org/browse/gimp/commit/?id=48ec15890e1751dede061f6d1f469b6508c13439',
        'http://git-wip-us.apache.org/repos/asf/cxf/commit/d9e2a6e7',
        'https://fisheye6.atlassian.com/changelog/camel-git?cs=341d4e6cca71c53c90962d1c3d45fc9e05cc50c6',
        'https://bugzilla.redhat.com/attachment.cgi?id=316093&action=diff',
        'https://projects.theforeman.org/attachments/855/0001-fixes-6086-CVE-2014-0007-fixed-TFTP-boot-API-remote-.patch',
        'https://bugs.gentoo.org/attachment.cgi?id=215643__fdse__attachment 215643'
    ]
    for tc in tcs:
        res = Node.is_patch_url(url=tc)
        print(res != False)

    # tc2 = 'https://github.com/pypa/pip/issues/bca635'
    # res = Node.is_patch_url(url=tc2)
    # print(res)

    # 格式
    tc2 = 'https://github.com/apache/olingo-odata4/commit/c3f982db3d97e395d313ae8f231202bb2139882c</a></p></comment>'
    res = Node.is_patch_url(url=tc2)
    print(res['formatted_url'] == 'https://github.com/apache/olingo-odata4/commit/c3f982db3d97e395d313ae8f231202bb2139882c' if res else False)
    # 'https://github.com/django/django/commit/d5d8942a160685c403d381a279e72e09de5489a9?branch=d5d8942a160685c403d381a279e72e09de5489a9&diff=unified__fdse__    Unified'
    # 'http://code.djangoproject.com/login?return_to=https%3A//github.com/django/django/commit/d5d8942a16'
    # 'https://github.com/django/django/commit/85207a245bf09fdebe486b4c7bbcb65300f2a693?branch=85207a245bf09fdebe486b4c7bbcb65300f2a693&diff=split'
    tc2 = 'https://github.com/django/django/commit/d5d8942a160685c403d381a279e72e09de5489a9?branch=d5d8942a160685c403d381a279e72e09de5489a9&diff=unified__fdse__    Unified'
    res = Node.is_patch_url(url=tc2)
    print(res['formatted_url']=='https://github.com/django/django/commit/d5d8942a160685c403d381a279e72e09de5489a9' if res else False)
    tc2 = 'http://code.djangoproject.com/login?return_to=https%3A//github.com/django/django/commit/d5d8942a16'
    res = Node.is_patch_url(url=tc2)
    print(res['formatted_url'] == 'https://github.com/django/django/commit/d5d8942a16' if res else False)
    tc2 = 'https://github.com/django/django/commit/85207a245bf09fdebe486b4c7bbcb65300f2a693?branch=85207a245bf09fdebe486b4c7bbcb65300f2a693&diff=split'
    res = Node.is_patch_url(url=tc2)
    print(res['formatted_url'] == 'https://github.com/django/django/commit/85207a245bf09fdebe486b4c7bbcb65300f2a693' if res else False)
    tc2 = 'https://github.com/django/django/commit/732198ed5c2a127249970e0cd4218d093a38e9a2?branch=732198ed5c2a127249970e0cd4218d093a38e9a2&diff=split'
    res = Node.is_patch_url(url=tc2)
    print(res['formatted_url'] == 'https://github.com/django/django/commit/732198ed5c2a127249970e0cd4218d093a38e9a2' if res else False)
    tc = 'https://pagure.io/389-ds-base/c/9724e8bb1'
    res = Node.is_patch_url(url=tc)
    print(res['formatted_url'] == 'https://pagure.io/389-ds-base/c/9724e8bb1' if res else False)
    tc = 'https://fisheye6.atlassian.com/changelog/camel-git?cs=341d4e6cca71c53c90962d1c3d45fc9e05cc50c6'
    res = Node.is_patch_url(url=tc)
    print(res['formatted_url'] == 'https://fisheye6.atlassian.com/changelog/camel-git?cs=341d4e6cca71c53c90962d1c3d45fc9e05cc50c6' if res else False)
    tc = 'https://github.com/restify/node-restify/pull/1031/commits/a015067232ad62aa035675dc63a46dce31fed3f3__fdse__a015067'
    res = Node.is_patch_url(url=tc)
    print(res['formatted_id'] == 'a01506' if res else False)
    tc = 'https://bugs.gentoo.org/attachment.cgi?id=215643__fdse__attachment 215643'
    res = Node.is_patch_url(url=tc)
    print(res['formatted_id'] == 'https://bugs.gentoo.org/attachment.cgi?id=215643' if res else False)
    tc = 'https://github.com/jnunemaker/httparty/commit/53a812426dd32108d6cba4272b493aa03bc8c031__fdse__xx'
    res = Node.is_patch_url(url=tc)
    print(res['formatted_url'] == 'https://github.com/jnunemaker/httparty/commit/53a812426dd32108d6cba4272b493aa03bc8c031' if res else False)
    tc = 'https://github.com/Legrandin/pycrypto/commit/9f912f13df99ad3421eff360d6a62d7dbec755c2__fdse__https://github.com/Leg...'
    res = Node.is_patch_url(url=tc)
    print(res['formatted_id'] == '9f912f' if res else False)
    tc = 'https://bitbucket.org/butor-team/portal/commits/cd7055d33e194fcf530100ee1d8d13aa9cde230b'
    res = Node.is_patch_url(url=tc)
    print(res['formatted_id'] == 'https://bitbucket.org/butor-team/portal/commit/cd7055' if res else False)
    tc = 'https://source.codeaurora.org/quic/le/meta-qti-bsp/commit/?id=e1a95254dd0ec874f884160aaf0f5ce7947a06c8'
    res = Node.is_patch_url(url=tc)
    print(res['formatted_id'] == 'https://source.codeaurora.org/quic/le/meta-qti-bsp/commit/e1a952' if res else False)
    tc = 'https://github.com/ImageMagick/ImageMagick/commit/2c75f301d9ac84f91071393b02d8c88c8341c91c__fdse__https://github.com/'
    res = Node.is_patch_url(url=tc)
    print(res['formatted_id'] == '2c75f3' if res else False)
    tc = 'https://github.com/openssl/openssl/commit/470990fee0182566d439ef7e82d1abf18b7085d7__fdse__'
    res = Node.is_patch_url(url=tc)
    print( True if res and res['formatted_id'] == '470990' else (res['formatted_id'],tc) )
    tc = 'http://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=3462896__fdse__from comment content'
    res = Node.is_patch_url(url=tc)
    print( True if res and res['formatted_id'] == 'http://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=3462896' else (res['formatted_id'],tc) )

def is_issue_test():
    # False
    tcs = [
        'https://issues.apache.org/jira/s/76e2e0ef77c870392faf3ad5edba7773-CDN/mkyotb/803005/bdb26e53b5dabdebb2a74849ead50650/0a4716d29b2d5b1bdcdb168b4efc119e/_/download/contextbatch/js/_super/batch.js?locale=en-UK',
       'https://issues.apache.org/jira/secure/Dashboard.jspa',
       'https://issues.apache.org/jira/',
       'http://issues.apache.org/enter_bug.cgi',
       'http://issues.apache.org/buglist.cgi?chfieldfrom=24h',
       'https://github.com/canonical-websites/www.ubuntu.com/issues/new?body=%0a%0a%0a---%0a*Reported%20from:%20https://ubuntu.com/security/notices/USN-1040-1*',
       'https://bugzilla.novell.com/',
       'https://bugzilla.novell.com/describecomponents.cgi',
       'https://bugzilla.novell.com/describecomponents.cgi',
       'https://bugzilla.novell.com/describecomponents.cgi?product=Baracus',
       "https://issues.apache.org/jira/browse/uima",
       "https://bugzilla.readthedocs.org/en/5.0/using/understanding.html__fdse__Help",
       'https://bugs.gentoo.org/buglist.cgi?component=Vulnerabilities&product=Gentoo%20Security&bug_status=__open____fdse__show other bugs',
       'https://bugs.gentoo.org/attachment.cgi?id=215643__fdse__attachment 215643',
       'https://bugs.eclipse.org/bugs/attachment.cgi?bugid=535670&action=enter',
       'https://github.com/join?return_to=https://github.com/nodejs/node/pull/new/2227).&source=login',
       'http://bugs.jqueryui.com/timeline?from=2012-11-17T22%3A23%3A23-05%3A00&precision=second__fdse__8 years ago',
       'https://bugzilla.mozilla.org/show_bug.cgi?id=1150351',
       'https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=733108',
        'https://bugs.gentoo.org/show_bug.cgi?id=352864#c11__fdse__Comment 11',
        'https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=733108'
    ]
    print('Teste cases for: False')
    for tc1 in tcs:
        res = Node.is_issue_url(url=tc1)
        if res: print(tc1)
    # tc = 'http://bugs.jqueryui.com/timeline?from=2012-11-17T22%3A23%3A23-05%3A00&precision=second__fdse__8 years ago'
    # res = Node.is_issue_url(url=tc)
    # print(res['formatted_id'] == 'issues.apache.org__fdse__OLINGO-1409' if res else False)

    print('Teste cases for: True')
    # True
    tcs = ['http://tickets.opscode.com/browse/CHEF-1289',
           'https://projects.puppetlabs.com/issues/13511',
           'https://pagure.io/389-ds-base/issue/50329',
           'https://tracker.phpbb.com/issues/?filter=15193',
           'https://tracker.phpbb.com/browse/PHPBB3-13551',
           'https://bugs.eclipse.org/bugs/show_bug.cgi?id=535670&GoAheadAndLogIn=1',
           'https://bugs.eclipse.org/bugs/show_bug.cgi?ctype=xml&id=535670',
           'https://github.com/apache/thrift/pull/1606/files/7a5e21'
           ]
    for tc1 in tcs:
        res = Node.is_issue_url(url=tc1)
        if not res: print('fail',tc1)
    # tc = 'https://tracker.phpbb.com/issues/?filter=15193'
    # res = Node.is_issue_url(url=tc)
    # print(res)

    # 格式
    # https://bugzilla.novell.com/747657 https://bugzilla.novell.com/show_bug.cgi?id=747657&GoAheadAndLogIn=1
    tc1 = 'https://issues.apache.org/jira/browse/OLINGO-1409'
    res = Node.is_issue_url(url=tc1)
    print(res['formatted_id']=='issues.apache.org__fdse__OLINGO-1409' if res else False)
    tc1 = 'https://issues.apache.org/jira/browse/OLINGO-1409</link>'
    res = Node.is_issue_url(url=tc1)
    print(res['formatted_id'] == 'issues.apache.org__fdse__OLINGO-1409' if res else False)
    tc1 = 'https://projects.puppetlabs.com/issues/13511'
    res = Node.is_issue_url(url=tc1)
    print(res['formatted_id'] == 'projects.puppetlabs.com__fdse__13511' if res else False)
    # tc1 = 'https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=733108'
    # res = Node.is_issue_url(url=tc1)
    # print(res['formatted_id'] == 'bugs.debian.org__fdse__733108' if res else False)
    tc1 = 'https://tracker.phpbb.com/issues/?filter=15193'
    res = Node.is_issue_url(url=tc1)
    print(res['formatted_id'] == 'tracker.phpbb.com__fdse__15193' if res else False)
    tc1 = 'https://tracker.phpbb.com/browse/PHPBB3-13551'
    res = Node.is_issue_url(url=tc1)
    print(res['formatted_id'] == 'tracker.phpbb.com__fdse__PHPBB3-13551' if res else False)
    tc1 = 'https://bugs.eclipse.org/bugs/show_bug.cgi?id=535670&GoAheadAndLogIn=1'
    res = Node.is_issue_url(url=tc1)
    print(res['formatted_id'] == 'bugs.eclipse.org__fdse__535670' if res else False)

if __name__ == '__main__':
    # url = 'https://github.com/tj/node-growl/issues/60'
    # res = Node.identify_target_types_of_nodes([url])
    # print(res.formatted_id)
    print('is_issue_test:')
    is_issue_test()
    # print( 'is_patch_test:')
    # is_patch_test()

    # Node(node_content_type='url',node_content='https://github.com/pmd/pmd/pull/592__fdse__#592')


#!/usr/bin/env python3

import bitcoin.rpc
from twisted.internet import reactor
from twisted.web import resource, server
import requests
import os

API_KEY = os.environ['WELCOME_BONUS_API_KEY']
VALUE = os.environ['WELCOME_BONUS_VALUE']
ENDPOINT = os.environ['WELCOME_BONUS_API_ENDPOINT']

class MyResource(resource.Resource):
    isLeaf = True

    @staticmethod
    def sendtoaddress(proxy, address, value):
        listunspent = proxy._call('listunspent', 0, 9999999, [], True, {"minimumAmount": value})
        print(listunspent)
        if len(listunspent) == 0:
            print("there aren't any available unspent")
            raise Exception
        firstunspent = listunspent[0]
        change = str(proxy._call('getnewaddress'))
        output = {}
        output[address] = value
        output[change] = float(firstunspent['amount']) - float(value)
        print(output)
        rawtx = proxy._call('createrawtransaction', [{"txid": firstunspent['txid'], "vout": firstunspent['vout']}], output )
        print(rawtx)
        signedrawtx = proxy._call('signrawtransaction', rawtx)
        signedrawtx = signedrawtx['hex']
        print(signedrawtx)
        result = proxy._call('sendrawtransaction', signedrawtx)
        print(result)

    @staticmethod
    def get_address(phone):
        r = requests.get(ENDPOINT + '/pn2a/v1/address/' + phone)
        if r.status_code != 200:
            raise LookupError
        address = r.json()['value']['address']
        return address

    @staticmethod
    def is_welcome_bonus_sent(phone):
        headers = {'api_key': API_KEY}
        r = requests.get(ENDPOINT + '/pn2a/v1/welcome_bonus/' + phone, headers=headers)
        if r.status_code != 200:
            raise LookupError
        print(r.json())
        code = r.json()['code']
        if code == 118021:
            return False
        else:
            if code == 118020:
                return True
        raise Exception

    @staticmethod
    def set_welcome_bonus(phone):
        headers = {'api_key': API_KEY}
        r = requests.post(ENDPOINT + '/pn2a/v1/welcome_bonus/' + phone, headers=headers)
        if r.status_code != 200:
            raise LookupError
        print(r.json())
        code = r.json()['code']
        if code == 118022:
            return True
        raise Exception

    @staticmethod
    def send_welcome_bonus(address,phone):
        proxy = bitcoin.rpc.Proxy()
        print(proxy.getinfo())
        isvalid = proxy._call('validateaddress', str(address))['isvalid']
        print("Is address valid? " + str(isvalid))
        if isvalid:

            MyResource.sendtoaddress(proxy, address, VALUE)
            print("sendtoaddress called")
            MyResource.set_welcome_bonus(phone)
            print("set_welcome_bonus called")

            return 'sent'
        else:
            return 'invalid address'

    def render_GET(self, request):
        request.setResponseCode(200)
        phone = request.postpath[0].decode('utf-8')
        try:
            address = MyResource.get_address(phone)
        except Exception as e:
            err = "can't lookup address from phone " + str(phone) + " " + str(e)
            print(err)
            return err

        print("Lookup address " + address)

        try:
            sent = MyResource.is_welcome_bonus_sent(phone)
        except Exception as e:
            err = "can't check if welcome bonus was already sent " + str(e)
            print(err)
            return err

        if sent:
            to_phone = "welcome bonus already sent to " + phone
            print(to_phone)
            return to_phone

        result = MyResource.send_welcome_bonus(address, phone)
        print(result)

        return result

site = server.Site(MyResource())

reactor.listenTCP(80, site)
reactor.run()

#  bitcoin-cli listunspent 1 99999 "[]" true ' { "minimumAmount": 0.06 }'


#!/usr/bin/python3

MT = [0 for a in range(624)]
index = 0

def num_to_bin(num):
    return "{0:b}".format(num)

def initialize_generator(seed):
    global index
    index = 0
    MT[0] = seed
    for i in range(1, 624):
        a = 1812433253 * (MT[i - 1] ^ (MT[i - 1] >> 30) + 1)
        a = str(num_to_bin(a))[-32:] # get lowest 32 bits
        a = int(a, 2)
        MT[i] = a

def generate_numbers():
    for i in range(0, 624):
        y = (MT[i] & 0x80000000) + (MT[(i + 1) % 624] & 0x7fffffff)
        MT[i] = MT[(i + 397) % 624] ^ (y >> 1)
        if y % 2 is not 0:
            MT[i] = MT[i] ^ 2567483615

def extract_number():
    global index
    if index is 0:
        generate_numbers()

    y = MT[index]
    y = y ^ (y >> 1)
    y = y ^ ((y << 7) & 2636928640)
    y = y ^ ((y << 15) & 4022730752)
    y = y ^ (y >> 18)
    index = (index + 1) % 624
    return y

import time
def timestamp():
    return int(time.time())

def generate_random_bit():
    num = extract_number() % 256
    return num #chr(num).encode('latin')

def mt19937_encrypt(seed, plain):
    initialize_generator(seed)
    res = b''
    for i in range(0, len(plain)):
        res += chr(generate_random_bit() ^ plain[i]).encode('latin')
    return res

def num_to_bin(num):
    return "{0:b}".format(num)

import random

def random_bytes(n):
    l = [chr(random.randint(0, 255)) for i in range(n)]
    l = ''.join(l)
    return l.encode('latin')

def truncate(num, nbits):
    return int(num_to_bin(num)[0:nbits], 2)

def encrypt_with_random_prefix(plain):
    seed = truncate(timestamp(), 16)
    prefix = random_bytes(random.randint(100, 1000))
    enc = mt19937_encrypt(seed, prefix + plain)
    return enc

def recover_the_key(enc, known_sufix):
    pref_len = len(enc) - len(known_sufix)
    pref = b'a' * pref_len
    print("Iterating from %d to %d" % (2 ** 15, 2 ** 16 + 1))
    for i in range(2 ** 15, 2 ** 16 + 1):
        seed = i
        if i % 1000 == 0:
            print(i)
        dec = mt19937_encrypt(seed, enc)
        if dec[-len(known_sufix):] == known_sufix:
            print("seed is: %d" % i)
            return i
    print("Couldn't recover key")
    return None

def main():
    plain = b'A' * 14
    enc = encrypt_with_random_prefix(plain)
    recovered_seed = recover_the_key(enc, plain)
    if recovered_seed is not None:
        print("Recovered seed: %d " % recovered_seed)

main()

"""
remaining:

>>> Use the same idea to generate a random "password reset token" using MT19937 seeded from the current time.
>>> Write a function to check if any given password token is actually the product of an MT19937 PRNG seeded with the current time.

^^^
Couldn't understand what you are asking exactly... should thinkg again after some time

"""


from channels.routing import ProtocolTypeRouter, URLRouter
from chat.auth_middleware import TokenAuthMiddleware
import chat.routing

application = ProtocolTypeRouter({
    'websocket': TokenAuthMiddleware(  # populates conn scope with auth'd user
        URLRouter(
            chat.routing.websocket_urlpatterns
        )
    ),
})


import os
import re
import datetime

from typing import List, Set
from amiyabot import Message, Chain
from core import bot as main_bot, log, AmiyaBotPluginInstance
from core.database.bot import DisabledFunction, FunctionUsed
from core.util import get_index_from_text, get_doc, check_file_content

from .database import ChannelRecord

curr_dir = os.path.dirname(__file__)
bot = AmiyaBotPluginInstance(
    name='功能管理',
    version='1.8',
    plugin_id='amiyabot-functions',
    plugin_type='official',
    description='管理已安装的插件功能',
    document=f'{curr_dir}/README.md',
    global_config_default=f'{curr_dir}/configs/global_config_default.json',
    global_config_schema=f'{curr_dir}/configs/global_config_schema.json',
)
disabled_remind = {}

@bot.message_before_handle
async def _(data: Message, factory_name: str, _):
    # 检查该 channel 是否已有禁用的功能
    disabled_functions_for_channel = DisabledFunction.select().where(DisabledFunction.channel_id == data.channel_id)

    # 检查是否已存在与当前 channel_id 相关的记录
    channel_record = ChannelRecord.get_or_none(channel_id=data.channel_id)

    # 如果记录不存在，创建一个新的记录并写入当前消息时间
    if not channel_record:
        ChannelRecord.create(channel_id=data.channel_id, last_message=datetime.datetime.now())

        # 如果该 channel 中已有禁用的功能，不更改当前状态
        if not disabled_functions_for_channel.exists():
            if bot.get_config('newChannelDisableAll'):
                log.info(f'关闭全部功能： {data.channel_id}')

                # 禁用所有功能
                disabled_all(data.channel_id)
                return False
    else:
        channel_record.last_message = datetime.datetime.now()
        channel_record.save()

    # 检查功能是否已被禁用
    disabled = DisabledFunction.get_or_none(function_id=factory_name, channel_id=data.channel_id)

    if disabled:
        if data.channel_id not in disabled_remind:
            disabled_remind[data.channel_id] = {}

        if factory_name not in disabled_remind[data.channel_id]:
            disabled_remind[data.channel_id][factory_name] = 1
        else:
            disabled_remind[data.channel_id][factory_name] += 1

        if disabled_remind[data.channel_id][factory_name] >= bot.get_config('disabledRemindRate'):
            disabled_remind[data.channel_id][factory_name] = 0
            plugin = main_bot.plugins[factory_name]

            await data.send(Chain(data).text(f'【{plugin.name}】功能已关闭，请管理员开启后再使用~'))

    return not bool(disabled)

@bot.message_after_handle
async def _(data: Chain, factory_name: str, _):
    _, is_created = FunctionUsed.get_or_create(function_id=factory_name)
    if not is_created:
        FunctionUsed.update(use_num=FunctionUsed.use_num + 1).where(FunctionUsed.function_id == factory_name).execute()

@bot.on_message(keywords=['功能', '帮助', '说明', 'help'], allow_direct=True)
async def _(data: Message):
    disabled_funcs: List[DisabledFunction] = DisabledFunction.select().where(
        DisabledFunction.channel_id == data.channel_id
    )
    disabled = [n.function_id for n in disabled_funcs]

    with open(f'{curr_dir}/template.md', mode='r', encoding='utf-8') as template:
        content = template.read().strip('\n')

    index = 1
    funcs = []
    items = ''
    for _, item in main_bot.plugins.items():
        if item.plugin_id == bot.plugin_id:
            continue

        status = '开启'
        if item.plugin_id in disabled:
            status = '已关闭'

        funcs.append(item)
        items += f'|{index}|{item.name}|{item.version}|{item.description}|{status}|\n'
        index += 1

    reply = await data.wait(Chain(data).markdown(content.format(items=items)))
    if reply:
        index = get_index_from_text(reply.text_digits, funcs)
        if index is not None:
            return Chain(reply).markdown(get_plugin_use_doc(funcs[index]))

@bot.on_message(keywords=re.compile(r'开启(全部|所有)?功能'), level=5)
async def _(data: Message):
    if not data.is_admin:
        return None

    disabled: List[DisabledFunction] = DisabledFunction.select().where(DisabledFunction.channel_id == data.channel_id)

    func_ids = get_plugins_set() & set([n.function_id for n in disabled])

    if func_ids:
        if data.verify.keypoint[0]:
            DisabledFunction.delete().where(DisabledFunction.channel_id == data.channel_id).execute()
            return Chain(data).text('已开启所有功能！')

        content, funcs = get_plugins_content(func_ids)

        reply = await data.wait(Chain(data).text('有以下可开启的功能，回复【序号】开启对应功能').markdown(content))
        if reply:
            index = get_index_from_text(reply.text_digits, funcs)
            if index is not None:
                func = funcs[index]

                DisabledFunction.delete().where(
                    DisabledFunction.channel_id == data.channel_id, DisabledFunction.function_id == func.plugin_id
                ).execute()

                return Chain(data).text(f'已开启功能【{func.name}】').markdown(get_plugin_use_doc(func))
    else:
        return Chain(data).text('未关闭任何功能，无需开启~')

@bot.on_message(keywords=re.compile(r'关闭(全部|所有)?功能'), level=5)
async def _(data: Message):
    if not data.is_admin:
        return None

    disabled: List[DisabledFunction] = DisabledFunction.select().where(DisabledFunction.channel_id == data.channel_id)

    func_ids = get_plugins_set() - set([n.function_id for n in disabled])

    if func_ids:
        if data.verify.keypoint[0]:
            disabled_all(data.channel_id)
            return Chain(data).text('已关闭所有功能！')

        content, funcs = get_plugins_content(func_ids)

        reply = await data.wait(Chain(data).text('有以下可关闭的功能，回复【序号】关闭对应功能').markdown(content))
        if reply:
            index = get_index_from_text(reply.text_digits, funcs)
            if index is not None:
                func = funcs[index]

                DisabledFunction.create(
                    function_id=func.plugin_id,
                    channel_id=data.channel_id,
                )

                return Chain(data).text(f'已关闭功能【{func.name}】')
    else:
        return Chain(data).text('已经没有可以关闭的功能了~')

def disabled_all(channel_id):
    funcs = [{'function_id': func, 'channel_id': channel_id} for func in get_plugins_set()]
    DisabledFunction.batch_insert(funcs)

def get_plugin_use_doc(instance: AmiyaBotPluginInstance):
    if hasattr(instance, 'instruction'):
        content = check_file_content(instance.instruction)
        if content:
            return f'# {instance.name}\n\n{content}'

    return get_doc(instance)

def get_plugins_set():
    return set([plugin_id for plugin_id in main_bot.plugins.keys() if plugin_id != bot.plugin_id])

def get_plugins_content(func_ids: Set[str]):
    content = '|序号|插件名|版本|描述|\n|----|----|----|----|\n'
    index = 1
    funcs = []
    for n in func_ids:
        item = main_bot.plugins[n]
        if item.plugin_id == bot.plugin_id:
            continue

        funcs.append(item)
        content += f'|{index}|{item.name}|{item.version}|{item.description}|\n'
        index += 1

    return content, funcs


import os
import boto3
import numerapi

tournament_file_name = 'tournament.parquet'

def handler(event, context):
	print('event:', event)

	api = numerapi.NumerAPI(
		public_id=config_data[os.getenv('PUBLIC_ID')],
		secret_key=config_data[os.getenv('SECRET_KEY')],
	)

	if not api.check_new_round():
		return True

	s3 = boto3.client('s3')

	try:
		api.download_dataset(
			filename=tournament_file_name,
			dest_path=filepath,
		)

		upload_file_response = s3.upload_file(
			tournament_file_name,
			os.getenv('DATA_BUCKET_NAME'),
			'tournament/'+tournament_file_name,
		)
		print('upload_file_response:', upload_file_response)

		return True

	except Exception as e:
		print('exception:', e)
		raise e


import sys

from io import StringIO

import json

import unittest

from parameterized import parameterized

from unittest.mock import patch

import idx

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

class Test_Case ( unittest.TestCase ) :

    data_1 = "uid=197697(phdye) gid=197121(None) groups=197697(phdye),197121(None)"

    @parameterized.expand([
        [ "no_args", data_1, [], '\n'+data_1+'\n' ],
        #
        [ "list", data_1, ['--list'], """
uid=
197697(phdye)
gid=
197121(None)
groups=
197697(phdye)
197121(None)
"""
        ],
        #
        [ "yaml", data_1, ['--yaml'], """
user:
  uid: 197697
  gecos: phdye
group:
  gid: 197121
  gecos: None
groups:
- gid: 197697
  gecos: phdye
- gid: 197121
  gecos: None

"""
        ],
        #
        [ "json", data_1, ['--json'], """
{
  "user": {
    "uid": 197697,
    "gecos": "phdye"
  },
  "group": {
    "gid": 197121,
    "gecos": "None"
  },
  "groups": [
    { "gid": 197697,
      "gecos": "phdye"
    },
    { "gid": 197121,
      "gecos": "None"
    }
  ]
}
"""
        ],
        #
        [ "groups", "197697 197121", ['--groups'], "\n197697 197121\n" ],
        #
        [ "groups-list", "197697 197121", ['--groups', '--list'], "\n197697\n197121\n" ],
        #
        [ "groups-yaml", "197697 197121", ['--groups', '--yaml'], """
groups:
- gid: 197697
- gid: 197121

"""
        ],
        #
        [ "groups-json", "197697 197121", ['--groups', '--json'], """
{
  "groups": [
    { "gid": 197697
    },
    { "gid": 197121
    }
  ]
}
"""
        ],
        #
    ] )

    def test_idx ( self, test_name, data, options, expected ):

        with patch('sys.stdout', new = StringIO()) as mock_out :
            idx.main(['id', '--data', data]+options)

        result = '\n' + mock_out.getvalue()

        # with open(f'log/out/{test_name}/result', 'w') as r, open('expected', 'w') as e :
        #     r.write( result )
        # with open(f'log/out/{test_name}/expected', 'w') as e:
        #     e.write( expected )

        self.assertEqual ( result, expected )

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


import os
from google.cloud import bigquery
import time

#########
#LOADING CSV FILE TO GOOGLE BIGQUERY
#########

#file to the credentials
os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = '/Users/selledge/Documents/keh_data_credentials.json'
client = bigquery.Client()

#set the table id (projectname.dataset.name.table.name)
table_id = 'keh-data.crawl_data.Web_Scrapping_Project'

#file path to the csv file
file_path = '/Users/selledge/Documents/pythonproject/ScrapingProject-main/ToScrapeProject3/project3_classes_file_complete.csv'

#this executes the job
job_config = bigquery.LoadJobConfig(
    source_format = bigquery.SourceFormat.CSV,
    #this skips the header if it is in the file
    skip_leading_rows = 1,
    autodetect=True
)

with open(file_path, 'rb') as source_file:
    job = client.load_table_from_file(source_file, table_id, job_config=job_config)

#while loop that checks whether the job is completed every 2 seconds and once it is complete it will print the result
while job.state != 'DONE':
    time.sleep(2)
    job.reload()
    print(job.state)

print(job.result())

#this code block makes sure that once the table is created
# it uses the bigquery api to retrieve the table to make sure it uploaded successfully

table = client.get_table(table_id) #make an api request
print(
    "Loaded {} rows and {} columns to {}".format(table.num_rows, len(table.schema), table_id)
)


import argparse
import sys

from os.path import exists

import numpy as np
import torch

max_val_abs = 32767
max_proba = 65536
min_cdf_bound = 2

def parse_args(argv):
    parser = argparse.ArgumentParser(description="extract latent from dataset")
    parser.add_argument("--model", type=str, required=True, help="model pth")
    parser.add_argument("--input", type=str, required=True, help="npy batch")
    parser.add_argument(
        "--nb_max", type=int, help="max latent to generate (all if not set)"
    )
    parser.add_argument(
        "--float_NHWC",
        action="store_true",
        help="store in float format SADL compatible",
    )
    parser.add_argument(
        "--output", type=str, required=True, help="tensor in binary format int16"
    )
    parser.add_argument("--verbose", action="store_true", help="verbose")
    args = parser.parse_args(argv)
    return args

def main(argv):  # noqa: C901
    args = parse_args(argv)

    print("[INFO] read checkpoint: ", args.model)
    checkpoint = torch.load(args.model, map_location="cpu")

    if args.verbose:
        for i, _k in checkpoint.items():
            print(i)

    autoencoder = checkpoint["model"]

    encoder = autoencoder.g_a

    if args.verbose:
        print("[INFO] encoder: {}".format(encoder))

    block_size = [256, 256]

    data: np.ndarray = np.memmap(args.input, mode="r", dtype="uint8")
    data = data.reshape((-1, block_size[0], block_size[1], 3))
    print("[INFO] training shape={}".format(data.shape))
    # get info with one run
    x1 = np.transpose(data[0], (2, 1, 0)).copy().astype("float32") / 255.0
    x1 = torch.tensor(x1)
    y_encode = encoder(x1.unsqueeze(0))
    y_encode = torch.round(y_encode)
    y_encode_int = y_encode.int()
    C = y_encode_int.shape[1]
    H = y_encode_int.shape[2]
    W = y_encode_int.shape[3]
    N = data.shape[0]

    if args.nb_max is not None:
        N = args.nb_max

    if args.float_NHWC:
        outputs: np.ndarray = np.memmap(
            args.output, mode="w+", dtype="float32", shape=(N, H, W, C)
        )
    else:
        outputs: np.ndarray = np.memmap(
            args.output, mode="w+", dtype="int16", shape=(N, C, H, W)
        )

    if exists(args.output + ".means"):
        m = np.fromfile(args.output + ".means", dtype="float32")
    else:
        m = np.zeros(C, dtype=float)
        for i in range(N):
            x1 = np.transpose(data[i], (2, 1, 0)).copy().astype("float32") / 255.0
            x1 = torch.tensor(x1)
            y_encode = encoder(x1.unsqueeze(0))
            m += np.mean(y_encode.cpu().detach().numpy(), (0, 2, 3))
        m /= N

    m = m.reshape(1, C, 1, 1)
    m_tensor = np.ones((1, C, H, W), dtype="float32") * m

    for i in range(N):
        x1 = np.transpose(data[i], (2, 1, 0)).copy().astype("float32") / 255.0
        x1 = torch.tensor(x1)
        y_encode = encoder(x1.unsqueeze(0))
        y_encode = np.round(y_encode.cpu().detach().numpy() - m_tensor)
        if args.float_NHWC:
            outputs[i] = np.transpose(y_encode.astype("float32"), (0, 2, 3, 1))
        else:
            # y_encode_int = y_encode.int()
            outputs[i] = y_encode.astype("int16")
        if args.verbose:
            sys.stdout.write("\r{}%     ".format(int(100.0 * i / N)))
            sys.stdout.flush()

    print("[INFO] wrote {}".format(args.output))
    if not exists(args.output + ".means"):
        m.astype("float32").tofile(args.output + ".means")

if __name__ == "__main__":
    main(sys.argv[1:])


"""
Parsing in Processing.py with pyparsing: a simple example

This example is drawn from John Strickler's article "Parseltongue":
https://www.accelebrate.com/blog/pyparseltongue-parsing-text-with-pyparsing/

It defines a simple parser to identify and extract
US Social Security Numbers (SSNs).

    grammar:
    ssn ::= nums+ '-' nums+ '-' nums+
    nums ::= '0' | '1' | '2' etc etc

"""

from pyparsing import *

dash = '-'

ssn_parser = Combine(
    Word(nums, exact=3)
    + dash
    + Word(nums, exact=2)
    + dash
    + Word(nums, exact=4)
)

input_string = """
    xxx 225-92-8416 yyy
    103-33-3929 zzz 028-91-0122
"""

for match, start, stop in ssn_parser.scanString(input_string):
    print(match, start, stop)


"""
Input: [{animal: mammal}, {lifeform: animal}, {cat: lion}, {mammal: cat}, {animal:bird}, {animal:fish}]
Output:
    lifeform
        animal
            mammal
                cat
                    lion
        bird
        fish
"""

def print_tree_relationships(relationships):
    adjacency_list = {}
    root_candidates = {}
    for parent, child in relationships:
        if parent in adjacency_list:
            adjacency_list[parent].append(child)
        else:
            adjacency_list[parent] = [child]

        if parent not in root_candidates:
            root_candidates[parent] = True
        root_candidates[child] = False

    parent = get_parent(root_candidates)
    explore(parent, adjacency_list, 0)

def get_parent(possible_parents):
    for parent in possible_parents:
        if possible_parents[parent]:
            return parent
    return None

def explore(root, adjacency_list, tabs):

    print_with_tabs(root, tabs)
    if root not in adjacency_list:
        return
    for value in adjacency_list[root]:
        explore(value, adjacency_list, tabs + 1)

def print_with_tabs(item, tabs):
    for _ in range(tabs):
        print("     ", end="", flush=True)
    print(item)

relationships = [("animal", "mammal"), ("lifeform", "animal"),
                 ("cat", "lion"), ("mammal", "cat"), ("animal", "bird"), ("animal", "fish")]

print_tree_relationships(relationships)


from connections import connect_dydx
from constants import ABORT_ALL_POSITIONS, FIND_COINTEGRATED, PLACE_TRADES
from private import abort_all_positions
from public import construct_market_prices
from cointegration import store_cointegration_results

if __name__ == '__main__':

    # Connect to client
    try:
        print('Connecting to client...')
        client = connect_dydx()
    except Exception as e:
        print('Error connecting to client :', e)
        exit(1)

    # Abote all open positions
    if ABORT_ALL_POSITIONS:
        try:
            print('Closing all positions...')
            close_orders = abort_all_positions(client)
        except Exception as e:
            print('Error closing all positions :', e)
            exit(1)

    # Find Cointegrated Pairs
    if FIND_COINTEGRATED:

        # Construct Market Prices
        try:
            print('Fetching market prices...')
            df_market_prices = construct_market_prices(client)
        except Exception as e:
            print('Error fetching market prices :', e)
            exit(1)

        # Store Cointegrated Pairs
        try:
            print('Storing cointegrated pairs...')
            store_result = store_cointegration_results(df_market_prices)
            if store_result != 'saved':
                print('Error saving cointegrated pairs')
                exit(1)
        except Exception as e:
            print('Error saving cointegrated pairs :', e)
            exit(1)

        # Place trades for opening positions
        if PLACE_TRADES:
            try:
                print('Finding trading opportunities...')
                open_positions(client)
            except Exception as e:
                print('Error trading pairs :', e)
                exit(1)


import json
from django.shortcuts import render
from django.http import HttpResponse
from django.http import HttpResponseRedirect
from rest_framework.renderers import TemplateHTMLRenderer
from django.core import serializers
import requests
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework import status
from .models import Article

# Create your views here.

#This function defines the GET and POST operations for my api choice
@api_view(["GET","POST"])
def api(req):
    if req.method == "GET":

        #Get all the articles in database and process them to produce a GET response
        articles = serializers.serialize( "python", Article.objects.all(),fields = ("Article_title","Article_summary","Article_authors","Article_link") )
        response ={}
        for i in range(len(articles)):
            response["article"+str(i+1)] = articles[i]["fields"]
        return Response(response,status=status.HTTP_200_OK)

    if req.method == "POST":

        #First try to catch possible errors with post body and produce an error response
        try:

            subject = req.POST["subject"]
            noOfArticles = req.POST["numberOfArticles"]

        except Exception as e:
            return Response("Bad Input",status=status.HTTP_400_BAD_REQUEST)

        try:
            int(noOfArticles)
        except Exception as e:
            return Response("numberOfArticles field should be an integer between 1 and 100",status=status.HTTP_400_BAD_REQUEST)

        if(int(noOfArticles)>100):
            return Response("Too large value for numberOfArticles field, try something smaller",status=status.HTTP_400_BAD_REQUEST)

        elif(int(noOfArticles)<= 0):
            return Response("numberOfArticles field cannot be non-positive",status=status.HTTP_400_BAD_REQUEST)

        #If post body is succesfull then make a search based on given inputs using external api: arXiv (https://arxiv.org/help/api/basics)
        parameters = {"search_query":"all:"+subject,"max_results":noOfArticles}
        data = requests.get("http://export.arxiv.org/api/query",params = parameters)

        #Process the data to find necessary information about article search result
        ArticleInfoList = findInfo(data,noOfArticles)

        newData = {}
        numberOfArticlesInDb = len(Article.objects.all())

        #For each result create the Article object to store and produce the api POST request response which is the found article attributes.
        for i in range(len(ArticleInfoList)):

            authors = ""
            for author in ArticleInfoList[i][2]:
                authors += author +','

            newData["article"+str(i+1+numberOfArticlesInDb)] = {"Article_title":ArticleInfoList[i][0],
                                                                "Article_summary":ArticleInfoList[i][1],
                                                                "Article_authors":authors,
                                                                "Article_link":ArticleInfoList[i][3]}

            newArticle = Article.objects.create(**newData["article"+str(i+1+numberOfArticlesInDb)])

        return Response(newData,status=status.HTTP_200_OK)

#Renders the index page for UI
def index(req):

    return render(req, "index.html")

#This function sends a request to api and uses it response to render the search history in html
def list(req):
    apiUrl = "http://"+req.get_host()+"/article/api"
    data = requests.get(apiUrl)
    data = data.text
    data =json.loads(data)
    Information = []

    i = 1
    for key in data:
            title = data[key]["Article_title"]
            summary = data[key]["Article_summary"]
            authors = data[key]["Article_authors"].split(",")[:-1]
            link = data[key]["Article_link"]
            Information.append((title,summary,authors,link,i))
            i+=1

    if len(Information)==0:
        return render(req,"list.html",{"ArticleInfoList":Information,"isEmpty":True})
    else:
        return render(req,"list.html",{"ArticleInfoList":Information,"isEmpty":False})

#This function sends a request to api and uses it response to render the search results in html based on the user input taken by user interface
def search(req):
    if req.method == "POST":

        subject = req.POST["subject"]
        noOfArticles = req.POST["numberOfArticles"]

        apiUrl = "http://"+req.get_host()+"/article/api"
        parameters = {"subject":subject,"numberOfArticles":noOfArticles}
        data = requests.post(apiUrl,data=parameters)

        data = data.text

        data =json.loads(data)
        Information = []

        i = 1
        for key in data:
                title = data[key]["Article_title"]
                summary = data[key]["Article_summary"]
                authors = data[key]["Article_authors"].split(",")[:-1]
                link = data[key]["Article_link"]
                Information.append((title,summary,authors,link,i))
                i+=1

        if len(Information) == 0:
            return render(req,"search.html",{"ArticleInfoList":Information,"isEmpty":True})

        return render(req,"search.html",{"ArticleInfoList":Information,"isEmpty":False})
    else :
        return render(req, "index.html")

#This function helps processing the external api's response to a dictionary format which is easier to work with.
def findInfo(data,noOfArticles):

    dataString = data.text
    ArticleInfoList = []

    for i in range(0,int(noOfArticles)):

        if dataString.count("<summary>") == 0:
            break

        startIndexOfTitle = dataString.index("<title>") + len("<title>")

        dataString = dataString[startIndexOfTitle:]

        endIndexOfTitle = dataString.index("</title>")
        startIndexOfSummary = dataString.index("<summary>")
        endIndexOfSummary = dataString.index("</summary>")

        title = dataString[:endIndexOfTitle]
        summary = dataString[startIndexOfSummary+len("<summary>"):endIndexOfSummary]

        dataString = dataString[endIndexOfSummary + len("</summmary>"):]

        authors = []
        dataCopy = dataString

        while(dataCopy.count("<name>")!=0 and dataCopy.count("</entry>")==int(noOfArticles)-i ):
            startIndexOfAuthor = dataCopy.index("<name>") + len("<name>")
            endIndexOfAuthor = dataCopy.index("</name>")

            author = dataCopy[startIndexOfAuthor:endIndexOfAuthor]
            authors.append(author)
            dataCopy = dataCopy[endIndexOfAuthor + len("</name>") : ]

        articleLinkStart = dataString.index("href=\"") + len("href=\"")
        articleLinkEnd = dataString.index("rel=") -2

        articleLink = dataString[articleLinkStart:articleLinkEnd]

        ArticleInfoList.append((title,summary,authors,articleLink,i+1))
    return ArticleInfoList

#This function is activated by UI and it deletes the article database therefore article history.
def deleteHistory(req):
    if req.method == "POST":
        try:
            Article.objects.all().delete()
            return HttpResponseRedirect("../article")
        except Exception as e:
            return Response("Could not performed deletion operation",status=status.HTTP_400_BAD_REQUEST)


class Solution:
    def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
        cans = []
        for n in candidates:
            n_cans = [(n, i) for i in range(0, (target // n) + 1)]
            cans.append(n_cans)
        res = []

        def dfs(i, ele, remain):
            if remain == 0:
                combis = []
                for e in ele:
                    combis.extend([e[0]] * e[1])
                if combis not in res:
                    res.append(combis)

            if i >= len(candidates):
                return

            for can in cans[i]:
                n = can[0] * can[1]

                if n > remain:
                    continue
                ele.append(can)
                dfs(i + 1, ele, remain - n)
                ele.pop()

        for i in range(len(candidates)):
            dfs(i, [], target)

        return res


import os
import sys
import json
import Bio
import argparse
from Bio import AlignIO
from Bio import SeqIO
from Bio.SeqUtils import seq3
from Bio.SeqUtils import seq1
import pandas as pd
import pyrosetta
pyrosetta.init()

# UPDATED JUNE 13, 2019
#
# This script is intended for use in the Homology modelling series if the user
# is modeling ENZYMES!!!!!!!!!!! This script will identify the catalytic residues in
# the targets from known catalytic residues in the templates, as well as generate
# distance constraints for CA-CA, CB-CB, CA-CB, and CB-CA atoms between the catalytic residues.
#
# Run this script after HM_ii_StructuralConst.py has generated .alignment.grishin.dist_csts
# files, and before HM_iii_Modelling.py.
#
# To run this script: python (path)/HM_eii_CatalyticConst.py -f "FAMILYNAME"
#
# Within your working directory make a data foldr and place these files:
#    ** aligned family fasta with TEMPLATES AND TARGETS! ("FAMILYNAME".family_fasta)
#    ** a file with template names and catalytic residues in three-letter-code+position comma-separated:
#                IE: "FAMILYNAME"_template_cats.txt"
#                >>  TEMPLATE1 ABC123,ABC123,ABC123
#                >>  TEMPALTE2 ABC123,ABC123,ABC123
#
# The first part of this script will generate the catalytic residues for each template in a .data file.
#
# The second part of this script will then calculate the atomic distances from the template pdbs in the
# templates folder, and from there append this distance information with specific target residue
# information onto the .alignment.grishin.dist_csts files for each target.
#
# This script saves many .txt, .csv and .data files for the user to use/call later.

##############PART i: Family Residue Identifier#############################################

parser = argparse.ArgumentParser()
parser.add_argument('-f', '--family',dest='family', type=str, help="Designated family name.", required=True)
args = parser.parse_args()

print('Family = %s' % (args.family))

os.chdir('data/')

data = {}
for fasta in SeqIO.parse("%s.family_fasta" % (args.family), "fasta"): # Counts each residue position
    seq_list = []
    counter = 0
    for char in fasta.seq:
        if char == '-':
            seq_list.append(char)
        else:
            counter += 1
            seq_list.append('%s%s' % (char, counter))
    data[fasta.id] = seq_list

df1 = pd.DataFrame(data) #A newdataframe with numbered residues with residue one-letter-codes
temp_res = {}

with open('%s_template_cats.txt' % (args.family), 'r') as f: # Read in catalytic information about templates. #
    for line in f:
        list2 = []
        a = line.strip()
        z = a.split(" ")
        with open("../templates/%s.data" %(z[0]), 'w') as q: # Writes individual catalytic data to file for each template. #
            q.write(z[1])
        q.close()
        b = a.replace(",", " ")
        c = b.split(" ")
        list = c # Strips spaces and commas from input file. #
        for i in range(1,len(list)):
            residue = str(list[i])
            one = seq1(residue[0:3])
            position = str(residue[3:])
            one_res = str("%s%s" % (one, position))
            list2.append(one_res)
        temp_res[list[0]] = list2 # Generates dictionary with template and one-letter-code residue info. #

template = []
positions = []
temp_pos = {}

#Confirmation that catalytic residues within the templates are aligned within the dataframe#

df1.to_csv(args.family + ".csv")
for i in temp_res:
    print("Template = " + i)
    template.append(i)
    posit = [] # Temporary Positions List
    for j in temp_res[i]:
        print("Residue = " + j)
        posit.append(df1[df1[i] == j].iloc[0].name)
        if df1[df1[i] == j].iloc[0].name in positions:
            pass
        else:
            positions.append(df1[df1[i] == j].iloc[0].name)
    temp_pos[i] = posit

nomatchs = 0 # No Matches Counter
for i in temp_pos: # Prints message to confirm that templates match each other! #
    if temp_pos[i] == positions:
        print(i + " Matches")
    else:
        print(i + " Does Not Match!!!!!!")
        nomatchs += 1 # Adds to No matches counter

if nomatchs != 0:
    sys.exit()

print(positions)

family = {}

for i in df1: # Parsing family dataframe for each catalytic residue for each target. #
    name = i
    locations = []
    for j in positions:
        locations.append(df1[name].loc[j])
    family[name] = locations # Generates a new family dictionary of catalytic residues. #

with open('%s_CatRes.txt' % (args.family), 'w') as file:
    file.write(json.dumps(family)) # Writes dictionary to file for safe keeping. #
file.close()

with open('%s_family_residues.txt' % (args.family), 'w') as g: # Writing catalytic residue information for later in three-letter-code. #
    g.write('ID Res1 Pos1 Res2 Pos2 Res3 Pos3\n')
    for i in family:
        if i in template:
            pass
        else:
            g.write(i)
            for j in family[i]:
                residue = j
                three = seq3(residue[0:1]) # Converts one- to three-letter-code. #
                position = str(residue[1:])
                three_res = str("%s %s" % (three, position))
                g.write(" %s" % (three_res.upper()))
            g.write('\n')
g.close()
os.chdir('../templates/')

#########################PART ii: Catalytic constraints generator#############################

template = []
residue1 = []
residue2 = []
pairing = []
CA1CA2 = []
CB1CB2 = []
CA1CB2 = []
CB1CA2 = []

for i in os.listdir('.'): # Parsing thru data files. #
    if i.endswith('.data'):
        template_n = i[:-5]
        res_list = []
        with open(i, 'r') as f:
            for line in f:
                a = line.strip()
                b = a.replace(",", " ")
                c = b.split(" ")
                list = c
                for j in range(len(list)):
                    res = str(list[j])
                    position = int(res[3:])
                    res_list.append(position)
        pose = pyrosetta.rosetta.core.import_pose.pose_from_file('%s.pdb' % (template_n))
        for k in range(0,len(res_list)): # Now we will begin calculating atomic distances. #
            pairing.append(k+1)
            template.append(template_n)
            if k <= len(res_list)-2:
                x = res_list[k]
                y = res_list[k+1]
            else:
                x = res_list[0]
                y = res_list[len(res_list)-1]
            CA1 = pose.residue(x).xyz('CA')
            CB1 = pose.residue(x).xyz('CB')
            CA2 = pose.residue(y).xyz('CA')
            CB2 = pose.residue(y).xyz('CB')
            CA1CA2_xyz = CA1 - CA2
            CB1CB2_xyz = CB1 - CB2
            CA1CB2_xyz = CA1 - CB2
            CB1CA2_xyz = CB1 - CA2
            residue1.append(x)
            residue2.append(y)
            CA1CA2.append(CA1CA2_xyz.norm())
            CB1CB2.append(CB1CB2_xyz.norm())
            CA1CB2.append(CA1CB2_xyz.norm())
            CB1CA2.append(CB1CA2_xyz.norm())

df = pd.DataFrame(zip(template,pairing,residue1,residue2,CA1CA2,CB1CB2,CA1CB2,CB1CA2),
                  columns=['template','pairing','residue1','residue2','CA1CA2','CB1CB2','CA1CB2','CB1CA2'])

pairs = []
for i in set(pairing):
    pairs.append(i)

CACA_average = []
CBCB_average = []
CACB_average = []
CBCA_average = []

with open('../data/%s_distances.txt' % (args.family), 'w') as distance: # Calculates distances and saves to external file
    distance.write('Pair CACA CBCB CACB CBCA\n')
    for i in pairs:
        distance.write('%s ' % (i))
        df_copy = df[df['pairing'] == i]
        CACA_average.append(df_copy['CA1CA2'].mean())
        distance.write('%s ' % (df_copy['CA1CA2'].mean()))
        CBCB_average.append(df_copy['CB1CB2'].mean())
        distance.write('%s ' % (df_copy['CB1CB2'].mean()))
        CACB_average.append(df_copy['CA1CB2'].mean())
        distance.write('%s ' % (df_copy['CA1CB2'].mean()))
        CBCA_average.append(df_copy['CB1CA2'].mean())
        distance.write('%s\n' % (df_copy['CB1CA2'].mean()))
distance.close()

listdata = []

d = pd.read_csv('../data/%s_family_residues.txt' % (args.family), sep='\s+') # Opens last file from first step
listdata.append(d) # Creates new dataframe with catalytic identifiers
df_fam = pd.concat(listdata)

os.chdir('../')
folders = [] # Generate list of current directories for cross-reference
for root, dirs, fils in os.walk('.'):
    for i in dirs:
        folders.append(i)

for i in df_fam['ID']: # Slices new DF for each target. #
    if i in template:
        pass
    elif i in folders:
        os.chdir('%s/' % (i)) # Changes to target directory
        print('Adding catalytic residue constraints to target: ' + i)
        with open('%s.alignment.grishin.dist_csts' % (i), 'a') as h: # Opens structural constraint file for appending. #
            df_famtest = df_fam[df_fam['ID']==i]
            for j in pairs:
                if j <= pairs[-2]: # Generates residue pairs based upon number of catalytic residues. #
                    res1 = df_famtest['Pos%s' % (j)].iloc[0]
                    res2 = df_famtest['Pos%s' % (j+1)].iloc[0]
                else:
                    res1 = df_famtest['Pos%s' % (pairs[0])].iloc[0]
                    res2 = df_famtest['Pos%s' % (pairs[-1])].iloc[0]
                ca_ca_d = CACA_average[pairs.index(j)]
                cb_cb_d = CBCB_average[pairs.index(j)]
                ca_cb_d = CACB_average[pairs.index(j)]
                cb_ca_d = CBCA_average[pairs.index(j)]
                h.write('AtomPair CA %s CA %s SCALARWEIGHTEDFUNC 1000 HARMONIC %s 1.0\n' % (res1, res2, round(ca_ca_d, 2)))
                h.write('AtomPair CB %s CB %s SCALARWEIGHTEDFUNC 1000 HARMONIC %s 1.0\n' % (res1, res2, round(cb_cb_d, 2)))
                h.write('AtomPair CA %s CB %s SCALARWEIGHTEDFUNC 1000 HARMONIC %s 1.0\n' % (res1, res2, round(ca_cb_d, 2)))
                h.write('AtomPair CB %s CA %s SCALARWEIGHTEDFUNC 1000 HARMONIC %s 1.0\n' % (res1, res2, round(cb_ca_d, 2)))
        h.close
        os.chdir('../') # Returns to working directory


import slave
import logging
from slave.transport import Timeout
from slave.protocol import Protocol
from message import AbstractMessage, Message, Response

import e21_util
from e21_util.lock import InterProcessTransportLock
from e21_util.error import CommunicationError

class PhytronProtocol(Protocol):
    def __init__(self, slave_addr=0, logger=None):

        if logger is None:
            logger = logging.getLogger(__name__)
            logger.addHandler(logging.NullHandler())

        self.logger = logger
        self.receiver = slave_addr

    def set_logger(self, logger):
        self.logger = logger

    def clear(self, transport):
        with InterProcessTransportLock(transport):
            self.logger.debug("Clearing message queue")
            while True:
                try:
                    transport.read_bytes(32)
                except slave.transport.Timeout:
                    return

    def send_message(self, transport, message):

        data = message.get_raw()
        self.logger.debug('Send: "%s"', message)

        transport.write(data)

    def read_response(self, transport):
        try:
            response = transport.read_until(Message.ETX)
            ret = []
            for chunk in response:
                ret.append(chr(chunk))
            ret.append(Message.ETX)
            return ret
        except:
            raise CommunicationError("Could not read response")

    def query(self, transport, message):
        with InterProcessTransportLock(transport):
            if not isinstance(message, AbstractMessage):
                raise TypeError("message must be an instance of AbstractMessage")

            msg = message.get_message()
            msg.set_address(self.receiver)
            msg.set_checksum(msg.compute_checksum())

            self.send_message(transport, msg)
            response = self.read_response(transport)

            resp = message.create_response(response)

            if not resp.is_valid():
                self.logger.error("Received invalid response: %s", resp)
                raise CommunicationError("Invalid response")

            if not resp.is_successful():
                self.logger.warning("Action (%s) was not successful: %s", message, resp)

            return resp

    def write(self, transport, message):
        return self.query(transport, message)


class getMaxRepetitions:
    def solution(self, s1: str, n1: int, s2: str, n2: int) -> int:
        dp = []
        for i in range(len(s2)):
            start = i
            cnt = 0
            for j in range(len(s1)):
                if s1[j] == s2[start]:
                    start = start + 1
                    if start == len(s2):
                        start = 0
                        cnt = cnt + 1
            dp.append((start,cnt))
        res = 0
        next = 0
        for _ in range(n1):
            res = res + dp[next][1]
            next = dp[next][0]
        return res // n2

obj = getMaxRepetitions()
s1 ="acb"
n1 = 4
s2 ="ab"
n2 = 2
res = obj.solution(s1, n1, s2, n2)
print(res)

466. Count The Repetitions/getMaxRepetitions.py


# -*- coding: utf-8 -*-
import torch
import torch.nn as nn
import os
import numpy as np
import pickle
import argparse
import torch.optim as optim
from datetime import datetime
from dscv.engine.model_trainer import ModelTrainer
from dscv.utiles.common import setup_seed
from dscv.utiles.draw import show_confMat, plot_line
from dscv.utiles.logger import make_logger
from dscv.modeling.build import get_model
from dscv.config.flower_config import cfg
from dscv.checkpoint.save import save_model
from dscv.data.datasets.flower_102 import make_data_loader
from dscv.modeling.loss.label_smooth import LabelSmoothLoss

# import sys
# BASE_DIR = os.path.dirname(os.path.abspath(__file__))
# sys.path.append(os.path.join(BASE_DIR, '..'))

def main(analysis_bad_case=False):
    setup_seed(12345)  # 先固定随机种子

    parser = argparse.ArgumentParser(description='Training')
    parser.add_argument('--lr', default=None, help='learning rate')
    parser.add_argument('--bs', default=None, help='training batch size')
    parser.add_argument('--max_epoch', default=None)
    parser.add_argument('--data_root_dir', default=r"F:\23-deepshare\09-deep_share_cv_code\datasets\102flowers",
                        help="path to your dataset")
    args = parser.parse_args()
    cfg.flower_data_root = args.data_root_dir if args.data_root_dir else cfg.flower_data_root
    cfg.lr_init = args.lr if args.lr else cfg.lr_init
    cfg.train_bs = args.bs if args.bs else cfg.train_bs
    cfg.max_epoch = args.max_epoch if args.max_epoch else cfg.max_epoch

    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

    # 创建logger
    res_dir = os.path.join("..", "results")
    logger, log_dir = make_logger(res_dir)

    # step1： 数据集
    train_loader = make_data_loader(cfg, mode="train")
    valid_loader = make_data_loader(cfg, mode="valid")

    # step2: 模型
    model = get_model(cfg, cfg.flower_cls_num, logger)
    model.to(device)  # to device， cpu or gpu

    # step3: 损失函数、优化器
    if cfg.label_smooth:
        loss_f = LabelSmoothLoss(cfg.label_smooth_eps)
    else:
        loss_f = nn.CrossEntropyLoss()
    optimizer = optim.SGD(model.parameters(), lr=cfg.lr_init, momentum=cfg.momentum, weight_decay=cfg.weight_decay)
    scheduler = optim.lr_scheduler.MultiStepLR(optimizer, gamma=cfg.factor, milestones=cfg.milestones)

    # step4: 迭代训练
    # 记录训练所采用的模型、损失函数、优化器、配置参数cfg
    logger.info(
        "cfg:\n{}\n loss_f:\n{}\n scheduler:\n{}\n optimizer:\n{}\n model:\n{}".format(
            cfg, loss_f, scheduler, optimizer, model
        )
    )

    loss_rec = {"train": [], "valid": []}
    acc_rec = {"train": [], "valid": []}
    best_acc, best_epoch = 0, 0
    for epoch in range(cfg.max_epoch):
        # train for one epoch
        loss_train, acc_train, mat_train, path_error_train = ModelTrainer.train(
            train_loader, model, loss_f, optimizer, scheduler, epoch, device, cfg, logger
        )
        # eval for after training for a epoch
        loss_valid, acc_valid, mat_valid, path_error_valid = ModelTrainer.valid(
            valid_loader, model, loss_f, device
        )
        # display info for that training epoch
        logger.info(
            "Epoch[{:0>3}/{:0>3}] Train Acc: {:.2%} Valid Acc:{:.2%} Train loss:{:.4f} Valid loss:{:.4f} LR:{}".
            format(
                epoch + 1, cfg.max_epoch, acc_train,
                acc_valid, loss_train, loss_valid,
                optimizer.param_groups[0]["lr"]
            )
        )
        # update training lr every epoch
        scheduler.step()

        # 记录训练信息
        loss_rec["train"].append(loss_train), loss_rec["valid"].append(loss_valid)
        acc_rec["train"].append(acc_train), acc_rec["valid"].append(acc_valid)
        # 保存混淆矩阵图
        show_confMat(mat_train, cfg.flower_cls_names, "train", log_dir, epoch=epoch, verbose=(epoch == cfg.max_epoch - 1))
        show_confMat(mat_valid, cfg.flower_cls_names, "valid", log_dir, epoch=epoch, verbose=(epoch == cfg.max_epoch - 1))
        # 保存loss曲线， acc曲线
        plt_x = np.arange(1, epoch + 2)
        plot_line(plt_x, loss_rec["train"], plt_x, loss_rec["valid"], mode="loss", out_dir=log_dir)
        plot_line(plt_x, acc_rec["train"], plt_x, acc_rec["valid"], mode="acc", out_dir=log_dir)

        # 模型保存
        if acc_valid > best_acc:
            save_model(epoch, best_acc, model, optimizer, log_dir, cfg)
            best_epoch = epoch
            best_acc = acc_valid

        if analysis_bad_case:
            # 保存错误图片的路径
            err_ims_name = "error_imgs_{}.pkl".format(epoch) if epoch == (cfg.max_epoch - 1) else "error_imgs_best.pkl"
            path_err_imgs = os.path.join(log_dir, err_ims_name)
            error_info = {"train": path_error_train, "valid": path_error_valid}
            pickle.dump(error_info, open(path_err_imgs, 'wb'))

    logger.info(
        "{} done, best acc: {} in :{}".format(
            datetime.strftime(datetime.now(), '%m-%d_%H-%M'), best_acc, best_epoch
        )
    )

if __name__ == "__main__":
    main()


# Method 1
def majorityElement(nums):
    ch = {}
    for i in nums:
        if i in ch:
            ch[i] += 1
        else:
            ch[i] = 1

    num = max(ch.keys())
    return num

num = majorityElement([2, 2, 1, 1, 1, 2, 2])
print(f"Majority element is {num}.")

# Method 2
def majorityElements(num):
    num.sort()
    return num[(len(num) // 2)]


from py_finance import YahooFinanceClient
from py_finance import InvestorsUtilities

def showIndex(ticker, startDate, endDate):
    print(ticker)
    stockClient = YahooFinanceClient(ticker)
    stockHistory = stockClient.getHistory(startDate, endDate)
    stockHistory.calcInvestorsData()
    stockHistory.printToScreen()

# stockSymbol = input("Enter stock symbol:")
# startDate = input("Start date (yyyy-mm-dd):")
# endDate = input("End date (yyyy-mm-dd):")
#
# if stockSymbol == "all":
#     showIndex('^DJT', startDate, endDate)
#     print('*******************')
#     showIndex('^DJI', startDate, endDate)
#     print('*******************')
#     showIndex('^GSPC', startDate, endDate)
#     print('*******************')
#     showIndex('^IXIC', startDate, endDate)
# else:
#     showIndex(stockSymbol, startDate, endDate)

thing1 = '2017-11-30'
thing2 = '2017-11-29'
thing3 = '2018-01-01'

print(thing1 == thing2)
print(thing1 >= thing2)
print(thing1 >= thing3)


from telebot import types

def notification_new_ref(worker_id, sended_message):
	try:

		from worker_config import bot

		bot.send_message(worker_id, sended_message, parse_mode = 'html')

	except Exception as e:
		print(e)

def notification_to_receive(worker_id, mamont_id, sended_message):
	try:

		from worker_config import bot

		inline_keyboard = types.InlineKeyboardMarkup(row_width = 2)
		inline_1 = types.InlineKeyboardButton(text = "Одобрить", callback_data = f'ACCEPT_CASINO_{mamont_id}')
		inline_2 = types.InlineKeyboardButton(text = "Отклонить", callback_data = f'CANCEL_CASINO_{mamont_id}')
		inline_keyboard.add(inline_1, inline_2)

		bot.send_message(worker_id, sended_message, parse_mode = 'html', reply_markup = inline_keyboard)

	except Exception as e:
		print(e)

def notification_new_deposit(worker_id, mamont_id, value, sended_message):
	try:

		from worker_config import bot

		inline_keyboard = types.InlineKeyboardMarkup(row_width = 1)
		inline_1 = types.InlineKeyboardButton(text = "Оплатить", callback_data = f'DEPOSIT_CASINO_{mamont_id}_{value}')
		inline_keyboard.add(inline_1)

		bot.send_message(worker_id, sended_message, parse_mode = 'html', reply_markup = inline_keyboard)

	except Exception as e:
		print(e)

def notification_to_accept_receive(mamont_id):
	try:
		from casino_config import bot

		bot.send_message(mamont_id, 'Администрация одобрила вывод\nДенежные средства поступят в течение 5-10 минут', parse_mode = 'html')
	except Exception as e:
		print(e)

def notification_new_profit(worker_id, chat_workers, chat_channel, value, sended_message, username_worker, share):
	try:
		from worker_config import bot

		bot.send_message(worker_id, sended_message, parse_mode = 'html') # Сообщение воркеру
		bot.send_message(chat_workers, f'💞 Успешная оплата\n💸 Сумма платежа: {value} ₽\n👨💻 Воркер: {username_worker}', parse_mode = 'html') # Сообщение в чат

		inline_keyboard = types.InlineKeyboardMarkup(row_width = 1)
		inline_1 = types.InlineKeyboardButton(text = "Выплачено", callback_data = f'PAID')
		inline_keyboard.add(inline_1)

		bot.send_message(chat_channel, f'💞 Успешная оплата\nДоля воркера ~ {share}\n\n💸 Сумма платежа: {value} ₽\n👨💻 Воркер: {username_worker}', parse_mode = 'html',
		reply_markup = inline_keyboard) # Сообщение в канал

	except Exception as e:
		print(e)

def sended_message_to_mamont(mamont_id, sended_message):
	try:
		from casino_config import bot

		bot.send_message(mamont_id, sended_message, parse_mode = 'html')

	except Exception as e:
		print(e)