<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Custom STIX Content
Custom Properties
Attempting to create a STIX object with properties not defined by the specification will result in an error. Try creating an Identity object with a custom x_foo property
Step1:  To create a STIX object with one or more custom properties, pass them in as a dictionary parameter called custom_properties
Step2:  Alternatively, setting allow_custom to True will allow custom properties without requiring a custom_properties dictionary.
Step4:  Likewise, when parsing STIX content with custom properties, pass allow_custom=True to parse()
Step5:  To remove a custom properties, use new_version() and set that property to None.
Step6:  Custom STIX Object Types
To create a custom STIX object type, define a class with the @CustomObject decorator. It takes the type name and a list of property tuples, each tuple consisting of the property name and a property instance. Any special validation of the properties can be added by supplying an __init__ function.
Let's say zoo animals have become a serious cyber threat and we want to model them in STIX using a custom object type. Let's use a species property to store the kind of animal, and make that property required. We also want a property to store the class of animal, such as "mammal" or "bird" but only want to allow specific values in it. We can add some logic to validate this property in __init__.
Step7:  Now we can create an instance of our custom Animal type.
Step8:  Trying to create an Animal instance with an animal_class that's not in the list will result in an error
Step10:  Parsing custom object types that you have already defined is simple and no different from parsing any other STIX object.
Step12:  However, parsing custom object types which you have not defined will result in an error
Step13:  Custom Cyber Observable Types
Similar to custom STIX object types, use a decorator to create custom Cyber Observable types. Just as before, __init__() can hold additional validation, but it is not necessary.
Step15:  Likewise, after the custom Cyber Observable type has been defined, it can be parsed.
Step16:  ID-Contributing Properties for Custom Cyber Observables
STIX 2.1 Cyber Observables (SCOs) have deterministic IDs, meaning that the ID of a SCO is based on the values of some of its properties. Thus, if multiple cyber observables of the same type have the same values for their ID-contributing properties, then these SCOs will have the same ID. UUIDv5 is used for the deterministic IDs, using the namespace "00abedb4-aa42-466c-9c01-fed23315a9b7". A SCO's ID-contributing properties may consist of a combination of required properties and optional properties.
If a SCO type does not have any ID contributing properties defined, or all of the ID-contributing properties are not present on the object, then the SCO uses a randomly-generated UUIDv4. Thus, you can optionally define which of your custom SCO's properties should be ID-contributing properties. Similar to standard SCOs, your custom SCO's ID-contributing properties can be any combination of the SCO's required and optional properties.
You define the ID-contributing properties when defining your custom SCO with the CustomObservable decorator. After the list of properties, you can optionally define the list of id-contributing properties. If you do not want to specify any id-contributing properties for your custom SCO, then you do not need to do anything additional.
See the example below
Step17:  In this example, a_property is the only id-contributing property. Notice that the ID for new_observable_a and new_observable_b is the same since they have the same value for the id-contributing a_property property.
Custom Cyber Observable Extensions
Finally, custom extensions to existing Cyber Observable types can also be created. Just use the @CustomExtension decorator. Note that you must provide the Cyber Observable class to which the extension applies. Again, any extra validation of the properties can be implemented by providing an __init__() but it is not required. Let's say we want to make an extension to the File Cyber Observable Object
Step19:  Once the custom Cyber Observable extension has been defined, it can be parsed.
<ASSISTANT_TASK:>
Python Code:
from stix2 import Identity
Identity(name="John Smith",
         identity_class="individual",
         x_foo="bar")
Explanation: Custom STIX Content
Custom Properties
Attempting to create a STIX object with properties not defined by the specification will result in an error. Try creating an Identity object with a custom x_foo property:
End of explanation
identity = Identity(name="John Smith",
                    identity_class="individual",
                    custom_properties={
                        "x_foo": "bar"
                    })
print(identity.serialize(pretty=True))
Explanation: To create a STIX object with one or more custom properties, pass them in as a dictionary parameter called custom_properties:
End of explanation
identity2 = Identity(name="John Smith",
                     identity_class="individual",
                     x_foo="bar",
                     allow_custom=True)
print(identity2.serialize(pretty=True))
Explanation: Alternatively, setting allow_custom to True will allow custom properties without requiring a custom_properties dictionary.
End of explanation
from stix2 import parse
input_string = {
    "type": "identity",
    "spec_version": "2.1",
    "id": "identity--311b2d2d-f010-4473-83ec-1edf84858f4c",
    "created": "2015-12-21T19:59:11Z",
    "modified": "2015-12-21T19:59:11Z",
    "name": "John Smith",
    "identity_class": "individual",
    "x_foo": "bar"
}
identity3 = parse(input_string, allow_custom=True)
print(identity3.x_foo)
Explanation: Likewise, when parsing STIX content with custom properties, pass allow_custom=True to parse():
End of explanation
identity4 = identity3.new_version(x_foo=None)
print(identity4.serialize(pretty=True))
Explanation: To remove a custom properties, use new_version() and set that property to None.
End of explanation
from stix2 import CustomObject, properties
@CustomObject('x-animal', [
    ('species', properties.StringProperty(required=True)),
    ('animal_class', properties.StringProperty()),
])
class Animal(object):
    def __init__(self, animal_class=None, **kwargs):
        if animal_class and animal_class not in ['mammal', 'bird', 'fish', 'reptile']:
            raise ValueError("'%s' is not a recognized class of animal." % animal_class)
Explanation: Custom STIX Object Types
To create a custom STIX object type, define a class with the @CustomObject decorator. It takes the type name and a list of property tuples, each tuple consisting of the property name and a property instance. Any special validation of the properties can be added by supplying an __init__ function.
Let's say zoo animals have become a serious cyber threat and we want to model them in STIX using a custom object type. Let's use a species property to store the kind of animal, and make that property required. We also want a property to store the class of animal, such as "mammal" or "bird" but only want to allow specific values in it. We can add some logic to validate this property in __init__.
End of explanation
animal = Animal(species="lion",
                animal_class="mammal")
print(animal.serialize(pretty=True))
Explanation: Now we can create an instance of our custom Animal type.
End of explanation
Animal(species="xenomorph",
       animal_class="alien")
Explanation: Trying to create an Animal instance with an animal_class that's not in the list will result in an error:
End of explanation
input_string2 = {
    "type": "x-animal",
    "id": "x-animal--941f1471-6815-456b-89b8-7051ddf13e4b",
    "created": "2015-12-21T19:59:11Z",
    "modified": "2015-12-21T19:59:11Z",
    "spec_version": "2.1",
    "species": "shark",
    "animal_class": "fish"
}
animal2 = parse(input_string2)
print(animal2.species)
Explanation: Parsing custom object types that you have already defined is simple and no different from parsing any other STIX object.
End of explanation
input_string3 = {
    "type": "x-foobar",
    "id": "x-foobar--d362beb5-a04e-4e6b-a030-b6935122c3f9",
    "created": "2015-12-21T19:59:11Z",
    "modified": "2015-12-21T19:59:11Z",
    "bar": 1,
    "baz": "frob"
}
parse(input_string3)
Explanation: However, parsing custom object types which you have not defined will result in an error:
End of explanation
from stix2 import CustomObservable
@CustomObservable('x-new-observable', [
    ('a_property', properties.StringProperty(required=True)),
    ('property_2', properties.IntegerProperty()),
])
class NewObservable():
    pass
new_observable = NewObservable(a_property="something",
                               property_2=10)
print(new_observable.serialize(pretty=True))
Explanation: Custom Cyber Observable Types
Similar to custom STIX object types, use a decorator to create custom Cyber Observable types. Just as before, __init__() can hold additional validation, but it is not necessary.
End of explanation
from stix2 import ObservedData
input_string4 = {
    "type": "observed-data",
    "id": "observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf",
    "spec_version": "2.1",
    "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
    "created": "2016-04-06T19:58:16.000Z",
    "modified": "2016-04-06T19:58:16.000Z",
    "first_observed": "2015-12-21T19:00:00Z",
    "last_observed": "2015-12-21T19:00:00Z",
    "number_observed": 50,
    "objects": {
        "0": {
            "type": "x-new-observable",
            "a_property": "foobaz",
            "property_2": 5
        }
    }
}
obs_data = parse(input_string4)
print(obs_data.objects["0"].a_property)
print(obs_data.objects["0"].property_2)
Explanation: Likewise, after the custom Cyber Observable type has been defined, it can be parsed.
End of explanation
from stix2 import CustomObservable
@CustomObservable('x-new-observable-2', [
    ('a_property', properties.StringProperty(required=True)),
    ('property_2', properties.IntegerProperty()),
], [
    'a_property'
])
class NewObservable2():
    pass
new_observable_a = NewObservable2(a_property="A property", property_2=2000)
print(new_observable_a.serialize(pretty=True))
new_observable_b = NewObservable2(a_property="A property", property_2=3000)
print(new_observable_b.serialize(pretty=True))
new_observable_c = NewObservable2(a_property="A different property", property_2=3000)
print(new_observable_c.serialize(pretty=True))
Explanation: ID-Contributing Properties for Custom Cyber Observables
STIX 2.1 Cyber Observables (SCOs) have deterministic IDs, meaning that the ID of a SCO is based on the values of some of its properties. Thus, if multiple cyber observables of the same type have the same values for their ID-contributing properties, then these SCOs will have the same ID. UUIDv5 is used for the deterministic IDs, using the namespace "00abedb4-aa42-466c-9c01-fed23315a9b7". A SCO's ID-contributing properties may consist of a combination of required properties and optional properties.
If a SCO type does not have any ID contributing properties defined, or all of the ID-contributing properties are not present on the object, then the SCO uses a randomly-generated UUIDv4. Thus, you can optionally define which of your custom SCO's properties should be ID-contributing properties. Similar to standard SCOs, your custom SCO's ID-contributing properties can be any combination of the SCO's required and optional properties.
You define the ID-contributing properties when defining your custom SCO with the CustomObservable decorator. After the list of properties, you can optionally define the list of id-contributing properties. If you do not want to specify any id-contributing properties for your custom SCO, then you do not need to do anything additional.
See the example below:
End of explanation
from stix2 import CustomExtension
@CustomExtension('x-new-ext', [
    ('property1', properties.StringProperty(required=True)),
    ('property2', properties.IntegerProperty()),
])
class NewExtension():
    pass
new_ext = NewExtension(property1="something",
                       property2=10)
print(new_ext.serialize(pretty=True))
Explanation: In this example, a_property is the only id-contributing property. Notice that the ID for new_observable_a and new_observable_b is the same since they have the same value for the id-contributing a_property property.
Custom Cyber Observable Extensions
Finally, custom extensions to existing Cyber Observable types can also be created. Just use the @CustomExtension decorator. Note that you must provide the Cyber Observable class to which the extension applies. Again, any extra validation of the properties can be implemented by providing an __init__() but it is not required. Let's say we want to make an extension to the File Cyber Observable Object:
End of explanation
input_string5 = {
    "type": "observed-data",
    "id": "observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf",
    "spec_version": "2.1",
    "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
    "created": "2016-04-06T19:58:16.000Z",
    "modified": "2016-04-06T19:58:16.000Z",
    "first_observed": "2015-12-21T19:00:00Z",
    "last_observed": "2015-12-21T19:00:00Z",
    "number_observed": 50,
    "objects": {
        "0": {
            "type": "file",
            "name": "foo.bar",
            "hashes": {
                "SHA-256": "35a01331e9ad96f751278b891b6ea09699806faedfa237d40513d92ad1b7100f"
            },
            "extensions": {
                "x-new-ext": {
                    "property1": "bla",
                    "property2": 50
                }
            }
        }
    }
}
obs_data2 = parse(input_string5)
print(obs_data2.objects["0"].extensions["x-new-ext"].property1)
print(obs_data2.objects["0"].extensions["x-new-ext"].property2)
Explanation: Once the custom Cyber Observable extension has been defined, it can be parsed.
End of explanation
<END_TASK>