From fb49687b08cf55edbbf3f0a344816b737a4f39cb Mon Sep 17 00:00:00 2001
From: Darshan Patel
+
The other field expects a json string, which can have the key value pairs of any field which the search API supports.
The MISP API doesn't support paging, but it is possible to work around this. By giving max results as a negative number, n, it will take the last n results from the query. From there, you can take the timestamp from the first object in the resulting list, then pass it in the other field like so: {\"timestamp\": <timestamp + 1>}. All the results will now be after that specified timestamp.
Also note that when searching for events, events with no attributes will not be returned.",
+ "verbose": "By setting max_results to 0, you can get every result. It is recommended you do not do this, as MISP can return a lot of data. The default is 10, and this will be the oldest 10 results.
The other field expects a json string, which can have the key value pairs of any field which the search API supports.
The MISP API doesn't support paging, but it is possible to work around this. By giving max results as a negative number, n, it will take the last n results from the query. From there, you can take the timestamp from the first object in the resulting list, then pass it in the other field like so: {\"timestamp\": <timestamp + 1>}. All the results will now be after that specified timestamp.
Also note that when searching for events, events with no attributes will not be returned.",
"type": "investigate",
"identifier": "run_query",
"read_only": true,
@@ -645,7 +1005,7 @@
"misp event id"
],
"order": 2,
- "allow_list": true
+ "primary": true
},
"tags": {
"description": "Comma seperated list of tags",
@@ -701,531 +1061,941 @@
"data_type": "string"
},
{
- "data_path": "action_result.parameter.tags",
+ "data_path": "action_result.parameter.tags",
+ "data_type": "string",
+ "example_values": [
+ "test_1"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.Attribute.*.Event.distribution",
+ "data_type": "string",
+ "example_values": [
+ "1"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.Attribute.*.Event.id",
+ "data_type": "string",
+ "example_values": [
+ "2020"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.Attribute.*.Event.info",
+ "data_type": "string",
+ "example_values": [
+ "Event created by test"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.Attribute.*.Event.org_id",
+ "data_type": "string",
+ "example_values": [
+ "1"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.Attribute.*.Event.orgc_id",
+ "data_type": "string",
+ "example_values": [
+ "1"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.Attribute.*.Event.uuid",
+ "data_type": "string",
+ "example_values": [
+ "342c12ab-32ad-41d0-aea2-1c3dccc6ce09"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.Attribute.*.Object.distribution",
+ "data_type": "string",
+ "example_values": [
+ "5"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.Attribute.*.Object.id",
+ "data_type": "string",
+ "example_values": [
+ "10"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.Attribute.*.Object.sharing_group_id",
+ "data_type": "string",
+ "example_values": [
+ "0"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.Attribute.*.category",
+ "data_type": "string",
+ "example_values": [
+ "Other",
+ "Payload delivery"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.Attribute.*.comment",
+ "data_type": "string"
+ },
+ {
+ "data_path": "action_result.data.*.Attribute.*.deleted",
+ "data_type": "numeric",
+ "example_values": [
+ true,
+ false
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.Attribute.*.disable_correlation",
+ "data_type": "numeric",
+ "example_values": [
+ false,
+ true
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.Attribute.*.distribution",
+ "data_type": "string",
+ "example_values": [
+ "5"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.Attribute.*.event_id",
+ "data_type": "string",
+ "example_values": [
+ "1"
+ ],
+ "contains": [
+ "misp event id"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.Attribute.*.first_seen",
+ "data_type": "string"
+ },
+ {
+ "data_path": "action_result.data.*.Attribute.*.id",
+ "data_type": "string",
+ "example_values": [
+ "164201"
+ ],
+ "contains": [
+ "misp attribute id"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.Attribute.*.last_seen",
+ "data_type": "string"
+ },
+ {
+ "data_path": "action_result.data.*.Attribute.*.object_id",
+ "data_type": "string",
+ "example_values": [
+ "0",
+ "10"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.Attribute.*.object_relation",
+ "data_type": "string",
+ "example_values": [
+ "filename"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.Attribute.*.sharing_group_id",
+ "data_type": "string",
+ "example_values": [
+ "0"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.Attribute.*.timestamp",
+ "data_type": "string",
+ "example_values": [
+ "1498505296"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.Attribute.*.to_ids",
+ "data_type": "boolean",
+ "example_values": [
+ true,
+ false
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.Attribute.*.type",
+ "data_type": "string",
+ "example_values": [
+ "comment",
+ "filename"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.Attribute.*.uuid",
+ "data_type": "string",
+ "example_values": [
+ "56e96919-ad18-4f68-8aa1-539002de0b81"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.Attribute.*.value",
+ "data_type": "string",
+ "contains": [
+ "url",
+ "domain",
+ "ip",
+ "email",
+ "hash",
+ "md5",
+ "sha256",
+ "md1"
+ ],
+ "example_values": [
+ "email1@gmail.com"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.*.Event.id",
+ "data_type": "string",
+ "example_values": [
+ "1"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.*.Event.Org.id",
+ "data_type": "string",
+ "example_values": [
+ "1"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.*.Event.Org.name",
+ "data_type": "string",
+ "example_values": [
+ "ORGNAME"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.*.Event.Org.uuid",
+ "data_type": "string",
+ "example_values": [
+ "2af87aa3-a713-4ca5-83f7-03ae949c8459"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.*.Event.Org.local",
+ "data_type": "numeric",
+ "example_values": [
+ true,
+ false
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.*.Event.Orgc.id",
+ "data_type": "string",
+ "example_values": [
+ "1"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.*.Event.Orgc.name",
+ "data_type": "string",
+ "example_values": [
+ "ORGNAME"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.*.Event.Orgc.uuid",
+ "data_type": "string",
+ "example_values": [
+ "2af87aa3-a713-4ca5-83f7-03ae949c8459"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.*.Event.Orgc.local",
+ "data_type": "numeric",
+ "example_values": [
+ true,
+ false
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.*.Event.date",
+ "data_type": "string",
+ "example_values": [
+ "2021-03-17"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.*.Event.info",
+ "data_type": "string",
+ "example_values": [
+ "Event created by test"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.*.Event.uuid",
+ "data_type": "string",
+ "example_values": [
+ "15483d56-fc32-4e54-a8b4-e9f56e7818bd"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.*.Event.locked",
+ "data_type": "numeric",
+ "example_values": [
+ true,
+ false
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.*.Event.org_id",
+ "data_type": "string",
+ "example_values": [
+ "1"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.*.Event.orgc_id",
+ "data_type": "string",
+ "example_values": [
+ "1"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.*.Event.analysis",
+ "data_type": "string",
+ "example_values": [
+ "0"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.*.Event.Attribute.*.id",
+ "data_type": "string",
+ "example_values": [
+ "4265"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.*.Event.Attribute.*.type",
+ "data_type": "string",
+ "example_values": [
+ "email-dst"
+ ],
+ "contains": [
+ "url"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.*.Event.Attribute.*.uuid",
+ "data_type": "string",
+ "example_values": [
+ "03fa856e-b6f9-4e34-82ac-1e50dd058f37"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.*.Event.Attribute.*.value",
+ "data_type": "string",
+ "example_values": [
+ "abc@abc.com"
+ ],
+ "contains": [
+ "url",
+ "domain",
+ "ip",
+ "email",
+ "hash",
+ "md5",
+ "sha256",
+ "md1"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.*.Event.Attribute.*.to_ids",
+ "data_type": "numeric",
+ "example_values": [
+ true,
+ false
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.*.Event.Attribute.*.comment",
+ "data_type": "string"
+ },
+ {
+ "data_path": "action_result.data.*.*.Event.Attribute.*.deleted",
+ "data_type": "numeric",
+ "example_values": [
+ true,
+ false
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.*.Event.Attribute.*.category",
+ "data_type": "string",
+ "example_values": [
+ "Network activity"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.*.Event.Attribute.*.event_id",
+ "data_type": "string",
+ "example_values": [
+ "1"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.*.Event.Attribute.*.last_seen",
+ "data_type": "string"
+ },
+ {
+ "data_path": "action_result.data.*.*.Event.Attribute.*.object_id",
+ "data_type": "string",
+ "example_values": [
+ "0"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.*.Event.Attribute.*.timestamp",
+ "data_type": "string",
+ "example_values": [
+ "1622191169"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.*.Event.Attribute.*.first_seen",
"data_type": "string"
},
{
- "data_path": "action_result.data.*.response.*.Event.Attribute.*.category",
+ "data_path": "action_result.data.*.*.Event.Attribute.*.distribution",
"data_type": "string",
"example_values": [
- "External analysis"
+ "5"
]
},
{
- "data_path": "action_result.data.*.response.*.Event.Attribute.*.comment",
+ "data_path": "action_result.data.*.*.Event.Attribute.*.object_relation",
"data_type": "string"
},
{
- "data_path": "action_result.data.*.response.*.Event.Attribute.*.deleted",
- "data_type": "boolean",
+ "data_path": "action_result.data.*.*.Event.Attribute.*.sharing_group_id",
+ "data_type": "string",
+ "example_values": [
+ "0"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.*.Event.Attribute.*.disable_correlation",
+ "data_type": "numeric",
"example_values": [
true,
false
]
},
{
- "data_path": "action_result.data.*.response.*.Event.Attribute.*.disable_correlation",
- "data_type": "boolean",
+ "data_path": "action_result.data.*.*.Event.published",
+ "data_type": "numeric",
"example_values": [
true,
false
]
},
{
- "data_path": "action_result.data.*.response.*.Event.Attribute.*.distribution",
+ "data_path": "action_result.data.*.*.Event.timestamp",
"data_type": "string",
"example_values": [
- "5"
+ "1623657727"
]
},
{
- "data_path": "action_result.data.*.response.*.Event.Attribute.*.event_id",
+ "data_path": "action_result.data.*.*.Event.RelatedEvent.*.Event.id",
"data_type": "string",
"example_values": [
- "1"
- ],
- "contains": [
- "misp event id"
+ "2161"
]
},
{
- "data_path": "action_result.data.*.response.*.Event.Attribute.*.id",
+ "data_path": "action_result.data.*.*.Event.RelatedEvent.*.Event.Org.id",
"data_type": "string",
"example_values": [
"1"
]
},
{
- "data_path": "action_result.data.*.response.*.Event.Attribute.*.sharing_group_id",
+ "data_path": "action_result.data.*.*.Event.RelatedEvent.*.Event.Org.name",
"data_type": "string",
"example_values": [
- "0"
+ "ORGNAME"
]
},
{
- "data_path": "action_result.data.*.response.*.Event.Attribute.*.timestamp",
+ "data_path": "action_result.data.*.*.Event.RelatedEvent.*.Event.Org.uuid",
"data_type": "string",
"example_values": [
- "1458137369"
+ "2af87aa3-a713-4ca5-83f7-03ae949c8459"
]
},
{
- "data_path": "action_result.data.*.response.*.Event.Attribute.*.to_ids",
- "data_type": "boolean",
+ "data_path": "action_result.data.*.*.Event.RelatedEvent.*.Event.Orgc.id",
+ "data_type": "string",
"example_values": [
- true,
- false
+ "1"
]
},
{
- "data_path": "action_result.data.*.response.*.Event.Attribute.*.type",
+ "data_path": "action_result.data.*.*.Event.RelatedEvent.*.Event.Orgc.name",
"data_type": "string",
"example_values": [
- "link"
+ "ORGNAME"
]
},
{
- "data_path": "action_result.data.*.response.*.Event.Attribute.*.uuid",
+ "data_path": "action_result.data.*.*.Event.RelatedEvent.*.Event.Orgc.uuid",
"data_type": "string",
"example_values": [
- "56e96919-ad18-4f68-8aa1-539002de0b81"
+ "2af87aa3-a713-4ca5-83f7-03ae949c8459"
]
},
{
- "data_path": "action_result.data.*.response.*.Event.Attribute.*.value",
+ "data_path": "action_result.data.*.*.Event.RelatedEvent.*.Event.date",
"data_type": "string",
"example_values": [
- "https://www.virustotal.com/file/b100e104a22f9670164d73679f7d4b6e5de055bf961bc4c1e9c28d2580d3f753/analysis/1458136225/"
- ],
- "contains": [
- "url",
- "ip"
+ "2021-06-14"
]
},
{
- "data_path": "action_result.data.*.response.*.Event.Org.id",
+ "data_path": "action_result.data.*.*.Event.RelatedEvent.*.Event.info",
"data_type": "string",
"example_values": [
- "1"
+ "Event created by test"
]
},
{
- "data_path": "action_result.data.*.response.*.Event.Org.name",
+ "data_path": "action_result.data.*.*.Event.RelatedEvent.*.Event.uuid",
"data_type": "string",
"example_values": [
- "MISP"
+ "f346cd43-ef47-4401-b725-a5f4f45a4ed3"
]
},
{
- "data_path": "action_result.data.*.response.*.Event.Org.uuid",
+ "data_path": "action_result.data.*.*.Event.RelatedEvent.*.Event.org_id",
"data_type": "string",
"example_values": [
- "56ef3277-1ad4-42f6-b90b-04e5c0a83832"
+ "1"
]
},
{
- "data_path": "action_result.data.*.response.*.Event.Orgc.id",
+ "data_path": "action_result.data.*.*.Event.RelatedEvent.*.Event.orgc_id",
"data_type": "string",
"example_values": [
- "2"
+ "1"
]
},
{
- "data_path": "action_result.data.*.response.*.Event.Orgc.name",
+ "data_path": "action_result.data.*.*.Event.RelatedEvent.*.Event.analysis",
"data_type": "string",
"example_values": [
- "CIRCL"
+ "0"
]
},
{
- "data_path": "action_result.data.*.response.*.Event.Orgc.uuid",
- "data_type": "string",
+ "data_path": "action_result.data.*.*.Event.RelatedEvent.*.Event.published",
+ "data_type": "numeric",
"example_values": [
- "55f6ea5e-2c60-40e5-964f-47a8950d210f"
+ true,
+ false
]
},
{
- "data_path": "action_result.data.*.response.*.Event.RelatedEvent.*.Event.Org.id",
+ "data_path": "action_result.data.*.*.Event.RelatedEvent.*.Event.timestamp",
"data_type": "string",
"example_values": [
- "1"
+ "1623645286"
]
},
{
- "data_path": "action_result.data.*.response.*.Event.RelatedEvent.*.Event.Org.name",
+ "data_path": "action_result.data.*.*.Event.RelatedEvent.*.Event.distribution",
"data_type": "string",
"example_values": [
- "MISP"
+ "1"
]
},
{
- "data_path": "action_result.data.*.response.*.Event.RelatedEvent.*.Event.Org.uuid",
+ "data_path": "action_result.data.*.*.Event.RelatedEvent.*.Event.threat_level_id",
"data_type": "string",
"example_values": [
- "56ef3277-1ad4-42f6-b90b-04e5c0a83832"
+ "4"
]
},
{
- "data_path": "action_result.data.*.response.*.Event.RelatedEvent.*.Event.Orgc.id",
+ "data_path": "action_result.data.*.*.Event.distribution",
"data_type": "string",
"example_values": [
- "2"
+ "1"
]
},
{
- "data_path": "action_result.data.*.response.*.Event.RelatedEvent.*.Event.Orgc.name",
- "data_type": "string",
- "example_values": [
- "CIRCL"
- ]
+ "data_path": "action_result.data.*.*.Event.extends_uuid",
+ "data_type": "string"
},
{
- "data_path": "action_result.data.*.response.*.Event.RelatedEvent.*.Event.Orgc.uuid",
+ "data_path": "action_result.data.*.*.Event.attribute_count",
"data_type": "string",
"example_values": [
- "55f6ea5e-2c60-40e5-964f-47a8950d210f"
+ "7"
]
},
{
- "data_path": "action_result.data.*.response.*.Event.RelatedEvent.*.Event.analysis",
+ "data_path": "action_result.data.*.*.Event.threat_level_id",
"data_type": "string",
"example_values": [
- "2"
+ "4"
]
},
{
- "data_path": "action_result.data.*.response.*.Event.RelatedEvent.*.Event.date",
+ "data_path": "action_result.data.*.*.Event.sharing_group_id",
"data_type": "string",
"example_values": [
- "2016-06-01"
+ "0"
]
},
{
- "data_path": "action_result.data.*.response.*.Event.RelatedEvent.*.Event.distribution",
+ "data_path": "action_result.data.*.*.Event.publish_timestamp",
"data_type": "string",
"example_values": [
- "3"
+ "0"
]
},
{
- "data_path": "action_result.data.*.response.*.Event.RelatedEvent.*.Event.id",
- "data_type": "string",
+ "data_path": "action_result.data.*.*.Event.disable_correlation",
+ "data_type": "numeric",
"example_values": [
- "75"
+ true,
+ false
]
},
{
- "data_path": "action_result.data.*.response.*.Event.RelatedEvent.*.Event.info",
+ "data_path": "action_result.data.*.*.Event.event_creator_email",
"data_type": "string",
"example_values": [
- "OSINT - DRIDEX\u2019s New Tricks Lead to Global Spam Outbreak"
+ "test@test.com"
+ ],
+ "contains": [
+ "email"
]
},
{
- "data_path": "action_result.data.*.response.*.Event.RelatedEvent.*.Event.org_id",
- "data_type": "string",
+ "data_path": "action_result.data.*.*.Event.proposal_email_lock",
+ "data_type": "numeric",
"example_values": [
- "1"
+ true,
+ false
]
},
{
- "data_path": "action_result.data.*.response.*.Event.RelatedEvent.*.Event.orgc_id",
+ "data_path": "action_result.data.*.*.Event.Tag.*.id",
"data_type": "string",
"example_values": [
- "2"
+ "8"
]
},
{
- "data_path": "action_result.data.*.response.*.Event.RelatedEvent.*.Event.published",
- "data_type": "boolean",
+ "data_path": "action_result.data.*.*.Event.Tag.*.name",
+ "data_type": "string",
"example_values": [
- true,
- false
+ "test_1"
]
},
{
- "data_path": "action_result.data.*.response.*.Event.RelatedEvent.*.Event.threat_level_id",
- "data_type": "string",
+ "data_path": "action_result.data.*.*.Event.Tag.*.local",
+ "data_type": "numeric",
"example_values": [
- "3"
+ 1
]
},
{
- "data_path": "action_result.data.*.response.*.Event.RelatedEvent.*.Event.timestamp",
+ "data_path": "action_result.data.*.*.Event.Tag.*.colour",
"data_type": "string",
"example_values": [
- "1464784644"
+ "#7ab870"
]
},
{
- "data_path": "action_result.data.*.response.*.Event.RelatedEvent.*.Event.uuid",
+ "data_path": "action_result.data.*.*.Event.Tag.*.user_id",
"data_type": "string",
"example_values": [
- "574ed4d9-83c0-4422-a492-423e950d210f"
+ "1"
]
},
{
- "data_path": "action_result.data.*.response.*.Event.Tag.*.colour",
- "data_type": "string",
+ "data_path": "action_result.data.*.*.Event.Tag.*.hide_tag",
+ "data_type": "numeric",
"example_values": [
- "#3d7a00"
+ true,
+ false
]
},
{
- "data_path": "action_result.data.*.response.*.Event.Tag.*.exportable",
- "data_type": "boolean",
+ "data_path": "action_result.data.*.*.Event.Tag.*.is_galaxy",
+ "data_type": "numeric",
"example_values": [
true,
false
]
},
{
- "data_path": "action_result.data.*.response.*.Event.Tag.*.hide_tag",
- "data_type": "boolean",
+ "data_path": "action_result.data.*.*.Event.Tag.*.exportable",
+ "data_type": "numeric",
"example_values": [
true,
false
]
},
{
- "data_path": "action_result.data.*.response.*.Event.Tag.*.id",
- "data_type": "string",
- "example_values": [
- "1"
- ]
+ "data_path": "action_result.data.*.*.Event.Tag.*.numerical_value",
+ "data_type": "string"
},
{
- "data_path": "action_result.data.*.response.*.Event.Tag.*.name",
- "data_type": "string",
+ "data_path": "action_result.data.*.*.Event.Tag.*.is_custom_galaxy",
+ "data_type": "numeric",
"example_values": [
- "circl:incident-classification=\"malware\""
+ true,
+ false
]
},
{
- "data_path": "action_result.data.*.response.*.Event.analysis",
+ "data_path": "action_result.data.*.*.Event.Object.*.id",
"data_type": "string",
"example_values": [
- "0"
+ "10"
]
},
{
- "data_path": "action_result.data.*.response.*.Event.attribute_count",
+ "data_path": "action_result.data.*.*.Event.Object.*.name",
"data_type": "string",
"example_values": [
- "103"
+ "file"
]
},
{
- "data_path": "action_result.data.*.response.*.Event.date",
+ "data_path": "action_result.data.*.*.Event.Object.*.uuid",
"data_type": "string",
"example_values": [
- "2016-03-16"
+ "4b5cb238-9e55-40eb-b60e-b30f71cab6f6"
]
},
{
- "data_path": "action_result.data.*.response.*.Event.disable_correlation",
- "data_type": "boolean",
+ "data_path": "action_result.data.*.*.Event.Object.*.comment",
+ "data_type": "string"
+ },
+ {
+ "data_path": "action_result.data.*.*.Event.Object.*.deleted",
+ "data_type": "numeric",
"example_values": [
true,
false
]
},
{
- "data_path": "action_result.data.*.response.*.Event.distribution",
+ "data_path": "action_result.data.*.*.Event.Object.*.event_id",
"data_type": "string",
"example_values": [
- "3"
+ "2020"
]
},
{
- "data_path": "action_result.data.*.response.*.Event.id",
+ "data_path": "action_result.data.*.*.Event.Object.*.Attribute.*.id",
"data_type": "string",
"example_values": [
- "686"
- ],
- "contains": [
- "misp event id"
+ "4953"
]
},
{
- "data_path": "action_result.data.*.response.*.Event.info",
+ "data_path": "action_result.data.*.*.Event.Object.*.Attribute.*.type",
"data_type": "string",
"example_values": [
- "Dridex of the day (2016-03-16) - botnet 120"
+ "filename"
]
},
{
- "data_path": "action_result.data.*.response.*.Event.locked",
- "data_type": "boolean",
- "example_values": [
- true,
- false
- ]
- },
- {
- "data_path": "action_result.data.*.response.*.Event.org_id",
+ "data_path": "action_result.data.*.*.Event.Object.*.Attribute.*.uuid",
"data_type": "string",
"example_values": [
- "1"
+ "2fd53a9b-44fd-4ebc-af93-0e1605cf3b64"
]
},
{
- "data_path": "action_result.data.*.response.*.Event.orgc_id",
+ "data_path": "action_result.data.*.*.Event.Object.*.Attribute.*.value",
"data_type": "string",
"example_values": [
- "2"
+ "6.43.3.2"
+ ],
+ "contains": [
+ "url",
+ "domain",
+ "ip",
+ "email",
+ "hash",
+ "md5",
+ "sha256",
+ "md1"
]
},
{
- "data_path": "action_result.data.*.response.*.Event.proposal_email_lock",
- "data_type": "boolean",
+ "data_path": "action_result.data.*.*.Event.Object.*.Attribute.*.to_ids",
+ "data_type": "numeric",
"example_values": [
true,
false
]
},
{
- "data_path": "action_result.data.*.response.*.Event.publish_timestamp",
- "data_type": "string",
- "example_values": [
- "1458516898"
- ]
+ "data_path": "action_result.data.*.*.Event.Object.*.Attribute.*.comment",
+ "data_type": "string"
},
{
- "data_path": "action_result.data.*.response.*.Event.published",
- "data_type": "boolean",
+ "data_path": "action_result.data.*.*.Event.Object.*.Attribute.*.deleted",
+ "data_type": "numeric",
"example_values": [
true,
false
]
},
{
- "data_path": "action_result.data.*.response.*.Event.sharing_group_id",
+ "data_path": "action_result.data.*.*.Event.Object.*.Attribute.*.category",
"data_type": "string",
"example_values": [
- "0"
+ "Payload delivery"
]
},
{
- "data_path": "action_result.data.*.response.*.Event.threat_level_id",
+ "data_path": "action_result.data.*.*.Event.Object.*.Attribute.*.event_id",
"data_type": "string",
"example_values": [
- "3"
+ "2020"
]
},
{
- "data_path": "action_result.data.*.response.*.Event.timestamp",
+ "data_path": "action_result.data.*.*.Event.Object.*.Attribute.*.last_seen",
+ "data_type": "string"
+ },
+ {
+ "data_path": "action_result.data.*.*.Event.Object.*.Attribute.*.object_id",
"data_type": "string",
"example_values": [
- "1458139531"
+ "10"
]
},
{
- "data_path": "action_result.data.*.response.*.Event.uuid",
+ "data_path": "action_result.data.*.*.Event.Object.*.Attribute.*.timestamp",
"data_type": "string",
"example_values": [
- "56e962e9-ed10-48d8-b885-4bcd950d210f"
+ "1623078296"
]
},
{
- "data_path": "action_result.data.*.response.Attribute.*.category",
+ "data_path": "action_result.data.*.*.Event.Object.*.Attribute.*.first_seen",
+ "data_type": "string"
+ },
+ {
+ "data_path": "action_result.data.*.*.Event.Object.*.Attribute.*.distribution",
"data_type": "string",
"example_values": [
- "Targeting data"
+ "5"
]
},
{
- "data_path": "action_result.data.*.response.Attribute.*.comment",
- "data_type": "string"
+ "data_path": "action_result.data.*.*.Event.Object.*.Attribute.*.object_relation",
+ "data_type": "string",
+ "example_values": [
+ "filename"
+ ]
},
{
- "data_path": "action_result.data.*.response.Attribute.*.deleted",
- "data_type": "boolean",
+ "data_path": "action_result.data.*.*.Event.Object.*.Attribute.*.sharing_group_id",
+ "data_type": "string",
"example_values": [
- true,
- false
+ "0"
]
},
{
- "data_path": "action_result.data.*.response.Attribute.*.disable_correlation",
- "data_type": "boolean",
+ "data_path": "action_result.data.*.*.Event.Object.*.Attribute.*.disable_correlation",
+ "data_type": "numeric",
"example_values": [
true,
false
]
},
{
- "data_path": "action_result.data.*.response.Attribute.*.distribution",
- "data_type": "string",
- "example_values": [
- "3"
- ]
+ "data_path": "action_result.data.*.*.Event.Object.*.last_seen",
+ "data_type": "string"
},
{
- "data_path": "action_result.data.*.response.Attribute.*.event_id",
+ "data_path": "action_result.data.*.*.Event.Object.*.timestamp",
"data_type": "string",
"example_values": [
- "687"
- ],
- "contains": [
- "misp event id"
+ "1623078296"
]
},
{
- "data_path": "action_result.data.*.response.Attribute.*.id",
+ "data_path": "action_result.data.*.*.Event.Object.*.first_seen",
+ "data_type": "string"
+ },
+ {
+ "data_path": "action_result.data.*.*.Event.Object.*.description",
"data_type": "string",
"example_values": [
- "164201"
- ],
- "contains": [
- "misp attribute id"
+ "File object describing a file with meta-information"
]
},
{
- "data_path": "action_result.data.*.response.Attribute.*.sharing_group_id",
+ "data_path": "action_result.data.*.*.Event.Object.*.distribution",
"data_type": "string",
"example_values": [
- "0"
+ "5"
]
},
{
- "data_path": "action_result.data.*.response.Attribute.*.timestamp",
+ "data_path": "action_result.data.*.*.Event.Object.*.meta-category",
"data_type": "string",
"example_values": [
- "1498505296"
+ "file"
]
},
{
- "data_path": "action_result.data.*.response.Attribute.*.to_ids",
- "data_type": "boolean",
+ "data_path": "action_result.data.*.*.Event.Object.*.template_uuid",
+ "data_type": "string",
"example_values": [
- true,
- false
+ "688c46fb-5edb-40a3-8273-1af7923e2215"
]
},
{
- "data_path": "action_result.data.*.response.Attribute.*.type",
+ "data_path": "action_result.data.*.*.Event.Object.*.sharing_group_id",
"data_type": "string",
"example_values": [
- "target-email"
+ "0"
]
},
{
- "data_path": "action_result.data.*.response.Attribute.*.uuid",
+ "data_path": "action_result.data.*.*.Event.Object.*.template_version",
"data_type": "string",
"example_values": [
- "59516050-23d4-4b71-b5e4-6b230a10000d"
+ "24"
]
},
{
- "data_path": "action_result.data.*.response.Attribute.*.value",
+ "data_path": "action_result.data.*.attribute_count",
"data_type": "string",
"example_values": [
- "test@test.com"
- ],
- "contains": [
- "ip",
- "email"
+ "103"
]
},
{
@@ -1234,7 +2004,10 @@
},
{
"data_path": "action_result.message",
- "data_type": "string"
+ "data_type": "string",
+ "example_values": [
+ "Successfully ran query"
+ ]
},
{
"data_path": "summary.total_objects",
@@ -1263,7 +2036,7 @@
"parameters": {
"event_id": {
"description": "An Event ID",
- "data_type": "string",
+ "data_type": "numeric",
"contains": [
"misp event id"
],
@@ -1303,16 +2076,83 @@
},
{
"data_path": "action_result.parameter.event_id",
- "data_type": "string",
+ "data_type": "numeric",
"example_values": [
- "686"
+ 686
],
"contains": [
"misp event id"
]
},
{
- "data_path": "action_result.data.*.response.Attribute.*.category",
+ "data_path": "action_result.data.*.Attribute.*.Event.distribution",
+ "data_type": "string",
+ "example_values": [
+ "1"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.Attribute.*.Event.id",
+ "data_type": "string",
+ "contains": [
+ "misp event id"
+ ],
+ "example_values": [
+ "2028"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.Attribute.*.Event.info",
+ "data_type": "string",
+ "example_values": [
+ "Event created by test"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.Attribute.*.Event.org_id",
+ "data_type": "string",
+ "example_values": [
+ "1"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.Attribute.*.Event.orgc_id",
+ "data_type": "string",
+ "example_values": [
+ "1"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.Attribute.*.Event.uuid",
+ "data_type": "string",
+ "example_values": [
+ "552d93e4-fa0d-48cb-810e-a5f56c0af5ea",
+ "342c12ab-32ad-41d0-aea2-1c3dccc6ce09"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.Attribute.*.Object.distribution",
+ "data_type": "string",
+ "example_values": [
+ "5"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.Attribute.*.Object.id",
+ "data_type": "string",
+ "example_values": [
+ "10"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.Attribute.*.Object.sharing_group_id",
+ "data_type": "string",
+ "example_values": [
+ "0"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.Attribute.*.category",
"data_type": "string",
"example_values": [
"Network activity"
@@ -1321,13 +2161,13 @@
"column_name": "Category"
},
{
- "data_path": "action_result.data.*.response.Attribute.*.comment",
+ "data_path": "action_result.data.*.Attribute.*.comment",
"data_type": "string",
"column_order": 3,
"column_name": "Comment"
},
{
- "data_path": "action_result.data.*.response.Attribute.*.deleted",
+ "data_path": "action_result.data.*.Attribute.*.deleted",
"data_type": "boolean",
"example_values": [
false,
@@ -1335,7 +2175,7 @@
]
},
{
- "data_path": "action_result.data.*.response.Attribute.*.disable_correlation",
+ "data_path": "action_result.data.*.Attribute.*.disable_correlation",
"data_type": "boolean",
"example_values": [
false,
@@ -1343,42 +2183,71 @@
]
},
{
- "data_path": "action_result.data.*.response.Attribute.*.distribution",
+ "data_path": "action_result.data.*.Attribute.*.distribution",
"data_type": "string",
"example_values": [
"5"
]
},
{
- "data_path": "action_result.data.*.response.Attribute.*.event_id",
+ "data_path": "action_result.data.*.Attribute.*.event_id",
"data_type": "string",
+ "contains": [
+ "misp event id"
+ ],
"example_values": [
"686"
]
},
{
- "data_path": "action_result.data.*.response.Attribute.*.id",
+ "data_path": "action_result.data.*.Attribute.*.first_seen",
+ "data_type": "string"
+ },
+ {
+ "data_path": "action_result.data.*.Attribute.*.id",
"data_type": "string",
+ "contains": [
+ "misp attribute id"
+ ],
"example_values": [
"164191"
]
},
{
- "data_path": "action_result.data.*.response.Attribute.*.sharing_group_id",
+ "data_path": "action_result.data.*.Attribute.*.last_seen",
+ "data_type": "string"
+ },
+ {
+ "data_path": "action_result.data.*.Attribute.*.object_id",
+ "data_type": "string",
+ "example_values": [
+ "0",
+ "10"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.Attribute.*.object_relation",
+ "data_type": "string",
+ "example_values": [
+ "filename"
+ ]
+ },
+ {
+ "data_path": "action_result.data.*.Attribute.*.sharing_group_id",
"data_type": "string",
"example_values": [
"0"
]
},
{
- "data_path": "action_result.data.*.response.Attribute.*.timestamp",
+ "data_path": "action_result.data.*.Attribute.*.timestamp",
"data_type": "string",
"example_values": [
"1498002097"
]
},
{
- "data_path": "action_result.data.*.response.Attribute.*.to_ids",
+ "data_path": "action_result.data.*.Attribute.*.to_ids",
"data_type": "boolean",
"example_values": [
true,
@@ -1386,7 +2255,7 @@
]
},
{
- "data_path": "action_result.data.*.response.Attribute.*.type",
+ "data_path": "action_result.data.*.Attribute.*.type",
"data_type": "string",
"example_values": [
"ip-src"
@@ -1395,15 +2264,25 @@
"column_name": "Type"
},
{
- "data_path": "action_result.data.*.response.Attribute.*.uuid",
+ "data_path": "action_result.data.*.Attribute.*.uuid",
"data_type": "string",
"example_values": [
"5949b2b1-35b4-4152-a633-7e530a10000d"
]
},
{
- "data_path": "action_result.data.*.response.Attribute.*.value",
+ "data_path": "action_result.data.*.Attribute.*.value",
"data_type": "string",
+ "contains": [
+ "url",
+ "domain",
+ "ip",
+ "email",
+ "hash",
+ "md5",
+ "sha256",
+ "md1"
+ ],
"example_values": [
"192.162.8.1"
],
@@ -1416,7 +2295,10 @@
},
{
"data_path": "action_result.message",
- "data_type": "string"
+ "data_type": "string",
+ "example_values": [
+ "Successfully retrieved attributes"
+ ]
},
{
"data_path": "summary.total_objects",
diff --git a/misp_connector.py b/misp_connector.py
index f5b0f31..ab15d14 100644
--- a/misp_connector.py
+++ b/misp_connector.py
@@ -17,10 +17,12 @@
import phantom.rules as ph_rules
# Imports local to this App
+from misp_consts import *
import json
import requests
from bs4 import BeautifulSoup
-from pymisp import PyMISP
+from pymisp import PyMISP, MISPEvent
+import ipaddress
# This patching is required because the PyMISP API sets the verify flag as a
@@ -77,86 +79,118 @@ def __init__(self):
self._verify = None
self._event = None
- def _validate_ip(self, input_data):
+ def _validate_integer(self, action_result, parameter, key, allow_zero=False):
+ if parameter is not None:
+ try:
+ if not float(parameter).is_integer():
+ return action_result.set_status(phantom.APP_ERROR, MISP_INVALID_INT_ERR.format(msg='', param=key)), None
+
+ parameter = int(parameter)
+ except Exception:
+ return action_result.set_status(phantom.APP_ERROR, MISP_INVALID_INT_ERR.format(msg='', param=key)), None
+
+ if parameter < 0:
+ return action_result.set_status(phantom.APP_ERROR, MISP_INVALID_INT_ERR.format(msg='non-negative', param=key)), None
+ if not allow_zero and parameter == 0:
+ return action_result.set_status(phantom.APP_ERROR, MISP_INVALID_INT_ERR.format(msg='non-zero positive', param=key)), None
+
+ return phantom.APP_SUCCESS, parameter
+
+ def _get_error_message_from_exception(self, e):
+ """ This function is used to get appropriate error message from the exception.
+ :param e: Exception object
+ :return: error message
+ """
+ error_msg = MISP_ERR_MESSAGE
+ error_code = MISP_ERR_CODE_MESSAGE
+ try:
+ if e.args:
+ if len(e.args) > 1:
+ error_code = e.args[0]
+ error_msg = e.args[1]
+ elif len(e.args) == 1:
+ error_msg = e.args[0]
+ except Exception:
+ pass
+ return "Error Code: {0}. Error Message: {1}".format(error_code, error_msg)
+
+ def _validate_ip(self, input_data):
ips = []
- # First work on the comma as the seperator
- if type(input_data) is list:
- ips = input_data
- elif (',' in input_data):
- ips = input_data.split(',')
- elif(';' in input_data):
- ips = input_data.split(';')
+ if ';' in input_data:
+ ips = list(filter(None, input_data.split(';')))
+
+ else:
+ ips = phantom.get_list_from_string(input_data)
for ip in ips:
- if (not ph_utils.is_ip(ip.strip())):
+ try:
+ ipaddress.ip_address(ip.strip())
+ except Exception:
return False
+
return True
def _validate_domain(self, input_data):
-
domains = []
- # First work on the comma as the seperator
- if (',' in input_data):
- domains = input_data.split(',')
- elif(';' in input_data):
- domains = input_data.split(';')
+ if ';' in input_data:
+ domains = list(filter(None, input_data.split(';')))
+ else:
+ domains = phantom.get_list_from_string(input_data)
for domain in domains:
- if (not ph_utils.is_domain(domain.strip())):
+ if not ph_utils.is_domain(domain.strip()):
return False
return True
def _validate_email(self, input_data):
-
emails = []
- # First work on the comma as the seperator
- if (',' in input_data):
- emails = input_data.split(',')
- elif(';' in input_data):
- emails = input_data.split(';')
+ if ';' in input_data:
+ emails = list(filter(None, input_data.split(';')))
+ else:
+ emails = phantom.get_list_from_string(input_data)
for email in emails:
- if (not ph_utils.is_email(email.strip())):
+ if not ph_utils.is_email(email.strip()):
return False
return True
def _validate_url(self, input_data):
-
urls = []
- # First work on the comma as the seperator
- if (',' in input_data):
- urls = input_data.split(',')
- elif(';' in input_data):
- urls = input_data.split(';')
+ if ';' in input_data:
+ urls = list(filter(None, input_data.split(';')))
+ else:
+ urls = phantom.get_list_from_string(input_data)
for url in urls:
- if (not ph_utils.is_url(url.strip())):
+ if not ph_utils.is_url(url.strip()):
return False
return True
def _validate_indicator(self, input_data, inc_type):
incs = []
- if type(input_data) is list:
+ if isinstance(input_data, list):
incs = input_data
- elif (',' in input_data):
+ elif ',' in input_data:
incs = input_data.split(',')
- elif(';' in input_data):
+ elif ';' in input_data:
incs = input_data.split(';')
+ incs = list(filter(None, incs))
+
for inc in incs:
if inc_type == "ip":
- if (not ph_utils.is_ip(inc.strip())):
+ if not self._validate_ip(inc.strip()):
return False
elif inc_type == "email":
- if (not ph_utils.is_email(inc.strip())):
+ if not ph_utils.is_email(inc.strip()):
return False
elif inc_type == "domain":
- if (not ph_utils.is_domain(inc.strip())):
+ if not ph_utils.is_domain(inc.strip()):
return False
elif inc_type == "url":
- if (not ph_utils.is_url(inc.strip())):
+ if not ph_utils.is_url(inc.strip()):
return False
return True
@@ -172,7 +206,8 @@ def initialize(self):
try:
self._misp = PyMISP(self._misp_url, api_key, ssl=self._verify)
except Exception as e:
- return self.set_status(phantom.APP_ERROR, "Failed to create API session:", e)
+ error_msg = self._get_error_message_from_exception(e)
+ return self.set_status(phantom.APP_ERROR, "Failed to create API session:{0}".format(error_msg))
self.set_validator('ip', self._validate_ip)
self.set_validator('domain', self._validate_domain)
@@ -191,7 +226,8 @@ def _test_connectivity(self):
self.append_to_message('Test connectivity failed')
return self.get_status()
else:
- return self.set_status_save_progress(phantom.APP_SUCCESS, "Test Connectivity Passed")
+ self.save_progress("Test Connectivity Passed")
+ return self.set_status(phantom.APP_SUCCESS)
def _create_event(self, param):
@@ -202,12 +238,10 @@ def _create_event(self, param):
'this community only': 1,
'connected communities': 2,
'all communities': 3,
- 'sharing group': 4,
'0': 0,
'1': 1,
'2': 2,
- '3': 3,
- '4': 4
+ '3': 3
}
tli_map = {
'high': 1,
@@ -236,50 +270,99 @@ def _create_event(self, param):
return action_result.set_status(phantom.APP_ERROR, "Invalid string in parameter: {}".format(str(e)))
try:
- self._event = self._misp.new_event(threat_level_id=threat_level_id, distribution=distribution,
- analysis=analysis, info=param["info"])
+ event = MISPEvent()
+ event.distribution = distribution
+ event.threat_level_id = threat_level_id
+ event.analysis = analysis
+ event.info = param["info"]
+
+ self._event = self._misp.add_event(event, pythonify=True)
+ except Exception as e:
+ error_msg = self._get_error_message_from_exception(e)
+ return action_result.set_status(phantom.APP_ERROR, "Failed to create MISP event:{0}".format(error_msg))
+
+ try:
+ action_result.add_data(json.loads(self._event.to_json()))
except Exception as e:
- return action_result.set_status(phantom.APP_ERROR, "Failed to create MISP event:", e)
+ error_msg = self._get_error_message_from_exception(e)
+ return action_result.set_status(phantom.APP_ERROR, "Failed to add data of MISP event:{0}".format(error_msg))
- action_result.add_data(self._event["Event"])
- action_result.set_summary({"message": "Event created with id: {0}".format(self._event["Event"]["id"])})
+ action_result.set_summary({"message": "Event created with id: {0}".format(self._event.id)})
- addAttributes = param.get("add_attributes")
- if addAttributes is True:
+ addAttributes = param.get("add_attributes", True)
+ if addAttributes:
ret_val = self._perform_adds(param, action_result, add_data=True)
+
+ error_msg = action_result.get_message()
+
+ if error_msg is not None:
+ summary = action_result.get_summary()
+ summary["errors"] = error_msg
+ action_result.update_summary(summary)
+
if phantom.is_fail(ret_val):
- return ret_val
+ return action_result.get_status()
+
+ try:
+ event_dict = json.loads(self._event.to_json())
+ except Exception as e:
+ error_msg = self._get_error_message_from_exception(e)
+ return action_result.set_status(phantom.APP_ERROR, "Failed to load data of MISP event:{0}".format(error_msg))
+
+ attributes = event_dict.get('Attribute', [])
+ for attribute in attributes:
+ action_result.add_data(attribute)
return action_result.set_status(phantom.APP_SUCCESS)
- def _add_indicator(self, indicator_list, action_result, indicator_type, to_ids, add_data=False):
+ def _add_indicator(self, indicator_list, action_result, indicator_type, to_ids):
+ is_valid = True
+ indic_type = indicator_type
for indicator in indicator_list:
if indicator_type == "source_ips":
- indicator_attribute = self._misp.add_ipsrc(event=self._event, ipsrc=indicator, to_ids=to_ids)
+ is_valid = self._validate_indicator(indicator_list, "ip")
+ indicator_type = "ip-src"
elif indicator_type == "dest_ips":
- indicator_attribute = self._misp.add_ipdst(event=self._event, ipdst=indicator, to_ids=to_ids)
+ is_valid = self._validate_indicator(indicator_list, "ip")
+ indicator_type = "ip-dst"
elif indicator_type == "domains":
- indicator_attribute = self._misp.add_domain(event=self._event, domain=indicator, to_ids=to_ids)
+ is_valid = self._validate_indicator(indicator_list, "domain")
+ indicator_type = "domain"
elif indicator_type == "source_emails":
- indicator_attribute = self._misp.add_email_src(event=self._event, email=indicator, to_ids=to_ids)
+ is_valid = self._validate_indicator(indicator_list, "email")
+ indicator_type = "email-src"
elif indicator_type == "dest_emails":
- indicator_attribute = self._misp.add_email_dst(event=self._event, email=indicator, to_ids=to_ids)
+ is_valid = self._validate_indicator(indicator_list, "email")
+ indicator_type = "email-dst"
elif indicator_type == "urls":
- indicator_attribute = self._misp.add_url(event=self._event, url=indicator, to_ids=to_ids)
- else:
- try:
- indicator_attribute = self._misp.add_named_attribute(
- event=self._event, type_value=indicator_type, value=indicator, to_ids=to_ids
- )
- except Exception as e:
- return action_result.set_status(phantom.APP_ERROR, "Failed to update MISP event:", e)
+ is_valid = self._validate_indicator(indicator_list, "url")
+ indicator_type = "url"
- if add_data is True:
- indicator_attribute["Attribute"]["attribute_id"] = indicator_attribute["Attribute"]["id"]
- action_result.add_data(indicator_attribute["Attribute"])
+ if not is_valid:
+ return action_result.set_status(phantom.APP_ERROR, "'{}'".format(indic_type)), 1
+
+ try:
+ self._event.add_attribute(type=indicator_type, value=indicator, to_ids=to_ids)
+ except Exception as e:
+ self.debug_print("Failed to add attribute due to following error: {}".format(str(e)))
+ return action_result.set_status(phantom.APP_ERROR, "'{}'".format(indicator_type)), 2
+
+ try:
+ self._event = self._misp.update_event(self._event, pythonify=True)
+ except Exception as e:
+ self.debug_print("Failed to update MISP event due to following error: {}".format(str(e)))
+ return action_result.set_status(phantom.APP_ERROR, "Failed to update MISP event. Check logs for more details."), 3
+
+ return phantom.APP_SUCCESS, 0
def _perform_adds(self, param, action_result, add_data=False):
+ errors = {}
+ errors["invalid_key"] = list()
+ errors["invalid_value"] = list()
+ is_added = False
+ is_empty = True
+
default_indicator_list = [
'source_ips', 'dest_ips',
'domains', 'urls',
@@ -289,35 +372,73 @@ def _perform_adds(self, param, action_result, add_data=False):
for i in default_indicator_list:
val = param.get(i)
if val:
- if type(val) is list:
- indicator_list = val
- else:
- indicator_list = phantom.get_list_from_string(val)
+ is_empty = False
+ indicator_list = phantom.get_list_from_string(val)
- try:
- self._add_indicator(indicator_list, action_result, i, param.get('to_ids', False), add_data=add_data)
- except Exception as e:
- return action_result.set_status(phantom.APP_ERROR, "Error adding attribute to MISP event: {}".format(str(e)))
+ ret_val, cust_error_code = self._add_indicator(indicator_list, action_result, i, param.get('to_ids', False))
+
+ if phantom.is_fail(ret_val):
+ return action_result.get_status()
+ else:
+ is_added = True
json_str = param.get('json')
if json_str:
try:
d = json.loads(json_str)
except Exception as e:
- return action_result.set_status(phantom.APP_ERROR, "Invalid JSON parameter. Error: {}".format(str(e)))
+ error_msg = self._get_error_message_from_exception(e)
+ return action_result.set_status(phantom.APP_ERROR, "Invalid JSON parameter. {0}".format(error_msg))
+ if not isinstance(d, dict):
+ return action_result.set_status(phantom.APP_ERROR, "Invalid JSON parameter")
for k, v in d.items():
- if type(v) is list:
+ is_empty = False
+ if isinstance(v, list):
indicator_list = v
else:
- if "," in str(v):
- indicator_list = phantom.get_list_from_string(str(v))
+ indicator_list = phantom.get_list_from_string(str(v))
+
+ ret_val, cust_error_code = self._add_indicator(indicator_list, action_result, k, param.get('to_ids', False))
+
+ if phantom.is_fail(ret_val):
+ status_msg = action_result.get_message()
+ if cust_error_code == 1:
+ errors["invalid_value"].append(status_msg)
+ elif cust_error_code == 2:
+ errors["invalid_key"].append(status_msg)
else:
- indicator_list = list(str(v))
- try:
- self._add_indicator(indicator_list, action_result, k, param.get('to_ids', False), add_data=add_data)
- except Exception as e:
- return action_result.set_status(phantom.APP_ERROR, "Error adding attribute to MISP event: {}".format(str(e)))
- return phantom.APP_SUCCESS
+ return action_result.get_status()
+ else:
+ is_added = True
+
+ error_msg = None
+ if errors["invalid_value"]:
+ invalid_values = ', '.join(errors["invalid_value"])
+ error_msg = "{} key/keys has invalid value".format(invalid_values)
+ if errors["invalid_key"]:
+ invalid_keys = ', '.join(errors["invalid_key"])
+ if error_msg is not None:
+ error_msg = "{} and ".format(error_msg)
+ else:
+ error_msg = ''
+ error_msg = "{} {} is/are invalid attribute name/names".format(error_msg, invalid_keys)
+
+ if error_msg is not None:
+ error_msg = "{} in 'json' action parameter".format(error_msg)
+
+ if self.get_action_identifier() == self.ACTION_ID_ADD_ATTRIBUTES:
+ status = phantom.APP_SUCCESS
+ # if not a single attribute is provided to update event
+ if is_empty:
+ status = phantom.APP_ERROR
+ error_msg = "Please provide at least one attribute"
+ # if not a single attribute is attached then "update event" task is completely failed
+ if not is_added:
+ status = phantom.APP_ERROR
+ return action_result.set_status(status, error_msg)
+ # Event is already created so it should be success regardless of the number of attributes attached
+ else:
+ return action_result.set_status(phantom.APP_SUCCESS, error_msg)
def _add_attributes(self, param):
@@ -325,15 +446,42 @@ def _add_attributes(self, param):
if self._event is None:
try:
- self._event = self._misp.get_event(event_id=param["event_id"])
+ ret_val, event_id = self._validate_integer(action_result, param.get("event_id"), MISP_INVALID_EVENT_ID)
+ if phantom.is_fail(ret_val):
+ return action_result.get_status()
+ self._event = self._misp.get_event(event=event_id, pythonify=True)
+ if not hasattr(self._event, "id"):
+ if isinstance(self._event, dict):
+ raise Exception(self._event.get("errors", ""))
+ else:
+ raise Exception
except Exception as e:
- return action_result.set_status(phantom.APP_ERROR, "Failed to get event for adding attributes:", e)
+ error_msg = self._get_error_message_from_exception(e)
+ return action_result.set_status(phantom.APP_ERROR, "Failed to get event for adding attributes:{0}".format(error_msg))
ret_val = self._perform_adds(param, action_result, add_data=True)
+
+ error_msg = action_result.get_message()
+
if phantom.is_fail(ret_val):
- return ret_val
- if self._event.get('Event', {}).get('id', ""):
- action_result.set_summary({"message": "Attributes added to event: {0}".format(self._event["Event"]["id"])})
+ return action_result.get_status()
+
+ try:
+ event_dict = json.loads(self._event.to_json())
+ except Exception as e:
+ error_msg = self._get_error_message_from_exception(e)
+ return action_result.set_status(phantom.APP_ERROR, "Failed to load data of MISP event:{0}".format(error_msg))
+
+ attributes = event_dict.get('Attribute', [])
+ for attribute in attributes:
+ action_result.add_data(attribute)
+
+ if hasattr(self._event, "id"):
+ summary = {}
+ summary["message"] = "Attributes added to event: {0}".format(self._event.id)
+ if error_msg is not None:
+ summary["errors"] = error_msg
+ action_result.set_summary(summary)
else:
return action_result.set_status(phantom.APP_ERROR, "Failed to get event '{0}' for adding attributes".format(param["event_id"]))
@@ -343,7 +491,8 @@ def _do_search(self, action_result, **kwargs):
try:
resp = self._misp.search(**kwargs)
except Exception as e:
- return RetVal(action_result.set_status(phantom.APP_ERROR, e), None)
+ error_msg = self._get_error_message_from_exception(e)
+ return RetVal(action_result.set_status(phantom.APP_ERROR, error_msg), None)
return RetVal(phantom.APP_SUCCESS, resp)
@@ -354,24 +503,45 @@ def _run_query(self, param):
query_dict['controller'] = controller
if 'event_id' in param:
if ',' in param['event_id']:
- query_dict['eventid'] = param['event_id'].split(',')
+ query_dict['eventid'] = list()
+ for event_id in phantom.get_list_from_string(param['event_id']):
+ ret_val, event_id = self._validate_integer(action_result, event_id, MISP_INVALID_EVENT_ID)
+
+ if phantom.is_fail(ret_val):
+ return action_result.get_status()
+
+ query_dict['eventid'].append(event_id)
else:
- query_dict['eventid'] = param['event_id']
+ ret_val, event_id = self._validate_integer(action_result, param['event_id'], MISP_INVALID_EVENT_ID)
+
+ if phantom.is_fail(ret_val):
+ return action_result.get_status()
+ query_dict['eventid'] = event_id
+
if 'tags' in param:
- if ',' in param['tags']:
- query_dict['tags'] = param['tags'].split(',')
- else:
- query_dict['tags'] = param['tags']
+ query_dict['tags'] = list(filter(None, param['tags'].split(',')))
+
if 'other' in param:
try:
- query_dict.update(json.loads(param['other']))
+ other = json.loads(param['other'])
except Exception as e:
- return action_result.set_status(phantom.APP_ERROR, "Unable to parse JSON object", e)
+ error_msg = self._get_error_message_from_exception(e)
+ return action_result.set_status(phantom.APP_ERROR, "Unable to parse JSON object{0}".format(error_msg))
+
+ if not isinstance(other, dict):
+ return action_result.set_status(phantom.APP_ERROR, "Invalid JSON in 'other' action parameter")
+
+ query_dict.update(other)
+
+ max_results = param.get('max_results', 10)
try:
- max_results = int(param.get('max_results', 10))
- except ValueError:
- return action_result.set_status(phantom.APP_ERROR, "The value of max results must be an integer")
+ if not float(max_results).is_integer():
+ return action_result.set_status(phantom.APP_ERROR, MISP_INVALID_INT_ERR.format(msg='', param=MISP_INVALID_MAX_RESULT))
+
+ max_results = int(max_results)
+ except Exception:
+ return action_result.set_status(phantom.APP_ERROR, MISP_INVALID_INT_ERR.format(msg='', param=MISP_INVALID_MAX_RESULT))
ret_val, response = self._do_search(action_result, **query_dict)
@@ -380,44 +550,58 @@ def _run_query(self, param):
if max_results:
if controller == 'events':
- if response['response']:
- response['response'] = slice_list(response['response'], max_results)
+ if response:
+ response = slice_list(response, max_results)
else:
- if response['response']:
- response['response']['Attribute'] = slice_list(response['response']['Attribute'], max_results)
+ if response:
+ response['Attribute'] = slice_list(response['Attribute'], max_results)
action_result.add_data(response)
return action_result.set_status(phantom.APP_SUCCESS, "Successfully ran query")
- def _download_malware_samples(self, action_result, event_id):
- """ Download malware samples for an event """
+ def _download_malware_samples(self):
try:
- resp = self._misp.download_samples(event_id=event_id)
+ """ Download malware samples for an event """
+ objects = self._event.objects
+ for obj in objects:
+ for attrib in obj.Attribute:
+ if attrib.malware_binary:
+ if hasattr(Vault, 'get_vault_tmp_dir'):
+ file_path = Vault.get_vault_tmp_dir() + '/' + attrib.malware_filename
+ Vault.create_attachment(file_path, self.get_container_id(), file_name=attrib.malware_filename)
+ else:
+ file_path = '/vault/tmp/' + attrib.malware_filename
+ with open(file_path, 'wb') as fp:
+ fp.write(attrib.malware_binary.read())
+ ph_rules.vault_add(container=self.get_container_id(), file_location=file_path, file_name=attrib.malware_filename)
except Exception as e:
- return action_result.set_status("Error getting attachments from event", e)
-
- # 'resp' is a tuple that looks like this:
- # (Success_bool, [[event_id, file_name, bytes], [...],...])
-
- if not resp[0]:
- return phantom.APP_SUCCESS # No Attachments
-
- for sample in resp[1]:
- if hasattr(Vault, 'get_vault_tmp_dir'):
- file_path = Vault.get_vault_tmp_dir() + '/' + sample[1]
- Vault.create_attachment(file_path, self.get_container_id(), file_name=sample[1])
- else:
- file_path = '/vault/tmp/' + sample[1]
- with open(file_path, 'wb') as fp:
- fp.write(sample[2].read())
- fp.close()
- ph_rules.vault_add(container=self.get_container_id(), file_location=file_path, file_name=sample[1])
+ error_msg = self._get_error_message_from_exception(e)
+ return action_result.set_status(phantom.APP_ERROR, "Failed to download malware samples: {0}".format(error_msg))
return phantom.APP_SUCCESS
def _get_attachments(self, param):
action_result = self.add_action_result(ActionResult(dict(param)))
- event_id = param['event_id']
+ ret_val, event_id = self._validate_integer(action_result, param.get("event_id"), MISP_INVALID_EVENT_ID)
+ if phantom.is_fail(ret_val):
+ return action_result.get_status()
+
+ try:
+ self._event = self._misp.get_event(event=event_id, pythonify=True)
+
+ if not hasattr(self._event, "id"):
+ if isinstance(self._event, dict):
+ errors = self._event.get("errors", "")
+ if isinstance(errors, tuple) and errors[0] == 404:
+ return action_result.set_status(phantom.APP_SUCCESS, "Failed to get event for getting attachment:{0}".format(errors))
+ else:
+ Exception(errors)
+ else:
+ raise Exception
+ except Exception as e:
+ error_msg = self._get_error_message_from_exception(e)
+ return action_result.set_status(phantom.APP_ERROR, "Failed to get event for getting attachment:{0}".format(error_msg))
+
query_dict = {}
query_dict['eventid'] = event_id
query_dict['controller'] = 'attributes'
@@ -428,7 +612,10 @@ def _get_attachments(self, param):
if param.get('download_samples'):
# Don't forget about this
- self._download_malware_samples(action_result, event_id)
+ ret_val = self._download_malware_samples()
+
+ if phantom.is_fail(ret_val):
+ return action_result.get_status()
action_result.add_data(attachments)
return action_result.set_status(phantom.APP_SUCCESS, "Successfully retrieved attributes")
@@ -444,7 +631,7 @@ def _process_html_response(self, response, action_result):
split_lines = error_text.split('\n')
split_lines = [x.strip() for x in split_lines if x.strip()]
error_text = '\n'.join(split_lines)
- except:
+ except Exception:
error_text = "Cannot parse error details"
message = "Status Code: {0}. Data from server:\n{1}\n".format(status_code,
@@ -460,9 +647,10 @@ def _process_json_response(self, r, action_result):
try:
resp_json = r.json()
except Exception as e:
- return action_result.set_status(phantom.APP_ERROR, "Unable to parse response as JSON", e), None
+ error_msg = self._get_error_message_from_exception(e)
+ return action_result.set_status(phantom.APP_ERROR, "Unable to parse response as JSON {0}".format(error_msg)), None
- if (200 <= r.status_code < 205):
+ if 200 <= r.status_code < 205:
return phantom.APP_SUCCESS, resp_json
action_result.add_data(resp_json)
@@ -475,7 +663,7 @@ def _process_response(self, r, action_result):
# store the r_text in debug data, it will get dumped in the logs if an error occurs
if hasattr(action_result, 'add_debug_data'):
- if (r is not None):
+ if r is not None:
action_result.add_debug_data({'r_text': r.text})
action_result.add_debug_data({'r_headers': r.headers})
action_result.add_debug_data({'r_status_code': r.status_code})
@@ -483,10 +671,10 @@ def _process_response(self, r, action_result):
action_result.add_debug_data({'r_text': 'r is None'})
# There are just too many differences in the response to handle all of them in the same function
- if ('json' in r.headers.get('Content-Type', '')):
+ if 'json' in r.headers.get('Content-Type', ''):
return self._process_json_response(r, action_result)
- if ('html' in r.headers.get('Content-Type', '')):
+ if 'html' in r.headers.get('Content-Type', ''):
return self._process_html_response(r, action_result)
# it's not an html or json, handle if it is a successful empty response
@@ -509,13 +697,15 @@ def _make_rest_call(self, endpoint, result, headers={}, params={}, json={}, meth
# Set the action_result status to error, the handler function will most probably return as is
return result.set_status(phantom.APP_ERROR, "Unsupported method: {0}".format(method)), None
except Exception as e:
+ error_msg = self._get_error_message_from_exception(e)
# Set the action_result status to error, the handler function will most probably return as is
- return result.set_status(phantom.APP_ERROR, "Handled exception: {0}".format(str(e))), None
+ return result.set_status(phantom.APP_ERROR, "Handled exception: {0}".format(error_msg)), None
try:
r = request_func(url, params=params, json=json, headers=headers, verify=self._verify)
except Exception as e:
- return result.set_status(phantom.APP_ERROR, "REST API to server failed: ", e), None
+ error_msg = self._get_error_message_from_exception(e)
+ return result.set_status(phantom.APP_ERROR, "REST API to server failed: {0}".format(error_msg)), None
return self._process_response(r, result)
@@ -528,15 +718,15 @@ def handle_action(self, param):
self.debug_print("action_id", self.get_action_identifier())
- if (action_id == self.ACTION_ID_CREATE_EVENT):
+ if action_id == self.ACTION_ID_CREATE_EVENT:
ret_val = self._create_event(param)
- elif (action_id == self.ACTION_ID_ADD_ATTRIBUTES):
+ elif action_id == self.ACTION_ID_ADD_ATTRIBUTES:
ret_val = self._add_attributes(param)
- elif (action_id == self.ACTION_ID_RUN_QUERY):
+ elif action_id == self.ACTION_ID_RUN_QUERY:
ret_val = self._run_query(param)
- elif (action_id == self.ACTION_ID_GET_EVENT):
+ elif action_id == self.ACTION_ID_GET_EVENT:
ret_val = self._get_attachments(param)
- elif (action_id == self.ACTION_ID_TEST_ASSET_CONNECTIVITY):
+ elif action_id == self.ACTION_ID_TEST_ASSET_CONNECTIVITY:
ret_val = self._test_connectivity()
return ret_val
@@ -550,7 +740,7 @@ def handle_action(self, param):
# Breakpoint at runtime
pudb.set_trace()
- if (len(sys.argv) < 2):
+ if len(sys.argv) < 2:
print("No test json specified as input")
exit(0)
diff --git a/misp_consts.py b/misp_consts.py
new file mode 100644
index 0000000..5789c7f
--- /dev/null
+++ b/misp_consts.py
@@ -0,0 +1,12 @@
+# File: misp_consts.py
+# Copyright (c) 2017-2021 Splunk Inc.
+#
+# SPLUNK CONFIDENTIAL - Use or disclosure of this material in whole or in part
+# without a valid written license from Splunk Inc. is PROHIBITED.
+#
+
+MISP_INVALID_INT_ERR = "Please provide a valid {msg} integer value in the {param}"
+MISP_INVALID_EVENT_ID = "'event_id' action parameter"
+MISP_INVALID_MAX_RESULT = "'max_result' action parameter"
+MISP_ERR_CODE_MESSAGE = "Error code unavailable"
+MISP_ERR_MESSAGE = "Unknown error occurred. Please check the asset configuration and|or action parameters."
diff --git a/pymisp b/pymisp
deleted file mode 160000
index cf09127..0000000
--- a/pymisp
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit cf09127d7066910e331a34124b0f2df797b0112c
diff --git a/readme.html b/readme.html
index 9172447..359df05 100644
--- a/readme.html
+++ b/readme.html
@@ -8,6 +8,26 @@
-->
+
+pymisp-2.4.138
+ This app uses the pymisp module, which is licensed under an open source license. A simplified 2-BSD License, Copyright (c) 2017 Raphaël Vinot.
+
+
+
+
Misp will return integers which correspond to various values. Here is the complete list:
For distribution:
@@ -17,14 +37,15 @@
+There is no validation provided in case of incorrect value in 'json' action parameter in 'create event' and 'update event' action. +Hence action will pass even if the incorrect attribute value is passed in 'json' action parameter and no attributes will be added. +
++The value of the attribute passed in 'json' action parameter in 'create event' and 'update event' will be treated as a list if the list is passed and +if the string is passed as the value of the attribute then a list will be created by splitting the string by comma(,), +for example: +
+In 'run query' action, tags containing a comma(,) in its value can be passed through the 'other' action parameter, +for example: +
R$!32qwdJyYUV=yAFcX6w6oA0)s|26fCOn{>c~ov?&!UKYXF~ z<6aB@=W+k_>%UI>F3Z)wZnadXA>UwrhiC)&i9y-G5lnz2v}6%hTnigZB+YG7=;=u$ zzgn6r;Y6OUX8g#g>NBn-sg#ECpbVcpg3ug$fDoY0x4X>e0K^0o+v2TP)^LrUVD0{oy#_99AVcjVd@}2aj z5D`W{1d70{GmEvRiN~P0`E2kTAq*)(o4o%M@5DfrUsy)QLnj#ORgbJBaD{kPX@8Gg znd+NceCC~={<3--jCR-c_I*EB3XWhe&|VHMtCVGT8`2SqxDbdY4^E(n?3C{!e{YJj zzrE)??a-D4x%V9wY{|72oaB907
f1bY$6JFNk^mHREZZ z2t%YhZ 2ZNl1DBeE z-siy!L3A#uHOY@hl%!HNQtj@j&Iz8itWX)fivKRx$=MxqV^*h`6pz&t&Na!sUaksV zkwdSjp@eMRUwzAjJ+Dg#o~H#vcO0ds*oFH&Omrb<0D9mxd9!)-yx5QC zT52_Gw9Ke5qVcP-Ajv~o`yEy67M>vvX0Z@NMzVN1nCC>)z0q(rzBd+BWF!wWB1XU9 z0L#o#@`R%tz8 P=jGf8@b(ex*YD4ZF0+rfx2|D;^RSy()8z z_!}#%%3yvvnB)oBu>C53j6cTl7%LCBIPm_15!cVEpYLe|alK=Yu|ZNJsaJF&XRp!T zY_$1dSQQGXYh6|xql)mZLR)Vllg;s8RF>WAWi*cws2f!8pRja$l;!)AhAvyZUsu=H zo94z>?8uDTbl1HfhK+y#0|PN@enUtspc!PTLp_PA7wIV5mNv(2fvN|0vz`PE1MiR< zB0yQbS@x<00$G`;ZE-z~TFsJ|U@F)Sx@;*tGsv^&UXg^oR*$k{Xi^*vo$Y-iC`R?b zd79>Nm60Adk^n&gvp{Iw^F4s1FXIcFGDVur*77!FTAxNDrTSG+ChehWupnY&h#qBV zaLYjBz-UA6V0Iv;eHB*4R;r+m7Jky3ioLW`7dThFzVT2qCppe~MThNq=+$9#rY_0} ztnbTrH0l7M1lpHr^J6(4$O27qwMO@hlhz?r_Of|I&CW51aIA^TKJzOpSiNl@MPg|X zLkb$SnB|pXWrDa!A415&NYFx^S!gYW$kK@L5{sAO;7VgbMwjV%QOSjjpv;WS$l{By zMMix$?Z6GXJ?RQ<->Mt^MPJxCYtFp_QK1(?B6KEk=hi~bA^x|CEo+1x6q@K7T|aHh z(&(AO7PF|S4Ex_fELjL>3#}?PtOlvUFj||+!;z2~P{7`*H4Y9DixgYJvBLp#49#$$ zZ^XoI)%37^p=2z3Fk0s 9mFsE8? z!^y?Z!=acRZJujAL71gr)TU0)B8_K5>yX8fhRKKAlhwP!oYEI~SZAy8fVe-^HKZ9Q z5Tmr8wHff$YHk8p#kBoUW@l!NZrM()PZ5&p8Vo2W(ei>93*KP%j>&CoFz_{BnHhuy zD~t^xsuBNM-u%n6l#S6>p)iSz`R=-nO1$7MpxX{QTi-^OBARTeNcUxfFY`=c47>=1 z5=tpKVSEKG!ksTD2EzaXg3EPpdQk+YHPpx8DMriL=UTX6P}CCzK7BE}$2K+@_sY$a z5A3NhaP9U1nN0|!K+6p|%_)F_Irsld< zt(w|yLZW7j#hG>(%W2Ceh|MQ<-ub?Cq4&6b#q>FelFf^=rI&jWbF;;iUi$=?*JU6qU^X%WPxpxq9@}Ee_63I&zFT$9lcea^a z-!mLvXu1NPM;Zba$MHCJTPusd6-bi3k0F!U-opKzfIWV+ED?z`mIFVo^*kR57~vnH zOT$dd`0+KiaCD-vur;-#la>$?kyR2=QIxXV`e@-jt3|TcDb_EmdM>3&NLOK|4=|W; z1oy&M2u2##6utYHDL%!=PDGlu&-Xf^s!s8rVRC^$v8k^xCO=IdAHeDartP8Pp5ytv zy0!Xx0Zcy{;cP78#<&=l)^1M*ZM*=`@|%gZcn0;T!%fyhoQPR gyZJB8p_~on#4&+mN5m(we$>TWQH{VVrnM6yTS4fj#)< zL~4IiwmjXDVVyD7vKB<^H-~U@hFyhG#37Oz8 QkI%D*hA(6g3|j zibk8l?&au@a5}#IEzxDkf=4u&-uT5TO&kYv{ki=ft$OYu+j)ol#dKstsqOmxWM}uZ zHz0=mRt5-X 4+lO%i5I$G32Q0FOx4x$Eu!II32796Kr zk !rH2UV8J+($yu`{;xmN=1Av*`1#1tR7(U8*Sn@ z@ydisDVk7Db!?Kv-==yKK4L}=%_*!ZX&zOSk08M7*RwRv9uU c8wg zJIw`&gAc;`rVl6|zSMNza8FGhrhK$KlyT67>bKgr*mt&=zczpmiO_qnKILvw5=nX} z@|7xbgdFWr63nVj4z`7ET7pyJ49h5R+0^NkU|^^uDA_o#>WEDxDN(D;1Q-8YLKzf= zu|XE(*y}2n<*RZ8;+z`63@=uU6pHF7;b<8~$o*7gi&FpKF==V(@PUCz)WuB#vuN|` zkvL|ylW1w+tQx&Mn?UnSGh>qihy7+E+jPi|Y(!=4nDNc^sa%7dZ<9=U?S(E)QsC+N zj;5s+mIi1u93gXNb!2-U!YYRr^JEMI>&AB6nsc4%n5qICq+O3>^V?S3MXg{uq{hT? zfqeB4Ny&+ q742GeujumD#-fXb#)+DN#}bJt0v4o6m6oa~Z8Hjq&KdPas%y zk}P@;BwG$8miCvD6&r+wBZ!=r(>|r$X}YY^%h?2$cAx6sY;toCcjDV!bCmm0o-NQ= zn>z}oCSDa#Wa;tkX8SOV(o$Ki2_39M5`32POi$}1{S=2u8@psr#1g6TjM@P@2$V_% zKKXgHUd1PkYjc*ZXGw;F!W!`9iP=hq6y@~{h&O!X54lq&pxFf8ME*B`u ti&9uQN@T2FQS^pxj* z@bqG8Yi@7rI5U}uzLW*1gBPLLbR@`<8S`GS %hzCmphu@%^mP4vh2VX%Yf}f zIZ>!hR%l7$F12?jRi$I#D* Kh|IOY^ISP0CEBqJ$`=&N*9$V(egV zbzJS`HWC-tcB`T27UNMf=bf2_*m>=se%h-7wI0#EyvT9{C`bkiBre>B1Uj_x>`P)) zt0f#pukZJcch`Z4Anhqd8n9XVZLv3Y3`{iz5z8>X_Z$d`C|&gYiFmr;o4!p0#+A(o zQ3 NlhN^agIxF*DyIGc!7 v-Q-IMsn_@3UU_VE9t56b&O$nkD;29Dre7Cc{s7LSZYZRV# z2YXg4cP{+RuG;>7zrq3zbCCk%m7JOx8|kXV2#DZsL9WT#3Yd#^Ewt-4TkLY-`a|EM z5+=kOcj0>u1BF RIp=W_zk>bi)gZNjfUG;ritTe&0oNZ&Av= zvybk3Xc8Iaus&j+kP=yY6%4tC&j80c3S^DlYblvIrs-%B=#z1c;$!&2R3{vTI%VQ` zlNXx55`qQ!02}2K|Fx>#!4#*l-;Z$s4^5K%(v -Z5TmQ(iX4Ge_{$M?~$AB}tnE)Bph4Qpt=pTLuH z?c48ol`9}CBsmZdV)3igt?3DmC7_c(z#j|Je4ldYs^M=v_AUkN9|YMcBqE}}#c^~j z#jX5ML?>;ZFL+Q`VT^S2S=lw!P2Nb~XzZyjNTwlabdK5WiF4&{4&?$b{pa1l!y!-f@B^DVdm&?<48@H zqm9<%neG`h4{@uolrmWJq!Gd)s{$WymR*g)aG*VP4n;%HGPJ_$-w7u=p+tYxxOb~W zj5;H~c-Pv=RI)tgiL5W6SNt(4TTwSzy+3VJ>oNIT>|}N^UZq*#T!jXTB!|HVvwx29 z7_u@7-t0Kc4vE?)k%LU;z0^5To9y-Ir@E1=DIJ{LbDw`wvo? 36Mnr&!r|zJIin|I)jamJ&bh51sq#hyS1TPEA}yL>g*bTxN6 ev&Tk1I&avI6e zLFsBmatcbBT}TP(21W8B=DE?~aj99Ek&>M)pie97zcRLk`B>4%Bntrfe_olBoxPs5 ziHnIft&^LRl&tiaIL+YrIK|#)%7@^s$CZx+b>t&KCHT*jiXuXCio)Jg4e_~}@L(HW zAA=x3-C$VypopsYVuA#b?A_QSfPiwoDh-w{3XHQ7VtTJOTjXO(AO?%?utM^{$iaG} zk+<%`QzLk*&ESL1?~&Ltb>YObU%jlPe%UuJgg6LmdN7319#hVd(}yp bCm7<((y~cDWr9X|m2-N>+=kYi7pjjrqBJ3C9wP-J^Go4+c9WeE!Ds zEMrl%-QLd-Zg$9`l6URFOSjBXCwY!fe754Q 7UMQAk-5=f)<0ZQdntAVk!OY-q z$g7yNSQ!s_JBUn>Z@&s{AmYK_k%@UdB_-eow4&CgtckxM9~WQ*;^%8!d@>hLU LkWF1Z*kEQq_}g#5iL6aqOtVHTiJ zFrmpghrs=^Vx^vjYYjv8GBY}lH?LevU^wwy-~e@0)k(-OJySR^Fv7;f-&srd8M-xY z=>Bzcro*nk3@32tHhJYqKrxthFPAJ=gtW|PULonLEA`xwS;NWcVWzQ$4>^6R$wN|Y zcKd)U$xksXd9#a#Y^m^Figl+}wM1${SFF6L(fW!Zfpin0M#V7%#8f=a?OT0jipgfS z$WD$YvL$6N0aUNeWm2|4C*bPQ8J)x|4dY^Wd{qt_;>uZ^08f1OTeD3EU?9;+?8gM} zN#wqV=b_Uo`O6#8^V)VcgF@cnmWl>;spzP=BIwM+^3FtDJ_z)8q6mGY `Vk-h`sDfj_4vQXPd{^fp4$930{}pt-}|2&|1-n+nc(yM+TR4MA2IunMf@?% z_L=4LRMX!qrXQ*OKUn^I#_2Qu^Nh{kc=RuS;{QEy^BMoSzx_9U1^N&Ce|Nh-<3Bem z|HjL~{ek~?>+&=Fb0h3;IOE5y<{#U){#RS%GyHQO *>+id$=e~$qq3f zbbnE+9xO^K(B-2MvJ>DTiE}TjY6m&64kK(0xGFxrt u! z0F{)aQbSUOeZ4FZS8D_W3f3}nx3$VA#>)f{P^87LC4QJ{I&J~6$y==4!!Ws94RqFy zs{FCsp`or|GzWrLRCV`V6Oh(Xk;))T$A%!Kssg@Q@z`QWB)lXl3kvO@6<8=^j;^ z*&y#MrFAKUiq m1egY#sSX8IN6r^QZhGP|=2BTtHe{2LPZNN^q_UfvsL`Ld} z7q3n6hd+uASpez7ROJOYT5_`LkM{qvZC3RxLNsbu(Uiyb$52hLn=fyCW#U=2*~Zu9 zJSdPn^-8qBgZRC4AyNbFByh&bmtNY&d)uMhqR#o&)BN|`rogc`+k_YqV7r~i+_=Ot z-VM9qcK5-oxC6<-1w;w$JA&gB+J*Xrz8$F5ck)2%+pl|2er)Ya=9ko_B;NKO(DfgL z&hDSD)j9ZPXM^SX+8axPL*<(mN-h25lu>F&+b;$+nMYD(CgIEf|J8gpV34sG2j?OC zS4HxF@BgW$je&*j|65Hd>d85kajMxlYS~%w8JT6N*$L(GY1(mmDur>G>FFaNM6670 zfd4w#$iiF>ynk~~3>pBSiWUF>^?&t=shy*Zf%CsMxzW6G+G0iet?dI6$~!C16(( zUdilSlFpj$V3MYIAa{kP8(b7nBLW0f;^{b@cn9%>~g*-RaEmWtYJtX;;5KYKzi| zch*AFE`*UHx=4*K?>PIBM7e-X_>q02N-0{%MAv$bqDU8KGmc7XUQbmo%(SGmlOp1D zKK7B6lsMR3=%si^n>x!z_h!Z_;XoUV_30w4XO4?np(jZ>8i5#~k0kp0%jE3RvTCfR zR(>oZ(cUdmk&zh9Jo9F!+aqlEJV-$u&R-pG9+jbpHUT?M%~qTSFKZI=^o>?ZIBm<) z=Eh#efNU%`|H0WVqMRQMF)0zsIuhGW>>WsfjMRjJM!Q-M6OXZ?IL+LK3b=U)Rw_>h zJyx?1G=OX1o`P(A4290>sl#&Z6cQZ(GWY?v2X&uQ%?{i{=PtruwG+w^9HI$b7b$6p z7ut4jI$ufkwOwymw#?t6JY4IgfB{S#y(lSuU!78ql&mv!-f39T8h#LI$L}-UO}o#z z6dfIW4->47D&p(H0*E)ns^e5b%8;nd)af++!AD`P(5Gg? cy>)@Ilh`B?o(b)EpI5hN$urW}ZG-uaO2 z$~?#8qv~KXFuw$M{W*B3na}imP=q--jzyc6tk9u78hCsaVdV4Ls6QMU^|{cZhjOd} zj}CjWd`zNV-~gYXvpZ_U7jSGi_Z(gNC)SQ^2Heh$ZcGx!8Q9+bF -7dZf9=|UZX^0LjUQQg1Z50>X3Zs}gnneIdNnlum8xGAyLiDe0k`)yIK7eWz z!+jb!C)%zBClJPl#;gQv2`|B_zA$6)6ze0-CryN$Di4u4fyGK98GI3DWL{S`S97@B zWCKQ)2Bzi?Ty5DB y!@J|cTaGiCXtzd9+!VutTZR}l%{ z$Nj>VM4}-?Ep>3ov9pT6>{> Nh79zxH%fE_&YYNdK8&S+5;})!)p6I5|Pjn z=Wt9`?;i#=5S#O@5No1)Nci^)Tob9|(s4tkb+E3HPNxW=zW~cF_LRSY3GJ?ZZzh@y zEGp#uFZ-Fj#MeLKZ{CM<`dlGCs-(jD0m>=&m=NjwoFNS91gbV_mcPndg9y4jY!+G!L-)ISpKS6&;^<)f%vfkC&Mk?)u>y;-mNu)58i z{$$9}aK%o!h5%^Hh0lXz7Xr!B^7Y2R*f?8o6|8T6Q4QMPG4Oc+JSCw$CHYL7!Rzx{ zG3MPE@%jNgc|?75&ulkw^4Hng41xKnvJ0(wGz@YWE0o(3`l(vtPg0_Es%V@m!*Wf* zZ7Pyk;MGs$OA%J^fVm6hN2N8QL=_cTQL(K^;s)dR=$)W66?Ka96bdQ} i?9Y zPH=`3XEsn$NI#i#^B?3^-sc-u*j-r;vhSgRDYrim?0q$r*d~=Hx!B|TAXgAg&ZuZ4 zrrycsFM$X<6vEe-%NpYSJv+M|TAFwm%S#%F>JvV~s~HMLU2u$Sf| -4j>TK|xJ0|7|3-HZZ3zN%S(+vkqU%deYVR#2&q2D3<=Xu$gTj-q$2 zeqWg1kDzd(I--bBM&||MU{x=-rC|+=L`G2%J#I_}jjF~0KOgzv^K Z$QXyFTgCP|hR3D9M(Vfh=ID39l6$C0ic#jbqTwd*L`P$h~{=WiSPOW_3g2 z^J?Js`}j6gRqO36Tt|t|N-p&Qe0tq@-gE!FO1ii(@qrxp(-UkCsJu EPfSh|JzBSL?JifbMPupX z &Y5pq&X5OGAU&O%%P$ |Fm*H*+qBt7r^P7%XVnQIj zQC^0MSKs8-)+ie%*Ov{CRkrYUj!t1ZYJIVX#IAZv<7q+p+)UWJd!Jdp@bGN6f?B3f zlgz>h^NRV}hUGTiKj5x4;ZI%X82>c3cBUYI1#4*J^cEz-!Y_u@OM^dFdr^NcjQz+r}Wdy@J-J z{#GB;kaNh7Fi_ZOL~ibEo^&2}2p>A)r&iJI9UD9O+Oba#Q+_)!nUOl_^AlgW9Xw}D z7l?~Z@ZulyiW?ibMri&gaEV)(+;`}7ZB`sOnY)9&(y*-ygVilUjv8j$Tje2~v)6)) zCCjI`kpuXsA-0)eW8~4;>O~^@_I5jJ{S>JXPOzYeDbt9Zgbn(51{dbkCA|qpWTL0o za}esQ4gq-lYp8ReYGY|$+lbc>CE{&<6gKKvFZV&8okNfISq6I7OK&}vfR;j00MycW zDX0<~9Zy~oE|?AX<;B-`S(CR(&uxSk2axN1>715SP?N;_y-jCVD3}o^%Z%4$bl^DJ zM4*7gyMs^s(@npq1tsTlN-3^0 z>CH_L!o1=adKL181Zm8@Y}Fvs^Q zx$|cWfRq>^Hc|0XJ^xB#Aj{p43b~y?7X@vkR0Y?a^mV5~IuZ>dSEcx?@AB>x?0Ro= zU$ )+i!$NK(fflTK(jF)Q6MKT`H~Xa{u`nFq zzZe~?o0TuMD^gan!JoPNH>B4@FIFxt-y-A`JNmIo6$(KRRjt8q*INPkzJh`xqJZ2E za&6n>;(=12L+eZ!ZlxulNy#e4%eu-MWpQWvdA4vznqW(&_L)5;QB$K&sO0aZxIGOS zE}?}%;sL%4*{C{tqrqrmi8dKk^q5z6<#@CnmA6w5_~x^ocw6e1X|x<{dg(grV!%FG zSsGKvj8|efGCK#%tKSnbqed?_29l}N+0<|wNPom6g|B5F&~a1uC*o0`ZDn^4f(C2Z zBdpjA->kVm{~M>bD&>@mBsl_^{HM;&5di=Q{ulGMHZe0W^3ZcNu(mKZaJF-F`bWY? z)F*7W7!Z2Cs38EsjQj6PctBNbZ)( n(Qd3HqCw1hcF9n=QVEa b zEx88azPb5tPnv!nxRSY 9hR=5*Yd~py99Apj!j-M**7sNWzZBICm z&8cp-cLbbx5Jo94V$%ZRIgPy%c<#On6H5;!lWIUYU=HSe^@><#=CMTPt l>e~vFuBe*Bn%c1MxUt?+@_VQE(^_9^)YGiY~XHsUBUa&L7k0CGBATNkXmYi z+$!N4X@jJau{$ILFZ=&tlWMZq#E_+2*j3Zq>S7d4>>j?cAj@fy73RnRnSNN1{e}}@ zYvpHjTh|R5*N7I2dTawwQmPiMCRG3Zz<8{#-FpV>Pd 3?~3v|yZdgNmDSTZ>wn%mgjggRJ?UT9_lT~WE0cmjoJr9tq?-O$)P zTu4H-^#6(%ym~7^-9bY?C*Bf+E@(cdXmt0DTziozdTEIlqotEA(jZ@q?CAY8weVm$ z`C7e+o4USk)Lge{z3yiEuFD#KTW4$2ULQz4>9o0o3AF*Bibzr@M=YvQMTQtEs@Y1l ze8#G1NL-9)ZfxSF+j9k6iPHfIKPfu8;1t+5T=%F3dS>MguB^d~iBJhu5E#?By2nF% z0<+Ae0l_V{EpezO`Tj#HEzg@ox}CgeKw7y=8WyLP}eoUs@JnOI8nopGZyK;?t># zQexe4YI^v#sr{w#oAFI?xkX7Yc~Q*DuuWw&Fs(FiS_*}5HSqGDXJ!1fxY*M3)Qiq1 z>twXY%j!0;%$lYggs0`wbvH5$O8V79Kt$ms&>PHJ(fcn2{vU1sxdct94GsX1hx~uF zy`zb#wTaPxBzTLuO%yf<($8+6pfp4)yc~Yl2P?ul!?Yj)7dq>~K16|nTbd22O@*9d z+!*%b-W{dHU(373DaR*+(ObHeDS23-!`PUJC+{BTnBQK9+ghMc)qBq zuCOY(B~9puyUk`*ui*5nE27@fi-+hJHJ)g9#unAjqg0L@!F&i2ZgzM0czoR9ISqwm z^eRDW8#6O9uLDv#Qd(7e`3DizN}^l_u7?tuCY `9;&z zPSyn+5#7IYRWwtTqMYQBVoy;OU7^0LIkju>bEqxW22N>^-}R jfCSy$MVVOv>UPx2RW1~^vR8P=5#7yIeH!$WovWg zbE|^INI`WNJNnm4_ sAmSC`j(sQt$yB{h6xdLQHv zkb>lA@lb>IJ-HJVjwo`A%qmwIzSyQwM8@?LtVdds| zEF4*jk>aG^>9Q0yR4HJGbB;M&3l2q3Y86a`8W5$JoQvKWkGXw3LRQ6GD07E{em>9= z#P}{3puy=g!Ay|GW}O1sghEngZu?M;Ors9F;_*n7UFUU?#0A+O8QzfDMjVtq(d(JK zMHt|?l@)fS;5dtp?^WE1=SQ>vSv!AU!*zdRhgvETII1NIE|?|BYbV;vMTFO}b@uSf zKcRMkQ4X7^=Y6p|%m9tzBcyTLPu#FT&3nNp&yw8o)f&Y>6FG1p?5yX Bx zWoGyZs5~OxvqNiqz+oiWYz2G&acDxnuDfAY{(-qme6X1x(Y@n3ffLB6E>L@jzaP&a zD3xspbu;c@$C;eK^1dWK>$Vfg|6R@Gf%237kTjE14e3nX@%6)VTwEgnN+))`mXQS9 zAH_n7AB7Sl3E>P(A@{(I6}|nK$kWQq>G};#?;T5Pkii!v2r6pVHz0{rTs`y$Npy{Z zvJVV0Y{G^xUc8V6{Od1haoO} yr)4Mxy&ZQXp?H~%-15Bp5(SP&r7t~A8ZgCDu*A&>N}IfH&!Hg zk)vT38dMf!X->vPb>oq#;~!cfe>-Iu=Bd<6{Tf4Qa>ToX0;<+UVaq$G+^r7-JIqcY zT$3)>PRg8gOG4)>)+sm&V8XC3h%2j}N#VnyB>8(%3p9@5Xax6^fs}kUm@sec(_B{; zo{bwbf4TY0U~fxdz=`=RLow81&lYzzCaXb%V(zlX#v)}+%(Q$=1w))! z?@H3cJkPI};&B)`no_JM5bPemBG6vzOo7*QwFqFD%o#d3n}pFrj-GFp9dw}%wb!CN z5}p77$#-~_Pm3c4-0wPqF9mcol-ifC8=H;n-X*RtpXx0I7Er3 %ld(ul^E8%kNZ61j7fT0BwAq-{od7 zl@UN8Ql%Ga36UH&t{VBu%`B$lim?_$W?$ZjR*cojuvbs-opCLJS^x08fDZY)q9HI~ z)5ATDncuA4gg@48*PXGSJ06WPv!3{p(ao{f`Im#-1F|}^*3>_aXDj|V3LJu@m 6K9B%&BT zm#afg2=X5l gOz~w?mAXU 5Ehx8W6NjEHzF@QL@dK{G?{XSj4UMgt%klg~Q+LoCISn z+3cO3ohzXyB#kFIrl%}SiRPTe)QR35e^v=atChyv@)!oRVw1t8u2eS(btfwqeQD z<`X#0+_cJ@_i_5-o~ALl=}63~zmL)&w^HZT{dWS_Y#IWzB+6|R_nzP
Rbt&boe!a zT02U%zQvL=GLZ{E*vBk4rV< CAT)^Y$(-CqH)T3h^g}`Z=n&=3d4FmboxE z324T^I@CK@qK3KXJErYp?ZzWpdmhA8wkdRuX1kOQ))a+c4nP1`T*kx4Z=uY?rjD?^ zLMYM}Wd;eJYlg{C%~}THnk`~FUITI-5%R~fQ`ow<>6IBf0Re>3*%Iv8?iWEU!Tfe# zXkEn` ia_wDZb3ZG;l7IXw#$~6IvLt7wI># zrzr;Zdj%Thg-t(~0QR1WmrPc#V{q~zrh|&ckWI4Ai6?{o73K}>ua8e2YSnXa^xVwn z &o67^mvLjhp-0#?DY;kk$J>MHvbd&X zc|xEok09EJpP`ztIK}!QK fL?O|G5~tH z*`utqDogz3%WK^h@1+5xJ#0oIOj9}`Lp=00PR6hPKJiw~78S*PxHGvI7(nucxQqPJ zMXHuwt`&xlBKTq)O-epWupLe8blc-RHI4?e%kA^=8=0YWO3DP_!jna$E=}`>;6YRM zaAi*Hxh-GM#5smB74Oadf94JgPF;hgmR&M?Q0z~e5YRVt@!)u=gaz 7CQJ;h&iud9`99O*aZNa2B6q`aZhZdDaWtCJ(JnBVYlM zpX9Ws>>4oWR~lh?28U$^O(wb?3$wikG8&nc>j@5fJsi5H5BYqB(c?m* L%R{Kb+_)#;EWNEsaci%Ju)xq z8%)=$8KU(?y<0kBl{d#+I^P7;_N4L|9=?Zo8NNqc@`2*ns57GC`Q(mKb%N>%1H-B@ zs`OiQuhjFpEK^DRsPE>4of51ME&i+r8Ms3S)yshj?GpME7sw|vv?VhFel49A$CA~# z7IgP^U~_ `;KoKhO}I7om{YXU?d|U}JH2>$uQlx|Z_7$X z46U+)=GzVBz;n=N4$1+MDSWMac9oxtc=2R 9Y9_iC0?ZrH7bLf`hxvVUTywD#GkR4zg zr7HUf%5D3`CT2$=UTmxPN`u!&v{6;&oeb?bS*OO%O&v{98l| WJ_1Eiin9g} C_5pl(O)fP5$+_Dp4VjR~-A8x}WONuFEj$neAv!sht|QaT;k}8xLN`YS&ctP9_sl z691Fp+~4Q-5vEV}kqUelWLiK|2+=#M;gR-7QCD#xIhm|xPuDMrCT)RRDNXqcg;qo} ziVfV6t?m?2-o$IYT&xk!Mu `kry5jdFYj<(EAB%tp%{ z4l$o9GQHB=vTniuo&w-|9%sVRHd?m%-b+Fs=u_&a8~>PUPgu(Ahj}~LN6a;M zcw+dfjec9FP`4ap6ZB0AH}XKLK?QH)BnO|1?dVN1tt7!ip+?@qK9LO~B*2PgdCu^0 zPWx9Xen$2 >$&ZvO$5NB;^wBF?tj%t-QrYXTxTVm( zC@~8+h-3=~pk=;ZUB@TLEomFfc0ovdjUQfuu!mi?(Db%2s!6tV?$soB{9+2JPOd2- zriB}_&Y(*+*$}AY`x~ENis*-Q);B$v$sqF@{XLlJtA;R7NIs}Y7&pJ~GYFxA=x0xE zF?N#cWH4F^*JA5>*^a}i5p7xZ_krLameaNOdt-=zi*`f00weY1tAU%vdv _#J 12q!2DTA8gI8fZ4Pu-vX%|0L|+`b9uDKf_!7DCiz=rJDmWSFIH z$06&g_WOBwO=78UDAwBOD-5#>ChcM=6@vXvgp-!dW|l|L!vuX)oSLgnj)#2e8P}-( zRo~l&Dg)Wand9v?46htUTW`<=S0i}<_q_i2)1NC^P)$?Es0ZQs93SabqgR792jkg7 zI>C;H#5-N0PE7Xo-{_%60<-QUJu;A=CJdpom#=yj?yx@>gTyz%ciL&Yowu;1(0%i9 zNsfy(V64+C;#{))h)JQoODy}F1xeLZN8ZNiri*p!XYJSTkz3$nkr5+sziez8g{LDq zuw6BW-AgaAlTWwaw{br 8s3W=PX#L~o69)+Wv06-Z_3>D!rGv8=W)DL z(wLS*)Sk fwm1Ahz- { zrj{yd5SMx%pTwLayd^-6?s4_1osF)$l<$d;zHjuy){uc`T&->3oo}>ic$VzTPPC)h zW$Pl7pYP_2F`GFi-6&(kmDX #|ko%d26ed|W^Hmq)V-Nt$do0OBv zdQ?$=k+OgNt(}a?E`dp*?B4$#mf$r&nwQ>Ty0tsSkN{o|d5M?GrS0bH!}7Sa$x|g> zTFS%vjooWuFIA32ZyX?GGKkd!_^i>drj^mQuLW=WTWgq>1_N N}k{znq9qq$}KPks2jsoBGV#QQVb=%Ks#qnQT) zY~Ap_kV3$W7TVZ4KPW1)+AjFr!Q7!xYRIxu${W!m(GM|&4P_8g>f&N8AP%5K)tFN~ zcGz6HHkqOJXujdnYYnPISqtosUACfI>pZr0DTC^HYF>_&$ ^$^$pZfUhF_(Cp>d~QlfJE@vtOJf{sQ0lH7VgvuG9M;>OGxR; zSEqq0yvZoxnwxb##zMYpwfr02`dUCL@``?q3{7IB@FHR z2>W;A8X6Qhrn@NMV{y$`(;0dXn@=TUiP=}N2hr0dv(LJi34| lrovqFGd?fI7J^OV}|-nM3wfhbir)Ihv3G&e_w zOU9$z_D_E2fn1b&Z-k4V!?5TTpAnE7oKS76guIqy;v{}d2mM9!@BQLPLFA04`>lYx zH {>0ZZ?A9|d9uzFTF+T+qVx^q3hQZ* zG;B=mcwj5(W6wlna-Ne)l&UlLismrM_u;7e=?=QQHHURwbtYL`;0~X&t$G^vljGyk z5hnGGi6YXP`A5O{y7*oUFynK@qZ7Q`*uZ^25{=i&TD4gfpJ^b%M^YowD)k)>f{sQB zm22{9a!QC(yN`wn%uwfj&>4|fFf>I5!lLh3zCTG*; ?dpZdVNjP(7vW>UVIY5%hXK$3g3RGqEB$7Zr|hD^*0tcg&x%6CaK9=JLMj%e;Q z $M78Jf7CSaONoI?ezCPIJrpGxfX^8jK!PTD{5_&Z=i9+8Ot zsJdlX UAQ zU(Hr-q4e@D8H$Y2LJVca>uunG22XQ#!AY^96&VL2mIYc?{BObRJQBQW_ffq0g!qK& zR1NpqYl<@IleK({j?mxJfDM+Yk4&M>2&48Hj4NN#-?#Wm%R30++{rJo2aqLWZ*g2P zvbaCBR1g- HbFSBtyxv@DkE-Q$b3!}^(onAc zJ(N{!K}!aG-!X8@JpyqDA))Z2$iq7^{=*5}@niV5VeUIkA$u&MH=%MiLonK+1~NnP zwJzOZ;17)(BvemJR|2`klaxigh*YO!T%~6_;XxOoFt?5*d7P8nU-~no0C-jdE^?2G zMynI3cth`_;de=@=1Ms$k>C8qNVWZ3Kx%Apf4CImf(S}S78<9mm)u%u7c; S8%Ng*rV+d2G;^Z zO8sr`PIef_o6gwvr;C=;^JpV)Ao&Zx%K$9TA&RA=l5Nr@i@EgoI%&rhxb^xI7_i7b z10-u)(7H=#?{-bmknDFRM=SDQ247Bg@`x4f%}i^ro)r{oIW6KTIj4KP^HV-Du9-je zl}V6f^6~7kN)WkUrRnh=tW7~!h8FbqUY}q} sMaq>l^T%xw}WL z*uN=pcZkjEmVl%p^X|Rzv?UBS(EF@iPxP!_dF@ha$*weBiur(9Fs@j+mTDt{i zpN3af_gpnW{a53&OzBw8EN^?AXFfM@%FJcy?sd13(?t@d pzvv1RCj*wj z^cZzFA#Tw?9RM8{Pkka#0jL|gra!A)i+02B{bD%#{%|K>w5_zPPq-oun5AA{85W=; zb%)V@dv`_!)+7{N_i;4-t4;LG63sZ|kr%Q!^l}$k6yG{x$af@{69>{OJ$qJ;@-)w1 zvuKr#ZuboJXJl$VT<|VZi-5n`5#T7vQG9aHBN4Rd$v8s^a929`IysLgNp^E5PX}^6mQB_ z_MRFy+vx2EF7-UiAmxz*+u_fX+5MFhHJg1q8&-YA{qO_Csp(A}j5iw@8`B}&hZE6k zcl1l_=}QVvW3ihDrG5jaH?}!&9li3XBt+A)FXXCLobN?wO8frunN8=z&J!#DI-B;7 z &LJsq z(cAu|?co-yqkvsansl*C?X`cb;h30G&sxam_Fj#v#M?Tios)N+j6zhCd08zg4vLO@ zrdlIqyxj|Af0???6k(< s&( zEB9#*e;%mM{ZV8gzft$~jo2%TS0RXPUa#O66vTDsrg4+nz+r%%r&T}#H15f=ri3rx z+Z3A$Ubk|Y&aD|Tt3AF3aZ)3w-*~T=0}S_D*$iDNY{Yc^+~3f6g%9{dED*x__PU9> zDkY+6vB4&hR7eQb0 e6uC=l%XmfR(~(&^dfsqhP7` ztN8@=0ead!9OA=WMgFKK7bj0I`RfE5x&2w3p4KdY%iZ8y66ND^XNM~GLs0Z|@gyT{ zL{%<8$pd|x!wY#bi}Z<%tdVhZeL?TMMPH;*%-!D#lqNLuc^iTEpZE0~zEt-i`Ebpj zp##w&QJw~NGxlY7ur3R#kHsc|{jkl6#yVQ&Z{zjfugDiH!@DJw-1^DDQnM)JxlD0l zuIV)V`J2f)s;R1iP&fh%Ol0;IY^ZRr92*bgF^+?X}kWTE|@FNP!kM%cHqWIW4xD z<9FcG4;#5JMDkTSQRH&czEK-?EuijRrNa1{TYohx=BblTYVs<>5wZ3+d3`uIQs8i} zd?fBG>ul{SIWO$p?ZC3BJf@>7S$D~}V%EALblblMd;Q4FzdqtmaNdN@IZb9MznZD` zZM+Xna?5@fd2>Y(z>bK-EQjXsR~@sh-l}~R0#`{;n)K#-)Dur@tVzM7errbG+nOHR zmP@Du5*Rk##v#Ib1oM9DY+01jfnuQXO_0D=Ckok2OSsEH&Lj<=);s=;<7<#C*NWeN z{gzDSoN}_%k+YOQ000u8|HslZva_-Oe>eP7l>fiwq9 HQEzZSfTS*`yQkZnb^e3LV#}V(B+mO>Hdpcv-cgM zM+PZ_ed<*=C&hNM pV6hu?Qa@?XRbn+h^Pv<`a z$B s% z-s2j*sYa8t$Cd5G5l5{$D6qwNJa&q+v6njQ-y`4NZ &o&~k^_P^UBixdC=82=OTP27!4?42$C-8%XQ{4<(1c1P`qKeu`U z7!Xt^IDj^M%@CJ|ty?{>^RKPzGrI-qAb*G#Sm_&!Bb9O5&i(GD??sA9yqco$JO^lH z52x%;Gu$SpP8=V2>Wn8^tS!kpYcG}~A3BXIIUq_sF)pqYSGiizRj4^rXjAJgwphSb znN>)kwky)Pn`O#0C|kShoGGDu0@M6n4GqkS(Q<4vB|8FIZ;Wepve4!}*B@LDz}i=L z2D6`v0+Azo*zMh Q}=OiEJatgk%~32)*ipFL-uG4RVh zXvVQhf1NQ&MGFpwn3Cw;DuY~YAK_q) Octf6QSE-bP8Z&z#!hjTaBYwQmr-IZkb=scJsK^g6vJM9 zH_lGvKW&s-E#(Bzok69h9dZ=p+q3o- XRd+)L)gK*`zHJXS|06#-SzE_y4>3dKp6s;#s5Gew!dqDfjoyyFUcY~u6i{1IeX zsf#^6>Mf=)H`>pDwC(``st%m(_AE{x&?UBEQQ2>90ES0-*@&c-;|vrSg=AugF-}Cd z7-0urrW?;!f1ZaEx?hc6z?jvc2P4`31;lFHr+%h5Fj-rNAJ@HA0RRs397p{c>@cgg zJ7Jt5VnWWW`jNVA#AzJuPWe;ePMeK*DquHC+_R6yGT|wO&04=(wit{jZ8;`}PhW(d z1e@kCtxm+*PUDZDr*n@{dOxw>n?03@W^J9F2(qCYvp+D#Od9-vh)8x3nrmc!Ed694 zX%z)lO8)&@wW%g{Jzii}CBYxgSpqN#GyN+eDA^>Uc*?dkMBW6de{+m$!;anU5EV8B z{gfN7jWq1YP8_lfMb%P^TxlbH2UU>h*TFw@JBKuBqe0UvDq}*m;nbqH=fbmWFFNUF z_$3>U>{%0|H7c+R7v#O9Mp}hEg9ifBze=tUYvSm_o Xne{9(T+P=gA%5C5_T#B#?I?*%^HqMaJ9p_Z5ls7ym1y1B_7lDGWfn znJ@Y}AeZFWb7=3x^dO9<8FN&eagk%Rx8CEPN;8LgelB%_FYIugbA+w9V(Q`ftAPG! zx;)jU!sM&Dq^p&<-7ZVp8kAeww(an5o*UwGgjDKWxc3s=SJ{e=`>w_cqP|-Wg2dB( z5yi8(m9J(4uwO9=QF~&%xwj|Btx3b14co5FTqO%U_clt7*@{i=$l5${jA2Fw0MPG` z9QOgVBGua8l=t&MavrBC 0ru1|lz z6I5s8LTlp`-uMGU(ac&y5VCrB>%rx>UM7cRZae{8Fxd69P@%2$HcXEoe2Zn?vS62y zpziW$!Zn0Vt^u1N5u;Mj9Kl7{SsCdKZ*% fBK z;5MjmJ$ZAfTk# N`^KcdDdNyd1N87$&B`>Gs2!}W zg1XQg=18PMkozdBZVIWYGMITKeaON#hgCZ9pQ-c?^gH6b!Cfz`C?UnYL8$8Q#Lfyk zPKD |^6IzA z&T>ynJIYn(Lf#^{%vqmC#lM6Cr3sN8@&J_MXhm9C35R4aHA!2hVaYzIxFDFgCVuRI z#|Yo^j)_J4aaZ@$*HBusrMoppbu~rBznQkI1=3z9 xaM!C?A)Q!QDD@B |$jmIT z=AX$8eA(JDjfQQxn>V4o5q5>zfqn-_pPIdd7dTk?;pwy@-$w(88Q=y`Ci6HYSVMmV z9E}J(uznc`#S=!Yf5al0hEo$}3U1&+sRN-YzM=bcV=D_AvbOW{U{EzWp*a3nKs`W( znb@3YfjDzB?W_M_#>U~$xag86&ldcpc#Zgy0e_#}q{rb{*Krf1X+?MlA_@5!*;2ii z)hM3-Hz$b~qw(dz$(%&6K3h$>08t6*v>&W10&=cT;9j=dlDZSerHxVI%7e)zvldFo z4B86{4dHv~I-RY(;RT244-mQo$|)=)$sq8Pml-l?;AO~D#V^E5g*9l8$0iJMkSnR} z5jv$vHVpFOjT@ML=AD^hjnxG-*JQR>p$e~Af{YjO%Yg(V!F8crorWMFv^Ag>h<009 z ?)9z2fKe&k#CVm+DK*k*QBysn3NZ5wO_H zu@RJKz4Z-*_1BM4s^s}jIfVkaurLY|xLIH5!;2d6LG?-dyP?LXWa_qb!5tu&6hTI; z%Dv|V0-^xHulEXqDk!xIL^Spc?g&Bcy5nSt>u%Za3o2xdvgRMyPLa9PnbTpMl~DT) zuEP#F)n%o}O(pG~Tyy?dK-dXdr^+yycewWmu^JdeSCiXX!yRwFqN-k$m70mw6D=hV zxgvAoEFd!2 ?1h*S(`4U>>`5S$j^`h$(xqnYHThq0 zIG N~6g-ap}{@W%KhYoR}UD?|zs(NEpa65p4!P)^%yh%$kUVik@y zy+Q`rwrsZ`(58F$G9Lz`z e%|8qP!lV7q+vReaQl?};@IY&P2F70=h+zr_Fc+-?GbEiJ2c z9+NL*wB5A#9QMfD3;&f3qNu7|e=N{uE19orC{W+Kx2drDe+YZWU{Qi*U31yCZSG~; zwr$(CZDTLnwr$(CjoIhixHIRAxHHqy-TykGIy xleXPq+q#4$SdhQffP|YjD2k^zQS-c52$K^;&~A)p+jkel{!eWcbi7 zk@Uy&49~VFj6NUNU@x}U*id($j+@`#mDE~K#99wu!q!-x{SSFOhjf=$**H2eLvz@D zAC5ZkG9REuzl~e *rW -@FC3}# z^YL|6qzjMvXCE= m0ZNq9Ewa4BHjW2@8-#9c zj*#>s*QXcX7C;X~kd=oVrSmS20R*;*>XT;xP &SQ3}nw6nWP-=ap6MumS1eD0^D0+({YNuQEV*B=O32y*J0pH!p;uzdcO@q08- z$3+KOS!MYiR!Fx}i>Ib7cd(3pLiDb1D9X6^K3Lg?i#&);2+&ZEh6FGqQrrL-8r<^9 z1+8Euz^Oc|2QVC&nS;}D gv;xkINLc47vEk zEL>i &_xJnholkZ)3Y~ryUPhL65_e}7W)@vDh7O)8R^rZy(XYrO zx#xhW6WATHu)h|tQoG_TvX<+rsv#HAL2O)=dfB^~C vPjy92A#VA>@%*c}crM!oso}=Qn!a+{=KyneKu09uVI%r zD~mP1_RF-V!ck_YSdZaKC!&i^k?-2M$>XVQwR!sw%2x{d?5teGtRHvhn-_u9USB>x z*9aai;jD=w7R2}Ml=5Vk#x$L+ARkDTh@M^ye;pPjWX%{>2(cMc?=kgEwO_$Dm3efJ z4XF$nKplwK@bn~At9~-$z^U*vaMPCp9sU*9-0S6L= ZtK@2Pr_bJu`pS!MFkbtC_@`NOixyba?xDBS*1qHtZ5?-2}{t<+eL$jy3L za$;`WQ*!Nld`x5S(z0~`i*v1&_KJgqa2PbHZk4{jQE_CEKTU!fnr0IMsUkAhaSfDf zq(!O}hlYGz4_>hd*%{)~3XUT313U$l*&dD4^F-^yH&hCGLq?%+j8o3pGsRz0yd^OU zZ$8aNj8VI4Wn8+{ajVn5y^`dmc5pGN_9isPuFRyWh0dB={qDe=qn|&rJZA?b*w_eU z+OFItCO|14@62JCZv(2CsO6vDsa7J i#fu#ylFnt zJ${*7YaZ#}R6L)>nEb66{M#WPqL%&=A4gZ#LCC$pb<2VI5`a%%{*VN0$GFmV2>Rtw zK;`Nv`W2w~@kaVOYtg7~;B5qU07bozeev}Cb*eL1>x{Ox(j$>6hjTUp9)xyRJQV5$ zEBmR<%A@VQH}enEjHP^|m{B1E%Qw*N`pHt)+coRNjrwV$remYj)^!aSFl*TMye(*# z#cU34BF5h&iVQ0LYzT#kceLp0rats{zv0B)qQ Mv$#&~-Z0uf z5 +ewt=r9sNhh{+ZFbgDh zBdRkAZ;0M<+9`e1iT4{}L}>tfD6$D-nA{rR_z@c-(W`5o2#(o_I?a}P6oe=wI%eeW z$!t_Iv0P0|jZyWAB> Plyi79spJ7@(#E!7R-u%_g=EGf{T zK64!7@kI#`1rc3i Q MYG#2 z4*}074+s)pJi`Tj)inioA@Hjf0nS`f=xGtx7b1K-=sHfP)lyHuw(xBt5h2jL_i!ge zWX4sr&q;K{VNIt7)$iR+2awkm{>eRk0SU65fzH8dxPi$lZD6SPiU4_^%yqsCnQH)X z+XR}a;NJKt#~YxOEhe3Egjk!9z=dfPnif(8Vsayd@(@Uoq3|A1Q~9@{rCYIVkNE za3PD*n*l|?(bVtJ&??`7Z2_9nbcHU9yW%+#G5e520SiWYY<0oUuGCLLr`>16`S=ja z1w0KnuS3ukL=7Ym1NiO2FTwO_HEi!aRa+;67}F8`MM12lZK9dVtk*OY$;I~ChmK;kf(@wm;#Gh5bi({KO}9- z+gdNHz9T;qR|aFj&e-1x^4SVGfiEC%OH19frEchV3QJUq7r1%vD3-v70I9I%WNzz3 zQId!2W10*jJd{&zg>95&rlP;Ee__6PMXq2qx&7$jpv>;~BwDRY)Sy1@XXNQwxV7)B zPwWcN>cx_Sjo>R`LJLGGc3Pob!xn6?cY(E~qMm~wpj+?1P~oz>ODP4G;B|q@HxovM ziZhas{C{ADixF;+I1OU4t28|2b2XFXOGlr=U6HBmcP>Qtyo;&=Rw`beE-dAuaJ$zR zWCaUyAAmNbJK^5c*SlmU6_gbq&$jn3;FA@ Ta zkM2nZ Y|efB(*Y7NW|4Qtu8_zQv4}G z9YJ9UX)F>mDtLKLf_V=zDm)1Knd-_NrFHDqij!G}dzXiYh2S+0(ow4MU^UWDHf!Yg zbYo?LHQO ubHKH8YNL7)jtV*f>< LvRW^=Gyt%46dN528<9g}i{bF~} zeW}_e?_?u)26_vIJFAOgWPPREIX3koy8x@(xjL1;M*_USI_0MXGK&4Uv#vay_U(T& z4GIq~e#v#| C2MA8Sj`~554Y0BqOjrT1UMmG)E$+ zqxMzWSq1 RUY*Q%E{v~gWTQ^gfy?E|Y=!4^|M_*FL(^H3C+|(1>A&At zDv#t)qzWMC$Tf4lcIokqBgPU-NhoXD!Woxj7Y)R`*{c}j246+DFk~mMbdN2{Sm_qt z+oO&Tc$Qh$U7Us$gW9?Tmz>Do4fZVlLATyialdHP +Tzdr*L z;OKig_x0_rxqtbJRR?s#EM8pS&!MJJVFQIpFX<6^b_iiJq)s;2)2;y{JqDNInW|6p zif!5;>^{VO@#>&%bAvg!($0x<9mk!|BEL92jP2reQ`6D<9TX$(X9&BVd+sb_wV7Re z1$S*7)KW%1^=v$SxM(_nejNzez)pJ^ L^A>aIMXcKk@yh3FpypoCoR z^lF`WR@;&idSf?3k&40(Q$lAjiYk`t6Di|N`=}90RFrxRt0rPoyv8^~5Y~I( uGW=MzQe}ez;TAZ}H_T2^5kYsGJb`i3 z44mlSbRN8&CY>2yX^Dg`IB4rSxYlHeG1PKw6(uyg0xSc)#*k%JwM&9!C l+jj81y8xG9+KoHdw%FEyI|#@Qo&J{iIYqNPl1n??8(Mkh6{rHU_BF0 zA)}IY^nKc~x@wLLv)Cnn17(rvz&y`y>t9>pi{lQlK8>-yvpT3L>Tt=IN4w;x#&70z zyj5X6eyLc99j^C#O{(#oF@4bFvKT16Er!hVoy$acTAH+XS3Xg(e03nD;VM!hPd>L( zw#9Eq%_NC@y$O=HSyU<~cb@({7qWuEHzw`(g1Hco*k1wAV+#~9`CZjyFZbQP;Q93k zK9)f}N6^StoDZ=52}*ug^h$YHe3hTj>q=AnIgl%sPWgjFg#t?jO$BSR9a^|F?AMie zdb=`Bal!Rdz3i6@f7vU`*8D-XuH55`zlgMv4BsC)baE*42cy3DZIKnHqURTG&~kzH zs1tr5-`k;9;N8#^b|~%EgrMhZk-v@)cBprRKUlnmE!XpX(cgOw>`35b- kg~_a)#2l!;BEiuYk7V0w$C4gY&e*cOD)xg9eALb1OBWUhA3#GYcyFT zY{0ozvOlW6HYu#Y{o&=~OB$c#1){DrSYbPppxuJw4)+!rVdD8u>U95#VP9dT*F&@X z6kUl}el##tXyh&^4VMPYo!R^&Enb}ol}iNp( F_Dt4U!8!bGl2Q$h>!t1oU*FffwOZ{b9b4x0^=ge zWGv#zeI&tPa{ug{Mw#mUnlUzgczkRjn{!KV&wOd~A3J#=l=N_)kkb2#NWqwnS!iOk zL)7o<9ntu 1An*- xJl^2-&9grCZ;#cLpaCWqSbO1Gq UP?>%Cv5xY`HB(cSWC%Tit)O2tYQrG9b zDLbW@lCt9NLuhx`Li=g%X>q(&W1Z?AMsCCFXEc&59%#Bj$f1QQiba*fu_{}(!l64< zsSfED+PG{K&{L_9aHa;0Dy|96fzYRcV2tE4Q5(rDUP0|n$E#5HfDRJDlP@8nT6>O* zyT;A(Dc+D=EeYzc$}guK2#osjV~Gew=mO3x=y5#iDHz>mf{J|bEO(X}A@^E{h3ZEz zgmxyhmHc2*J9>IXxSkQ;lHiyK7HD}Vnh1v>MZu`d%f{UReMVGMU#RQI*63T&zm4C7 zvA*YrFF<$ztYn+QI@o={m^{Q*T@)EUW?(I7!43oFD%YbLY>it$&ZLhi1y)5QohIL0 z*{)2ujTvctkA;z|nvQQZJ+P%h;+)et6X_a*gl`t*t01P;1Q5CxEIqf4+^LNFgsNO_ z*ki4EUfhM~9#$8EACTzVkJ`Pz&a=wvEvg@~MuTDJMRd!g1JkudcEg5`%F1{a4~2Wf zQ5W3DgexpKa>AH`LO1Nwy_?%VoU~ewn;!tqe!M^RMcn!sjxE+#`=CjNWP8wtjV^pG zSY8-CYBhDrd*I8e&oNrXt0+(glSzQhNyh$AodB-Ix4@4T&IR<_C^e-{Dntb?Ls{0U zG8!=a1;4c&p*gn@+ZQ(%b6WwAXwo#VVqh5qSJ#0#lA?8u@Z7j_ocP?Z;L2+$?Q?|g zY*Y6H6vH$$N%TGnz$42A{PHR@A0P4qPk;d{5w4j}@<|VQk~bKt)gaOCoccJK!HM3i zAqz^u +jcE@1NSj;E6amuh<1vFn+8`ebSfHAk$3FcIP)8Ozj6d}Ho@^2%U zREjV+Q`;0JS6fxgr719CVf6Yjb}9WIeuz-U7b5mNowMb{ABKCy!>hbJ#aKar8#G_R zkl*a#a*S;2p42 `*{v? z1xSDK|6H*WmY~HV^h)?X=cTP(XC*J0o`8J>`YgJ%9>)4|lUxo6Wovtz*8Zc8q4)|% zE$M`bU&X0-0#1`DJgTF wEw; zQ3`5VLA$cRIo3|&*1-`G$w?^{<7|EP%t1<8*|4FCc!*`2Hus!EtAAiLmf+QHRp+J1 zlI}|z5D{EU-~J7P2p2$s;jY443 Bq oEJ7G|7DC) zrzA7#?}V&W-AX#>YY(jBh2Jq#Z2cLkzsbOcw>0Sxs!kNdf0o&;011JL)E$clsIio6 z|H~iEB?yyAHlCpAO8f)+@`A5GMH=~+gsQl-5S) rE?OY_`rQg_W*5j6RQ_k z0P?$YI&{G0158+r?33ig =>clCpXn(}n&?0|Zu^BNcC&W`H 0kZi%q$I`utmQ`u$=nQHfU# zROCk3!)l*^|Ms%Bw d%saH$J>gBo$yToDYc!;tjS|J*%0E& zJXh;iFGhZI#>n(TD23S>cd$&1gVja8IIJYOfqNOSWDtPA(Aq`2PzGFvKpzykD86xV z7e#NJhk>JJI}TIK$jrJ9=y8x%SE2wJ2;0Cke5?L>z_#^c3-2F6JiI&i_h zP5Y{uHq{d%GWZ-m3S;@f#*?@TS~BRNF^)q{1P<8pF^ncA$@==z=!a(@p#z3m^}6Vw z{6BE(c 81fT>) z22U(VE`#*748Q!qL7gw?EQ}2iEW 6d89MGI1tJfXa!Ctl#J zsLdUXq>Y7&hR_}Kuj&Eq-cKb26u={V8zd_`=wLL8ju9?y-eo8q*JwdADEWyERvGjx zWr#R9X44@XO_eSUzep)8hV9ok8HO=70`Ig-W)u|W$@yy%;zX;CS(W|L=w;Is!}g>} zSeJ_zuCtsQZ)};StB@`nam<6XyS<=^>&ypWLgoWYrbv4sM3SV7FfJBV)rJ^33Fv9K zHPKaxdLB?pIn~T;Bu+uA=~DqGzVzDUty@%kf65i%fxzHv@M}LjeY~f1owxmE+vn{3 zn^6XJuDdaIcYIHSf>~IEPgUd51o!=Rz`>#haBr)?Y!C7IGg>a*)ob;|SGf-?DqSWl-=Bl~fo3{Gv;fty5 z6lqJxF$(n8++PvM |WCz(L^b{n5oUXkZ=6BXwc0d$s;s`6Z<$L zfvZY?4BS>5_l*o_<8H|%slSnoIe0;%k^+VtE2HT==Y3+~r01^}|CQU&9PMpudhOW{ z4N8ZWW62bHR+XdDjj#QpghdB`?9KNI7+MUI$Y#b5N=nN_sMa)jW;76MAHB^ZTSvDS z`hcK^{eX>i&4`5?Hve*&FF-sBWdkg7Mk|XKbrGVc_8`3*?-@#Pau>=NNLfQOWHUnk zSIZ%OTC>*vh6o{Tm!UPidKqf$|HNR}bCbwDp4VTB{!8imuZ!?MQ~L}}Y>muq3>>YT z{wGUZNm22@QF2;pW=w`=f=*R@l3tNQYHD0sf@XYbcJc54YJ7}Fl|o#4Mpjx*1%R>n z;X$ei1xhl>kueDs2blZ0E!qDc;`;wdUHz{{aIeQ3F#MyK PXVqY+f`V&T zcy7t@@WSba&IYq<8pD*&&UKmHB^nZgyg@7m>GD!13*3z&N;GLv2XRn{a?UY=Vl0J8 z4nV~@&xpDYKdG-NS9GMt!#ha~XVeEm?PEicmJLL1URVr6{37C1hQ+uH&`#j1&ogAf zG;vc70cx631agpLRt>7*NSfiXV9T@Z)h*=%C7X0WaT}&iHJg_K30UtrEu=d2*aG2! z5P;c2#KEZ(5c5~)GA4_gr&ShcLB&u#tco%dILB48jGD8*&v#eH7 zGohqvo<(ctjqej(Ccq|vbbY>xIbIa6k=gCOULOi|g6-mIXePo=lFG^|E1+CpLch;@ zSQ!)GNQ91K`3+#H_aKl5VvFIeO@*Tn4NN3p6~iHid2#P?u|p0DuYA=ki2ejlPkljh zVs}n~q%M`|e!jML% y9rM)1tbHweee}|I5wM0E4 z;#Wd=xO{eWGLLgGb87vXFv(C36E~q5Nmx1KLRD8A%y+meuIa_5s66@^pEDJ8)=yL@ zs{N<6IyElXCH{Hl(!b3Pc>igw|79H~dSgceQ)ec+|FYP%nv`7@KSIx^nlQ;|k?gWo ztO|XKX89{s7z@mc@Fzj1l;z|>FZxO_02ee$lDNtNa%M)(>*1q=i^5L ZEuxa)8yI56Jr33F%YBZpX0~ELQc3Vqg-t7z&z_X zBJ>nT1wUOSLkjHrk3|X8W>RU>wls^BfRU{ zV^+&_5$g0bZo29WQb )0_exz;04FT8nPttj^zFXhb;+8$3$_~z*Di_%FqM&l2r#QnV-(2L(N7Z ze~HesTv+8Xk8_1vu4Lb!sq-9r{r-HSW)J^0St}G|tEr02&@2=4CuHVmr{_^W+#7!< zs(07nOuYo#9WP6#h&T@JTZu|1h@)pnSX*{)9+>O=S)S{m{tD@*BH_U uD+z_a zIH2X sQMJl2RcWbp`OqqR|I-Nt zBm}y?{y8D~KYIWFmlHDow-auwbJ_iai0*t-!xR@Pwey!+i!@@G&% E z23{Q>epso`;{~daV)o}A)hj2aSxFT{OHOF0#!DHFi+hxe`56q7;P7KiJ@6MCC2}i7 zKTjNuIYEWEDMztxT~1W~wmaHfZxA|sS=ElwgSEfW!4*%$`5$=SA-D!YU%TV1U;bM- zu)$ibK?`aS5vr|tkb!V?9V|vloFdE$$e7WJMGsjwC)MLlAuP7p;>avw_)-AZp$F18 z>EBi~kFkXcQkyX%fH7MB4yaSd8)fJ57$$wY#J(aK886DeLfBGDe>l1uSh5(ViK&Sl zp2GB*{fm}D6vi4XG8%s|gQ5;%EmjQ$X1_7)QF7BK=eVHuI_xORgmvK>62Zo{i?$lA zy7fS_37LuZS`YEag gh- za{U4mQGjG1-X(xdLU6?m(`#AzJe}dMj5kD)lK$Es*~LX^8~lwe=izek8?7TpLapw7 z gE2*!3K-`efbOW&@8(6a~i0U&n^fH$5y4TQ;uuD5$7ksUzJ365<~JRP68E6&6$ zT2zZ; yyrb<8DW+R_KjIP}w}p j||k9*``TkQkvlxf M5uF?_Ygv!@U@G2 z5cA?@EQN$rF_6DR2HHyyb)OmRt?6b5_bJGREth;E>`A51OBR%X*s4!-QH7#B+F)yM z$;=enq2w^97Y|u9?-#!x z&KK~1#tk_~n!)D3xKa84>AYG0J8p*6xstN}Al!UYb8AmH*=M4xnk0@ejc=o#bJH2C zTW=FYAQKtIjsEf=$pKQsu)|AQ;P3XRX`@Mfd*CnZK}5UDN!^wyKOBA9mG4y^JQc=+ z^CgogRz92cvU}a(Ny%c(>?tY_>%a9tK~5exj`JrZwiiGX7GzUVxmT3azZ>`}#QP*9 zW^18`JUJyolfOS3eI_dODD*{l$>mUM=IS+RAQ2HC^lRx_6<7(~I`rr5^P_x&V%O{e zEW`w*g7}amn@B5FiB-ITA&wh1-&7Jgd>I1RX^oyV#@y5TeT0Lyct-KjEMeuRvQ4!L z1(YU}GJGwql=>9)IVFAa&)XlPdl4EE;B*e?XtmKt8GU76JHXZZ1@RlOl_w_ScQLe_ zCOaW5PV_|9C~v|>r8#`$3Z#rkn$8iL6SXw!)6vwW#M;=n9G>b(B#I~aD>osJG@RhJ zq@;8C6A@xExOYh}q|AuL_W|F@ KV1ye%Vy|u<5CeCB0Ie=7vGPWskQAJ#C@~`lL1jdQEcvpW|y@-~Xxf#mC zW4OXurc0aEl}jNPP)_x#3dd3KIx9;qlkwiZH9WGI_&uUECUycl=+X|qy$A( pu zx4kb}Rl!Y5<9SJNJOKPN-930Ue~YCV7xV6P>KZB5*eBj?jSFMCUW*xS@!wDJ4L#ep zIc-`rY;Of>antG87Wk@BI8G(`G`JgG7Q`2VoFeYD1K;} 0oKsyeK~ z=)?D?8~+`da2U8M!nAi^)?7U(@=!naZ&dJoB6e(60GV%JWO7E&c_xv@i#cF#Q|$FA z7t`wjhZy(WwAVuut5tyKeBCY(sP3O!vpef9`VMgcWjeQjg7XRpDM}^+AmaVM)q`rL zn7%V LV0uXr!08`xWpwHMl(aek1l`Q>U48$i_zzXcr6%@1ut| z?|?WxW-AzdV-z0!fzz6BEMO^HY$foVPMPl>?j}uEH5YdcyM@BL{hJ4#q zO+JMp$ns5RB;#Kb8Go;&x_^!bLDEcq7_`FovNz{4_T5SoZd6%h{))Q(h% z|I_(hOQI;hFh9{=Iv?AE8uN_ErKOr6z{?vkj)w9VUT)hr_lK4SJ!BhrAJ%PcZpJM{ z5H2v& NIrY!7i}L(K@MN{E%FNq-6v- zsCsjYXUK}=5124K=2Z42A)6l*7#(s?5q0e&X|aDoqTt0%j#al&P{@hT!~bAOqWgi! z{SyTM|HhdAK5+is{|8I*zl76&=x5;np?%%t$mC>_UV1G4J(KhA`aeHwZene3^51ND zDG3=RaVnYBF&a8LndaxoS*hiw14V$qt)+v5p(kZfEl^UikgKk*2kv-I9@08v(@Y?B z;CSV+NqPl<^B{Afl?vFUN`&l8D3wZW*b=Mf
TrNo5-?sUNa zSv-m{kW{XV4#ZyaAF)Op3jpBX`G0u5|E&y{HMH!uSkZj*^aRQ%h}w-nv#x-m`eo-s zR!2(sldP{~6xu@j5-8w}B$Op4Zmj2idrol_-KL9tDdz$Vtb}tvuZeL%`Y*owZ&Zex z%9{TaG;B$#V3s(Vz6SdEec#Y_%DxsHU5R2$)?izJHr|;Zr~o`wYF8#6%cN))Lk${h zP}^usH>Y%|zt`qPS8SM>Y>?A#kS|_YRx28GusEIJWl3r#pP8(aTU3o5WHQG&X@qBP z`cS_^_4J0_(z3LwdPyz~#4|WlND^3D?EF4?wj3s)Gajm*&y@U3&(XB{G;5j=nMu%9 z(lDGA{n@C(@NQB}wduc5SB_H*8hITE1@vTX?|FMYhX0kerK`0|y!`EHZ-*f&NN6Wc z3RSr~t*!_*5`_t|ab8}>JeV