|
|
|
@ -43,11 +43,16 @@ pid_file: /homeserver.pid
|
|
|
|
|
#
|
|
|
|
|
#web_client_location: https://riot.example.com/
|
|
|
|
|
|
|
|
|
|
# The public-facing base URL that clients use to access this HS
|
|
|
|
|
# (not including _matrix/...). This is the same URL a user would
|
|
|
|
|
# enter into the 'custom HS URL' field on their client. If you
|
|
|
|
|
# use synapse with a reverse proxy, this should be the URL to reach
|
|
|
|
|
# synapse via the proxy.
|
|
|
|
|
# The public-facing base URL that clients use to access this Homeserver (not
|
|
|
|
|
# including _matrix/...). This is the same URL a user might enter into the
|
|
|
|
|
# 'Custom Homeserver URL' field on their client. If you use Synapse with a
|
|
|
|
|
# reverse proxy, this should be the URL to reach Synapse via the proxy.
|
|
|
|
|
# Otherwise, it should be the URL to reach Synapse's client HTTP listener (see
|
|
|
|
|
# 'listeners' below).
|
|
|
|
|
#
|
|
|
|
|
# If this is left unset, it defaults to 'https://<server_name>/'. (Note that
|
|
|
|
|
# that will not work unless you configure Synapse or a reverse-proxy to listen
|
|
|
|
|
# on port 443.)
|
|
|
|
|
#
|
|
|
|
|
public_baseurl: https://{{ matrix_server_fqn_matrix }}/
|
|
|
|
|
|
|
|
|
@ -1152,8 +1157,9 @@ account_validity:
|
|
|
|
|
# send an email to the account's email address with a renewal link. By
|
|
|
|
|
# default, no such emails are sent.
|
|
|
|
|
#
|
|
|
|
|
# If you enable this setting, you will also need to fill out the 'email' and
|
|
|
|
|
# 'public_baseurl' configuration sections.
|
|
|
|
|
# If you enable this setting, you will also need to fill out the 'email'
|
|
|
|
|
# configuration section. You should also check that 'public_baseurl' is set
|
|
|
|
|
# correctly.
|
|
|
|
|
#
|
|
|
|
|
#renew_at: 1w
|
|
|
|
|
|
|
|
|
@ -1250,8 +1256,7 @@ allow_guest_access: {{ matrix_synapse_allow_guest_access|to_json }}
|
|
|
|
|
# The identity server which we suggest that clients should use when users log
|
|
|
|
|
# in on this server.
|
|
|
|
|
#
|
|
|
|
|
# (By default, no suggestion is made, so it is left up to the client.
|
|
|
|
|
# This setting is ignored unless public_baseurl is also set.)
|
|
|
|
|
# (By default, no suggestion is made, so it is left up to the client.)
|
|
|
|
|
#
|
|
|
|
|
#default_identity_server: https://matrix.org
|
|
|
|
|
|
|
|
|
@ -1276,8 +1281,6 @@ allow_guest_access: {{ matrix_synapse_allow_guest_access|to_json }}
|
|
|
|
|
# by the Matrix Identity Service API specification:
|
|
|
|
|
# https://matrix.org/docs/spec/identity_service/latest
|
|
|
|
|
#
|
|
|
|
|
# If a delegate is specified, the config option public_baseurl must also be filled out.
|
|
|
|
|
#
|
|
|
|
|
account_threepid_delegates:
|
|
|
|
|
email: {{ matrix_synapse_account_threepid_delegates_email|to_json }}
|
|
|
|
|
msisdn: {{ matrix_synapse_account_threepid_delegates_msisdn|to_json }}
|
|
|
|
@ -1722,141 +1725,158 @@ saml2_config:
|
|
|
|
|
#idp_entityid: 'https://our_idp/entityid'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Enable OpenID Connect (OIDC) / OAuth 2.0 for registration and login.
|
|
|
|
|
# List of OpenID Connect (OIDC) / OAuth 2.0 identity providers, for registration
|
|
|
|
|
# and login.
|
|
|
|
|
#
|
|
|
|
|
# See https://github.com/matrix-org/synapse/blob/master/docs/openid.md
|
|
|
|
|
# for some example configurations.
|
|
|
|
|
# Options for each entry include:
|
|
|
|
|
#
|
|
|
|
|
oidc_config:
|
|
|
|
|
# Uncomment the following to enable authorization against an OpenID Connect
|
|
|
|
|
# server. Defaults to false.
|
|
|
|
|
#
|
|
|
|
|
#enabled: true
|
|
|
|
|
|
|
|
|
|
# Uncomment the following to disable use of the OIDC discovery mechanism to
|
|
|
|
|
# discover endpoints. Defaults to true.
|
|
|
|
|
#
|
|
|
|
|
#discover: false
|
|
|
|
|
|
|
|
|
|
# the OIDC issuer. Used to validate tokens and (if discovery is enabled) to
|
|
|
|
|
# discover the provider's endpoints.
|
|
|
|
|
#
|
|
|
|
|
# Required if 'enabled' is true.
|
|
|
|
|
#
|
|
|
|
|
#issuer: "https://accounts.example.com/"
|
|
|
|
|
|
|
|
|
|
# oauth2 client id to use.
|
|
|
|
|
#
|
|
|
|
|
# Required if 'enabled' is true.
|
|
|
|
|
#
|
|
|
|
|
#client_id: "provided-by-your-issuer"
|
|
|
|
|
|
|
|
|
|
# oauth2 client secret to use.
|
|
|
|
|
#
|
|
|
|
|
# Required if 'enabled' is true.
|
|
|
|
|
#
|
|
|
|
|
#client_secret: "provided-by-your-issuer"
|
|
|
|
|
|
|
|
|
|
# auth method to use when exchanging the token.
|
|
|
|
|
# Valid values are 'client_secret_basic' (default), 'client_secret_post' and
|
|
|
|
|
# 'none'.
|
|
|
|
|
#
|
|
|
|
|
#client_auth_method: client_secret_post
|
|
|
|
|
|
|
|
|
|
# list of scopes to request. This should normally include the "openid" scope.
|
|
|
|
|
# Defaults to ["openid"].
|
|
|
|
|
#
|
|
|
|
|
#scopes: ["openid", "profile"]
|
|
|
|
|
|
|
|
|
|
# the oauth2 authorization endpoint. Required if provider discovery is disabled.
|
|
|
|
|
#
|
|
|
|
|
#authorization_endpoint: "https://accounts.example.com/oauth2/auth"
|
|
|
|
|
|
|
|
|
|
# the oauth2 token endpoint. Required if provider discovery is disabled.
|
|
|
|
|
#
|
|
|
|
|
#token_endpoint: "https://accounts.example.com/oauth2/token"
|
|
|
|
|
|
|
|
|
|
# the OIDC userinfo endpoint. Required if discovery is disabled and the
|
|
|
|
|
# "openid" scope is not requested.
|
|
|
|
|
#
|
|
|
|
|
#userinfo_endpoint: "https://accounts.example.com/userinfo"
|
|
|
|
|
|
|
|
|
|
# URI where to fetch the JWKS. Required if discovery is disabled and the
|
|
|
|
|
# "openid" scope is used.
|
|
|
|
|
#
|
|
|
|
|
#jwks_uri: "https://accounts.example.com/.well-known/jwks.json"
|
|
|
|
|
|
|
|
|
|
# Uncomment to skip metadata verification. Defaults to false.
|
|
|
|
|
#
|
|
|
|
|
# Use this if you are connecting to a provider that is not OpenID Connect
|
|
|
|
|
# compliant.
|
|
|
|
|
# Avoid this in production.
|
|
|
|
|
#
|
|
|
|
|
#skip_verification: true
|
|
|
|
|
|
|
|
|
|
# Whether to fetch the user profile from the userinfo endpoint. Valid
|
|
|
|
|
# values are: "auto" or "userinfo_endpoint".
|
|
|
|
|
#
|
|
|
|
|
# Defaults to "auto", which fetches the userinfo endpoint if "openid" is included
|
|
|
|
|
# in `scopes`. Uncomment the following to always fetch the userinfo endpoint.
|
|
|
|
|
#
|
|
|
|
|
#user_profile_method: "userinfo_endpoint"
|
|
|
|
|
|
|
|
|
|
# Uncomment to allow a user logging in via OIDC to match a pre-existing account instead
|
|
|
|
|
# of failing. This could be used if switching from password logins to OIDC. Defaults to false.
|
|
|
|
|
#
|
|
|
|
|
#allow_existing_users: true
|
|
|
|
|
|
|
|
|
|
# An external module can be provided here as a custom solution to mapping
|
|
|
|
|
# attributes returned from a OIDC provider onto a matrix user.
|
|
|
|
|
#
|
|
|
|
|
user_mapping_provider:
|
|
|
|
|
# The custom module's class. Uncomment to use a custom module.
|
|
|
|
|
# Default is 'synapse.handlers.oidc_handler.JinjaOidcMappingProvider'.
|
|
|
|
|
#
|
|
|
|
|
# See https://github.com/matrix-org/synapse/blob/master/docs/sso_mapping_providers.md#openid-mapping-providers
|
|
|
|
|
# for information on implementing a custom mapping provider.
|
|
|
|
|
#
|
|
|
|
|
#module: mapping_provider.OidcMappingProvider
|
|
|
|
|
|
|
|
|
|
# Custom configuration values for the module. This section will be passed as
|
|
|
|
|
# a Python dictionary to the user mapping provider module's `parse_config`
|
|
|
|
|
# method.
|
|
|
|
|
#
|
|
|
|
|
# The examples below are intended for the default provider: they should be
|
|
|
|
|
# changed if using a custom provider.
|
|
|
|
|
#
|
|
|
|
|
config:
|
|
|
|
|
# name of the claim containing a unique identifier for the user.
|
|
|
|
|
# Defaults to `sub`, which OpenID Connect compliant providers should provide.
|
|
|
|
|
#
|
|
|
|
|
#subject_claim: "sub"
|
|
|
|
|
|
|
|
|
|
# Jinja2 template for the localpart of the MXID.
|
|
|
|
|
#
|
|
|
|
|
# When rendering, this template is given the following variables:
|
|
|
|
|
# * user: The claims returned by the UserInfo Endpoint and/or in the ID
|
|
|
|
|
# Token
|
|
|
|
|
#
|
|
|
|
|
# If this is not set, the user will be prompted to choose their
|
|
|
|
|
# own username.
|
|
|
|
|
#
|
|
|
|
|
localpart_template: "{% raw %}{{ user.preferred_username }}{% endraw %}"
|
|
|
|
|
|
|
|
|
|
# Jinja2 template for the display name to set on first login.
|
|
|
|
|
#
|
|
|
|
|
# If unset, no displayname will be set.
|
|
|
|
|
#
|
|
|
|
|
#display_name_template: "{% raw %}{{ user.given_name }} {{ user.last_name }}{% endraw %}"
|
|
|
|
|
|
|
|
|
|
# Jinja2 templates for extra attributes to send back to the client during
|
|
|
|
|
# login.
|
|
|
|
|
#
|
|
|
|
|
# Note that these are non-standard and clients will ignore them without modifications.
|
|
|
|
|
#
|
|
|
|
|
#extra_attributes:
|
|
|
|
|
#birthdate: "{% raw %}{{ user.birthdate }}{% endraw %}"
|
|
|
|
|
|
|
|
|
|
# idp_id: a unique identifier for this identity provider. Used internally
|
|
|
|
|
# by Synapse; should be a single word such as 'github'.
|
|
|
|
|
#
|
|
|
|
|
# Note that, if this is changed, users authenticating via that provider
|
|
|
|
|
# will no longer be recognised as the same user!
|
|
|
|
|
#
|
|
|
|
|
# idp_name: A user-facing name for this identity provider, which is used to
|
|
|
|
|
# offer the user a choice of login mechanisms.
|
|
|
|
|
#
|
|
|
|
|
# idp_icon: An optional icon for this identity provider, which is presented
|
|
|
|
|
# by identity picker pages. If given, must be an MXC URI of the format
|
|
|
|
|
# mxc://<server-name>/<media-id>. (An easy way to obtain such an MXC URI
|
|
|
|
|
# is to upload an image to an (unencrypted) room and then copy the "url"
|
|
|
|
|
# from the source of the event.)
|
|
|
|
|
#
|
|
|
|
|
# discover: set to 'false' to disable the use of the OIDC discovery mechanism
|
|
|
|
|
# to discover endpoints. Defaults to true.
|
|
|
|
|
#
|
|
|
|
|
# issuer: Required. The OIDC issuer. Used to validate tokens and (if discovery
|
|
|
|
|
# is enabled) to discover the provider's endpoints.
|
|
|
|
|
#
|
|
|
|
|
# client_id: Required. oauth2 client id to use.
|
|
|
|
|
#
|
|
|
|
|
# client_secret: Required. oauth2 client secret to use.
|
|
|
|
|
#
|
|
|
|
|
# client_auth_method: auth method to use when exchanging the token. Valid
|
|
|
|
|
# values are 'client_secret_basic' (default), 'client_secret_post' and
|
|
|
|
|
# 'none'.
|
|
|
|
|
#
|
|
|
|
|
# scopes: list of scopes to request. This should normally include the "openid"
|
|
|
|
|
# scope. Defaults to ["openid"].
|
|
|
|
|
#
|
|
|
|
|
# authorization_endpoint: the oauth2 authorization endpoint. Required if
|
|
|
|
|
# provider discovery is disabled.
|
|
|
|
|
#
|
|
|
|
|
# token_endpoint: the oauth2 token endpoint. Required if provider discovery is
|
|
|
|
|
# disabled.
|
|
|
|
|
#
|
|
|
|
|
# userinfo_endpoint: the OIDC userinfo endpoint. Required if discovery is
|
|
|
|
|
# disabled and the 'openid' scope is not requested.
|
|
|
|
|
#
|
|
|
|
|
# jwks_uri: URI where to fetch the JWKS. Required if discovery is disabled and
|
|
|
|
|
# the 'openid' scope is used.
|
|
|
|
|
#
|
|
|
|
|
# skip_verification: set to 'true' to skip metadata verification. Use this if
|
|
|
|
|
# you are connecting to a provider that is not OpenID Connect compliant.
|
|
|
|
|
# Defaults to false. Avoid this in production.
|
|
|
|
|
#
|
|
|
|
|
# user_profile_method: Whether to fetch the user profile from the userinfo
|
|
|
|
|
# endpoint. Valid values are: 'auto' or 'userinfo_endpoint'.
|
|
|
|
|
#
|
|
|
|
|
# Defaults to 'auto', which fetches the userinfo endpoint if 'openid' is
|
|
|
|
|
# included in 'scopes'. Set to 'userinfo_endpoint' to always fetch the
|
|
|
|
|
# userinfo endpoint.
|
|
|
|
|
#
|
|
|
|
|
# allow_existing_users: set to 'true' to allow a user logging in via OIDC to
|
|
|
|
|
# match a pre-existing account instead of failing. This could be used if
|
|
|
|
|
# switching from password logins to OIDC. Defaults to false.
|
|
|
|
|
#
|
|
|
|
|
# user_mapping_provider: Configuration for how attributes returned from a OIDC
|
|
|
|
|
# provider are mapped onto a matrix user. This setting has the following
|
|
|
|
|
# sub-properties:
|
|
|
|
|
#
|
|
|
|
|
# module: The class name of a custom mapping module. Default is
|
|
|
|
|
# 'synapse.handlers.oidc_handler.JinjaOidcMappingProvider'.
|
|
|
|
|
# See https://github.com/matrix-org/synapse/blob/master/docs/sso_mapping_providers.md#openid-mapping-providers
|
|
|
|
|
# for information on implementing a custom mapping provider.
|
|
|
|
|
#
|
|
|
|
|
# config: Configuration for the mapping provider module. This section will
|
|
|
|
|
# be passed as a Python dictionary to the user mapping provider
|
|
|
|
|
# module's `parse_config` method.
|
|
|
|
|
#
|
|
|
|
|
# For the default provider, the following settings are available:
|
|
|
|
|
#
|
|
|
|
|
# sub: name of the claim containing a unique identifier for the
|
|
|
|
|
# user. Defaults to 'sub', which OpenID Connect compliant
|
|
|
|
|
# providers should provide.
|
|
|
|
|
#
|
|
|
|
|
# localpart_template: Jinja2 template for the localpart of the MXID.
|
|
|
|
|
# If this is not set, the user will be prompted to choose their
|
|
|
|
|
# own username.
|
|
|
|
|
#
|
|
|
|
|
# display_name_template: Jinja2 template for the display name to set
|
|
|
|
|
# on first login. If unset, no displayname will be set.
|
|
|
|
|
#
|
|
|
|
|
# extra_attributes: a map of Jinja2 templates for extra attributes
|
|
|
|
|
# to send back to the client during login.
|
|
|
|
|
# Note that these are non-standard and clients will ignore them
|
|
|
|
|
# without modifications.
|
|
|
|
|
#
|
|
|
|
|
# When rendering, the Jinja2 templates are given a 'user' variable,
|
|
|
|
|
# which is set to the claims returned by the UserInfo Endpoint and/or
|
|
|
|
|
# in the ID Token.
|
|
|
|
|
#
|
|
|
|
|
# See https://github.com/matrix-org/synapse/blob/master/docs/openid.md
|
|
|
|
|
# for information on how to configure these options.
|
|
|
|
|
#
|
|
|
|
|
# For backwards compatibility, it is also possible to configure a single OIDC
|
|
|
|
|
# provider via an 'oidc_config' setting. This is now deprecated and admins are
|
|
|
|
|
# advised to migrate to the 'oidc_providers' format. (When doing that migration,
|
|
|
|
|
# use 'oidc' for the idp_id to ensure that existing users continue to be
|
|
|
|
|
# recognised.)
|
|
|
|
|
#
|
|
|
|
|
oidc_providers:
|
|
|
|
|
# Generic example
|
|
|
|
|
#
|
|
|
|
|
#- idp_id: my_idp
|
|
|
|
|
# idp_name: "My OpenID provider"
|
|
|
|
|
# idp_icon: "mxc://example.com/mediaid"
|
|
|
|
|
# discover: false
|
|
|
|
|
# issuer: "https://accounts.example.com/"
|
|
|
|
|
# client_id: "provided-by-your-issuer"
|
|
|
|
|
# client_secret: "provided-by-your-issuer"
|
|
|
|
|
# client_auth_method: client_secret_post
|
|
|
|
|
# scopes: ["openid", "profile"]
|
|
|
|
|
# authorization_endpoint: "https://accounts.example.com/oauth2/auth"
|
|
|
|
|
# token_endpoint: "https://accounts.example.com/oauth2/token"
|
|
|
|
|
# userinfo_endpoint: "https://accounts.example.com/userinfo"
|
|
|
|
|
# jwks_uri: "https://accounts.example.com/.well-known/jwks.json"
|
|
|
|
|
# skip_verification: true
|
|
|
|
|
|
|
|
|
|
# For use with Keycloak
|
|
|
|
|
#
|
|
|
|
|
#- idp_id: keycloak
|
|
|
|
|
# idp_name: Keycloak
|
|
|
|
|
# issuer: "https://127.0.0.1:8443/auth/realms/my_realm_name"
|
|
|
|
|
# client_id: "synapse"
|
|
|
|
|
# client_secret: "copy secret generated in Keycloak UI"
|
|
|
|
|
# scopes: ["openid", "profile"]
|
|
|
|
|
|
|
|
|
|
# For use with Github
|
|
|
|
|
#
|
|
|
|
|
#- idp_id: github
|
|
|
|
|
# idp_name: Github
|
|
|
|
|
# discover: false
|
|
|
|
|
# issuer: "https://github.com/"
|
|
|
|
|
# client_id: "your-client-id" # TO BE FILLED
|
|
|
|
|
# client_secret: "your-client-secret" # TO BE FILLED
|
|
|
|
|
# authorization_endpoint: "https://github.com/login/oauth/authorize"
|
|
|
|
|
# token_endpoint: "https://github.com/login/oauth/access_token"
|
|
|
|
|
# userinfo_endpoint: "https://api.github.com/user"
|
|
|
|
|
# scopes: ["read:user"]
|
|
|
|
|
# user_mapping_provider:
|
|
|
|
|
# config:
|
|
|
|
|
# subject_claim: "id"
|
|
|
|
|
# localpart_template: "{ user.login }"
|
|
|
|
|
# display_name_template: "{ user.name }"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Enable Central Authentication Service (CAS) for registration and login.
|
|
|
|
@ -1906,9 +1926,9 @@ sso:
|
|
|
|
|
# phishing attacks from evil.site. To avoid this, include a slash after the
|
|
|
|
|
# hostname: "https://my.client/".
|
|
|
|
|
#
|
|
|
|
|
# If public_baseurl is set, then the login fallback page (used by clients
|
|
|
|
|
# that don't natively support the required login flows) is whitelisted in
|
|
|
|
|
# addition to any URLs in this list.
|
|
|
|
|
# The login fallback page (used by clients that don't natively support the
|
|
|
|
|
# required login flows) is automatically whitelisted in addition to any URLs
|
|
|
|
|
# in this list.
|
|
|
|
|
#
|
|
|
|
|
# By default, this list is empty.
|
|
|
|
|
#
|
|
|
|
@ -1922,22 +1942,31 @@ sso:
|
|
|
|
|
#
|
|
|
|
|
# Synapse will look for the following templates in this directory:
|
|
|
|
|
#
|
|
|
|
|
# * HTML page for a confirmation step before redirecting back to the client
|
|
|
|
|
# with the login token: 'sso_redirect_confirm.html'.
|
|
|
|
|
# * HTML page to prompt the user to choose an Identity Provider during
|
|
|
|
|
# login: 'sso_login_idp_picker.html'.
|
|
|
|
|
#
|
|
|
|
|
# When rendering, this template is given three variables:
|
|
|
|
|
# * redirect_url: the URL the user is about to be redirected to. Needs
|
|
|
|
|
# manual escaping (see
|
|
|
|
|
# https://jinja.palletsprojects.com/en/2.11.x/templates/#html-escaping).
|
|
|
|
|
# This is only used if multiple SSO Identity Providers are configured.
|
|
|
|
|
#
|
|
|
|
|
# * display_url: the same as `redirect_url`, but with the query
|
|
|
|
|
# parameters stripped. The intention is to have a
|
|
|
|
|
# human-readable URL to show to users, not to use it as
|
|
|
|
|
# the final address to redirect to. Needs manual escaping
|
|
|
|
|
# (see https://jinja.palletsprojects.com/en/2.11.x/templates/#html-escaping).
|
|
|
|
|
# When rendering, this template is given the following variables:
|
|
|
|
|
# * redirect_url: the URL that the user will be redirected to after
|
|
|
|
|
# login. Needs manual escaping (see
|
|
|
|
|
# https://jinja.palletsprojects.com/en/2.11.x/templates/#html-escaping).
|
|
|
|
|
#
|
|
|
|
|
# * server_name: the homeserver's name.
|
|
|
|
|
#
|
|
|
|
|
# * providers: a list of available Identity Providers. Each element is
|
|
|
|
|
# an object with the following attributes:
|
|
|
|
|
# * idp_id: unique identifier for the IdP
|
|
|
|
|
# * idp_name: user-facing name for the IdP
|
|
|
|
|
#
|
|
|
|
|
# The rendered HTML page should contain a form which submits its results
|
|
|
|
|
# back as a GET request, with the following query parameters:
|
|
|
|
|
#
|
|
|
|
|
# * redirectUrl: the client redirect URI (ie, the `redirect_url` passed
|
|
|
|
|
# to the template)
|
|
|
|
|
#
|
|
|
|
|
# * idp: the 'idp_id' of the chosen IDP.
|
|
|
|
|
#
|
|
|
|
|
# * HTML page which notifies the user that they are authenticating to confirm
|
|
|
|
|
# an operation on their account during the user interactive authentication
|
|
|
|
|
# process: 'sso_auth_confirm.html'.
|
|
|
|
@ -1957,6 +1986,14 @@ sso:
|
|
|
|
|
#
|
|
|
|
|
# This template has no additional variables.
|
|
|
|
|
#
|
|
|
|
|
# * HTML page shown after a user-interactive authentication session which
|
|
|
|
|
# does not map correctly onto the expected user: 'sso_auth_bad_user.html'.
|
|
|
|
|
#
|
|
|
|
|
# When rendering, this template is given the following variables:
|
|
|
|
|
# * server_name: the homeserver's name.
|
|
|
|
|
# * user_id_to_verify: the MXID of the user that we are trying to
|
|
|
|
|
# validate.
|
|
|
|
|
#
|
|
|
|
|
# * HTML page shown during single sign-on if a deactivated user (according to Synapse's database)
|
|
|
|
|
# attempts to login: 'sso_account_deactivated.html'.
|
|
|
|
|
#
|
|
|
|
|