)]}'
{"patrole_tempest_plugin/rbac_rule_validation.py":[{"author":{"_account_id":8556,"name":"Ghanshyam Maan","display_name":"Ghanshyam Maan","email":"gmaan.os14@gmail.com","username":"ghanshyam"},"change_message_id":"e9f4111c4f38d80b66fa8341c4c15c5860370b1f","unresolved":false,"context_lines":[{"line_number":344,"context_line":"        if not roles:"},{"line_number":345,"context_line":"            roles.append(CONF.patrole.rbac_test_role)"},{"line_number":346,"context_line":""},{"line_number":347,"context_line":"    # Adding implied roles"},{"line_number":348,"context_line":"    roles \u003d test_obj.rbac_utils.get_all_needed_roles(roles)"},{"line_number":349,"context_line":""},{"line_number":350,"context_line":"    # Test RBAC against custom requirements. Otherwise use oslo.policy."}],"source_content_type":"text/x-python","patch_set":10,"id":"9fdfeff1_9c7fcd64","line":347,"range":{"start_line":347,"start_character":0,"end_line":347,"end_character":26},"updated":"2019-02-01 07:24:41.000000000","message":"adding more explanation here is good for future or new maintainer (when we will be gone from community :)) to understand that why we did this. SOmething like, patrole does oslo.policy rule checks directly and then via API call. and for first one, we need to prepare the implied roles because that is what keystone does.\n\nBut that is ok to add in followup patch","commit_id":"19e3becfc73cf02df18de42742ac1d90e8d29ac6"},{"author":{"_account_id":8911,"name":"Sergey Vilgelm","email":"sergey@vilgelm.info","username":"sergey.vilgelm"},"change_message_id":"f52d6d19ecb01839afcf29fbd2c03f3978050987","unresolved":false,"context_lines":[{"line_number":344,"context_line":"        if not roles:"},{"line_number":345,"context_line":"            roles.append(CONF.patrole.rbac_test_role)"},{"line_number":346,"context_line":""},{"line_number":347,"context_line":"    # Adding implied roles"},{"line_number":348,"context_line":"    roles \u003d test_obj.rbac_utils.get_all_needed_roles(roles)"},{"line_number":349,"context_line":""},{"line_number":350,"context_line":"    # Test RBAC against custom requirements. Otherwise use oslo.policy."}],"source_content_type":"text/x-python","patch_set":10,"id":"9fdfeff1_683ca32e","line":347,"range":{"start_line":347,"start_character":0,"end_line":347,"end_character":26},"in_reply_to":"9fdfeff1_9c7fcd64","updated":"2019-02-01 13:07:05.000000000","message":"Ok. Thanks.","commit_id":"19e3becfc73cf02df18de42742ac1d90e8d29ac6"}],"patrole_tempest_plugin/rbac_utils.py":[{"author":{"_account_id":23186,"name":"Felipe Monteiro","email":"felipe.carneiro.monteiro@gmail.com","username":"felipe.monteiro"},"change_message_id":"9399160402a54db3ac89da085722de73f9a1c3a8","unresolved":false,"context_lines":[{"line_number":180,"context_line":"        def convert_data(data):"},{"line_number":181,"context_line":"            res \u003d {}"},{"line_number":182,"context_line":"            for rule in data:"},{"line_number":183,"context_line":"                prior_role \u003d rule[\u0027prior_role\u0027][\u0027name\u0027].lower()"},{"line_number":184,"context_line":"                implies \u003d {r[\u0027name\u0027].lower() for r in rule[\u0027implies\u0027]}"},{"line_number":185,"context_line":"                res[prior_role] \u003d implies"},{"line_number":186,"context_line":"            return res"}],"source_content_type":"text/x-python","patch_set":4,"id":"9fdfeff1_283efa8b","line":183,"range":{"start_line":183,"start_character":55,"end_line":183,"end_character":63},"updated":"2019-01-28 01:11:25.000000000","message":"Curious why lower is needed? What if a role is uppercase? This is legal.","commit_id":"988f4cb905974baf2cf174c5668a20f086670e8d"},{"author":{"_account_id":8911,"name":"Sergey Vilgelm","email":"sergey@vilgelm.info","username":"sergey.vilgelm"},"change_message_id":"0ebae493dc5cdbb768ca1d668c1b014652edd372","unresolved":false,"context_lines":[{"line_number":180,"context_line":"        def convert_data(data):"},{"line_number":181,"context_line":"            res \u003d {}"},{"line_number":182,"context_line":"            for rule in data:"},{"line_number":183,"context_line":"                prior_role \u003d rule[\u0027prior_role\u0027][\u0027name\u0027].lower()"},{"line_number":184,"context_line":"                implies \u003d {r[\u0027name\u0027].lower() for r in rule[\u0027implies\u0027]}"},{"line_number":185,"context_line":"                res[prior_role] \u003d implies"},{"line_number":186,"context_line":"            return res"}],"source_content_type":"text/x-python","patch_set":4,"id":"9fdfeff1_8805a648","line":183,"range":{"start_line":183,"start_character":55,"end_line":183,"end_character":63},"in_reply_to":"9fdfeff1_283efa8b","updated":"2019-01-28 02:32:50.000000000","message":"Yes, it is legal, but the RoleCheck matches in lower cases: https://github.com/openstack/oslo.policy/blob/b9fd10e2612f26c93d49c168a0408aba6d20e5bf/oslo_policy/_checks.py#L286\n\nSo to prepare a mapping I decided to unify them using lower cases. But I think that I need to rewrite it to use IDs instead of names.","commit_id":"988f4cb905974baf2cf174c5668a20f086670e8d"},{"author":{"_account_id":23186,"name":"Felipe Monteiro","email":"felipe.carneiro.monteiro@gmail.com","username":"felipe.monteiro"},"change_message_id":"9399160402a54db3ac89da085722de73f9a1c3a8","unresolved":false,"context_lines":[{"line_number":181,"context_line":"            res \u003d {}"},{"line_number":182,"context_line":"            for rule in data:"},{"line_number":183,"context_line":"                prior_role \u003d rule[\u0027prior_role\u0027][\u0027name\u0027].lower()"},{"line_number":184,"context_line":"                implies \u003d {r[\u0027name\u0027].lower() for r in rule[\u0027implies\u0027]}"},{"line_number":185,"context_line":"                res[prior_role] \u003d implies"},{"line_number":186,"context_line":"            return res"},{"line_number":187,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"9fdfeff1_c83e4e8a","line":184,"range":{"start_line":184,"start_character":36,"end_line":184,"end_character":45},"updated":"2019-01-28 01:11:25.000000000","message":"Ditto.","commit_id":"988f4cb905974baf2cf174c5668a20f086670e8d"},{"author":{"_account_id":23186,"name":"Felipe Monteiro","email":"felipe.carneiro.monteiro@gmail.com","username":"felipe.monteiro"},"change_message_id":"047906a0fd5836860396738f277220619526735a","unresolved":false,"context_lines":[{"line_number":141,"context_line":"        # Change default role to admin"},{"line_number":142,"context_line":"        self._override_role(test_obj, False)"},{"line_number":143,"context_line":""},{"line_number":144,"context_line":"    def _prepare_role_inferences_mapping(self):"},{"line_number":145,"context_line":"        \"\"\"Preparing roles mapping to support role inferences"},{"line_number":146,"context_line":""},{"line_number":147,"context_line":"        Making query to `list-all-role-inference-rules`_ keystone API"}],"source_content_type":"text/x-python","patch_set":7,"id":"9fdfeff1_647df97d","line":144,"range":{"start_line":144,"start_character":8,"end_line":144,"end_character":40},"updated":"2019-01-29 02:27:06.000000000","message":"Should add a basic unit test to validate that the expected mapping is returned for both \u0027admin\u0027 and \u0027member\u0027 as well as \u0027reader\u0027 for good measure.","commit_id":"2e621ead2a77949a33f30aa092392f6cc783c538"},{"author":{"_account_id":8911,"name":"Sergey Vilgelm","email":"sergey@vilgelm.info","username":"sergey.vilgelm"},"change_message_id":"4e8d2d76ca480e50f2cd8704a3d4bc118836ef78","unresolved":false,"context_lines":[{"line_number":141,"context_line":"        # Change default role to admin"},{"line_number":142,"context_line":"        self._override_role(test_obj, False)"},{"line_number":143,"context_line":""},{"line_number":144,"context_line":"    def _prepare_role_inferences_mapping(self):"},{"line_number":145,"context_line":"        \"\"\"Preparing roles mapping to support role inferences"},{"line_number":146,"context_line":""},{"line_number":147,"context_line":"        Making query to `list-all-role-inference-rules`_ keystone API"}],"source_content_type":"text/x-python","patch_set":7,"id":"9fdfeff1_96a27cfb","line":144,"range":{"start_line":144,"start_character":8,"end_line":144,"end_character":40},"in_reply_to":"9fdfeff1_647df97d","updated":"2019-01-31 02:50:29.000000000","message":"sure","commit_id":"2e621ead2a77949a33f30aa092392f6cc783c538"},{"author":{"_account_id":23186,"name":"Felipe Monteiro","email":"felipe.carneiro.monteiro@gmail.com","username":"felipe.monteiro"},"change_message_id":"047906a0fd5836860396738f277220619526735a","unresolved":false,"context_lines":[{"line_number":145,"context_line":"        \"\"\"Preparing roles mapping to support role inferences"},{"line_number":146,"context_line":""},{"line_number":147,"context_line":"        Making query to `list-all-role-inference-rules`_ keystone API"},{"line_number":148,"context_line":"        returns all interference rules, which makes it possible to prepare"},{"line_number":149,"context_line":"        roles mapping."},{"line_number":150,"context_line":""},{"line_number":151,"context_line":"        It walks recursively through the raw data::"}],"source_content_type":"text/x-python","patch_set":7,"id":"9fdfeff1_c414e546","line":148,"range":{"start_line":148,"start_character":20,"end_line":148,"end_character":32},"updated":"2019-01-29 02:27:06.000000000","message":"nit: inference","commit_id":"2e621ead2a77949a33f30aa092392f6cc783c538"},{"author":{"_account_id":8911,"name":"Sergey Vilgelm","email":"sergey@vilgelm.info","username":"sergey.vilgelm"},"change_message_id":"4e8d2d76ca480e50f2cd8704a3d4bc118836ef78","unresolved":false,"context_lines":[{"line_number":145,"context_line":"        \"\"\"Preparing roles mapping to support role inferences"},{"line_number":146,"context_line":""},{"line_number":147,"context_line":"        Making query to `list-all-role-inference-rules`_ keystone API"},{"line_number":148,"context_line":"        returns all interference rules, which makes it possible to prepare"},{"line_number":149,"context_line":"        roles mapping."},{"line_number":150,"context_line":""},{"line_number":151,"context_line":"        It walks recursively through the raw data::"}],"source_content_type":"text/x-python","patch_set":7,"id":"9fdfeff1_56b09443","line":148,"range":{"start_line":148,"start_character":20,"end_line":148,"end_character":32},"in_reply_to":"9fdfeff1_c414e546","updated":"2019-01-31 02:50:29.000000000","message":"Done","commit_id":"2e621ead2a77949a33f30aa092392f6cc783c538"},{"author":{"_account_id":23186,"name":"Felipe Monteiro","email":"felipe.carneiro.monteiro@gmail.com","username":"felipe.monteiro"},"change_message_id":"047906a0fd5836860396738f277220619526735a","unresolved":false,"context_lines":[{"line_number":170,"context_line":"            }"},{"line_number":171,"context_line":""},{"line_number":172,"context_line":"        .. _list-all-role-inference-rules: https://developer.openstack.org/api-ref/identity/v3/#list-all-role-inference-rules"},{"line_number":173,"context_line":"        \"\"\"  # noqa: E501"},{"line_number":174,"context_line":"        def process_roles(role_id, data):"},{"line_number":175,"context_line":"            roles \u003d data.get(role_id, set())"},{"line_number":176,"context_line":"            for rid in roles.copy():"}],"source_content_type":"text/x-python","patch_set":7,"id":"9fdfeff1_0420ad9a","line":173,"range":{"start_line":173,"start_character":13,"end_line":173,"end_character":25},"updated":"2019-01-29 02:27:06.000000000","message":"nit: better to use newline before this, so that it\u0027s at start of new line","commit_id":"2e621ead2a77949a33f30aa092392f6cc783c538"},{"author":{"_account_id":8911,"name":"Sergey Vilgelm","email":"sergey@vilgelm.info","username":"sergey.vilgelm"},"change_message_id":"4e8d2d76ca480e50f2cd8704a3d4bc118836ef78","unresolved":false,"context_lines":[{"line_number":170,"context_line":"            }"},{"line_number":171,"context_line":""},{"line_number":172,"context_line":"        .. _list-all-role-inference-rules: https://developer.openstack.org/api-ref/identity/v3/#list-all-role-inference-rules"},{"line_number":173,"context_line":"        \"\"\"  # noqa: E501"},{"line_number":174,"context_line":"        def process_roles(role_id, data):"},{"line_number":175,"context_line":"            roles \u003d data.get(role_id, set())"},{"line_number":176,"context_line":"            for rid in roles.copy():"}],"source_content_type":"text/x-python","patch_set":7,"id":"9fdfeff1_b67220ac","line":173,"range":{"start_line":173,"start_character":13,"end_line":173,"end_character":25},"in_reply_to":"9fdfeff1_0420ad9a","updated":"2019-01-31 02:50:29.000000000","message":"This is noqa for the long link in the documentation. It doesn\u0027t work on new line","commit_id":"2e621ead2a77949a33f30aa092392f6cc783c538"},{"author":{"_account_id":23186,"name":"Felipe Monteiro","email":"felipe.carneiro.monteiro@gmail.com","username":"felipe.monteiro"},"change_message_id":"047906a0fd5836860396738f277220619526735a","unresolved":false,"context_lines":[{"line_number":342,"context_line":""},{"line_number":343,"context_line":"        self.admin_role_id \u003d admin_role_id"},{"line_number":344,"context_line":"        self.rbac_role_ids \u003d rbac_role_ids"},{"line_number":345,"context_line":"        # Adding backward mapping"},{"line_number":346,"context_line":"        self._role_map.update({v: k for k, v in self._role_map.items()})"},{"line_number":347,"context_line":""},{"line_number":348,"context_line":"    def _create_user_role_on_project(self, role_ids):"},{"line_number":349,"context_line":"        for role_id in role_ids:"}],"source_content_type":"text/x-python","patch_set":7,"id":"9fdfeff1_4478f58e","line":346,"range":{"start_line":345,"start_character":8,"end_line":346,"end_character":72},"updated":"2019-01-29 02:27:06.000000000","message":"nit: Can\u0027t this be moved up to ~L311 for better code organization?","commit_id":"2e621ead2a77949a33f30aa092392f6cc783c538"},{"author":{"_account_id":8911,"name":"Sergey Vilgelm","email":"sergey@vilgelm.info","username":"sergey.vilgelm"},"change_message_id":"4e8d2d76ca480e50f2cd8704a3d4bc118836ef78","unresolved":false,"context_lines":[{"line_number":342,"context_line":""},{"line_number":343,"context_line":"        self.admin_role_id \u003d admin_role_id"},{"line_number":344,"context_line":"        self.rbac_role_ids \u003d rbac_role_ids"},{"line_number":345,"context_line":"        # Adding backward mapping"},{"line_number":346,"context_line":"        self._role_map.update({v: k for k, v in self._role_map.items()})"},{"line_number":347,"context_line":""},{"line_number":348,"context_line":"    def _create_user_role_on_project(self, role_ids):"},{"line_number":349,"context_line":"        for role_id in role_ids:"}],"source_content_type":"text/x-python","patch_set":7,"id":"9fdfeff1_b659c035","line":346,"range":{"start_line":345,"start_character":8,"end_line":346,"end_character":72},"in_reply_to":"9fdfeff1_4478f58e","updated":"2019-01-31 02:50:29.000000000","message":"No, otherwise the missing_roles will also contain IDs in the `Available roles:` section","commit_id":"2e621ead2a77949a33f30aa092392f6cc783c538"}],"patrole_tempest_plugin/tests/unit/fixtures.py":[{"author":{"_account_id":23186,"name":"Felipe Monteiro","email":"felipe.carneiro.monteiro@gmail.com","username":"felipe.monteiro"},"change_message_id":"9399160402a54db3ac89da085722de73f9a1c3a8","unresolved":false,"context_lines":[{"line_number":170,"context_line":"        self.admin_roles_client.list_user_roles_on_project.return_value \u003d ("},{"line_number":171,"context_line":"            available_project_roles)"},{"line_number":172,"context_line":""},{"line_number":173,"context_line":"    def get_all_needed_roles(self, roles):"},{"line_number":174,"context_line":"        role_inferences_mapping \u003d {"},{"line_number":175,"context_line":"            \"admin\": {\"member\", \"reader\"},"},{"line_number":176,"context_line":"            \"member\": {\"reader\"}"},{"line_number":177,"context_line":"        }"},{"line_number":178,"context_line":"        res \u003d set(r.lower() for r in roles)"},{"line_number":179,"context_line":"        for role in res.copy():"},{"line_number":180,"context_line":"            res.update(role_inferences_mapping.get(role, set()))"},{"line_number":181,"context_line":"        return list(res)"}],"source_content_type":"text/x-python","patch_set":4,"id":"9fdfeff1_0839b6a2","line":181,"range":{"start_line":173,"start_character":0,"end_line":181,"end_character":24},"updated":"2019-01-28 01:11:25.000000000","message":"This appears to be identical to the one in: https://review.openstack.org/#/c/633255/4/patrole_tempest_plugin/tests/unit/base.py","commit_id":"988f4cb905974baf2cf174c5668a20f086670e8d"},{"author":{"_account_id":8911,"name":"Sergey Vilgelm","email":"sergey@vilgelm.info","username":"sergey.vilgelm"},"change_message_id":"0ebae493dc5cdbb768ca1d668c1b014652edd372","unresolved":false,"context_lines":[{"line_number":170,"context_line":"        self.admin_roles_client.list_user_roles_on_project.return_value \u003d ("},{"line_number":171,"context_line":"            available_project_roles)"},{"line_number":172,"context_line":""},{"line_number":173,"context_line":"    def get_all_needed_roles(self, roles):"},{"line_number":174,"context_line":"        role_inferences_mapping \u003d {"},{"line_number":175,"context_line":"            \"admin\": {\"member\", \"reader\"},"},{"line_number":176,"context_line":"            \"member\": {\"reader\"}"},{"line_number":177,"context_line":"        }"},{"line_number":178,"context_line":"        res \u003d set(r.lower() for r in roles)"},{"line_number":179,"context_line":"        for role in res.copy():"},{"line_number":180,"context_line":"            res.update(role_inferences_mapping.get(role, set()))"},{"line_number":181,"context_line":"        return list(res)"}],"source_content_type":"text/x-python","patch_set":4,"id":"9fdfeff1_289cba0d","line":181,"range":{"start_line":173,"start_character":0,"end_line":181,"end_character":24},"in_reply_to":"9fdfeff1_0839b6a2","updated":"2019-01-28 02:32:50.000000000","message":"Yes, it\u0027s identical, but I still didn\u0027t figure out how to re-use it from base TestClass","commit_id":"988f4cb905974baf2cf174c5668a20f086670e8d"},{"author":{"_account_id":23186,"name":"Felipe Monteiro","email":"felipe.carneiro.monteiro@gmail.com","username":"felipe.monteiro"},"change_message_id":"5f9732d8b4c2325fdac82582922498edd5a0052b","unresolved":false,"context_lines":[{"line_number":180,"context_line":"            obj._role_map \u003d {"},{"line_number":181,"context_line":"                \"1\": \"admin\", \"admin\": \"1\","},{"line_number":182,"context_line":"                \"2\": \"member\", \"member\": \"2\","},{"line_number":183,"context_line":"                \"3\": \"reader\", \"reader\": 3"},{"line_number":184,"context_line":"            }"},{"line_number":185,"context_line":"            return obj.get_all_needed_roles(roles)"}],"source_content_type":"text/x-python","patch_set":6,"id":"9fdfeff1_4b9c9869","line":183,"range":{"start_line":183,"start_character":41,"end_line":183,"end_character":42},"updated":"2019-01-28 04:24:35.000000000","message":"Should this not be a string?","commit_id":"a2092393efe75e7738e95003c86b7e1ef7128aeb"}],"patrole_tempest_plugin/tests/unit/test_rbac_utils.py":[{"author":{"_account_id":23186,"name":"Felipe Monteiro","email":"felipe.carneiro.monteiro@gmail.com","username":"felipe.monteiro"},"change_message_id":"d1462df0b5ff073e443249cecd0e8a7d16196dc2","unresolved":false,"context_lines":[{"line_number":230,"context_line":"                    }"},{"line_number":231,"context_line":"                ]"},{"line_number":232,"context_line":"            }"},{"line_number":233,"context_line":"        _rbac_utils.admin_roles_client.list_all_role_inference_rules.\\"},{"line_number":234,"context_line":"            reset_mock()"},{"line_number":235,"context_line":"        _rbac_utils.__role_inferences_mapping \u003d {}"},{"line_number":236,"context_line":""},{"line_number":237,"context_line":"        expected_role_inferences_mapping \u003d {"}],"source_content_type":"text/x-python","patch_set":9,"id":"9fdfeff1_166f55fc","line":234,"range":{"start_line":233,"start_character":7,"end_line":234,"end_character":24},"updated":"2019-01-31 07:19:30.000000000","message":"This shouldn\u0027t be needed.","commit_id":"933039d4c7aea9c97139e2fea5a0dede67008ff6"},{"author":{"_account_id":8911,"name":"Sergey Vilgelm","email":"sergey@vilgelm.info","username":"sergey.vilgelm"},"change_message_id":"245abd7de63b3e2469e971064ca0d1841615b57c","unresolved":false,"context_lines":[{"line_number":230,"context_line":"                    }"},{"line_number":231,"context_line":"                ]"},{"line_number":232,"context_line":"            }"},{"line_number":233,"context_line":"        _rbac_utils.admin_roles_client.list_all_role_inference_rules.\\"},{"line_number":234,"context_line":"            reset_mock()"},{"line_number":235,"context_line":"        _rbac_utils.__role_inferences_mapping \u003d {}"},{"line_number":236,"context_line":""},{"line_number":237,"context_line":"        expected_role_inferences_mapping \u003d {"}],"source_content_type":"text/x-python","patch_set":9,"id":"9fdfeff1_b20c4c94","line":234,"range":{"start_line":233,"start_character":7,"end_line":234,"end_character":24},"in_reply_to":"9fdfeff1_166f55fc","updated":"2019-01-31 14:21:43.000000000","message":"Removed","commit_id":"933039d4c7aea9c97139e2fea5a0dede67008ff6"},{"author":{"_account_id":23186,"name":"Felipe Monteiro","email":"felipe.carneiro.monteiro@gmail.com","username":"felipe.monteiro"},"change_message_id":"d1462df0b5ff073e443249cecd0e8a7d16196dc2","unresolved":false,"context_lines":[{"line_number":232,"context_line":"            }"},{"line_number":233,"context_line":"        _rbac_utils.admin_roles_client.list_all_role_inference_rules.\\"},{"line_number":234,"context_line":"            reset_mock()"},{"line_number":235,"context_line":"        _rbac_utils.__role_inferences_mapping \u003d {}"},{"line_number":236,"context_line":""},{"line_number":237,"context_line":"        expected_role_inferences_mapping \u003d {"},{"line_number":238,"context_line":"            \"2\": {\"3\"},      # \"member\": [\"reader\"],"}],"source_content_type":"text/x-python","patch_set":9,"id":"9fdfeff1_967a65b7","line":235,"range":{"start_line":235,"start_character":7,"end_line":235,"end_character":50},"updated":"2019-01-31 07:19:30.000000000","message":"This should be `self._role_inferences_mapping`, with one underscore.","commit_id":"933039d4c7aea9c97139e2fea5a0dede67008ff6"},{"author":{"_account_id":8911,"name":"Sergey Vilgelm","email":"sergey@vilgelm.info","username":"sergey.vilgelm"},"change_message_id":"245abd7de63b3e2469e971064ca0d1841615b57c","unresolved":false,"context_lines":[{"line_number":232,"context_line":"            }"},{"line_number":233,"context_line":"        _rbac_utils.admin_roles_client.list_all_role_inference_rules.\\"},{"line_number":234,"context_line":"            reset_mock()"},{"line_number":235,"context_line":"        _rbac_utils.__role_inferences_mapping \u003d {}"},{"line_number":236,"context_line":""},{"line_number":237,"context_line":"        expected_role_inferences_mapping \u003d {"},{"line_number":238,"context_line":"            \"2\": {\"3\"},      # \"member\": [\"reader\"],"}],"source_content_type":"text/x-python","patch_set":9,"id":"9fdfeff1_d20f9085","line":235,"range":{"start_line":235,"start_character":7,"end_line":235,"end_character":50},"in_reply_to":"9fdfeff1_967a65b7","updated":"2019-01-31 14:21:43.000000000","message":"Removed","commit_id":"933039d4c7aea9c97139e2fea5a0dede67008ff6"}]}
