From 85018787f8d0f494155edacfbb3215df47e722f7 Mon Sep 17 00:00:00 2001 From: Alex Tweeddale Date: Tue, 18 Jun 2024 20:13:12 +1000 Subject: [PATCH] Fixed all formatting issues I went and fixed all the bikeshed formatting issues, converting markdown to HTML where necessary --- index.bs | 333 ++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 231 insertions(+), 102 deletions(-) diff --git a/index.bs b/index.bs index ad55fcc..2eed051 100644 --- a/index.bs +++ b/index.bs @@ -14,9 +14,11 @@ Introduction {#intro} DID-Linked Resources are digital files that can be retrieved and referenced using a persistent and unique DID URL. -This specification defines common requirements, algorithms including their request formats and response formats, architectural options, and various considerations for how DID-Linked Resources SHOULD act as persistent identifiers for referencing and retrieving digital Resources (such as data schemas, status lists, trust registries, governance documents, or policy definitions). This specification complements the [DID Resolution Specification](https://w3c-ccg.github.io/did-resolution/), including its patterns and algorithms for DID URL resolution and dereferencing. By using DID URLs which remain conformant with W3C Decentralized Identifiers (DIDs) v1.0 Recommendation [[DID-CORE]] and the [DID Resolution Specification](https://w3c-ccg.github.io/did-resolution/), existing DID Resolvers will be able to dereference these DID URLs to retrieve the identified resources using the DID URL query syntax in this specification. +This specification defines common requirements, algorithms including their request formats and response formats, architectural options, and various considerations for how DID-Linked Resources SHOULD act as persistent identifiers for referencing and retrieving digital Resources (such as data schemas, status lists, trust registries, governance documents, or policy definitions). This specification complements the DID Resolution Specification, including its patterns and algorithms for DID URL resolution and dereferencing. -_**Note:** While this specification defines some base-level functionality for DID URL dereferencing, the actual steps required to communicate with a DID's verifiable data registry are defined by the applicable DID method specification. +By using DID URLs which remain conformant with W3C Decentralized Identifiers (DIDs) v1.0 Recommendation [[DID-CORE]] and the DID Resolution Specification, existing DID Resolvers will be able to dereference these DID URLs to retrieve the identified resources using the DID URL query syntax in this specification. + +Note: while this specification defines some base-level functionality for DID URL dereferencing, the actual steps required to communicate with a DID's verifiable data registry are defined by the applicable DID method specification. Conformance {#conformance} --------------------- @@ -44,34 +46,36 @@ Terminology {#terminology} DID-Linked Resources {#resources} ===================== +This section explains the context for building DID-Linked Resources, as well as their fundamental components for construction. + DID-Linked Resources context {#context} --------------------- -The [[DID Core]] specification defines an interoperable standard for DID documents and associated core properties, however it does not currently have a standardized way to specify properties of Resources associated with DIDs, nor how to consistently reference nor retrieve them. +The [[DID-CORE]] specification defines an interoperable standard for DID documents and associated core properties, however it does not currently have a standardized way to specify properties of Resources associated with DIDs, nor how to consistently reference nor retrieve them. + +Digital Resources are generally stored on traditional centralized-storage endpoints, but this comes with certain drawbacks: -Digital Resources are _generally_ stored on traditional centralized-storage endpoints, but this comes with certain drawbacks: +1. Digital Resources could be tampered with by compromising the hosting provider: Digital Resources stored at a centralized web endpoint can be compromised and replaced by malicious actors. +2. Hosting providers could unilaterally cease to host particular clients: Hosting providers could terminate accounts due to factors such as non-payment of fees, violation of Terms of Service, etc. +3. Single point of failure (SPOF): Even with highly-trusted and sophisticated hosting providers who may not present a risk of infrastructure being compromised, a service outage at the hosting provider can make a Resource anchored on their systems inaccessible. -1. **Digital Resources could be tampered with by compromising the hosting provider**: Digital Resources stored at a centralized web endpoint can be compromised and replaced by malicious actors. -2. **Hosting providers could unilaterally cease to host particular clients**: Hosting providers could terminate accounts due to factors such as non-payment of fees, violation of Terms of Service, etc. -3. **[Single point of failure (SPOF)](https://dbpedia.org/resource/Single_point_of_failure) in resiliency**: Even with highly-trusted and sophisticated hosting providers who may not present a risk of infrastructure being compromised, a service outage at the hosting provider can make a Resource anchored on their systems inaccessible. +Despite these issues, many decentralized identity or Digital Credential implementations, even ones that use ledgers or other distributed systems for DIDs, often utilize centralized storage. From the W3C Verifiable Credential Implementation Guide. -Despite these issues, many decentralized identity or Digital Credential implementations, _even ones that use ledgers or other distributed systems for DIDs_, often utilize centralized storage. From the [W3C Verifiable Credential Implementation Guide](https://w3c.github.io/vc-imp-guide/#creating-new-credential-types): +Example schema.org address with full URLs: -> Example schema.org address with full URLs: -> -> ```json -> { -> "@type": "http://schema.org/Person", -> "http://schema.org/address": { -> "@type": "http://schema.org/PostalAddress", -> "http://schema.org/streetAddress": "123 Main St.", -> "http://schema.org/addressLocality": "Blacksburg", -> "http://schema.org/addressRegion": "VA", -> "http://schema.org/postalCode": "24060", -> "http://schema.org/addressCountry": "US" -> } -> } -> ``` +```json + { + "@type": "http://schema.org/Person", + "http://schema.org/address": { + "@type": "http://schema.org/PostalAddress", + "http://schema.org/streetAddress": "123 Main St.", + "http://schema.org/addressLocality": "Blacksburg", + "http://schema.org/addressRegion": "VA", + "http://schema.org/postalCode": "24060", + "http://schema.org/addressCountry": "US" + } + } +``` Using traditional web endpoints to store digital resources that are critical for a Verifiable Credential to function, detracts from the proper functioning and utility that persistently-accessible Decentralized Identifiers offer. This has also resulted in inconsistent and unstandardized approaches to storing, referencing, and retrieving digital resources such as schemas, trusted issuer lists and status lists. @@ -84,9 +88,11 @@ Using UUIDs ensures a high level of confidence that no two identical Resource ID The following path-based syntax is an example of how a DID Method may construct a DID URL to point to a DID-Linked Resource: -`did:example:/resources/` + ```json +did:example:/resources/ +``` -_**Note:** The above path-based syntax would be an implementation-specific way of referencing a resource._ +Note: The above path-based syntax would be an implementation-specific way of referencing a resource. DID-Linked Resource Collections {#collections} --------------------- @@ -98,11 +104,17 @@ The most important concept used in this design is that each Collection is identi The DID document acts as metadata, providing information about the Collection, such as who is able to update it, when it was created, and what are the latest and/or deprecated versions of Resources within the Collection. For example, the following DID: -`did:example:0a5b94d0-a417-48ed-a6f5-4abc9e95888d` + ```json +did:example:0a5b94d0-a417-48ed-a6f5-4abc9e95888d +``` + +will derive the Collection ID: -will derive the Collection ID: `0a5b94d0-a417-48ed-a6f5-4abc9e95888d` +```json +0a5b94d0-a417-48ed-a6f5-4abc9e95888d +``` -_**Note:** The Collection ID may take the syntactical form of the DID method that the DID-Linked Resource is associated with._ +Note: The Collection ID may take the syntactical form of the DID method that the DID-Linked Resource is associated with. DID-Linked Resources Algorithm {#algorithm} ===================== @@ -120,7 +132,7 @@ Next, to create a digital Resource associated with the "parent" DID, you MUST pr As a response, the DID Document SHOULD append metadata about the DID-Linked Resource into the existing DID Document Metadata. -> ```json +```json { "@context": "https://w3id.org/did-resolution/v1", "didResolutionMetadata": { @@ -182,7 +194,7 @@ As a response, the DID Document SHOULD append metadata about the DID-Linked Reso ] } } -> ``` +``` Linking DIDs to Resources and Collections {#linkage} ===================== @@ -191,14 +203,12 @@ Multiple Resources can be stored within a Collection and linked to the same DID; Once you have created a resource, the DID document will automatically reference the resource and the collection within the `didDocumentMetadata` in a newly defined section called `linkedResourceMetadata`. -This relationship is shown in the diagram below: - -Relationship between DIDs and DID-Linked Resources - Architecture Overview {#archoverview} ===================== -DID-Linked Resources Architecture Overview +The relationship between DIDs, Resource Collections and Resources is shown in the diagram below: + +DID-Linked Resources Architecture Overview Design principles {#principles} ===================== @@ -217,35 +227,116 @@ Resource Request Parameters {#request} The following list defines which specific parameters are required and are optional for a request to create a resource: -| Parameter | Type | Required? | -| ------------------------- | ------------------------------------------------------------- | ----------- | -| `"resourceCollectionId"` | A [String](https://infra.spec.whatwg.org/#string) that conforms to a unique identifier format for an associated DID method | Yes | -| `"resourceId"` | A [String](https://infra.spec.whatwg.org/#string), such as a UUID, that uniquely identifies the resource | Yes | -| `"resourceName"` | A [String](https://infra.spec.whatwg.org/#string) that names and identifies a resource. This property, along with the `resourceType` below, can be used to track version changes within a resource | Yes | -| `"resourceType"` | A [String](https://infra.spec.whatwg.org/#string), such as a UUID, that uniquely identifies the resource | Yes | -| `"resourceVersion"` | A [String](https://infra.spec.whatwg.org/#string) identifies the type of resource. This property, along with the `resourceName` above, can be used to track version changes within a resource | No | -| `"alsoKnownAs"` | An [array](https://infra.spec.whatwg.org/#array) that describes alternative URIs for the resource | No | + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeRequired?
"resourceCollectionId"A String that conforms to a unique identifier format for an associated DID methodYes
"resourceId"A String, such as a UUID, that uniquely identifies the resourceYes
"resourceName"A String that names and identifies a resource. This property, along with the resourceType below, can be used to track version changes within a resourceYes
"resourceType"A String that uniquely identifies the type of resourceYes
"resourceVersion"A String that identifies the version of the resource. This property, along with the resourceName above, can be used to track version changes within a resourceNo
"alsoKnownAs"An array that describes alternative URIs for the resourceNo
Resource Response Parameters {#response} ===================== The following list defines which specific parameters are required and which are optional for a response, following the creation of a Resource: -| Parameter | Description | -| :--- | :--- | -| **`resourceUri`** | A string or a map that conforms to the rules of [[RFC3986]] URIs which SHOULD directly lead to a location where the resource can be accessed. For example: `did:example:46e2af9a-2ea0-4815-999d-730a6778227c/resources/0f964a80-5d18-4867-83e3-b47f5a756f02`. | -| **`resourceCollectionId`** | A string that conforms to a method-specific supported unique identifier format. For example, a UUID: `46e2af9a-2ea0-4815-999d-730a6778227c`. | -| **`resourceId`** | A string that uniquely identifies the resource. For example, a UUID: `0f964a80-5d18-4867-83e3-b47f5a756f02`. | -| **`resourceName`** | A string that uniquely names and identifies a resource. This property, along with the `resourceType` below, can be used to track version changes within a resource. | -| **`resourceType`** | A string that identifies the type of resource. This property, along with the `resourceName` above, can be used to track version changes within a resource. Not to be confused with `mediaType`. | -| **`resourceVersion`** | (Optional) A string that identifies the version of the resource. This property is provided by the client and can be any value. | -| **`alsoKnownAs`** | (Optional) An array that describes alternative URIs for the resource. | -| **`mediaType`** | A string that identifies the IANA-media type of the resource. | -| **`created`** | A string that identifies the time the resource was created, as an XML date-time. | -| **`updated`** | (Optional) A string that identifies the time the resource was updated, as an XML date-time. | -| **`checksum`** | A string that may be used to prove that the resource has not been tampered with. | -| **`previousVersionId`** | (Optional) A string that identifies the previous version of the resource. | -| **`nextVersionId`** | (Optional) A string that identifies the next version of the resource. | + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterDescription
resourceUriA string or a map that conforms to the rules of RFC3986 URIs which SHOULD directly lead to a location where the resource can be accessed. For example: did:example:46e2af9a-2ea0-4815-999d-730a6778227c/resources/0f964a80-5d18-4867-83e3-b47f5a756f02.
resourceCollectionIdA string that conforms to a method-specific supported unique identifier format. For example, a UUID: 46e2af9a-2ea0-4815-999d-730a6778227c.
resourceIdA string that uniquely identifies the resource. For example, a UUID: 0f964a80-5d18-4867-83e3-b47f5a756f02.
resourceNameA string that uniquely names and identifies a resource. This property, along with the resourceType below, can be used to track version changes within a resource.
resourceTypeA string that identifies the type of resource. This property, along with the resourceName above, can be used to track version changes within a resource. Not to be confused with mediaType.
resourceVersion(Optional) A string that identifies the version of the resource. This property is provided by the client and can be any value.
alsoKnownAs(Optional) An array that describes alternative URIs for the resource.
mediaTypeA string that identifies the IANA-media type of the resource.
createdA string that identifies the time the resource was created, as an XML date-time.
updated(Optional) A string that identifies the time the resource was updated, as an XML date-time.
checksumA string that may be used to prove that the resource has not been tampered with.
previousVersionId(Optional) A string that identifies the previous version of the resource.
nextVersionId(Optional) A string that identifies the next version of the resource.
+ Discoverability via DIDDoc Metadata {#discoverability} @@ -294,7 +385,7 @@ The syntax of the linked Resource metadata is as follows: } ``` -Importantly, we decided not to populate the `didDocumentMetadata` with the actual resource data, but instead, populate what we refer to as a _Resource Preview_ which contains all the metadata about the associated resources. +Importantly, we decided not to populate the `didDocumentMetadata` with the actual resource data, but instead, populate what we refer to as a Resource Preview which contains all the metadata about the associated resources. Composition of Resource Preview {#preview} --------------------- @@ -355,26 +446,64 @@ Resource resolution and dereferencing {#dereferencing} Normal DID URL dereferencing can be conceived in two steps: 1. A DID is resolved to a DID Document; -2. A resource within / associated with the DID Document is identified, based on the portion of the DID URL that follows the DID (path, query, fragment as defined by the ABNF in section 3.2 of the DID 1.0 specification.). +2. A resource within / associated with the DID Document is identified, based on the portion of the DID URL that follows the DID (path, query, fragment as defined by the ABNF in section 3.2 of the [[DID-CORE]] specification.). Requests to fetch Resources are considered as a DID URL Dereferencing scenario it uses [DID URL paths](https://w3c.github.io/did-core/#path) to lead to a Resource object, rather than a DIDDoc. -On the other hand, Resources _metadata_ requests are handled like DID URL Resolution since the result is a subsection of `didDocumentMetadata` specific to that resource. +On the other hand, Resources metadata requests are handled like DID URL Resolution since the result is a subsection of `didDocumentMetadata` specific to that resource. Resource resolution and dereferencing parameters --------------------- Here we have an ability to specify different parameters to filter to particular DID-Linked Resources. -| Parameter | Type | Description | -| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- | -| `resourceId` | A [string](https://infra.spec.whatwg.org/#string) that conforms to a method specific unique identifier format. | The unique identifier of a particular DID-Linked Resource | -| `resourceCollectionId` | A [string](https://infra.spec.whatwg.org/#string) that conforms to a method specific unique identifier format. | Can be used to query all resources associated with a DID if combined with resourceMetadata=true | -| `resourceName` | A [string](https://infra.spec.whatwg.org/#string) | The specific name of a DID-Linked Resource | -| `resourceType` | A [string](https://infra.spec.whatwg.org/#string) | The specific type of a DID-Linked Resource | -| `resourceVersionTime` | A [JSON String](https://www.rfc-editor.org/rfc/rfc8259#section-7) serialized as an [XML Datetime](https://www.w3.org/TR/xmlschema11-2/#dateTime) normalized to UTC 00:00:00 and without sub-second decimal precision. | Used to fetch a version of a resource at a specific point in time | -| `checksum` | A [string](https://infra.spec.whatwg.org/#string) | Used to specify a particular resource checksum to demonstrate it is untampered | -| `resourceMetadata` | [Boolean](https://infra.spec.whatwg.org/#booleans) | Used to fetch metadata related to a specific resource or group of resources | + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
resourceIdA string that conforms to a method specific unique identifier format.The unique identifier of a particular DID-Linked Resource.
resourceCollectionIdA string that conforms to a method specific unique identifier format.Can be used to query all resources associated with a DID if combined with resourceMetadata=true.
resourceNameA string.The specific name of a DID-Linked Resource.
resourceTypeA string.The specific type of a DID-Linked Resource.
resourceVersionTimeA JSON String serialized as an XML Datetime normalized to UTC 00:00:00 and without sub-second decimal precision.Used to fetch a version of a resource at a specific point in time.
checksumA string.Used to specify a particular resource checksum to demonstrate it is untampered.
resourceMetadataBoolean.Used to fetch metadata related to a specific resource or group of resources.
+ Like with DIDDoc query parameters, these can all be chained together to create complex requests for specific DID-Linked Resources at particular points in time or associated with particular DIDDoc versions. @@ -383,17 +512,17 @@ Rules and logic for handling ambiguous queries It is important to understand how our resolver logically handles more complex dereferencing requests. We have set some baseline defaults and rules to ensure a logical and consistent experience for clients who use our resolver. -### **Ambiguity generally throws an error** ### +### Ambiguity generally throws an error -If the request specifies a parameter where there are multiple potential results, such as where the DID has two resources of the same `resourceType` ('String') but `resourceName` is not the same, an error will be thrown because there is not enough information to discern which resource is being requested. +If the request specifies a parameter where there are multiple potential results, such as where the DID has two resources of the same `resourceType` but `resourceName` is not the same, an error will be thrown because there is not enough information to discern which resource is being requested. -### **Multiple versions of the same resource** ### +### Multiple versions of the same resource -If there are multiple resources with the same `resourceType` and `resourceName` but with different `versionIds,` and there is no parameter specified to fetch a particular version, **the resolver will fetch the latest resource by default**. +If there are multiple resources with the same `resourceType` and `resourceName` but with different `versionIds,` and there is no parameter specified to fetch a particular version, the resolver will fetch the latest resource by default. This is because the query is not ambiguous in terms of discerning which set of resources to dereference to, but is only ambiguous in terms of which version of that resource to fetch. -### **Ambiguity + resourceMetadata=true** ### +### Ambiguity + resourceMetadata=true If there is an ambiguous query, such as where there are two resources with the same name but different types, AND there is a resourceMetadata=true parameter, resource data pertaining to all the resources which could potentially be seen as being ambiguous will be returned. @@ -403,8 +532,8 @@ For example, in the below example, there are multiple resources with the `resour Request format -``` -1.0/identifiers/did:example:c1685ca0-1f5b-439c-8eb8-5c0e85ab7cd0?resourceType=String&resourceMetadata=true +```json +did:example:c1685ca0-1f5b-439c-8eb8-5c0e85ab7cd0?resourceType=String&resourceMetadata=true ``` @@ -471,14 +600,14 @@ ResourceId `ResourceId` parameter can be used for filtering a particular resource version by specifically identifying its unique ID. -**Example**: +For example:
Request format -``` -1.0/identifiers/did:example:b5d70adf-31ca-4662-aa10-d3a54cd8f06c?resourceId=5e16a3f9-7c6e-4b6b-8e28-20f56780ee25 +```json +did:example:b5d70adf-31ca-4662-aa10-d3a54cd8f06c?resourceId=5e16a3f9-7c6e-4b6b-8e28-20f56780ee25 ```
@@ -514,14 +643,14 @@ ResourceCollectionId `resourceCollectionId` parameter filters all the resource by `collectionId` field. By default cause we are asking for resources for a particular DID it already includes all the resource with the same `collectionId` and this parameter can used mostly as sanity check. Without `resourceMetadata=true` parameter will return the latest created resource if there is only one resource or an unambiguous resource. -**Example**: +For example:
Request format -``` -1.0/identifiers/did:example:d8ac0372-0d4b-413e-8ef5-8e8f07822b2c?resourceCollectionId=d8ac0372-0d4b-413e-8ef5-8e8f07822b2c +```json +did:example:d8ac0372-0d4b-413e-8ef5-8e8f07822b2c?resourceCollectionId=d8ac0372-0d4b-413e-8ef5-8e8f07822b2c ```
@@ -558,14 +687,14 @@ ResourceType This parameter is also just a filter by `Type` field through resources. But there is a corner case if the user asks about exact resource (exact data). If after applying all the parameters in request several resources are left with the same `Name` - the latest one will be responded. Otherwise - error `NotFoundError` will be raised. -**Example**: +For example:
Request format -``` -1.0/identifiers/did:example:d8ac0372-0d4b-413e-8ef5-8e8f07822b2c?resourceType=exampleResourceType +```json +did:example:d8ac0372-0d4b-413e-8ef5-8e8f07822b2c?resourceType=exampleResourceType ```
@@ -603,14 +732,14 @@ ResourceName Behavior of this parameter is similar with [resourceType](adr-005-did-resolution-and-did-url-dereferencing.md#resourcetype) one. If there is no ambiguous resource, it will be fetched. Otherwise greater specifity is required. -**Example**: +For example:
Request format -``` -1.0/identifiers/did:example:d8ac0372-0d4b-413e-8ef5-8e8f07822b2c?resourceName=exampleResourceName +```json +did:example:d8ac0372-0d4b-413e-8ef5-8e8f07822b2c?resourceName=exampleResourceName ```
@@ -646,14 +775,14 @@ ResourceVersion This parameter filters by `Version` field. We introduced it with latest network upgrade and can be optionally set to identify a version of a resource with a particular string. -**Example**: +For example:
Request format -``` -1.0/identifiers/did:example:d8ac0372-0d4b-413e-8ef5-8e8f07822b2c?resourceVersion=b9029cf7-c40b-4850-b9a1-9bfad46a68d7 +```json +did:example:d8ac0372-0d4b-413e-8ef5-8e8f07822b2c?resourceVersion=b9029cf7-c40b-4850-b9a1-9bfad46a68d7 ```
@@ -689,18 +818,18 @@ This parameter filters by `Version` field. We introduced it with latest network ResourceVersionTime --------------------- -**Important:** This parameter must always be accompanied by another resource query qualifier. +Important: This parameter must always be accompanied by another resource query qualifier. The main goal here is to get the nearest resource for `resourceVersionTime` value. "Nearest" means that if we are asking for time between `resource1` and `resource2` were created - `resource1` will be returned. In case if requested `resourceVersionTime` is before the first resource created - `NotFoundError` will be returned. The most useful use-case here is checking that some "Credential" (driver's license) was active at `resourceVersionTime` (was not revoked from Revocation Registry for example). -**Example**: +For example:
Request format -``` -1.0/identifiers/did:example:d8ac0372-0d4b-413e-8ef5-8e8f07822b2c?resourceVersionTime=2023-02-22T06:58:18.61Z&resourceVersion=1.14.41 +```json +did:example:d8ac0372-0d4b-413e-8ef5-8e8f07822b2c?resourceVersionTime=2023-02-22T06:58:18.61Z&resourceVersion=1.14.41 ```
@@ -737,14 +866,14 @@ Checksum It just checks that `checksum` is the same as resource's metadata and also can used as a sanity check. For example, if the user knows what is exact checksum then it may be checked before actual downloading. -**Example**: +For example:
Request format -``` -1.0/identifiers/did:example:d8ac0372-0d4b-413e-8ef5-8e8f07822b2c?checksum=27ad51a49f079a6634b18bbc3ac08dd2d91f13fabf72ea8e5d83692fe4820058 +```json +did:example:d8ac0372-0d4b-413e-8ef5-8e8f07822b2c?checksum=27ad51a49f079a6634b18bbc3ac08dd2d91f13fabf72ea8e5d83692fe4820058 ```
@@ -785,14 +914,14 @@ This parameter a kind of modifier which works in the same manner as [metadata](a * `resourceMetadata=false` * Unused -**Example**: +For example:
Request format -``` -1.0/identifiers/did:example:d8ac0372-0d4b-413e-8ef5-8e8f07822b2c?resourceType=exampleSchema&resourceMetadata=true +```json +did:example:d8ac0372-0d4b-413e-8ef5-8e8f07822b2c?resourceType=exampleSchema&resourceMetadata=true ```