DealCloud SDK is a wrapper around the DealCloud API, designed to assist clients and partners to build on top of our platform quickly and easily.
Project description
dealcloud_sdk
A wrapper around the DealCloud API, designed to assist users, clients and partners to build on top of our platform's API.
Contents
- Installation
- Usage
- Contacts and Support
Installation
pip
Install using pip with:
pip install dealcloud-sdk
Usage
Creating a client and authenticating
dealcloud_sdk's main entrypoint is the DealCloud class. When it is instantiated, the object is scoped to a given DealCloud environment, by passing the site URL and API credentials as arguments:
from dealcloud_sdk import DealCloud
dc = DealCloud(
site_url="client.dealcloud.com",
client_id="12345",
client_secret="your_client_secret",
)
[!WARNING] Whilst suitable for local development, the above implementation is insecure if you keep code in online repositories such as GitHub. Please see the below examples for more secure implementations.
Securely loading credentials
Using Environment Variables
Where the environment variables contain the relevant values. These can be loaded from a .env file using the python-dotenv PyPi package.
The default environment variable names are, these can be overridden if desired:
DC_SDK_SITE_URL
DC_SDK_CLIENT_ID
DC_SDK_CLIENT_SECRET
from dealcloud_sdk import DealCloud
dc = DealCloud().from_env()
To override the default environment variable names:
from dealcloud_sdk import DealCloud
dc = DealCloud().from_env(
site_url_env_name="OVERRIDDEN_SITE_KEY",
client_id_env_name="OVERRIDDEN_CLIENT_ID_KEY",
client_secret_env_name="OVERRIDDEN_CLIENT_SECRET_KEY",
)
Using JSON Config File
Given a JSON file in the below format:
{
"site_url": "client.dealcloud.com",
"client_id": 12345,
"client_secret": "your_client_secret"
}
The DealCloud object can be created as below:
from dealcloud_sdk import DealCloud
dc = DealCloud.from_json("path/to/json_config_file.json")
Similarly, if the credentials are stored as part of a larger JSON config file, a key path can be passed as the second argument, directing DealCloud to the path of the credentials in the wider JSON. For example:
{
"other": [1,2,3],
"creds":{
"dc":{
"site_url": "client.dealcloud.com",
"client_id": 12345,
"client_secret": "your_client_secret"
}
}
}
from dealcloud_sdk import DealCloud
dc = DealCloud.from_json("path/to/json_config_file.json", "creds.dc")
Using YAML Config File
Given a YAML file in the below format:
site_url: "client.dealcloud.com"
client_id: 12345
client_secret: "your_client_secret"
The DealCloud object can be created as below:
from dealcloud_sdk import DealCloud
dc = DealCloud.from_yaml("path/to/yaml_config_file.json")
Similarly, if the credentials are stored as part of a larger YAML config file, a key path can be passed as the second argument, directing DealCloud to the path of the credentials in the wider YAML. For example:
other:
- 1
- 2
- 3
creds:
dc:
site_url: "client.dealcloud.com"
client_id: 12345
client_secret: "your_client_secret"
from dealcloud_sdk import DealCloud
dc = DealCloud.from_yaml("path/to/yaml_config_file.json", "creds.dc")
Schema Querying
The DealCloud API allows you to query the schema of a given site. The DealCloud class provides access to the schema endpoints through the following methods:
The schema models are defined using Pydantic, for clear validation, straightforward attribute access and IDE assistance.
Get Users
DealCloud.get_users() will return all users in the site. Specifically, an array of User objects. The argument: active_only is a boolean that can be passed, if true, the function will only return active users.
Example:
from dealcloud_sdk import DealCloud
dc = DealCloud.from_yaml("path/to/yaml_config_file.json")
users = dc.get_users()
for user in users:
print(f"{user.name}: {user.email}")
Will output:
User 1: user1@email.com
User 2: user2@email.com
User 3: user3@email.com
User 4: user4@email.com
...etc
Get Currencies
DealCloud.get_currencies() will return the currency codes of all enabled currencies in the site.
Example:
from dealcloud_sdk import DealCloud
dc = DealCloud.from_yaml("path/to/yaml_config_file.json")
currencies = dc.get_currencies()
for ccy in currencies:
print(ccy)
Will output:
GBP
USD
EUR
...etc
Get Objects
DealCloud.get_object() will return all configured objects in the site. Specifically, an array of Object objects.
Example:
from dealcloud_sdk import DealCloud
dc = DealCloud.from_yaml("path/to/yaml_config_file.json")
objects = dc.get_objects()
for obj in objects:
print(f"{obj.apiName}: {obj.pluralName}, {obj.singularName}")
Will output:
Company: Companies, Company
Contact: Contacts, Contact
CompanyAddress: Company Addresses, Company Address
...etc
Get Fields
DealCloud.get_fields() provides the ability to return fields configured in the site. Specifically, an array of Field objects.
There are three ways to query for fields:
- All Fields: call
DealCloud.get_fields()with no arguments to return all fields.
from dealcloud_sdk import DealCloud
dc = DealCloud.from_yaml("path/to/yaml_config_file.json")
fields = dc.get_fields()
fields will contain a list of Field objects containing all configured fields in the site.
- All Fields for an Object: call
DealCloud.get_fields(object_id="ObjectName")withobject_idset to the desired object api name, or object id, to return all fields configured for that object.
from dealcloud_sdk import DealCloud
dc = DealCloud.from_yaml("path/to/yaml_config_file.json")
fields = dc.get_fields("Company")
fields will contain a list of Field objects, containing all fields configured in the "Company" object.
- A Field by Field ID: call
DealCloud.get_fields(field_id=1234)withfield_idset to the ID of the desired field.
from dealcloud_sdk import DealCloud
dc = DealCloud.from_yaml("path/to/yaml_config_file.json")
field = dc.get_fields(field_id=1234)
field will contain a single Field object, describing the field with ID 1234.
Get Schema
DealCloud.get_schema() is a method that will return the full DealCloud schema in a single object.
The method takes the argument: key_type, which describes which field will be used as keys in the nested object structure describing the schema.
The options are:
api- The API namedisplay- The display nameid- The object/field ID
Usage Example:
from dealcloud_sdk import DealCloud
dc = DealCloud.from_yaml("path/to/yaml_config_file.json")
schema = dc.get_schema("api")
schema will contain the a Schema object with the API names as keys, as below:
api Example:
{
"CompanyAPIName": {
"CompanyObjectMetaData": "...",
"CompanyObjectFields": {
"Field1APIName": {
"Field1MetaData": "..."
}
}
}
}
display Example:
{
"Company Display Name": {
"CompanyObjectMetaData": "...",
"CompanyObjectFields": {
"Field 1 Display Name": {
"Field1MetaData": "..."
}
}
}
}
id Example:
Note the ID of the "Company" object is 12345 and the ID of the "Field 1" field is 123456
{
12345: {
"CompanyObjectMetaData": "...",
"CompanyObjectFields": {
123456: {
"Field1MetaData": "..."
}
}
}
}
Data Operations
The DealCloud object provides methods to Create, Read, Update and Delete data in bulk. As its default behaviour, when working with site data, the library uses DataFrames with
the Pandas library, however the option is available for it to work with just python standard data types.
List Configured Views
DealCloud.list_configured_views() returns a Rows object containing all configured views in the site.
The argument is_private can be passed as a boolean, where if true, only private views to (including views shared with) the authenticated user will be returned.
Example:
from dealcloud_sdk import DealCloud
dc = DealCloud.from_yaml("path/to/yaml_config_file.json")
views = dc.list_configured_views()
views will contain a summary of configured views.
Read Data
DealCloud.read_data() allows users to read data from a DealCloud object into a pandas.DataFrame or a list of python dictionaries.
[!IMPORTANT] Only one of object_id or view_id can be populated
Arguments:
- object_id
Union[int, str]: the object to pull data from - view_id
Union[int, str]: the view to pull data from - output
str:pandasorlist, decides the output format,pandasis default - resolve
str: for pandas, where fields contain an object (choice, reference, user), resolve to the id or name - view_filter
list[dict]: column queries to "supply value later" in views, see: https://api.docs.dealcloud.com/docs/data/rows/view_details - fields
list[str]: if notNone, return only fields in the list. - query
str: a DealCloud rows query string to request specific information, see: https://api.docs.dealcloud.com/docs/data/rows/query - include_nulls
bool: if true, null columns will also be returned - column_headers
str: specifies the value type of the return field keys/column names.api= Field API Namename= Field Display Nameid= Field ID
Reading Data from an Object
Example:
from dealcloud_sdk import DealCloud
dc = DealCloud.from_yaml("path/to/yaml_config_file.json")
data = dc.read_data("Company")
data will be a pandas.DataFrame as below:
| EntryId | CompanyName | CompanyType |
|---|---|---|
| 12345 | Company1 | [{'seqNumber': 3, 'isAutoPdf': False, 'id': 3197780, 'name': 'Limited Partner', 'entryListId': -6}] |
| 12346 | Company2 | [{'seqNumber': 1, 'isAutoPdf': False, 'id': 3197782, 'name': 'Operating Company', 'entryListId': -6}] |
| 12347 | Company3 | [{'seqNumber': 3, 'isAutoPdf': False, 'id': 3197780, 'name': 'Limited Partner', 'entryListId': -6}] |
To return a python list instead of a pandas.DataFrame:
from dealcloud_sdk import DealCloud
dc = DealCloud.from_yaml("path/to/yaml_config_file.json")
data = dc.read_data("Company", output="list")
data will be a list of dicts as below:
[
{
'EntryId': 12345,
'CompanyName': 'Company1',
'CompanyType': [
{
'seqNumber': 3,
'isAutoPdf': False,
'id': 3197780,
'name': 'Limited Partner',
'entryListId': -6
}
],
},
{
'EntryId': 12346,
'CompanyName': 'Company2',
'CompanyType': [
{
'seqNumber': 1,
'isAutoPdf': False,
'id': 3197782,
'name': 'Operating Company',
'entryListId': -6
}
]
},
{
'EntryId': 12347,
'CompanyName': 'Company3',
'CompanyType': [
{
'seqNumber': 4,
'isAutoPdf': False,
'id': 3197779,
'name': 'Service Provider',
'entryListId': -6
}
]
},
]
Resolving to Name or to ID
[!NOTE] The following methods only apply to where a
pandas.DataFrameis returned.
Choice, Reference and User fields appear as lists of dictionaries as seen in the above example by default.
To resolve these fields to a more readable name value:
from dealcloud_sdk import DealCloud
dc = DealCloud.from_yaml("path/to/yaml_config_file.json")
data = dc.read_data("Company", resolve="name")
data will be a pandas.DataFrame as below:
| EntryId | CompanyName | CompanyType |
|---|---|---|
| 12345 | Company1 | Limited Partner |
| 12346 | Company2 | Operating Company |
| 12347 | Company3 | Limited Partner |
To resolve the fields to an id value:
from dealcloud_sdk import DealCloud
dc = DealCloud.from_yaml("path/to/yaml_config_file.json")
data = dc.read_data("Company", resolve="id")
data will be a pandas.DataFrame as below:
| EntryId | CompanyName | CompanyType |
|---|---|---|
| 12345 | Company1 | 3197780 |
| 12346 | Company2 | 3197782 |
| 12347 | Company3 | 3197780 |
Reading a Subset of Fields
To read a specific set of fields from an object, pass a list of DealCloud field API names to the argument fields:
from dealcloud_sdk import DealCloud
dc = DealCloud.from_yaml("path/to/yaml_config_file.json")
data = dc.read_data("Company", fields=["CompanyName"])
data will be a pandas.DataFrame as below:
| EntryId | CompanyName |
|---|---|
| 12345 | Company1 |
| 12346 | Company2 |
| 12347 | Company3 |
Using Queries to Read Data
A query can be passed to the DealCloud request for data to return more specific information, and reduce the volume of incoming data.
To use a query, pass the query string to the query argument.
The available query operations are below:
| Name | Query Operation |
|---|---|
| Equals | $eq |
| Contains | $contains |
| Greater | $gt |
| GreaterOrEqual | $gte |
| Less | $lt |
| LessOrEquals | $lte |
| StartsWith | $startswith |
| In | $in |
| Between | $between |
| NotIn | $nin |
| NotEqualTo | $not |
| EndsWith | $endswith |
| Or | $or |
| And | $and |
from dealcloud_sdk import DealCloud
dc = DealCloud.from_yaml("path/to/yaml_config_file.json")
dc.read_data("Company", query="{CompanyName: {$contains: \"1\"}}")
data will be a pandas.DataFrame as below:
| EntryId | CompanyName | CompanyType |
|---|---|---|
| 12345 | Company1 | 3197780 |
Some other example query strings are below: Filter on excluding records with a specific reference value:
from dealcloud_sdk import DealCloud
dc = DealCloud.from_yaml("path/to/yaml_config_file.json")
dc.read_data("Company", query="{CoveragePerson: {$nin: [5785]}")
Filter using Or:
from dealcloud_sdk import DealCloud
dc = DealCloud.from_yaml("path/to/yaml_config_file.json")
dc.read_data("Company", query="{$or: [{CompanyName: \"DealCloud\"},{CompanyName: \"API Entry\"}]}")
Reading Data from a View
To read data from a view with ID: 12345
Example:
from dealcloud_sdk import DealCloud
dc = DealCloud.from_yaml("path/to/yaml_config_file.json")
data = dc.read_data(view_id=12345)
Alternatively, if the view is named: "My Company View":
from dealcloud_sdk import DealCloud
dc = DealCloud.from_yaml("path/to/yaml_config_file.json")
data = dc.read_data(view_id="My Company View")
data will be a pandas.DataFrame as below:
| EntryId | CompanyName | CompanyType |
|---|---|---|
| 12345 | Company1 | [{'seqNumber': 3, 'isAutoPdf': False, 'id': 3197780, 'name': 'Limited Partner', 'entryListId': -6}] |
| 12346 | Company2 | [{'seqNumber': 1, 'isAutoPdf': False, 'id': 3197782, 'name': 'Operating Company', 'entryListId': -6}] |
| 12347 | Company3 | [{'seqNumber': 3, 'isAutoPdf': False, 'id': 3197780, 'name': 'Limited Partner', 'entryListId': -6}] |
Using a Filter When Reading View Data
When reading data from a view, which has "Supply Value Later" filters configured, the filter values can be provided by passing them to the view_filter argument in a list of dicts. For more information on their format, please see the API Documentation.
For Example, supplying a "CompanyType" filter value to filter for only "Limited Partner" companies:
from dealcloud_sdk import DealCloud
dc = DealCloud.from_yaml("path/to/yaml_config_file.json")
data = dc.read_data(
view_id = "My Company View",
view_filter = [
{
"column":"CompanyType",
"value": [3197780]
}
]
)
data will be a pandas.DataFrame as below:
| EntryId | CompanyName | CompanyType |
|---|---|---|
| 12345 | Company1 | [{'seqNumber': 3, 'isAutoPdf': False, 'id': 3197780, 'name': 'Limited Partner', 'entryListId': -6}] |
| 12347 | Company3 | [{'seqNumber': 3, 'isAutoPdf': False, 'id': 3197780, 'name': 'Limited Partner', 'entryListId': -6}] |
Create, Update and Upsert Data
DealCloud.insert_data(), DealCloud.update_data(), DealCloud.upsert_data() are methods which provide the ability to create, update and upsert data respectively.
These methods have the same argument pattern:
Arguments:
- object_api_name
str: the object API name to write data to - data
Union[list[dict], pd.DataFrame]: the data to be sent to DealCloud. - use_dealcloud_ids
bool: Default isTrueIfTrue, DealCloud EntryIds must be used to reference records and choice values. IfFalse, use a column as a lookup, defined by the lookup_column argument. - lookup_column
str: ifuse_dealcloud_idsisFalse, this defines the column to be used as a lookup. - output
str:listorpandas, defines the output format returned from the function
Returns:
Union[list[dict], pd.DataFrame]: the data returned from the data operation.
[!IMPORTANT] When not using
use_dealcloud_ids, for Reference fields, reference by record EntryId. For choice fields, use the choice value ID. For user fields, use the user ID (fromDealCloud.get_users()). When usinguse_dealcloud_ids, for Reference fields, reference by the lookup column on the referenced object. For choice fields, use the choice field display name. For user fields, use the user email address.
Field Mapping
All columns passed to the create, update and upsert methods must match by API Name. If a column passed to the method does not exist in the site by API name, then a KeyError will be raised:
from dealcloud_sdk import DealCloud
dc = DealCloud.from_yaml("path/to/yaml_config_file.json")
to_send = [
{
"CompanyName": "Test Company 1",
"UnmappableColumn": "Foo",
}
]
responses = dc.insert_data("Company", to_send)
Will Return
Traceback...
KeyError: "mapping error, could not map: ['UnmappableColumn']"
Create Data
Example, to insert data into the "Company" object from a list:
from dealcloud_sdk import DealCloud
dc = DealCloud.from_yaml("path/to/yaml_config_file.json")
to_send = [
{
"CompanyName": "Test Company 1",
"CompanyType": 12345,
"BusinessDescription": "Here is a business description",
"Sector": 14321,
}
]
responses = dc.insert_data("Company", to_send)
If successful, responses will contain the below - note that EntryId is now included:
[
{
"EntryId": 234567,
"CompanyName": "Test Company 1",
"CompanyType": 12345,
"BusinessDescription": "Here is a business description",
"Sector": 14321,
}
]
Example, to insert data into the "Company" object from a CSV, using pandas:
CSV File (company.csv):
| CompanyName | CompanyType |
|---|---|
| Company1 | 3197780 |
| Company2 | 3197782 |
| Company3 | 3197780 |
import pandas as pd
from dealcloud_sdk import DealCloud
dc = DealCloud.from_yaml("path/to/yaml_config_file.json")
to_send = pd.read_csv("company.csv")
responses = dc.insert_data("Company", to_send)
Example, to insert data into the "Company" object using "ExternalSystemID" as a lookup column:
from dealcloud_sdk import DealCloud
dc = DealCloud.from_yaml("path/to/yaml_config_file.json")
to_send = [
{
"CompanyName": "Test Company 1",
"CompanyType": "Operating Company",
"BusinessDescription": "Here is a business description",
"Sector": "612E9FF4-1D8C-41B7-B8ED-2D1C15240434",
}
]
responses = dc.insert_data(
object_api_name = "Company",
data = to_send,
use_dealcloud_ids = False,
lookup_column = "ExternalSystemID"
)
Update Data
To update existing site data, the process is similar, except objects must include EntryId, or a valid primary key by lookup_column.
Example, to update data in the "Company" object from a list:
from dealcloud_sdk import DealCloud
dc = DealCloud.from_yaml("path/to/yaml_config_file.json")
to_send = [
{
"EntryId": 234567,
"BusinessDescription": "Here is an updated business description!",
}
]
responses = dc.insert_data("Company", to_send)
If successful, responses will contain the below:
[
{
"EntryId": 234567,
"CompanyName": "Test Company 1",
"CompanyType": 12345,
"BusinessDescription": "Here is an updated business description!",
"Sector": 14321,
}
]
Example, to update data in the "Company" object from a list, using the lookup_column, ExternalSystemId:
from dealcloud_sdk import DealCloud
dc = DealCloud.from_yaml("path/to/yaml_config_file.json")
to_send = [
{
"ExternalSystemId": "F628AFC8-532C-406C-BDE6-A782F03508D5",
"BusinessDescription": "Here is an updated business description!",
}
]
responses = dc.insert_data(
object_api_name = "Company",
data = to_send,
use_dealcloud_ids = False,
lookup_column = "ExternalSystemId"
)
Upsert Data
Upserting data is a method that combines insert and update. If a record exists and can be found by EntryId or a lookup_column then it will be updated, if not, it will be created new.
Example, to upsert data in the "Company" object from a list:
from dealcloud_sdk import DealCloud
dc = DealCloud.from_yaml("path/to/yaml_config_file.json")
to_send = [
{
"EntryId": 234567,
"CompanyName": "Test Company 1",
"CompanyType": 12345,
"BusinessDescription": "Here is an updated business description",
"Sector": 14321,
},
{
"CompanyName": "Test Company 2",
"CompanyType": 12345,
"BusinessDescription": "Here is a business description for a new company",
"Sector": 14321,
},
]
responses = dc.insert_data("Company", to_send)
If successful, responses will contain the below, note that the "Test Company 2" now has an EntryId as it has been created:
[
{
"EntryId": 234567,
"CompanyName": "Test Company 1",
"CompanyType": 12345,
"BusinessDescription": "Here is an updated business description",
"Sector": 14321,
},
{
"EntryId": 234568,
"CompanyName": "Test Company 2",
"CompanyType": 12345,
"BusinessDescription": "Here is a business description for a new company",
"Sector": 14321,
},
]
Understanding Errors
The data operation methods raise errors in a number of ways, when use_dealcloud_ids is False, errors are fed back from the API into the data returned from the function.
Example, if the sector 12345 does not exist:
from dealcloud_sdk import DealCloud
dc = DealCloud.from_yaml("path/to/yaml_config_file.json")
to_send = [
{'CompanyName': 'TEST_UPDATED', "Sector": 12345}
]
responses = dc.insert_data("WJ_Company", to_send)
responses will contain.
[{'EntryId': -1,
'CompanyName': 'TEST_UPDATED',
'Sector': None,
'Errors': [{'field': 'Sector',
'code': 5006,
'description': 'One or more referenced entries are not valid for this field.'}]}]
[!NOTE] In this case, the record has not been created in the site. When multiple records are trying to be made and any one fails in this way, none of the records in that group will be created. When a large volume of records are being created,
DealCloudhandles breaking the large volume of data into multiple pages. In this case, where there is an error on a record in a page, all of the records in that page will not be created/updated.
When use_dealcloud_ids is True, and lookup values are used, the create/update/upsert methods are less prone to "failing" errors. This is because, when a value is being resolved through a lookup_column, a value that cannot be found will result in an error being logged to the configured logger. However, as the record progresses, the un-resolvable value will simply be blank. The logs appear as below:
For choice fields:
ERROR: Choice mapping error on: {object}, {field}, could not find value: {value}
For reference fields:
ERROR: Reference mapping error on: {object}, {field}, could not find value: {value}
For user fields:
ERROR: User mapping error on: {object}, {field}, could not find value: {value}
When using DealCloud.update_data(), if an EntryId cannot be located, you will see the following error:
ERROR: Primary Key error on object: {object}, record found without 'EntryId' field.
Delete Data
DealCloud.delete_data() provides the ability to delete data from an object by the EntryId. To use it, simply pass the object api name to the object_api_name argument
and a list of EntryIds to the records argument.
Example to delete two records with the EntryIds 123451 and 12346:
from dealcloud_sdk import DealCloud
dc = DealCloud.from_yaml("path/to/yaml_config_file.json")
response = dc.delete_data(
object_api_name="Company",
records=[12345, 12346]
)
response will contain:
[
{'entryId': 12345, 'fieldId': 0, 'rowId': 4935650, 'isNoData': False},
{'entryId': 12346, 'fieldId': 0, 'rowId': 4935650, 'isNoData': False},
]
Support
For any support, provide feedback or to report issues, please contact Intapp Support at support@dealcloud.com.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file dealcloud_sdk-0.1.9.tar.gz.
File metadata
- Download URL: dealcloud_sdk-0.1.9.tar.gz
- Upload date:
- Size: 33.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.10.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b36162420b4e85dadfdde3d6c05353ed6990e275108b5289c4b5979c73b1e536
|
|
| MD5 |
41a8151e84abf019d92cd3b94f62226c
|
|
| BLAKE2b-256 |
752cbb69f5d4d5a7636be54398abba0d071e1d514b4d79d10e577a7017c605cc
|
File details
Details for the file dealcloud_sdk-0.1.9-py3-none-any.whl.
File metadata
- Download URL: dealcloud_sdk-0.1.9-py3-none-any.whl
- Upload date:
- Size: 33.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.10.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
16e5251b31ef0fb4d9113016ae56c605079c0ce7077f534424f06635fbc0d400
|
|
| MD5 |
7523a32c873b8d1ceddb79032beef002
|
|
| BLAKE2b-256 |
82f8672f49d7be8fef67b13975bda87bdf1823faa1fb47aad0d8caad47cb5ea0
|