2023-03-15 08:58:12 +00:00
---
########################################################################
# #
# com.devture.ansible.role.systemd_service_manager #
# #
########################################################################
devture_systemd_service_manager_services_list_auto: |
{{
2023-03-17 12:25:31 +00:00
([{'name': (collabora_online_identifier + '.service'), 'priority': 2000, 'groups': ['mash', 'collabora-online']}] if collabora_online_enabled else [])
+
2023-03-15 08:58:12 +00:00
([{'name': (devture_postgres_identifier + '.service'), 'priority': 500, 'groups': ['mash', 'postgres']}] if devture_postgres_enabled else [])
+
([{'name': (devture_container_socket_proxy_identifier + '.service'), 'priority': 2900, 'groups': ['mash', 'reverse-proxies', 'container-socket-proxy']}] if devture_container_socket_proxy_enabled else [])
+
([{'name': (devture_traefik_identifier + '.service'), 'priority': 3000, 'groups': ['mash', 'traefik', 'reverse-proxies']}] if devture_traefik_enabled else [])
+
2023-03-16 16:26:06 +00:00
([{'name': (devture_woodpecker_ci_server_identifier + '.service'), 'priority': 4000, 'groups': ['mash', 'woodpecker', 'ci', 'woodpecker-ci-server']}] if devture_woodpecker_ci_server_enabled else [])
+
([{'name': (devture_woodpecker_ci_agent_identifier + '.service'), 'priority': 4100, 'groups': ['mash', 'woodpecker', 'ci', 'woodpecker-ci-agent']}] if devture_woodpecker_ci_agent_enabled else [])
+
([{'name': (gitea_identifier + '.service'), 'priority': 2000, 'groups': ['mash', 'gitea', 'gitea-server']}])
+
2023-03-17 12:25:31 +00:00
([{'name': (nextcloud_identifier + '-server.service'), 'priority': 2000, 'groups': ['mash', 'nextcloud', 'nextcloud-server']}] if nextcloud_enabled else [])
2023-03-17 09:39:04 +00:00
+
([{'name': (nextcloud_identifier + '-cron.timer'), 'priority': 2500, 'groups': ['mash', 'nextcloud', 'nextcloud-cron']}] if nextcloud_enabled else [])
+
2023-03-15 08:58:12 +00:00
([{'name': (miniflux_identifier + '.service'), 'priority': 2000, 'groups': ['mash', 'miniflux']}] if miniflux_enabled else [])
+
([{'name': (radicale_identifier + '.service'), 'priority': 2000, 'groups': ['mash', 'radicale']}] if radicale_enabled else [])
+
2023-03-17 12:25:31 +00:00
([{'name': (vaultwarden_identifier + '.service'), 'priority': 2000, 'groups': ['mash', 'vaultwarden', 'vaultwarden-server']}] if vaultwarden_enabled else [])
2023-03-16 10:05:21 +00:00
+
2023-03-15 08:58:12 +00:00
([{'name': (uptime_kuma_identifier + '.service'), 'priority': 2000, 'groups': ['mash', 'uptime-kuma']}] if uptime_kuma_enabled else [])
}}
########################################################################
# #
# /com.devture.ansible.role.systemd_service_manager #
# #
########################################################################
########################################################################
# #
# com.devture.ansible.role.postgres #
# #
########################################################################
devture_postgres_enabled: false
2023-03-16 12:41:37 +00:00
devture_postgres_identifier: "{{ mash_playbook_service_identifier_prefix }}postgres"
2023-03-15 08:58:12 +00:00
devture_postgres_architecture: "{{ mash_playbook_architecture }}"
devture_postgres_base_path: "{{ mash_playbook_base_path }}/postgres"
devture_postgres_uid: "{{ mash_playbook_uid }}"
devture_postgres_gid: "{{ mash_playbook_gid }}"
devture_postgres_systemd_services_to_stop_for_maintenance_list: |
{{
([(miniflux_identifier + '.service')] if miniflux_enabled else [])
}}
devture_postgres_managed_databases_auto: |
{{
2023-03-16 16:26:06 +00:00
([{
'name': gitea_config_database_name,
'username': gitea_config_database_username,
'password': gitea_config_database_password,
}] if gitea_enabled else [])
+
([{
'name': devture_woodpecker_ci_server_database_datasource_db_name,
'username': devture_woodpecker_ci_server_database_datasource_username,
'password': devture_woodpecker_ci_server_database_datasource_password,
}] if devture_woodpecker_ci_server_enabled else [])
+
2023-03-15 08:58:12 +00:00
([{
'name': miniflux_database_name,
'username': miniflux_database_username,
'password': miniflux_database_password,
}] if miniflux_enabled else [])
2023-03-16 10:05:21 +00:00
+
2023-03-17 09:39:04 +00:00
([{
'name': nextcloud_database_name,
'username': nextcloud_database_username,
'password': nextcloud_database_password,
}] if nextcloud_enabled else [])
+
2023-03-16 10:05:21 +00:00
([{
'name': vaultwarden_database_name,
'username': vaultwarden_database_username,
'password': vaultwarden_database_password,
}] if vaultwarden_enabled else [])
2023-03-15 08:58:12 +00:00
}}
########################################################################
# #
# /com.devture.ansible.role.postgres #
# #
########################################################################
########################################################################
# #
# com.devture.ansible.role.playbook_state_preserver #
# #
########################################################################
# To completely disable this feature, use `devture_playbook_state_preserver_enabled: false`.
devture_playbook_state_preserver_uid: "{{ mash_playbook_uid }}"
devture_playbook_state_preserver_gid: "{{ mash_playbook_gid }}"
devture_playbook_state_preserver_vars_preservation_dst: "{{ mash_playbook_base_path }}/vars.yml"
devture_playbook_state_preserver_commit_hash_preservation_dst: "{{ mash_playbook_base_path }}/git_hash.yml"
########################################################################
# #
# /com.devture.ansible.role.playbook_state_preserver #
# #
########################################################################
########################################################################
# #
# com.devture.ansible.role.container_socket_proxy #
# #
########################################################################
devture_container_socket_proxy_enabled: "{{ devture_traefik_enabled }}"
2023-03-16 12:41:37 +00:00
devture_container_socket_proxy_identifier: "{{ mash_playbook_service_identifier_prefix }}container-socket-proxy"
2023-03-15 08:58:12 +00:00
devture_container_socket_proxy_base_path: "{{ mash_playbook_base_path }}/container-socket-proxy"
devture_container_socket_proxy_uid: "{{ mash_playbook_uid }}"
devture_container_socket_proxy_gid: "{{ mash_playbook_gid }}"
# Traefik requires read access to the containers APIs to do its job
devture_container_socket_proxy_api_containers_enabled: true
########################################################################
# #
# /com.devture.ansible.role.container_socket_proxy #
# #
########################################################################
########################################################################
# #
# com.devture.ansible.role.traefik #
# #
########################################################################
devture_traefik_enabled: "{{ mash_playbook_reverse_proxy_type == 'playbook-managed-traefik' }}"
2023-03-16 12:41:37 +00:00
devture_traefik_identifier: "{{ mash_playbook_service_identifier_prefix }}traefik"
2023-03-15 08:58:12 +00:00
devture_traefik_base_path: "{{ mash_playbook_base_path }}/traefik"
devture_traefik_uid: "{{ mash_playbook_uid }}"
devture_traefik_gid: "{{ mash_playbook_gid }}"
devture_traefik_config_providers_docker_endpoint: "{{ devture_container_socket_proxy_endpoint if devture_container_socket_proxy_enabled else 'unix:///var/run/docker.sock' }}"
devture_traefik_container_additional_networks: |
{{
([devture_container_socket_proxy_container_network] if devture_container_socket_proxy_enabled else [])
}}
devture_traefik_systemd_required_services_list: |
{{
(['docker.service'])
+
([devture_container_socket_proxy_identifier + '.service'] if devture_container_socket_proxy_enabled else [])
}}
########################################################################
# #
# /com.devture.ansible.role.traefik #
# #
########################################################################
########################################################################
# #
# com.devture.ansible.role.docker_sdk_for_python #
# #
########################################################################
# To completely disable installing the Docker SDK for Python, use `devture_docker_sdk_for_python_installation_enabled: false`.
devture_docker_sdk_for_python_installation_enabled: true
########################################################################
# #
# /com.devture.ansible.role.docker_sdk_for_python #
# #
########################################################################
########################################################################
# #
# com.devture.ansible.role.timesync #
# #
########################################################################
# To completely disable installing systemd-timesyncd/ntpd, use `devture_timesync_installation_enabled: false`.
devture_timesync_installation_enabled: false
########################################################################
# #
# /com.devture.ansible.role.timesync #
# #
########################################################################
2023-03-17 12:25:31 +00:00
########################################################################
# #
# collabora-online #
# #
########################################################################
collabora_online_enabled: false
collabora_online_identifier: "{{ mash_playbook_service_identifier_prefix }}collabora-online"
collabora_online_base_path: "{{ mash_playbook_base_path }}/collabora-online"
collabora_online_uid: "{{ mash_playbook_uid }}"
collabora_online_gid: "{{ mash_playbook_gid }}"
collabora_online_container_additional_networks: |
{{
([mash_playbook_reverse_proxyable_services_additional_network] if mash_playbook_reverse_proxyable_services_additional_network else [])
}}
collabora_online_container_labels_traefik_enabled: "{{ mash_playbook_traefik_labels_enabled }}"
collabora_online_container_labels_traefik_docker_network: "{{ mash_playbook_reverse_proxyable_services_additional_network }}"
collabora_online_container_labels_traefik_entrypoints: "{{ devture_traefik_entrypoint_primary }}"
collabora_online_container_labels_traefik_tls_certResolver: "{{ devture_traefik_certResolver_primary }}"
########################################################################
# #
# /collabora-online #
# #
########################################################################
2023-03-15 08:58:12 +00:00
2023-03-16 16:26:06 +00:00
########################################################################
# #
# gitea #
# #
########################################################################
gitea_enabled: false
gitea_identifier: "{{ mash_playbook_service_identifier_prefix }}gitea"
gitea_base_path: "{{ mash_playbook_base_path }}/gitea"
gitea_uid: "{{ mash_playbook_uid }}"
gitea_gid: "{{ mash_playbook_gid }}"
gitea_systemd_required_systemd_services_list: |
{{
(['docker.service'])
+
([devture_postgres_identifier ~ '.service'] if devture_postgres_enabled and gitea_config_database_hostname == devture_postgres_identifier else [])
}}
gitea_container_additional_networks: |
{{
([mash_playbook_reverse_proxyable_services_additional_network] if mash_playbook_reverse_proxyable_services_additional_network else [])
+
([devture_postgres_container_network] if devture_postgres_enabled and gitea_config_database_hostname == devture_postgres_identifier and gitea_container_network != devture_postgres_container_network else [])
}}
gitea_container_labels_traefik_enabled: "{{ mash_playbook_traefik_labels_enabled }}"
gitea_container_labels_traefik_docker_network: "{{ mash_playbook_reverse_proxyable_services_additional_network }}"
gitea_container_labels_traefik_entrypoints: "{{ devture_traefik_entrypoint_primary }}"
gitea_container_labels_traefik_tls_certResolver: "{{ devture_traefik_certResolver_primary }}"
gitea_config_database_hostname: "{{ devture_postgres_identifier if devture_postgres_enabled else '' }}"
gitea_config_database_port: "{{ '5432' if devture_postgres_enabled else '' }}"
gitea_config_database_username: "gitea"
gitea_config_database_password: "{{ '%s' | format(mash_playbook_generic_secret_key) | password_hash('sha512', 'db.gitea', rounds=655555) | to_uuid }}"
########################################################################
# #
# /gitea #
# #
########################################################################
2023-03-15 08:58:12 +00:00
########################################################################
# #
2023-03-17 09:39:04 +00:00
# miniflux #
2023-03-15 08:58:12 +00:00
# #
########################################################################
miniflux_enabled: false
2023-03-16 12:41:37 +00:00
miniflux_identifier: "{{ mash_playbook_service_identifier_prefix }}miniflux"
2023-03-15 08:58:12 +00:00
miniflux_base_path: "{{ mash_playbook_base_path }}/miniflux"
miniflux_uid: "{{ mash_playbook_uid }}"
miniflux_gid: "{{ mash_playbook_gid }}"
2023-03-16 13:41:06 +00:00
miniflux_systemd_required_services_list: |
{{
(['docker.service'])
+
([devture_postgres_identifier ~ '.service'] if devture_postgres_enabled and miniflux_database_hostname == devture_postgres_identifier else [])
}}
2023-03-15 08:58:12 +00:00
miniflux_container_additional_networks: |
{{
([mash_playbook_reverse_proxyable_services_additional_network] if mash_playbook_reverse_proxyable_services_additional_network else [])
+
2023-03-16 13:41:06 +00:00
([devture_postgres_container_network] if devture_postgres_enabled and miniflux_database_hostname == devture_postgres_identifier and miniflux_container_network != devture_postgres_container_network else [])
2023-03-15 08:58:12 +00:00
}}
2023-03-16 09:17:25 +00:00
miniflux_container_labels_traefik_enabled: "{{ mash_playbook_traefik_labels_enabled }}"
2023-03-15 08:58:12 +00:00
miniflux_container_labels_traefik_docker_network: "{{ mash_playbook_reverse_proxyable_services_additional_network }}"
miniflux_container_labels_traefik_entrypoints: "{{ devture_traefik_entrypoint_primary }}"
miniflux_container_labels_traefik_tls_certResolver: "{{ devture_traefik_certResolver_primary }}"
miniflux_database_hostname: "{{ devture_postgres_connection_hostname if devture_postgres_enabled else '' }}"
miniflux_database_password: "{{ '%s' | format(mash_playbook_generic_secret_key) | password_hash('sha512', 'miniflux.db', rounds=655555) | to_uuid }}"
########################################################################
# #
2023-03-17 09:39:04 +00:00
# miniflux #
# #
########################################################################
########################################################################
# #
# nextcloud #
# #
########################################################################
nextcloud_enabled: false
nextcloud_identifier: "{{ mash_playbook_service_identifier_prefix }}nextcloud"
nextcloud_base_path: "{{ mash_playbook_base_path }}/nextcloud"
nextcloud_uid: "{{ mash_playbook_uid }}"
nextcloud_gid: "{{ mash_playbook_gid }}"
nextcloud_systemd_required_systemd_services_list: |
{{
(['docker.service'])
+
([devture_postgres_identifier ~ '.service'] if devture_postgres_enabled and nextcloud_database_hostname == devture_postgres_identifier else [])
}}
nextcloud_container_additional_networks: |
{{
([mash_playbook_reverse_proxyable_services_additional_network] if mash_playbook_reverse_proxyable_services_additional_network else [])
+
([devture_postgres_container_network] if devture_postgres_enabled and nextcloud_database_hostname == devture_postgres_identifier and nextcloud_container_network != devture_postgres_container_network else [])
}}
nextcloud_container_labels_traefik_enabled: "{{ mash_playbook_traefik_labels_enabled }}"
nextcloud_container_labels_traefik_docker_network: "{{ mash_playbook_reverse_proxyable_services_additional_network }}"
nextcloud_container_labels_traefik_entrypoints: "{{ devture_traefik_entrypoint_primary }}"
nextcloud_container_labels_traefik_tls_certResolver: "{{ devture_traefik_certResolver_primary }}"
nextcloud_database_hostname: "{{ devture_postgres_identifier if devture_postgres_enabled else '' }}"
nextcloud_database_port: "{{ '5432' if devture_postgres_enabled else '' }}"
nextcloud_database_username: "nextcloud"
nextcloud_database_password: "{{ '%s' | format(mash_playbook_generic_secret_key) | password_hash('sha512', 'db.nextcloud', rounds=655555) | to_uuid }}"
########################################################################
# #
# /nextcloud #
2023-03-15 08:58:12 +00:00
# #
########################################################################
########################################################################
# #
2023-03-17 09:39:04 +00:00
# radicale #
2023-03-15 08:58:12 +00:00
# #
########################################################################
radicale_enabled: false
2023-03-16 12:41:37 +00:00
radicale_identifier: "{{ mash_playbook_service_identifier_prefix }}radicale"
2023-03-15 08:58:12 +00:00
radicale_base_path: "{{ mash_playbook_base_path }}/radicale"
radicale_uid: "{{ mash_playbook_uid }}"
radicale_gid: "{{ mash_playbook_gid }}"
radicale_container_additional_networks: |
{{
([mash_playbook_reverse_proxyable_services_additional_network] if mash_playbook_reverse_proxyable_services_additional_network else [])
}}
2023-03-16 09:17:25 +00:00
radicale_container_labels_traefik_enabled: "{{ mash_playbook_traefik_labels_enabled }}"
2023-03-15 08:58:12 +00:00
radicale_container_labels_traefik_docker_network: "{{ mash_playbook_reverse_proxyable_services_additional_network }}"
radicale_container_labels_traefik_entrypoints: "{{ devture_traefik_entrypoint_primary }}"
radicale_container_labels_traefik_tls_certResolver: "{{ devture_traefik_certResolver_primary }}"
########################################################################
# #
2023-03-17 09:39:04 +00:00
# radicale #
2023-03-15 08:58:12 +00:00
# #
########################################################################
2023-03-16 10:05:21 +00:00
########################################################################
# #
# vaultwarden #
# #
########################################################################
2023-03-16 16:35:34 +00:00
vaultwarden_enabled: false
2023-03-16 10:05:21 +00:00
2023-03-16 12:41:37 +00:00
vaultwarden_identifier: "{{ mash_playbook_service_identifier_prefix }}vaultwarden"
2023-03-16 10:05:21 +00:00
vaultwarden_uid: "{{ mash_playbook_uid }}"
vaultwarden_gid: "{{ mash_playbook_gid }}"
vaultwarden_base_path: "{{ mash_playbook_base_path }}/vaultwarden"
vaultwarden_systemd_required_systemd_services_list: |
{{
(['docker.service'])
+
2023-03-16 13:41:06 +00:00
([devture_postgres_identifier ~ '.service'] if devture_postgres_enabled and vaultwarden_database_hostname == devture_postgres_identifier else [])
2023-03-16 10:05:21 +00:00
}}
vaultwarden_container_additional_networks: |
{{
([mash_playbook_reverse_proxyable_services_additional_network] if mash_playbook_reverse_proxyable_services_additional_network else [])
+
([devture_postgres_container_network] if devture_postgres_enabled and vaultwarden_database_hostname == devture_postgres_identifier and vaultwarden_container_network != devture_postgres_container_network else [])
}}
vaultwarden_container_labels_traefik_enabled: "{{ mash_playbook_traefik_labels_enabled }}"
vaultwarden_container_labels_traefik_docker_network: "{{ mash_playbook_reverse_proxyable_services_additional_network }}"
vaultwarden_database_hostname: "{{ devture_postgres_identifier if devture_postgres_enabled else '' }}"
vaultwarden_database_port: "{{ '5432' if devture_postgres_enabled else '' }}"
vaultwarden_database_username: "vaultwarden"
vaultwarden_database_password: "{{ '%s' | format(mash_playbook_generic_secret_key) | password_hash('sha512', 'db.vaultwarden', rounds=655555) | to_uuid }}"
########################################################################
# #
# /vaultwarden #
# #
########################################################################
2023-03-15 08:58:12 +00:00
########################################################################
# #
# etke/uptime_kuma #
# #
########################################################################
uptime_kuma_enabled: false
2023-03-16 12:41:37 +00:00
uptime_kuma_identifier: "{{ mash_playbook_service_identifier_prefix }}uptime-kuma"
2023-03-15 08:58:12 +00:00
uptime_kuma_base_path: "{{ mash_playbook_base_path }}/uptime-kuma"
uptime_kuma_uid: "{{ mash_playbook_uid }}"
uptime_kuma_gid: "{{ mash_playbook_gid }}"
uptime_kuma_container_additional_networks: |
{{
([mash_playbook_reverse_proxyable_services_additional_network] if mash_playbook_reverse_proxyable_services_additional_network else [])
}}
2023-03-16 09:17:25 +00:00
uptime_kuma_container_labels_traefik_enabled: "{{ mash_playbook_traefik_labels_enabled }}"
2023-03-15 08:58:12 +00:00
uptime_kuma_container_labels_traefik_docker_network: "{{ mash_playbook_reverse_proxyable_services_additional_network }}"
uptime_kuma_container_labels_traefik_entrypoints: "{{ devture_traefik_entrypoint_primary }}"
uptime_kuma_container_labels_traefik_tls_certResolver: "{{ devture_traefik_certResolver_primary }}"
########################################################################
# #
# /etke/uptime_kuma #
# #
########################################################################
2023-03-16 16:26:06 +00:00
########################################################################
# #
# woodpecker-ci-server #
# #
########################################################################
devture_woodpecker_ci_server_enabled: false
devture_woodpecker_ci_server_identifier: "{{ mash_playbook_service_identifier_prefix }}woodpecker-ci-server"
devture_woodpecker_ci_server_uid: "{{ mash_playbook_uid }}"
devture_woodpecker_ci_server_gid: "{{ mash_playbook_gid }}"
devture_woodpecker_ci_server_base_path: "{{ mash_playbook_base_path }}/woodpecker-ci/server"
devture_woodpecker_ci_server_systemd_required_systemd_services_list: |
{{
(['docker.service'])
+
([devture_postgres_identifier ~ '.service'] if devture_postgres_enabled and devture_woodpecker_ci_server_database_datasource_hostname == devture_postgres_identifier else [])
}}
devture_woodpecker_ci_server_container_additional_networks: |
{{
(
([mash_playbook_reverse_proxyable_services_additional_network] if mash_playbook_reverse_proxyable_services_additional_network else [])
+
([devture_postgres_container_network] if devture_postgres_enabled and devture_woodpecker_ci_server_database_datasource_hostname == devture_postgres_identifier and devture_woodpecker_ci_server_container_network != devture_postgres_container_network else [])
) | unique
}}
devture_woodpecker_ci_server_container_labels_traefik_enabled: "{{ mash_playbook_traefik_labels_enabled }}"
devture_woodpecker_ci_server_container_labels_traefik_docker_network: "{{ mash_playbook_reverse_proxyable_services_additional_network }}"
devture_woodpecker_ci_server_database_driver: postgres
devture_woodpecker_ci_server_database_datasource: "postgres://{{ devture_woodpecker_ci_server_database_datasource_username }}:{{ devture_woodpecker_ci_server_database_datasource_password }}@{{ devture_woodpecker_ci_server_database_datasource_hostname }}:{{ devture_woodpecker_ci_server_database_datasource_port }}/{{ devture_woodpecker_ci_server_database_datasource_db_name }}?sslmode=disable"
devture_woodpecker_ci_server_database_datasource_hostname: "{{ devture_postgres_identifier if devture_postgres_enabled else '' }}"
devture_woodpecker_ci_server_database_datasource_port: "{{ '5432' if devture_postgres_enabled else '' }}"
devture_woodpecker_ci_server_database_datasource_username: woodpecker_ci_server
devture_woodpecker_ci_server_database_datasource_password: "{{ '%s' | format(mash_playbook_generic_secret_key) | password_hash('sha512', 'woodpecker.ci', rounds=655555) | to_uuid }}"
devture_woodpecker_ci_server_database_datasource_db_name: woodpecker_ci_server
########################################################################
# #
# /woodpecker-ci-server #
# #
########################################################################
########################################################################
# #
# woodpecker-ci-agent #
# #
########################################################################
devture_woodpecker_ci_agent_enabled: false
devture_woodpecker_ci_agent_identifier: "{{ mash_playbook_service_identifier_prefix }}woodpecker-ci-agent"
devture_woodpecker_ci_agent_uid: "{{ mash_playbook_uid }}"
devture_woodpecker_ci_agent_gid: "{{ mash_playbook_gid }}"
devture_woodpecker_ci_agent_base_path: "{{ mash_playbook_base_path }}/woodpecker-ci/agent"
devture_woodpecker_ci_agent_systemd_required_systemd_services_list: |
{{
(['docker.service'])
+
([devture_woodpecker_ci_server_identifier ~ '.service'] if devture_woodpecker_ci_server_enabled else [])
}}
devture_woodpecker_ci_agent_container_additional_networks: |
{{
(
([devture_woodpecker_ci_server_container_network] if devture_woodpecker_ci_server_enabled and devture_woodpecker_ci_server_container_network != devture_woodpecker_ci_agent_container_network else [])
) | unique
}}
devture_woodpecker_ci_agent_config_server: "{{ (devture_woodpecker_ci_server_identifier + ':' + devture_woodpecker_ci_server_config_grpc_addr_port | string) if devture_woodpecker_ci_agent_enabled else '' }}"
devture_woodpecker_ci_agent_config_agent_secret: "{{ devture_woodpecker_ci_server_config_agent_secret if devture_woodpecker_ci_agent_enabled else '' }}"
########################################################################
# #
# /woodpecker-ci-agent #
# #
########################################################################