def load_library():
    # note: for a mapping between bitcoin-core/secp256k1 git tags and .so.V libtool version numbers,
    #       see https://github.com/bitcoin-core/secp256k1/pull/1055#issuecomment-1227505189
    tested_libversions = [2, 1, 0, ]  # try latest version first
    libnames = []
    if sys.platform == 'darwin':
        for v in tested_libversions:
            libnames.append(f"libsecp256k1.{v}.dylib")
    elif sys.platform in ('windows', 'win32'):
        for v in tested_libversions:
            libnames.append(f"libsecp256k1-{v}.dll")
    elif 'ANDROID_DATA' in os.environ:
        libnames = ['libsecp256k1.so', ]  # don't care about version number. we built w/e is available.
    else:  # desktop Linux and similar
        for v in tested_libversions:
            libnames.append(f"libsecp256k1.so.{v}")
        # maybe we could fall back to trying "any" version? maybe guarded with an env var?
        #libnames.append(f"libsecp256k1.so")
    library_paths = []
    for libname in libnames:  # try local files in repo dir first
        library_paths.append(os.path.join(os.path.dirname(__file__), libname))
    for libname in libnames:
        library_paths.append(libname)

    exceptions = []
    secp256k1 = None
    for libpath in library_paths:
        try:
            secp256k1 = ctypes.cdll.LoadLibrary(libpath)
        except BaseException as e:
            exceptions.append(e)
        else:
            break
    if not secp256k1:
        _logger.error(f'libsecp256k1 library failed to load. exceptions: {repr(exceptions)}')
        return None

    try:
        secp256k1.secp256k1_context_create.argtypes = [c_uint]
        secp256k1.secp256k1_context_create.restype = c_void_p

        secp256k1.secp256k1_context_randomize.argtypes = [c_void_p, c_char_p]
        secp256k1.secp256k1_context_randomize.restype = c_int

        secp256k1.secp256k1_ec_pubkey_create.argtypes = [c_void_p, c_void_p, c_char_p]
        secp256k1.secp256k1_ec_pubkey_create.restype = c_int

        secp256k1.secp256k1_ecdsa_sign.argtypes = [c_void_p, c_char_p, c_char_p, c_char_p, c_void_p, c_void_p]
        secp256k1.secp256k1_ecdsa_sign.restype = c_int

        secp256k1.secp256k1_ecdsa_verify.argtypes = [c_void_p, c_char_p, c_char_p, c_char_p]
        secp256k1.secp256k1_ecdsa_verify.restype = c_int

        secp256k1.secp256k1_ec_pubkey_parse.argtypes = [c_void_p, c_char_p, c_char_p, c_size_t]
        secp256k1.secp256k1_ec_pubkey_parse.restype = c_int

        secp256k1.secp256k1_ec_pubkey_serialize.argtypes = [c_void_p, c_char_p, c_void_p, c_char_p, c_uint]
        secp256k1.secp256k1_ec_pubkey_serialize.restype = c_int

        secp256k1.secp256k1_ecdsa_signature_parse_compact.argtypes = [c_void_p, c_char_p, c_char_p]
        secp256k1.secp256k1_ecdsa_signature_parse_compact.restype = c_int

        secp256k1.secp256k1_ecdsa_signature_normalize.argtypes = [c_void_p, c_char_p, c_char_p]
        secp256k1.secp256k1_ecdsa_signature_normalize.restype = c_int

        secp256k1.secp256k1_ecdsa_signature_serialize_compact.argtypes = [c_void_p, c_char_p, c_char_p]
        secp256k1.secp256k1_ecdsa_signature_serialize_compact.restype = c_int

        secp256k1.secp256k1_ecdsa_signature_parse_der.argtypes = [c_void_p, c_char_p, c_char_p, c_size_t]
        secp256k1.secp256k1_ecdsa_signature_parse_der.restype = c_int

        secp256k1.secp256k1_ecdsa_signature_serialize_der.argtypes = [c_void_p, c_char_p, c_void_p, c_char_p]
        secp256k1.secp256k1_ecdsa_signature_serialize_der.restype = c_int

        secp256k1.secp256k1_ec_pubkey_tweak_mul.argtypes = [c_void_p, c_char_p, c_char_p]
        secp256k1.secp256k1_ec_pubkey_tweak_mul.restype = c_int

        secp256k1.secp256k1_ec_pubkey_combine.argtypes = [c_void_p, c_char_p, c_void_p, c_size_t]
        secp256k1.secp256k1_ec_pubkey_combine.restype = c_int

        # --enable-module-recovery
        try:
            secp256k1.secp256k1_ecdsa_recover.argtypes = [c_void_p, c_char_p, c_char_p, c_char_p]
            secp256k1.secp256k1_ecdsa_recover.restype = c_int

            secp256k1.secp256k1_ecdsa_recoverable_signature_parse_compact.argtypes = [c_void_p, c_char_p, c_char_p, c_int]
            secp256k1.secp256k1_ecdsa_recoverable_signature_parse_compact.restype = c_int
        except (OSError, AttributeError):
            raise LibModuleMissing('libsecp256k1 library found but it was built '
                                   'without required module (--enable-module-recovery)')

        secp256k1.ctx = secp256k1.secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY)
        ret = secp256k1.secp256k1_context_randomize(secp256k1.ctx, os.urandom(32))
        if not ret:
            _logger.error('secp256k1_context_randomize failed')
            return None

        return secp256k1
    except (OSError, AttributeError) as e:
        _logger.error(f'libsecp256k1 library was found and loaded but there was an error when using it: {repr(e)}')
        return None

load_library()

[OSError('/local/rcs/jinjun/code/pytrace-collector/logs/self_collected/tried/spesmilo+electrum/spesmilo+electrum/electrum/libsecp256k1.so.2: cannot open shared object file: No such file or directory')]

[OSError('/local/rcs/jinjun/code/pytrace-collector/logs/self_collected/tried/spesmilo+electrum/spesmilo+electrum/electrum/libsecp256k1.so.2: cannot open shared object file: No such file or directory'), OSError('/local/rcs/jinjun/code/pytrace-collector/logs/self_collected/tried/spesmilo+electrum/spesmilo+electrum/electrum/libsecp256k1.so.1: cannot open shared object file: No such file or directory')]

[OSError('/local/rcs/jinjun/code/pytrace-collector/logs/self_collected/tried/spesmilo+electrum/spesmilo+electrum/electrum/libsecp256k1.so.2: cannot open shared object file: No such file or directory'), OSError('/local/rcs/jinjun/code/pytrace-collector/logs/self_collected/tried/spesmilo+electrum/spesmilo+electrum/electrum/libsecp256k1.so.1: cannot open shared object file: No such file or directory'), OSError('/local/rcs/jinjun/code/pytrace-collector/logs/self_collected/tried/spesmilo+electrum/spesmilo+electrum/electrum/libsecp256k1.so.0: cannot open shared object file: No such file or directory')]

[OSError('/local/rcs/jinjun/code/pytrace-collector/logs/self_collected/tried/spesmilo+electrum/spesmilo+electrum/electrum/libsecp256k1.so.2: cannot open shared object file: No such file or directory'), OSError('/local/rcs/jinjun/code/pytrace-collector/logs/self_collected/tried/spesmilo+electrum/spesmilo+electrum/electrum/libsecp256k1.so.1: cannot open shared object file: No such file or directory'), OSError('/local/rcs/jinjun/code/pytrace-collector/logs/self_collected/tried/spesmilo+electrum/spesmilo+electrum/electrum/libsecp256k1.so.0: cannot open shared object file: No such file or directory'), OSError('libsecp256k1.so.2: cannot open shared object file: No such file or directory')]

[OSError('/local/rcs/jinjun/code/pytrace-collector/logs/self_collected/tried/spesmilo+electrum/spesmilo+electrum/electrum/libsecp256k1.so.2: cannot open shared object file: No such file or directory'), OSError('/local/rcs/jinjun/code/pytrace-collector/logs/self_collected/tried/spesmilo+electrum/spesmilo+electrum/electrum/libsecp256k1.so.1: cannot open shared object file: No such file or directory'), OSError('/local/rcs/jinjun/code/pytrace-collector/logs/self_collected/tried/spesmilo+electrum/spesmilo+electrum/electrum/libsecp256k1.so.0: cannot open shared object file: No such file or directory'), OSError('libsecp256k1.so.2: cannot open shared object file: No such file or directory'), OSError('libsecp256k1.so.1: cannot open shared object file: No such file or directory')]

[OSError('/local/rcs/jinjun/code/pytrace-collector/logs/self_collected/tried/spesmilo+electrum/spesmilo+electrum/electrum/libsecp256k1.so.2: cannot open shared object file: No such file or directory'), OSError('/local/rcs/jinjun/code/pytrace-collector/logs/self_collected/tried/spesmilo+electrum/spesmilo+electrum/electrum/libsecp256k1.so.1: cannot open shared object file: No such file or directory'), OSError('/local/rcs/jinjun/code/pytrace-collector/logs/self_collected/tried/spesmilo+electrum/spesmilo+electrum/electrum/libsecp256k1.so.0: cannot open shared object file: No such file or directory'), OSError('libsecp256k1.so.2: cannot open shared object file: No such file or directory'), OSError('libsecp256k1.so.1: cannot open shared object file: No such file or directory'), OSError('libsecp256k1.so.0: cannot open shared object file: No such file or directory')]


def driver():
    TEST_BROWSER = os.environ.get("TEST_BROWSER", "chrome").lower()

    if TEST_BROWSER == "chrome":
        options = webdriver.ChromeOptions()
        options.headless = True
        capabilities = DesiredCapabilities.CHROME
        capabilities["goog:loggingPrefs"] = {"browser": "ALL"}

        if platform.system() == "Windows":
            options.binary_location = "C:/Program Files/Google/Chrome/Application/chrome.exe"

        driver = webdriver.Chrome(
            ChromeDriverManager().install(),
            options=options,
            desired_capabilities=capabilities,
            service_log_path=os.path.devnull,
        )

    # Firefox doesn't currently supported pulling JavaScript console logs, which we currently scan to affirm that
    # JS/Python can communicate in some places. So for now, we can't really use firefox/geckodriver during testing.
    # This may be added in the future: https://github.com/mozilla/geckodriver/issues/284

    # elif TEST_BROWSER == "firefox":
    #     options = webdriver.FirefoxOptions()
    #     options.headless = True
    #     capabilities = DesiredCapabilities.FIREFOX
    #     capabilities['loggingPrefs'] = {"browser": "ALL"}
    #
    #     driver = webdriver.Firefox(options=options, capabilities=capabilities, service_log_path=os.path.devnull)

    else:
        raise ValueError(f"Unsupported browser for testing: {TEST_BROWSER}")

    with mock.patch("eel.browsers.open"):
        yield driver

driver()

{_caps={'browserName': 'chrome', 'goog:loggingPrefs': {'browser': 'ALL'}, 'pageLoadStrategy': <PageLoadStrategy.normal: 'normal'>}, _proxy=None, mobile_options=None, _arguments=[], _ignore_local_proxy=False, _binary_location='', _extension_files=[], _extensions=[], _experimental_options={}, _debugger_address=None}

{_caps={'browserName': 'chrome', 'goog:loggingPrefs': {'browser': 'ALL'}, 'pageLoadStrategy': <PageLoadStrategy.normal: 'normal'>}, _proxy=None, mobile_options=None, _arguments=[], _ignore_local_proxy=False, _binary_location='', _extension_files=[], _extensions=[], _experimental_options={}, _debugger_address=None, headless=True}

{'browserName': 'chrome', 'goog:loggingPrefs': {'browser': 'ALL'}}


def find_csv_separators(csv):
    """Finds column and decimal separators in a CSV string

    Args:
        csv: CSV text data

    Returns:
        (column_separator, decimal separator)
    """
    lines = csv.strip().split('\n')
    # First find all potential column separators by checking which characters appear on each line that starts with digit
    column_separator_candidates = {',', ';', '\t', '|'}
    for line in lines:
        if not numeric_start.match(line):  # Skip rows which don't start with numbers
            continue
        remove_candidates = []
        for column_separator in column_separator_candidates:
            if column_separator not in line:
                # Numeric line doesn't contain the column separator candidate, eliminate the candidate
                remove_candidates.append(column_separator)
        for remove_candidate in remove_candidates:
            column_separator_candidates.remove(remove_candidate)

    if len(column_separator_candidates) == 0:
        raise CsvParseError('Could not find column and decimal separators')

    if column_separator_candidates == {','}:
        # Only comma found, it must be the column separator and decimal point must be dot
        return [',', '.']

    if ',' in column_separator_candidates:
        # Comma is included in the candidates (along with something else), it must be the decimal separator
        decimal_separator = ','
        column_separator_candidates.remove(',')
    else:
        decimal_separator = '.'

    if len(column_separator_candidates) > 1:
        raise CsvParseError(f'Found multiple potential column separators: {column_separator_candidates}')

    return list(column_separator_candidates)[0], decimal_separator

find_csv_separators(csv='frequency,raw\n20,0\n1000,3\n20000,0\n')


def partition(a, lo, hi):
        i = lo
        j = hi

        while True:
            while not util.less(a[lo], a[i]):
                i += 1
                if i >= hi:
                    break

            while util.less(a[lo], a[j]):
                j -= 1
                if j <= lo:
                    break

            if i >= j:
                break

            util.exchange(a, i, j)

        util.exchange(a, lo, j)
        return j

partition(a=[4, 2, 1, 23, 4, 5, 6, 7, 8, 9, 20, 11, 13, 34, 66], lo=0, hi=14)


def version_compare(self, other):
        "Compares version of the form [epoch:]upstream-version[-debian-revision]" \
        + " according to Debian package version number format."

        # compare epoch
        diff = self.epoch - other.epoch
        if diff != 0:
            return diff

        # compare upstream version and debian revision
        for slf, othr in (self.upstream_version, other.upstream_version), (self.revision, other.revision):
            i = 0
            while len(slf) > 0 or len(othr) > 0:
                decimal = (i % 2 == 1)
                slf_part, slf = self._get_part(slf, decimal=decimal)
                othr_part, othr = self._get_part(othr, decimal=decimal)
                diff = self._compare_parts(slf_part, othr_part, decimal=decimal)
                if diff != 0:
                    return diff
                i += 1

        # versions are equal
        return 0

version_compare(self=2.2.0~rc5, other=2.2.0~rc5, self.epoch=0, self.revision='0', self.revision_allowed_chars=('.', '+', '~'), self.upstream_version='2.2.0~rc5', self.upstream_version_allowed_chars=('.', '+', '~', '-', ':'), self.version='2.2.0~rc5')


def _get_part(self, s, decimal):
        "Strips first part of string containing either non-decimal or decimal characters." \
        + " Returns tuple (part, remider)."
        div = 0
        for c in s:
            if decimal and not c.isdecimal():
                break
            elif not decimal and c.isdecimal():
                break
            else:
                div += 1

        return (s[:div], s[div:])

_get_part(self=2.2.0~rc5, s='2.2.0~rc5', decimal=False, self.epoch=0, self.revision='0', self.revision_allowed_chars=('.', '+', '~'), self.upstream_version='2.2.0~rc5', self.upstream_version_allowed_chars=('.', '+', '~', '-', ':'), self.version='2.2.0~rc5')


def _compare_parts(self, a, b, decimal):
        if decimal:
            if a == "": a = "0"
            if b == "": b = "0"
            return int(a) - int(b)
        else:
            i = 0
            while i < (min(len(a), len(b)) + 1):
                res = self._order(self._get_empty_str_on_index_error(a, i)) \
                        - self._order(self._get_empty_str_on_index_error(b, i))
                if res != 0:
                    return res
                i += 1
            else:
                return 0

_compare_parts(self=2.2.0~rc5, a='', b='', decimal=False, self.epoch=0, self.revision='0', self.revision_allowed_chars=('.', '+', '~'), self.upstream_version='2.2.0~rc5', self.upstream_version_allowed_chars=('.', '+', '~', '-', ':'), self.version='2.2.0~rc5')


def static_bool_env(varname: str, default: bool) -> bool:
  """Read an environment variable and interpret it as a boolean.

  This is deprecated. Please use bool_flag() unless your flag
  will be used in a static method and does not require runtime updates.

  True values are (case insensitive): 'y', 'yes', 't', 'true', 'on', and '1';
  false values are 'n', 'no', 'f', 'false', 'off', and '0'.
  Args:
    varname: the name of the variable
    default: the default boolean value
  Returns:
    boolean return value derived from defaults and environment.
  Raises: ValueError if the environment variable is anything else.
  """
  val = os.getenv(varname, str(default))
  val = val.lower()
  if val in ('y', 'yes', 't', 'true', 'on', '1'):
    return True
  elif val in ('n', 'no', 'f', 'false', 'off', '0'):
    return False
  else:
    raise ValueError(
      'invalid truth value {!r} for environment {!r}'.format(val, varname)
    )

static_bool_env(varname='FLAX_LAZY_RNG', default=True)


def _copy(src, dst, src_is_storage, dst_is_storage):
    """
    Copies file from source to destination

    Args:
        src (str or file-like object): Source file.
        dst (str or file-like object): Destination file.
        src_is_storage (bool): Source is storage.
        dst_is_storage (bool): Destination is storage.
    """
    # If both storage: Tries to perform same storage direct copy
    if src_is_storage and dst_is_storage:
        system = get_instance(src)
        if system is get_instance(dst):

            # Checks if same file
            if system.relpath(src) == system.relpath(dst):
                raise same_file_error(
                    "'%s' and '%s' are the same file" % (src, dst))

            # Tries to copy
            try:
                return system.copy(src, dst)
            except (UnsupportedOperation, ObjectException):
                pass

    # At least one storage object: copies streams
    with cos_open(src, 'rb') as fsrc:
        with cos_open(dst, 'wb') as fdst:

            # Get stream buffer size
            for stream in (fdst, fsrc):
                try:
                    buffer_size = getattr(stream, '_buffer_size')
                    break
                except AttributeError:
                    continue
            else:
                buffer_size = 16384

            # Read and write
            copyfileobj(fsrc, fdst, buffer_size)

_copy(src='dummy_read://file.txt', dst='/tmp/pytest-of-jinjun/pytest-198/test_cos_open0/file_dst.txt', src_is_storage=True, dst_is_storage=False)


def get_logger_name(context=None):
        log_names = [root_logger_name, logger_name]

        if context is not None:
            log_names.insert(1,
                             context if isinstance(context,
                                                   string_types) else context.__class__.__name__)

        return '.'.join(log_names)

get_logger_name(context=None, logger_name='State')


def _setHeaderBaseData(array, coeff_name, hao, long_name) -> None:
        if not isinstance(array, (np.ndarray, np.float32, np.int32,np.float64)):
            print(type(array))
            raise HeaderArrayObj.UnsupportedArrayType("'array' must be of numpy.ndarray type.")

        # Defaults handling
        if coeff_name is None:
            coeff_name = " " * 12
        if long_name is None:
            long_name = coeff_name
        if len(coeff_name) < 12:
            coeff_name = coeff_name.ljust(12)
        if len(long_name) < 70:
            long_name = long_name.ljust(70)
        hao.array = array
        hao.coeff_name = coeff_name
        hao.long_name = long_name

_setHeaderBaseData(array=array(['at 2/03/2018 4:22:38 PM                                               '],      dtype='<U70'), coeff_name=None, hao={_coeff_name='', _array=None, _sets=None, _long_name=''}, long_name='Creation Date and Time                                                ')

'Creation Date and Time                                                '

{_coeff_name='            ', _array=array(['at 2/03/2018 4:22:38 PM                                               '],      dtype='<U70'), _sets=None, _long_name='Creation Date and Time                                                '}


def make_input_stream(input, charset):
    # Is already an input stream.
    if hasattr(input, 'read'):
        if PY2:
            return input
        rv = _find_binary_reader(input)
        if rv is not None:
            return rv
        raise TypeError('Could not find binary reader for input stream.')

    if input is None:
        input = b''
    elif not isinstance(input, bytes):
        input = input.encode(charset)
    if PY2:
        return StringIO(input)
    return io.BytesIO(input)

make_input_stream(input=None, charset='utf-8')

Input: b''


def _fetch(c):
        try:
            if spos is None:
                return c.popleft()
            else:
                return c.pop()
        except IndexError:
            return None

_fetch(c=deque([-1, 1]), spos=None)


def _build_prompt(text, suffix, show_default=False, default=None):
    prompt = text
    if default is not None and show_default:
        prompt = '%s [%s]' % (prompt, default)
    return prompt + suffix

_build_prompt(text='Foo', suffix=': ', show_default=True, default=None)

'Foo'

'Foo'

Prompt: 'Foo'


def parse_array(data, start=0):
    endcnt = data.find(CRLF, start + 1)

    if endcnt == -1:
        raise ParseError("Unterminated array element count after pos {}.".format(start + 1))

    try:
        count = int(data[start + 1:endcnt])
    except (ValueError, TypeError):
        raise ParseError("Invalid array element count at pos {} - {}.".format(start + 1, endcnt))

    start = endcnt + CRLFLEN

    if count == -1:
        return None, endcnt

    result = []

    for i in range(count):
        if start + 4 < len(data):
            obj, start = _decode(data, start)
            result.append(obj)
        else:
            raise ParseError("Unterminated array element at pos {}".format(start))

    return result, start

parse_array(data='*3\r\n$3\r\nSET\r\n$15\r\nmemtier-8232902\r\n$2\r\nxx\r\n*3\r\n$3\r\nSET\r\n$15\r\nmemtier-8232902\r\n$2\r\nxx\r\n*3\r\n$3\r\nSET\r\n$15\r\nmemtier-7630684\r\n$3\r\nAAA\r\n', start=0)


def elapsed_text(seconds, precise, prefix=''):
    seconds = round(seconds, 1 if precise else 0)
    if seconds < 60.:
        return '{}{:{}f}s'.format(prefix, seconds, .1 if precise else .0)

    minutes, seconds = divmod(seconds, 60.)
    if minutes < 60.:
        return '{}{:.0f}:{:0{}f}'.format(prefix, minutes, seconds, 4.1 if precise else 2.0)

    hours, minutes = divmod(minutes, 60.)
    return '{}{:.0f}:{:02.0f}:{:0{}f}'.format(prefix, hours, minutes, seconds,
                                              4.1 if precise else 2.0)

elapsed_text(seconds=1.23, precise=True, prefix='')


def mknode(id=None, ip=None, port=None, intid=None):
    """
    Make a node.  Created a random id if not specified.
    """
    if intid is not None:
        id = pack('>l', intid)
    id = id or hashlib.sha1(str(random.getrandbits(255))).digest()
    return Node(id, ip, port)

mknode(id=None, ip=None, port=None, intid=0)


def strtobool(val):
    """Convert a string representation of truth to true (1) or false (0).

    True values are 'y', 'yes', 't', 'true', 'on', and '1'; false values
    are 'n', 'no', 'f', 'false', 'off', and '0'.  Raises ValueError if
    'val' is anything else.
    """
    val = val.lower()
    if val in ('y', 'yes', 't', 'true', 'on', '1'):
        return 1
    if val in ('n', 'no', 'f', 'false', 'off', '0'):
        return 0
    raise ValueError(f"invalid truth value {val!r}")

strtobool(val='False')


def stringified_dict_contains_value(key, value, str_dict):
    """Checks if dict in for of string like "{'test': 5}" contains
    key/value pair. This works faster, then creating actual dict
    from string since this operation is called for each task in case
    of kwargs search."""
    if not str_dict:
        return False
    value = str(value)
    try:
        # + 3 for key right quote, one for colon and one for space
        key_index = str_dict.index(key) + len(key) + 3
    except ValueError:
        return False
    try:
        comma_index = str_dict.index(',', key_index)
    except ValueError:
        # last value in dict
        comma_index = str_dict.index('}', key_index)
    return str(value) == str_dict[key_index:comma_index].strip('"\'')

stringified_dict_contains_value(key='test', value=5, str_dict="{'test': 5}")


def authenticate(pattern, email):
    if '|' in pattern:
        return email in pattern.split('|')
    if '*' in pattern:
        pattern = re.escape(pattern).replace(r'\.\*', r"[A-Za-z0-9!#$%&'*+/=?^_`{|}~.\-]*")
        return re.fullmatch(pattern, email)
    return pattern == email

authenticate(pattern='.*@example.com', email='one@example.com')


def to_tuple(param, low=None, bias=None):
    """Convert input argument to min-max tuple
    Args:
        param (scalar, tuple or list of 2+ elements): Input value.
            If value is scalar, return value would be (offset - value, offset + value).
            If value is tuple, return value would be value + offset (broadcasted).
        low:  Second element of tuple can be passed as optional argument
        bias: An offset factor added to each element
    """
    if low is not None and bias is not None:
        raise ValueError("Arguments low and bias are mutually exclusive")

    if param is None:
        return param

    if isinstance(param, (int, float)):
        if low is None:
            param = -param, +param
        else:
            param = (low, param) if low < param else (param, low)
    elif isinstance(param, Sequence):
        if len(param) != 2:
            raise ValueError("to_tuple expects 1 or 2 values")
        param = tuple(param)
    else:
        raise ValueError("Argument param must be either scalar (int, float) or tuple")

    if bias is not None:
        return tuple(bias + x for x in param)

    return tuple(param)

to_tuple(param=7, low=3, bias=None)


def file(input_file, light=False):
    """Import colorscheme from json file."""
    util.create_dir(os.path.join(CONF_DIR, "colorschemes/light/"))
    util.create_dir(os.path.join(CONF_DIR, "colorschemes/dark/"))

    theme_name = ".".join((input_file, "json"))
    bri = "light" if light else "dark"

    user_theme_file = os.path.join(CONF_DIR, "colorschemes", bri, theme_name)
    theme_file = os.path.join(MODULE_DIR, "colorschemes", bri, theme_name)

    # Find the theme file.
    if input_file in ("random", "random_dark"):
        theme_file = get_random_theme()

    elif input_file == "random_light":
        theme_file = get_random_theme(light)

    elif input_file == "random_user":
        theme_file = get_random_theme_user()

    elif os.path.isfile(user_theme_file):
        theme_file = user_theme_file

    elif os.path.isfile(input_file):
        theme_file = input_file

    # Parse the theme file.
    if os.path.isfile(theme_file):
        logging.info("Set theme to \033[1;37m%s\033[0m.",
                     os.path.basename(theme_file))
        util.save_file(os.path.basename(theme_file),
                       os.path.join(CACHE_DIR, "last_used_theme"))
        return parse(theme_file)

    logging.error("No %s colorscheme file found.", bri)
    logging.error("Try adding   '-l' to set light themes.")
    logging.error("Try removing '-l' to set dark themes.")
    sys.exit(1)

file(input_file='tests/test_files/test_file.json', light=False)


def parse(theme_file):
    """Parse the theme file."""
    data = util.read_file_json(theme_file)

    if "wallpaper" not in data:
        data["wallpaper"] = "None"

    if "alpha" not in data:
        data["alpha"] = util.Color.alpha_num

    # Terminal.sexy format.
    if "color" in data:
        data = terminal_sexy_to_wal(data)

    return data

parse(theme_file='tests/test_files/test_file.json')


def _keep_only_referenced_tex(contents, splits):
  """Returns the filenames referenced from the tex files themselves.

  It needs various iterations in case one file is referenced from an
  unreferenced file.
  """
  old_referenced = set(splits['tex_in_root'] + splits['tex_not_in_root'])
  while True:
    referenced = set(splits['tex_in_root'])
    for fn in old_referenced:
      for fn2 in old_referenced:
        if regex.search(
            r'(' + os.path.splitext(fn)[0] + r'[.}])', '\n'.join(contents[fn2])
        ):
          referenced.add(fn)

    if referenced == old_referenced:
      splits['tex_to_copy'] = list(referenced)
      return

    old_referenced = referenced.copy()

_keep_only_referenced_tex(contents={'main.tex': ['\\begin{document}', 'Text', '', 'Text%', '', '', 'This is a percent \\%.', '\\includegraphics{images/im1_included.png}', '\\includegraphics{images/im3_included.png}', '\\includegraphics{%', '  images/im4_included.png%', '  }', '\\includegraphics[width=.5\\linewidth]{%', '  images/im5_included.jpg}', '', '\\includegraphics{./images/im3_included.png}', '', 'This line should not be separated', '%', 'from this one.', '', '', '', '\\newif\\ifvar', '', '\\ifvar', '\\fi', '', '\\newcommand{\\red}[1]{{\\color{red} #1}}', 'hello test hello', 'test hello', 'test', '', '', '\\input{figures/figure_included.tex}', '', '\\includegraphics{ext_tikz/test1.pdf}', '', '\\input{figures/figure_included.tikz}', '', '\\begin{tikzpicture}', '    \\node (test) at (0,0) {Test3};', '\\end{tikzpicture}', '', '\\tikzsetnextfilename{test_no_match}', '\\begin{tikzpicture}', '    \\node (test) at (0,0) {Test4};', '\\end{tikzpicture}', '', '\\end{document}', ''], 'figures/figure_not_included.tex': ['\\addplot{figures/data_not_included.txt}', '\\input{figures/figure_not_included_2.tex}', ''], 'figures/figure_not_included_2.tex': [''], 'figures/figure_included.tikz': ['\ufeff\\includegraphics{ext_tikz/test2.pdf}', ''], 'figures/figure_included.tex': ['\\includegraphics{images/im2_included.jpg}', '\\addplot{figures/data_included.txt}', '']}, splits={'all': ['main.bib', 'main.bbl', 'main.tex', 'main.aux', 'ext_tikz/test2.pdf', 'ext_tikz/test1.pdf', 'ext_tikz/figure_not_included.pdf', 'figures/data_not_included.txt', 'figures/figure_not_included.tex', 'figures/figure_not_included_2.tex', 'figures/figure_included.tikz', 'figures/figure_included.tex', 'figures/data_included.txt', 'not_included/figures/data_included.txt', 'images/im4_included.png', 'images/im1.png', 'images/im4_not_included.png', 'images/im3_included.png', 'images/im2_included.jpg', 'images/im5_not_included.jpg', 'images/im5_included.jpg', 'images/im1_included.png', 'images/im_not_included.png', 'images/include/images/im3_included.png'], 'in_root': ['main.bib', 'main.bbl', 'main.tex', 'main.aux'], 'not_in_root': ['ext_tikz/test2.pdf', 'ext_tikz/test1.pdf', 'ext_tikz/figure_not_included.pdf', 'figures/data_not_included.txt', 'figures/figure_not_included.tex', 'figures/figure_not_included_2.tex', 'figures/figure_included.tikz', 'figures/figure_included.tex', 'figures/data_included.txt', 'not_included/figures/data_included.txt', 'images/im4_included.png', 'images/im1.png', 'images/im4_not_included.png', 'images/im3_included.png', 'images/im2_included.jpg', 'images/im5_not_included.jpg', 'images/im5_included.jpg', 'images/im1_included.png', 'images/im_not_included.png', 'images/include/images/im3_included.png'], 'to_copy_in_root': ['main.bbl', 'main.tex'], 'to_copy_not_in_root': ['figures/data_not_included.txt', 'figures/figure_not_included.tex', 'figures/figure_not_included_2.tex', 'figures/figure_included.tikz', 'figures/figure_included.tex', 'figures/data_included.txt', 'not_included/figures/data_included.txt'], 'figures': ['ext_tikz/test2.pdf', 'ext_tikz/test1.pdf', 'ext_tikz/figure_not_included.pdf', 'images/im4_included.png', 'images/im1.png', 'images/im4_not_included.png', 'images/im3_included.png', 'images/im2_included.jpg', 'images/im5_not_included.jpg', 'images/im5_included.jpg', 'images/im1_included.png', 'images/im_not_included.png', 'images/include/images/im3_included.png'], 'tex_in_root': ['main.tex'], 'tex_not_in_root': ['figures/figure_not_included.tex', 'figures/figure_not_included_2.tex', 'figures/figure_included.tikz', 'figures/figure_included.tex'], 'non_tex_in_root': ['main.bbl'], 'non_tex_not_in_root': ['figures/data_not_included.txt', 'figures/data_included.txt', 'not_included/figures/data_included.txt'], 'external_tikz_figures': ['ext_tikz/test2.pdf', 'ext_tikz/test1.pdf', 'ext_tikz/figure_not_included.pdf'], 'svg_inkscape': []})

{'figures/figure_included.tex', 'figures/figure_not_included.tex', 'figures/figure_included.tikz', 'main.tex', 'figures/figure_not_included_2.tex'}

{'all': ['main.bib', 'main.bbl', 'main.tex', 'main.aux', 'ext_tikz/test2.pdf', 'ext_tikz/test1.pdf', 'ext_tikz/figure_not_included.pdf', 'figures/data_not_included.txt', 'figures/figure_not_included.tex', 'figures/figure_not_included_2.tex', 'figures/figure_included.tikz', 'figures/figure_included.tex', 'figures/data_included.txt', 'not_included/figures/data_included.txt', 'images/im4_included.png', 'images/im1.png', 'images/im4_not_included.png', 'images/im3_included.png', 'images/im2_included.jpg', 'images/im5_not_included.jpg', 'images/im5_included.jpg', 'images/im1_included.png', 'images/im_not_included.png', 'images/include/images/im3_included.png'], 'in_root': ['main.bib', 'main.bbl', 'main.tex', 'main.aux'], 'not_in_root': ['ext_tikz/test2.pdf', 'ext_tikz/test1.pdf', 'ext_tikz/figure_not_included.pdf', 'figures/data_not_included.txt', 'figures/figure_not_included.tex', 'figures/figure_not_included_2.tex', 'figures/figure_included.tikz', 'figures/figure_included.tex', 'figures/data_included.txt', 'not_included/figures/data_included.txt', 'images/im4_included.png', 'images/im1.png', 'images/im4_not_included.png', 'images/im3_included.png', 'images/im2_included.jpg', 'images/im5_not_included.jpg', 'images/im5_included.jpg', 'images/im1_included.png', 'images/im_not_included.png', 'images/include/images/im3_included.png'], 'to_copy_in_root': ['main.bbl', 'main.tex'], 'to_copy_not_in_root': ['figures/data_not_included.txt', 'figures/figure_not_included.tex', 'figures/figure_not_included_2.tex', 'figures/figure_included.tikz', 'figures/figure_included.tex', 'figures/data_included.txt', 'not_included/figures/data_included.txt'], 'figures': ['ext_tikz/test2.pdf', 'ext_tikz/test1.pdf', 'ext_tikz/figure_not_included.pdf', 'images/im4_included.png', 'images/im1.png', 'images/im4_not_included.png', 'images/im3_included.png', 'images/im2_included.jpg', 'images/im5_not_included.jpg', 'images/im5_included.jpg', 'images/im1_included.png', 'images/im_not_included.png', 'images/include/images/im3_included.png'], 'tex_in_root': ['main.tex'], 'tex_not_in_root': ['figures/figure_not_included.tex', 'figures/figure_not_included_2.tex', 'figures/figure_included.tikz', 'figures/figure_included.tex'], 'non_tex_in_root': ['main.bbl'], 'non_tex_not_in_root': ['figures/data_not_included.txt', 'figures/data_included.txt', 'not_included/figures/data_included.txt'], 'external_tikz_figures': ['ext_tikz/test2.pdf', 'ext_tikz/test1.pdf', 'ext_tikz/figure_not_included.pdf'], 'svg_inkscape': [], 'tex_to_copy': ['figures/figure_included.tex', 'figures/figure_included.tikz', 'main.tex']}

{'figures/figure_included.tex', 'figures/figure_included.tikz', 'main.tex', 'figures/figure_not_included_2.tex'}


def apply_changes(file_path: str, changes: List, confirm: bool = False):
    """
    Pass changes as loaded json (list of dicts)
    """
    with open(file_path) as f:
        original_file_lines = f.readlines()

    # Filter out explanation elements
    operation_changes = [change for change in changes if "operation" in change]
    explanations = [
        change["explanation"] for change in changes if "explanation" in change
    ]

    # Sort the changes in reverse line order
    operation_changes.sort(key=lambda x: x["line"], reverse=True)

    file_lines = original_file_lines.copy()
    for change in operation_changes:
        operation = change["operation"]
        line = change["line"]
        content = change["content"]

        if operation == "Replace":
            file_lines[line - 1] = content + "\n"
        elif operation == "Delete":
            del file_lines[line - 1]
        elif operation == "InsertAfter":
            file_lines.insert(line, content + "\n")

    # Print explanations
    cprint("Explanations:", "blue")
    for explanation in explanations:
        cprint(f"- {explanation}", "blue")

    # Display changes diff
    print("\nChanges to be made:")
    diff = difflib.unified_diff(original_file_lines, file_lines, lineterm="")
    for line in diff:
        if line.startswith("+"):
            cprint(line, "green", end="")
        elif line.startswith("-"):
            cprint(line, "red", end="")
        else:
            print(line, end="")

    if confirm:
        # check if user wants to apply changes or exit
        confirmation = input("Do you want to apply these changes? (y/n): ")
        if confirmation.lower() != "y":
            print("Changes not applied")
            sys.exit(0)

    with open(file_path, "w") as f:
        f.writelines(file_lines)
    print("Changes applied.")

apply_changes(file_path='/tmp/tmp6qrrn_j9', changes=[{'operation': 'Replace', 'line': 2, 'content': 'new second line'}], confirm=False)

<_io.TextIOWrapper name='/tmp/tmp6qrrn_j9' mode='r' encoding='UTF-8'>

<_io.TextIOWrapper name='/tmp/tmp6qrrn_j9' mode='w' encoding='UTF-8'>

['first line\n', 'second line\n', 'third line']

['first line\n', 'new second line\n', 'third line']

'new second line'

<generator object unified_diff at 0x7f5b71b2cba0>


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 import_ext(name, optional=False):
  components = name.split(".")
  if (len(components) > 1):
    __import__(".".join(components[:-1]))
  previous_dlopenflags = None
  if (sys.platform.startswith("linux")) :
    previous_dlopenflags = sys.getdlopenflags()
    sys.setdlopenflags(0x100|0x2)
  try: mod = __import__(name)
  except ImportError as e:
    if (optional): return None
    error_msg = str(e)
    m = symbol_not_found_pat.search(error_msg)
    if m:
      error_msg = (  error_msg[:m.start(1)]
                   + cpp_function_name.demangle(m.group(1))
                   + error_msg[m.end(1):])
    raise ImportError(
      "\n  ".join(['__import__("%s"): %s' % (name, error_msg), "sys.path:"]
      + ["  "+p for p in sys.path]))
  for comp in components[1:]:
    mod = getattr(mod, comp)
  if (previous_dlopenflags is not None):
    sys.setdlopenflags(previous_dlopenflags)
  if (python_libstdcxx_so is not None):
    mod_file = getattr(mod, "__file__", None)
    if (mod_file is not None):
      for line in easy_run.fully_buffered(
                    command='/usr/bin/ldd "%s"' % mod_file).stdout_lines:
        if (line.strip().startswith("libstdc++.so")):
          mod_libstdcxx_so = line.split()[0]
          if (mod_libstdcxx_so != python_libstdcxx_so):
            raise SystemError("""\
FATAL: libstdc++.so mismatch:
  %s: %s
  %s: %s""" % (sys.executable, python_libstdcxx_so,
               mod_file, mod_libstdcxx_so))
          break
  return mod

import_ext(name='boost_python_meta_ext', optional=False)

ModuleNotFoundError("No module named 'boost_python_meta_ext'")


def _make_text_tag(column, attributes, text, cell_width):
    """Build SVG text element based on content and style attributes"""
    text_tag_attributes = {
        'x': str(column * cell_width),
        'textLength': str(wcswidth(text) * cell_width),
    }
    if attributes['bold']:
        text_tag_attributes['font-weight'] = 'bold'

    if attributes['italics']:
        text_tag_attributes['font-style'] = 'italic'

    decoration = ''
    if attributes['underscore']:
        decoration = 'underline'
    if attributes['strikethrough']:
        decoration += ' line-through'
    if decoration:
        text_tag_attributes['text-decoration'] = decoration

    if attributes['color'].startswith('#'):
        text_tag_attributes['fill'] = attributes['color']
    else:
        text_tag_attributes['class'] = attributes['color']

    text_tag = etree.Element('text', text_tag_attributes)
    text_tag.text = text
    return text_tag

_make_text_tag(column=0, attributes={'color': 'red', 'bold': False, 'italics': False, 'underscore': False, 'strikethrough': False}, text='A', cell_width=8)

'A'

'A'


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 from_file(filepath, delimiter="", blanklines=False):
    """Imports userdata from a file.

    :type filepath: string

    :param filepath  The absolute path to the file.

    :type delimiter: string

    :param: delimiter  Delimiter to use with the troposphere.Join().

    :type blanklines: boolean

    :param blanklines  If blank lines should be ignored

    rtype: troposphere.Base64
    :return The base64 representation of the file.
    """
    data = []

    try:
        with open(filepath, "r") as f:
            for line in f:
                if blanklines and line.strip("\n\r ") == "":
                    continue

                data.append(line)
    except IOError:
        raise IOError("Error opening or reading file: {}".format(filepath))

    return Base64(Join(delimiter, data))

from_file(filepath='/local/rcs/jinjun/code/pytrace-collector/logs/self_collected/tried/cloudtools+troposphere/cloudtools+troposphere/tests/userdata_test_scripts/char_escaping.sh', delimiter='', blanklines=False)


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 config_dict(configuration_tuple):
    config_dict = {}

    config_file = configuration_tuple._asdict().get('CFG')
    if config_file is None:
        config_file = configfile.get_config_path(configuration_tuple)

    if config_file is not None:
        config_dict = utils.filter_fields(configfile.read_config(config_file), configuration_tuple)
        config_dict = utils.type_correct_with(config_dict, configuration_tuple)

    return config_dict

config_dict(configuration_tuple={})


def do_replace(fname, content, before_text, after_text, fence=None):
    before_text = strip_quoted_wrapping(before_text, fname, fence)
    after_text = strip_quoted_wrapping(after_text, fname, fence)
    fname = Path(fname)

    # does it want to make a new file?
    if not fname.exists() and not before_text.strip():
        fname.touch()
        content = ""

    if content is None:
        return

    if not before_text.strip():
        # append to existing file, or start a new file
        new_content = content + after_text
    else:
        new_content = replace_most_similar_chunk(content, before_text, after_text)

    return new_content

do_replace(fname='/tmp/tmp7g7a2csg/file.txt', content='two\n', before_text='two\n', after_text='three\n', fence=('```', '```'))

'two\n'

'two\n'

'two\n'


def strip_quoted_wrapping(res, fname=None, fence=DEFAULT_FENCE):
    """
    Given an input string which may have extra "wrapping" around it, remove the wrapping.
    For example:

    filename.ext
    ```
    We just want this content
    Not the filename and triple quotes
    ```
    """
    if not res:
        return res

    res = res.splitlines()

    if fname and res[0].strip().endswith(Path(fname).name):
        res = res[1:]

    if res[0].startswith(fence[0]) and res[-1].startswith(fence[1]):
        res = res[1:-1]

    res = "\n".join(res)
    if res and res[-1] != "\n":
        res += "\n"

    return res

strip_quoted_wrapping(res='two\n', fname='/tmp/tmp7g7a2csg/file.txt', fence=('```', '```'))


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 process_fenced_block(lines, start_line_num):
    for line_num in range(start_line_num, len(lines)):
        line = lines[line_num]
        if line.startswith("```"):
            break

    block = lines[start_line_num:line_num]
    block.append("@@ @@")

    if block[0].startswith("--- ") and block[1].startswith("+++ "):
        # Extract the file path, considering that it might contain spaces
        fname = block[1][4:].strip()
        block = block[2:]
    else:
        fname = None

    edits = []

    keeper = False
    hunk = []
    op = " "
    for line in block:
        hunk.append(line)
        if len(line) < 2:
            continue

        if line.startswith("+++ ") and hunk[-2].startswith("--- "):
            if hunk[-3] == "\n":
                hunk = hunk[:-3]
            else:
                hunk = hunk[:-2]

            edits.append((fname, hunk))
            hunk = []
            keeper = False

            fname = line[4:].strip()
            continue

        op = line[0]
        if op in "-+":
            keeper = True
            continue
        if op != "@":
            continue
        if not keeper:
            hunk = []
            continue

        hunk = hunk[:-1]
        edits.append((fname, hunk))
        hunk = []
        keeper = False

    return line_num + 1, edits

process_fenced_block(lines=['\n', 'Some text...\n', '\n', '```diff\n', '--- /dev/null\n', '+++ file.txt\n', '@@ ... @@\n', '-Original\n', '+Modified\n', '```\n'], start_line_num=4)


def _addpoint(sol, i, distances, prec):
    """
    Try to add point i to a given solution-approach.

    gives all possibilties and a status about the solution:
        state = 0: possibilities found
        state = 1: no possibilities but no contradiction
        state = 2: solution-approach has a contradiction with point i
    """
    res = []

    # if i is already part of the solution return it
    if np.ndim(sol[i]) != 0:
        return [sol], 0

    # collect the points already present in the solution
    solpnts = []
    for n, m in enumerate(sol):
        if np.ndim(m) != 0:
            solpnts.append(n)

    # number of present points
    pntscount = len(solpnts)

    # try to add the point in all possible constellations
    for n in range(pntscount - 1):
        for m in range(n + 1, pntscount):
            tmppnt, state = _pntcoord(
                sol, i, solpnts[n], solpnts[m], distances, prec
            )

            # if possiblities are found, add them (at most 2! (think about))
            if state == 0:
                for pnt in tmppnt:
                    res.append(dcopy(sol))
                    res[-1][i] = pnt

            # if one possiblity or a contradiction is found, return the result
            if state != 1:
                return res, state

    # if the state remaind 1, return empty result and no contradiction
    return res, state

_addpoint(sol=[array([0., 0.]), array([3., 0.]), 0, 0], i=2, distances=array([[ 0.,  3.,  4.,  1.],       [ 3.,  0.,  2.,  3.],       [ 4.,  2.,  0., -1.],       [ 1.,  3., -1.,  0.]]), prec=0.1)


def _pntcoord(sol, i, n, m, distances, prec):
    """
    Generate coordinates for point i in constellation to points m and n.

    Check if these coordinates are valid with all other points in the solution.
    """
    tmppnt = []

    state = 1

    pntscount = len(sol)

    # if no distances known, return empty result and the unknown-state
    if distances[i, n] < -0.5 or distances[i, m] < -0.5:
        return tmppnt, state

    # if the Triangle inequality is not fullfilled give a contradiction
    if distances[i, n] + distances[i, m] < _dist(sol[n], sol[m]):
        state = 2
        return tmppnt, state

    # generate the affine rotation to bring the points in the right place
    g = _affinef(*_invtranmat(*_tranmat(sol[n], sol[m])))

    # generate the coordinates
    x = _xvalue(distances[i, n], distances[i, m], _dist(sol[n], sol[m]))
    y1, y2 = _yvalue(distances[i, n], distances[i, m], _dist(sol[n], sol[m]))

    # generate the possible positons
    pos1 = g(np.array([x, y1]))
    pos2 = g(np.array([x, y2]))

    valid1 = True
    valid2 = True

    # check if the possible positions are valid
    for k in range(pntscount):
        if np.ndim(sol[k]) != 0 and distances[i, k] > -0.5:
            valid1 &= abs(_dist(sol[k], pos1) - distances[i, k]) < prec
            valid2 &= abs(_dist(sol[k], pos2) - distances[i, k]) < prec

    # if any position is valid, add it to the result
    if valid1 or valid2:
        state = 0
        same = abs(y1 - y2) < prec / 4.0
        if valid1:
            tmppnt.append(dcopy(pos1))
        if valid2 and not same:
            tmppnt.append(dcopy(pos2))
    # if the positions are not valid, give a contradiction
    else:
        state = 2

    return tmppnt, state

_pntcoord(sol=[array([0., 0.]), array([3., 0.]), 0, 0], i=2, n=0, m=1, distances=array([[ 0.,  3.,  4.,  1.],       [ 3.,  0.,  2.,  3.],       [ 4.,  2.,  0., -1.],       [ 1.,  3., -1.,  0.]]), prec=0.1)

<function _affinef.<locals>.func at 0x7f9d2f5dc9d0>


def str2datetime(string):
    """
    Convert a normalized Benthos timestamp to a datetime object

    Parameters
    ----------
    string : str
        String to convert
    """

    if string == "0000-00-00T24:60:60Z":
        return None

    ms = string[20:-1]
    ms += "000000"[:6 - len(ms)]
    return datetime.datetime(
        int(string[:4]),
        int(string[5:7]),
        int(string[8:10]),
        int(string[11:13]),
        int(string[14:16]),
        int(string[17:19]),
        int(ms))

str2datetime(string='1970-01-01T00:00:00.0Z')


def getLogger(name, stdout=None):
    """ Return logger suitable for Cumulus """
    logger = logging.getLogger(name)
    # clear existing handlers
    logger.handlers = []
    if (stdout is None):
        logger.addHandler(logging.NullHandler())
    if stdout is not None:
        handler = logging.StreamHandler()
        handler.setLevel(stdout['level'])
        handler.setFormatter(CumulusFormatter())
        logger.addHandler(handler)
    # logging level
    logger.setLevel(1)
    return logger

getLogger(name='cumulus.aws', stdout=None)


def delete(self, *, ip_parameter, cascade):

        as_address = clean_address(ip_parameter)
        as_network = clean_network(ip_parameter)

        if as_address in self.__description:
            return self.__remove_ip_object(as_address)
        elif as_network in self.__description:
            return self.__remove_ip_object(as_network)

        raise IPObjectNotInSpaceError("cannot delete undescribed IP object")

delete(self=AddressSpace(_AddressSpace__strict=False, _AddressSpace__description={IPv4Address('203.0.113.128'): 'an IPv4 test net address'}, _AddressSpace__networks={}, _AddressSpace__addresses={4: {IPv4Address('203.0.113.128')}}, _AddressSpace__parent_supernet={IPv4Address('203.0.113.128'): None}, _AddressSpace__children_ip_object={None: {IPv4Address('203.0.113.128')}}), ip_parameter='203.0.113.128', cascade=True, self._AddressSpace__addresses={4: {IPv4Address('203.0.113.128')}}, self._AddressSpace__children_ip_object={None: {IPv4Address('203.0.113.128')}}, self._AddressSpace__description={IPv4Address('203.0.113.128'): 'an IPv4 test net address'}, self._AddressSpace__networks={}, self._AddressSpace__parent_supernet={IPv4Address('203.0.113.128'): None}, self._AddressSpace__strict=False)

AddressSpace(_AddressSpace__strict=False, _AddressSpace__description={}, _AddressSpace__networks={}, _AddressSpace__addresses={4: {IPv4Address('203.0.113.128')}}, _AddressSpace__parent_supernet={}, _AddressSpace__children_ip_object={None: set()})


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_audioclip_stereo_max_volume(nchannels, channel_muted):
    def make_frame(t):
        frame = []
        # build channels (one of each pair muted)
        for i in range(int(nchannels / 2)):
            if channel_muted == "left":
                # if muted channel is left, [0, sound, 0, sound...]
                frame.append(np.sin(t * 0))
                frame.append(np.sin(440 * 2 * np.pi * t))
            else:
                # if muted channel is right, [sound, 0, sound, 0...]
                frame.append(np.sin(440 * 2 * np.pi * t))
                frame.append(np.sin(t * 0))
        return np.array(frame).T

    clip = AudioClip(make_frame, fps=44100, duration=1)
    max_volume = clip.max_volume(stereo=True)
    # if `stereo == True`, `AudioClip.max_volume` returns a Numpy array`
    assert isinstance(max_volume, np.ndarray)
    assert len(max_volume) == nchannels

    # check channels muted and with sound
    for i, channel_max_volume in enumerate(max_volume):
        if i % 2 == 0:
            if channel_muted == "left":
                assert channel_max_volume == 0
            else:
                assert channel_max_volume > 0
        else:
            if channel_muted == "right":
                assert channel_max_volume == 0
            else:
                assert channel_max_volume > 0

test_audioclip_stereo_max_volume(nchannels=2, channel_muted='left')

<function test_audioclip_stereo_max_volume.<locals>.make_frame at 0x7f8c02a8e670>

{start=0, end=1, duration=1, memoize=False, memoized_t=None, memoized_frame=None, fps=44100, nchannels=2}


def test_clip_with_end(duration, start, end, expected_start, expected_duration):
    clip = ColorClip(color=(255, 0, 0), size=(2, 2), duration=duration).with_fps(1)
    if start is not None:
        clip = clip.with_start(start)
    else:
        clip.start = None
    clip = clip.with_end(end)

    assert clip.start == expected_start
    assert clip.duration == expected_duration

test_clip_with_end(duration=3, start=1, end=2, expected_start=1, expected_duration=1)

{start=0, end=3, duration=3, memoize=False, memoized_t=None, memoized_frame=None, mask=None, audio=None, relative_pos=False, layer=0, is_mask=False, has_constant_size=True, size=(2, 2), img=array([[[255,   0,   0],        [255,   0,   0]],       [[255,   0,   0],        [255,   0,   0]]]), fps=1}

{start=1, end=4, duration=3, memoize=False, memoized_t=None, memoized_frame=None, mask=None, audio=None, relative_pos=False, layer=0, is_mask=False, has_constant_size=True, size=(2, 2), img=array([[[255,   0,   0],        [255,   0,   0]],       [[255,   0,   0],        [255,   0,   0]]]), fps=1}

{start=1, end=2, duration=1, memoize=False, memoized_t=None, memoized_frame=None, mask=None, audio=None, relative_pos=False, layer=0, is_mask=False, has_constant_size=True, size=(2, 2), img=array([[[255,   0,   0],        [255,   0,   0]],       [[255,   0,   0],        [255,   0,   0]]]), fps=1}


def ffmpeg_write_image(filename, image, logfile=False, pixel_format=None):
    """Writes an image (HxWx3 or HxWx4 numpy array) to a file, using ffmpeg.

    Parameters
    ----------

    filename : str
        Path to the output file.

    image : np.ndarray
        Numpy array with the image data.

    logfile : bool, optional
        Writes the ffmpeg output inside a logging file (``True``) or not
        (``False``).

    pixel_format : str, optional
        Pixel format for ffmpeg. If not defined, it will be discovered checking
        if the image data contains an alpha channel (``"rgba"``) or not
        (``"rgb24"``).
    """
    if image.dtype != "uint8":
        image = image.astype("uint8")
    if not pixel_format:
        pixel_format = "rgba" if (image.shape[2] == 4) else "rgb24"

    cmd = [
        FFMPEG_BINARY,
        "-y",
        "-s",
        "%dx%d" % (image.shape[:2][::-1]),
        "-f",
        "rawvideo",
        "-pix_fmt",
        pixel_format,
        "-i",
        "-",
        filename,
    ]

    if logfile:
        log_file = open(filename + ".log", "w+")
    else:
        log_file = sp.PIPE

    popen_params = cross_platform_popen_params(
        {"stdout": sp.DEVNULL, "stderr": log_file, "stdin": sp.PIPE}
    )

    proc = sp.Popen(cmd, **popen_params)
    out, err = proc.communicate(image.tobytes())

    if proc.returncode:
        error = (
            f"{err}\n\nMoviePy error: FFMPEG encountered the following error while "
            f"writing file {filename} with command {cmd}:\n\n {err.decode()}"
        )

        raise IOError(error)

    del proc

ffmpeg_write_image(filename='/tmp/moviepy_ffmpeg_write_image.png', image=array([[[  0., 255.,   0.],        [ 51., 204.,   0.],        [102., 153.,   0.],        [153., 102.,   0.],        [204.,  51.,   0.]]]), logfile=False, pixel_format=None)

['/local/rcs/jinjun/miniforge3/envs/Zulko+moviepy/lib/python3.9/site-packages/imageio_ffmpeg/binaries/ffmpeg-linux64-v4.2.2', '-y', '-s', '5x1', '-f', 'rawvideo', '-pix_fmt', 'rgb24', '-i', '-', '/tmp/moviepy_ffmpeg_write_image.png']

<Popen: returncode: None args: ['/local/rcs/jinjun/miniforge3/envs/Zulko+mov...>

<Popen: returncode: 0 args: ['/local/rcs/jinjun/miniforge3/envs/Zulko+moviep...>

b"ffmpeg version 4.2.2-static https://johnvansickle.com/ffmpeg/  Copyright (c) 2000-2019 the FFmpeg developers\n  built with gcc 8 (Debian 8.3.0-6)\n  configuration: --enable-gpl --enable-version3 --enable-static --disable-debug --disable-ffplay --disable-indev=sndio --disable-outdev=sndio --cc=gcc --enable-fontconfig --enable-frei0r --enable-gnutls --enable-gmp --enable-libgme --enable-gray --enable-libaom --enable-libfribidi --enable-libass --enable-libvmaf --enable-libfreetype --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-librubberband --enable-libsoxr --enable-libspeex --enable-libsrt --enable-libvorbis --enable-libopus --enable-libtheora --enable-libvidstab --enable-libvo-amrwbenc --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libdav1d --enable-libxvid --enable-libzvbi --enable-libzimg\n  libavutil      56. 31.100 / 56. 31.100\n  libavcodec     58. 54.100 / 58. 54.100\n  libavformat    58. 29.100 / 58. 29.100\n  libavdevice    58.  8.100 / 58.  8.100\n  libavfilter     7. 57.100 /  7. 57.100\n  libswscale      5.  5.100 /  5.  5.100\n  libswresample   3.  5.100 /  3.  5.100\n  libpostproc    55.  5.100 / 55.  5.100\nInput #0, rawvideo, from 'pipe:':\n  Duration: N/A, start: 0.000000, bitrate: 3 kb/s\n    Stream #0:0: Video: rawvideo (RGB[24] / 0x18424752), rgb24, 5x1, 3 kb/s, 25 tbr, 25 tbn, 25 tbc\nStream mapping:\n  Stream #0:0 -> #0:0 (rawvideo (native) -> png (native))\nOutput #0, image2, to '/tmp/moviepy_ffmpeg_write_image.png':\n  Metadata:\n    encoder         : Lavf58.29.100\n    Stream #0:0: Video: png, rgb24, 5x1, q=2-31, 200 kb/s, 25 fps, 25 tbn, 25 tbc\n    Metadata:\n      encoder         : Lavc58.54.100 png\nframe=    1 fps=0.0 q=-0.0 Lsize=N/A time=00:00:00.04 bitrate=N/A speed=1.64x    \nvideo:0kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown\n"


def test_mask_and(image_from, duration, color, mask_color, expected_color):
    """Checks ``mask_and`` FX behaviour."""
    clip_size = tuple(random.randint(3, 10) for i in range(2))

    if duration == "random":
        duration = round(random.uniform(0, 0.5), 2)

    # test ImageClip and np.ndarray types as mask argument
    clip = ColorClip(color=color, size=clip_size).with_duration(duration)
    mask_clip = ColorClip(color=mask_color, size=clip.size)
    masked_clip = mask_and(
        clip, mask_clip if image_from == "ImageClip" else mask_clip.get_frame(0)
    )

    assert masked_clip.duration == clip.duration
    assert np.array_equal(masked_clip.get_frame(0)[0][0], np.array(expected_color))

    # test VideoClip as mask argument
    color_frame, mask_color_frame = (np.array([[color]]), np.array([[mask_color]]))
    clip = VideoClip(lambda t: color_frame).with_duration(duration)
    mask_clip = VideoClip(lambda t: mask_color_frame).with_duration(duration)
    masked_clip = mask_and(clip, mask_clip)

    assert np.array_equal(masked_clip.get_frame(0)[0][0], np.array(expected_color))

test_mask_and(image_from='np.ndarray', duration=None, color=(0, 0, 0), mask_color=(255, 255, 255), expected_color=(0, 0, 0))

{start=0, end=None, duration=None, memoize=False, memoized_t=None, memoized_frame=None, mask=None, audio=None, relative_pos=False, layer=0, size=(1, 1), is_mask=False, has_constant_size=True}


def _validate_htype_overwrites(htype: str, htype_overwrite: dict):
    """Raises errors if ``htype_overwrite`` has invalid keys or was missing required values."""

    defaults = HTYPE_CONFIGURATIONS[htype]

    for key, value in htype_overwrite.items():
        if key not in defaults:
            raise TensorMetaInvalidHtypeOverwriteKey(htype, key, list(defaults.keys()))

        if isinstance(value, str) and value == UNSPECIFIED:
            if defaults[key] == REQUIRE_USER_SPECIFICATION:
                raise TensorMetaMissingRequiredValue(htype, key)

    sc = htype_overwrite["sample_compression"]
    cc = htype_overwrite["chunk_compression"]
    compr = sc if cc in (None, UNSPECIFIED) else cc
    actual_htype = f"link[{htype}]" if htype_overwrite["is_link"] else htype
    if htype.startswith("image") and sc == UNSPECIFIED and cc == UNSPECIFIED:
        raise TensorMetaMissingRequiredValue(
            actual_htype, ["chunk_compression", "sample_compression"]  # type: ignore
        )
    if htype in ("audio", "video", "point_cloud", "mesh", "nifti"):
        if cc not in (UNSPECIFIED, None):
            raise UnsupportedCompressionError("Chunk compression", htype=htype)
        elif sc == UNSPECIFIED:
            raise TensorMetaMissingRequiredValue(
                actual_htype, "sample_compression"  # type: ignore
            )
    supported_compressions = HTYPE_SUPPORTED_COMPRESSIONS.get(htype)
    if (
        compr
        and compr != UNSPECIFIED
        and supported_compressions
        and compr not in supported_compressions
    ):
        raise UnsupportedCompressionError(compr, htype=htype)

_validate_htype_overwrites(htype='generic', htype_overwrite={'sample_compression': 'unspecified', 'chunk_compression': 'unspecified', 'dtype': 'unspecified', 'hidden': False, 'tiling_threshold': None, 'max_chunk_size': 2000000, 'is_sequence': False, 'is_link': False, 'verify': True})

{'dtype': None, 'sample_compression': None, 'chunk_compression': None, 'typestr': None, 'max_chunk_size': None, 'tiling_threshold': None, 'is_sequence': False, 'is_link': False, 'hidden': False, 'links': None, 'verify': False}


def get_rack_tile_index(player_rack, move_letter):
    for i, rack_tile in enumerate(player_rack):
        if rack_tile.letter == move_letter:
            return i

    return None

get_rack_tile_index(player_rack=[Q, E, O, S, G, H, E, B, A, K, E, R], move_letter='K')