def generate(resource_types=()):
    resource_defs = {}
    definitions = {
        'resources': resource_defs,
        'string_dict': {
            "type": "object",
            "patternProperties": {
                "": {"type": "string"},
            },
        },
        'basic_dict': {
            "type": "object",
            "patternProperties": {
                "": {
                    'oneOf': [
                        {"type": "string"},
                        {"type": "boolean"},
                        {"type": "number"},
                    ],
                }
            },
        },
        'iam-statement': {
            'additionalProperties': False,
            'type': 'object',
            'properties': {
                'Sid': {'type': 'string'},
                'Effect': {'type': 'string', 'enum': ['Allow', 'Deny']},
                'Principal': {'anyOf': [
                    {'type': 'string'},
                    {'type': 'object'}, {'type': 'array'}]},
                'NotPrincipal': {'anyOf': [{'type': 'object'}, {'type': 'array'}]},
                'Action': {'anyOf': [{'type': 'string'}, {'type': 'array'}]},
                'NotAction': {'anyOf': [{'type': 'string'}, {'type': 'array'}]},
                'Resource': {'anyOf': [{'type': 'string'}, {'type': 'array'}]},
                'NotResource': {'anyOf': [{'type': 'string'}, {'type': 'array'}]},
                'Condition': {'type': 'object'}
            },
            'required': ['Sid', 'Effect'],
            'oneOf': [
                {'required': ['Principal', 'Action', 'Resource']},
                {'required': ['NotPrincipal', 'Action', 'Resource']},
                {'required': ['Principal', 'NotAction', 'Resource']},
                {'required': ['NotPrincipal', 'NotAction', 'Resource']},
                {'required': ['Principal', 'Action', 'NotResource']},
                {'required': ['NotPrincipal', 'Action', 'NotResource']},
                {'required': ['Principal', 'NotAction', 'NotResource']},
                {'required': ['NotPrincipal', 'NotAction', 'NotResource']}
            ]
        },
        'actions': {},
        'filters': {
            'value': ValueFilter.schema,
            'event': EventFilter.schema,
            'age': AgeFilter.schema,
            'reduce': ReduceFilter.schema,
            # Shortcut form of value filter as k=v
            'valuekv': {
                'type': 'object',
                'additionalProperties': {'oneOf': [{'type': 'number'}, {'type': 'null'},
                    {'type': 'array', 'maxItems': 0}, {'type': 'string'}, {'type': 'boolean'}]},
                'minProperties': 1,
                'maxProperties': 1},
        },
        'filters_common': {
            'list_item_attrs': _get_attr_schema(),
            'comparison_operators': {
                'enum': list(OPERATORS.keys())},
            'value_types': {'enum': VALUE_TYPES},
            'value_from': ValuesFrom.schema,
            'value': {'oneOf': [
                {'type': 'array'},
                {'type': 'string'},
                {'type': 'boolean'},
                {'type': 'number'},
                {'type': 'null'}]},
        },
        'policy': {
            'type': 'object',
            'required': ['name', 'resource'],
            'additionalProperties': False,
            'properties': {
                'name': {
                    'type': 'string',
                    'pattern': "^[A-z][A-z0-9]*(-[A-z0-9]+)*$"},
                'conditions': {
                    'type': 'array',
                    'items': {'anyOf': [
                        {'type': 'object', 'additionalProperties': False,
                         'properties': {'or': {
                             '$ref': '#/definitions/policy/properties/conditions'}}},
                        {'type': 'object', 'additionalProperties': False,
                         'properties': {'not': {
                             '$ref': '#/definitions/policy/properties/conditions'}}},
                        {'type': 'object', 'additionalProperties': False,
                         'properties': {'and': {
                             '$ref': '#/definitions/policy/properties/conditions'}}},
                        {'$ref': '#/definitions/filters/value'},
                        {'$ref': '#/definitions/filters/event'},
                        {'$ref': '#/definitions/filters/valuekv'}]}},
                # these should be deprecated for conditions
                'region': {'type': 'string'},
                'tz': {'type': 'string'},
                'start': {'format': 'date-time'},
                'end': {'format': 'date-time'},
                'resource': {'oneOf': [
                    {'type': 'string'},
                    {'type': 'array', 'items': {'type': 'string'}}]},
                'max-resources': {'anyOf': [
                    {'type': 'integer', 'minimum': 1},
                    {'$ref': '#/definitions/max-resources-properties'}
                ]},
                'max-resources-percent': {'type': 'number', 'minimum': 0, 'maximum': 100},
                'comment': {'type': 'string'},
                'comments': {'type': 'string'},
                'description': {'type': 'string'},
                'tags': {'type': 'array', 'items': {'type': 'string'}},
                'metadata': {'type': 'object'},
                'mode': {'$ref': '#/definitions/policy-mode'},
                'source': {'enum': list(sources.keys())},
                'actions': {
                    'type': 'array',
                },
                'filters': {
                    'type': 'array'
                },
                #
                # TODO: source queries should really move under
                # source. This was initially used for describe sources
                # to expose server side query mechanisms, however its
                # important to note it also prevents resource cache
                # utilization between policies that have different
                # queries.
                'query': {
                    'type': 'array', 'items': {'type': 'object'}}

            },
        },
        'policy-mode': {
            'anyOf': [e.schema for _, e in execution.items()],
        },
        'max-resources-properties': {
            'type': 'object',
            'additionalProperties': False,
            'properties': {
                'amount': {"type": 'integer', 'minimum': 1},
                'op': {'enum': ['or', 'and']},
                'percent': {'type': 'number', 'minimum': 0, 'maximum': 100}
            }
        }
    }

    resource_refs = []
    for cloud_name, cloud_type in sorted(clouds.items()):
        for type_name, resource_type in sorted(cloud_type.resources.items()):
            r_type_name = "%s.%s" % (cloud_name, type_name)
            if resource_types and r_type_name not in resource_types:
                if not resource_type.type_aliases:
                    continue
                elif not {"%s.%s" % (cloud_name, ralias) for ralias
                        in resource_type.type_aliases}.intersection(
                        resource_types):
                    continue

            aliases = []
            if resource_type.type_aliases:
                aliases.extend(["%s.%s" % (cloud_name, a) for a in resource_type.type_aliases])
                # aws gets legacy aliases with no cloud prefix
                if cloud_name == 'aws':
                    aliases.extend(resource_type.type_aliases)

            # aws gets additional alias for default name
            if cloud_name == 'aws':
                aliases.append(type_name)

            resource_refs.append(
                process_resource(
                    r_type_name,
                    resource_type,
                    resource_defs,
                    aliases,
                    definitions,
                    cloud_name
                ))

    schema = {
        "$schema": "http://json-schema.org/draft-07/schema#",
        'id': 'http://schema.cloudcustodian.io/v0/custodian.json',
        'definitions': definitions,
        'type': 'object',
        'required': ['policies'],
        'additionalProperties': False,
        'properties': {
            'vars': {'type': 'object'},
            'policies': {
                'type': 'array',
                'additionalItems': False,
                'items': {'anyOf': resource_refs}
            }
        }
    }

    # allow empty policies with lazy load
    if not resource_refs:
        schema['properties']['policies']['items'] = {'type': 'object'}
    return schema

generate(resource_types=())

{'resources': {}, 'string_dict': {'type': 'object', 'patternProperties': {'': {'type': 'string'}}}, 'basic_dict': {'type': 'object', 'patternProperties': {'': {'oneOf': [{'type': 'string'}, {'type': 'boolean'}, {'type': 'number'}]}}}, 'iam-statement': {'additionalProperties': False, 'type': 'object', 'properties': {'Sid': {'type': 'string'}, 'Effect': {'type': 'string', 'enum': ['Allow', 'Deny']}, 'Principal': {'anyOf': [{'type': 'string'}, {'type': 'object'}, {'type': 'array'}]}, 'NotPrincipal': {'anyOf': [{'type': 'object'}, {'type': 'array'}]}, 'Action': {'anyOf': [{'type': 'string'}, {'type': 'array'}]}, 'NotAction': {'anyOf': [{'type': 'string'}, {'type': 'array'}]}, 'Resource': {'anyOf': [{'type': 'string'}, {'type': 'array'}]}, 'NotResource': {'anyOf': [{'type': 'string'}, {'type': 'array'}]}, 'Condition': {'type': 'object'}}, 'required': ['Sid', 'Effect'], 'oneOf': [{'required': ['Principal', 'Action', 'Resource']}, {'required': ['NotPrincipal', 'Action', 'Resource']}, {'required': ['Principal', 'NotAction', 'Resource']}, {'required': ['NotPrincipal', 'NotAction', 'Resource']}, {'required': ['Principal', 'Action', 'NotResource']}, {'required': ['NotPrincipal', 'Action', 'NotResource']}, {'required': ['Principal', 'NotAction', 'NotResource']}, {'required': ['NotPrincipal', 'NotAction', 'NotResource']}]}, 'actions': {}, 'filters': {'value': {'type': 'object', 'additionalProperties': False, 'required': ['type'], 'properties': {'type': {'enum': ['value']}, 'key': {'type': 'string'}, 'value_type': {'$ref': '#/definitions/filters_common/value_types'}, 'default': {'type': 'object'}, 'value_regex': {'type': 'string'}, 'value_from': {'$ref': '#/definitions/filters_common/value_from'}, 'value': {'$ref': '#/definitions/filters_common/value'}, 'op': {'$ref': '#/definitions/filters_common/comparison_operators'}, 'value_path': {'type': 'string'}}}, 'event': {'type': 'object', 'additionalProperties': False, 'required': ['type'], 'properties': {'type': {'enum': ['event']}, 'key': {'type': 'string'}, 'value_type': {'$ref': '#/definitions/filters_common/value_types'}, 'default': {'type': 'object'}, 'value_regex': {'type': 'string'}, 'value_from': {'$ref': '#/definitions/filters_common/value_from'}, 'value': {'$ref': '#/definitions/filters_common/value'}, 'op': {'$ref': '#/definitions/filters_common/comparison_operators'}, 'value_path': {'type': 'string'}}}, 'age': None, 'reduce': {'type': 'object', 'additionalProperties': False, 'required': ['type'], 'properties': {'type': {'enum': ['reduce']}, 'group-by': {'oneOf': [{'type': 'string'}, {'type': 'object', 'key': {'type': 'string'}, 'value_type': {'enum': ['string', 'number', 'date']}, 'value_regex': 'string'}]}, 'sort-by': {'oneOf': [{'type': 'string'}, {'type': 'object', 'key': {'type': 'string'}, 'value_type': {'enum': ['string', 'number', 'date']}, 'value_regex': 'string'}]}, 'order': {'enum': ['asc', 'desc', 'reverse', 'randomize']}, 'null-order': {'enum': ['first', 'last']}, 'limit': {'type': 'number', 'minimum': 0}, 'limit-percent': {'type': 'number', 'minimum': 0, 'maximum': 100}, 'discard': {'type': 'number', 'minimum': 0}, 'discard-percent': {'type': 'number', 'minimum': 0, 'maximum': 100}}}, 'valuekv': {'type': 'object', 'additionalProperties': {'oneOf': [{'type': 'number'}, {'type': 'null'}, {'type': 'array', 'maxItems': 0}, {'type': 'string'}, {'type': 'boolean'}]}, 'minProperties': 1, 'maxProperties': 1}}, 'filters_common': {'list_item_attrs': {'items': {'anyOf': [{'$ref': '#/definitions/filters/value'}, {'$ref': '#/definitions/filters/valuekv'}, {'additional_properties': False, 'properties': {'and': {'type': 'array', 'items': {'anyOf': [{'$ref': '#/definitions/filters/value'}, {'$ref': '#/definitions/filters/valuekv'}]}}}, 'type': 'object'}, {'additional_properties': False, 'properties': {'or': {'type': 'array', 'items': {'anyOf': [{'$ref': '#/definitions/filters/value'}, {'$ref': '#/definitions/filters/valuekv'}]}}}, 'type': 'object'}, {'additional_properties': False, 'properties': {'not': {'type': 'array', 'items': {'anyOf': [{'$ref': '#/definitions/filters/value...onalProperties': False, 'properties': {'execution-options': {'type': 'object'}, 'function-prefix': {'type': 'string'}, 'member-role': {'type': 'string'}, 'packages': {'type': 'array', 'items': {'type': 'string'}}, 'layers': {'type': 'array', 'items': {'type': 'string'}}, 'concurrency': {'type': 'integer'}, 'runtime': {'enum': ['python3.8', 'python3.9', 'python3.10', 'python3.11', 'python3.12']}, 'role': {'type': 'string'}, 'handler': {'type': 'string'}, 'pattern': {'type': 'object', 'minProperties': 1}, 'timeout': {'type': 'number'}, 'memory': {'type': 'number'}, 'environment': {'type': 'object'}, 'tags': {'type': 'object'}, 'dead_letter_config': {'type': 'object'}, 'kms_key_arn': {'type': 'string'}, 'tracing_config': {'type': 'object'}, 'security_groups': {'type': 'array'}, 'subnets': {'type': 'array'}, 'type': {'enum': ['asg-instance-state']}, 'events': {'type': 'array', 'items': {'enum': ['launch-success', 'launch-failure', 'terminate-success', 'terminate-failure']}}}, 'required': ['type']}, {'type': 'object', 'additionalProperties': False, 'properties': {'execution-options': {'type': 'object'}, 'function-prefix': {'type': 'string'}, 'member-role': {'type': 'string'}, 'packages': {'type': 'array', 'items': {'type': 'string'}}, 'layers': {'type': 'array', 'items': {'type': 'string'}}, 'concurrency': {'type': 'integer'}, 'runtime': {'enum': ['python3.8', 'python3.9', 'python3.10', 'python3.11', 'python3.12']}, 'role': {'type': 'string'}, 'handler': {'type': 'string'}, 'pattern': {'type': 'object', 'minProperties': 1}, 'timeout': {'type': 'number'}, 'memory': {'type': 'number'}, 'environment': {'type': 'object'}, 'tags': {'type': 'object'}, 'dead_letter_config': {'type': 'object'}, 'kms_key_arn': {'type': 'string'}, 'tracing_config': {'type': 'object'}, 'security_groups': {'type': 'array'}, 'subnets': {'type': 'array'}, 'type': {'enum': ['guard-duty']}}, 'required': ['type']}, {'type': 'object', 'additionalProperties': False, 'properties': {'execution-options': {'type': 'object'}, 'function-prefix': {'type': 'string'}, 'member-role': {'type': 'string'}, 'packages': {'type': 'array', 'items': {'type': 'string'}}, 'layers': {'type': 'array', 'items': {'type': 'string'}}, 'concurrency': {'type': 'integer'}, 'runtime': {'enum': ['python3.8', 'python3.9', 'python3.10', 'python3.11', 'python3.12']}, 'role': {'type': 'string'}, 'handler': {'type': 'string'}, 'pattern': {'type': 'object', 'minProperties': 1}, 'timeout': {'type': 'number'}, 'memory': {'type': 'number'}, 'environment': {'type': 'object'}, 'tags': {'type': 'object'}, 'dead_letter_config': {'type': 'object'}, 'kms_key_arn': {'type': 'string'}, 'tracing_config': {'type': 'object'}, 'security_groups': {'type': 'array'}, 'subnets': {'type': 'array'}, 'type': {'enum': ['config-poll-rule']}, 'schedule': {'enum': ['One_Hour', 'Three_Hours', 'Six_Hours', 'Twelve_Hours', 'TwentyFour_Hours']}, 'ignore-support-check': {'type': 'boolean'}}, 'required': ['type']}, {'type': 'object', 'additionalProperties': False, 'properties': {'execution-options': {'type': 'object'}, 'function-prefix': {'type': 'string'}, 'member-role': {'type': 'string'}, 'packages': {'type': 'array', 'items': {'type': 'string'}}, 'layers': {'type': 'array', 'items': {'type': 'string'}}, 'concurrency': {'type': 'integer'}, 'runtime': {'enum': ['python3.8', 'python3.9', 'python3.10', 'python3.11', 'python3.12']}, 'role': {'type': 'string'}, 'handler': {'type': 'string'}, 'pattern': {'type': 'object', 'minProperties': 1}, 'timeout': {'type': 'number'}, 'memory': {'type': 'number'}, 'environment': {'type': 'object'}, 'tags': {'type': 'object'}, 'dead_letter_config': {'type': 'object'}, 'kms_key_arn': {'type': 'string'}, 'tracing_config': {'type': 'object'}, 'security_groups': {'type': 'array'}, 'subnets': {'type': 'array'}, 'type': {'enum': ['config-rule']}}, 'required': ['type']}]}, 'max-resources-properties': {'type': 'object', 'additionalProperties': False, 'properties': {'amount': {'type': 'integer', 'minimum': 1}, 'op': {'enum': ['or', 'and']}, 'percent': {'type': 'number', 'minimum': 0, 'maximum': 100}}}}

{'resources': {'gcp.region': {'actions': {}, 'filters': {}, 'policy': {'allOf': [{'$ref': '#/definitions/policy'}, {'properties': {'resource': {'enum': ['gcp.region']}, 'filters': {'type': 'array', 'items': {'anyOf': [{'enum': []}, {'type': 'object', 'additionalProperties': False, 'properties': {'or': {'$ref': '#/definitions/resources/gcp.region/policy/allOf/1/properties/filters'}}}, {'type': 'object', 'additionalProperties': False, 'properties': {'and': {'$ref': '#/definitions/resources/gcp.region/policy/allOf/1/properties/filters'}}}, {'type': 'object', 'additionalProperties': False, 'properties': {'not': {'$ref': '#/definitions/resources/gcp.region/policy/allOf/1/properties/filters'}}}]}}, 'actions': {'type': 'array', 'items': {'anyOf': [{'enum': []}]}}}}]}}}, 'string_dict': {'type': 'object', 'patternProperties': {'': {'type': 'string'}}}, 'basic_dict': {'type': 'object', 'patternProperties': {'': {'oneOf': [{'type': 'string'}, {'type': 'boolean'}, {'type': 'number'}]}}}, 'iam-statement': {'additionalProperties': False, 'type': 'object', 'properties': {'Sid': {'type': 'string'}, 'Effect': {'type': 'string', 'enum': ['Allow', 'Deny']}, 'Principal': {'anyOf': [{'type': 'string'}, {'type': 'object'}, {'type': 'array'}]}, 'NotPrincipal': {'anyOf': [{'type': 'object'}, {'type': 'array'}]}, 'Action': {'anyOf': [{'type': 'string'}, {'type': 'array'}]}, 'NotAction': {'anyOf': [{'type': 'string'}, {'type': 'array'}]}, 'Resource': {'anyOf': [{'type': 'string'}, {'type': 'array'}]}, 'NotResource': {'anyOf': [{'type': 'string'}, {'type': 'array'}]}, 'Condition': {'type': 'object'}}, 'required': ['Sid', 'Effect'], 'oneOf': [{'required': ['Principal', 'Action', 'Resource']}, {'required': ['NotPrincipal', 'Action', 'Resource']}, {'required': ['Principal', 'NotAction', 'Resource']}, {'required': ['NotPrincipal', 'NotAction', 'Resource']}, {'required': ['Principal', 'Action', 'NotResource']}, {'required': ['NotPrincipal', 'Action', 'NotResource']}, {'required': ['Principal', 'NotAction', 'NotResource']}, {'required': ['NotPrincipal', 'NotAction', 'NotResource']}]}, 'actions': {}, 'filters': {'value': {'type': 'object', 'additionalProperties': False, 'required': ['type'], 'properties': {'type': {'enum': ['value']}, 'key': {'type': 'string'}, 'value_type': {'$ref': '#/definitions/filters_common/value_types'}, 'default': {'type': 'object'}, 'value_regex': {'type': 'string'}, 'value_from': {'$ref': '#/definitions/filters_common/value_from'}, 'value': {'$ref': '#/definitions/filters_common/value'}, 'op': {'$ref': '#/definitions/filters_common/comparison_operators'}, 'value_path': {'type': 'string'}}}, 'event': {'type': 'object', 'additionalProperties': False, 'required': ['type'], 'properties': {'type': {'enum': ['event']}, 'key': {'type': 'string'}, 'value_type': {'$ref': '#/definitions/filters_common/value_types'}, 'default': {'type': 'object'}, 'value_regex': {'type': 'string'}, 'value_from': {'$ref': '#/definitions/filters_common/value_from'}, 'value': {'$ref': '#/definitions/filters_common/value'}, 'op': {'$ref': '#/definitions/filters_common/comparison_operators'}, 'value_path': {'type': 'string'}}}, 'age': None, 'reduce': {'type': 'object', 'additionalProperties': False, 'required': ['type'], 'properties': {'type': {'enum': ['reduce']}, 'group-by': {'oneOf': [{'type': 'string'}, {'type': 'object', 'key': {'type': 'string'}, 'value_type': {'enum': ['string', 'number', 'date']}, 'value_regex': 'string'}]}, 'sort-by': {'oneOf': [{'type': 'string'}, {'type': 'object', 'key': {'type': 'string'}, 'value_type': {'enum': ['string', 'number', 'date']}, 'value_regex': 'string'}]}, 'order': {'enum': ['asc', 'desc', 'reverse', 'randomize']}, 'null-order': {'enum': ['first', 'last']}, 'limit': {'type': 'number', 'minimum': 0}, 'limit-percent': {'type': 'number', 'minimum': 0, 'maximum': 100}, 'discard': {'type': 'number', 'minimum': 0}, 'discard-percent': {'type': 'number', 'minimum': 0, 'maximum': 100}}}, 'valuekv': {'type': 'object', 'additionalProperties': {'oneOf': [{'type': 'number'}, {'type': 'null'}, {'type': 'array', 'maxItems': 0}, {...onalProperties': False, 'properties': {'execution-options': {'type': 'object'}, 'function-prefix': {'type': 'string'}, 'member-role': {'type': 'string'}, 'packages': {'type': 'array', 'items': {'type': 'string'}}, 'layers': {'type': 'array', 'items': {'type': 'string'}}, 'concurrency': {'type': 'integer'}, 'runtime': {'enum': ['python3.8', 'python3.9', 'python3.10', 'python3.11', 'python3.12']}, 'role': {'type': 'string'}, 'handler': {'type': 'string'}, 'pattern': {'type': 'object', 'minProperties': 1}, 'timeout': {'type': 'number'}, 'memory': {'type': 'number'}, 'environment': {'type': 'object'}, 'tags': {'type': 'object'}, 'dead_letter_config': {'type': 'object'}, 'kms_key_arn': {'type': 'string'}, 'tracing_config': {'type': 'object'}, 'security_groups': {'type': 'array'}, 'subnets': {'type': 'array'}, 'type': {'enum': ['asg-instance-state']}, 'events': {'type': 'array', 'items': {'enum': ['launch-success', 'launch-failure', 'terminate-success', 'terminate-failure']}}}, 'required': ['type']}, {'type': 'object', 'additionalProperties': False, 'properties': {'execution-options': {'type': 'object'}, 'function-prefix': {'type': 'string'}, 'member-role': {'type': 'string'}, 'packages': {'type': 'array', 'items': {'type': 'string'}}, 'layers': {'type': 'array', 'items': {'type': 'string'}}, 'concurrency': {'type': 'integer'}, 'runtime': {'enum': ['python3.8', 'python3.9', 'python3.10', 'python3.11', 'python3.12']}, 'role': {'type': 'string'}, 'handler': {'type': 'string'}, 'pattern': {'type': 'object', 'minProperties': 1}, 'timeout': {'type': 'number'}, 'memory': {'type': 'number'}, 'environment': {'type': 'object'}, 'tags': {'type': 'object'}, 'dead_letter_config': {'type': 'object'}, 'kms_key_arn': {'type': 'string'}, 'tracing_config': {'type': 'object'}, 'security_groups': {'type': 'array'}, 'subnets': {'type': 'array'}, 'type': {'enum': ['guard-duty']}}, 'required': ['type']}, {'type': 'object', 'additionalProperties': False, 'properties': {'execution-options': {'type': 'object'}, 'function-prefix': {'type': 'string'}, 'member-role': {'type': 'string'}, 'packages': {'type': 'array', 'items': {'type': 'string'}}, 'layers': {'type': 'array', 'items': {'type': 'string'}}, 'concurrency': {'type': 'integer'}, 'runtime': {'enum': ['python3.8', 'python3.9', 'python3.10', 'python3.11', 'python3.12']}, 'role': {'type': 'string'}, 'handler': {'type': 'string'}, 'pattern': {'type': 'object', 'minProperties': 1}, 'timeout': {'type': 'number'}, 'memory': {'type': 'number'}, 'environment': {'type': 'object'}, 'tags': {'type': 'object'}, 'dead_letter_config': {'type': 'object'}, 'kms_key_arn': {'type': 'string'}, 'tracing_config': {'type': 'object'}, 'security_groups': {'type': 'array'}, 'subnets': {'type': 'array'}, 'type': {'enum': ['config-poll-rule']}, 'schedule': {'enum': ['One_Hour', 'Three_Hours', 'Six_Hours', 'Twelve_Hours', 'TwentyFour_Hours']}, 'ignore-support-check': {'type': 'boolean'}}, 'required': ['type']}, {'type': 'object', 'additionalProperties': False, 'properties': {'execution-options': {'type': 'object'}, 'function-prefix': {'type': 'string'}, 'member-role': {'type': 'string'}, 'packages': {'type': 'array', 'items': {'type': 'string'}}, 'layers': {'type': 'array', 'items': {'type': 'string'}}, 'concurrency': {'type': 'integer'}, 'runtime': {'enum': ['python3.8', 'python3.9', 'python3.10', 'python3.11', 'python3.12']}, 'role': {'type': 'string'}, 'handler': {'type': 'string'}, 'pattern': {'type': 'object', 'minProperties': 1}, 'timeout': {'type': 'number'}, 'memory': {'type': 'number'}, 'environment': {'type': 'object'}, 'tags': {'type': 'object'}, 'dead_letter_config': {'type': 'object'}, 'kms_key_arn': {'type': 'string'}, 'tracing_config': {'type': 'object'}, 'security_groups': {'type': 'array'}, 'subnets': {'type': 'array'}, 'type': {'enum': ['config-rule']}}, 'required': ['type']}]}, 'max-resources-properties': {'type': 'object', 'additionalProperties': False, 'properties': {'amount': {'type': 'integer', 'minimum': 1}, 'op': {'enum': ['or', 'and']}, 'percent': {'type': 'number', 'minimum': 0, 'maximum': 100}}}}

{'$schema': 'http://json-schema.org/draft-07/schema#', 'id': 'http://schema.cloudcustodian.io/v0/custodian.json', 'definitions': {'resources': {'gcp.region': {'actions': {}, 'filters': {}, 'policy': {'allOf': [{'$ref': '#/definitions/policy'}, {'properties': {'resource': {'enum': ['gcp.region']}, 'filters': {'type': 'array', 'items': {'anyOf': [{'enum': []}, {'type': 'object', 'additionalProperties': False, 'properties': {'or': {'$ref': '#/definitions/resources/gcp.region/policy/allOf/1/properties/filters'}}}, {'type': 'object', 'additionalProperties': False, 'properties': {'and': {'$ref': '#/definitions/resources/gcp.region/policy/allOf/1/properties/filters'}}}, {'type': 'object', 'additionalProperties': False, 'properties': {'not': {'$ref': '#/definitions/resources/gcp.region/policy/allOf/1/properties/filters'}}}]}}, 'actions': {'type': 'array', 'items': {'anyOf': [{'enum': []}]}}}}]}}}, 'string_dict': {'type': 'object', 'patternProperties': {'': {'type': 'string'}}}, 'basic_dict': {'type': 'object', 'patternProperties': {'': {'oneOf': [{'type': 'string'}, {'type': 'boolean'}, {'type': 'number'}]}}}, 'iam-statement': {'additionalProperties': False, 'type': 'object', 'properties': {'Sid': {'type': 'string'}, 'Effect': {'type': 'string', 'enum': ['Allow', 'Deny']}, 'Principal': {'anyOf': [{'type': 'string'}, {'type': 'object'}, {'type': 'array'}]}, 'NotPrincipal': {'anyOf': [{'type': 'object'}, {'type': 'array'}]}, 'Action': {'anyOf': [{'type': 'string'}, {'type': 'array'}]}, 'NotAction': {'anyOf': [{'type': 'string'}, {'type': 'array'}]}, 'Resource': {'anyOf': [{'type': 'string'}, {'type': 'array'}]}, 'NotResource': {'anyOf': [{'type': 'string'}, {'type': 'array'}]}, 'Condition': {'type': 'object'}}, 'required': ['Sid', 'Effect'], 'oneOf': [{'required': ['Principal', 'Action', 'Resource']}, {'required': ['NotPrincipal', 'Action', 'Resource']}, {'required': ['Principal', 'NotAction', 'Resource']}, {'required': ['NotPrincipal', 'NotAction', 'Resource']}, {'required': ['Principal', 'Action', 'NotResource']}, {'required': ['NotPrincipal', 'Action', 'NotResource']}, {'required': ['Principal', 'NotAction', 'NotResource']}, {'required': ['NotPrincipal', 'NotAction', 'NotResource']}]}, 'actions': {}, 'filters': {'value': {'type': 'object', 'additionalProperties': False, 'required': ['type'], 'properties': {'type': {'enum': ['value']}, 'key': {'type': 'string'}, 'value_type': {'$ref': '#/definitions/filters_common/value_types'}, 'default': {'type': 'object'}, 'value_regex': {'type': 'string'}, 'value_from': {'$ref': '#/definitions/filters_common/value_from'}, 'value': {'$ref': '#/definitions/filters_common/value'}, 'op': {'$ref': '#/definitions/filters_common/comparison_operators'}, 'value_path': {'type': 'string'}}}, 'event': {'type': 'object', 'additionalProperties': False, 'required': ['type'], 'properties': {'type': {'enum': ['event']}, 'key': {'type': 'string'}, 'value_type': {'$ref': '#/definitions/filters_common/value_types'}, 'default': {'type': 'object'}, 'value_regex': {'type': 'string'}, 'value_from': {'$ref': '#/definitions/filters_common/value_from'}, 'value': {'$ref': '#/definitions/filters_common/value'}, 'op': {'$ref': '#/definitions/filters_common/comparison_operators'}, 'value_path': {'type': 'string'}}}, 'age': None, 'reduce': {'type': 'object', 'additionalProperties': False, 'required': ['type'], 'properties': {'type': {'enum': ['reduce']}, 'group-by': {'oneOf': [{'type': 'string'}, {'type': 'object', 'key': {'type': 'string'}, 'value_type': {'enum': ['string', 'number', 'date']}, 'value_regex': 'string'}]}, 'sort-by': {'oneOf': [{'type': 'string'}, {'type': 'object', 'key': {'type': 'string'}, 'value_type': {'enum': ['string', 'number', 'date']}, 'value_regex': 'string'}]}, 'order': {'enum': ['asc', 'desc', 'reverse', 'randomize']}, 'null-order': {'enum': ['first', 'last']}, 'limit': {'type': 'number', 'minimum': 0}, 'limit-percent': {'type': 'number', 'minimum': 0, 'maximum': 100}, 'discard': {'type': 'number', 'minimum': 0}, 'discard-percent': {'type': 'number', 'minimum': 0, 'maximum': 100}}}, 'valuekv'...ype': 'string'}}, 'concurrency': {'type': 'integer'}, 'runtime': {'enum': ['python3.8', 'python3.9', 'python3.10', 'python3.11', 'python3.12']}, 'role': {'type': 'string'}, 'handler': {'type': 'string'}, 'pattern': {'type': 'object', 'minProperties': 1}, 'timeout': {'type': 'number'}, 'memory': {'type': 'number'}, 'environment': {'type': 'object'}, 'tags': {'type': 'object'}, 'dead_letter_config': {'type': 'object'}, 'kms_key_arn': {'type': 'string'}, 'tracing_config': {'type': 'object'}, 'security_groups': {'type': 'array'}, 'subnets': {'type': 'array'}, 'type': {'enum': ['asg-instance-state']}, 'events': {'type': 'array', 'items': {'enum': ['launch-success', 'launch-failure', 'terminate-success', 'terminate-failure']}}}, 'required': ['type']}, {'type': 'object', 'additionalProperties': False, 'properties': {'execution-options': {'type': 'object'}, 'function-prefix': {'type': 'string'}, 'member-role': {'type': 'string'}, 'packages': {'type': 'array', 'items': {'type': 'string'}}, 'layers': {'type': 'array', 'items': {'type': 'string'}}, 'concurrency': {'type': 'integer'}, 'runtime': {'enum': ['python3.8', 'python3.9', 'python3.10', 'python3.11', 'python3.12']}, 'role': {'type': 'string'}, 'handler': {'type': 'string'}, 'pattern': {'type': 'object', 'minProperties': 1}, 'timeout': {'type': 'number'}, 'memory': {'type': 'number'}, 'environment': {'type': 'object'}, 'tags': {'type': 'object'}, 'dead_letter_config': {'type': 'object'}, 'kms_key_arn': {'type': 'string'}, 'tracing_config': {'type': 'object'}, 'security_groups': {'type': 'array'}, 'subnets': {'type': 'array'}, 'type': {'enum': ['guard-duty']}}, 'required': ['type']}, {'type': 'object', 'additionalProperties': False, 'properties': {'execution-options': {'type': 'object'}, 'function-prefix': {'type': 'string'}, 'member-role': {'type': 'string'}, 'packages': {'type': 'array', 'items': {'type': 'string'}}, 'layers': {'type': 'array', 'items': {'type': 'string'}}, 'concurrency': {'type': 'integer'}, 'runtime': {'enum': ['python3.8', 'python3.9', 'python3.10', 'python3.11', 'python3.12']}, 'role': {'type': 'string'}, 'handler': {'type': 'string'}, 'pattern': {'type': 'object', 'minProperties': 1}, 'timeout': {'type': 'number'}, 'memory': {'type': 'number'}, 'environment': {'type': 'object'}, 'tags': {'type': 'object'}, 'dead_letter_config': {'type': 'object'}, 'kms_key_arn': {'type': 'string'}, 'tracing_config': {'type': 'object'}, 'security_groups': {'type': 'array'}, 'subnets': {'type': 'array'}, 'type': {'enum': ['config-poll-rule']}, 'schedule': {'enum': ['One_Hour', 'Three_Hours', 'Six_Hours', 'Twelve_Hours', 'TwentyFour_Hours']}, 'ignore-support-check': {'type': 'boolean'}}, 'required': ['type']}, {'type': 'object', 'additionalProperties': False, 'properties': {'execution-options': {'type': 'object'}, 'function-prefix': {'type': 'string'}, 'member-role': {'type': 'string'}, 'packages': {'type': 'array', 'items': {'type': 'string'}}, 'layers': {'type': 'array', 'items': {'type': 'string'}}, 'concurrency': {'type': 'integer'}, 'runtime': {'enum': ['python3.8', 'python3.9', 'python3.10', 'python3.11', 'python3.12']}, 'role': {'type': 'string'}, 'handler': {'type': 'string'}, 'pattern': {'type': 'object', 'minProperties': 1}, 'timeout': {'type': 'number'}, 'memory': {'type': 'number'}, 'environment': {'type': 'object'}, 'tags': {'type': 'object'}, 'dead_letter_config': {'type': 'object'}, 'kms_key_arn': {'type': 'string'}, 'tracing_config': {'type': 'object'}, 'security_groups': {'type': 'array'}, 'subnets': {'type': 'array'}, 'type': {'enum': ['config-rule']}}, 'required': ['type']}]}, 'max-resources-properties': {'type': 'object', 'additionalProperties': False, 'properties': {'amount': {'type': 'integer', 'minimum': 1}, 'op': {'enum': ['or', 'and']}, 'percent': {'type': 'number', 'minimum': 0, 'maximum': 100}}}}, 'type': 'object', 'required': ['policies'], 'additionalProperties': False, 'properties': {'vars': {'type': 'object'}, 'policies': {'type': 'array', 'additionalItems': False, 'items': {'anyOf': [{'$ref': '#/definitions/resources/gcp.region/policy'}]}}}}


def parse_single_layout(layout_str):
    """Parse a single layout from a string

    See parse_layout for details about valid layout strings.
    """
    # width of the layout (x-axis)
    width = None
    # list of layout rows
    rows = []
    start = False
    for i, line in enumerate(layout_str.splitlines()):
        row = line.strip()
        if not row:
            # always ignore empty lines
            continue
        # a layout is always started by a full row of walls
        if not start:
            if row.count('#') != len(row):
                raise ValueError(f"Layout must be enclosed by walls (line: {i})!")
            else:
                # start the layout parsing
                start = True
                # set width of layout
                width = len(row)
                # check that width is even
                if width % 2:
                    raise ValueError(f"Layout width must be even (found {width})!")
                rows.append(row)
                continue
        # Here we are within the layout
        # every row must have the same length
        if len(row) != width:
            raise ValueError(f"Layout rows have differing widths (line: {i})!")
        # rows are always enclosed by walls
        if row[0] != '#' or row[-1] != '#':
            raise ValueError(f"Layout must be enclosed by walls (line:{i})!")
        # append current row to the list of rows
        rows.append(row)
        # detect closing row and ignore whatever follows
        if row.count('#') == len(row):
            start = False
            break

    if start:
        # layout has not been closed!
        raise ValueError(f"Layout must be enclosed by walls (line:{i})!")

    # height of the layout (y-axis)
    height = len(rows)
    walls = []
    food = []
    # bot positions (we assume 4 bots)
    bots = [None]*4

    # iterate through the grid of characters
    for y, row in enumerate(rows):
        for x, char in enumerate(row):
            coord = (x, y)
            # assign the char to the corresponding list
            if char == '#':
                # wall
                walls.append(coord)
            elif char == '.':
                # food
                food.append(coord)
            elif char == ' ':
                # empty
                continue
            else:
                # bot
                try:
                    # we expect an 0<=index<=3
                    bot_idx = int(char)
                    if bot_idx >= len(bots):
                        # reuse the except below
                        raise ValueError
                except ValueError:
                    raise ValueError(f"Unknown character {char} in maze!")
                bots[bot_idx] = coord
    walls.sort()
    food.sort()
    return {'walls':walls, 'food':food, 'bots':bots}

parse_single_layout(layout_str='##################\n#. ... .##.     3#\n# # #  .  .### #1#\n# # ##.   .      #\n#      .   .## # #\n#0# ###.  .  # # #\n#2     .##. ... .#\n##################')


def initial_positions(walls):
    """Calculate initial positions.

    Given the list of walls, returns the free positions that are closest to the
    bottom left and top right corner. The algorithm starts searching from
    (1, height-2) and (width-2, 1) respectively and uses the Manhattan distance
    for judging what is closest. On equal distances, a smaller distance in the
    x value is preferred.
    """
    width = max(walls)[0] + 1
    height = max(walls)[1] + 1

    left_start = (1, height - 2)
    left = []
    right_start = (width - 2, 1)
    right = []

    dist = 0
    while len(left) < 2:
        # iterate through all possible x distances (inclusive)
        for x_dist in range(dist + 1):
            y_dist = dist - x_dist
            pos = (left_start[0] + x_dist, left_start[1] - y_dist)
            # if both coordinates are out of bounds, we stop
            if not (0 <= pos[0] < width) and not (0 <= pos[1] < height):
                raise ValueError("Not enough free initial positions.")
            # if one coordinate is out of bounds, we just continue
            if not (0 <= pos[0] < width) or not (0 <= pos[1] < height):
                continue
            # check if the new value is free
            if pos not in walls:
                left.append(pos)

            if len(left) == 2:
                break

        dist += 1

    dist = 0
    while len(right) < 2:
        # iterate through all possible x distances (inclusive)
        for x_dist in range(dist + 1):
            y_dist = dist - x_dist
            pos = (right_start[0] - x_dist, right_start[1] + y_dist)
            # if both coordinates are out of bounds, we stop
            if not (0 <= pos[0] < width) and not (0 <= pos[1] < height):
                raise ValueError("Not enough free initial positions.")
            # if one coordinate is out of bounds, we just continue
            if not (0 <= pos[0] < width) or not (0 <= pos[1] < height):
                continue
            # check if the new value is free
            if pos not in walls:
                right.append(pos)

            if len(right) == 2:
                break

        dist += 1

    # lower indices start further away
    left.reverse()
    right.reverse()
    return [left[0], right[0], left[1], right[1]]

initial_positions(walls=[(0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 3), (2, 0), (2, 1), (2, 3), (3, 0), (3, 1), (3, 3), (4, 0), (4, 1), (4, 3), (5, 0), (5, 3), (6, 0), (6, 3), (7, 0), (7, 1), (7, 2), (7, 3)])


def digit_version(version_str: str, length: int = 4):
    """Convert a version string into a tuple of integers.

    This method is usually used for comparing two versions. For pre-release
    versions: alpha < beta < rc.

    Args:
        version_str (str): The version string.
        length (int): The maximum number of version levels. Default: 4.

    Returns:
        tuple[int]: The version info in digits (integers).
    """
    assert 'parrots' not in version_str
    version = parse(version_str)
    assert version.release, f'failed to parse version {version_str}'
    release = list(version.release)
    release = release[:length]
    if len(release) < length:
        release = release + [0] * (length - len(release))
    if version.is_prerelease:
        mapping = {'a': -3, 'b': -2, 'rc': -1}
        val = -4
        # version.pre can be None
        if version.pre:
            if version.pre[0] not in mapping:
                warnings.warn(f'unknown prerelease version {version.pre[0]}, '
                              'version checking may go wrong')
            else:
                val = mapping[version.pre[0]]
            release.extend([val, version.pre[-1]])
        else:
            release.extend([val, 0])

    elif version.is_postrelease:
        release.extend([1, version.post])
    else:
        release.extend([0, 0])
    return tuple(release)

digit_version(version_str='2.2.2+cu121', length=4)


def SeparateFlagArgs(args: list):
  """Splits a list of args into those for Flags and those for Fire.

  If an isolated '--' arg is not present in the arg list, then all of the args
  are for Fire. If there is an isolated '--', then the args after the final '--'
  are flag args, and the rest of the args are fire args.

  Args:
    args: The list of arguments received by the Fire command.
  Returns:
    A tuple with the Fire args (a list), followed by the Flag args (a list).
  """
  if len(args) > 0 and (args[-1] == '-h' or args[-1] == '--help') and '--' not in args:
    args.pop()
    args.append('--')
    args.append('-h')

  if '--' in args:
    separator_index = len(args) - 1 - args[::-1].index('--')  # index of last --
    flag_args = args[separator_index + 1:]
    args = args[:separator_index]
    return args, flag_args

  return args, []

SeparateFlagArgs(args=['a', 'b', '--'])


def _ParseFn(args):
    """Parses the list of `args` into (varargs, kwargs), remaining_args."""
    kwargs, remaining_kwargs, remaining_args = _ParseKeywordArgs(
        args, all_args, fn_spec.varkw)

    # Note: _ParseArgs modifies kwargs.
    parsed_args, kwargs, remaining_args, capacity = _ParseArgs(
        fn_spec.args, fn_spec.defaults, num_required_args, kwargs,
        remaining_args, metadata)

    if fn_spec.varargs or fn_spec.varkw:
      # If we're allowed *varargs or **kwargs, there's always capacity.
      capacity = True

    extra_kw = set(kwargs) - set(fn_spec.kwonlyargs)
    if fn_spec.varkw is None and extra_kw:
      raise FireError('Unexpected kwargs present:', extra_kw)

    missing_kwonly = set(required_kwonly) - set(kwargs)
    if missing_kwonly:
      raise FireError('Missing required flags:', missing_kwonly)

    # If we accept *varargs, then use all remaining arguments for *varargs.
    if fn_spec.varargs is not None:
      varargs, remaining_args = remaining_args, []
    else:
      varargs = []

    for index, value in enumerate(varargs):
      varargs[index] = _ParseValue(value, None, None, metadata)

    varargs = parsed_args + varargs
    remaining_args += remaining_kwargs

    consumed_args = args[:len(args) - len(remaining_args)]
    return (varargs, kwargs), consumed_args, remaining_args, capacity

_ParseFn(args=['x'], all_args=[], fn_spec={args=[], varargs=None, varkw='cli_args', defaults=(), kwonlyargs=[], kwonlydefaults={}, annotations={}}, metadata={'ACCEPTS_POSITIONAL_ARGS': False}, num_required_args=0, required_kwonly=set())


def find_original_update_blocks(content, fence=DEFAULT_FENCE):
    # make sure we end with a newline, otherwise the regex will miss <<UPD on the last line
    if not content.endswith("\n"):
        content = content + "\n"

    pieces = re.split(split_re, content)

    pieces.reverse()
    processed = []

    # Keep using the same filename in cases where GPT produces an edit block
    # without a filename.
    current_filename = None
    try:
        while pieces:
            cur = pieces.pop()

            if cur in (DIVIDER, UPDATED):
                processed.append(cur)
                raise ValueError(f"Unexpected {cur}")

            if cur.strip() != HEAD:
                processed.append(cur)
                continue

            processed.append(cur)  # original_marker

            filename = strip_filename(processed[-2].splitlines()[-1], fence)
            try:
                if not filename:
                    filename = strip_filename(processed[-2].splitlines()[-2], fence)
                if not filename:
                    if current_filename:
                        filename = current_filename
                    else:
                        raise ValueError(missing_filename_err)
            except IndexError:
                if current_filename:
                    filename = current_filename
                else:
                    raise ValueError(missing_filename_err)

            current_filename = filename

            original_text = pieces.pop()
            processed.append(original_text)

            divider_marker = pieces.pop()
            processed.append(divider_marker)
            if divider_marker.strip() != DIVIDER:
                raise ValueError(f"Expected `{DIVIDER}` not {divider_marker.strip()}")

            updated_text = pieces.pop()
            processed.append(updated_text)

            updated_marker = pieces.pop()
            processed.append(updated_marker)
            if updated_marker.strip() != UPDATED:
                raise ValueError(f"Expected `{UPDATED}` not `{updated_marker.strip()}")

            yield filename, original_text, updated_text
    except ValueError as e:
        processed = "".join(processed)
        err = e.args[0]
        raise ValueError(f"{processed}\n^^^ {err}")
    except IndexError:
        processed = "".join(processed)
        raise ValueError(f"{processed}\n^^^ Incomplete SEARCH/REPLACE block.")
    except Exception:
        processed = "".join(processed)
        raise ValueError(f"{processed}\n^^^ Error parsing SEARCH/REPLACE block.")

find_original_update_blocks(content='ok', fence=('<source>', '</source>'))

'ok'

'ok'

'ok'

'ok\n'


def perfect_replace(whole_lines, part_lines, replace_lines):
    part_tup = tuple(part_lines)
    part_len = len(part_lines)

    for i in range(len(whole_lines) - part_len + 1):
        whole_tup = tuple(whole_lines[i : i + part_len])
        if part_tup == whole_tup:
            res = whole_lines[:i] + replace_lines + whole_lines[i + part_len :]
            return "".join(res)

perfect_replace(whole_lines=['two\n'], part_lines=['two\n'], replace_lines=['three\n'])


def replace_part_with_missing_leading_whitespace(whole_lines, part_lines, replace_lines):
    # GPT often messes up leading whitespace.
    # It usually does it uniformly across the ORIG and UPD blocks.
    # Either omitting all leading whitespace, or including only some of it.

    # Outdent everything in part_lines and replace_lines by the max fixed amount possible
    leading = [len(p) - len(p.lstrip()) for p in part_lines if p.strip()] + [
        len(p) - len(p.lstrip()) for p in replace_lines if p.strip()
    ]

    if leading and min(leading):
        num_leading = min(leading)
        part_lines = [p[num_leading:] if p.strip() else p for p in part_lines]
        replace_lines = [p[num_leading:] if p.strip() else p for p in replace_lines]

    # can we find an exact match not including the leading whitespace
    num_part_lines = len(part_lines)

    for i in range(len(whole_lines) - num_part_lines + 1):
        add_leading = match_but_for_leading_whitespace(
            whole_lines[i : i + num_part_lines], part_lines
        )

        if add_leading is None:
            continue

        replace_lines = [add_leading + rline if rline.strip() else rline for rline in replace_lines]
        whole_lines = whole_lines[:i] + replace_lines + whole_lines[i + num_part_lines :]
        return "".join(whole_lines)

    return None

replace_part_with_missing_leading_whitespace(whole_lines=['    line1\n', '    line2\n', '    line3\n'], part_lines=[' line1\n', ' line2\n'], replace_lines=[' new_line1\n', '     new_line2\n'])

['    new_line1\n', '        new_line2\n', '    line3\n']

['    new_line1\n', '        new_line2\n']


def check_gitignore(git_root, io, ask=True):
    if not git_root:
        return

    try:
        repo = git.Repo(git_root)
        if repo.ignored(".aider"):
            return
    except git.exc.InvalidGitRepositoryError:
        pass

    pat = ".aider*"

    gitignore_file = Path(git_root) / ".gitignore"
    if gitignore_file.exists():
        content = io.read_text(gitignore_file)
        if content is None:
            return
        if pat in content.splitlines():
            return
    else:
        content = ""

    if ask and not io.confirm_ask(f"Add {pat} to .gitignore (recommended)?"):
        return

    if content and not content.endswith("\n"):
        content += "\n"
    content += pat + "\n"
    io.write_text(gitignore_file, content)

    io.tool_output(f"Added {pat} to .gitignore")

check_gitignore(git_root=PosixPath('/tmp/tmpcr1f5en7'), io={user_input_color=None, tool_output_color=None, tool_error_color=None, input=None, output=None, pretty=False, yes=True, input_history_file=None, chat_history_file=None, encoding='utf-8', dry_run=False, console=<console width=105 None>}, ask=True)

{user_input_color=None, tool_output_color=None, tool_error_color=None, input=None, output=None, pretty=False, yes=True, input_history_file=None, chat_history_file=None, encoding='utf-8', dry_run=False, console=<console width=105 None>, num_user_asks=1}

'.aider*\n'


def _tranmat(a, b):
    """
    Get the coefficents for the affine-linear function f(x)=Ax+s.

    Which fullfills that A is a rotation-matrix,
    f(a) = [0,0] and f(b) = [|b-a|,0].
    """
    A = np.zeros((2, 2))
    A[0, 0] = b[0] - a[0]
    A[1, 1] = b[0] - a[0]
    A[1, 0] = -(b[1] - a[1])
    A[0, 1] = +(b[1] - a[1])
    A /= _dist(a, b)
    s = -np.dot(A, a)
    return A, s

_tranmat(a=array([0., 0.]), b=array([3., 0.]))


def _yvalue(b, a, c):
    """
    Get the two possible y-values for the upper point of a triangle.

    where c is the length of the down side starting in the origin and
    lying on the x-axes, a is the distance of the unknown point to the origen
    and b is the distance of the unknown point to the righter given point
    """
    # ckeck flatness to eliminate numerical errors when the triangle is flat
    if a + b <= c or a + c <= b or b + c <= a:
        return 0.0, -0.0

    res = 2 * ((a * b) ** 2 + (a * c) ** 2 + (b * c) ** 2)
    res -= a ** 4 + b ** 4 + c ** 4
    # in case of numerical errors set res to 0 (hope you check validty before)
    res = max(res, 0.0)
    res = np.sqrt(res)
    res /= 2 * c
    return res, -res

_yvalue(b=4.0, a=2.0, c=3.0)


def _test_grad_nd(n, ndim):
    coords = [np.arange(n)] * ndim
    xc = np.meshgrid(*coords, indexing="ij")

    # u = sum_i(xc[i]**2)
    u = reduce(lambda x,y: x+y**2, xc, 0.0)
    ucopy = np.copy(u)

    # check the gradient values
    slices = tuple([slice(1,-1,None)] * ndim)
    for i in range(ndim):
        assert grad(u, axis=i) == pytest.approx(2*xc[i][slices])

    # check if u is unchanged
    assert np.all(u == ucopy)

_test_grad_nd(n=92, ndim=1)


def get_idx(ndim, axis=None, axis_idx=None):
    s = [midx] * ndim
    if axis is not None:
        if hasattr(axis, "__iter__"):
            for ax, axidx in zip(axis, axis_idx):
                s[ax] = axidx
        else:
            s[axis] = axis_idx
    return tuple(s)

get_idx(ndim=1, axis=0, axis_idx=slice(None, -2, None))


def _test_grad2_nd(n, ndim):
    coords = [np.arange(n)] * ndim
    xc = np.meshgrid(*coords, indexing="ij")

    # u = sum_i(xc[i]**2)
    u = reduce(lambda x,y: x+y**2, xc, 0.0)
    ucopy = np.copy(u)

    # check the gradient values
    gu = np.zeros(tuple([n-2]*ndim))
    gu2 = gu + 2.0
    for i in range(ndim):
        for j in range(ndim):
            if i == j:
                assert grad2(u, axes=(i,j)) == pytest.approx(gu2)
            else:
                assert grad2(u, axes=(i,j)) == pytest.approx(gu)

    # check if u is unchanged
    assert np.all(u == ucopy)

_test_grad2_nd(n=32, ndim=1)


def det_hess(u):
    """
    Get the determinant of the Hessian matrix of `u`.

    Parameters
    ----------
    * `u` : numpy.ndarray
        The ndarray input with shape (n0+2, n1+2, ..., nd1+2).

    Returns
    -------
    * numpy.ndarray
        The ndarray of the second grad of `u` with shape (n0, n1, ..., nd1).
    """
    ndim = np.ndim(u)
    inshape = np.asarray(u.shape)
    outshape = list(inshape - 2)

    # obtain the second gradient per each pairs of axes
    hess_unarranged = np.zeros([ndim, ndim] + outshape)
    for i in range(ndim):
        for j in range(i,ndim):
            grad2_val = grad2(u, (i,j))
            hess_unarranged[i,j] = grad2_val
            hess_unarranged[j,i] = grad2_val

    # rearrange hessian to have shape: outshape + [ndim, ndim]
    perm_idx = list(range(2,ndim+2)) + list(range(2))
    hess = np.transpose(hess_unarranged, perm_idx)

    # calculate and return the determinant
    return np.linalg.det(hess)

det_hess(u=array([  0.,   1.,   4.,   9.,  16.,  25.,  36.,  49.,  64.,  81., 100.,       121., 144., 169., 196., 225., 256., 289., 324., 361., 400., 441.,       484., 529., 576., 625., 676., 729., 784., 841., 900., 961.]))


def forward(source, phi):
    """
    Obtain the target density distribution given the source distribution and
    the mapping potential, phi.
    The mapping from source coordinate, $x$, to the target coordinate, $y$, is
    given by:

    $$
    y = x + \nabla phi(x).
    $$

    The coordinate in i-th dimension is given by `np.arange(source.shape[i])`.

    Parameters
    ----------
    * `source` : numpy.ndarray
        The source density distribution in n-dimensional array.
    * `phi` : numpy.ndarray
        The mapping potential given above. It must have the same shape as
        `source`.

    Returns
    -------
    * numpy.ndarray
        The target density distribution in n-dimensional array.
    """
    # convert to np.ndarray
    source = np.asarray(source)
    phi = np.asarray(phi)
    # check the shapes of inputs
    if source.shape != phi.shape:
        raise ValueError("The source and phi must have the same shape.")

    # calculate the total potential so that $y = \nabla u(x)$
    u0, u, phi_pad = _get_full_potential(phi)
    ndim = np.ndim(phi)

    # calculate the determinant of the hessian
    det_hess_s = det_hess(u)

    # get the displacement in (n x D) format
    x = np.array([grad(u0, axis=i) for i in range(ndim)]).reshape((ndim,-1)).T
    y = np.array([grad(u , axis=i) for i in range(ndim)]).reshape((ndim,-1)).T

    # interpolate the values
    interp = lambda s: griddata(y, s.flatten(), x, "linear").reshape(s.shape)
    target_s = source / det_hess_s
    target = interp(target_s)

    # fill nan values with zeros
    target[np.isnan(target)] = 0.0
    return target

forward(source=array([3.72665317e-06, 6.14389891e-06, 1.00262383e-05, 1.61957424e-05,       2.58959932e-05, 4.09857759e-05, 6.42099934e-05, 9.95728564e-05,       1.52843925e-04, 2.32233182e-04, 3.49276399e-04, 5.19975743e-04,       7.66241736e-04, 1.11767979e-03, 1.61375600e-03, 2.30636063e-03,       3.26276232e-03, 4.56890930e-03, 6.33298575e-03, 8.68907130e-03,       1.18006814e-02, 1.58638899e-02, 2.11096565e-02, 2.78049116e-02,       3.62518979e-02, 4.67852390e-02, 5.97662260e-02, 7.55738747e-02,       9.45924385e-02, 1.17195255e-01, 1.43725065e-01, 1.74471250e-01,       2.09644807e-01, 2.49352209e-01, 2.93569685e-01, 3.42119690e-01,       3.94651546e-01, 4.50628259e-01, 5.09321387e-01, 5.69815527e-01,       6.31023482e-01, 6.91712523e-01, 7.50541364e-01, 8.06106646e-01,       8.56996891e-01, 9.01851159e-01, 9.39419053e-01, 9.68618450e-01,       9.88587205e-01, 9.98725433e-01, 9.98725433e-01, 9.88587205e-01,       9.68618450e-01, 9.39419053e-01, 9.01851159e-01, 8.56996891e-01,       8.06106646e-01, 7.50541364e-01, 6.91712523e-01, 6.31023482e-01,       5.69815527e-01, 5.09321387e-01, 4.50628259e-01, 3.94651546e-01,       3.42119690e-01, 2.93569685e-01, 2.49352209e-01, 2.09644807e-01,       1.74471250e-01, 1.43725065e-01, 1.17195255e-01, 9.45924385e-02,       7.55738747e-02, 5.97662260e-02, 4.67852390e-02, 3.62518979e-02,       2.78049116e-02, 2.11096565e-02, 1.58638899e-02, 1.18006814e-02,       8.68907130e-03, 6.33298575e-03, 4.56890930e-03, 3.26276232e-03,       2.30636063e-03, 1.61375600e-03, 1.11767979e-03, 7.66241736e-04,       5.19975743e-04, 3.49276399e-04, 2.32233182e-04, 1.52843925e-04,       9.95728564e-05, 6.42099934e-05, 4.09857759e-05, 2.58959932e-05,       1.61957424e-05, 1.00262383e-05, 6.14389891e-06, 3.72665317e-06]), phi=array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,       0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,       0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,       0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,       0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,       0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]))

<function forward.<locals>.<lambda> at 0x7fab7f2e3700>


def _get_default_expanded_coordinate(shape, ndim):
    x_coords = []
    for i in range(ndim):
        idx = [None] * ndim
        idx[i] = slice(None, None, None)
        x_coords.append(np.arange(shape[i])[tuple(idx)])
    return x_coords

_get_default_expanded_coordinate(shape=array([102]), ndim=1)


def _get_idx(ndim, dim, s, defidx=None):
    defidx = slice(None, None, None) if defidx is None else defidx
    idx = [defidx] * ndim
    idx[dim] = s
    return tuple(idx)

_get_idx(ndim=1, dim=0, s=slice(1, 2, None), defidx=None)


def _test_forward_nd_slanted_pot(n, ndim, abs=None):
    x = np.arange(n) - n / 2.0
    xs = np.meshgrid(*([x]*ndim), indexing="ij")
    xs_sq = reduce(lambda x,y:x+y*y, xs, 0.0)

    # phi is slanted on the first dimension, so the target will be shifted
    # source on the first dimension by A
    A = n / 6.0
    sigma = (n/30.)
    source = np.exp(-xs_sq / (2*sigma**2))
    source_copy = np.copy(source)
    phi = xs[0] * A
    target = sb.forward(source, phi)

    xs2 = np.copy(xs)
    xs2[0] -= A
    xs2_sq = reduce(lambda x,y:x+y*y, xs2, 0.0)
    target_calc = np.exp(-xs2_sq / (2*sigma**2))

    # accurate within 2.5*(1/n)*100%
    abs = 2.5/n if abs is None else abs
    assert target == pytest.approx(target_calc, abs=abs)

    # check the dimension of target
    assert np.ndim(target) == ndim

    # make sure the source is not changed
    assert np.all(source == source_copy)

_test_forward_nd_slanted_pot(n=100, ndim=1, abs=None)


def _test_forward_nd_quad_pot(n, ndim, abs=None):
    x = np.arange(n) - n / 2.0
    xs = np.meshgrid(*([x]*ndim), indexing="ij")
    xs_sq = reduce(lambda x,y:x+y*y, xs, 0.0)

    # phi is quadratic on all dimension, so the target will be scaled
    # source on all dimension by (1+B)
    B = 1.0
    scale = 1 + B
    sigma = (n/30.)
    source = np.exp(-xs_sq / (2*sigma**2))
    source_copy = np.copy(source)
    phi = 0.5*B*xs_sq
    target = sb.forward(source, phi)

    target_calc = (scale**-ndim)*np.exp(-xs_sq / (2*(sigma*scale)**2))

    # accurate within 2.5*(1/n)*100%
    abs = 2.5/n if abs is None else abs
    assert target == pytest.approx(target_calc, abs=abs)

    # check the dimension of target
    assert np.ndim(target) == ndim

    # make sure the source is not changed
    assert np.all(source == source_copy)

_test_forward_nd_quad_pot(n=100, ndim=1, abs=None)


def parse_access_method(access_method: str):
    num_workers = 0
    scheduler = "threaded"
    download = access_method.startswith("download")
    local = access_method.startswith("local")
    if download or local:
        split = access_method.split(":")
        if len(split) == 1:
            split.extend(("threaded", "0"))
        elif len(split) == 2:
            split.append("threaded" if split[1].isnumeric() else "0")
        elif len(split) >= 3:
            num_integers = sum(1 for i in split if i.isnumeric())
            if num_integers != 1 or len(split) > 3:
                raise ValueError(
                    "Invalid access_method format. Expected format is one of the following: {download, download:scheduler, download:num_workers, download:scheduler:num_workers, download:num_workers:scheduler}"
                )

        access_method = "download" if download else "local"
        num_worker_index = 1 if split[1].isnumeric() else 2
        scheduler_index = 3 - num_worker_index
        num_workers = int(split[num_worker_index])
        scheduler = split[scheduler_index]
    return access_method, num_workers, scheduler

parse_access_method(access_method='download')


def serialize_chunkids(version: str, arr: np.ndarray) -> memoryview:
    """Serializes chunk ID encoders into a single byte stream. This is how the encoders will be written to the storage provider.

    Args:
        version: (str) Version of deeplake library.
        arr: (np.ndarray) Encoded chunk ids from a `ChunkIdEncoder` instance.

    Returns:
        Serialized chunk ids as memoryview.
    """
    len_version = len(version)
    write_dtype = version_compare(version, "2.7.6") >= 0
    flatbuff = bytearray(1 + int(write_dtype) + len_version + arr.nbytes)

    # Write version
    len_version = len(version)
    flatbuff[0] = len_version
    flatbuff[1 : 1 + len_version] = version.encode("ascii")
    offset = 1 + len_version

    # write encoder dtype
    if write_dtype:
        dtype = arr.dtype
        num_bytes = int(dtype.itemsize)
        flatbuff[offset] = num_bytes
        offset += 1

    # Write ids
    flatbuff[offset : offset + arr.nbytes] = arr.tobytes()
    offset += arr.nbytes
    return memoryview(flatbuff)

serialize_chunkids(version='3.8.18', arr=array([], shape=(0, 2), dtype=uint64))


def rolling_mean_by_h(x, h, w, name):
    """Compute a rolling mean of x, after first aggregating by h.

    Right-aligned. Computes a single mean for each unique value of h. Each
    mean is over at least w samples.

    Parameters
    ----------
    x: Array.
    h: Array of horizon for each value in x.
    w: Integer window size (number of elements).
    name: Name for metric in result dataframe

    Returns
    -------
    Dataframe with columns horizon and name, the rolling mean of x.
    """
    # Aggregate over h
    df = pd.DataFrame({'x': x, 'h': h})
    df2 = (
        df.groupby('h').agg(['sum', 'count']).reset_index().sort_values('h')
    )
    xs = df2['x']['sum'].values
    ns = df2['x']['count'].values
    hs = df2.h.values

    trailing_i = len(df2) - 1
    x_sum = 0
    n_sum = 0
    # We don't know output size but it is bounded by len(df2)
    res_x = np.empty(len(df2))

    # Start from the right and work backwards
    for i in range(len(df2) - 1, -1, -1):
        x_sum += xs[i]
        n_sum += ns[i]
        while n_sum >= w:
            # Include points from the previous horizon. All of them if still
            # less than w, otherwise weight the mean by the difference
            excess_n = n_sum - w
            excess_x = excess_n * xs[i] / ns[i]
            res_x[trailing_i] = (x_sum - excess_x)/ w
            x_sum -= xs[trailing_i]
            n_sum -= ns[trailing_i]
            trailing_i -= 1

    res_h = hs[(trailing_i + 1):]
    res_x = res_x[(trailing_i + 1):]

    return pd.DataFrame({'horizon': res_h, name: res_x})

rolling_mean_by_h(x=array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]), h=array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]), w=1, name='x')


def rolling_median_by_h(x, h, w, name):
    """Compute a rolling median of x, after first aggregating by h.

    Right-aligned. Computes a single median for each unique value of h. Each
    median is over at least w samples.

    For each h where there are fewer than w samples, we take samples from the previous h,
    moving backwards. (In other words, we ~ assume that the x's are shuffled within each h.)

    Parameters
    ----------
    x: Array.
    h: Array of horizon for each value in x.
    w: Integer window size (number of elements).
    name: Name for metric in result dataframe

    Returns
    -------
    Dataframe with columns horizon and name, the rolling median of x.
    """
    # Aggregate over h
    df = pd.DataFrame({'x': x, 'h': h})
    grouped = df.groupby('h')
    df2 = grouped.size().reset_index().sort_values('h')
    hs = df2['h']

    res_h = []
    res_x = []
    # Start from the right and work backwards
    i = len(hs) - 1
    while i >= 0:
        h_i = hs[i]
        xs = grouped.get_group(h_i).x.tolist()

        # wrap in array so this works if h is pandas Series with custom index or numpy array
        next_idx_to_add = np.array(h == h_i).argmax() - 1
        while (len(xs) < w) and (next_idx_to_add >= 0):
            # Include points from the previous horizon. All of them if still
            # less than w, otherwise just enough to get to w.
            xs.append(x[next_idx_to_add])
            next_idx_to_add -= 1
        if len(xs) < w:
            # Ran out of points before getting enough.
            break
        res_h.append(hs[i])
        res_x.append(np.median(xs))
        i -= 1
    res_h.reverse()
    res_x.reverse()
    return pd.DataFrame({'horizon': res_h, name: res_x})

rolling_median_by_h(x=array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]), h=array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]), w=1, name='x')

<pandas.core.groupby.generic.DataFrameGroupBy object at 0x7ff75ca12880>


def glob_absolute_paths(file: Union[str, Path]) -> List[Path]:
            path = Path(file)
            if not path.is_absolute():
                path = base / path
            return sorted(path.parent.glob(path.name), key=lambda p: p.stem)

glob_absolute_paths(file='aggrid.js', base=PosixPath('/local/rcs/jinjun/code/pytrace-collector/logs/self_collected/tried/zauberzeug+nicegui/zauberzeug+nicegui/nicegui/elements'))


def ios_screenshot(args: list = None) -> None:
    """
        Take an iOS screenshot.

        :param args:
        :return:
    """

    if len(args) <= 0:
        click.secho('Usage: ios ui screenshot <local png destination>', bold=True)
        return

    destination = args[0]

    if not destination.endswith('.png'):
        destination = destination + '.png'

    api = state_connection.get_api()
    png = api.ios_ui_screenshot()

    with open(destination, 'wb') as f:
        f.write(png)

    click.secho('Screenshot saved to: {0}'.format(destination), fg='green')

ios_screenshot(args=['foo'])


def aes(text, key):
    pad = 16 - len(text) % 16
    text = text + bytearray([pad] * pad)
    encryptor = AES.new(key, 2, b"0102030405060708")
    ciphertext = encryptor.encrypt(text)
    return base64.b64encode(ciphertext)

aes(text=b'{"ids": [347230, 496619464, 405998841, 28012031], "br": 320000, "csrf_token": ""}', key=b'0CoJUm6Qyw8W8jud')

b'{"ids": [347230, 496619464, 405998841, 28012031], "br": 320000, "csrf_token": ""}\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f'

{_state=<Cryptodome.Util._raw_api.SmartPointer object at 0x7f925764db80>, block_size=16, iv=b'0102030405060708', IV=b'0102030405060708', _next=[<bound method CbcMode.encrypt of <Cryptodome.Cipher._mode_cbc.CbcMode object at 0x7f925764dd60>>, <bound method CbcMode.decrypt of <Cryptodome.Cipher._mode_cbc.CbcMode object at 0x7f925764dd60>>]}

{_state=<Cryptodome.Util._raw_api.SmartPointer object at 0x7f925764db80>, block_size=16, iv=b'0102030405060708', IV=b'0102030405060708', _next=[<bound method CbcMode.encrypt of <Cryptodome.Cipher._mode_cbc.CbcMode object at 0x7f925764dd60>>]}


def test_generate(monkeypatch, generated, stop_tokens, expected):
    import chat.base as chat
    import generate.base as generate

    input_idx = torch.tensor([5, 3])
    max_returned_tokens = len(input_idx) + 8
    model = MagicMock()
    model.config.block_size = 100
    model.max_seq_length = 100
    it = iter(generated)

    def multinomial(*_, **__):
        out = next(it)
        return torch.tensor([out])

    monkeypatch.setattr(generate, "multinomial_num_samples_1", multinomial)
    actual = chat.generate(model, input_idx, max_returned_tokens, stop_tokens=stop_tokens)
    actual = list(actual)

    assert len(actual) == len(expected)
    if not actual:
        assert actual == expected
    else:
        for t in actual:
            assert t.dtype == torch.long
        assert torch.cat(actual).tolist() == expected

test_generate(monkeypatch={_setattr=[], _setitem=[], _cwd=None, _savesyspath=None}, generated=repeat(1), stop_tokens=(), expected=[1, 1, 1, 1, 1, 1, 1, 1])

{_setattr=[(<module 'generate.base' from '/local/rcs/jinjun/code/pytrace-collector/logs/self_collected/tried/Lightning-AI+lit-gpt/Lightning-AI+lit-gpt/generate/base.py'>, 'multinomial_num_samples_1', <function multinomial_num_samples_1 at 0x7f805238a160>)], _setitem=[], _cwd=None, _savesyspath=None}

<function test_generate.<locals>.multinomial at 0x7f7fd0f7e430>

<generator object generate at 0x7f803c55ff90>


def rowcol_to_a1(row, col):
    """Translates a row and column cell address to A1 notation.

    :param row: The row of the cell to be converted.
        Rows start at index 1.
    :type row: int, str

    :param col: The column of the cell to be converted.
        Columns start at index 1.
    :type row: int, str

    :returns: a string containing the cell's coordinates in A1 notation.

    Example:

    >>> rowcol_to_a1(1, 1)
    A1

    """
    row = int(row)
    col = int(col)

    if row < 1 or col < 1:
        raise IncorrectCellLabel("({}, {})".format(row, col))

    div = col
    column_label = ""

    while div:
        (div, mod) = divmod(div, 26)
        if mod == 0:
            mod = 26
            div -= 1
        column_label = chr(mod + MAGIC_NUMBER) + column_label

    label = "{}{}".format(column_label, row)

    return label

rowcol_to_a1(row=4, col=4)


def fill_gaps(L, rows=None, cols=None, padding_value=""):
    """Fill gaps in a list of lists.
    e.g.,::

        >>> L = [
        ... [1, 2, 3],
        ... ]
        >>> fill_gaps(L, 2, 4)
        [
            [1, 2, 3, ""],
            ["", "", "", ""]
        ]

    :param L: List of lists to fill gaps in.
    :param rows: Number of rows to fill.
    :param cols: Number of columns to fill.
    :param padding_value: Default value to fill gaps with.

    :type L: list[list[T]]
    :type rows: int
    :type cols: int
    :type padding_value: T

    :return: List of lists with gaps filled.
    :rtype: list[list[T]]:
    """
    try:
        max_cols = max(len(row) for row in L) if cols is None else cols
        max_rows = len(L) if rows is None else rows

        pad_rows = max_rows - len(L)

        if pad_rows:
            L = L + ([[]] * pad_rows)

        return [rightpad(row, max_cols, padding_value=padding_value) for row in L]
    except ValueError:
        return []

fill_gaps(L=[['', 'Dummy']], rows=None, cols=None, padding_value='')


def render_pep440_feature(pieces):
    """Build up version string, used within "feature" branch of repository.

    Our goal: MERGE-POINT.post.devN+gHEX.BRANCH-NAME.M[.dirty]
        +) MERGE-POINT = Most recent common ancestor for `develop` and `master`
          *) Does not yet handle branch from `release-*`
        +) N = DISTANCE from the MERGE-POINT of `develop` and `master`
        +) M = DISTANCE from the MERGE-POINT of "feature" and `develop`

    Exceptions:
    1: no tags. 0.post.devDISTANCE+gHEX[.dirty]
    """
    if pieces["closest-tag"] and pieces["develop"]:
        rendered = pieces["closest-tag"]
        distance_to_develop = pieces["distance-to-develop"]
        distance_to_merge = pieces["distance-to-master"]
        distance_merge_to_tag = (pieces["distance"] - distance_to_merge)
        distance_dev_to_merge = (distance_to_merge - distance_to_develop)
        if (distance_merge_to_tag > 0):
            rendered += ".%d" % distance_merge_to_tag
        rendered += ".post.dev%d" % distance_dev_to_merge
        rendered += plus_or_dot(pieces)
        rendered += "g%s" % pieces["short"]
        rendered += ".%s" % pieces["branch"]
        rendered += ".%d" % distance_to_develop
    else:
        # exception #1
        rendered = "0.post.dev%d" % (pieces["distance"] - 1)
        rendered += plus_or_dot(pieces)
        rendered += "g%s" % pieces["short"]
    if pieces["dirty"]:
        rendered += ".dirty"
    return rendered

render_pep440_feature(pieces={'long': 'e60d005d389cb31b6e99f937e35adbe3fccb7aaf', 'short': 'e60d005', 'error': None, 'dirty': False, 'closest-tag': '0.8', 'distance': 3, 'branch': 'HEAD', 'distance-to-master': 0, 'develop': None, 'distance-to-develop': None, 'date': '2018-05-05T22:17:58-0700', 'authors': ['Padraic Shafer']})


def compute_loc(idx, shape):
    loc = [0] * len(shape)
    for i in range(len(shape)):
        prod = int(np.prod(shape[i + 1:]))
        loc[i] = idx // prod
        idx = idx % prod
    return tuple(loc)

compute_loc(idx=0, shape=(2, 4))


def __build_func(verb, args, kwargs={}):
        params = ['self']
        params += ['%s' % stringcase.snakecase(k) for k in args]
        params += ['%s=%s' % (stringcase.snakecase(k), v) for k, v in kwargs.items()]
        largs = list(args) + list(kwargs.keys())
        return eval(
            'lambda %s: self._%s(%s)' % (
                ','.join(params), verb, ','.join(['%s=%s' % (k, stringcase.snakecase(k)) for k in largs])
            )
        )

__build_func(verb='get', args=[], kwargs={})


def __str__(self):
        self.reduce()
        sign = '-' if self.integer < 0 else ''
        integer_array = list(str(abs(self.integer)).rjust(self.decimals, '0'))
        index = len(integer_array) - self.decimals
        if index == 0:
            item = '0.'
        elif self.decimals < 0:
            item = '0' * (-self.decimals)
        elif self.decimals == 0:
            item = ''
        else:
            item = '.'
        integer_array.insert(index, item)
        return sign + ''.join(integer_array)

__str__(self=Precise(1393.938), self.base=10, self.decimals=3, self.integer=1393938)


def div(self, other, precision=18):
        distance = precision - self.decimals + other.decimals
        if distance == 0:
            numerator = self.integer
        elif distance < 0:
            exponent = self.base ** -distance
            numerator = self.integer // exponent
        else:
            exponent = self.base ** distance
            numerator = self.integer * exponent
        result, mod = divmod(numerator, other.integer)
        # python floors negative numbers down instead of truncating
        # if mod is zero it will be floored to itself so we do not add one
        result = result + 1 if result < 0 and mod else result
        return Precise(result, precision)

div(self=Precise(0.00000002), other=Precise(69696900000), precision=1, self.base=10, self.decimals=8, self.integer=2)


def _get_channels(self, mode, width_mult):
        if mode == "small":
            channels = [16, 16, 24, 48, 576]
        else:
            channels = [16, 24, 40, 112, 960]
        channels = [
            3,
        ] + [_make_divisible(x * width_mult) for x in channels]
        return tuple(channels)

_get_channels(self=MobileNetV3Encoder(), mode='large', width_mult=0.75, self._backward_hooks=OrderedDict(), self._backward_pre_hooks=OrderedDict(), self._buffers=OrderedDict(), self._depth=3, self._forward_hooks=OrderedDict(), self._forward_hooks_always_called=OrderedDict(), self._forward_hooks_with_kwargs=OrderedDict(), self._forward_pre_hooks=OrderedDict(), self._forward_pre_hooks_with_kwargs=OrderedDict(), self._is_full_backward_hook=None, self._load_state_dict_post_hooks=OrderedDict(), self._load_state_dict_pre_hooks=OrderedDict(), self._mode='large', self._modules=OrderedDict(), self._non_persistent_buffers_set=set(), self._parameters=OrderedDict(), self._state_dict_hooks=OrderedDict(), self._state_dict_pre_hooks=OrderedDict(), self.training=True)


def _make_stage(self, planes: int, num_blocks: int, num_se_blocks: int) -> nn.Sequential:
        """Build a stage of MobileOne model.

        :param planes: Number of output channels.
        :param num_blocks: Number of blocks in this stage.
        :param num_se_blocks: Number of SE blocks in this stage.
        :return: A stage of MobileOne model.
        """
        # Get strides for all layers
        strides = [2] + [1] * (num_blocks - 1)
        blocks = []
        for ix, stride in enumerate(strides):
            use_se = False
            if num_se_blocks > num_blocks:
                raise ValueError("Number of SE blocks cannot " "exceed number of layers.")
            if ix >= (num_blocks - num_se_blocks):
                use_se = True

            # Depthwise conv
            blocks.append(
                MobileOneBlock(
                    in_channels=self.in_planes,
                    out_channels=self.in_planes,
                    kernel_size=3,
                    stride=stride,
                    padding=1,
                    groups=self.in_planes,
                    inference_mode=self.inference_mode,
                    use_se=use_se,
                    num_conv_branches=self.num_conv_branches,
                )
            )
            # Pointwise conv
            blocks.append(
                MobileOneBlock(
                    in_channels=self.in_planes,
                    out_channels=planes,
                    kernel_size=1,
                    stride=1,
                    padding=0,
                    groups=1,
                    inference_mode=self.inference_mode,
                    use_se=use_se,
                    num_conv_branches=self.num_conv_branches,
                )
            )
            self.in_planes = planes
            self.cur_layer_idx += 1
        return nn.Sequential(*blocks)

_make_stage(self=MobileOne(  (stage0): MobileOneBlock(    (se): Identity()    (activation): ReLU()    (rbr_conv): ModuleList(      (0): Sequential(        (conv): Conv2d(3, 48, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)        (bn): BatchNorm2d(48, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)      )    )    (rbr_scale): Sequential(      (conv): Conv2d(3, 48, kernel_size=(1, 1), stride=(2, 2), bias=False)      (bn): BatchNorm2d(48, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)    )  )), planes=48, num_blocks=2, num_se_blocks=0, self._backward_hooks=OrderedDict(), self._backward_pre_hooks=OrderedDict(), self._buffers=OrderedDict(), self._depth=3, self._forward_hooks=OrderedDict(), self._forward_hooks_always_called=OrderedDict(), self._forward_hooks_with_kwargs=OrderedDict(), self._forward_pre_hooks=OrderedDict(), self._forward_pre_hooks_with_kwargs=OrderedDict(), self._in_channels=3, self._is_full_backward_hook=None, self._load_state_dict_post_hooks=OrderedDict(), self._load_state_dict_pre_hooks=OrderedDict(), self._modules=OrderedDict([('stage0', MobileOneBlock(  (se): Identity()  (activation): ReLU()  (rbr_conv): ModuleList(    (0): Sequential(      (conv): Conv2d(3, 48, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)      (bn): BatchNorm2d(48, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)    )  )  (rbr_scale): Sequential(    (conv): Conv2d(3, 48, kernel_size=(1, 1), stride=(2, 2), bias=False)    (bn): BatchNorm2d(48, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)  )))]), self._non_persistent_buffers_set=set(), self._out_channels=(3, 48, 48, 128, 256, 1024), self._parameters=OrderedDict(), self._state_dict_hooks=OrderedDict(), self._state_dict_pre_hooks=OrderedDict(), self.cur_layer_idx=1, self.in_planes=48, self.inference_mode=False, self.num_conv_branches=4, self.training=True, self.use_se=False)

[MobileOneBlock(  (se): Identity()  (activation): ReLU()  (rbr_conv): ModuleList(    (0-3): 4 x Sequential(      (conv): Conv2d(48, 48, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), groups=48, bias=False)      (bn): BatchNorm2d(48, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)    )  )  (rbr_scale): Sequential(    (conv): Conv2d(48, 48, kernel_size=(1, 1), stride=(2, 2), groups=48, bias=False)    (bn): BatchNorm2d(48, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)  ))]

[MobileOneBlock(  (se): Identity()  (activation): ReLU()  (rbr_conv): ModuleList(    (0-3): 4 x Sequential(      (conv): Conv2d(48, 48, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), groups=48, bias=False)      (bn): BatchNorm2d(48, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)    )  )  (rbr_scale): Sequential(    (conv): Conv2d(48, 48, kernel_size=(1, 1), stride=(2, 2), groups=48, bias=False)    (bn): BatchNorm2d(48, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)  )), MobileOneBlock(  (se): Identity()  (activation): ReLU()  (rbr_skip): BatchNorm2d(48, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)  (rbr_conv): ModuleList(    (0-3): 4 x Sequential(      (conv): Conv2d(48, 48, kernel_size=(1, 1), stride=(1, 1), bias=False)      (bn): BatchNorm2d(48, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)    )  ))]

[MobileOneBlock(  (se): Identity()  (activation): ReLU()  (rbr_conv): ModuleList(    (0-3): 4 x Sequential(      (conv): Conv2d(48, 48, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), groups=48, bias=False)      (bn): BatchNorm2d(48, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)    )  )  (rbr_scale): Sequential(    (conv): Conv2d(48, 48, kernel_size=(1, 1), stride=(2, 2), groups=48, bias=False)    (bn): BatchNorm2d(48, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)  )), MobileOneBlock(  (se): Identity()  (activation): ReLU()  (rbr_skip): BatchNorm2d(48, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)  (rbr_conv): ModuleList(    (0-3): 4 x Sequential(      (conv): Conv2d(48, 48, kernel_size=(1, 1), stride=(1, 1), bias=False)      (bn): BatchNorm2d(48, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)    )  )), MobileOneBlock(  (se): Identity()  (activation): ReLU()  (rbr_skip): BatchNorm2d(48, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)  (rbr_conv): ModuleList(    (0-3): 4 x Sequential(      (conv): Conv2d(48, 48, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), groups=48, bias=False)      (bn): BatchNorm2d(48, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)    )  )  (rbr_scale): Sequential(    (conv): Conv2d(48, 48, kernel_size=(1, 1), stride=(1, 1), groups=48, bias=False)    (bn): BatchNorm2d(48, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)  ))]

[MobileOneBlock(  (se): Identity()  (activation): ReLU()  (rbr_conv): ModuleList(    (0-3): 4 x Sequential(      (conv): Conv2d(48, 48, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), groups=48, bias=False)      (bn): BatchNorm2d(48, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)    )  )  (rbr_scale): Sequential(    (conv): Conv2d(48, 48, kernel_size=(1, 1), stride=(2, 2), groups=48, bias=False)    (bn): BatchNorm2d(48, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)  )), MobileOneBlock(  (se): Identity()  (activation): ReLU()  (rbr_skip): BatchNorm2d(48, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)  (rbr_conv): ModuleList(    (0-3): 4 x Sequential(      (conv): Conv2d(48, 48, kernel_size=(1, 1), stride=(1, 1), bias=False)      (bn): BatchNorm2d(48, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)    )  )), MobileOneBlock(  (se): Identity()  (activation): ReLU()  (rbr_skip): BatchNorm2d(48, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)  (rbr_conv): ModuleList(    (0-3): 4 x Sequential(      (conv): Conv2d(48, 48, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), groups=48, bias=False)      (bn): BatchNorm2d(48, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)    )  )  (rbr_scale): Sequential(    (conv): Conv2d(48, 48, kernel_size=(1, 1), stride=(1, 1), groups=48, bias=False)    (bn): BatchNorm2d(48, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)  )), MobileOneBlock(  (se): Identity()  (activation): ReLU()  (rbr_skip): BatchNorm2d(48, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)  (rbr_conv): ModuleList(    (0-3): 4 x Sequential(      (conv): Conv2d(48, 48, kernel_size=(1, 1), stride=(1, 1), bias=False)      (bn): BatchNorm2d(48, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)    )  ))]


def _to_str(size, suffixes, base):
    # type: (SupportsInt, Iterable[Text], int) -> Text
    try:
        size = int(size)
    except ValueError:
        raise TypeError("filesize requires a numeric value, not {!r}".format(size))
    if size == 1:
        return "1 byte"
    elif size < base:
        return "{:,} bytes".format(size)

    for i, suffix in enumerate(suffixes, 2):
        unit = base ** i
        if size < unit:
            break
    return "{:,.1f} {}".format((base * size / unit), suffix)

_to_str(size=1024, suffixes=('KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'), base=1024)


def _insert(self, key, value):
        flat_key = self._serialize_key(key)
        i = self._index.get(flat_key, -1)
        if i >= 0:
            self._items[i] = (key, value)
        else:
            self._items.append((key, value))
            self._index[flat_key] = len(self._items) - 1

_insert(self=OrderedMapSerializedKey([]), key='みbob', value=199)


def quat_from_axis_angle(axis, angle):
        axis_ = np.array(axis, dtype=np.float64)
        half_angle = angle * 0.5
        ret = np.empty(4)
        ret[0] = math.cos(half_angle)
        ret[1:4] = math.sin(half_angle) * axis_
        return ret

quat_from_axis_angle(axis=[1.0, 0.0, 0.0], angle=6.1086523819801535)


def base64url_decode(input: Union[bytes, str]) -> bytes:
    input_bytes = force_bytes(input)

    rem = len(input_bytes) % 4

    if rem > 0:
        input_bytes += b"=" * (4 - rem)

    return base64.urlsafe_b64decode(input_bytes)

base64url_decode(input='hJtXIZ2uSN5kbQfbtTNWbpdmhkV8FJG-Onbc6mxCcYg')


def generate_samples_loguniform(low, high, step, base, size=1):
    """Generate sample for (discrete)uniform density."""

    samples = base ** (random.uniform(low=logb(low, base), high=logb(high, base), size=size))
    if step:
        samples = step * np.floor(samples / step)
    return samples

generate_samples_loguniform(low=5.8884365535558836e-08, high=2.6977394324449206e-07, step=None, base=10, size=100000)


def parzen_estimator_build_posterior_parameter(parameter, observations):
    """TPE algorith transform a prior parameter into a posterior parameters using observations
    to build posterior.
    """
    posterior_parameter = None
    parameter_values = [observation.sample[parameter.name] for observation in observations]
    search_space = parameter.search_space
    if parameter.category == "categorical":
        """ TODO Compare mean (current implem) vs hyperopt approach."""
        prior_probabilities = np.array(search_space["probabilities"])
        posterior_probabilities = prior_probabilities
        if len(parameter_values) != 0:
            observed_probabilities = np.array([parameter_values.count(value)
                                               for value in search_space["values"]])
            observed_probabilities = observed_probabilities / np.sum(observed_probabilities)
            posterior_probabilities += observed_probabilities
        posterior_probabilities /= sum(posterior_probabilities)

        # Build param
        posterior_parameter = Parameter.from_dict(
            {
                "name": parameter.name,
                "category": "categorical",
                "search_space": {
                    "values": search_space["values"],
                    "probabilities": list(posterior_probabilities),
                }
            }
        )

    if parameter.category in ("uniform", "normal", "loguniform", "lognormal"):
        if parameter.category in ("uniform", "loguniform"):
            prior_mu = 0.5 * (search_space["high"] + search_space["low"])
            prior_sigma = (search_space["high"] - search_space["low"])
        elif parameter.category in ("normal", "lognormal"):
            prior_mu = search_space["mu"]
            prior_sigma = search_space["sigma"]

        # Mus
        mus = np.sort(parameter_values + [prior_mu])

        # Sigmas
        # Trick to get for each mu the greater distance from left and right neighbor
        # when low and high are not defined we use inf to get the only available distance
        # (right neighbor for sigmas[0] and left for sigmas[-1])
        tmp = np.concatenate(
            (
                [search_space.get("low", np.inf)],
                mus,
                [search_space.get("high", -np.inf)],
            )
        )
        sigmas = np.maximum(tmp[1:-1] - tmp[0:-2], tmp[2:] - tmp[1:-1])

        # Use formulas from hyperopt to clip sigmas
        sigma_max_value = prior_sigma
        sigma_min_value = prior_sigma / min(100.0, (1.0 + len(mus)))
        sigmas = np.clip(sigmas, sigma_min_value, sigma_max_value)

        # Fix prior sigma with correct value
        sigmas[np.where(mus == prior_mu)[0]] = prior_sigma

        posterior_parameter = Parameter.from_dict(
            {
                "name": parameter.name,
                "category": "mixture",
                "search_space": {
                    "parameters": [
                        {
                            "category": "normal",
                            "search_space": {
                                "mu": mu.tolist(),
                                "sigma": sigma.tolist(),
                                "low": search_space["low"],
                                "high": search_space["high"],
                                "step": search_space.get("step", None)
                            }
                        } if parameter.category[:3] != "log" else
                        {
                            "category": "lognormal",
                            "search_space": {
                                "mu": mu.tolist(),
                                "sigma": sigma.tolist(),
                                "low": search_space["low"],
                                "high": search_space["high"],
                                "step": search_space["step"],
                                "base": search_space["base"],
                            }
                        } for mu, sigma in zip(mus, sigmas)
                    ],
                    "weights": [1 / len(mus) for _ in range(len(mus))]
                }
            }
        )

    return posterior_parameter

parzen_estimator_build_posterior_parameter(parameter=x, observations=[])


def parse_route_template(template):
    rbuilder = ["^"]
    fbuilder = []
    position = 0
    schema = {}

    for match in template_var_re_finditer(template):
        param_name = match.group("name")
        param_type = match.group("type") or "id"
        # TODO: Handle KeyError, maybe we want to use a custom error here.
        param_formatchar, param_re, param_schema = _schema_map[param_type]
        schema[param_name] = param_schema

        rbuilder.append(re.escape(template[position:match.start()]))
        rbuilder.append(param_re.format(param_name))

        fbuilder.append(template[position:match.start()])
        fbuilder.append("{")
        fbuilder.append(param_name)
        fbuilder.append(":")
        fbuilder.append(param_formatchar)
        fbuilder.append("}")

        position = match.end()

    rbuilder.append(re.escape(template[position:]))
    rbuilder.append("$")
    fbuilder.append(template[position:])

    return (valid.Schema(schema),
            re.compile("".join(rbuilder)),
            u"".join(fbuilder).format)

parse_route_template(template='get/{variable}')

{'variable': And(<class 'str'>, <function Match at 0x7f0c58d64940>)}

<re.Match object; span=(4, 14), match='{variable}'>


def kilometers(meters=0, miles=0, feet=0, nautical=0):
    """
    Convert distance to kilometers.
    """
    ret = 0.
    if meters:
        ret += meters / 1000.
    if feet:
        ret += feet / ft(1.)
    if nautical:
        ret += nautical / nm(1.)
    ret += miles * 1.609344
    return ret

kilometers(meters=0, miles=0, feet=0, nautical=0)


def feet(kilometers=0, meters=0, miles=0, nautical=0):
    """
    Convert distance to feet.
    """
    ret = 0.
    if nautical:
        kilometers += nautical / nm(1.)
    if meters:
        kilometers += meters / 1000.
    if kilometers:
        miles += mi(kilometers=kilometers)
    ret += miles * 5280
    return ret

feet(kilometers=1.0, meters=0, miles=0, nautical=0)


def nautical(kilometers=0, meters=0, miles=0, feet=0):
    """
    Convert distance to nautical miles.
    """
    ret = 0.
    if feet:
        kilometers += feet / ft(1.)
    if miles:
        kilometers += km(miles=miles)
    if meters:
        kilometers += meters / 1000.
    ret += kilometers / 1.852
    return ret

nautical(kilometers=1.0, meters=0, miles=0, feet=0)


def format_decimal(self, altitude=None):
        """
        Format decimal degrees with altitude::

            >>> p = Point(41.5, -81.0, 12.3)
            >>> p.format_decimal()
            '41.5, -81.0, 12.3km'
            >>> p = Point(41.5, 0, 0)
            >>> p.format_decimal()
            '41.5, 0.0'

        :param bool altitude: Whether to include ``altitude`` value.
            By default it is automatically included if it is non-zero.
        """
        coordinates = [str(self.latitude), str(self.longitude)]

        if altitude is None:
            altitude = bool(self.altitude)
        if altitude:
            if not isinstance(altitude, str):
                altitude = 'km'
            coordinates.append(self.format_altitude(altitude))

        return ", ".join(coordinates)

format_decimal(self=Point(41.5, 81.0, 2.5), altitude=None, self.altitude=2.5, self.latitude=41.5, self.longitude=81.0)


def test_speech_extraction(sample_rate, start_seconds):
    parser = GenericSubtitleParser(start_seconds=start_seconds)
    extractor = SubtitleSpeechTransformer(
        sample_rate=sample_rate, start_seconds=start_seconds
    )
    pipe = make_pipeline(parser, extractor)
    bitstring = pipe.fit_transform(BytesIO(fake_srt)).astype(bool)
    bitstring_shifted_left = np.append(bitstring[1:], [False])
    bitstring_shifted_right = np.append([False], bitstring[:-1])
    bitstring_cumsum = np.cumsum(bitstring)
    consec_ones_end_pos = np.nonzero(
        bitstring_cumsum
        * (bitstring ^ bitstring_shifted_left)
        * (bitstring_cumsum != np.cumsum(bitstring_shifted_right))
    )[0]
    prev = 0
    for pos, sub in zip(consec_ones_end_pos, parser.subs_):
        start = int(round(sub.start.total_seconds() * sample_rate))
        duration = sub.end.total_seconds() - sub.start.total_seconds()
        stop = start + int(round(duration * sample_rate))
        assert bitstring_cumsum[pos] - prev == stop - start
        prev = bitstring_cumsum[pos]

test_speech_extraction(sample_rate=10, start_seconds=0)

{subs_=None, sub_format='srt', encoding='infer', caching=False, fit_fname=None, detected_encoding_=None, max_subtitle_seconds=None, start_seconds=0, _skip_ssa_info=False, _strict=False}

{subs_=<ffsubsync.generic_subtitles.GenericSubtitlesFile object at 0x7fb01543e5e0>, sub_format='srt', encoding='infer', caching=False, fit_fname=<_io.BytesIO object at 0x7fb014da3310>, detected_encoding_='ASCII', max_subtitle_seconds=None, start_seconds=0, _skip_ssa_info=False, _strict=False}

{sample_rate=10, start_seconds=0, framerate_ratio=1.0, subtitle_speech_results_=None, max_time_=None}

{steps=[('genericsubtitleparser', <ffsubsync.subtitle_parser.GenericSubtitleParser object at 0x7fb01543ef40>), ('subtitlespeechtransformer', <ffsubsync.speech_transformers.SubtitleSpeechTransformer object at 0x7fb01543e6a0>)], verbose=False}

array([False, False,  True,  True,  True,  True,  True,  True,  True,        True,  True,  True,  True,  True,  True,  True,  True,  True,        True,  True,  True,  True,  True,  True, False, False, False,       False,  True,  True,  True,  True,  True,  True,  True,  True,        True,  True,  True,  True,  True,  True,  True,  True,  True,       False, False,  True,  True,  True,  True,  True,  True,  True,        True,  True,  True,  True,  True,  True,  True, False])

array([False,  True,  True,  True,  True,  True,  True,  True,  True,        True,  True,  True,  True,  True,  True,  True,  True,  True,        True,  True,  True,  True,  True, False, False, False, False,        True,  True,  True,  True,  True,  True,  True,  True,  True,        True,  True,  True,  True,  True,  True,  True,  True, False,       False,  True,  True,  True,  True,  True,  True,  True,  True,        True,  True,  True,  True,  True,  True, False, False])

array([False, False, False,  True,  True,  True,  True,  True,  True,        True,  True,  True,  True,  True,  True,  True,  True,  True,        True,  True,  True,  True,  True,  True,  True, False, False,       False, False,  True,  True,  True,  True,  True,  True,  True,        True,  True,  True,  True,  True,  True,  True,  True,  True,        True, False, False,  True,  True,  True,  True,  True,  True,        True,  True,  True,  True,  True,  True,  True,  True])

{start=datetime.timedelta(microseconds=178000), end=datetime.timedelta(seconds=2, microseconds=416000), inner=Subtitle(index=1, start=datetime.timedelta(microseconds=178000), end=datetime.timedelta(seconds=2, microseconds=416000), content='<i>Previously on "Your favorite TV show..."</i>', proprietary='')}

{start=datetime.timedelta(seconds=2, microseconds=828000), end=datetime.timedelta(seconds=4, microseconds=549000), inner=Subtitle(index=2, start=datetime.timedelta(seconds=2, microseconds=828000), end=datetime.timedelta(seconds=4, microseconds=549000), content='Oh hi, Mark.', proprietary='')}

{start=datetime.timedelta(seconds=4, microseconds=653000), end=datetime.timedelta(seconds=6, microseconds=62000), inner=Subtitle(index=3, start=datetime.timedelta(seconds=4, microseconds=653000), end=datetime.timedelta(seconds=6, microseconds=62000), content='You are tearing me apart, Lisa!', proprietary='')}


def add_active_line_prints(code):
    """
    Add print statements indicating line numbers to a python string.
    """
    # Replace newlines and comments with pass statements, so the line numbers are accurate (ast will remove them otherwise)
    code_lines = code.split("\n")
    in_multiline_string = False
    for i in range(len(code_lines)):
        line = code_lines[i]
        if '"""' in line or "'''" in line:
            in_multiline_string = not in_multiline_string
        if not in_multiline_string and (line.strip().startswith("#") or line == ""):
            whitespace = len(line) - len(line.lstrip(" "))
            code_lines[i] = " " * whitespace + "pass"
    processed_code = "\n".join(code_lines)
    try:
        tree = ast.parse(processed_code)
    except:
        # If you can't parse the processed version, try the unprocessed version before giving up
        tree = ast.parse(code)
    transformer = AddLinePrints()
    new_tree = transformer.visit(tree)
    return ast.unparse(new_tree)

add_active_line_prints(code="import matplotlib\n        matplotlib.use('Agg')")

['import matplotlib', "        matplotlib.use('Agg')"]