text: import collections
  
  # Summary of defined SROs.  This basically shows how STIX types are allowed to
  # relate to each other, and via which relationship types.
  #
  # Hopefully this is an easy structure to maintain: maps relationship source
  # STIX type to a map from relationship type to a list of target types.  It
  # eliminates repetition in source and relationship types.
  _RELATIONSHIPS = {
      "attack-pattern": {
          "delivers": ["malware"],
          "targets": ["identity", "location", "vulnerability"],
          "uses": ["malware", "tool"]
      },
      "campaign": {
          "attributed-to": ["intrusion-set", "threat-actor"],
          "compromises": ["infrastructure"],
          "originates-from": ["location"],
          "targets": ["identity", "location", "vulnerability"],
          "uses": ["attack-pattern", "infrastructure", "malware", "tool"]
      },
      "course-of-action": {
          "investigates": ["indicator"],
          "mitigates": [
              "attack-pattern", "indicator", "malware", "tool", "vulnerability"
          ]
      },
      "identity": {
          "located-at": ["location"]
      },
      "indicator": {
          "indicates": [
              "attack-pattern", "campaign", "infrastructure", "intrusion-set",
              "malware", "threat-actor", "tool"
          ],
          "based-on": ["observed-data"]
      },
      "infrastructure": {
          "communicates-with": [
              "infrastructure", "ipv4-addr", "ipv6-addr", "domain-name", "url"
          ],
          "consists-of": [
              "infrastructure", "observed-data",
              # all generatable SCO types
              "artifact", "autonomous-system", "directory", "domain-name",
              "email-addr", "email-message", "file", "ipv4-addr", "ipv6-addr",
              "mac-addr", "mutex", "network-traffic", "process", "software",
              "url", "user-account", "windows-registry-key", "x509-certificate"
          ],
          "controls": ["infrastructure", "malware"],
          "delivers": ["malware"],
          "has": ["vulnerability"],
          "hosts": ["tool", "malware"],
          "located-at": ["location"],
          "uses": ["infrastructure"],
      },
      "intrusion-set": {
          "attributed-to": ["threat-actor"],
          "compromises": ["infrastructure"],
          "hosts": ["infrastructure"],
          "owns": ["infrastructure"],
          "originates-from": ["location"],
          "targets": ["identity", "location", "vulnerability"],
          "uses": ["attack-pattern", "infrastructure", "malware", "tool"]
      },
      "malware": {
          "authored-by": ["threat-actor", "intrusion-set"],
          "beacons-to": ["infrastructure"],
          "exfiltrate-to": ["infrastructure"],
          "communicates-with": ["ipv4-addr", "ipv6-addr", "domain-name", "url"],
          "controls": ["malware"],
          "downloads": ["malware", "tool", "file"],
          "drops": ["malware", "tool", "file"],
          "exploits": ["vulnerability"],
          "originates-from": ["location"],
          "targets": ["identity", "infrastructure", "location", "vulnerability"],
          "uses": ["attack-pattern", "infrastructure", "malware", "tool"],
          "variant-of": ["malware"],
      },
      "malware-analysis": {
          "characterizes": ["malware"],
          "analysis-of": ["malware"],
          "static-analysis-of": ["malware"],
          "dynamic-analysis-of": ["malware"]
      },
      "threat-actor": {
          "attributed-to": ["identity"],
          "compromises": ["infrastructure"],
          "hosts": ["infrastructure"],
          "owns": ["infrastructure"],
          "impersonates": ["identity"],
          "located-at": ["location"],
          "targets": ["identity", "location", "vulnerability"],
          "uses": ["attack-pattern", "infrastructure", "malware", "tool"]
      },
      "tool": {
          "delivers": ["malware"],
          "drops": ["malware"],
          "has": ["vulnerability"],
          "targets": ["identity", "infrastructure", "location", "vulnerability"]
      }
  }
  
  
  # Programmatically add some common relationships, to reduce verbosity in
  # the _RELATIONSHIPS map
  for src_type, rel_info in _RELATIONSHIPS.items():
      rel_info["derived-from"] = [src_type]
      rel_info["duplicate-of"] = [src_type]
  
  
  # Omit "related-to".  Currently special-casing that in the STIX generator.
  
  
  Relationship = collections.namedtuple(
      "Relationship", "src_type, rel_type, target_type"
  )
  
  
  # A structure to make it easy to choose a graph edge based on the type of node
  # it needs to connect to at one end.
  RELATIONSHIP_OBJECTS_BY_ENDPOINT_TYPE = {}
  
  
  for src_type, rel_info in _RELATIONSHIPS.items():
      for rel_type, target_types in rel_info.items():
          for target_type in target_types:
  
              rel_obj = Relationship(src_type, rel_type, target_type)
  
              RELATIONSHIP_OBJECTS_BY_ENDPOINT_TYPE.setdefault(
                  src_type, []
              ).append(rel_obj)
  
              RELATIONSHIP_OBJECTS_BY_ENDPOINT_TYPE.setdefault(
                  target_type, []
              ).append(rel_obj)
  