<jupyter_start><jupyter_text>STIX 2.1 Preview i18nLet's pretend we're an ISAC publishing an indicator in several different languages.**Note:** This STIX 2.1 Preview depends on the 2.1 development branch of cti-python-stix2. Assuming that you did a `pip install -r requirements.txt` to get the STIX 2.0 Training Jupyter notebook running, you'll need to do a couple of steps to replace the PyPi python-stix2 with the one from the stix2.1 branch on GitHub. Run the following commands in your Python virtual environment before proceeding:* `pip uninstall stix2`* `pip install git+git://github.com/oasis-open/cti-python-stix2.git@stix2.1egg=stix2`<jupyter_code>from stix2 import Indicator, LanguageContent, Identity, Campaign, ThreatActor, \
    Relationship, Opinion, ObjectFactory, CompositeDataSource, MemoryStore
from jose import jws

# First, let's pretend we're the CARNISAC...
# (The ISAC for Carnivals, Circuses, Amusement Parks, and Licensed Games of Chance, natch.)

isac_producer = Identity(name="CARNISAC", identity_class="organization", 
                         id="identity--3d368fac-7e96-4c66-b46c-8c763194a523")

# Now, let's publish an indicator...
indicator = Indicator(name="File hash for malware variant", 
                      pattern="[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']",
                      created_by_ref="identity--3d368fac-7e96-4c66-b46c-8c763194a523",
                      indicator_types=["malicious-activity",],
                      lang="en",
                      confidence=95)

# Next, let's create a language content object for our indicator...
indicator_trans = LanguageContent(object_ref=indicator.id, object_modified=indicator.modified, 
    contents={
        "fr": {"name": "Fichier hash pour la variante du malware"},
        "nl": {"name": "Bestandshash voor malware-variant"},
        "de": {"name": "Dateihash für Malware-Variante"},
        "zh": {"name": "文件散列用於惡意軟件變體"},
        "ru": {"name": "Хэш файла для варианта вредоносного ПО"},
        "ja": {"name": "マルウェアバリアントのファイルハッシュ"},
        "eo": {"name": "Dosiero hash por malware varianto"},
        "ar": {"name": "تجزئة ملف لبرامج ضارة مختلفة"}
        },
    created_by_ref="identity--3d368fac-7e96-4c66-b46c-8c763194a523")
# Let's see how that looks...
print(indicator_trans)
# Next, let's pretend that the elite CARNISAC analysts are ready to do some attribution...
threat_actor = ThreatActor(name="Doctor Evil",
                           threat_actor_types=["terrorist",],
                           created_by_ref="identity--3d368fac-7e96-4c66-b46c-8c763194a523",
                           confidence=95)

campaign = Campaign(name="Blow-up the moon",
                    created_by_ref="identity--3d368fac-7e96-4c66-b46c-8c763194a523", 
                    confidence=80)

# Of course, we need SROs to link all the SDOs together...
rel1 = Relationship(source_ref=campaign.id,
                    target_ref=threat_actor.id,
                    relationship_type="attributed-to",
                    created_by_ref="identity--3d368fac-7e96-4c66-b46c-8c763194a523",
                    confidence=75)

rel2 = Relationship(source_ref=indicator.id,
                    target_ref=threat_actor.id, relationship_type="indicates",
                    created_by_ref="identity--3d368fac-7e96-4c66-b46c-8c763194a523",
                    confidence=70)
# Let's see how that looks...
print(threat_actor, campaign, rel1, rel2)
# Now let's make up some fictitious CARNISAC member organizations
company_foo = Identity(name="Foo, Inc.", identity_class="organization", 
                       id="identity--dbc4c981-60c4-45bd-a988-b56801e484f5")

company_bar = Identity(name="Bar, Inc.", identity_class="organization", 
                       id="identity--26eea235-040f-46e8-b6ef-5592c88da7ed")

company_baz = Identity(name="Baz, Inc.", identity_class="organization", 
                       id="identity--31e8b302-7654-4fa5-8b1e-608222dea432")

# All these orgs have teams of crackerjack analysts with their own opinions of CARNISAC's attribution...
company_foo_opinion = Opinion(created_by_ref="identity--dbc4c981-60c4-45bd-a988-b56801e484f5",
                              object_refs=rel1.id, 
                              opinion="strongly-disagree")

company_bar_opinion = Opinion(created_by_ref="identity--26eea235-040f-46e8-b6ef-5592c88da7ed",
                              object_refs=rel1.id, 
                              opinion="agree")

company_baz_opinion = Opinion(created_by_ref="identity--31e8b302-7654-4fa5-8b1e-608222dea432",
                              object_refs=rel1.id, 
                              opinion="disagree")
# Let's compare the community's assessment with CarnISAC's own confidence on its campaign attribution...

opinion_map = {
    "strongly-disagree": 1,
    "disagree": 2,
    "neutral": 3,
    "agree": 4,
    "strongly-agree": 5
}

# Just a little helper function...
opinion_reverse_map = {v: k for k, v in opinion_map.items()}

# Determine the average community opinion...
opinions = [opinion_map[company_foo_opinion.opinion], opinion_map[company_bar_opinion.opinion], opinion_map[company_foo_opinion.opinion]]
opinion_average = sum(opinions)/(len(opinions))

print("CarnISAC's campaign attribution confidence: %i" % (rel1.confidence))
print("Average trust-group opinion of campaign attribution: %s" % (opinion_reverse_map[opinion_average]))
# But, hey, CARNISAC has an international constituency...
# Remember that LanguageContent object we created for our Indicator?
# Let's have a look at that...

from stix2.utils import new_version

# Just another little helper function...
def trans_lang(lang_content_obj, obj, lang):
    new_props = {}
    if lang in lang_content_obj.contents:
        for i in lang_content_obj.contents[lang]:
            if i in obj:
                new_props[i] = lang_content_obj.contents[lang][i]
    new_props["lang"] = lang
    trans_obj = new_version(obj, **new_props)
    return(trans_obj)

# Now, let's see how the translations work...
new_obj = trans_lang(indicator_trans, indicator, 'ja')
print(repr(new_obj))

# That's all for now, folks. Hope you enjoyed it!<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.11050080775444265, 'fraction_numerical': 0.055896607431340874, 'mean_word_length': 3.0703484549638396, 'pattern_counts': {'":': 21, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '1', 'dir': 'jupyter-structured-clean-dedup', 'id': '604398', 'license': 'MIT', 'n_tokens_mistral': 2257, 'n_tokens_neox': 1942, 'n_words': 456, 'path': 'STIX 2.1 Preview.ipynb', 'repo_name': 'treyka/stix2-jupyter', 'size': '6190'}