mirror of https://github.com/dapr/docs.git
Merge branch 'v1.3' into v1.3
This commit is contained in:
commit
99e5bea584
|
@ -1,58 +0,0 @@
|
|||
//
|
||||
// Right side toc
|
||||
//
|
||||
.td-toc {
|
||||
border-left: 1px solid $border-color;
|
||||
|
||||
@supports (position: sticky) {
|
||||
position: sticky;
|
||||
top: 4rem;
|
||||
height: calc(100vh - 10rem);
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
order: 2;
|
||||
padding-top: 2.75rem;
|
||||
padding-bottom: 1.5rem;
|
||||
vertical-align: top;
|
||||
|
||||
a {
|
||||
display: block;
|
||||
font-weight: $font-weight-medium;
|
||||
padding-bottom: .25rem;
|
||||
}
|
||||
|
||||
li {
|
||||
list-style: none;
|
||||
display: block;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
li li {
|
||||
margin-left: 1.5rem;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.td-page-meta {
|
||||
a {
|
||||
font-weight: $font-weight-medium;
|
||||
}
|
||||
}
|
||||
|
||||
#TableOfContents {
|
||||
// Hugo's ToC is a mouthful, this can be used to style the top level h2 entries.
|
||||
> ul > li > ul > li > a {}
|
||||
|
||||
a {
|
||||
color: rgb(68, 68, 68);
|
||||
&:hover {
|
||||
color: $blue;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ul {
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
|
@ -219,6 +219,102 @@ brew install dapr/tap/dapr-cli
|
|||
|
||||
{{< /tabs >}}
|
||||
|
||||
### Embedded code snippets
|
||||
|
||||
Use the `code-snippet` shortcode to reference code snippets from the `static/code` directory.
|
||||
|
||||
```
|
||||
{{</* code-snippet file="myfile.py" lang="python" */>}}
|
||||
```
|
||||
|
||||
{{% alert title="Warning" color="warning" %}}
|
||||
All Dapr sample code should be self-contained in separate files, not in markdown. Use the techniques described here to highlight the parts of the sample code users should focus on.
|
||||
{{% /alert %}}
|
||||
|
||||
Use the `lang` (default `txt`) parameter to configure the language used for syntax highlighting.
|
||||
|
||||
Use the `marker` parameter to limit the embedded snipped to a portion of the sample file. This is useful when you want to show just a portion of a larger file. The typical way to do this is surround the interesting code with comments, and then pass the comment text into `marker`.
|
||||
|
||||
The shortcode below and code sample:
|
||||
|
||||
```
|
||||
{{</* code-snippet file="./contributing-1.py" lang="python" marker="#SAMPLE" */>}}
|
||||
```
|
||||
|
||||
```python
|
||||
import json
|
||||
import time
|
||||
|
||||
from dapr.clients import DaprClient
|
||||
|
||||
#SAMPLE
|
||||
with DaprClient() as d:
|
||||
req_data = {
|
||||
'id': 1,
|
||||
'message': 'hello world'
|
||||
}
|
||||
|
||||
while True:
|
||||
# Create a typed message with content type and body
|
||||
resp = d.invoke_method(
|
||||
'invoke-receiver',
|
||||
'my-method',
|
||||
data=json.dumps(req_data),
|
||||
)
|
||||
|
||||
# Print the response
|
||||
print(resp.content_type, flush=True)
|
||||
print(resp.text(), flush=True)
|
||||
|
||||
time.sleep(2)
|
||||
#SAMPLE
|
||||
```
|
||||
|
||||
Will result in the following output:
|
||||
|
||||
{{< code-snippet file="contributing-1.py" lang="python" marker="#SAMPLE" >}}
|
||||
|
||||
Use the `replace-key-[token]` and `replace-value-[token]` parameters to limit the embedded snipped to a portion of the sample file. This is useful when you want abbreviate a portion of the code sample. Multiple replacements are supported with multiple values of `token`.
|
||||
|
||||
The shortcode below and code sample:
|
||||
|
||||
```
|
||||
{{</* code-snippet file="./contributing-2.py" lang="python" replace-key-imports="#IMPORTS" replace-value-imports="# Import statements" */>}}
|
||||
```
|
||||
|
||||
```python
|
||||
#IMPORTS
|
||||
import json
|
||||
import time
|
||||
#IMPORTS
|
||||
|
||||
from dapr.clients import DaprClient
|
||||
|
||||
with DaprClient() as d:
|
||||
req_data = {
|
||||
'id': 1,
|
||||
'message': 'hello world'
|
||||
}
|
||||
|
||||
while True:
|
||||
# Create a typed message with content type and body
|
||||
resp = d.invoke_method(
|
||||
'invoke-receiver',
|
||||
'my-method',
|
||||
data=json.dumps(req_data),
|
||||
)
|
||||
|
||||
# Print the response
|
||||
print(resp.content_type, flush=True)
|
||||
print(resp.text(), flush=True)
|
||||
|
||||
time.sleep(2)
|
||||
```
|
||||
|
||||
Will result in the following output:
|
||||
|
||||
{{< code-snippet file="./contributing-2.py" lang="python" replace-key-imports="#IMPORTS" replace-value-imports="# Import statements" >}}
|
||||
|
||||
### YouTube videos
|
||||
Hugo can automatically embed YouTube videos using a shortcode:
|
||||
```
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
---
|
||||
type: docs
|
||||
title: "Dapr Roadmap"
|
||||
linkTitle: "Roadmap"
|
||||
description: "The Dapr Roadmap is a tool to help with visibility into investments across the Dapr project"
|
||||
weight: 1100
|
||||
no_list: true
|
||||
---
|
||||
|
||||
|
||||
Dapr encourages the community to help with prioritization. A GitHub project board is available to view and provide feedback on proposed issues and track them across development.
|
||||
|
||||
[<img src="/images/roadmap.png" alt="Screenshot of the Dapr Roadmap board" width=500 >](https://aka.ms/dapr/roadmap)
|
||||
|
||||
{{< button text="View the backlog" link="https://aka.ms/dapr/roadmap" color="primary" >}}
|
||||
<br />
|
||||
|
||||
Please vote by adding a 👍 on the GitHub issues for the feature capabilities you would most like to see Dapr support. This will help the Dapr maintainers understand which features will provide the most value.
|
||||
|
||||
Contributions from the community is also welcomed. If there are features on the roadmap that you are interested in contributing to, please comment on the GitHub issue and include your solution proposal.
|
||||
|
||||
{{% alert title="Note" color="primary" %}}
|
||||
The Dapr roadmap includes issues only from the v1.2 release and onwards. Issues closed and released prior to v1.2 are not included.
|
||||
{{% /alert %}}
|
||||
|
||||
## Stages
|
||||
|
||||
The Dapr Roadmap progresses through the following stages:
|
||||
|
||||
{{< cardpane >}}
|
||||
{{< card title="**[📄 Backlog](https://github.com/orgs/dapr/projects/52#column-14691591)**" >}}
|
||||
Issues (features) that need 👍 votes from the community to prioritize. Updated by Dapr maintainers.
|
||||
{{< /card >}}
|
||||
{{< card title="**[⏳ Planned (Committed)](https://github.com/orgs/dapr/projects/52#column-14561691)**" >}}
|
||||
Issues with a proposal and/or targeted release milestone. This is where design proposals are discussed and designed.
|
||||
{{< /card >}}
|
||||
{{< card title="**[👩💻 In Progress (Development)](https://github.com/orgs/dapr/projects/52#column-14561696)**" >}}
|
||||
Implementation specifics have been agreed upon and the feature is under active development.
|
||||
{{< /card >}}
|
||||
{{< /cardpane >}}
|
||||
{{< cardpane >}}
|
||||
{{< card title="**[☑ Done](https://github.com/orgs/dapr/projects/52#column-14561700)**" >}}
|
||||
The feature capability has been completed and is scheduled for an upcoming release.
|
||||
{{< /card >}}
|
||||
{{< card title="**[✅ Released](https://github.com/orgs/dapr/projects/52#column-14659973)**" >}}
|
||||
The feature is released and available for use.
|
||||
{{< /card >}}
|
||||
{{< /cardpane >}}
|
|
@ -22,7 +22,7 @@ When message time-to-live has native support in the pub/sub component, Dapr simp
|
|||
|
||||
#### Azure Service Bus
|
||||
|
||||
Azure Service Bus supports [entity level time-to-live]((https://docs.microsoft.com/en-us/azure/service-bus-messaging/message-expiration)). This means that messages have a default time-to-live but can also be set with a shorter timespan at publishing time. Dapr propagates the time-to-live metadata for the message and lets Azure Service Bus handle the expiration directly.
|
||||
Azure Service Bus supports [entity level time-to-live](https://docs.microsoft.com/en-us/azure/service-bus-messaging/message-expiration). This means that messages have a default time-to-live but can also be set with a shorter timespan at publishing time. Dapr propagates the time-to-live metadata for the message and lets Azure Service Bus handle the expiration directly.
|
||||
|
||||
## Non-Dapr subscribers
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ Dapr can use any Redis instance - either containerized on your local dev machine
|
|||
{{< tabs "Self-Hosted" "Kubernetes" "Azure" "AWS" "GCP" >}}
|
||||
|
||||
{{% codetab %}}
|
||||
Redis is automatically installed in self-hosted environments by the Dapr CLI as part of the initialization process. You are all set and can skip to the [next steps](next steps)
|
||||
Redis is automatically installed in self-hosted environments by the Dapr CLI as part of the initialization process. You are all set and can skip to the [next steps](#next-steps)
|
||||
{{% /codetab %}}
|
||||
|
||||
{{% codetab %}}
|
||||
|
@ -127,7 +127,7 @@ spec:
|
|||
key: redis-password
|
||||
```
|
||||
|
||||
This example uses the the kubernetes secret that was created when setting up a cluster with the above instructions.
|
||||
This example uses the kubernetes secret that was created when setting up a cluster with the above instructions.
|
||||
|
||||
{{% alert title="Other stores" color="primary" %}}
|
||||
If using a state store other than Redis, refer to the [supported state stores]({{< ref supported-state-stores >}}) for information on what options to set.
|
||||
|
@ -155,7 +155,7 @@ spec:
|
|||
key: redis-password
|
||||
```
|
||||
|
||||
This example uses the the kubernetes secret that was created when setting up a cluster with the above instructions.
|
||||
This example uses the kubernetes secret that was created when setting up a cluster with the above instructions.
|
||||
|
||||
{{% alert title="Other stores" color="primary" %}}
|
||||
If using a pub/sub message broker other than Redis, refer to the [supported pub/sub message brokers]({{< ref supported-pubsub >}}) for information on what options to set.
|
||||
|
|
|
@ -46,7 +46,7 @@ spec:
|
|||
dapr.io/enabled: "true"
|
||||
dapr.io/app-id: "nodesubscriber"
|
||||
dapr.io/app-port: "3000"
|
||||
<b>dapr.io/app-max-concurrency: "1"</b>
|
||||
dapr.io/app-max-concurrency: "1"
|
||||
...
|
||||
```
|
||||
|
||||
|
|
|
@ -37,12 +37,7 @@ Deploying and running a Dapr enabled application into your Kubernetes cluster is
|
|||
You can see some examples [here](https://github.com/dapr/quickstarts/tree/master/hello-kubernetes) in the Kubernetes getting started quickstart.
|
||||
|
||||
## Supported versions
|
||||
Dapr is tested and supported on the following versions of Kubernetes.
|
||||
|
||||
| Supported Kubernetes versions |
|
||||
|-----------------------|
|
||||
| 1.17.x and above |
|
||||
|
||||
Dapr support for Kubernetes is aligned with [Kubernetes Version Skew Policy](https://kubernetes.io/releases/version-skew-policy).
|
||||
|
||||
## Related links
|
||||
|
||||
|
|
|
@ -72,5 +72,9 @@ After announcing a future breaking change, the change will happen in 2 releases
|
|||
## Upgrade on Hosting platforms
|
||||
Dapr can support multiple hosting platforms for production. With the 1.0 release the two supported platforms are Kubernetes and physical machines. For Kubernetes upgrades see [Production guidelines on Kubernetes]({{< ref kubernetes-production.md >}})
|
||||
|
||||
### Supported Kubernetes versions
|
||||
|
||||
Dapr follows [Kubernetes Version Skew Policy](https://kubernetes.io/releases/version-skew-policy).
|
||||
|
||||
## Related links
|
||||
* Read the [Versioning policy]({{< ref support-versioning.md >}})
|
||||
|
|
|
@ -14,7 +14,7 @@ Gets the health state for Dapr.
|
|||
|
||||
### HTTP Request
|
||||
|
||||
```http
|
||||
```
|
||||
GET http://localhost:<daprPort>/v1.0/healthz
|
||||
```
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ Gets the Dapr sidecar information provided by the Metadata Endpoint.
|
|||
|
||||
### HTTP Request
|
||||
|
||||
```http
|
||||
```
|
||||
GET http://localhost:<daprPort>/v1.0/metadata
|
||||
```
|
||||
|
||||
|
|
|
@ -22,38 +22,38 @@ spec:
|
|||
metadata:
|
||||
- name: connectionString # Required
|
||||
value: "Endpoint=sb://{ServiceBusNamespace}.servicebus.windows.net/;SharedAccessKeyName={PolicyName};SharedAccessKey={Key};EntityPath={ServiceBus}"
|
||||
- name: timeoutInSec # Optional
|
||||
value: 60
|
||||
- name: handlerTimeoutInSec # Optional
|
||||
value: 60
|
||||
- name: disableEntityManagement # Optional
|
||||
value: "false"
|
||||
- name: maxDeliveryCount # Optional
|
||||
value: 3
|
||||
- name: lockDurationInSec # Optional
|
||||
value: 60
|
||||
- name: lockRenewalInSec # Optional
|
||||
value: 20
|
||||
- name: maxActiveMessages # Optional
|
||||
value: 2000
|
||||
- name: maxActiveMessagesRecoveryInSec # Optional
|
||||
value: 2
|
||||
- name: maxConcurrentHandlers # Optional
|
||||
value: 10
|
||||
- name: prefetchCount # Optional
|
||||
value: 5
|
||||
- name: defaultMessageTimeToLiveInSec # Optional
|
||||
value: 10
|
||||
- name: autoDeleteOnIdleInSec # Optional
|
||||
value: 10
|
||||
- name: maxReconnectionAttempts # Optional
|
||||
value: 30
|
||||
- name: connectionRecoveryInSec # Optional
|
||||
value: 2
|
||||
- name: publishMaxRetries # Optional
|
||||
value: 5
|
||||
- name: publishInitialRetryInternalInMs # Optional
|
||||
value: 500
|
||||
# - name: timeoutInSec # Optional
|
||||
# value: 60
|
||||
# - name: handlerTimeoutInSec # Optional
|
||||
# value: 60
|
||||
# - name: disableEntityManagement # Optional
|
||||
# value: "false"
|
||||
# - name: maxDeliveryCount # Optional
|
||||
# value: 3
|
||||
# - name: lockDurationInSec # Optional
|
||||
# value: 60
|
||||
# - name: lockRenewalInSec # Optional
|
||||
# value: 20
|
||||
# - name: maxActiveMessages # Optional
|
||||
# value: 2000
|
||||
# - name: maxActiveMessagesRecoveryInSec # Optional
|
||||
# value: 2
|
||||
# - name: maxConcurrentHandlers # Optional
|
||||
# value: 10
|
||||
# - name: prefetchCount # Optional
|
||||
# value: 5
|
||||
# - name: defaultMessageTimeToLiveInSec # Optional
|
||||
# value: 10
|
||||
# - name: autoDeleteOnIdleInSec # Optional
|
||||
# value: 10
|
||||
# - name: maxReconnectionAttempts # Optional
|
||||
# value: 30
|
||||
# - name: connectionRecoveryInSec # Optional
|
||||
# value: 2
|
||||
# - name: publishMaxRetries # Optional
|
||||
# value: 5
|
||||
# - name: publishInitialRetryInternalInMs # Optional
|
||||
# value: 500
|
||||
```
|
||||
|
||||
> __NOTE:__ The above settings are shared across all topics that use this component.
|
||||
|
@ -66,7 +66,7 @@ The above example uses secrets as plain strings. It is recommended to use a secr
|
|||
|
||||
| Field | Required | Details | Example |
|
||||
|--------------------|:--------:|---------|---------|
|
||||
| connectionString | Y | Connection-string for the Service Bus | "`Endpoint=sb://{ServiceBusNamespace}.servicebus.windows.net/;SharedAccessKeyName={PolicyName};SharedAccessKey={Key};EntityPath={ServiceBus}`"
|
||||
| connectionString | Y | Shared access policy connection-string for the Service Bus | "`Endpoint=sb://{ServiceBusNamespace}.servicebus.windows.net/;SharedAccessKeyName={PolicyName};SharedAccessKey={Key};EntityPath={ServiceBus}`"
|
||||
| timeoutInSec | N | Timeout for sending messages and management operations. Default: `60` |`30`
|
||||
| handlerTimeoutInSec| N | Timeout for invoking app handler. # Optional. Default: `60` | `30`
|
||||
| disableEntityManagement | N | When set to true, topics and subscriptions do not get created automatically. Default: `"false"` | `"true"`, `"false"`
|
||||
|
|
|
@ -47,7 +47,7 @@ The above example uses secrets as plain strings. It is recommended to use a loca
|
|||
|
||||
| Field | Required | Details | Example |
|
||||
|--------------------|:--------:|---------|---------|
|
||||
| vaultName | Y | The name of the Azure Key Vault | `"mykeyvault"`
|
||||
| vaultName | Y | The name of the Azure Key Vault. If you only provide a name, it will covert to `[your_keyvault_name].vault.azure.net` in Dapr. If your URL uses another suffix, please provide the entire URI, such as `test.vault.azure.cn`. | `"mykeyvault"`, `"mykeyvault.value.azure.cn"`
|
||||
| spnTenantId | Y | Service Principal Tenant Id | `"spnTenantId"`
|
||||
| spnClientId | Y | Service Principal App Id | `"spnAppId"`
|
||||
| spnCertificateFile | Y | PFX certificate file path. <br></br> For Windows the `[pfx_certificate_file_fully_qualified_local_path]` value must use escaped backslashes, i.e. double backslashes. For example `"C:\\folder1\\folder2\\certfile.pfx"`. <br></br> For Linux you can use single slashes. For example `"/folder1/folder2/certfile.pfx"`. <br></br> See [configure the component](#configure-the-component) for more details | `"C:\\folder1\\folder2\\certfile.pfx"`, `"/folder1/folder2/certfile.pfx"`
|
||||
|
|
|
@ -39,6 +39,8 @@ spec:
|
|||
value : "[path_to_file_containing_token]"
|
||||
- name: vaultKVPrefix # Optional. Default: "dapr"
|
||||
value : "[vault_prefix]"
|
||||
- name: vaultKVUsePrefix # Optional. default: "true"
|
||||
value: "[true/false]"
|
||||
```
|
||||
{{% alert title="Warning" color="warning" %}}
|
||||
The above example uses secrets as plain strings. It is recommended to use a local secret store such as [Kubernetes secret store]({{< ref kubernetes-secret-store.md >}}) or a [local file]({{< ref file-secret-store.md >}}) to bootstrap secure key storage.
|
||||
|
@ -57,6 +59,7 @@ The above example uses secrets as plain strings. It is recommended to use a loca
|
|||
| vaultTokenMountPath | Y | Path to file containing token | `"path/to/file"` |
|
||||
| vaultToken | Y | [Token](https://learn.hashicorp.com/tutorials/vault/tokens) for authentication within Vault. | `"tokenValue"` |
|
||||
| vaultKVPrefix | N | The prefix in vault. Defautls to `"dapr"` | `"dapr"`, `"myprefix"` |
|
||||
| vaultKVUsePrefix | N | If false, vaultKVPrefix is forced to be empty. If the value is not given or set to true, vaultKVPrefix is used when accessing the vault. Setting it to false is needed to be able to use the BulkGetSecret method of the store. | `"true"`, `"false"` |
|
||||
|
||||
## Setup Hashicorp Vault instance
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
{{ partial "page-meta-links.html" . }}
|
||||
{{ if not .Params.notoc }}
|
||||
{{ with .TableOfContents }}
|
||||
{{ if ge (len .) 200 }}
|
||||
{{ . }}
|
||||
<br />
|
||||
<div class="td-toc">{{ . }}</div>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
|
@ -0,0 +1,23 @@
|
|||
{{ $file := .Get "file" }}
|
||||
{{ $filePath := (path.Join "/static/code/" $file ) }}
|
||||
{{ $fileContents := $filePath | readFile }}
|
||||
{{ $lang := .Get "lang" | default "txt" }}
|
||||
{{ $embed := .Get "embed" | default true }}
|
||||
{{ if $embed }}
|
||||
{{ if isset .Params "marker" }}
|
||||
{{ $marker := .Get "marker" }}
|
||||
{{ $regex := printf "(?s).*%s%s%s.*" $marker `(\n)?(?P<inner>.*?)(\n\s+)?` $marker }}
|
||||
{{ $fileContents = replaceRE $regex "$inner" $fileContents}}
|
||||
{{ end }}
|
||||
{{ range $key, $value := $.Params }}
|
||||
{{ if hasPrefix $key "replace-key" }}
|
||||
{{ $replace := $value }}
|
||||
{{ $replaceValueParameter := printf "replace-value-%s" (slicestr $key (len "replace-key-")) }}
|
||||
<p>{{ $replaceValueParameter }}</p>
|
||||
{{ $replaceWith := index $.Params $replaceValueParameter }}
|
||||
{{ $regex := printf "(?s)%s%s%s" $replace `(\n)?(?P<inner>.*?)(\n\s+)?` $replace }}
|
||||
{{ $fileContents = replaceRE $regex $replaceWith $fileContents}}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ (print "```" $lang "\n" $fileContents "\n```") | markdownify }}
|
||||
{{ end }}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,26 @@
|
|||
import json
|
||||
import time
|
||||
|
||||
from dapr.clients import DaprClient
|
||||
|
||||
#SAMPLE
|
||||
with DaprClient() as d:
|
||||
req_data = {
|
||||
'id': 1,
|
||||
'message': 'hello world'
|
||||
}
|
||||
|
||||
while True:
|
||||
# Create a typed message with content type and body
|
||||
resp = d.invoke_method(
|
||||
'invoke-receiver',
|
||||
'my-method',
|
||||
data=json.dumps(req_data),
|
||||
)
|
||||
|
||||
# Print the response
|
||||
print(resp.content_type, flush=True)
|
||||
print(resp.text(), flush=True)
|
||||
|
||||
time.sleep(2)
|
||||
#SAMPLE
|
|
@ -0,0 +1,26 @@
|
|||
#IMPORTS
|
||||
import json
|
||||
import time
|
||||
#IMPORTS
|
||||
|
||||
from dapr.clients import DaprClient
|
||||
|
||||
with DaprClient() as d:
|
||||
req_data = {
|
||||
'id': 1,
|
||||
'message': 'hello world'
|
||||
}
|
||||
|
||||
while True:
|
||||
# Create a typed message with content type and body
|
||||
resp = d.invoke_method(
|
||||
'invoke-receiver',
|
||||
'my-method',
|
||||
data=json.dumps(req_data),
|
||||
)
|
||||
|
||||
# Print the response
|
||||
print(resp.content_type, flush=True)
|
||||
print(resp.text(), flush=True)
|
||||
|
||||
time.sleep(2)
|
Binary file not shown.
After Width: | Height: | Size: 415 KiB |
|
@ -1 +1 @@
|
|||
Subproject commit 4808e0ac5bb2df27021401fd33b2ef2756f751c2
|
||||
Subproject commit c36be07b2dcb9aa5aa01bad6ed0f8e111dd0452c
|
|
@ -1 +1 @@
|
|||
Subproject commit 3d610a4db9a589d85de7fa20c42be1934a1d6f0e
|
||||
Subproject commit 058cfcf4d603823c5916bb5ae533bb9f5bb862fd
|
Loading…
Reference in New Issue