)]}'
{"/PATCHSET_LEVEL":[{"author":{"_account_id":13478,"name":"Boris Bobrov","email":"b.bobrov@sap.com","username":"bbobrov"},"change_message_id":"3c1ac2c43578f1a44b18394e499694f97504a07f","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":2,"id":"fb6fa5de_8679bc0a","updated":"2026-03-10 17:58:40.000000000","message":"There should also be unit-tests. I also think there should be a spec, because the current behavior is not a bug - it is a lack of feature.","commit_id":"8c37ff85780805d07e48d41201399dddf01aff94"},{"author":{"_account_id":7414,"name":"David Wilde","email":"dwilde@redhat.com","username":"d34dh0r53"},"change_message_id":"5749804d00a886dc721f70f595288111238dbd7e","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":2,"id":"fafbc206_ddb9956f","updated":"2026-03-13 15:25:34.000000000","message":"This is a start, but we need documentation, release notes, and clear examples of how the mapping will look on various LDAP backends.","commit_id":"8c37ff85780805d07e48d41201399dddf01aff94"},{"author":{"_account_id":8313,"name":"Lajos Katona","display_name":"lajoskatona","email":"katonalala@gmail.com","username":"elajkat","status":"Ericsson Software Technology"},"change_message_id":"e88caf357b013bd9365a18f5a4e4aedff575ccf3","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":2,"id":"94ac3da0_528a3a4c","in_reply_to":"fafbc206_ddb9956f","updated":"2026-03-16 10:08:25.000000000","message":"Thanks, I will update the patch with necessary documentation, tests etc...","commit_id":"8c37ff85780805d07e48d41201399dddf01aff94"}],"keystone/conf/ldap.py":[{"author":{"_account_id":8313,"name":"Lajos Katona","display_name":"lajoskatona","email":"katonalala@gmail.com","username":"elajkat","status":"Ericsson Software Technology"},"change_message_id":"3f8473481d91baf2f3ad008a1e94e833727c76b4","unresolved":true,"context_lines":[{"line_number":365,"context_line":"    ),"},{"line_number":366,"context_line":")"},{"line_number":367,"context_line":""},{"line_number":368,"context_line":"group_password_expiry_format_mapping \u003d cfg.ListOpt("},{"line_number":369,"context_line":"    \u0027group_password_expiry_format_mapping\u0027,"},{"line_number":370,"context_line":"    default\u003d[],"},{"line_number":371,"context_line":"    help\u003dutils.fmt("},{"line_number":372,"context_line":"        \"\"\""},{"line_number":373,"context_line":"A list of LDAP password expiry attribute name and converter method pairing."},{"line_number":374,"context_line":"\"\"\""},{"line_number":375,"context_line":"    ),"},{"line_number":376,"context_line":")"},{"line_number":377,"context_line":""},{"line_number":378,"context_line":"group_tree_dn \u003d cfg.StrOpt("},{"line_number":379,"context_line":"    \u0027group_tree_dn\u0027,"}],"source_content_type":"text/x-python","patch_set":1,"id":"d09f5869_47d0d945","line":376,"range":{"start_line":368,"start_character":0,"end_line":376,"end_character":1},"updated":"2026-02-13 09:02:12.000000000","message":"I have to double check this, the fact that user and group cfg options kind of mirrored this way confuse me regarding these LDAP options now, so I have to read more and think about it.","commit_id":"0aa6bfa705502aaa6e7dc314528b40d32320ad56"},{"author":{"_account_id":8313,"name":"Lajos Katona","display_name":"lajoskatona","email":"katonalala@gmail.com","username":"elajkat","status":"Ericsson Software Technology"},"change_message_id":"4a9d115575277127f622313c3460bd9b14051837","unresolved":false,"context_lines":[{"line_number":365,"context_line":"    ),"},{"line_number":366,"context_line":")"},{"line_number":367,"context_line":""},{"line_number":368,"context_line":"group_password_expiry_format_mapping \u003d cfg.ListOpt("},{"line_number":369,"context_line":"    \u0027group_password_expiry_format_mapping\u0027,"},{"line_number":370,"context_line":"    default\u003d[],"},{"line_number":371,"context_line":"    help\u003dutils.fmt("},{"line_number":372,"context_line":"        \"\"\""},{"line_number":373,"context_line":"A list of LDAP password expiry attribute name and converter method pairing."},{"line_number":374,"context_line":"\"\"\""},{"line_number":375,"context_line":"    ),"},{"line_number":376,"context_line":")"},{"line_number":377,"context_line":""},{"line_number":378,"context_line":"group_tree_dn \u003d cfg.StrOpt("},{"line_number":379,"context_line":"    \u0027group_tree_dn\u0027,"}],"source_content_type":"text/x-python","patch_set":1,"id":"74a54f1a_5d392b2d","line":376,"range":{"start_line":368,"start_character":0,"end_line":376,"end_character":1},"in_reply_to":"d09f5869_47d0d945","updated":"2026-05-08 14:23:44.000000000","message":"I moved to UserApi, so no need for the group_password_expiry_format_mapping cfg option","commit_id":"0aa6bfa705502aaa6e7dc314528b40d32320ad56"},{"author":{"_account_id":27900,"name":"Artem Goncharov","email":"artem.goncharov@gmail.com","username":"gtema"},"change_message_id":"8156922eb3f12c92a2367eca94d77783c23dae3a","unresolved":true,"context_lines":[{"line_number":370,"context_line":"    ),"},{"line_number":371,"context_line":")"},{"line_number":372,"context_line":""},{"line_number":373,"context_line":"group_password_expiry_format_mapping \u003d cfg.ListOpt("},{"line_number":374,"context_line":"    \u0027group_password_expiry_format_mapping\u0027,"},{"line_number":375,"context_line":"    default\u003d[],"},{"line_number":376,"context_line":"    help\u003dutils.fmt("}],"source_content_type":"text/x-python","patch_set":5,"id":"f7c82490_e698bdbc","line":373,"updated":"2026-05-07 07:21:01.000000000","message":"what is the group_password for? I do not understand the purpose of it and it doesn\u0027t look to be actually used in the code (only in tests)","commit_id":"508d7d6ceee3c31df3b0b79dfbd6192c15748091"},{"author":{"_account_id":8313,"name":"Lajos Katona","display_name":"lajoskatona","email":"katonalala@gmail.com","username":"elajkat","status":"Ericsson Software Technology"},"change_message_id":"4a9d115575277127f622313c3460bd9b14051837","unresolved":false,"context_lines":[{"line_number":370,"context_line":"    ),"},{"line_number":371,"context_line":")"},{"line_number":372,"context_line":""},{"line_number":373,"context_line":"group_password_expiry_format_mapping \u003d cfg.ListOpt("},{"line_number":374,"context_line":"    \u0027group_password_expiry_format_mapping\u0027,"},{"line_number":375,"context_line":"    default\u003d[],"},{"line_number":376,"context_line":"    help\u003dutils.fmt("}],"source_content_type":"text/x-python","patch_set":5,"id":"b9e31c4b_390bb382","line":373,"in_reply_to":"f7c82490_e698bdbc","updated":"2026-05-08 14:23:44.000000000","message":"True, it was there due to my misunderstanding of the user_ and group_ cfg options handling for LDAP section. I moved the parsing and validation to core::UserApi","commit_id":"508d7d6ceee3c31df3b0b79dfbd6192c15748091"}],"keystone/identity/backends/ldap/common.py":[{"author":{"_account_id":8313,"name":"Lajos Katona","display_name":"lajoskatona","email":"katonalala@gmail.com","username":"elajkat","status":"Ericsson Software Technology"},"change_message_id":"4a9d115575277127f622313c3460bd9b14051837","unresolved":false,"context_lines":[{"line_number":1487,"context_line":"        mapping \u003d {}"},{"line_number":1488,"context_line":"        for item in option_list:"},{"line_number":1489,"context_line":"            try:"},{"line_number":1490,"context_line":"                # TODO(lajoskatona): check also if ldap_attr is present"},{"line_number":1491,"context_line":"                # in the self.extra_attr_mapping"},{"line_number":1492,"context_line":"                ldap_attr, exp_format \u003d item.split(\u0027:\u0027)"},{"line_number":1493,"context_line":"            except ValueError:"},{"line_number":1494,"context_line":"                LOG.warning("}],"source_content_type":"text/x-python","patch_set":5,"id":"f594b513_e07bda6e","line":1491,"range":{"start_line":1490,"start_character":16,"end_line":1491,"end_character":48},"updated":"2026-05-08 14:23:44.000000000","message":"I moved the parsing to UserApi and added there this validation to make sure that extra_attr_mapping has the setting in user_password_expiry_format_mapping","commit_id":"508d7d6ceee3c31df3b0b79dfbd6192c15748091"}],"keystone/identity/backends/ldap/core.py":[{"author":{"_account_id":13478,"name":"Boris Bobrov","email":"b.bobrov@sap.com","username":"bbobrov"},"change_message_id":"3c1ac2c43578f1a44b18394e499694f97504a07f","unresolved":true,"context_lines":[{"line_number":47,"context_line":"    ) + datetime.timedelta(days\u003ddays)"},{"line_number":48,"context_line":""},{"line_number":49,"context_line":""},{"line_number":50,"context_line":"def _convert_windows_filetime(value):"},{"line_number":51,"context_line":"    intervals \u003d int(value)"},{"line_number":52,"context_line":"    if intervals \u003d\u003d 0 or intervals \u003d\u003d 9223372036854775807:"},{"line_number":53,"context_line":"        return None  # Never expires"}],"source_content_type":"text/x-python","patch_set":2,"id":"1e39319b_9a895c74","line":50,"updated":"2026-03-10 17:58:40.000000000","message":"Could you please add a docstring to this function explaining what is going on here?","commit_id":"8c37ff85780805d07e48d41201399dddf01aff94"},{"author":{"_account_id":8313,"name":"Lajos Katona","display_name":"lajoskatona","email":"katonalala@gmail.com","username":"elajkat","status":"Ericsson Software Technology"},"change_message_id":"b921acded5ae2a40e18f0f46d353aa7d39e92a9f","unresolved":true,"context_lines":[{"line_number":47,"context_line":"    ) + datetime.timedelta(days\u003ddays)"},{"line_number":48,"context_line":""},{"line_number":49,"context_line":""},{"line_number":50,"context_line":"def _convert_windows_filetime(value):"},{"line_number":51,"context_line":"    intervals \u003d int(value)"},{"line_number":52,"context_line":"    if intervals \u003d\u003d 0 or intervals \u003d\u003d 9223372036854775807:"},{"line_number":53,"context_line":"        return None  # Never expires"}],"source_content_type":"text/x-python","patch_set":2,"id":"e9178d37_02a14d19","line":50,"in_reply_to":"1e39319b_9a895c74","updated":"2026-03-24 10:29:27.000000000","message":"I tried to cover the functionality of these methods","commit_id":"8c37ff85780805d07e48d41201399dddf01aff94"},{"author":{"_account_id":8313,"name":"Lajos Katona","display_name":"lajoskatona","email":"katonalala@gmail.com","username":"elajkat","status":"Ericsson Software Technology"},"change_message_id":"81bed4d41bfb42d3390189ac40a96f08e59f2428","unresolved":false,"context_lines":[{"line_number":47,"context_line":"    ) + datetime.timedelta(days\u003ddays)"},{"line_number":48,"context_line":""},{"line_number":49,"context_line":""},{"line_number":50,"context_line":"def _convert_windows_filetime(value):"},{"line_number":51,"context_line":"    intervals \u003d int(value)"},{"line_number":52,"context_line":"    if intervals \u003d\u003d 0 or intervals \u003d\u003d 9223372036854775807:"},{"line_number":53,"context_line":"        return None  # Never expires"}],"source_content_type":"text/x-python","patch_set":2,"id":"cf180739_61fdd0bc","line":50,"in_reply_to":"e9178d37_02a14d19","updated":"2026-04-29 14:39:49.000000000","message":"Done","commit_id":"8c37ff85780805d07e48d41201399dddf01aff94"},{"author":{"_account_id":13478,"name":"Boris Bobrov","email":"b.bobrov@sap.com","username":"bbobrov"},"change_message_id":"3c1ac2c43578f1a44b18394e499694f97504a07f","unresolved":true,"context_lines":[{"line_number":49,"context_line":""},{"line_number":50,"context_line":"def _convert_windows_filetime(value):"},{"line_number":51,"context_line":"    intervals \u003d int(value)"},{"line_number":52,"context_line":"    if intervals \u003d\u003d 0 or intervals \u003d\u003d 9223372036854775807:"},{"line_number":53,"context_line":"        return None  # Never expires"},{"line_number":54,"context_line":"    return datetime("},{"line_number":55,"context_line":"        1601, 1, 1, tzinfo\u003ddatetime.timezone.utc"}],"source_content_type":"text/x-python","patch_set":2,"id":"1ad9f574_7e467bba","line":52,"range":{"start_line":52,"start_character":38,"end_line":52,"end_character":57},"updated":"2026-03-10 17:58:40.000000000","message":"please explain in a comment why it was chosen","commit_id":"8c37ff85780805d07e48d41201399dddf01aff94"},{"author":{"_account_id":8313,"name":"Lajos Katona","display_name":"lajoskatona","email":"katonalala@gmail.com","username":"elajkat","status":"Ericsson Software Technology"},"change_message_id":"b921acded5ae2a40e18f0f46d353aa7d39e92a9f","unresolved":false,"context_lines":[{"line_number":49,"context_line":""},{"line_number":50,"context_line":"def _convert_windows_filetime(value):"},{"line_number":51,"context_line":"    intervals \u003d int(value)"},{"line_number":52,"context_line":"    if intervals \u003d\u003d 0 or intervals \u003d\u003d 9223372036854775807:"},{"line_number":53,"context_line":"        return None  # Never expires"},{"line_number":54,"context_line":"    return datetime("},{"line_number":55,"context_line":"        1601, 1, 1, tzinfo\u003ddatetime.timezone.utc"}],"source_content_type":"text/x-python","patch_set":2,"id":"1143278e_b0ed969b","line":52,"range":{"start_line":52,"start_character":38,"end_line":52,"end_character":57},"in_reply_to":"1ad9f574_7e467bba","updated":"2026-03-24 10:29:27.000000000","message":"Done, perhaps these numbers like max int64 can be easier to consume (for me at least ) as hex, I hope that also makes this part easier to follow","commit_id":"8c37ff85780805d07e48d41201399dddf01aff94"},{"author":{"_account_id":13478,"name":"Boris Bobrov","email":"b.bobrov@sap.com","username":"bbobrov"},"change_message_id":"3c1ac2c43578f1a44b18394e499694f97504a07f","unresolved":true,"context_lines":[{"line_number":60,"context_line":"    return timeutils.parse_strtime(value, fmt\u003d\u0027%Y%m%d%H%M%S.%fZ\u0027)"},{"line_number":61,"context_line":""},{"line_number":62,"context_line":""},{"line_number":63,"context_line":"EXPIRY_CONVERTERS \u003d {"},{"line_number":64,"context_line":"    \u0027epoch_days\u0027: _convert_epoch_days,"},{"line_number":65,"context_line":"    \u0027windows_filetime\u0027: _convert_windows_filetime,"},{"line_number":66,"context_line":"    \u0027generalized_time\u0027: _convert_generalized_time,"}],"source_content_type":"text/x-python","patch_set":2,"id":"e7d87475_c67213d1","line":63,"updated":"2026-03-10 17:58:40.000000000","message":"Why did you decide to implement these functions, and not others?","commit_id":"8c37ff85780805d07e48d41201399dddf01aff94"},{"author":{"_account_id":8313,"name":"Lajos Katona","display_name":"lajoskatona","email":"katonalala@gmail.com","username":"elajkat","status":"Ericsson Software Technology"},"change_message_id":"81bed4d41bfb42d3390189ac40a96f08e59f2428","unresolved":false,"context_lines":[{"line_number":60,"context_line":"    return timeutils.parse_strtime(value, fmt\u003d\u0027%Y%m%d%H%M%S.%fZ\u0027)"},{"line_number":61,"context_line":""},{"line_number":62,"context_line":""},{"line_number":63,"context_line":"EXPIRY_CONVERTERS \u003d {"},{"line_number":64,"context_line":"    \u0027epoch_days\u0027: _convert_epoch_days,"},{"line_number":65,"context_line":"    \u0027windows_filetime\u0027: _convert_windows_filetime,"},{"line_number":66,"context_line":"    \u0027generalized_time\u0027: _convert_generalized_time,"}],"source_content_type":"text/x-python","patch_set":2,"id":"f36d3c30_161c8312","line":63,"in_reply_to":"e21435f3_a8c8b90c","updated":"2026-04-29 14:39:49.000000000","message":"Done","commit_id":"8c37ff85780805d07e48d41201399dddf01aff94"},{"author":{"_account_id":8313,"name":"Lajos Katona","display_name":"lajoskatona","email":"katonalala@gmail.com","username":"elajkat","status":"Ericsson Software Technology"},"change_message_id":"b921acded5ae2a40e18f0f46d353aa7d39e92a9f","unresolved":true,"context_lines":[{"line_number":60,"context_line":"    return timeutils.parse_strtime(value, fmt\u003d\u0027%Y%m%d%H%M%S.%fZ\u0027)"},{"line_number":61,"context_line":""},{"line_number":62,"context_line":""},{"line_number":63,"context_line":"EXPIRY_CONVERTERS \u003d {"},{"line_number":64,"context_line":"    \u0027epoch_days\u0027: _convert_epoch_days,"},{"line_number":65,"context_line":"    \u0027windows_filetime\u0027: _convert_windows_filetime,"},{"line_number":66,"context_line":"    \u0027generalized_time\u0027: _convert_generalized_time,"}],"source_content_type":"text/x-python","patch_set":2,"id":"e21435f3_a8c8b90c","line":63,"in_reply_to":"e7d87475_c67213d1","updated":"2026-03-24 10:29:27.000000000","message":"As I read the available LDAP documentations and have feedback from our support teams these are used as backends. I hope if somebody find another exotic backend with some different expiry format based on these docstrings it is easier to extend Keystone with that as well.","commit_id":"8c37ff85780805d07e48d41201399dddf01aff94"},{"author":{"_account_id":13478,"name":"Boris Bobrov","email":"b.bobrov@sap.com","username":"bbobrov"},"change_message_id":"3c1ac2c43578f1a44b18394e499694f97504a07f","unresolved":true,"context_lines":[{"line_number":93,"context_line":"        if not user_id or not password:"},{"line_number":94,"context_line":"            raise AssertionError(_(\u0027Invalid user / password\u0027))"},{"line_number":95,"context_line":""},{"line_number":96,"context_line":"        # Check if password is expired"},{"line_number":97,"context_line":"        if user_ref.get(\u0027password_expires_at\u0027):"},{"line_number":98,"context_line":"            expires_at \u003d timeutils.normalize_time("},{"line_number":99,"context_line":"                user_ref[\u0027password_expires_at\u0027]"}],"source_content_type":"text/x-python","patch_set":2,"id":"9a0a2abd_38ef4e23","line":96,"updated":"2026-03-10 17:58:40.000000000","message":"if user\u0027s password in ldap is expired, i would expect ldap to prevent authentication. Why do we need this exception?","commit_id":"8c37ff85780805d07e48d41201399dddf01aff94"},{"author":{"_account_id":8313,"name":"Lajos Katona","display_name":"lajoskatona","email":"katonalala@gmail.com","username":"elajkat","status":"Ericsson Software Technology"},"change_message_id":"81bed4d41bfb42d3390189ac40a96f08e59f2428","unresolved":false,"context_lines":[{"line_number":93,"context_line":"        if not user_id or not password:"},{"line_number":94,"context_line":"            raise AssertionError(_(\u0027Invalid user / password\u0027))"},{"line_number":95,"context_line":""},{"line_number":96,"context_line":"        # Check if password is expired"},{"line_number":97,"context_line":"        if user_ref.get(\u0027password_expires_at\u0027):"},{"line_number":98,"context_line":"            expires_at \u003d timeutils.normalize_time("},{"line_number":99,"context_line":"                user_ref[\u0027password_expires_at\u0027]"}],"source_content_type":"text/x-python","patch_set":2,"id":"e3975d31_ef7f41ac","line":96,"in_reply_to":"5c0cf627_4b41a32e","updated":"2026-04-29 14:39:49.000000000","message":"Done","commit_id":"8c37ff85780805d07e48d41201399dddf01aff94"},{"author":{"_account_id":8313,"name":"Lajos Katona","display_name":"lajoskatona","email":"katonalala@gmail.com","username":"elajkat","status":"Ericsson Software Technology"},"change_message_id":"b921acded5ae2a40e18f0f46d353aa7d39e92a9f","unresolved":true,"context_lines":[{"line_number":93,"context_line":"        if not user_id or not password:"},{"line_number":94,"context_line":"            raise AssertionError(_(\u0027Invalid user / password\u0027))"},{"line_number":95,"context_line":""},{"line_number":96,"context_line":"        # Check if password is expired"},{"line_number":97,"context_line":"        if user_ref.get(\u0027password_expires_at\u0027):"},{"line_number":98,"context_line":"            expires_at \u003d timeutils.normalize_time("},{"line_number":99,"context_line":"                user_ref[\u0027password_expires_at\u0027]"}],"source_content_type":"text/x-python","patch_set":2,"id":"5c0cf627_4b41a32e","line":96,"in_reply_to":"9a0a2abd_38ef4e23","updated":"2026-03-24 10:29:27.000000000","message":"I added comment for this also to make it visible for future readers of the code. some LDaP backends dont force pw expiration during bind, like shadowexpire for openldap, and 389ds for example) so this why the pwExpired is raised if the returned expiration time is over.","commit_id":"8c37ff85780805d07e48d41201399dddf01aff94"},{"author":{"_account_id":13478,"name":"Boris Bobrov","email":"b.bobrov@sap.com","username":"bbobrov"},"change_message_id":"3c1ac2c43578f1a44b18394e499694f97504a07f","unresolved":true,"context_lines":[{"line_number":343,"context_line":"                    except (ValueError, TypeError):"},{"line_number":344,"context_line":"                        LOG.warning(\u0027Invalid shadowExpire value: %s\u0027, value)"},{"line_number":345,"context_line":"                else:"},{"line_number":346,"context_line":"                    obj[keystone_attr] \u003d value"},{"line_number":347,"context_line":""},{"line_number":348,"context_line":"        return obj"},{"line_number":349,"context_line":""}],"source_content_type":"text/x-python","patch_set":2,"id":"c32d4170_0b2707d0","line":346,"updated":"2026-03-10 17:58:40.000000000","message":"Why do you need this line? The values that are not in `self.pw_expiry_mapping` all go now to `obj`, but they were not there before this change.","commit_id":"8c37ff85780805d07e48d41201399dddf01aff94"},{"author":{"_account_id":8313,"name":"Lajos Katona","display_name":"lajoskatona","email":"katonalala@gmail.com","username":"elajkat","status":"Ericsson Software Technology"},"change_message_id":"81bed4d41bfb42d3390189ac40a96f08e59f2428","unresolved":false,"context_lines":[{"line_number":343,"context_line":"                    except (ValueError, TypeError):"},{"line_number":344,"context_line":"                        LOG.warning(\u0027Invalid shadowExpire value: %s\u0027, value)"},{"line_number":345,"context_line":"                else:"},{"line_number":346,"context_line":"                    obj[keystone_attr] \u003d value"},{"line_number":347,"context_line":""},{"line_number":348,"context_line":"        return obj"},{"line_number":349,"context_line":""}],"source_content_type":"text/x-python","patch_set":2,"id":"b58488a4_6f550b81","line":346,"in_reply_to":"91ca1619_f154cb34","updated":"2026-04-29 14:39:49.000000000","message":"Done","commit_id":"8c37ff85780805d07e48d41201399dddf01aff94"},{"author":{"_account_id":8313,"name":"Lajos Katona","display_name":"lajoskatona","email":"katonalala@gmail.com","username":"elajkat","status":"Ericsson Software Technology"},"change_message_id":"b921acded5ae2a40e18f0f46d353aa7d39e92a9f","unresolved":true,"context_lines":[{"line_number":343,"context_line":"                    except (ValueError, TypeError):"},{"line_number":344,"context_line":"                        LOG.warning(\u0027Invalid shadowExpire value: %s\u0027, value)"},{"line_number":345,"context_line":"                else:"},{"line_number":346,"context_line":"                    obj[keystone_attr] \u003d value"},{"line_number":347,"context_line":""},{"line_number":348,"context_line":"        return obj"},{"line_number":349,"context_line":""}],"source_content_type":"text/x-python","patch_set":2,"id":"91ca1619_f154cb34","line":346,"in_reply_to":"c32d4170_0b2707d0","updated":"2026-03-24 10:29:27.000000000","message":"thanks it is really not necessary","commit_id":"8c37ff85780805d07e48d41201399dddf01aff94"}]}
