GitHub PullRequestReviewCommentEvent at 2014-08-22 21:48:07
Repository: qiime
Actor: gregcaporaso
Payload: {"action":"created","comment":{"url":"https://api.github.com/repos/biocore/qiime/pulls/comments/16623293","id":16623293,"diff_hunk":"@@ -116,6 +118,344 @@ def _parse_id_to_taxonomy_file(f):\n         return result\n \n \n+class SortMeRNATaxonAssigner(TaxonAssigner):\n+    \"\"\" Assign taxonomy using SortMeRNA\n+    \"\"\"\n+\n+    Name = 'SortMeRNATaxonAssigner'\n+    Application = \"SortMeRNA\"\n+    Citation = (\"SortMeRNA is hosted at:\\n\"\n+                \"http://bioinfo.lifl.fr/RNA/sortmerna\\n\"\n+                \"https://github.com/biocore/sortmerna\\n\\n\"\n+                \"The following paper should be cited if this resource is \"\n+                \"used:\\n\\n\"\n+                \"Kopylova, E., Noe L. and Touzet, H.,\\n\"\n+                \"SortMeRNA: fast and accurate filtering of ribosomal RNAs \"\n+                \"in\\n\"\n+                \"metatranscriptomic data, Bioinformatics (2012) 28(24)\\n\"\n+                )\n+    _tracked_properties = ['Application', 'Citation']\n+\n+    def __init__(self, params):\n+        _params = {\n+            # id to taxonomy filepath\n+            'id_to_taxonomy_fp': None,\n+            # reference sequences filepath\n+            'reference_sequences_fp': None,\n+            # reference sequences indexed database\n+            'sortmerna_db': None,\n+            # Fraction of sequence hits that a taxonomy assignment\n+            # must show up in to be considered the consensus assignment\n+            'min_consensus_fraction': 0.51,\n+            # minimum identity to consider a hit\n+            'min_percent_id': 90.0,\n+            # minimum query coverage to consider a hit\n+            'min_percent_cov': 90.0,\n+            # output 10 best alignments\n+            'best_N_alignments': 10,\n+            # E-value\n+            'e_value': 1,\n+            # threads\n+            'threads': 1,\n+            # label to apply for queries that cannot be assigned\n+            'unassignable_label': 'Unassigned'\n+        }\n+        _params.update(params)\n+        super(SortMeRNATaxonAssigner, self).__init__(_params)\n+\n+    def __call__(self,\n+                 seq_path,\n+                 result_path=None,\n+                 log_path=None,\n+                 HALT_EXEC=False):\n+        \"\"\"Returns mapping of each seq to (taxonomy, consensus fraction, n).\n+\n+        Parameters\n+        ----------\n+        seq_path : str, mandatory\n+            The filepath to input sequences.\n+        result_path : str, optional\n+            The filepath to store resulting alignments.\n+        log_path : str, optional\n+            The filepath to store logging information.\n+        HALT_EXEC : bool, debugging parameter\n+            If passed, will exit just before the sortmerna command in issued\n+            and will print out the command that would have been called\n+            to stdout.\n+\n+        Returns\n+        -------\n+        None if result_path = None\n+        dict if result_path != None\n+\n+            The results will be written to result_path as tab-separated\n+            lines of:\n+                query_id <tab> tax <tab> consensus fraction <tab> n\n+\n+            The values represent:\n+            tax: the consensus taxonomy assignment\n+            consensus fraction: the fraction of the assignments for the\n+            query that contained the lowest level tax assignment that is\n+            included in tax (e.g., if the assignment goes to genus level,\n+            this will be the fraction of assignments that had the consensus\n+            genus assignment)\n+            n: the number of assignments that were considered when\n+            constructing the consensus\n+        \"\"\"\n+        # Check input reference sequence and taxonomy are provided\n+        if self.Params['reference_sequences_fp'] is None:\n+            raise ValueError(\"Filepath for reference sequences is mandatory.\")\n+        if self.Params['id_to_taxonomy_fp'] is None:\n+            raise ValueError(\"Filepath for id to taxonomy map is mandatory.\")\n+\n+        # initialize the logger\n+        logger = self._get_logger(log_path)\n+        logger.info(str(self))\n+        self.dirs_to_remove = []\n+\n+        # Indexed database not provided, build it\n+        if not self.Params['sortmerna_db']:\n+            output_dir = mkdtemp()\n+            self.sortmerna_db, files_to_remove = \\\n+                build_database_sortmerna(abspath(self.Params[\n+                    'reference_sequences_fp']),\n+                    output_dir=output_dir)\n+            self.dirs_to_remove.append(output_dir)\n+\n+        # Indexed database provided\n+        else:\n+            self.sortmerna_db = self.Params['sortmerna_db']\n+\n+        # Set SortMeRNA's output directory\n+        if result_path is None:\n+            output_dir = mkdtemp()\n+            self.dirs_to_remove.append(output_dir)\n+        else:\n+            output_dir = dirname(abspath(result_path))\n+\n+        # Call sortmerna mapper\n+        app_result =\\\n+            sortmerna_map(seq_path=seq_path,\n+                          output_dir=output_dir,\n+                          sortmerna_db=self.sortmerna_db,\n+                          refseqs_fp=self.Params['reference_sequences_fp'],\n+                          e_value=self.Params['e_value'],\n+                          threads=self.Params['threads'],\n+                          best=self.Params['best_N_alignments'],\n+                          HALT_EXEC=False)\n+\n+        with open(self.Params['id_to_taxonomy_fp'], \"U\") as id_to_taxonomy_f:\n+            self.id_to_taxonomy_map =\\\n+                self._parse_id_to_taxonomy_file(id_to_taxonomy_f)\n+\n+        blast_tabular_fp = app_result['BlastAlignments'].name\n+        query_to_assignments = self._blast_to_tax_assignments(blast_tabular_fp)\n+        result = self._tax_assignments_to_consensus_assignments(\n+            query_to_assignments)\n+\n+        # Write results to file\n+        if result_path is not None:\n+            with open(result_path, 'w') as of:\n+                of.write('#OTU ID\\ttaxonomy\\tconfidence\\tnum hits\\n')\n+                for seq_id, (assignment, consensus_fraction, n) in result.items():\n+                    assignment_str = ';'.join(assignment)\n+                    of.write('%s\\t%s\\t%1.2f\\t%d\\n' % (\n+                        seq_id, assignment_str, consensus_fraction, n))\n+            result = None\n+            logger.info('Result path: %s' % result_path)\n+        else:\n+            # If no result_path was provided, the result dict is\n+            # returned as-is.\n+            logger.info('Result path: None, returned as dict.')\n+\n+        # clean up\n+        map(rmtree, self.dirs_to_remove)\n+\n+        return result\n+\n+    def _get_logger(self, log_path=None):\n+        if log_path is not None:\n+            handler = logging.FileHandler(log_path, mode='w')\n+        else:\n+            class NullHandler(logging.Handler):\n+\n+                def emit(self, record):\n+                    pass\n+            handler = NullHandler()\n+        logger = logging.getLogger(\"SortMeRNATaxonAssigner logger\")\n+        logger.addHandler(handler)\n+        logger.setLevel(logging.INFO)\n+        return logger\n+\n+    def _blast_to_tax_assignments(self,","path":"qiime/assign_taxonomy.py","position":270,"original_position":198,"commit_id":"d87ab9636a51e6a1813b0f6c18223f6aae8c4089","original_commit_id":"fea561a94216e1c1808058b25a745383bc274ce4","user":{"login":"gregcaporaso","id":192372,"avatar_url":"https://avatars.githubusercontent.com/u/192372?v=2","gravatar_id":"24f019bae9a9c4282123961b01c7f0d5","url":"https://api.github.com/users/gregcaporaso","html_url":"https://github.com/gregcaporaso","followers_url":"https://api.github.com/users/gregcaporaso/followers","following_url":"https://api.github.com/users/gregcaporaso/following{/other_user}","gists_url":"https://api.github.com/users/gregcaporaso/gists{/gist_id}","starred_url":"https://api.github.com/users/gregcaporaso/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gregcaporaso/subscriptions","organizations_url":"https://api.github.com/users/gregcaporaso/orgs","repos_url":"https://api.github.com/users/gregcaporaso/repos","events_url":"https://api.github.com/users/gregcaporaso/events{/privacy}","received_events_url":"https://api.github.com/users/gregcaporaso/received_events","type":"User","site_admin":false},"body":"That makes sense, thanks! As we discussed, when we port to BLAST+ we should refactor the BLAST assigner to be consensus-based as well. ","created_at":"2014-08-22T21:48:07Z","updated_at":"2014-08-22T21:48:07Z","html_url":"https://github.com/biocore/qiime/pull/1662#discussion_r16623293","pull_request_url":"https://api.github.com/repos/biocore/qiime/pulls/1662","_links":{"self":{"href":"https://api.github.com/repos/biocore/qiime/pulls/comments/16623293"},"html":{"href":"https://github.com/biocore/qiime/pull/1662#discussion_r16623293"},"pull_request":{"href":"https://api.github.com/repos/biocore/qiime/pulls/1662"}}},"pull_request":{"url":"https://api.github.com/repos/biocore/qiime/pulls/1662","id":19992263,"html_url":"https://github.com/biocore/qiime/pull/1662","diff_url":"https://github.com/biocore/qiime/pull/1662.diff","patch_url":"https://github.com/biocore/qiime/pull/1662.patch","issue_url":"https://api.github.com/repos/biocore/qiime/issues/1662","number":1662,"state":"open","locked":false,"title":"Add sortmerna to assign_taxonomy.py","user":{"login":"ekopylova","id":6933444,"avatar_url":"https://avatars.githubusercontent.com/u/6933444?v=2","gravatar_id":"8d70e61e94b45642a786ed83fccccc33","url":"https://api.github.com/users/ekopylova","html_url":"https://github.com/ekopylova","followers_url":"https://api.github.com/users/ekopylova/followers","following_url":"https://api.github.com/users/ekopylova/following{/other_user}","gists_url":"https://api.github.com/users/ekopylova/gists{/gist_id}","starred_url":"https://api.github.com/users/ekopylova/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ekopylova/subscriptions","organizations_url":"https://api.github.com/users/ekopylova/orgs","repos_url":"https://api.github.com/users/ekopylova/repos","events_url":"https://api.github.com/users/ekopylova/events{/privacy}","received_events_url":"https://api.github.com/users/ekopylova/received_events","type":"User","site_admin":false},"body":"Partially resolves https://github.com/gregcaporaso/short-read-tax-assignment/issues/68.\r\n\r\nMost of the functions follow those in https://github.com/ekopylova/short-read-tax-assignment, with modifications relating to Null alignment strings now output by sortmerna.\r\n","created_at":"2014-08-19T16:33:19Z","updated_at":"2014-08-22T21:48:07Z","closed_at":null,"merged_at":null,"merge_commit_sha":"dfea229776c8bd23c1bdd4e513b72e0f123a6ce4","assignee":{"login":"gregcaporaso","id":192372,"avatar_url":"https://avatars.githubusercontent.com/u/192372?v=2","gravatar_id":"24f019bae9a9c4282123961b01c7f0d5","url":"https://api.github.com/users/gregcaporaso","html_url":"https://github.com/gregcaporaso","followers_url":"https://api.github.com/users/gregcaporaso/followers","following_url":"https://api.github.com/users/gregcaporaso/following{/other_user}","gists_url":"https://api.github.com/users/gregcaporaso/gists{/gist_id}","starred_url":"https://api.github.com/users/gregcaporaso/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gregcaporaso/subscriptions","organizations_url":"https://api.github.com/users/gregcaporaso/orgs","repos_url":"https://api.github.com/users/gregcaporaso/repos","events_url":"https://api.github.com/users/gregcaporaso/events{/privacy}","received_events_url":"https://api.github.com/users/gregcaporaso/received_events","type":"User","site_admin":false},"milestone":null,"commits_url":"https://api.github.com/repos/biocore/qiime/pulls/1662/commits","review_comments_url":"https://api.github.com/repos/biocore/qiime/pulls/1662/comments","review_comment_url":"https://api.github.com/repos/biocore/qiime/pulls/comments/{number}","comments_url":"https://api.github.com/repos/biocore/qiime/issues/1662/comments","statuses_url":"https://api.github.com/repos/biocore/qiime/statuses/d87ab9636a51e6a1813b0f6c18223f6aae8c4089","head":{"label":"ekopylova:sortmerna-assign-taxonomy","ref":"sortmerna-assign-taxonomy","sha":"d87ab9636a51e6a1813b0f6c18223f6aae8c4089","user":{"login":"ekopylova","id":6933444,"avatar_url":"https://avatars.githubusercontent.com/u/6933444?v=2","gravatar_id":"8d70e61e94b45642a786ed83fccccc33","url":"https://api.github.com/users/ekopylova","html_url":"https://github.com/ekopylova","followers_url":"https://api.github.com/users/ekopylova/followers","following_url":"https://api.github.com/users/ekopylova/following{/other_user}","gists_url":"https://api.github.com/users/ekopylova/gists{/gist_id}","starred_url":"https://api.github.com/users/ekopylova/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ekopylova/subscriptions","organizations_url":"https://api.github.com/users/ekopylova/orgs","repos_url":"https://api.github.com/users/ekopylova/repos","events_url":"https://api.github.com/users/ekopylova/events{/privacy}","received_events_url":"https://api.github.com/users/ekopylova/received_events","type":"User","site_admin":false},"repo":{"id":18440977,"name":"qiime","full_name":"ekopylova/qiime","owner":{"login":"ekopylova","id":6933444,"avatar_url":"https://avatars.githubusercontent.com/u/6933444?v=2","gravatar_id":"8d70e61e94b45642a786ed83fccccc33","url":"https://api.github.com/users/ekopylova","html_url":"https://github.com/ekopylova","followers_url":"https://api.github.com/users/ekopylova/followers","following_url":"https://api.github.com/users/ekopylova/following{/other_user}","gists_url":"https://api.github.com/users/ekopylova/gists{/gist_id}","starred_url":"https://api.github.com/users/ekopylova/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ekopylova/subscriptions","organizations_url":"https://api.github.com/users/ekopylova/orgs","repos_url":"https://api.github.com/users/ekopylova/repos","events_url":"https://api.github.com/users/ekopylova/events{/privacy}","received_events_url":"https://api.github.com/users/ekopylova/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/ekopylova/qiime","description":"Quantitative Insights Into Microbial Ecology (QIIME): Official repository for software and unit tests","fork":true,"url":"https://api.github.com/repos/ekopylova/qiime","forks_url":"https://api.github.com/repos/ekopylova/qiime/forks","keys_url":"https://api.github.com/repos/ekopylova/qiime/keys{/key_id}","collaborators_url":"https://api.github.com/repos/ekopylova/qiime/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/ekopylova/qiime/teams","hooks_url":"https://api.github.com/repos/ekopylova/qiime/hooks","issue_events_url":"https://api.github.com/repos/ekopylova/qiime/issues/events{/number}","events_url":"https://api.github.com/repos/ekopylova/qiime/events","assignees_url":"https://api.github.com/repos/ekopylova/qiime/assignees{/user}","branches_url":"https://api.github.com/repos/ekopylova/qiime/branches{/branch}","tags_url":"https://api.github.com/repos/ekopylova/qiime/tags","blobs_url":"https://api.github.com/repos/ekopylova/qiime/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/ekopylova/qiime/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/ekopylova/qiime/git/refs{/sha}","trees_url":"https://api.github.com/repos/ekopylova/qiime/git/trees{/sha}","statuses_url":"https://api.github.com/repos/ekopylova/qiime/statuses/{sha}","languages_url":"https://api.github.com/repos/ekopylova/qiime/languages","stargazers_url":"https://api.github.com/repos/ekopylova/qiime/stargazers","contributors_url":"https://api.github.com/repos/ekopylova/qiime/contributors","subscribers_url":"https://api.github.com/repos/ekopylova/qiime/subscribers","subscription_url":"https://api.github.com/repos/ekopylova/qiime/subscription","commits_url":"https://api.github.com/repos/ekopylova/qiime/commits{/sha}","git_commits_url":"https://api.github.com/repos/ekopylova/qiime/git/commits{/sha}","comments_url":"https://api.github.com/repos/ekopylova/qiime/comments{/number}","issue_comment_url":"https://api.github.com/repos/ekopylova/qiime/issues/comments/{number}","contents_url":"https://api.github.com/repos/ekopylova/qiime/contents/{+path}","compare_url":"https://api.github.com/repos/ekopylova/qiime/compare/{base}...{head}","merges_url":"https://api.github.com/repos/ekopylova/qiime/merges","archive_url":"https://api.github.com/repos/ekopylova/qiime/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/ekopylova/qiime/downloads","issues_url":"https://api.github.com/repos/ekopylova/qiime/issues{/number}","pulls_url":"https://api.github.com/repos/ekopylova/qiime/pulls{/number}","milestones_url":"https://api.github.com/repos/ekopylova/qiime/milestones{/number}","notifications_url":"https://api.github.com/repos/ekopylova/qiime/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/ekopylova/qiime/labels{/name}","releases_url":"https://api.github.com/repos/ekopylova/qiime/releases{/id}","created_at":"2014-04-04T14:08:58Z","updated_at":"2014-08-07T02:29:36Z","pushed_at":"2014-08-22T18:18:55Z","git_url":"git://github.com/ekopylova/qiime.git","ssh_url":"git@github.com:ekopylova/qiime.git","clone_url":"https://github.com/ekopylova/qiime.git","svn_url":"https://github.com/ekopylova/qiime","homepage":"www.qiime.org","size":102662,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_downloads":true,"has_wiki":true,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"biocore:master","ref":"master","sha":"3447761ad14fd5f35cbaf6b052c4f356953b252e","user":{"login":"biocore","id":6241857,"avatar_url":"https://avatars.githubusercontent.com/u/6241857?v=2","gravatar_id":null,"url":"https://api.github.com/users/biocore","html_url":"https://github.com/biocore","followers_url":"https://api.github.com/users/biocore/followers","following_url":"https://api.github.com/users/biocore/following{/other_user}","gists_url":"https://api.github.com/users/biocore/gists{/gist_id}","starred_url":"https://api.github.com/users/biocore/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/biocore/subscriptions","organizations_url":"https://api.github.com/users/biocore/orgs","repos_url":"https://api.github.com/users/biocore/repos","events_url":"https://api.github.com/users/biocore/events{/privacy}","received_events_url":"https://api.github.com/users/biocore/received_events","type":"Organization","site_admin":false},"repo":{"id":6209952,"name":"qiime","full_name":"biocore/qiime","owner":{"login":"biocore","id":6241857,"avatar_url":"https://avatars.githubusercontent.com/u/6241857?v=2","gravatar_id":null,"url":"https://api.github.com/users/biocore","html_url":"https://github.com/biocore","followers_url":"https://api.github.com/users/biocore/followers","following_url":"https://api.github.com/users/biocore/following{/other_user}","gists_url":"https://api.github.com/users/biocore/gists{/gist_id}","starred_url":"https://api.github.com/users/biocore/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/biocore/subscriptions","organizations_url":"https://api.github.com/users/biocore/orgs","repos_url":"https://api.github.com/users/biocore/repos","events_url":"https://api.github.com/users/biocore/events{/privacy}","received_events_url":"https://api.github.com/users/biocore/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/biocore/qiime","description":"Quantitative Insights Into Microbial Ecology (QIIME): Official repository for software and unit tests","fork":false,"url":"https://api.github.com/repos/biocore/qiime","forks_url":"https://api.github.com/repos/biocore/qiime/forks","keys_url":"https://api.github.com/repos/biocore/qiime/keys{/key_id}","collaborators_url":"https://api.github.com/repos/biocore/qiime/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/biocore/qiime/teams","hooks_url":"https://api.github.com/repos/biocore/qiime/hooks","issue_events_url":"https://api.github.com/repos/biocore/qiime/issues/events{/number}","events_url":"https://api.github.com/repos/biocore/qiime/events","assignees_url":"https://api.github.com/repos/biocore/qiime/assignees{/user}","branches_url":"https://api.github.com/repos/biocore/qiime/branches{/branch}","tags_url":"https://api.github.com/repos/biocore/qiime/tags","blobs_url":"https://api.github.com/repos/biocore/qiime/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/biocore/qiime/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/biocore/qiime/git/refs{/sha}","trees_url":"https://api.github.com/repos/biocore/qiime/git/trees{/sha}","statuses_url":"https://api.github.com/repos/biocore/qiime/statuses/{sha}","languages_url":"https://api.github.com/repos/biocore/qiime/languages","stargazers_url":"https://api.github.com/repos/biocore/qiime/stargazers","contributors_url":"https://api.github.com/repos/biocore/qiime/contributors","subscribers_url":"https://api.github.com/repos/biocore/qiime/subscribers","subscription_url":"https://api.github.com/repos/biocore/qiime/subscription","commits_url":"https://api.github.com/repos/biocore/qiime/commits{/sha}","git_commits_url":"https://api.github.com/repos/biocore/qiime/git/commits{/sha}","comments_url":"https://api.github.com/repos/biocore/qiime/comments{/number}","issue_comment_url":"https://api.github.com/repos/biocore/qiime/issues/comments/{number}","contents_url":"https://api.github.com/repos/biocore/qiime/contents/{+path}","compare_url":"https://api.github.com/repos/biocore/qiime/compare/{base}...{head}","merges_url":"https://api.github.com/repos/biocore/qiime/merges","archive_url":"https://api.github.com/repos/biocore/qiime/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/biocore/qiime/downloads","issues_url":"https://api.github.com/repos/biocore/qiime/issues{/number}","pulls_url":"https://api.github.com/repos/biocore/qiime/pulls{/number}","milestones_url":"https://api.github.com/repos/biocore/qiime/milestones{/number}","notifications_url":"https://api.github.com/repos/biocore/qiime/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/biocore/qiime/labels{/name}","releases_url":"https://api.github.com/repos/biocore/qiime/releases{/id}","created_at":"2012-10-14T02:51:46Z","updated_at":"2014-08-18T19:33:08Z","pushed_at":"2014-08-15T20:20:10Z","git_url":"git://github.com/biocore/qiime.git","ssh_url":"git@github.com:biocore/qiime.git","clone_url":"https://github.com/biocore/qiime.git","svn_url":"https://github.com/biocore/qiime","homepage":"www.qiime.org","size":123499,"stargazers_count":81,"watchers_count":81,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"forks_count":99,"mirror_url":null,"open_issues_count":387,"forks":99,"open_issues":387,"watchers":81,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/biocore/qiime/pulls/1662"},"html":{"href":"https://github.com/biocore/qiime/pull/1662"},"issue":{"href":"https://api.github.com/repos/biocore/qiime/issues/1662"},"comments":{"href":"https://api.github.com/repos/biocore/qiime/issues/1662/comments"},"review_comments":{"href":"https://api.github.com/repos/biocore/qiime/pulls/1662/comments"},"review_comment":{"href":"https://api.github.com/repos/biocore/qiime/pulls/comments/{number}"},"commits":{"href":"https://api.github.com/repos/biocore/qiime/pulls/1662/commits"},"statuses":{"href":"https://api.github.com/repos/biocore/qiime/statuses/d87ab9636a51e6a1813b0f6c18223f6aae8c4089"}}}}