text: """This module provides classes that make up an issue report."""
  import logging
  import json
  import operator
  from jinja2 import PackageLoader, Environment
  from typing import Dict, List, Any, Optional
  import hashlib
  
  from mythril.laser.execution_info import ExecutionInfo
  from mythril.solidity.soliditycontract import SolidityContract
  from mythril.analysis.swc_data import SWC_TO_TITLE
  from mythril.support.source_support import Source
  from mythril.support.start_time import StartTime
  from mythril.support.support_utils import get_code_hash
  from mythril.support.signatures import SignatureDB
  from time import time
  
  log = logging.getLogger(__name__)
  
  
  class Issue:
      """Representation of an issue and its location."""
  
      def __init__(
          self,
          contract,
          function_name,
          address,
          swc_id,
          title,
          bytecode,
          gas_used=(None, None),
          severity=None,
          description_head="",
          description_tail="",
          transaction_sequence=None,
      ):
          """
  
          :param contract: The contract
          :param function_name: Function name where the issue is detected
          :param address: The address of the issue
          :param swc_id: Issue's corresponding swc-id
          :param title: Title
          :param bytecode: bytecode of the issue
          :param gas_used: amount of gas used
          :param severity: The severity of the issue
          :param description_head: The top part of description
          :param description_tail: The bottom part of the description
          :param debug: The transaction sequence
          """
          self.title = title
          self.contract = contract
          self.function = function_name
          self.address = address
          self.description_head = description_head
          self.description_tail = description_tail
          self.description = "%s\n%s" % (description_head, description_tail)
          self.severity = severity
          self.swc_id = swc_id
          self.min_gas_used, self.max_gas_used = gas_used
          self.filename = None
          self.code = None
          self.lineno = None
          self.source_mapping = None
          self.discovery_time = time() - StartTime().global_start_time
          self.bytecode_hash = get_code_hash(bytecode)
          self.transaction_sequence = transaction_sequence
  
      @property
      def transaction_sequence_users(self):
          """ Returns the transaction sequence without pre-generated block data"""
          return self.transaction_sequence
  
      @property
      def transaction_sequence_jsonv2(self):
          """ Returns the transaction sequence as a json string with pre-generated block data"""
          return (
              self.add_block_data(self.transaction_sequence)
              if self.transaction_sequence
              else None
          )
  
      @staticmethod
      def add_block_data(transaction_sequence: Dict):
          """ Adds sane block data to a transaction_sequence """
          for step in transaction_sequence["steps"]:
              step["gasLimit"] = "0x7d000"
              step["gasPrice"] = "0x773594000"
              step["blockCoinbase"] = "0xcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcb"
              step["blockDifficulty"] = "0xa7d7343662e26"
              step["blockGasLimit"] = "0x7d0000"
              step["blockNumber"] = "0x66e393"
              step["blockTime"] = "0x5bfa4639"
          return transaction_sequence
  
      @property
      def as_dict(self):
          """
  
          :return:
          """
  
          issue = {
              "title": self.title,
              "swc-id": self.swc_id,
              "contract": self.contract,
              "description": self.description,
              "function": self.function,
              "severity": self.severity,
              "address": self.address,
              "tx_sequence": self.transaction_sequence,
              "min_gas_used": self.min_gas_used,
              "max_gas_used": self.max_gas_used,
              "sourceMap": self.source_mapping,
          }
  
          if self.filename and self.lineno:
              issue["filename"] = self.filename
              issue["lineno"] = self.lineno
  
          if self.code:
              issue["code"] = self.code
  
          return issue
  
      def _set_internal_compiler_error(self):
          """
          Adds the false positive to description and changes severity to low
          """
          self.severity = "Low"
          self.description_tail += (
              " This issue is reported for internal compiler generated code."
          )
          self.description = "%s\n%s" % (self.description_head, self.description_tail)
          self.code = ""
  
      def add_code_info(self, contract):
          """
  
          :param contract:
          """
          if self.address and isinstance(contract, SolidityContract):
              codeinfo = contract.get_source_info(
                  self.address, constructor=(self.function == "constructor")
              )
  
              if codeinfo is None:
                  self.source_mapping = self.address
                  self.filename = "Internal File"
                  return
  
              self.filename = codeinfo.filename
              self.code = codeinfo.code
              self.lineno = codeinfo.lineno
              if self.lineno is None:
                  self._set_internal_compiler_error()
              self.source_mapping = codeinfo.solc_mapping
          else:
              self.source_mapping = self.address
  
      def resolve_function_names(self):
          """ Resolves function names for each step """
  
          if (
              self.transaction_sequence is None
              or "steps" not in self.transaction_sequence
          ):
              return
  
          signatures = SignatureDB()
  
          for step in self.transaction_sequence["steps"]:
              _hash = step["input"][:10]
  
              try:
                  sig = signatures.get(_hash)
  
                  if len(sig) > 0:
                      step["name"] = sig[0]
                  else:
                      step["name"] = "unknown"
              except ValueError:
                  step["name"] = "unknown"
  
  
  class Report:
      """A report containing the content of multiple issues."""
  
      environment = Environment(
          loader=PackageLoader("mythril.analysis"), trim_blocks=True
      )
  
      def __init__(
          self,
          contracts=None,
          exceptions=None,
          execution_info: Optional[List[ExecutionInfo]] = None,
      ):
          """
  
          :param contracts:
          :param exceptions:
          """
          self.issues = {}  # type: Dict[bytes, Issue]
          self.solc_version = ""
          self.meta = {}  # type: Dict[str, Any]
          self.source = Source()
          self.source.get_source_from_contracts_list(contracts)
          self.exceptions = exceptions or []
          self.execution_info = execution_info or []
  
      def sorted_issues(self):
          """
  
          :return:
          """
          issue_list = [issue.as_dict for key, issue in self.issues.items()]
          return sorted(issue_list, key=operator.itemgetter("address", "title"))
  
      def append_issue(self, issue):
          """
  
          :param issue:
          """
          m = hashlib.md5()
          m.update((issue.contract + str(issue.address) + issue.title).encode("utf-8"))
          issue.resolve_function_names()
          self.issues[m.digest()] = issue
  
      def as_text(self):
          """
  
          :return:
          """
          name = self._file_name()
          template = Report.environment.get_template("report_as_text.jinja2")
  
          return template.render(filename=name, issues=self.sorted_issues())
  
      def as_json(self):
          """
  
          :return:
          """
          result = {"success": True, "error": None, "issues": self.sorted_issues()}
          return json.dumps(result, sort_keys=True)
  
      def _get_exception_data(self) -> dict:
          if not self.exceptions:
              return {}
          logs = []  # type: List[Dict]
          for exception in self.exceptions:
              logs += [{"level": "error", "hidden": True, "msg": exception}]
          return {"logs": logs}
  
      def as_swc_standard_format(self):
          """Format defined for integration and correlation.
  
          :return:
          """
          # Setup issues
          _issues = []
  
          for key, issue in self.issues.items():
  
              idx = self.source.get_source_index(issue.bytecode_hash)
              try:
                  title = SWC_TO_TITLE[issue.swc_id]
              except KeyError:
                  title = "Unspecified Security Issue"
              extra = {"discoveryTime": int(issue.discovery_time * 10 ** 9)}
              if issue.transaction_sequence_jsonv2:
                  extra["testCases"] = [issue.transaction_sequence_jsonv2]
  
              _issues.append(
                  {
                      "swcID": "SWC-" + issue.swc_id,
                      "swcTitle": title,
                      "description": {
                          "head": issue.description_head,
                          "tail": issue.description_tail,
                      },
                      "severity": issue.severity,
                      "locations": [{"sourceMap": "%d:1:%d" % (issue.address, idx)}],
                      "extra": extra,
                  }
              )
          # Setup meta
          meta_data = self.meta
  
          # Add logs to meta
          meta_data.update(self._get_exception_data())
  
          # Add execution info to meta
          analysis_duration = int(
              round((time() - StartTime().global_start_time) * (10 ** 9))
          )
          meta_data["mythril_execution_info"] = {"analysis_duration": analysis_duration}
          for execution_info in self.execution_info:
              meta_data["mythril_execution_info"].update(execution_info.as_dict())
  
          result = [
              {
                  "issues": _issues,
                  "sourceType": self.source.source_type,
                  "sourceFormat": self.source.source_format,
                  "sourceList": self.source.source_list,
                  "meta": meta_data,
              }
          ]
  
          return json.dumps(result, sort_keys=True)
  
      def as_markdown(self):
          """
  
          :return:
          """
          filename = self._file_name()
          template = Report.environment.get_template("report_as_markdown.jinja2")
          return template.render(filename=filename, issues=self.sorted_issues())
  
      def _file_name(self):
          """
  
          :return:
          """
          if len(self.issues.values()) > 0:
              return list(self.issues.values())[0].filename
  