text: import itertools
  import logging
  import re
  from functools import reduce
  from math import ceil, floor, log
  from typing import Union, Any, Dict, Callable, List, Optional
  
  from checkov.terraform.parser_functions import tonumber, FUNCTION_FAILED, create_map, tobool, tomap, tostring
  
  """
  This file contains a custom implementation of the builtin `eval` function.
  `eval` is not a safe function, because it can execute *every* command, 
  so this file overrides `eval` and allows only the functions in SAFE_EVAL_DICT.
  
  The functions are an implementation of Terraform's built-in functions
  https://www.terraform.io/docs/configuration/functions.html
  
  Not all of the functions are implemented yet. If a function doesn't exist, the original value is returned.
  """
  
  
  def _find_regex_groups(pattern: str, input_str: str) -> Optional[Union[Dict[str, str], List[str]]]:
      match = re.match(pattern, input_str)
      if match:
          if match.groupdict():
              # try to find named capturing groups
              return match.groupdict()
          if list(match.groups()):
              # try to find unnamed capturing groups
              return list(match.groups())
      return None
  
  
  def regex(pattern: str, input_str: str) -> Union[Dict[str, str], List[str], str]:
      try:
          groups = _find_regex_groups(pattern, input_str)
          if groups is not None:
              return groups
  
          results: List[str] = re.findall(pattern, input_str)
          # return first match
          if len(results) > 0:
              return results[0]
          return ""
      except TypeError:
          return f"regex({pattern}, {input_str})"
  
  
  def regexall(pattern: str, input_str: str) -> Union[Dict[str, str], List[str], str]:
      try:
          groups = _find_regex_groups(pattern, input_str)
          if groups is not None:
              return groups
  
          results = re.findall(pattern, input_str)
          return results
      except TypeError:
          return f"regexall({pattern}, {input_str})"
  
  
  def trim(input_str: str, chars_to_remove: str) -> str:
      for c in chars_to_remove:
          input_str = input_str.replace(c, "")
      return input_str
  
  
  def coalesce(*arg: Any) -> Any:
      return reduce(lambda x, y: x if x not in [None, ""] else y, arg)
  
  
  def coalesce_list(*arg: List[Any]) -> List[Any]:
      return reduce(lambda x, y: x if x not in [None, []] else y, arg)
  
  
  def flatten(lst: List[List[Any]]) -> List[Any]:
      res = [item for sublist in lst for item in sublist]
      if any(type(elem) is list for elem in res):
          return flatten(res)
      else:
          return res
  
  
  def matchkeys(values_list: List[Any], keys_list: List[Any], search_set: List[Any]) -> List[Any]:
      matching = set()
      for search in search_set:
          indices = [i for i, x in enumerate(keys_list) if x == search]
          for i in indices:
              matching.add(values_list[i])
  
      return list(matching)
  
  
  def reverse(lst: List[Any]) -> List[Any]:
      lst.reverse()
      return lst
  
  
  def sort(lst: List[str]) -> List[str]:
      lst.sort()
      return lst
  
  
  def merge(*args: Any) -> Dict[str, Any]:
      res: Dict[str, Any] = {}
      for d in args:
          res = {**res, **d}
      return res
  
  
  def wrap_func(f: Callable[..., Any], *args: Any) -> Any:
      res = f(*args)
      if res == FUNCTION_FAILED:
          raise ValueError
      return res
  
  
  SAFE_EVAL_FUNCTIONS: List[str] = []
  SAFE_EVAL_DICT = dict([(k, locals().get(k, None)) for k in SAFE_EVAL_FUNCTIONS])
  
  # math functions
  SAFE_EVAL_DICT["abs"] = abs
  SAFE_EVAL_DICT["ceil"] = ceil
  SAFE_EVAL_DICT["floor"] = floor
  SAFE_EVAL_DICT["log"] = log
  SAFE_EVAL_DICT["max"] = max
  SAFE_EVAL_DICT["min"] = min
  SAFE_EVAL_DICT["parsint"] = int
  SAFE_EVAL_DICT["pow"] = pow
  SAFE_EVAL_DICT["signum"] = lambda x: -1 if x < 0 else 0 if x == 0 else 1
  
  # string functions
  SAFE_EVAL_DICT["chomp"] = lambda x: x.rstrip()
  SAFE_EVAL_DICT["format"] = lambda text_to_format, *args: (text_to_format % args)
  SAFE_EVAL_DICT["formatlist"] = lambda text_to_format, args_list: [(text_to_format % args) for args in args_list]
  SAFE_EVAL_DICT["indent"] = lambda num_of_space, input_str: input_str
  SAFE_EVAL_DICT["join"] = lambda separator, lst: separator.join(lst)
  SAFE_EVAL_DICT["lower"] = lambda input_str: input_str.lower()
  SAFE_EVAL_DICT["regex"] = regex
  SAFE_EVAL_DICT["regexall"] = regexall
  SAFE_EVAL_DICT["replace"] = lambda string, substring, replacement: string.replace(substring, replacement)
  SAFE_EVAL_DICT["split"] = lambda separator, input_str: input_str.split(separator)
  SAFE_EVAL_DICT["strrev"] = lambda input_str: input_str[::-1]
  SAFE_EVAL_DICT["substr"] = lambda input_str, offset, length: input_str[offset : offset + length]
  SAFE_EVAL_DICT["title"] = lambda input_str: input_str.title()
  SAFE_EVAL_DICT["trim"] = trim
  SAFE_EVAL_DICT["trimprefix"] = lambda input_str, prefix: input_str.lstrip(prefix)
  SAFE_EVAL_DICT["trimsuffix"] = lambda input_str, prefix: input_str.rstrip(prefix)
  SAFE_EVAL_DICT["trimspace"] = lambda input_str: input_str.strip()
  SAFE_EVAL_DICT["upper"] = lambda input_str: input_str.upper()
  
  # collections
  SAFE_EVAL_DICT["chunklist"] = lambda lst, chunk_size: [lst[i : i + chunk_size] for i in range(0, len(lst), chunk_size)]
  SAFE_EVAL_DICT["coalesce"] = coalesce
  SAFE_EVAL_DICT["coalescelist"] = coalesce_list
  SAFE_EVAL_DICT["compact"] = lambda lst: list(filter(lambda l: l != "", lst))
  SAFE_EVAL_DICT["concat"] = lambda *lists: list(itertools.chain(*lists))
  SAFE_EVAL_DICT["contains"] = lambda lst, value: value in lst
  SAFE_EVAL_DICT["distinct"] = lambda lst: list(dict.fromkeys(lst))
  SAFE_EVAL_DICT["element"] = lambda lst, index: lst[index]
  SAFE_EVAL_DICT["flatten"] = flatten
  SAFE_EVAL_DICT["index"] = lambda lst, value: lst.index(value)
  SAFE_EVAL_DICT["keys"] = lambda map_input: list(map_input.keys())
  SAFE_EVAL_DICT["length"] = len
  SAFE_EVAL_DICT["list"] = lambda *args: list(args)
  SAFE_EVAL_DICT["lookup"] = lambda map_input, key, default: map_input.get(key, default)
  SAFE_EVAL_DICT["map"] = lambda *args: wrap_func(create_map, list(args))
  SAFE_EVAL_DICT["matchkeys"] = matchkeys
  SAFE_EVAL_DICT["merge"] = merge
  # SAFE_EVAL_DICT['range']
  SAFE_EVAL_DICT["reverse"] = reverse
  SAFE_EVAL_DICT["sort"] = sort
  
  
  # type conversion
  SAFE_EVAL_DICT["tobool"] = lambda arg: wrap_func(tobool, arg)
  SAFE_EVAL_DICT["tolist"] = lambda *args: list(*args)
  SAFE_EVAL_DICT["tomap"] = lambda arg: wrap_func(tomap, str(arg))
  SAFE_EVAL_DICT["tonumber"] = lambda arg: arg if type(arg) in [int, float] else wrap_func(tonumber, arg)
  SAFE_EVAL_DICT["toset"] = lambda origin: set(origin)
  SAFE_EVAL_DICT["tostring"] = lambda arg: arg if isinstance(arg, str) else wrap_func(tostring, str(arg))
  
  # encoding
  SAFE_EVAL_DICT["jsonencode"] = lambda arg: arg
  
  
  def evaluate(input_str: str) -> Any:
      if "__" in input_str:
          logging.warning(f"got a substring with double underscore, which is not allowed. origin string: {input_str}")
          return input_str
      return eval(input_str, {"__builtins__": None}, SAFE_EVAL_DICT)  # nosec
  