Co-authored-by: Octavia Squidington III <octavia-squidington-iii@users.noreply.github.com>
669 lines
21 KiB
YAML
669 lines
21 KiB
YAML
version: 4.6.2
|
|
|
|
type: DeclarativeSource
|
|
|
|
description: |-
|
|
Website: https://dashboard.lob.com/
|
|
API docs: https://docs.lob.com/
|
|
Auth Docs: https://docs.lob.com/#tag/Authentication
|
|
Auth page: https://dashboard.lob.com/settings/api-keys
|
|
|
|
check:
|
|
type: CheckStream
|
|
stream_names:
|
|
- addresses
|
|
|
|
definitions:
|
|
streams:
|
|
addresses:
|
|
type: DeclarativeStream
|
|
name: addresses
|
|
primary_key:
|
|
- id
|
|
retriever:
|
|
type: SimpleRetriever
|
|
requester:
|
|
$ref: "#/definitions/base_requester"
|
|
path: addresses
|
|
http_method: GET
|
|
request_parameters:
|
|
limit: "{{ config['limit'] }}"
|
|
error_handler:
|
|
type: CompositeErrorHandler
|
|
error_handlers:
|
|
- type: DefaultErrorHandler
|
|
max_retries: 3
|
|
backoff_strategies:
|
|
- type: ExponentialBackoffStrategy
|
|
factor: 2
|
|
response_filters:
|
|
- type: HttpResponseFilter
|
|
action: RATE_LIMITED
|
|
http_codes:
|
|
- 429
|
|
error_message: Rate limits hit
|
|
record_selector:
|
|
type: RecordSelector
|
|
extractor:
|
|
type: DpathExtractor
|
|
field_path:
|
|
- data
|
|
paginator:
|
|
type: DefaultPaginator
|
|
page_token_option:
|
|
type: RequestPath
|
|
pagination_strategy:
|
|
type: CursorPagination
|
|
cursor_value: "{{ response.get('next_url') }}"
|
|
stop_condition: "{{ response.get('next_url') is none }}"
|
|
incremental_sync:
|
|
type: DatetimeBasedCursor
|
|
cursor_field: date_modified
|
|
cursor_datetime_formats:
|
|
- "%Y-%m-%dT%H:%M:%S.%fZ"
|
|
datetime_format: "%Y-%m-%dT%H:%M:%S.%fZ"
|
|
start_datetime:
|
|
type: MinMaxDatetime
|
|
datetime: '{{ config["start_date"] }}'
|
|
datetime_format: "%Y-%m-%dT%H:%M:%SZ"
|
|
end_datetime:
|
|
type: MinMaxDatetime
|
|
datetime: "{{ now_utc().strftime('%Y-%m-%dT%H:%M:%SZ') }}"
|
|
datetime_format: "%Y-%m-%dT%H:%M:%SZ"
|
|
schema_loader:
|
|
type: InlineSchemaLoader
|
|
schema:
|
|
$ref: "#/schemas/addresses"
|
|
banks:
|
|
type: DeclarativeStream
|
|
name: banks
|
|
primary_key:
|
|
- id
|
|
retriever:
|
|
type: SimpleRetriever
|
|
requester:
|
|
$ref: "#/definitions/base_requester"
|
|
path: bank_accounts
|
|
http_method: GET
|
|
request_parameters:
|
|
limit: "{{ config['limit'] }}"
|
|
error_handler:
|
|
type: CompositeErrorHandler
|
|
error_handlers:
|
|
- type: DefaultErrorHandler
|
|
max_retries: 3
|
|
backoff_strategies:
|
|
- type: ExponentialBackoffStrategy
|
|
factor: 2
|
|
response_filters:
|
|
- type: HttpResponseFilter
|
|
action: RATE_LIMITED
|
|
http_codes:
|
|
- 429
|
|
error_message: Rate limits hit
|
|
record_selector:
|
|
type: RecordSelector
|
|
extractor:
|
|
type: DpathExtractor
|
|
field_path:
|
|
- data
|
|
paginator:
|
|
type: DefaultPaginator
|
|
page_token_option:
|
|
type: RequestPath
|
|
pagination_strategy:
|
|
type: CursorPagination
|
|
cursor_value: "{{ response.get('next_url') }}"
|
|
stop_condition: "{{ response.get('next_url') is none }}"
|
|
incremental_sync:
|
|
type: DatetimeBasedCursor
|
|
cursor_field: date_modified
|
|
cursor_datetime_formats:
|
|
- "%Y-%m-%dT%H:%M:%S.%fZ"
|
|
datetime_format: "%Y-%m-%dT%H:%M:%S.%fZ"
|
|
start_datetime:
|
|
type: MinMaxDatetime
|
|
datetime: '{{ config["start_date"] }}'
|
|
datetime_format: "%Y-%m-%dT%H:%M:%SZ"
|
|
end_datetime:
|
|
type: MinMaxDatetime
|
|
datetime: "{{ now_utc().strftime('%Y-%m-%dT%H:%M:%SZ') }}"
|
|
datetime_format: "%Y-%m-%dT%H:%M:%SZ"
|
|
schema_loader:
|
|
type: InlineSchemaLoader
|
|
schema:
|
|
$ref: "#/schemas/banks"
|
|
postcards:
|
|
type: DeclarativeStream
|
|
name: postcards
|
|
primary_key:
|
|
- id
|
|
retriever:
|
|
type: SimpleRetriever
|
|
requester:
|
|
$ref: "#/definitions/base_requester"
|
|
path: postcards
|
|
http_method: GET
|
|
request_parameters:
|
|
limit: "{{ config['limit'] }}"
|
|
error_handler:
|
|
type: CompositeErrorHandler
|
|
error_handlers:
|
|
- type: DefaultErrorHandler
|
|
max_retries: 3
|
|
backoff_strategies:
|
|
- type: ExponentialBackoffStrategy
|
|
factor: 2
|
|
response_filters:
|
|
- type: HttpResponseFilter
|
|
action: RATE_LIMITED
|
|
http_codes:
|
|
- 429
|
|
error_message: Rate limits hit
|
|
record_selector:
|
|
type: RecordSelector
|
|
extractor:
|
|
type: DpathExtractor
|
|
field_path:
|
|
- data
|
|
paginator:
|
|
type: DefaultPaginator
|
|
page_token_option:
|
|
type: RequestPath
|
|
pagination_strategy:
|
|
type: CursorPagination
|
|
cursor_value: "{{ response.get('next_url') }}"
|
|
stop_condition: "{{ response.get('next_url') is none }}"
|
|
incremental_sync:
|
|
type: DatetimeBasedCursor
|
|
cursor_field: date_modified
|
|
cursor_datetime_formats:
|
|
- "%Y-%m-%dT%H:%M:%S.%fZ"
|
|
datetime_format: "%Y-%m-%dT%H:%M:%S.%fZ"
|
|
start_datetime:
|
|
type: MinMaxDatetime
|
|
datetime: '{{ config["start_date"] }}'
|
|
datetime_format: "%Y-%m-%dT%H:%M:%SZ"
|
|
end_datetime:
|
|
type: MinMaxDatetime
|
|
datetime: "{{ now_utc().strftime('%Y-%m-%dT%H:%M:%SZ') }}"
|
|
datetime_format: "%Y-%m-%dT%H:%M:%SZ"
|
|
schema_loader:
|
|
type: InlineSchemaLoader
|
|
schema:
|
|
$ref: "#/schemas/postcards"
|
|
templates:
|
|
type: DeclarativeStream
|
|
name: templates
|
|
primary_key:
|
|
- id
|
|
retriever:
|
|
type: SimpleRetriever
|
|
requester:
|
|
$ref: "#/definitions/base_requester"
|
|
path: templates
|
|
http_method: GET
|
|
request_parameters:
|
|
limit: "{{ config['limit'] }}"
|
|
error_handler:
|
|
type: CompositeErrorHandler
|
|
error_handlers:
|
|
- type: DefaultErrorHandler
|
|
max_retries: 3
|
|
backoff_strategies:
|
|
- type: ExponentialBackoffStrategy
|
|
factor: 2
|
|
response_filters:
|
|
- type: HttpResponseFilter
|
|
action: RATE_LIMITED
|
|
http_codes:
|
|
- 429
|
|
error_message: Rate limits hit
|
|
record_selector:
|
|
type: RecordSelector
|
|
extractor:
|
|
type: DpathExtractor
|
|
field_path:
|
|
- data
|
|
paginator:
|
|
type: DefaultPaginator
|
|
page_token_option:
|
|
type: RequestPath
|
|
pagination_strategy:
|
|
type: CursorPagination
|
|
cursor_value: "{{ response.get('next_url') }}"
|
|
stop_condition: "{{ response.get('next_url') is none }}"
|
|
incremental_sync:
|
|
type: DatetimeBasedCursor
|
|
cursor_field: date_modified
|
|
cursor_datetime_formats:
|
|
- "%Y-%m-%dT%H:%M:%S.%fZ"
|
|
datetime_format: "%Y-%m-%dT%H:%M:%S.%fZ"
|
|
start_datetime:
|
|
type: MinMaxDatetime
|
|
datetime: '{{ config["start_date"] }}'
|
|
datetime_format: "%Y-%m-%dT%H:%M:%SZ"
|
|
end_datetime:
|
|
type: MinMaxDatetime
|
|
datetime: "{{ now_utc().strftime('%Y-%m-%dT%H:%M:%SZ') }}"
|
|
datetime_format: "%Y-%m-%dT%H:%M:%SZ"
|
|
schema_loader:
|
|
type: InlineSchemaLoader
|
|
schema:
|
|
$ref: "#/schemas/templates"
|
|
templates_versions:
|
|
type: DeclarativeStream
|
|
name: templates_versions
|
|
primary_key:
|
|
- id
|
|
retriever:
|
|
type: SimpleRetriever
|
|
requester:
|
|
$ref: "#/definitions/base_requester"
|
|
path: templates/{{ stream_partition.tmpl_id }}/versions
|
|
http_method: GET
|
|
request_parameters:
|
|
limit: "{{ config['limit'] }}"
|
|
error_handler:
|
|
type: CompositeErrorHandler
|
|
error_handlers:
|
|
- type: DefaultErrorHandler
|
|
max_retries: 3
|
|
backoff_strategies:
|
|
- type: ExponentialBackoffStrategy
|
|
factor: 2
|
|
response_filters:
|
|
- type: HttpResponseFilter
|
|
action: RATE_LIMITED
|
|
http_codes:
|
|
- 429
|
|
error_message: Rate limits hit
|
|
record_selector:
|
|
type: RecordSelector
|
|
extractor:
|
|
type: DpathExtractor
|
|
field_path:
|
|
- data
|
|
paginator:
|
|
type: DefaultPaginator
|
|
page_token_option:
|
|
type: RequestPath
|
|
pagination_strategy:
|
|
type: CursorPagination
|
|
cursor_value: "{{ response.get('next_url') }}"
|
|
stop_condition: "{{ response.get('next_url') is none }}"
|
|
partition_router:
|
|
type: SubstreamPartitionRouter
|
|
parent_stream_configs:
|
|
- type: ParentStreamConfig
|
|
parent_key: id
|
|
partition_field: tmpl_id
|
|
stream:
|
|
$ref: "#/definitions/streams/templates"
|
|
incremental_sync:
|
|
type: DatetimeBasedCursor
|
|
cursor_field: date_modified
|
|
cursor_datetime_formats:
|
|
- "%Y-%m-%dT%H:%M:%S.%fZ"
|
|
datetime_format: "%Y-%m-%dT%H:%M:%S.%fZ"
|
|
start_datetime:
|
|
type: MinMaxDatetime
|
|
datetime: '{{ config["start_date"] }}'
|
|
datetime_format: "%Y-%m-%dT%H:%M:%SZ"
|
|
end_datetime:
|
|
type: MinMaxDatetime
|
|
datetime: "{{ now_utc().strftime('%Y-%m-%dT%H:%M:%SZ') }}"
|
|
datetime_format: "%Y-%m-%dT%H:%M:%SZ"
|
|
schema_loader:
|
|
type: InlineSchemaLoader
|
|
schema:
|
|
$ref: "#/schemas/templates_versions"
|
|
campaigns:
|
|
type: DeclarativeStream
|
|
name: campaigns
|
|
primary_key:
|
|
- id
|
|
retriever:
|
|
type: SimpleRetriever
|
|
requester:
|
|
$ref: "#/definitions/base_requester"
|
|
path: campaigns
|
|
http_method: GET
|
|
request_parameters:
|
|
limit: "{{ config['limit'] }}"
|
|
error_handler:
|
|
type: CompositeErrorHandler
|
|
error_handlers:
|
|
- type: DefaultErrorHandler
|
|
max_retries: 3
|
|
backoff_strategies:
|
|
- type: ExponentialBackoffStrategy
|
|
factor: 2
|
|
response_filters:
|
|
- type: HttpResponseFilter
|
|
action: RATE_LIMITED
|
|
http_codes:
|
|
- 429
|
|
error_message: Rate limits hit
|
|
record_selector:
|
|
type: RecordSelector
|
|
extractor:
|
|
type: DpathExtractor
|
|
field_path:
|
|
- data
|
|
paginator:
|
|
type: DefaultPaginator
|
|
page_token_option:
|
|
type: RequestPath
|
|
pagination_strategy:
|
|
type: CursorPagination
|
|
cursor_value: "{{ response.get('next_url') }}"
|
|
stop_condition: "{{ response.get('next_url') is none }}"
|
|
incremental_sync:
|
|
type: DatetimeBasedCursor
|
|
cursor_field: date_modified
|
|
cursor_datetime_formats:
|
|
- "%Y-%m-%dT%H:%M:%S.%fZ"
|
|
datetime_format: "%Y-%m-%dT%H:%M:%S.%fZ"
|
|
start_datetime:
|
|
type: MinMaxDatetime
|
|
datetime: '{{ config["start_date"] }}'
|
|
datetime_format: "%Y-%m-%dT%H:%M:%SZ"
|
|
end_datetime:
|
|
type: MinMaxDatetime
|
|
datetime: "{{ now_utc().strftime('%Y-%m-%dT%H:%M:%SZ') }}"
|
|
datetime_format: "%Y-%m-%dT%H:%M:%SZ"
|
|
schema_loader:
|
|
type: InlineSchemaLoader
|
|
schema:
|
|
$ref: "#/schemas/campaigns"
|
|
uploads:
|
|
type: DeclarativeStream
|
|
name: uploads
|
|
primary_key:
|
|
- id
|
|
retriever:
|
|
type: SimpleRetriever
|
|
requester:
|
|
$ref: "#/definitions/base_requester"
|
|
path: uploads
|
|
http_method: GET
|
|
request_parameters:
|
|
campaignId: "{{ stream_partition.cmp_id }}"
|
|
error_handler:
|
|
type: CompositeErrorHandler
|
|
error_handlers:
|
|
- type: DefaultErrorHandler
|
|
max_retries: 3
|
|
backoff_strategies:
|
|
- type: ExponentialBackoffStrategy
|
|
factor: 2
|
|
response_filters:
|
|
- type: HttpResponseFilter
|
|
action: RATE_LIMITED
|
|
http_codes:
|
|
- 429
|
|
error_message: Rate limits hit
|
|
record_selector:
|
|
type: RecordSelector
|
|
extractor:
|
|
type: DpathExtractor
|
|
field_path: []
|
|
paginator:
|
|
type: DefaultPaginator
|
|
page_token_option:
|
|
type: RequestPath
|
|
pagination_strategy:
|
|
type: CursorPagination
|
|
cursor_value: "{{ response.get('next_url') }}"
|
|
stop_condition: "{{ response.get('next_url') is none }}"
|
|
partition_router:
|
|
type: SubstreamPartitionRouter
|
|
parent_stream_configs:
|
|
- type: ParentStreamConfig
|
|
parent_key: id
|
|
partition_field: cmp_id
|
|
stream:
|
|
$ref: "#/definitions/streams/campaigns"
|
|
incremental_sync:
|
|
type: DatetimeBasedCursor
|
|
cursor_field: dateModified
|
|
cursor_datetime_formats:
|
|
- "%Y-%m-%dT%H:%M:%S.%fZ"
|
|
datetime_format: "%Y-%m-%dT%H:%M:%S.%fZ"
|
|
start_datetime:
|
|
type: MinMaxDatetime
|
|
datetime: '{{ config["start_date"] }}'
|
|
datetime_format: "%Y-%m-%dT%H:%M:%SZ"
|
|
end_datetime:
|
|
type: MinMaxDatetime
|
|
datetime: "{{ now_utc().strftime('%Y-%m-%dT%H:%M:%SZ') }}"
|
|
datetime_format: "%Y-%m-%dT%H:%M:%SZ"
|
|
schema_loader:
|
|
type: InlineSchemaLoader
|
|
schema:
|
|
$ref: "#/schemas/uploads"
|
|
qr_code_analytics:
|
|
type: DeclarativeStream
|
|
name: qr_code_analytics
|
|
primary_key:
|
|
- resource_id
|
|
retriever:
|
|
type: SimpleRetriever
|
|
requester:
|
|
$ref: "#/definitions/base_requester"
|
|
path: qr_code_analytics
|
|
http_method: GET
|
|
request_parameters:
|
|
limit: "{{ config['limit'] }}"
|
|
error_handler:
|
|
type: CompositeErrorHandler
|
|
error_handlers:
|
|
- type: DefaultErrorHandler
|
|
max_retries: 3
|
|
backoff_strategies:
|
|
- type: ExponentialBackoffStrategy
|
|
factor: 2
|
|
response_filters:
|
|
- type: HttpResponseFilter
|
|
action: RATE_LIMITED
|
|
http_codes:
|
|
- 429
|
|
error_message: Rate limits hit
|
|
record_selector:
|
|
type: RecordSelector
|
|
extractor:
|
|
type: DpathExtractor
|
|
field_path:
|
|
- data
|
|
paginator:
|
|
type: DefaultPaginator
|
|
page_token_option:
|
|
type: RequestPath
|
|
pagination_strategy:
|
|
type: CursorPagination
|
|
cursor_value: "{{ response.get('next_url') }}"
|
|
stop_condition: "{{ response.get('next_url') is none }}"
|
|
incremental_sync:
|
|
type: DatetimeBasedCursor
|
|
cursor_field: date_created
|
|
cursor_datetime_formats:
|
|
- "%Y-%m-%dT%H:%M:%S.%fZ"
|
|
datetime_format: "%Y-%m-%dT%H:%M:%S.%fZ"
|
|
start_datetime:
|
|
type: MinMaxDatetime
|
|
datetime: '{{ config["start_date"] }}'
|
|
datetime_format: "%Y-%m-%dT%H:%M:%SZ"
|
|
end_datetime:
|
|
type: MinMaxDatetime
|
|
datetime: "{{ now_utc().strftime('%Y-%m-%dT%H:%M:%SZ') }}"
|
|
datetime_format: "%Y-%m-%dT%H:%M:%SZ"
|
|
schema_loader:
|
|
type: InlineSchemaLoader
|
|
schema:
|
|
$ref: "#/schemas/qr_code_analytics"
|
|
base_requester:
|
|
type: HttpRequester
|
|
url_base: https://api.lob.com/v1/
|
|
authenticator:
|
|
type: BasicHttpAuthenticator
|
|
username: '{{ config["api_key"] }}'
|
|
|
|
streams:
|
|
- $ref: "#/definitions/streams/addresses"
|
|
- $ref: "#/definitions/streams/banks"
|
|
- $ref: "#/definitions/streams/postcards"
|
|
- $ref: "#/definitions/streams/templates"
|
|
- $ref: "#/definitions/streams/templates_versions"
|
|
- $ref: "#/definitions/streams/campaigns"
|
|
- $ref: "#/definitions/streams/uploads"
|
|
- $ref: "#/definitions/streams/qr_code_analytics"
|
|
|
|
spec:
|
|
type: Spec
|
|
connection_specification:
|
|
type: object
|
|
$schema: http://json-schema.org/draft-07/schema#
|
|
required:
|
|
- api_key
|
|
- start_date
|
|
properties:
|
|
api_key:
|
|
type: string
|
|
description: >-
|
|
API key to use for authentication. You can find your account's API
|
|
keys in your Dashboard Settings at
|
|
https://dashboard.lob.com/settings/api-keys.
|
|
name: api_key
|
|
order: 0
|
|
title: API Key
|
|
airbyte_secret: true
|
|
start_date:
|
|
type: string
|
|
order: 1
|
|
title: Start date
|
|
format: date-time
|
|
pattern: ^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$
|
|
limit:
|
|
type: string
|
|
description: Max records per page limit
|
|
order: 2
|
|
title: Limit
|
|
default: "50"
|
|
additionalProperties: true
|
|
|
|
metadata:
|
|
autoImportSchema:
|
|
addresses: false
|
|
banks: false
|
|
postcards: false
|
|
templates: false
|
|
templates_versions: false
|
|
campaigns: false
|
|
uploads: false
|
|
qr_code_analytics: false
|
|
yamlComponents:
|
|
global:
|
|
- authenticator
|
|
testedStreams:
|
|
addresses:
|
|
streamHash: 711246651bb3f43c08f53c18277b2dfeb4a696f3
|
|
hasResponse: true
|
|
responsesAreSuccessful: true
|
|
hasRecords: true
|
|
primaryKeysArePresent: true
|
|
primaryKeysAreUnique: true
|
|
banks:
|
|
streamHash: 38a964896ee36814e5ff4dd40bae81844a952c44
|
|
hasResponse: true
|
|
responsesAreSuccessful: true
|
|
hasRecords: true
|
|
primaryKeysArePresent: true
|
|
primaryKeysAreUnique: true
|
|
postcards:
|
|
streamHash: 6a9f97666263853a2228b1260e23dd1f513ee39b
|
|
hasResponse: true
|
|
responsesAreSuccessful: true
|
|
hasRecords: true
|
|
primaryKeysArePresent: true
|
|
primaryKeysAreUnique: true
|
|
templates:
|
|
streamHash: f39abd5fe21b958c5ae64e8aaa4b833e2684e164
|
|
hasResponse: true
|
|
responsesAreSuccessful: true
|
|
hasRecords: true
|
|
primaryKeysArePresent: true
|
|
primaryKeysAreUnique: true
|
|
templates_versions:
|
|
streamHash: 73bf858614649dd69f7eef4c2684c8ea13eb1478
|
|
hasResponse: true
|
|
responsesAreSuccessful: true
|
|
hasRecords: true
|
|
primaryKeysArePresent: true
|
|
primaryKeysAreUnique: true
|
|
campaigns:
|
|
streamHash: b6532212caec8e2760c379b66a849dfdb498330b
|
|
hasResponse: true
|
|
responsesAreSuccessful: true
|
|
hasRecords: true
|
|
primaryKeysArePresent: true
|
|
primaryKeysAreUnique: true
|
|
uploads:
|
|
streamHash: 11a141613dd26027c4a57e5a74e337c795592146
|
|
hasResponse: true
|
|
responsesAreSuccessful: true
|
|
hasRecords: true
|
|
primaryKeysArePresent: true
|
|
primaryKeysAreUnique: true
|
|
qr_code_analytics:
|
|
streamHash: 589c594ff994d791a63dd033ab3fe661b7f1a950
|
|
hasResponse: true
|
|
responsesAreSuccessful: true
|
|
hasRecords: true
|
|
primaryKeysArePresent: true
|
|
primaryKeysAreUnique: true
|
|
assist:
|
|
docsUrl: https://docs.lob.com/#tag/Introduction
|
|
|
|
schemas:
|
|
addresses:
|
|
type: object
|
|
$schema: http://json-schema.org/draft-07/schema#
|
|
additionalProperties: true
|
|
properties: {}
|
|
banks:
|
|
type: object
|
|
$schema: http://json-schema.org/draft-07/schema#
|
|
additionalProperties: true
|
|
properties: {}
|
|
postcards:
|
|
type: object
|
|
$schema: http://json-schema.org/draft-07/schema#
|
|
additionalProperties: true
|
|
properties: {}
|
|
templates:
|
|
type: object
|
|
$schema: http://json-schema.org/draft-07/schema#
|
|
additionalProperties: true
|
|
properties: {}
|
|
templates_versions:
|
|
type: object
|
|
$schema: http://json-schema.org/draft-07/schema#
|
|
additionalProperties: true
|
|
properties: {}
|
|
campaigns:
|
|
type: object
|
|
$schema: http://json-schema.org/draft-07/schema#
|
|
additionalProperties: true
|
|
properties: {}
|
|
uploads:
|
|
type: object
|
|
$schema: http://json-schema.org/draft-07/schema#
|
|
additionalProperties: true
|
|
properties: {}
|
|
qr_code_analytics:
|
|
type: object
|
|
$schema: http://json-schema.org/draft-07/schema#
|
|
additionalProperties: true
|
|
properties: {}
|