From 2c0f8493839e086dd064edef2baa12e0b86820b3 Mon Sep 17 00:00:00 2001 From: mik-tf Date: Mon, 15 Apr 2024 18:35:56 +0000 Subject: [PATCH] manual added whole devs --- .../documentation/developers/flist/flist.md | 11 + .../flist_case_studies/flist_case_studies.md | 6 + .../flist_debian_case_study.md | 300 ++++++ .../flist_nextcloud_case_study.md | 858 ++++++++++++++++++ .../img/nextcloud_logo.jpeg | Bin 0 -> 29564 bytes .../developers/flist/flist_hub/api_token.md | 33 + .../flist/flist_hub/convert_docker_image.md | 45 + .../flist/flist_hub/img/docker_convert.png | Bin 0 -> 191136 bytes .../flist/flist_hub/img/flist_ready.png | Bin 0 -> 47573 bytes .../flist/flist_hub/img/hub_flist.png | Bin 0 -> 212870 bytes .../flist/flist_hub/img/preview.png | Bin 0 -> 69725 bytes .../developers/flist/flist_hub/img/search.png | Bin 0 -> 39845 bytes .../developers/flist/flist_hub/zos_hub.md | 142 +++ .../flist/grid3_supported_flists.md | 26 + .../developers/go/grid3_go_gateways.md | 104 +++ .../developers/go/grid3_go_gpu.md | 6 + .../developers/go/grid3_go_gpu_support.md | 116 +++ .../developers/go/grid3_go_installation.md | 45 + .../developers/go/grid3_go_kubernetes.md | 120 +++ .../developers/go/grid3_go_load_client.md | 35 + .../developers/go/grid3_go_qsfs.md | 186 ++++ .../developers/go/grid3_go_readme.md | 17 + .../developers/go/grid3_go_vm.md | 99 ++ .../developers/go/grid3_go_vm_with_gpu.md | 121 +++ .../developers/go/grid3_go_vms.md | 125 +++ .../grid_deployment/grid_deployment.md | 9 + .../grid_deployment_full_vm.md | 152 ++++ .../developers/grid_deployment/snapshots.md | 196 ++++ .../grid_deployment/snapshots_archive.md | 206 +++++ .../grid_deployment/tfgrid_stacks.md | 32 + .../developers/internals/internals.md | 19 + .../developers/internals/rmb/img/layout.png | Bin 0 -> 31775 bytes .../developers/internals/rmb/img/peer.png | Bin 0 -> 43853 bytes .../developers/internals/rmb/img/relay.png | Bin 0 -> 28484 bytes .../developers/internals/rmb/rmb_intro.md | 107 +++ .../developers/internals/rmb/rmb_specs.md | 258 ++++++ .../developers/internals/rmb/rmb_toc.md | 18 + .../developers/internals/rmb/uml/peer.md | 44 + .../developers/internals/rmb/uml/relay.md | 40 + .../developers/internals/zos/assets/.keep | 0 .../zos/assets/0-OS v2 architecture.xml | 1 + .../internals/zos/assets/0-OS-upgrade.png | Bin 0 -> 16652 bytes .../internals/zos/assets/0-OS-upgrade.wsd | 12 + .../zos/assets/0-OS_v2_architecture.png | Bin 0 -> 25641 bytes .../zos/assets/Container_module_flow.png | Bin 0 -> 48572 bytes .../zos/assets/boot_sequence.plantuml | 50 + .../internals/zos/assets/boot_sequence.png | Bin 0 -> 33268 bytes .../zos/assets/grid_provisioning.png | Bin 0 -> 46207 bytes .../zos/assets/grid_provisioning.wsd | 37 + .../zos/assets/grid_provisioning2.png | Bin 0 -> 71768 bytes .../zos/assets/grid_provisioning2.wsd | 42 + .../internals/zos/assets/ipc.plantuml | 20 + .../developers/internals/zos/assets/ipc.png | Bin 0 -> 15186 bytes .../internals/zos/assets/market.png | Bin 0 -> 23204 bytes .../internals/zos/assets/market.wsd | 22 + .../internals/zos/development/README.md | 6 + .../internals/zos/development/net.sh | 30 + .../internals/zos/development/packages.md | 61 ++ .../internals/zos/development/quickstart.md | 70 ++ .../internals/zos/development/testing.md | 157 ++++ .../developers/internals/zos/faq/readme.md | 6 + .../internals/zos/internals/boot.md | 11 + .../internals/zos/internals/capacity.md | 89 ++ .../zos/internals/compatibility/readme.md | 14 + .../zos/internals/container/readme.md | 106 +++ .../internals/zos/internals/flist/readme.md | 74 ++ .../internals/zos/internals/gateway/readme.md | 121 +++ .../internals/zos/internals/history/readme.md | 99 ++ .../zos/internals/identity/identity.md | 143 +++ .../zos/internals/identity/readme.md | 8 + .../zos/internals/identity/upgrade.md | 98 ++ .../internals/zos/internals/internals.md | 88 ++ .../internals/zos/internals/macdev/readme.md | 57 ++ .../internals/network/Deploy_Network-V2.md | 74 ++ .../zos/internals/network/HIDDEN-PUBLIC.dia | Bin 0 -> 4201 bytes .../zos/internals/network/HIDDEN-PUBLIC.png | Bin 0 -> 62117 bytes .../zos/internals/network/NR_layout.dia | Bin 0 -> 2884 bytes .../zos/internals/network/NR_layout.png | Bin 0 -> 39589 bytes .../zos/internals/network/Network-V2.md | 315 +++++++ .../zos/internals/network/attic/exitpoints.md | 66 ++ .../zos/internals/network/attic/tools.md | 264 ++++++ .../zos/internals/network/attic/zostst.dhcp | 54 ++ .../zos/internals/network/definitions.md | 35 + .../zos/internals/network/introduction.md | 87 ++ .../internals/zos/internals/network/mesh.md | 134 +++ .../internals/zos/internals/network/readme.md | 8 + .../internals/network/setup_farm_network.md | 123 +++ .../network/topology/png/ndmz-dualstack.png | Bin 0 -> 53698 bytes .../network/topology/png/ndmz-hidden.png | Bin 0 -> 51548 bytes .../network/topology/png/nr-join.png | Bin 0 -> 20412 bytes .../network/topology/png/nr-step-1.png | Bin 0 -> 29124 bytes .../network/topology/png/nr-step-2.png | Bin 0 -> 30699 bytes .../network/topology/png/public-namespace.png | Bin 0 -> 26025 bytes .../network/topology/png/zos-bridge.png | Bin 0 -> 11727 bytes .../zos/internals/network/topology/readme.md | 68 ++ .../network/topology/uml/ndmz-dualstack.wsd | 57 ++ .../network/topology/uml/ndmz-hidden.wsd | 55 ++ .../network/topology/uml/nr-join.wsd | 23 + .../network/topology/uml/nr-step-1.wsd | 31 + .../network/topology/uml/nr-step-2.wsd | 33 + .../network/topology/uml/public-namespace.wsd | 29 + .../network/topology/uml/zos-bridge.wsd | 16 + .../zos/internals/network/yggdrasil.md | 25 + .../internals/zos/internals/network/zbus.md | 46 + .../internals/zos/internals/node/readme.md | 50 + .../zos/internals/provision/readme.md | 35 + .../internals/zos/internals/storage/readme.md | 153 ++++ .../internals/zos/internals/vmd/readme.md | 66 ++ .../developers/internals/zos/manual/api.md | 273 ++++++ .../zos/manual/gateway/fqdn-proxy.md | 5 + .../zos/manual/gateway/name-proxy.md | 5 + .../internals/zos/manual/ip/readme.md | 11 + .../developers/internals/zos/manual/manual.md | 187 ++++ .../internals/zos/manual/network/readme.md | 14 + .../internals/zos/manual/qsfs/readme.md | 5 + .../internals/zos/manual/workload_types.md | 108 +++ .../internals/zos/manual/zdb/readme.md | 4 + .../internals/zos/manual/zlogs/readme.md | 11 + .../zos/manual/zmachine/cloud-console.md | 14 + .../internals/zos/manual/zmachine/readme.md | 13 + .../internals/zos/manual/zmachine/zmachine.md | 410 +++++++++ .../internals/zos/manual/zmount/readme.md | 2 + .../internals/zos/performance/cpubench.md | 85 ++ .../internals/zos/performance/healthcheck.md | 38 + .../internals/zos/performance/iperf.md | 80 ++ .../internals/zos/performance/performance.md | 90 ++ .../internals/zos/performance/publicips.md | 55 ++ .../developers/internals/zos/readme.md | 28 + .../internals/zos/release/readme.md | 31 + .../grid3_javascript_capacity_planning.md | 110 +++ .../javascript/grid3_javascript_caprover.md | 232 +++++ .../grid3_javascript_gpu_support.md | 91 ++ .../grid3_javascript_installation.md | 124 +++ .../javascript/grid3_javascript_kubernetes.md | 186 ++++ .../javascript/grid3_javascript_kvstore.md | 101 +++ .../javascript/grid3_javascript_loadclient.md | 68 ++ .../javascript/grid3_javascript_qsfs.md | 297 ++++++ .../javascript/grid3_javascript_qsfs_zdbs.md | 142 +++ .../javascript/grid3_javascript_readme.md | 24 + .../grid3_javascript_run_scripts.md | 15 + .../javascript/grid3_javascript_vm.md | 194 ++++ .../grid3_javascript_vm_gateways.md | 189 ++++ .../javascript/grid3_javascript_vms.md | 108 +++ .../javascript/grid3_javascript_zdb.md | 143 +++ .../javascript/grid3_wireguard_gateway.md | 302 ++++++ .../developers/javascript/sidebar.md | 11 + .../developers/proxy/commands.md | 127 +++ .../developers/proxy/contributions.md | 55 ++ .../developers/proxy/database.md | 21 + .../developers/proxy/db_testing.md | 45 + .../developers/proxy/explorer.md | 38 + .../developers/proxy/production.md | 117 +++ .../documentation/developers/proxy/proxy.md | 149 +++ .../developers/proxy/proxy_readme.md | 25 + .../documentation/developers/proxy/release.md | 32 + .../documentation/developers/proxy/setup.md | 50 + .../developers/tfchain/farming_policies.md | 94 ++ .../developers/tfchain/img/{tf.png => TF.png} | Bin .../developers/tfchain/introduction.md | 57 ++ .../tfchain_external_service_contract.md | 142 +++ .../tfchain/tfchain_solution_provider.md | 81 ++ .../documentation/developers/tfcmd/tfcmd.md | 15 + .../developers/tfcmd/tfcmd_basics.md | 67 ++ .../developers/tfcmd/tfcmd_contracts.md | 99 ++ .../developers/tfcmd/tfcmd_gateway_fqdn.md | 87 ++ .../developers/tfcmd/tfcmd_gateway_name.md | 88 ++ .../developers/tfcmd/tfcmd_kubernetes.md | 147 +++ .../developers/tfcmd/tfcmd_vm.md | 171 ++++ .../developers/tfcmd/tfcmd_zdbs.md | 125 +++ .../developers/tfrobot/tfrobot.md | 13 + .../tfrobot/tfrobot_commands_flags.md | 57 ++ .../developers/tfrobot/tfrobot_config.md | 131 +++ .../tfrobot/tfrobot_configurations.md | 68 ++ .../developers/tfrobot/tfrobot_deploy.md | 59 ++ .../tfrobot/tfrobot_installation.md | 36 + 175 files changed, 12747 insertions(+) create mode 100644 collections/manual/documentation/developers/flist/flist.md create mode 100644 collections/manual/documentation/developers/flist/flist_case_studies/flist_case_studies.md create mode 100644 collections/manual/documentation/developers/flist/flist_case_studies/flist_debian_case_study.md create mode 100644 collections/manual/documentation/developers/flist/flist_case_studies/flist_nextcloud_case_study.md create mode 100644 collections/manual/documentation/developers/flist/flist_case_studies/img/nextcloud_logo.jpeg create mode 100644 collections/manual/documentation/developers/flist/flist_hub/api_token.md create mode 100644 collections/manual/documentation/developers/flist/flist_hub/convert_docker_image.md create mode 100644 collections/manual/documentation/developers/flist/flist_hub/img/docker_convert.png create mode 100644 collections/manual/documentation/developers/flist/flist_hub/img/flist_ready.png create mode 100644 collections/manual/documentation/developers/flist/flist_hub/img/hub_flist.png create mode 100644 collections/manual/documentation/developers/flist/flist_hub/img/preview.png create mode 100644 collections/manual/documentation/developers/flist/flist_hub/img/search.png create mode 100644 collections/manual/documentation/developers/flist/flist_hub/zos_hub.md create mode 100644 collections/manual/documentation/developers/flist/grid3_supported_flists.md create mode 100644 collections/manual/documentation/developers/go/grid3_go_gateways.md create mode 100644 collections/manual/documentation/developers/go/grid3_go_gpu.md create mode 100644 collections/manual/documentation/developers/go/grid3_go_gpu_support.md create mode 100644 collections/manual/documentation/developers/go/grid3_go_installation.md create mode 100644 collections/manual/documentation/developers/go/grid3_go_kubernetes.md create mode 100644 collections/manual/documentation/developers/go/grid3_go_load_client.md create mode 100644 collections/manual/documentation/developers/go/grid3_go_qsfs.md create mode 100644 collections/manual/documentation/developers/go/grid3_go_readme.md create mode 100644 collections/manual/documentation/developers/go/grid3_go_vm.md create mode 100644 collections/manual/documentation/developers/go/grid3_go_vm_with_gpu.md create mode 100644 collections/manual/documentation/developers/go/grid3_go_vms.md create mode 100644 collections/manual/documentation/developers/grid_deployment/grid_deployment.md create mode 100644 collections/manual/documentation/developers/grid_deployment/grid_deployment_full_vm.md create mode 100644 collections/manual/documentation/developers/grid_deployment/snapshots.md create mode 100644 collections/manual/documentation/developers/grid_deployment/snapshots_archive.md create mode 100644 collections/manual/documentation/developers/grid_deployment/tfgrid_stacks.md create mode 100644 collections/manual/documentation/developers/internals/internals.md create mode 100644 collections/manual/documentation/developers/internals/rmb/img/layout.png create mode 100644 collections/manual/documentation/developers/internals/rmb/img/peer.png create mode 100644 collections/manual/documentation/developers/internals/rmb/img/relay.png create mode 100644 collections/manual/documentation/developers/internals/rmb/rmb_intro.md create mode 100644 collections/manual/documentation/developers/internals/rmb/rmb_specs.md create mode 100644 collections/manual/documentation/developers/internals/rmb/rmb_toc.md create mode 100644 collections/manual/documentation/developers/internals/rmb/uml/peer.md create mode 100644 collections/manual/documentation/developers/internals/rmb/uml/relay.md create mode 100644 collections/manual/documentation/developers/internals/zos/assets/.keep create mode 100644 collections/manual/documentation/developers/internals/zos/assets/0-OS v2 architecture.xml create mode 100644 collections/manual/documentation/developers/internals/zos/assets/0-OS-upgrade.png create mode 100644 collections/manual/documentation/developers/internals/zos/assets/0-OS-upgrade.wsd create mode 100644 collections/manual/documentation/developers/internals/zos/assets/0-OS_v2_architecture.png create mode 100644 collections/manual/documentation/developers/internals/zos/assets/Container_module_flow.png create mode 100644 collections/manual/documentation/developers/internals/zos/assets/boot_sequence.plantuml create mode 100644 collections/manual/documentation/developers/internals/zos/assets/boot_sequence.png create mode 100644 collections/manual/documentation/developers/internals/zos/assets/grid_provisioning.png create mode 100644 collections/manual/documentation/developers/internals/zos/assets/grid_provisioning.wsd create mode 100644 collections/manual/documentation/developers/internals/zos/assets/grid_provisioning2.png create mode 100644 collections/manual/documentation/developers/internals/zos/assets/grid_provisioning2.wsd create mode 100644 collections/manual/documentation/developers/internals/zos/assets/ipc.plantuml create mode 100644 collections/manual/documentation/developers/internals/zos/assets/ipc.png create mode 100644 collections/manual/documentation/developers/internals/zos/assets/market.png create mode 100644 collections/manual/documentation/developers/internals/zos/assets/market.wsd create mode 100644 collections/manual/documentation/developers/internals/zos/development/README.md create mode 100755 collections/manual/documentation/developers/internals/zos/development/net.sh create mode 100644 collections/manual/documentation/developers/internals/zos/development/packages.md create mode 100644 collections/manual/documentation/developers/internals/zos/development/quickstart.md create mode 100644 collections/manual/documentation/developers/internals/zos/development/testing.md create mode 100644 collections/manual/documentation/developers/internals/zos/faq/readme.md create mode 100644 collections/manual/documentation/developers/internals/zos/internals/boot.md create mode 100644 collections/manual/documentation/developers/internals/zos/internals/capacity.md create mode 100644 collections/manual/documentation/developers/internals/zos/internals/compatibility/readme.md create mode 100644 collections/manual/documentation/developers/internals/zos/internals/container/readme.md create mode 100644 collections/manual/documentation/developers/internals/zos/internals/flist/readme.md create mode 100644 collections/manual/documentation/developers/internals/zos/internals/gateway/readme.md create mode 100644 collections/manual/documentation/developers/internals/zos/internals/history/readme.md create mode 100644 collections/manual/documentation/developers/internals/zos/internals/identity/identity.md create mode 100644 collections/manual/documentation/developers/internals/zos/internals/identity/readme.md create mode 100644 collections/manual/documentation/developers/internals/zos/internals/identity/upgrade.md create mode 100644 collections/manual/documentation/developers/internals/zos/internals/internals.md create mode 100644 collections/manual/documentation/developers/internals/zos/internals/macdev/readme.md create mode 100644 collections/manual/documentation/developers/internals/zos/internals/network/Deploy_Network-V2.md create mode 100644 collections/manual/documentation/developers/internals/zos/internals/network/HIDDEN-PUBLIC.dia create mode 100644 collections/manual/documentation/developers/internals/zos/internals/network/HIDDEN-PUBLIC.png create mode 100644 collections/manual/documentation/developers/internals/zos/internals/network/NR_layout.dia create mode 100644 collections/manual/documentation/developers/internals/zos/internals/network/NR_layout.png create mode 100644 collections/manual/documentation/developers/internals/zos/internals/network/Network-V2.md create mode 100644 collections/manual/documentation/developers/internals/zos/internals/network/attic/exitpoints.md create mode 100644 collections/manual/documentation/developers/internals/zos/internals/network/attic/tools.md create mode 100644 collections/manual/documentation/developers/internals/zos/internals/network/attic/zostst.dhcp create mode 100644 collections/manual/documentation/developers/internals/zos/internals/network/definitions.md create mode 100644 collections/manual/documentation/developers/internals/zos/internals/network/introduction.md create mode 100644 collections/manual/documentation/developers/internals/zos/internals/network/mesh.md create mode 100644 collections/manual/documentation/developers/internals/zos/internals/network/readme.md create mode 100644 collections/manual/documentation/developers/internals/zos/internals/network/setup_farm_network.md create mode 100644 collections/manual/documentation/developers/internals/zos/internals/network/topology/png/ndmz-dualstack.png create mode 100644 collections/manual/documentation/developers/internals/zos/internals/network/topology/png/ndmz-hidden.png create mode 100644 collections/manual/documentation/developers/internals/zos/internals/network/topology/png/nr-join.png create mode 100644 collections/manual/documentation/developers/internals/zos/internals/network/topology/png/nr-step-1.png create mode 100644 collections/manual/documentation/developers/internals/zos/internals/network/topology/png/nr-step-2.png create mode 100644 collections/manual/documentation/developers/internals/zos/internals/network/topology/png/public-namespace.png create mode 100644 collections/manual/documentation/developers/internals/zos/internals/network/topology/png/zos-bridge.png create mode 100644 collections/manual/documentation/developers/internals/zos/internals/network/topology/readme.md create mode 100644 collections/manual/documentation/developers/internals/zos/internals/network/topology/uml/ndmz-dualstack.wsd create mode 100644 collections/manual/documentation/developers/internals/zos/internals/network/topology/uml/ndmz-hidden.wsd create mode 100644 collections/manual/documentation/developers/internals/zos/internals/network/topology/uml/nr-join.wsd create mode 100644 collections/manual/documentation/developers/internals/zos/internals/network/topology/uml/nr-step-1.wsd create mode 100644 collections/manual/documentation/developers/internals/zos/internals/network/topology/uml/nr-step-2.wsd create mode 100644 collections/manual/documentation/developers/internals/zos/internals/network/topology/uml/public-namespace.wsd create mode 100644 collections/manual/documentation/developers/internals/zos/internals/network/topology/uml/zos-bridge.wsd create mode 100644 collections/manual/documentation/developers/internals/zos/internals/network/yggdrasil.md create mode 100644 collections/manual/documentation/developers/internals/zos/internals/network/zbus.md create mode 100644 collections/manual/documentation/developers/internals/zos/internals/node/readme.md create mode 100644 collections/manual/documentation/developers/internals/zos/internals/provision/readme.md create mode 100644 collections/manual/documentation/developers/internals/zos/internals/storage/readme.md create mode 100644 collections/manual/documentation/developers/internals/zos/internals/vmd/readme.md create mode 100644 collections/manual/documentation/developers/internals/zos/manual/api.md create mode 100644 collections/manual/documentation/developers/internals/zos/manual/gateway/fqdn-proxy.md create mode 100644 collections/manual/documentation/developers/internals/zos/manual/gateway/name-proxy.md create mode 100644 collections/manual/documentation/developers/internals/zos/manual/ip/readme.md create mode 100644 collections/manual/documentation/developers/internals/zos/manual/manual.md create mode 100644 collections/manual/documentation/developers/internals/zos/manual/network/readme.md create mode 100644 collections/manual/documentation/developers/internals/zos/manual/qsfs/readme.md create mode 100644 collections/manual/documentation/developers/internals/zos/manual/workload_types.md create mode 100644 collections/manual/documentation/developers/internals/zos/manual/zdb/readme.md create mode 100644 collections/manual/documentation/developers/internals/zos/manual/zlogs/readme.md create mode 100644 collections/manual/documentation/developers/internals/zos/manual/zmachine/cloud-console.md create mode 100644 collections/manual/documentation/developers/internals/zos/manual/zmachine/readme.md create mode 100644 collections/manual/documentation/developers/internals/zos/manual/zmachine/zmachine.md create mode 100644 collections/manual/documentation/developers/internals/zos/manual/zmount/readme.md create mode 100644 collections/manual/documentation/developers/internals/zos/performance/cpubench.md create mode 100644 collections/manual/documentation/developers/internals/zos/performance/healthcheck.md create mode 100644 collections/manual/documentation/developers/internals/zos/performance/iperf.md create mode 100644 collections/manual/documentation/developers/internals/zos/performance/performance.md create mode 100644 collections/manual/documentation/developers/internals/zos/performance/publicips.md create mode 100644 collections/manual/documentation/developers/internals/zos/readme.md create mode 100644 collections/manual/documentation/developers/internals/zos/release/readme.md create mode 100644 collections/manual/documentation/developers/javascript/grid3_javascript_capacity_planning.md create mode 100644 collections/manual/documentation/developers/javascript/grid3_javascript_caprover.md create mode 100644 collections/manual/documentation/developers/javascript/grid3_javascript_gpu_support.md create mode 100644 collections/manual/documentation/developers/javascript/grid3_javascript_installation.md create mode 100644 collections/manual/documentation/developers/javascript/grid3_javascript_kubernetes.md create mode 100644 collections/manual/documentation/developers/javascript/grid3_javascript_kvstore.md create mode 100644 collections/manual/documentation/developers/javascript/grid3_javascript_loadclient.md create mode 100644 collections/manual/documentation/developers/javascript/grid3_javascript_qsfs.md create mode 100644 collections/manual/documentation/developers/javascript/grid3_javascript_qsfs_zdbs.md create mode 100644 collections/manual/documentation/developers/javascript/grid3_javascript_readme.md create mode 100644 collections/manual/documentation/developers/javascript/grid3_javascript_run_scripts.md create mode 100644 collections/manual/documentation/developers/javascript/grid3_javascript_vm.md create mode 100644 collections/manual/documentation/developers/javascript/grid3_javascript_vm_gateways.md create mode 100644 collections/manual/documentation/developers/javascript/grid3_javascript_vms.md create mode 100644 collections/manual/documentation/developers/javascript/grid3_javascript_zdb.md create mode 100644 collections/manual/documentation/developers/javascript/grid3_wireguard_gateway.md create mode 100644 collections/manual/documentation/developers/javascript/sidebar.md create mode 100644 collections/manual/documentation/developers/proxy/commands.md create mode 100644 collections/manual/documentation/developers/proxy/contributions.md create mode 100644 collections/manual/documentation/developers/proxy/database.md create mode 100644 collections/manual/documentation/developers/proxy/db_testing.md create mode 100644 collections/manual/documentation/developers/proxy/explorer.md create mode 100644 collections/manual/documentation/developers/proxy/production.md create mode 100644 collections/manual/documentation/developers/proxy/proxy.md create mode 100644 collections/manual/documentation/developers/proxy/proxy_readme.md create mode 100644 collections/manual/documentation/developers/proxy/release.md create mode 100644 collections/manual/documentation/developers/proxy/setup.md create mode 100644 collections/manual/documentation/developers/tfchain/farming_policies.md rename collections/manual/documentation/developers/tfchain/img/{tf.png => TF.png} (100%) create mode 100644 collections/manual/documentation/developers/tfchain/introduction.md create mode 100644 collections/manual/documentation/developers/tfchain/tfchain_external_service_contract.md create mode 100644 collections/manual/documentation/developers/tfchain/tfchain_solution_provider.md create mode 100644 collections/manual/documentation/developers/tfcmd/tfcmd.md create mode 100644 collections/manual/documentation/developers/tfcmd/tfcmd_basics.md create mode 100644 collections/manual/documentation/developers/tfcmd/tfcmd_contracts.md create mode 100644 collections/manual/documentation/developers/tfcmd/tfcmd_gateway_fqdn.md create mode 100644 collections/manual/documentation/developers/tfcmd/tfcmd_gateway_name.md create mode 100644 collections/manual/documentation/developers/tfcmd/tfcmd_kubernetes.md create mode 100644 collections/manual/documentation/developers/tfcmd/tfcmd_vm.md create mode 100644 collections/manual/documentation/developers/tfcmd/tfcmd_zdbs.md create mode 100644 collections/manual/documentation/developers/tfrobot/tfrobot.md create mode 100644 collections/manual/documentation/developers/tfrobot/tfrobot_commands_flags.md create mode 100644 collections/manual/documentation/developers/tfrobot/tfrobot_config.md create mode 100644 collections/manual/documentation/developers/tfrobot/tfrobot_configurations.md create mode 100644 collections/manual/documentation/developers/tfrobot/tfrobot_deploy.md create mode 100644 collections/manual/documentation/developers/tfrobot/tfrobot_installation.md diff --git a/collections/manual/documentation/developers/flist/flist.md b/collections/manual/documentation/developers/flist/flist.md new file mode 100644 index 0000000..6c69e05 --- /dev/null +++ b/collections/manual/documentation/developers/flist/flist.md @@ -0,0 +1,11 @@ +

Flist

+ +

Table of Contents

+ +- [Zero-OS Hub](./flist_hub/zos_hub.md) +- [Generate an API Token](./flist_hub/api_token.md) +- [Convert Docker Image Into Flist](./flist_hub/convert_docker_image.md) +- [Supported Flists](./grid3_supported_flists.md) +- [Flist Case Studies](./flist_case_studies/flist_case_studies.md) + - [Case Study: Debian 12](./flist_case_studies/flist_debian_case_study.md) + - [Case Study: Nextcloud AIO](./flist_case_studies/flist_nextcloud_case_study.md) \ No newline at end of file diff --git a/collections/manual/documentation/developers/flist/flist_case_studies/flist_case_studies.md b/collections/manual/documentation/developers/flist/flist_case_studies/flist_case_studies.md new file mode 100644 index 0000000..b258836 --- /dev/null +++ b/collections/manual/documentation/developers/flist/flist_case_studies/flist_case_studies.md @@ -0,0 +1,6 @@ +

Flist Case Studies

+ +

Table of Contents

+ +- [Case Study: Debian 12](./flist_debian_case_study.md) +- [Case Study: Nextcloud AIO](./flist_nextcloud_case_study.md) \ No newline at end of file diff --git a/collections/manual/documentation/developers/flist/flist_case_studies/flist_debian_case_study.md b/collections/manual/documentation/developers/flist/flist_case_studies/flist_debian_case_study.md new file mode 100644 index 0000000..3777433 --- /dev/null +++ b/collections/manual/documentation/developers/flist/flist_case_studies/flist_debian_case_study.md @@ -0,0 +1,300 @@ +

Flist Case Study: Debian 12

+ +

Table of Contents

+ +- [Introduction](#introduction) + - [You Said Flist?](#you-said-flist) + - [Case Study Objective](#case-study-objective) + - [The Overall Process](#the-overall-process) +- [Docker Image Creation](#docker-image-creation) + - [Dockerfile](#dockerfile) + - [Docker Image Script](#docker-image-script) + - [zinit Folder](#zinit-folder) + - [README.md File](#readmemd-file) + - [Putting it All Together](#putting-it-all-together) +- [Docker Publishing Steps](#docker-publishing-steps) + - [Create Account and Access Token](#create-account-and-access-token) + - [Build and Push the Docker Image](#build-and-push-the-docker-image) +- [Convert the Docker Image to an Flist](#convert-the-docker-image-to-an-flist) +- [Deploy the Flist on the TF Playground](#deploy-the-flist-on-the-tf-playground) +- [Conclusion](#conclusion) + +*** + +## Introduction + +For this tutorial, we will present a case study demonstrating how easy it is to create a new flist on the ThreeFold ecosystem. We will be creating a Debian Flist and we will deploy a micro VM on the ThreeFold Playground and access our Debian deployment. + +To do all this, we will need to create a Docker Hub account, create a Dockerfile, a docker image and a docker container, then convert the docker image to a Zero-OS flist. After all this, we will be deploying our Debian workload on the ThreeFold Playground. You'll see, it's pretty straightforward and fun to do. + + + +### You Said Flist? + +First, let's recall what an flist actually is and does. In short, an flist is a very effective way to deal with software data and the end result is fast deployment and high reliability. + +In a flist, we separate the metadata from the data. The metadata is a description of what files are in that particular image. It's the data providing information about the app/software. Thanks to flist, the 3Node doesn't need to install a complete software program in order to run properly. Only the necessary files are installed. Zero-OS can read the metadata of a container and only download and execute the necessary binaries and applications to run the workload, when it is necessary. + +Sounds great? It really is great, and very effective! + +One amazing thing about the flist technology is that it is possible to convert any Docker image into an flist, thanks to the [ThreeFold Docker Hub Converter tool](https://hub.grid.tf/docker-convert). If this sounds complicated, fear not. It is very easy and we will show you how to proceed in this case study. + + + +### Case Study Objective + +The goal of this case study is to give you enough information and tools so that you can yourself build your own flist projects and deploy on the ThreeFold Grid. + +This case study is not meant to show you all the detailed steps on creating an flist from scratch. We will instead start with some files templates available on the ThreeFold repository [tf-images](https://github.com/threefoldtech/tf-images). This is one of the many advantages of working with open-source projects: we can easily get inspiration from the already available codes of the many ThreeFold repositories and work our way up from there. + + + +### The Overall Process + +To give you a bird's view of the whole project, here are the main steps: + +* Create the Docker image +* Push the Docker image to the Docker Hub +* Convert the Docker image to a Zero-OS flist +* Deploy a micro VM with the flist on the ThreeFold Playground + + + +## Docker Image Creation + +As we've said previously, we will not explore all the details of creating an flist from scratch. This would be done in a subsequent guide. For now, we want to take existing codes and work our way from there. This is not only quicker, but it is a good way to get to know the ThreeFold's ecosystem and repositories. + +We will be using the code available on the [ThreeFold Tech's Github page](https://github.com/threefoldtech). In our case, we want to explore the repository [tf-images](https://github.com/threefoldtech/tf-images). + +If you go on the subsection [tfgrid3](https://github.com/threefoldtech/tf-images/tree/development/tfgrid3), you can see many different flists available. In our case, we want to deploy the Debian Linux distribution. It is thus logic to try and find similar Linux distributions to take inspiration from. + +For this case study, we draw inspiration from the [Ubuntu 22.04](https://github.com/threefoldtech/tf-images/tree/development/tfgrid3/ubuntu22.04) directory. + +If we look at the Ubuntu 22.04 directory tree, this is what we get: + +``` +. +├── Dockerfile +├── README.md +├── start.sh +└── zinit + ├── ssh-init.yaml + └── sshd.yaml +``` + +We will now explore each of those files to get a good look at the whole repository and try to understand how it all works together. + +### Dockerfile + +We recall that to make a Docker image, you need to create a Dockerfile. As per [Docker's documentation](https://docs.docker.com/engine/reference/builder/), a Dockerfile is "a Dockerfile is a text document that contains all the commands a user could call on the command line to assemble an image". + +The Ubuntu 22.04 Dockerfile is as follows: + +File: `Dockerfile` + +```Dockerfile +FROM ubuntu:22.04 + +RUN apt update && \ + apt -y install wget openssh-server + +RUN wget -O /sbin/zinit https://github.com/threefoldtech/zinit/releases/download/v0.2.5/zinit && \ + chmod +x /sbin/zinit + +COPY zinit /etc/zinit +COPY start.sh /start.sh + +RUN chmod +x /sbin/zinit && chmod +x /start.sh +ENTRYPOINT ["zinit", "init"] +``` + +We can see from the first line that the Dockerfile will look for the docker image `ubuntu:22.04`. In our case, we want to get the Debian 12 docker image. This information is available on the Docker Hub (see [Debian Docker Hub](https://hub.docker.com/_/debian)). + +We will thus need to change the line `FROM ubuntu:22.04` to the line `FROM debian:12`. It isn't more complicated than that! + +We now have the following Dockerfile fore the Debian docker image: + +File: `Dockerfile` + +```Dockerfile +FROM debian:12 + +RUN apt update && \ + apt -y install wget openssh-server + +RUN wget -O /sbin/zinit https://github.com/threefoldtech/zinit/releases/download/v0.2.5/zinit && \ + chmod +x /sbin/zinit + +COPY zinit /etc/zinit +COPY start.sh /start.sh + +RUN chmod +x /sbin/zinit && chmod +x /start.sh +ENTRYPOINT ["zinit", "init"] +``` + +There is nothing more needed here. Pretty fun to start from some existing open-source code, right? + +### Docker Image Script + +The other important file we will be looking at is the `start.sh` file. This is the basic script that will be used to properly set the docker image. Thankfully, there is nothing more to change in this file, we can leave it as is. As we will see later, this file will be executed by zinit when the container starts. + +File: `start.sh` + +```.sh +#!/bin/bash + +mkdir -p /var/run/sshd +mkdir -p /root/.ssh +touch /root/.ssh/authorized_keys + +chmod 700 /root/.ssh +chmod 600 /root/.ssh/authorized_keys + +echo "$SSH_KEY" >> /root/.ssh/authorized_keys +``` + +### zinit Folder + +Next, we want to take a look at the zinit folder. + +But first, what is zinit? In a nutshell, zinit is a process manager (pid 1) that knows how to launch, monitor and sort dependencies. It thus executes targets in the proper order. For more information on zinit, check the [zinit repository](https://github.com/threefoldtech/zinit). + +When we start the Docker container, the files in the folder zinit will be executed. + +If we take a look at the file `ssh-init.yaml`, we find the following: + +```.yaml +exec: bash /start.sh +log: stdout +oneshot: true +```` + +We can see that the first line calls the [bash](https://www.gnu.org/software/bash/) Unix shell and that it will run the file `start.sh` we've seen earlier. + +In this zinit service file, we define a service named `ssh-init.yaml`, where we tell zinit which commands to execute (here `bash /start.sh`), where to log (here in `stdout`) and where `oneshot` is set to `true` (meaning that it should only be executed once). + +If we take a look at the file `sshd.yaml`, we find the following: + +```.yaml +exec: bash -c "/usr/sbin/sshd -D" +after: + - ssh-init +``` + +Here another service `sshd.yaml` runs after the `ssh-init.yaml` process. + +### README.md File + +As every good programmer knows, a good code is nothing without some good documentation to help others understand what's going on! This is where the `README.md` file comes into play. + +In this file, we can explain what our code is doing and offer steps to properly configure the whole deployment. For the users that will want to deploy the flist on the ThreeFold Playground, they would need the FLIst URL and the basic steps to deploy a Micro VM on the TFGrid. We will thus add this information in the README.md file. This information can be seen in the [section below](#deploy-the-flist-on-the-tf-playground). To read the complete README.md file, go to [this link](https://github.com/threefoldtech/tf-images/tree/development/tfgrid3/debian). + +### Putting it All Together + +We've now went through all the files available in the Ubuntu 22.04 directory on the tf-images repository. To build your own image, you would simply need to put all those files in a local folder on your computer and follow the steps presented at the next section, [Docker Publishing Steps](#docker-publishing-steps). + +To have a look at the final result of the changes we bring to the Ubuntu 22.04 version, have a look at this [Debian directory](https://github.com/threefoldtech/tf-images/tree/development/tfgrid3/debian) on the ThreeFold's tf-images repository. + + + +## Docker Publishing Steps + +### Create Account and Access Token + +To be able to push Docker images to the Docker Hub, you obviously need to create a Docker Hub account! This is very easy and please note that there are so many amazing documentation on Docker online. If you're lost, make the most of your favorite search engine and find a way out of the blue. + +Here are the steps to create an account and an access token. + +* Go to the [Docker Hub](https://hub.docker.com/) +* Click `Register` and follow the steps given by Docker +* On the top right corner, click on your account name and select `Account Settings` +* On the left menu, click on `Security` +* Click on `New Access Token` +* Choose an Access Token description that you will easily identify then click `Generate` + * Make sure to set the permissions `Read, Write, Delete` +* Follow the steps given to properly connect your local computer to the Docker Hub + * Run `docker login -u ` + * Set the password + +You now have access to the Docker Hub from your local computer. We will then proceed to push the Docker image we've created. + +### Build and Push the Docker Image + +* Make sure the Docker Daemon is running +* Build the docker container + * Template: + * ``` + docker build -t / . + ``` + * Example: + * ``` + docker build -t username/debian12 . + ``` +* Push the docker container to the [Docker Hub](https://hub.docker.com/) + * Template: + * ``` + docker push / + ``` + * Example: + * ``` + docker push username/debian12 + ``` +* You should now see your docker image on the [Docker Hub](https://hub.docker.com/) when you go into the menu option `My Profile`. + * Note that you can access this link quickly with the following template: + * ``` + https://hub.docker.com/u/ + ``` + + + +## Convert the Docker Image to an Flist + +We will now convert the Docker image into a Zero-OS flist. This part is so easy you will almost be wondering why you never heard about flist before! + +* Go to the [ThreeFold Hub](https://hub.grid.tf/). +* Sign in with the ThreeFold Connect app. +* Go to the [Docker Hub Converter](https://hub.grid.tf/docker-convert) section. +* Next to `Docker Image Name`, add the docker image repository and name, see the example below: + * Template: + * `/docker_image_name:tagname` + * Example: + * `username/debian12:latest` +* Click `Convert the docker image`. +* Once the conversion is done, the flist is available as a public link on the ThreeFold Hub. +* To get the flist URL, go to the [TF Hub main page](https://hub.grid.tf/), scroll down to your 3Bot ID and click on it. +* Under `Name`, you will see all your available flists. +* Right-click on the flist you want and select `Copy Clean Link`. This URL will be used when deploying on the ThreeFold Playground. We show below the template and an example of what the flist URL looks like. + * Template: + * ``` + https://hub.grid.tf/<3BOT_name.3bot>/--.flist + ``` + * Example: + * ``` + https://hub.grid.tf/idrnd.3bot/username-debian12-latest.flist + ``` + + + +## Deploy the Flist on the TF Playground + +* Go to the [ThreeFold Playground](https://play.grid.tf). +* Set your profile manager. +* Go to the [Micro VM](https://play.grid.tf/#/vm) page. +* Choose your parameters (name, VM specs, etc.). +* Under `flist`, paste the Debian flist from the TF Hub you copied previously. +* Make sure the entrypoint is as follows: + * ``` + /sbin/zinit init + ``` +* Choose a 3Node to deploy on +* Click `Deploy` + +That's it! You can now SSH into your Debian deployment and change the world one line of code at a time! + +* + +## Conclusion + +In this case study, we've seen the overall process of creating a new flist to deploy a Debian workload on a Micro VM on the ThreeFold Playground. + +If you have any questions or feedback, please let us know by either writing a post on the [ThreeFold Forum](https://forum.threefold.io/), or by chatting with us on the [TF Grid Tester Community](https://t.me/threefoldtesting) Telegram channel. diff --git a/collections/manual/documentation/developers/flist/flist_case_studies/flist_nextcloud_case_study.md b/collections/manual/documentation/developers/flist/flist_case_studies/flist_nextcloud_case_study.md new file mode 100644 index 0000000..4193317 --- /dev/null +++ b/collections/manual/documentation/developers/flist/flist_case_studies/flist_nextcloud_case_study.md @@ -0,0 +1,858 @@ +

Flist Case Study: Nextcloud All-in-One

+ +

Table of Contents

+ +- [Introduction](#introduction) + - [Flist: What is It?](#flist-what-is-it) + - [Case Study Objective](#case-study-objective) + - [The Overall Process](#the-overall-process) +- [Docker Image Creation](#docker-image-creation) + - [Nextcloud Flist Directory Tree](#nextcloud-flist-directory-tree) + - [Caddyfile](#caddyfile) + - [Dockerfile](#dockerfile) + - [README.md File](#readmemd-file) + - [scripts Folder](#scripts-folder) + - [caddy.sh](#caddysh) + - [sshd\_init.sh](#sshd_initsh) + - [ufw\_init.sh](#ufw_initsh) + - [nextcloud.sh](#nextcloudsh) + - [nextcloud\_conf.sh](#nextcloud_confsh) + - [zinit Folder](#zinit-folder) + - [ssh-init.yaml and sshd.yaml](#ssh-inityaml-and-sshdyaml) + - [ufw-init.yaml and ufw.yaml](#ufw-inityaml-and-ufwyaml) + - [caddy.yaml](#caddyyaml) + - [dockerd.yaml](#dockerdyaml) + - [nextcloud.yaml](#nextcloudyaml) + - [nextcloud-conf.yaml](#nextcloud-confyaml) + - [Putting it All Together](#putting-it-all-together) +- [Docker Publishing Steps](#docker-publishing-steps) + - [Create Account and Access Token](#create-account-and-access-token) + - [Build and Push the Docker Image](#build-and-push-the-docker-image) +- [Convert the Docker Image to an Flist](#convert-the-docker-image-to-an-flist) +- [Deploy Nextcloud AIO on the TFGrid with Terraform](#deploy-nextcloud-aio-on-the-tfgrid-with-terraform) + - [Create the Terraform Files](#create-the-terraform-files) + - [Deploy Nextcloud with Terraform](#deploy-nextcloud-with-terraform) + - [Nextcloud Setup](#nextcloud-setup) +- [Conclusion](#conclusion) + +*** + +# Introduction + +In this case study, we explain how to create a new flist on the ThreeFold ecosystem. We will show the process of creating a Nextcloud All-in-One flist and we will deploy a micro VM on the ThreeFold Playground to access our Nextcloud instance. As a reference, the official Nextcloud flist is available [here](https://hub.grid.tf/tf-official-apps/threefoldtech-nextcloudaio-latest.flist.md). + +To achieve all this, we will need to create a Docker Hub account, create a Dockerfile and its associated files, a docker image and a docker container, then convert the docker image to a Zero-OS flist. After all this, we will be deploying our Nextcloud instance on the ThreeFold Playground. + +As a general advice, before creating an flist for a ThreeFold deployment, you should make sure that you are able to deploy your workload properly by using a micro VM or a full VM on the TFGrid. Once you know all the steps to deploy your workload, and after some thorough tests, you can take what you've learned and incorporate all this into an flist. + +## Flist: What is It? + +Before we go any further, let us recall what is an flist. In short, an flist is a technology for storing and efficiently sharing sets of files. While it has many great features, it's purpose in this case is simply to deliver the image contents to Zero-OS for execution as a micro VM. It thus acts as a bundle of files like a normal archive. + +One convenient thing about the flist technology is that it is possible to convert any Docker image into an flist, thanks to the [ThreeFold Docker Hub Converter tool](https://hub.grid.tf/docker-convert). It is very easy to do and we will show you how to proceed in this case study. For a quick guide on converting Docker images into flists, read [this section](../flist_hub/convert_docker_image.md) of the ThreeFold Manual. + +## Case Study Objective + +The goal of this case study is to give you enough information and tools so that you can build your own flist projects and deploy on the ThreeFold Grid. + +We will explore the different files needed to create the flist and explain the overall process. Instead of starting from scratch, we will analyze the Nextcloud flist directory in the [tf-images](https://github.com/threefoldtech/tf-images/tree/development/tfgrid3/nextcloud) ThreeFold Tech repository. As the project is already done, it will be easier to get an overview of the process and the different components so you can learn to create your own. + +## The Overall Process + +To give you a bird's-eye view of the whole project, here are the main steps: + +* Create the Docker image +* Push the Docker image to the Docker Hub +* Convert the Docker image to a Zero-OS flist +* Deploy a micro VM with the flist on the ThreeFold Playground with Terraform + +One important thing to have in mind is that, when we create an flist, what we are doing is basically automating the required steps to deploy a given workload on the TFGrid. Usually, these steps would be done manually and step-by-step by an individual deploying on a micro or a full VM. + +Once we've successfully created an flist, we thus have a very quick way to deploy a specific workload while always obtaining the same result. This is why it is highly recommended to test a given deployment on a full or micro VM before building an flist. + +For example, in the case of building a Nextcloud All-in-One flist, the prerequisites would be to successfully deploy a Nextcloud AIO instance on a full VM by executing each step sequentially. This specific example is documented in the Terraform section [Nextcloud All-in-One Guide](../../../system_administrators/terraform/advanced/terraform_nextcloud_aio.md) of the System Administrators book. + +In our case, the flist we will be using has some specific configurations depending on the way we deploy Nextcloud (e.g. using or not the gateway and a custom domain). The Terraform **main.tf** we will be sharing later on will thus take all this into account for a smooth deployment. + +# Docker Image Creation + +As we've said previously, we will explore the different components of the existing Nextcloud flist directory. We thus want to check the existing files and try to understand as much as possible how the different components work together. This is also a very good introduction to the ThreeFold ecosystem. + +We will be using the files available on the [ThreeFold Tech Github page](https://github.com/threefoldtech). In our case, we want to explore the repository [tf-images](https://github.com/threefoldtech/tf-images). + +If you go in the subsection [tfgrid3](https://github.com/threefoldtech/tf-images/tree/development/tfgrid3), you can see many different flists available. In our case, we want to deploy the [Nextcloud All-in-One Flist](https://github.com/threefoldtech/tf-images/tree/development/tfgrid3/nextcloud). + +## Nextcloud Flist Directory Tree + +The Nextcloud flist directory tree is the following: + +``` +tree tf-images/tfgrid3/nextcloud +. +├── Caddyfile +├── Dockerfile +├── README.md +├── scripts +│ ├── caddy.sh +│ ├── nextcloud_conf.sh +│ ├── nextcloud.sh +│ ├── sshd_init.sh +│ └── ufw_init.sh +└── zinit + ├── caddy.yaml + ├── dockerd.yaml + ├── nextcloud-conf.yaml + ├── nextcloud.yaml + ├── sshd.yaml + ├── ssh-init.yaml + ├── ufw-init.yaml + └── ufw.yaml +``` + +We can see that the directory is composed of a Caddyfile, a Dockerfile, a README.md and two directories, **scripts** and **zinit**. We will now explore each of those components to have a good grasp of the whole repository and to understand how it all works together. + +To get a big picture of this directory, we could say that the **README.md** file provides the necessary documentation for the users to understand the Nextcloud flist, how it is built and how it works, the **Caddyfile** provides the necessary requirements to run the reverse proxy, the **Dockerfile** specifies how the Docker image is built, installing things such as [openssh](https://www.openssh.com/) and the [ufw firewall](https://wiki.ubuntu.com/UncomplicatedFirewall) for secure remote connection, while the two folders, **scripts** and **zinit**, could be said to work hand-in-hand. + +Each `.yaml` file is a *unit file* for zinit. That means it specifies a single service for zinit to start. We'll learn more about these files later, but for now we can just note that each script file (ending with `.sh`) has an associated zinit file to make sure that the script is run. There are also some other files for running programs aside from our scripts. + +## Caddyfile + +For our Nextcloud deployment, we are using Caddy as a reverse proxy. A reverse proxy is an application that sits in front of back-end applications and forwards client requests to those applications. + +Since Nextcloud AIO actually includes two web applications, both Nextcloud itself and the AIO management interface, we use the reverse proxy to serve them both on a single domain. It also allows us to make some changes on the fly to the content of the AIO site to considerably enhance the user experience. Finally, we also use Caddy to provide SSL termination if the user reserves a public IP and no gateway, since otherwise SSL termination is provided by the gateway. + +File: `Caddyfile` +``` +{ + order replace after encode + servers { + trusted_proxies static 100.64.0.0/10 10.0.0.0/8 + } +} + + +{$DOMAIN}:{$PORT} { + handle_path /aio* { + replace { + href="/ href="/aio/ + src="/ src="/aio/ + action=" action="/aio + url(' url('/aio + `value="" placeholder="nextcloud.yourdomain.com"` `value="{$DOMAIN}"` + `"Submit domain"` `"Submit domain" id="domain-submit"` + {$REPLACEMENTS} + {$BODY} + } + + reverse_proxy localhost:8000 { + header_down Location "^/(.*)$" "/aio/$1" + header_down Refresh "^/(.*)$" "/aio/$1" + } + + } + + redir /api/auth/getlogin /aio{uri} + + reverse_proxy localhost:11000 + + handle_errors { + @502-aio expression {err.status_code} == 502 && path('/aio*') + handle @502-aio { + header Content-Type text/html + respond < + Nextcloud + Your Nextcloud management interface isn't ready. If you just deployed this instance, please wait a minute and refresh the page. + + HTML 200 + } + + @502 expression {err.status_code} == 502 + handle @502 { + redir /* /aio + } + } +} +``` + +We can see in the first section (`trusted_proxies static`) that we set a range of IP addresses as trusted proxy addresses. These include the possible source addresses for gateway traffic, which we mark as trusted for compatibility with some Nextcloud features. + +After the global config at the top, the line `{$DOMAIN}:{$PORT}` defines the port that Caddy will listen to and the domain that we are using for our site. This is important, because in the case that port `443` is specified, Caddy will handle SSL certificates automatically. + +The following blocks define behavior for different URL paths that users might try to access. + +To begin, we have `/aio*`. This is how we place the AIO management app in a "subfolder" of our main domain. To accomplish that we need a few rules that rewrite the contents of the returned pages to correct the links. We also add some text replacements here to accomplish the enhancements mentioned earlier, like automatically filling the domain entry field. + +With the `reverse_proxy` line, we specify that requests to all URLs starting with `/aio` should be sent to the web server running on port `8000` of `localhost`. That's the port where the AIO server is listening, as we'll see below. There's also a couple of header rewrite rules here that correct the links for any redirects the AIO site makes. + +The `redir` line is needed to support a feature where users open the AIO interface from within Nextcloud. This redirects the original request to the correct equivalent within the `/aio` "subfolder". + +Then there's a second `reverse_proxy` line, which is the catch-all for any traffic that didn't get intercepted earlier. This handles the actual Nextcloud app and sends the traffic to its separate server running on port `11000`. + +The section starting with `handle_errors` ensures that the user will receive an understandable error message when trying to access the Nextcloud deployment before it has fully started up. + +## Dockerfile + +We recall that to make a Docker image, you need to create a Dockerfile. As per the [Docker documentation](https://docs.docker.com/engine/reference/builder/), a Dockerfile is "a text document that contains all the commands a user could call on the command line to assemble an image". + +File: `Dockerfile` + +```Dockerfile +FROM ubuntu:22.04 + +RUN apt update && \ + apt -y install wget openssh-server curl sudo ufw inotify-tools iproute2 + +RUN wget -O /sbin/zinit https://github.com/threefoldtech/zinit/releases/download/v0.2.5/zinit && \ + chmod +x /sbin/zinit + +RUN wget -O /sbin/caddy 'https://caddyserver.com/api/download?os=linux&arch=amd64&p=github.com%2Fcaddyserver%2Freplace-response&idempotency=43631173212363' && \ + chmod +x /sbin/caddy + +RUN curl -fsSL https://get.docker.com -o /usr/local/bin/install-docker.sh && \ + chmod +x /usr/local/bin/install-docker.sh + +RUN sh /usr/local/bin/install-docker.sh + +COPY ./Caddyfile /etc/caddy/ +COPY ./scripts/ /scripts/ +COPY ./zinit/ /etc/zinit/ +RUN chmod +x /scripts/*.sh + +ENTRYPOINT ["/sbin/zinit", "init"] +``` + +We can see from the first line that this Dockerfile uses a base image of Ubuntu Linux version 22.04. + +With the first **RUN** command, we refresh the package lists, and then install **openssh**, **ufw** and other dependencies for our Nextcloud uses. Note that we also install **curl** so that we can quickly install **Docker**. + +With the second **RUN** command, we install **zinit** and we give it execution permission with the command `chmod +x`. More will be said about zinit in a section below. + +With the third **RUN** command, we install **caddy** and we give it execution permission with the command `chmod +x`. Caddy is an extensible, cross-platform, open-source web server written in Go. For more information on Caddy, check the [Caddy website](https://caddyserver.com/). + +With fourth **RUN** command, we download and give proper permissions to the script `install-docker.sh`. On a terminal, the common line to install Docker would be `curl -fsSL https://get.docker.com | sudo sh`. To understand really what's going here, we can simply go to the link provided at the line [https://get.docker.com](https://get.docker.com) for more information. + +The fifth **RUN** command runs the `install-docker.sh` script to properly install Docker within the image. + +Once those commands are run, we proceed to copy into our Docker image the necessary folders `scripts` and `zinit` as well as the Caddyfile. Once this is done, we give execution permissions to all scripts in the scripts folder using `chmod +x`. + +Finally, we set an entrypoint in our Dockerfile. As per the [Docker documentation](https://docs.docker.com/engine/reference/builder/), an entrypoint "allows you to configure a container that will run as an executable". Since we are using zinit, we set the entrypoint `/sbin/zinit`. + +## README.md File + +The **README.md** file has the main goal of explaining clearly to the user the functioning of the Nextcloud directory and its associated flist. In this file, we can explain what our code is doing and offer steps to properly configure the whole deployment. + +We also give the necessary steps to create the Docker image and convert it into an flist starting directly with the Nextcloud directory. This can be useful for users that want to create their own flist, instead of using the [official ThreeFold Nextcloud flist](https://hub.grid.tf/tf-official-apps/threefoldtech-nextcloudaio-latest.flist.md). + +To read the complete README.md file, go to [this link](https://github.com/threefoldtech/tf-images/blob/development/tfgrid3/nextcloud/README.md). + +## scripts Folder + +The **scripts** folder contains without surprise the scripts necessary to run the Nextcloud instance. + +In the Nextcloud Flist case, there are five scripts: + +* **caddy.sh** +* **nextcloud.sh** +* **nextcloud_conf.sh** +* **sshd_init.sh** +* **ufw_init.sh** + +Let's take a look at each of them. + +### caddy.sh + +File: `caddy.sh` + +```bash +#!/bin/bash +export DOMAIN=$NEXTCLOUD_DOMAIN + +if $IPV4 && ! $GATEWAY; then + export PORT=443 +else + export PORT=80 +fi + +if $IPV4; then + export BODY="\`\`" + +else + export BODY="\`\`" + + export REPLACEMENTS=' `name="talk"` `name="talk" disabled` + `needs ports 3478/TCP and 3478/UDP open/forwarded in your firewall/router` `running the Talk container requires a public IP and this VM does not have one. It is still possible to use Talk in a limited capacity. Please consult the documentation for details`' +fi + +caddy run --config /etc/caddy/Caddyfile +``` + +The script **caddy.sh** sets the proper port depending on the network configuration (e.g. IPv4 or Gateway) in the first if/else section. In the second if/else section, the script also makes sure that the proper domain is given to Nextcloud All-in-One. This quickens the installation process as the user doesn't have to set the domain in Nextcloud AIO after deployment. We also disable a feature that's not relevant if the user didn't reserve an IPv4 address and we insert a note about that. + +### sshd_init.sh + +File: `sshd_init.sh` + +```bash +#!/bin/bash + +mkdir -p ~/.ssh +mkdir -p /var/run/sshd +chmod 600 ~/.ssh +chmod 600 /etc/ssh/* +echo $SSH_KEY >> ~/.ssh/authorized_keys +``` + +This file starts with a shebang (`#!`) that instructs the operating system to execute the following lines using the [Bash shell](https://www.gnu.org/software/bash/). In essence, it lets us write `./sshd_init.sh` with the same outcome as `bash ./sshd_init.sh`, assuming the file is executable. + +The goal of this script is to add the public key within the VM in order for the user to get a secure and remote connection to the VM. The two lines starting with `mkdir` create the necessary folders. The lines starting with `chmod` give the owner the permission to write and read the content within the folders. Finally, the line `echo` will write the public SSH key in a file within the VM. In the case that the flist is used as a weblet, the SSH key is set in the Playground profile manager and passed as an environment variable when we deploy the solution. + +### ufw_init.sh + +File: `ufw_init.sh` + +```bash +#!/bin/bash + +ufw default deny incoming +ufw default allow outgoing +ufw allow ssh +ufw allow http +ufw allow https +ufw allow 8443 +ufw allow 3478 +ufw limit ssh +``` + +The goal of the `ufw_init.sh` script is to set the correct firewall parameters to make sure that our deployment is secure while also providing the necessary access for the Nextcloud users. + +The first two lines starting with `ufw default` are self-explanatory. We want to restrain incoming traffic while making sure that outgoing traffic has no restraints. + +The lines starting with `ufw allow` open the ports necessary for our Nextcloud instance. We note that **ssh** is port 22, **http** is port 80 and **https** is port 443. This means, for example, that the line `ufw allow 22` is equivalent to the line `ufw allow ssh`. + +Port 8443 can be used to access the AIO interface, as an alternative to using the `/aio` "subfolder" on deployments with a public IPv4 address. Finally, the port 3478 is used for Nextcloud Talk. + +The line `ufw limit ssh` will provide additional security by denying connection from IP addresses that attempt to initiate 6 or more connections within a 30-second period. + +### nextcloud.sh + +File: `nextcloud.sh` + +```bash +#!/bin/bash + +export COMPOSE_HTTP_TIMEOUT=800 +while ! docker info > /dev/null 2>&1; do + echo docker not ready + sleep 2 +done + +docker run \ +--init \ +--sig-proxy=false \ +--name nextcloud-aio-mastercontainer \ +--restart always \ +--publish 8000:8000 \ +--publish 8080:8080 \ +--env APACHE_PORT=11000 \ +--env APACHE_IP_BINDING=0.0.0.0 \ +--env SKIP_DOMAIN_VALIDATION=true \ +--volume nextcloud_aio_mastercontainer:/mnt/docker-aio-config \ +--volume /var/run/docker.sock:/var/run/docker.sock:ro \ +nextcloud/all-in-one:latest +``` + +The **nextcloud.sh** script is where the real action starts. This is where we run the Nextcloud All-in-One docker image. + +Before discussing the main part of this script, we note that the `while` loop is used to ensure that the `docker run` command starts only after the Docker daemon has properly started. + +The code section starting with `docker run` is taken from the [Nextcloud All-in-One repository on Github](https://github.com/nextcloud/all-in-one) with some slight modifications. The last line indicates that the Docker image being pulled will always be the latest version of Nextcloud All-in-One. + +We note here that Nextcloud AIO is published on the port 8000 and 8080. We also note that we set restart to **always**. This is very important as it will make sure that the Nextcloud instance is restarted if the Docker daemon reboots. We take the opportunity to note that the way zinit configures micro VMs, the Docker daemon restarts automatically after a reboot. Thus, this latter fact combined with the line `--restart always` ensures that the user that the Nextcloud instance will restart after a VM reboot. + +We also set **11000** as the Apache port with an IP binding of **0.0.0.0**. For our deployment, we want to skip the domain validation, thus it is set to **true**. + +Considering the line `--sig-proxy=false`, when this command is run interactively, it prevents the user from accidentally killing the spawned AIO container. While it is not of great importance in our case, it means that zinit will not kill the container if the service is stopped. + +For more information on this, we invite the readers to consult the [Nextcloud documentation](https://github.com/nextcloud/all-in-one#how-to-use-this). + +### nextcloud_conf.sh + +File: `nextcloud_conf.sh` + +```bash +#!/bin/bash + +# Wait for the nextcloud container to become healthy. Note that we can set the +# richtext config parameters even before the app is installed + +nc_ready () { + until [[ "`docker inspect -f {{.State.Health.Status}} nextcloud-aio-nextcloud 2> /dev/null`" == "healthy" ]]; do + sleep 1; + done; +} + +# When a gateway is used, AIO sets the WOPI allow list to only include the +# gateway IP. Since requests don't originate from the gateway IP, they are +# blocked by default. Here we add the public IP of the VM, or of the router +# upstream of the node +# See: github.com/nextcloud/security-advisories/security/advisories/GHSA-24x8-h6m2-9jf2 + +if $IPV4; then + interface=$(ip route show default | cut -d " " -f 5) + ipv4_address=$(ip a show $interface | grep -Po 'inet \K[\d.]+') +fi + +if $GATEWAY; then + nc_ready + wopi_list=$(docker exec --user www-data nextcloud-aio-nextcloud php occ config:app:get richdocuments wopi_allowlist) + + if $IPV4; then + ip=$ipv4_address + else + ip=$(curl -fs https://ipinfo.io/ip) + fi + + if [[ $ip ]] && ! echo $wopi_list | grep -q $ip; then + docker exec --user www-data nextcloud-aio-nextcloud php occ config:app:set richdocuments wopi_allowlist --value=$ip + fi +fi + + +# If the VM has a gateway and a public IPv4, then AIO will set the STUN/TURN +# servers to the gateway domain which does not point to the public IP, so we +# use the IP instead. In this case, we must wait for the Talk app to be +# installed before changing the settings. With inotifywait, we don't need +# a busy loop that could run indefinitely + +apps_dir=/mnt/data/docker/volumes/nextcloud_aio_nextcloud/_data/custom_apps/ + +if $GATEWAY && $IPV4; then + if [[ ! -d ${apps_dir}spreed ]]; then + inotifywait -qq -e create --include spreed $apps_dir + fi + nc_ready + + turn_list=$(docker exec --user www-data nextcloud-aio-nextcloud php occ talk:turn:list) + turn_secret=$(echo "$turn_list" | grep secret | cut -d " " -f 4) + turn_server=$(echo "$turn_list" | grep server | cut -d " " -f 4) + + if ! echo $turn_server | grep -q $ipv4_address; then + docker exec --user www-data nextcloud-aio-nextcloud php occ talk:turn:delete turn $turn_server udp,tcp + docker exec --user www-data nextcloud-aio-nextcloud php occ talk:turn:add turn $ipv4_address:3478 udp,tcp --secret=$turn_secret + fi + + stun_list=$(docker exec --user www-data nextcloud-aio-nextcloud php occ talk:stun:list) + stun_server=$(echo $stun_list | cut -d " " -f 2) + + if ! echo $stun_server | grep -q $ipv4_address; then + docker exec --user www-data nextcloud-aio-nextcloud php occ talk:stun:add $ipv4_address:3478 + docker exec --user www-data nextcloud-aio-nextcloud php occ talk:stun:delete $stun_server + fi +fi +``` + +The script **nextcloud_conf.sh** ensures that the network settings are properly configured. In the first section, we use a function called **nc_ready ()**. This function will makes sure that the rest of the script only starts when the Nextcloud container is healthy. + +We note that the comments present in this script explain very well what is happening. In short, we want to set the Nextcloud instance according to the user's choice of network. For example, the user can decide to deploy using a ThreeFold gateway or a standard IPv4 connection. If the VM has a gateway and a public IPv4, then Nextcloud All-in-One will set the STUN/TURN servers to the gateway domain which does not point to the public IP, so we use the IP instead. + +## zinit Folder + +Next, we want to take a look at the zinit folder. + +But first, what is zinit? In a nutshell, zinit is a process manager (pid 1) that knows how to launch, monitor and sort dependencies. It thus executes targets in the proper order. For more information on zinit, check the [zinit repository](https://github.com/threefoldtech/zinit). + +When we start the Docker container, zinit will parse each unit file in the `/etc/zinit` folder and execute the contained command according to the specified parameters. + +In the Nextcloud Flist case, there are eight **.yaml** files: + +* **caddy.yaml** +* **dockerd.yaml** +* **nextcloud-conf.yaml** +* **nextcloud.yaml** +* **ssh-init.yaml** +* **sshd.yaml** +* **ufw-init.yaml** +* **ufw.yaml** + + +### ssh-init.yaml and sshd.yaml + +We start by taking a look at the **ssh-init.yaml** and **sshd.yaml** files. + +File: `ssh-init.yaml` + +```yaml +exec: /scripts/sshd_init.sh +oneshot: true +``` + +In this zinit service file, we define a service named `ssh-init.yaml`, where we tell zinit to execute the following command: `exec: /scripts/sshd_init.sh`. This unit file thus runs the script `sshd_init.sh` we covered in a previous section. + +We also note that `oneshot` is set to `true` and this means that it should only be executed once. This directive is often used for setup scripts that only need to run once. When it is not specified, the default value of `false` means that zinit will continue to start up a service if it ever dies. + +Now, we take a look at the file `sshd.yaml`: + +File: `sshd.yaml` + +```yaml +exec: bash -c "/usr/sbin/sshd -D" +after: + - ssh-init +``` + +We can see that this file executes a line from the Bash shell. It is important to note that, with zinit and .yaml files, you can easily order the executions of the files with the `after` directive. In this case, it means that the service `sshd` will only run after `ssh-init`. + +### ufw-init.yaml and ufw.yaml + +Let's take a look at the files **ufw-init.yaml** and **ufw.yaml**. + +File: `ufw-init.yaml` + +```yaml +exec: /scripts/ufw_init.sh +oneshot: true +``` + +The file `ufw-init.yaml` is very similar to the previous file `ssh-init.yaml`. + +File: `ufw.yaml` + +```yaml +exec: ufw --force enable +oneshot: true +after: + - ufw-init +``` + +We can see that the file `ufw.yaml` will only run once and only after the file `ufw-init.yaml` has been run. This is important since the file `ufw-init.yaml` executes the script `ufw_init.sh`. We recall this script allows different ports in the firewall. Once those ports are defined, we can then run the command `ufw --force enable`. This will start the ufw firewall. + +### caddy.yaml + +```yaml +exec: /scripts/caddy.sh +oneshot: true +``` + +This is also very similar to previous files and just runs the Caddy script as a oneshot. + +### dockerd.yaml + +We now take a look at the file **dockerd.yaml**. + +File: `dockerd.yaml` + +```yaml +exec: /usr/bin/dockerd --data-root /mnt/data/docker +``` + +This file will run the [dockerd daemon](https://docs.docker.com/engine/reference/commandline/dockerd/) which is the persistent process that manages containers. We also note that it sets the data to be stored in the directory **/mnt/data/docker**, which is important because we will mount a virtual disk there that will provide better performance, especially for Docker's storage driver. + +### nextcloud.yaml + +File: `nextcloud.yaml` + +```yaml +exec: /scripts/nextcloud.sh +after: + - dockerd +``` + +The file `nextcloud.yaml` runs after dockerd. + +This file will execute the `nextcloud.sh` script we saw earlier. We recall that this script starts the Nextcloud All-in-One image. + +### nextcloud-conf.yaml + +File: `nextcloud-conf.yaml` + +```yaml +exec: /scripts/nextcloud_conf.sh +oneshot: true +after: + - nextcloud +``` + +Finally, the file `nextcloud-conf.yaml` runs after `nextcloud.yaml`. + +This file will execute the `nextcloud-conf.sh` script we saw earlier. We recall that this script starts the Nextcloud All-in-One image. At this point, the deployment is complete. + +## Putting it All Together + +We've now gone through all the files in the Nextcloud flist directory. You should now have a proper understanding of the interplay between the zinit (.yaml) and the scripts (.sh) files as well as the basic steps to build a Dockerfile and to write clear documentation. + +To build your own Nextcloud docker image, you would simply need to clone this directory to your local computer and to follow the steps presented in the next section [Docker Publishing Steps](#docker-publishing-steps). + +To have a look at the complete directory, you can always refer to the [Nextcloud flist directory](https://github.com/threefoldtech/tf-images/tree/development/tfgrid3/nextcloud) on the ThreeFold tf-images repository. + +# Docker Publishing Steps + +In this section, we show the necessary steps to publish the Docker image to the Docker Hub. + +To do so, we need to create an account and an access token. Then we will build the Docker image and push it to the Docker Hub. + +## Create Account and Access Token + +To be able to push Docker images to the Docker Hub, you obviously need to create a Docker Hub account! This is very easy and note that there are many great tutorials online about Docker. + +Here are the steps to create an account and an access token: + +* Go to the [Docker Hub](https://hub.docker.com/) +* Click `Register` and follow the steps given by Docker +* On the top right corner, click on your account name and select `Account Settings` +* On the left menu, click on `Security` +* Click on `New Access Token` +* Choose an Access Token description that you will easily identify then click `Generate` + * Make sure to set the permissions `Read, Write, Delete` +* On your local computer, make sure that the Docker daemon is running +* Write the following in the command line to connect to the Docker hub: + * Run `docker login -u ` + * Set the password + +You now have access to the Docker Hub from your local computer. We will then proceed to push the Docker image to the Docker Hub. + +## Build and Push the Docker Image + +* Make sure the Docker Daemon is running +* Build the docker container (note that, while the tag is optional, it can help to track different versions) + * Template: + * ``` + docker build -t /: . + ``` + * Example: + * ``` + docker build -t dockerhubuser/nextcloudaio . + ``` +* Push the docker container to the [Docker Hub](https://hub.docker.com/) + * Template: + * ``` + docker push / + ``` + * Example: + * ``` + docker push dockerhubuser/nextcloudaio + ``` +* You should now see your docker image on the [Docker Hub](https://hub.docker.com/) when you go into the menu option `My Profile`. + * Note that you can access this link quickly with the following template: + * ``` + https://hub.docker.com/u/ + ``` + +# Convert the Docker Image to an Flist + +We will now convert the Docker image into a Zero-OS flist. + +* Go to the [ThreeFold Hub](https://hub.grid.tf/). +* Sign in with the ThreeFold Connect app. +* Go to the [Docker Hub Converter](https://hub.grid.tf/docker-convert) section. +* Next to `Docker Image Name`, add the docker image repository and name, see the example below: + * Template: + * `/docker_image_name:tagname` + * Example: + * `dockerhubuser/nextcloudaio:latest` +* Click `Convert the docker image`. +* Once the conversion is done, the flist is available as a public link on the ThreeFold Hub. +* To get the flist URL, go to the [TF Hub main page](https://hub.grid.tf/), scroll down to your 3Bot ID and click on it. +* Under `Name`, you will see all your available flists. +* Right-click on the flist you want and select `Copy Clean Link`. This URL will be used when deploying on the ThreeFold Playground. We show below the template and an example of what the flist URL looks like. + * Template: + * ``` + https://hub.grid.tf/<3BOT_name.3bot>/--.flist + ``` + * Example: + * ``` + https://hub.grid.tf/tf-official-apps/threefoldtech-nextcloudaio-latest.flist + ``` + +# Deploy Nextcloud AIO on the TFGrid with Terraform + +We now proceed to deploy a Nextcloud All-in-One instance by using the Nextcloud flist we've just created. + +To do so, we will deploy a micro VM with the Nextcloud flist on the TFGrid using Terraform. + +## Create the Terraform Files + +For this guide, we use two files to deploy with Terraform. The first file contains the environment variables and the second file contains the parameters to deploy our workloads. + +To facilitate the deployment, only the environment variables file needs to be adjusted. The **main.tf** file contains the environment variables (e.g. **var.size** for the disk size) and thus you do not need to change this file. Of course, you can adjust the deployment based on your preferences. That being said, it should be easy to deploy the Terraform deployment with the main.tf as is. + +For this example, we will be deployment with a ThreeFold gateway as well as a gateway domain. + +* Copy the following content and save the file under the name `credentials.auto.tfvars`: + +``` +mnemonics = "..." +network = "main" +SSH_KEY = "..." + +size = "50" +cpu = "2" +memory = "4096" + +gateway_id = "50" +vm1_id = "5453" + +deployment_name = "nextcloudgateway" +nextcloud_flist = "https://hub.grid.tf/tf-official-apps/threefoldtech-nextcloudaio-latest.flist" +``` + +Make sure to add your own seed phrase and SSH public key. Simply replace the three dots by the content. Note that you can deploy on a different node than node 5453 for the **vm1** node. If you want to deploy on another node than node 5453 for the **gateway** node, make sure that you choose a gateway node. To find a gateway node, go on the [ThreeFold Dashboard](https://dashboard.grid.tf/) Nodes section of the Explorer and select **Gateways (Only)**. + +Obviously, you can decide to increase or modify the quantity in the variables `size`, `cpu` and `memory`. + +Note that in our case, we set the flist to be the official Nextcloud flist. Simply replace the URL with your newly created Nextcloud flist to test it! + +* Copy the following content and save the file under the name `main.tf`: + +``` +variable "mnemonics" { + type = string + default = "your mnemonics" +} + +variable "network" { + type = string + default = "main" +} + +variable "SSH_KEY" { + type = string + default = "your SSH pub key" +} + +variable "deployment_name" { + type = string +} + +variable "size" { + type = string +} + +variable "cpu" { + type = string +} + +variable "memory" { + type = string +} + +variable "nextcloud_flist" { + type = string +} + +variable "gateway_id" { + type = string +} + +variable "vm1_id" { + type = string +} + + +terraform { + required_providers { + grid = { + source = "threefoldtech/grid" + } + } +} + +provider "grid" { + mnemonics = var.mnemonics + network = var.network +} + +data "grid_gateway_domain" "domain" { + node = var.gateway_id + name = var.deployment_name +} + +resource "grid_network" "net" { + nodes = [var.gateway_id, var.vm1_id] + ip_range = "10.1.0.0/16" + name = "network" + description = "My network" + add_wg_access = true +} + +resource "grid_deployment" "d1" { + node = var.vm1_id + network_name = grid_network.net.name + + disks { + name = "data" + size = var.size + } + + vms { + name = "vm1" + flist = var.nextcloud_flist + cpu = var.cpu + memory = var.memory + rootfs_size = 15000 + entrypoint = "/sbin/zinit init" + env_vars = { + SSH_KEY = var.SSH_KEY + GATEWAY = "true" + IPV4 = "false" + NEXTCLOUD_DOMAIN = data.grid_gateway_domain.domain.fqdn + } + mounts { + disk_name = "data" + mount_point = "/mnt/data" + } + } +} + +resource "grid_name_proxy" "p1" { + node = var.gateway_id + name = data.grid_gateway_domain.domain.name + backends = [format("http://%s:80", grid_deployment.d1.vms[0].ip)] + network = grid_network.net.name + tls_passthrough = false +} + +output "wg_config" { + value = grid_network.net.access_wg_config +} + +output "vm1_ip" { + value = grid_deployment.d1.vms[0].ip +} +output "vm1_ygg_ip" { + value = grid_deployment.d1.vms[0].ygg_ip +} + +output "fqdn" { + value = data.grid_gateway_domain.domain.fqdn +} +``` + +## Deploy Nextcloud with Terraform + +We now deploy Nextcloud with Terraform. Make sure that you are in the correct folder containing the main and variables files. + +* Initialize Terraform: + * ``` + terraform init + ``` + +* Apply Terraform to deploy Nextcloud: + * ``` + terraform apply + ``` + +Note that, at any moment, if you want to see the information on your Terraform deployment, write the following: + * ``` + terraform show + ``` + +## Nextcloud Setup + +Once you've deployed Nextcloud, you can access the Nextcloud setup page by pasting the URL displayed on the line `fqdn = "..."` of the Terraform output. + +# Conclusion + +In this case study, we've seen the overall process of creating a new flist to deploy a Nextcloud instance on a Micro VM on the TFGrid with Terraform. + +If you have any questions or feedback, please let us know by either writing a post on the [ThreeFold Forum](https://forum.threefold.io/), or by chatting with us on the [TF Grid Tester Community](https://t.me/threefoldtesting) Telegram channel. \ No newline at end of file diff --git a/collections/manual/documentation/developers/flist/flist_case_studies/img/nextcloud_logo.jpeg b/collections/manual/documentation/developers/flist/flist_case_studies/img/nextcloud_logo.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..2d85227476a0eeb4273ec73fde0fc796e46be73e GIT binary patch literal 29564 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 literal 0 HcmV?d00001 diff --git a/collections/manual/documentation/developers/flist/flist_hub/api_token.md b/collections/manual/documentation/developers/flist/flist_hub/api_token.md new file mode 100644 index 0000000..5ca968f --- /dev/null +++ b/collections/manual/documentation/developers/flist/flist_hub/api_token.md @@ -0,0 +1,33 @@ +

TF Hub API Token

+ +

Table of Contents

+ +- [Generate an API Token](#generate-an-api-token) +- [Verify the Token Validity](#verify-the-token-validity) + +*** + +## Generate an API Token + +To generate an API Token on the TF Hub, follow those steps: + +* Go to the [ThreeFold Hub](https://hub.grid.tf/) +* Open the top right drop-down menu +* Click on `Generate API Token` +* Take note of the token and keep it somewhere safe + +## Verify the Token Validity + +To make sure the generated token is valid, in the terminal write the following with your own API Token: + +```bash +curl -H "Authorization: bearer " https://hub.grid.tf/api/flist/me +``` + +You should see the following line with your own 3BotID + +```bash +{"status": "success", "payload": {"username": "<3BotID>.3bot"}} +``` + +You can then use this API Token in the terminal to [get and update information through the API](./zos_hub.md#get-and-update-information-through-the-api). \ No newline at end of file diff --git a/collections/manual/documentation/developers/flist/flist_hub/convert_docker_image.md b/collections/manual/documentation/developers/flist/flist_hub/convert_docker_image.md new file mode 100644 index 0000000..e6fba85 --- /dev/null +++ b/collections/manual/documentation/developers/flist/flist_hub/convert_docker_image.md @@ -0,0 +1,45 @@ +

Convert Docker Image to Flist

+ +

Table of Contents

+ +- [Introduction](#introduction) +- [Upload the Image](#upload-the-image) +- [Flist on the Hub](#flist-on-the-hub) + +*** + +## Introduction + +We show the steps to convert a docker image to an Flist. + +## Upload the Image + +1. Upload the Docker image to Docker Hub with the following command: + +```bash +docker push +``` + +2. Navigate to the docker converter link: https://hub.grid.tf/docker-convert + ![ ](./img/docker_convert.png) + +3. Copy the name of the uploaded Docker image to the Docker Image Name field. + +4. Then press the convert button. + +When the image is ready, some information will be displayed. + +![ ](./img/flist_ready.png) + +## Flist on the Hub + +To navigate to the created flist, you can search with the newly created file name in the search tab. + +![ ](./img/search.png) + +You can also navigate to your repository in the contributors section from the Zero-Os Hub and navigate to the newly created flist. + +Then press the preview button to display the flist's url and some other data. + +![ ](./img/preview.png) + diff --git a/collections/manual/documentation/developers/flist/flist_hub/img/docker_convert.png b/collections/manual/documentation/developers/flist/flist_hub/img/docker_convert.png new file mode 100644 index 0000000000000000000000000000000000000000..1be37a0ad5d61ff3392592c2bc43c3dadf72dbf2 GIT binary patch literal 191136 zcmbTc1yozlwm6Jiv6SKtEmn#<0ZQ>A!HTrF6ez`AQ=|oo7T2U$f#Ss}F2S9m#oZ-n zf_&-k-uK>p|9ii+?tSO1lQWr_J#+S+**+1P8cIY2Gz4g9XhbT?^4e%<_&_u?ED1au zRE=c;(={3z!7n>GIZYKgIVMe4r?+tpJ+S3IJLzzaXWV z1+PWFts!x@ElIa6D0oxmQpSb{?U8A%aw7Uu^f=Bz3MDM>iM3U-?Rxa*7`tegk3Kxj zUoheZ1hg({;ke_3XZ`IOtON ziMMHxd}8}BQYLm2torto`&$xA`96OaGb{`8IQY+$7H)&#j&*EvLGERZZVbH?Lmr38025$Ws zR3S1@Msmqc@!(W!L2i{;LP+$<7i9N1p3g1N{KMsb%iZas;1lqUep`I`(54c0zn{&> z)Cie?joZuB^%@tSmcT0hu~ToY+B$z;Eya2uBn7~9sp`tIVPEwn*3HwQ{)TX3Ms`Jz zFeixK3{7Sk&*%dY+HBMB{XRDTSZ*;{rNj_p(QsSKFy2_a2AETHa^b%Voz^47$8NCUcC!~1U(wWsCy@mL)L*NP<_z8pK;pb1|a)von9E`eDTvlO6f#L(pAeZh6K9^M8L02{AZ;#xlCO$NT?sOBHEt*#v&`e?NMGPzcW|il!Rk>KRn2edvzevZw>fN+rbY(Gox%fi*h2xVY_E>F>N0y%{p9ICL z&%P+iuGWEQN^@wEmpn2cF#0G=Ku!=%AVpCA2>-LJxhYF`oS4C^kI`0HMOKaC^M=r-sEeJs}g>Z+MUJ>=CDhGd^9KGQFKaZr*T^(lvX!l0UPPH#?S zj()B{e9kS^&D%|6s3>DXaH|<%|2gtCu;lzRcwTLMzcltq}!^y4Sh@> z5WciG8TS|0_b8h;8vdQrz`i9t8eB72!&0qhOFy|gNi#7uMm$PkcQocW9atncaWbwl zFYM&HO)qUxq%)m=aD3<@Z9yn(h<@mLlYCQ@+w1}RgP?Bd$U~o0A0Bup{QKrY z&Eq!$&)m4}pCL)p&Q{p=8T;5$z-FY3AJ zN%xcB=lsPZKQL1GV(6lro}12_7)gI9u1zmTFDg+h9_Zrg`B3tgIFTf+1iSc=N6Ubw zb*P|-U|GGHQIqjheWuIx_U?N6f$#V^iKuFwdtI)h99(@9zR8%rbX0aU>?yO%1OMvx z*vJ2f89oWO^3(H?J{LG%^`*a{u}bHkNbN~2Z*pkrUL;yP3NQ-LyRJs$_+$D<`v1Jq zy~(-lzlB`wAqx=Gh*&H!oDw`+qAn~PTt||of$_I42Erv@n6|#YlBEpkYyZ-|(GHRu zlic(P`(aDN+-5jvTu*t5b*z@RT5lP*KJ*A(2GL%#EhC6ArJ?VN(r$O~* zz0P(zCrG}htD{RYQk`Opr=?NeO$8QTrAnUiBL(uZ<8e0|y*gr$*iyf;C*H8nFF{F6 zI&&eD(uns^~4%LjBSMwD3h@@Nzxn)Re#qjj0QBHh=uSuEfP3-=&mM(gIDx_s?&%U^L)KNZ6Lb8>hTL|;dI~ss8bw8C zw05R3N*W5oVH^Adpbf4q0yjzcAY5dFXcM`0UxCpaT$SUHzu52b6sgCrPj5g}s$sHF z3o}!1PYV#qdW$0M(@?zL~A}0d|d7LNxLAT7Z`b` zckD3DhE(?x33#?jVf?g~ljqr8Q(D#aoLB8qQh;dX6KmCJy@FC?op~L8-NNi)Lvy2i z!{gRGu+nx6EbA;wL2~Kvb>rT zZI(smcVypoK{L_hryRvX{&JVRh^5E&F;0il^zMzN-KF^}HpS4`%rQwF7rlf1DYq^+ z>@Bw8EhwWsc}+`GoNsokgWY`RMg7G*C8f!J<0Jo_e(U>z1Ny-jxc=|*%!Xax^D|*s z&9^;`X_ATVBw;ll=zgfy=3l`I7l*Kgu)DrHB@{ zBga+aS*gS3Y$WxisZ6gA-<|UT>tJq9&&yamfBP)VS=xuA9b|Ryxp+UXjjp{E@FMCxAiT9JhVlantg5qukOtHz05=_JjGz5 z7^~0=1qd5I_`qVp-jmJ2i#9($aBj+?QdyTVtf2VqH(6CV@bkrk_PW#_wMRX1{%)ja}(9pu{(6IjAM+5c#bH$;a zKQMoLW5$0%!$tjjhvi3P;VVeS8HoWH(Mw7XJfdc zs0w^%WkWYKG>RvG9&{D$$H%DgXY6zh+zr&#BrKgAc+9PwEUbCF9i0D+g9h}LKouRV z-OZW29o{>-Nq9@K{MADORsK`W%fj?m7k7Ip76WxnCOIcpYbFsMJ{~?6X#yrDCZMa; zTM2D>#lM52{zY!~@IRmef+9ly z2>K6A|1an(H)~fpCkND|?$ZCWV1Ebx$Hu<{0(t-7{tvYH8=?QIMNwLs0Lc5_t0qnG zf|>LIY9Z z7pbZC32}`JV9Clp#!8I*mS;!(PS!%Dj?5=lXlHYxb#!P__hD4;WS1k;w{O;XkFB^2 z+2UVYy^f2JwZ7CqW`!-C&aVwN@c11B4FC3PU4my;U8JY*_xNv7Em7G=E#1H%g2Q5# zOY#XHupTp^<10VMco_HZ6f21E_O*_yi6HTYiT_Uj{~22X!%suz_AJ2fVn1zvzRqd2 zfQ}n?3iI|u;B%R;jH4vmxM!FM^#9~<5I+)~6lGbUIUnVxfY$oP$t=B>+Hto2H;y7oZG20F$R?jEN78H}4G8FwJ$ zTozmb{cxuVE|i&M+$A{=Bdw77-*>f)8My84!!0@z^8$CDWQMWguZp(z0}}UOb}o}B z++{Bx1BMH-3h8Z(`d@eU z|4Wd6K;mx{`fwX0x5T)O1pn!}~Q_eAvG&dH%LX z)|e``CUrmyqA?|@5B@XCJ;$iRN3qE?4c*e~kTUdLny*u;d-?x&)KQ`f0D1eMI$Hq&El(+UC5_}vn!m1oGmgT>B`{=ML}^HBQYkDa=$ z&W|^adg2GFVZf<_Hv!H41t!x6xMlcUjMM!!CI-C!sU%0gZEL^8%#A({tyo{WJ6Ia^ zegB!>bH+R)epo{Ti~Rn-4w84;jAEQe0UIjvFis>=9r8-jWuz#&$a`Rr$9C zThPKwv+Cdiymumd?MxM8pYWOZkeA^5OMEC^6vIilk{ZMD2V6DM&kI}9mpiqr&ygwM z>y*CIx&*;F0I?R7beYt{7ErvJl^ZMVd)kI8?d*DwTmrkcA{WZZ7#DoDvJyrD zFRBto{5J&?P*N~A;pbsvvFe3t>zQf+;2TAQ#uEQJzgF%{?D1!$F-(Lt+PbW#vW6$l z^gl&pq>mlid z=aV|@1zDbR?$fx^$3cBWqQCiWTY4GSkzZo{*Uv_2otj)u?=D-xh=8YeGe5nK))y~Z zyi(3&ZYN~a%j#D@m)1ww{rlTI$U*ii84w`*_PzZ}7H^5IOg9lCmSFZnm-m-Gh49XY zp7O1}qah4J;zv#JDTU{+v7}kPO}E~iCxF0+i3EA`-KQWUT)$yA$b>@F>&FMagKrj3 zllzpUPrqn9{*`jaLKlVw8p!j4QQOcldA|^=={-+r&`>`Le!!FZxsw#wyrb?kH@@c} z1hteV$);DkPT??xpQ>K7rc?Bs#M-_+Zy1yWF9zm#oW#1jMGvWg7ti%)p-sGK3grY8lm=y#`pnJ0xV8Je8O6t0z9f*x0l=sX@YA%fL@8*VBZ%~UWwf~ zY$4xF-D}m3mru(?72h3wbFF{haDH_Xt@GOCobjK9VVmOZa~MP%Ja#f{-9N8a&^m@R zIRl=KP?^IjMI-{duPc4lI@h1UU&c^6INeLn;ekwVf0;`8zyu**1R72Y01#q%Wre$G z6o2-K2Cj)}Fu+rL=$xNlR3*}DByq^e2fd44TfC^PQI5-*4&}1E)ufmQVb~Ex5-arBuu=oL_{6zr`S|3#UPLK z0aDLi7uXvbRhKTsy!W(#*vmvO(au-W(+s#}-xG{XLbLr>B9DAV{1}ci?66hgqev&Z*6RKVxOGSZvAqxm0pv^W=N_qCiyYyv6&} z6X<$MHI=0m55`o0Px)G3n5&wA&*Dp1(t*Z}Uv)6M8F)iKa6@~Qf~(6sj9x?>xnDIc z^^~o`1UWZdHouwDhXokdft)7xo%Ara660!|NTI%Py_50o7(HY|jVYj0)L*WS+jx(z ztodTj(Wh=oWzBY2Vy~nRpFOkUP=fJh8TaQJYi6%TCY9=li+?jt$YqL&?@ptGxXl+3 zHYieaF0F?y@MzIO)fI?EO`&&X>nM z$E+c>f!rH1*Nek};+GXV(sq`|3NtweBGQ+Emp@IthS_DV`-<>>%rAp;+1efet{w*d zzCSm;KmUY8{QNvpemhrw5Ll(fyNx+PnLXmuL+_>L*tqkpjQ0n5@Lh;= z25lpjC6?*=E7M!ou5E z)eIUvvo^i3&Z78u8yO?(w*Pjn-K;6?n%@4kAH#L8(jmzX-xM8BDleNo=OdY$PMId2 z*91uzl{#GOCF^2Pur5!ih+0>v0JV~Y5fp@zXp{e{e8`11+CpgWZdbajM}E8tdb{7) zKo(3YyZuMuPCGcY0+-QAQvH#2U}U3z{N{k^-Kpana<29d`TGJc3a_V)y%wHh8#@ffLwox~Q8sCVN#3`?T<8ea^6=V6yf8)_iyKCd7VTe<+2tp1CK5}F{n;Y{8}&l5?Ze_TGKM} zovxFe(&*d<`4?QcMWeh;=NYhC4(3}*$sQ!ki#DwgWpUW}t@|4_boH=MpcpYqpm7KG%dT@ozqMY(AgrlUzKB!4G;icU}L7RT3;?rD`Q_)SY~FE>}H=r3|3BAt&vP zDRMqp9>MHv#sJN(+5s;t;YZs?$d;oF;BgR%+QrY2rQ3z2tglvGh{G^9t*et+n@2)8 zK>()ntdTa?;SDjahvbE&SNn3;2G^T&a%2NW2`byV!!3K$XUVf8p(14Pi1ChQ!R1?+ zXp75tL}m&DL7$B@JZ<9U3(lBo;Qb}I)iN305Vj?Af4zT5D3W62s=_;R5oq9e)I|mw zEJ~0FN;<1@TfEde)}3I9_Svdp43m89-G7}J0n~vQvjKjz4)Fr7Qh;9thL(=E$$=kXRtO5mxS4vDNUMAL)}Rrq@ZPv$~LjE=1E!lpPqlY^Qcz ze9k`N_7ooWHM!SIt=28;-K5s8@ly+H+83fMOUtaa0^rDFGs6jCboZ3=x|Z|Ota>xa z>qvIs3jT!cM}5-(4|eZ4jcb|75pdETFPHcC^I%3weG?yR{ky8D11gCAjlebXk7%+> z)?cYoz7@R11cOJFqRlX&@{`aR(sJhZiP01IxZ8ao25tx=z$PLlye7CH#O0R%3VK^j ziIf^oF-6ece7b69ylMA%p&hf)&4gffFb%ysC^k9&?%}j`pt~p+T#)74TAa*2vIJ^7 zbumN!-U4&;CR5@Wn3nJ&!VW~CIrmfGy;g_T_o&CAmBbM_^jQD}HB=aj72v(A1Dz9g zE;X>t-66YK|Lrz%Fy4f+g4w}WVc?nD=CQNJgz3BDE!G!}%fSzR6eIKAKV0DqF7O57 zu1i{QvdBs88IJ63c27SU_ctH>@|7hjcH@S*UFU*5qV#65$NOn{kJLfe*)%@nbh&nd z{UbwApJ>2@s5-;#wo>_kgp()hJ8A(OFxfDnIhh6Lqc}BbvfZdS*9f*yZ!Ca{JsyZf z!dzyDsfERqyH6>d`$^jmP?HMnTB8x;8jwI}IHnc9%2e(^=ek}R+qo(Vm<7JO-it@p zm?CTN2kxI)7CvcRlWei{CAhrZ)o=A((Do+r>6K$!LX<8^NZ}C6bMCH*OKl&@tQP*r zI`#%V7Md-+A{rCM85QLYRZ z&$guWydGyt5^4kMTYI7rj zVbPG3YD#gi$zp;YvO#(7K>T{q>+lBvB9eZzZq6Qf`X*Sp2mhId>ALZe?{ppy{Bv7k zis-KE=8fV8cJ`V2rSfKp}`ge=r&wTF` zshu8!B(F0ac)efjcb$?Kb@>=@2edz=l7nFh-jhBCY?fq&4)}!YYjQtqCu*yu5?5H4oi?n45^NOM4g7_e8GP`b;#we(H_*g|gi>v<5Pc1NNQg zz$nE&pQLcNSmLS!uU@!YeBVwM&0#@K^O7x=W5R#Sl(3yT;Yu#J&WCJoQilfK;_h=e znI$yY@b-3ncI&1w%dL011kM>IUMF(*n`|q~xdWfat`0|dWIHF4Cw)pm!YZ^SPwkBQ zpyQ9#2g>E<1E{>|7JMQ#M;GNPsO#xntHQWsaEoTQK09rrlnyY{b5X%+lvjQc_i>D3 z6k;CHG7->#lE`hSp3rs^VQ(>Z_6^B*la@A_rfuI zmhs5q9^%`Do~Cl1IGHk%9uY=4yQB4kSI6?ukN6kNmhtpKzW$WK&jYPAhhOhmj_{ky z=*q+sZ|SgIt($UhR8NKMXKba|i?7l3+rPolmU-tF_hUR|E79##A%LyCi1vmk|CTH>Zd!Yrwc+;eCtzvD zBn6(}bokLfOx9n_M`Ka!n{Z67k*i5FV~qWT)5wP3lJG3V9ujad8v=lc5$~yDZr-qF zT_xQr9ktva`7I$m$6^}XAOPMUgwJ*~bYF&cRGK34O?Nlyv^I-u64MeZjh>D~3K*6q zZ(L0!>Wr^6&FOW4;(L6FVpNR_cj|)Kll4HxeJ+XFlSvCEkd7|UzX+>|gtei(X&4t3 zyp1ZutSNP5(2WlVCIgcb5b3DLlfZ^qQgwDw(c1Nxh)G*MTaZO*%^8#NAHjB>^t$lh-Urb1$)=4ngJcG%1Q9vw`81u;xQyVt+t4A96Z67L+T!q{a|4+ z%qWw4#59Q7nd;`EY)8!XpsxAAVb6s4JvOLmbU}dS{w728F7<>@?AVL@a^(6K>N_Au zOMCeHhO{?G|Lxdwq~d*azw?ZFm^uWWxuwRg+$RKZ{L349s(JpF!!|tTk9&hT6GCMN>dl>)7NN$?=3 zNJQP_0`ASw8`O3^>(_5_UEu!{DJsCcNp$GvO`w5C2@J;rGv(H*GNSpu$ai!gAcl;z zEI=&~zXX2b4wZGLZ>W|dT+}+nMlQ6T%36}_>nv>Rf$3Gp;ZuyXM)!xbKCm>S4M`8I zY{H&z*;cf7ANJ~C4Lgr2Nf;FvILOxNS<3_HaSlJi1%0}N#bR6&g(7U_mC)WK+ISrk zBV%n`rd~^SbTQ++VVPQ|CR*TOS&(lIx$LGi{eAMuhmC#bhVa)LiRPP5QX!a)tF%w= zIj3KuQtipUWnRWG`SeMWSNzpMe1vCj{!s2k54Xi)~p*@4k|L&=5N%YM^p#G z^kU;V>dSuI)){BBBT~QiH1EXN$9{;FFN!XyNZL&WaQ|v7tQq7y%2R2nm`v%9cL?xs z9kqNK`4DvqvRkVNlgXv(Jgi4qC8hMI9vU$H^a;Z3j1rTl9nzo~`_3vkSeT_7XMogUbIs<2#9W?0?C3Jl2f2f!11VaPBmIs?`8_zGX4+3eaU2+FG z!JK>R9|e*mp8KdU2A}q~8c31Is2FZCDyDTpzh!L+jzDhnK#fHY-rLW+Cm#$gQy=K! zjKs?fgQPZn6WP`ODQba=#J{IN?~=nZYY%TbJM?PxGamP73gPF0DG6N0`4Gb-sp@*E z@bURtdc=q=X`@oi4`w{nGvH~{D_2n?E*kWdgQ>zk!v@kp=4CC2cf<#$u#-wpI!-sC zKGB{UOJQm!>n1kdO=jhOf`=ZCT+?+KFJ-E*#q(c6v8>{~IK9GvdM#=Wwb+0hem$EiSw zTqZ4@>BWx}k0l+*?pNP&_~o6;-GrM)mwDb znEkEWE#2tlZ3M`FRrgVw%d7n_YpCes?9w+Gl)G{gupf^Doy6|PB{Hyouk@iE3r!6U z6yw?1%FMcH1|16>1^)3*95INcuRcyUZ3^oI3gvJcs$^N?E3uFPui8l<8Zm8Yz6#ZX zUGbBKyT%(!8YS#9be-^3Z#E}@;&?^RF*^5y>x;V9=AViZ#NyD?=W8!nHPXtr;&H5l zRh|tORLM$piZR}+Abv{*vmI6NcA=5*j^>vgOEhUE?E3*gL_VJFqnOK_xXo7+o6;`>aH&sx~{N*JSb zfM*_P4vZ)O&t3Dh=;$RZP4QMSva0V=S|O`Xm2(r@%rjc2}^G=+3EVEm>gqKII3c+lBA#>uQ;BqwXL~}6akn| z$;e#oP_B*CZ&CfWWu@|e z{@VbFO^5kruH=swyU?r$?v*YBSt%oy3ET2Yi-5MQ%Mr~hL{8iO-ha4r{Oh82d9P>) zQJ?5thzPC=ElW|wti$<7WN8Z(#Tm$lB2mVBBki>B1eM=ellbQR?I30}?e=)Hfr!6{ zz0w^xtwPU4KdwHnV!GaLAFu{|dSQ9?#5*D!UJT89pXqnlu)u%ibsEx|-zsakVF;&% zHfgbWM{J-xeMb zC{G6cO{95uT?bFid@6tjjAyt={B2Yw{;y2BCKwNWJ|tv`fp3wvos1XFh9`KdU5xOa zN>t{wm-XjXrx>>7qrm}dNJyov-bV|yP;mfEg4*74_@j%0-p_Wbd&QIw{D-{;1n`eH z#cPm#o05-~__{9|%z&XTY_MH{+Af#%FiU<|12sw43{05no;3jGEkT(6{w14JjisFBpqiYQ&2l5|wiAlMk z`IslTQSGg6ynsnx|D*>$ZsjxZln$vBcjt=a(+KP%*}TNuJCbOh2vl3UhZ1z;wUOMk zk*FEWSI{Kg>p&5@3)P2C!`7#f5s6gfK`Iz*K@%&M&WXV>mPHg}TD8CMK(ompF8&0@ zo7{)|)HiwTQbol^;-5g77??w1f`nULR-SCtKcnsM7d+=3j2}~FwsR?djMjNV&qg59 zm}z|4US)PFN%2L!MX=#vSiHk^m&z))S(i)~-LJxZV610b6GK(+(s2m@;#^T0>}et) zb}jF=G7~Pf>w^k5_^RFdDIX_VqFgcV1m(2ub_>27S#yCxn)hkI{x1E6x;J-+e>~_* zLsW)7JRXOPt!BS&XB9VGEX=9zF=G#*dWm4AGX3qJz@#1P(ziaZU7~Y}FN){*nXO*x z;StJa$zyn?Eo=g9DX^;y7~_&sh`5#7;sl@_vD-H4Bk3U75vn%4(wb&uG|1|D|F&%4Q935?)}{KTWem1u;v7p_KFZO5 zBl;G|1fvp=4-2=kdoa#m6=7Z`H`{&5E|XVf>zK!R+(CAJn#*{*{rgRJDR^6s zagKgk(ff6ck-`ipW4Ou!Eqi3<{!b_snf1lyH$%^LHRbhCd*Epu0ID-j6bL&0`SHh$ z4WZHTn_!W^UdPtki?WeaS)5blg~!_Vr8WUuI!;tn%Ep^U2y#%su1-NmdJ9~P7~Q}> zF#0$#=uu$Z`s_u%?0k?}oP>z`eZba1o&V<{ zbArn&m+sVp1uK+HnK$w;ipmVh7+Gt-2h4`QIH_AYH(nAJ)fTwrz<~*b>tlm%*ld7i zy@k2*zv;hs%560m|0`>V5K!m__jsQsE(MeHUWu=iiaHSprr^5|v;LhfPPiFDrBnjD zLTDlejlXyn7Zh&6MR{xaTVOLZyarP)X%{mx*9kH^!JqkJVYD{UYn1}TYtdCv;#iwDX=KXlY_QXn9x-z0w(RMtFmKK$&K(3xBUyzuRcG}XB$GHRr4-$qEu`S=s@v0@DK%(qqT3*OJaY}cV0J073?>S8mF zBkU9v(WKwJ`)W@fu=8~?!owezOptqm+VTxnLO9m8P}jXPp*clbeV+);RrqP4s=M~K zG9P|8NH!@;rEIQfRbsz9LHG9qr;`L63_c0$2948cecT^T1>mx0_>x35`0Q*A`jrwc z&46~Y-COtYox!nMO%c*A0CTqI)OfNpF$O2gGlgoot+)trJ8QM0l)?%Ru;r_=7tCd`h zMZxS6bH6AzuO@5yLwniqJg;1Wen3zl3GDtFmqRYm_(n2e_t%l)S>l}<7AR4r-@g?1%B){- z!>P`Y9C#uiH(zkLCL0jT@r?kY_e|gDX>fs2ip|HRt=Ul#_A{3Yc%R4hLfnrx;4{|O zBjdxxSDAB;>vKkw&`@Yz%V=$#;_TyHvYz;Ii4U@qvi_2a^lNn*{tQdk^e?hjjppbO zz{*A;8f4MHXl1zh3oe%S)$Zhz(@$UHe5+`QWG-&D zWWc-n=4ei#3O8@R0(Cp5+sY7h7v&w9)$i6-$1O->QobBdgxBn;Vi3Z*zb{8DA!kb}YFpfHk!WX=MI8ZO#GhImn>!(^`GEg-|WR9p>do*QLl8(Pcsn$-T z6iY#djt6~Fznn`4v-v*ti4nqPo?2e4hfz+{dq(kdz|Ax)DqGLwd*+rykW!BDDsKX2f?2uKuoCdxxqcj7illTA}n}}il z0Rv*DRqU8fEhdv}mhLY@5;90CtdUT(fr7^pcu0I5+^|F)`{g@ZN^0NyFEbC!yXYQ0ztl3uFijIepc6 z_=RCL1rKmFEDs=iSryecE74x9Y?zU>=(!Yz#+|SpFj8`KM|w4?X(=>^%I@@?@#Sn! zMo{%Xm*niod*C!@!$NW&3jNG49<%cFn3{?nM?%Di)-s2oTM)`mbB9VlJMAV2_&|KM z1|DopMY#Io(2;Uj2+drPMcJ?I3CxCQ;%E`lM^arz?WR6awun3(Jdxa~LTLMQw78SY zx$Ck5iSP?|J<@JeL)qD=b%;r4#!SZbx*02*9+LS|y_lw1iOK)0A$`5>$Vjik)?t}Q zitllqW4ocMIS%{0$w++t3R2d;c?C$#JP(pQIXnPz{9j5vw_0+aQ^jq>x>@T~F%ziW-*c2Y?tdF^?R zes12+W_f)dumWIU;kqFPHCp#XUv+$A>#u2lu3OhPUU(AS<+;RHihhgD1s&1tiZOy^LzX z4@i8MNC~mo6|sO3E}qPjE}2Bj^4(bbyU*)0h59}HWX1FVAgq|Cpc%>RZ4uFAV2bQG z>bmkPQ$c?HS0~4UhL|*a@~NSgiy4*Hu$Kbty;nq*p8ymajns9+Ua*(cf<zXp6M201BIpIh&N2Iao{5QHaBZ|quKzvh}KTN7RK)m@R^Nw zz>62S?D~x{JzK~>tbj(iDUh}|_?ya7zJ#XZcB7?1v3TAL7}@Yyf@egG0-lq0&pe7Y z!UG2s$4HJ?HgQKv;56?y$j!xAPl!M2ae9i1h@{FIu$}2B2f;o(Cd;isBW^EAXrv4A z=6u(h?MB69og=0wJ3N+w78K=y1F;gb=t?1qS<6+9;;X@I9z+c5O+_&M z>_qJ6X9yr1a;VsDaglDGyv5QBu=kT*&22K&4lp<$s7?#lW0lyFn2g3tif6O_3@^0o zQzhTs5cB7jG2xfT4VNg)KqVKIg_g4FBkzhgELrP}u|dVjPs>cPL8WF1w?J^0RAq~F zphIqPss;HUd%K?zBf9p6`Mb@vRSCiKczx+&&HO1#lep(rk<9V3X7P7e)=+y_M-%y? zyXM-b2WBcM%M16v>??{0AXJ(WsdgOWltx7%H&e_`2a%ZPuYayM`O|hls$JwR)x=f& zOiVcpKl+gCO@w6w^O}xTe6m5qPR~oG^7W1womLLN#yV z%DY#~J^W4Q1^<6cg{{&g6kZ=D4%o!zhaIHaY-f-SqI597<8YISWSQ1P`5K!CLuBPK z_pRbehXJl}Cf47wUZ5ovV8uL6h z3^CMg#)4-@Ve<$6qJe*Kj^g)fJIUZb1jf3QH4JVk%7ftU^aDosnsh%Mut0NFaEME4E)C}QD-idRZRXtUeSn&R%b0ik_%^IdK)VC}%(AK7WZ*>>hq}Zo_lj8n*8{|Cat0T1 zVb8&**5YOSFFh==l zBX~;`Q*#cN8ISoL!f-1eCO{%ib+ADNnXdireQZ+|PhNDy0hqa%xsZSJd;PM!S>y2> zI&)xxtBjvya!V#7_6)N+v++PR0l7ojI;uSl-!~de$lFfoi^(QRmm_LF)e>h+d%j|R zN&fIx)2~8Z;~cMheFcuRuO-Oq3=v)cWijZD{Bf7nQww&9X?)9(-7=!Un_=dAV5>|Q8LW^rHU2G8i=1#Lw(#4M)IF_sh z-l7f^l1a2TZBCAiPJCL13i7nn@N~X{%e(WJjl>#5oS^wpui7WLqzh_k!+EG5*_B?{ zaO4JzS?_>5@lnb0!!Yn9;6~=sG`c#XKLLRn|CN~F(Lo7KHeYLgJ;l5oD<`H5Tu?@b zxB1Ws@uaBy%yheF-?LM6Y$?~6&3Ag#i9L{Yd~;mMC`tV8OJjPVEs`+Y9hD|4v#7!X z2_qPK;zf6v1E>hK?njTnCUO1CuUN8BjvwzBU+*s)c}b$k?8Zee$o#)LiQmSJ@hYyX zUYNJ|i88?&XG!WfzilIUhqSq(Dx=0gq>JPc12szjx^I#$t`=n$Phs?ZVw!L+~_ytzpm5oIb9~ zn|7V752bdK{eu_TDiOXKcV+!bwHuH(3g$6K$P%&8NzMNaNFxq$tubhQwUC1hik7 z6kK5F)XNUKE{REZki!V3YfX?rDIOu+txmGmq{eo6@0`Z`5N*`rbqRr&$yhk8&}Mp>`R=am#kLoU{_9+{SXa6hTihNcvxplZ-qB(g&Q48RyZS z%G!{+^v8X9YkbF{+NX;;%k$Vefc68NloG^jgvysfY!_d%@GVonzO!Hm=HhfFMY^Z4!yxR!vmrW=Zx9L@*CH z$Cw^UhA{%=>#|$)idkf8d0)SE1)qmK1ZWi^=kg*uC;&q_EQqZX~my0%?#!ktgRmwlLQZP${^U~{Rj0*@L#|hQ?>knMWFlZ3l zSLQf`b4$d+w}_0r9|Js+OsBfd(f~G}74*pE2+vBzq1TB+IUN_iw^_$tT{6^}?~Woa zsKMRy?l+J!2dY(VoPllHk`B71n7CBeb|%`fZtpT~g|MTN>BnHXVD>p{mREXfM!O^; z#SBw!yGtIKb_ca)?Hbt6~wFzK3tou{AtMhVbdf{v_Dffi}gD^8g7!V_S(PW!=A-@ zK7E0eq-DV%iIM><^jK(SXlxEFF9%C44b+VR8Plzw_)`|sS~j%3Lx$YMfq z1B46&bnzB((z1BtO^2Nvfys6ODAE0ShuBN`T-e?~n0P^sNIz_9O*Wh#68w=BLD1aG)#I@9XLt)u4?>+nSwh;RGnU0Xn18F`t@7! zkZ3B*d6{z^8R3n7!D6y84?Cint>}4$vhFq@z;4xFj6LKuGSf8HPW<6U82XVlq1JO$ z?6@fSVeRW@mh#?>h~477L(IFkuF?4DQ4#r`&RL2~WF9wFqV4qeNNPL_lXNXcb&Z+i*d}Vb9v=?{HhtpdSFjn2Z^{m{pGSj1kY-$2dr%0TB_ylmmI@ z?mS`1N(#q`$Iz0k!7i_;S{&ICR89t>j_W^uM+yjQ`nIpPG$jpAeq-T7x1apRkvi&g zTVOxsi{!jWZN_5jj6#*P)C14OThr2~@&c$sSo;SJcf8}BbB<{VuUfgC z`Ymv|0`uG$8FC81RHsOu+7zvUr=sV{xmTsl^0Xzo%Df+@FeO~G=AJ-U1u-(DPwX1D zqf=KgSe3=#OHajRR7r+2g5ra-t(d^PeUIr{Eokwn)%j8VixIh4NypwHCj!4a!H#=J zr!Z5S%m$oL^*1syXxvoVifhBjF+3nlq7BX4CIDG2n$fG>6Tm{q~{=EV!=P&{_%GyX)P#W}Ah% z(h1q+!dt>ZwMe;_+(;9j>xH_eYqy=!n5b%{wd5^sB0~Z-ZOn%QNlnxUjEh7i@Gp`K z%j9KYK=u9I2qo;qkd z^*HpUpJjTn@4JRMqIK-Yw~+Y2UliGs1Cc8^OTU%NyQeg@1^z*TgxVG4!D%Qm<-#O? zLa>r@B!&Q9WJqQ6TYflr{3q^lix;9;!lvTMm&taWrP4Kq_C_(VB@$6WFoyzA! z*0i;U&_}V%dk$=sDTcAS{GY?iR{HT5L=?Oh@}+l2${-8x6q&4HG4+dP&FI|muDr&y zp(v84w@sKwAy?&L4tF1{QTS3yc93Sf`VPWPRa4zTCShn1*1{W`nCLTTA zKSr{ByM&|%<7%fGr5i%O?1y1ysw#@CrhfOC)QsNwlwDCx=bE9cc6Carg`iq-9nWmz z@H3x+v}*#=d6jS^P&q?@-Bm>8LgkTwA5Px7N?9*w9yXV0;Nuk`5A@OvkFP)O7bl%} ze|FaZ+pn-b%0Z=d1LxXu`Os--$Zd$0m|q78R|wMCakWWc!ow9+_(*ZR>>a;57<2yV zBS;mo5MJF~3E_{VAgOat=#W#0+S^oOt9gE224&$?84=+?YH@)LxZtjff-@s2eIZX? z4ay>@hTAO5SXXo63qJ2zB(3314;rcYAUMX$Y>sRa*JCCfw+Hr9RSk!H2hwDZS#-K~ z_(TKYDE*sB1!H=G2pwoE4Z&O1JJqha=u7(b#|a*YpUXXB`UTg!&KjU-4IB)b@^2ou zD$|tTm5U20VscT8f15hyIm(w-!FAB#AR&IL(A zrQ=Cj(ZOELyI6AArSKmC*$&&!>?u3cVC5^PO9|Ys()c{Q#>p5}nu>q-_*2_#ixt(&_m%M3c7fO_cVw@~_p)bGvwnmNA?Jt= zbav$xG;s^TWI^G%_>RY%f_dMQk6qOp^2FSYD-8y0#$~Qq!Ron3CQMxg8n(yoN(}d$ z#VW}uEE@;QPCEQ?%)YXg6N6+{-CGHPhmPFRIIs?jbkei;SJHL?UhS(!d)-TM_KFh= zK{#WI9zV3)9i;s$XR-Ga1e4tgTbq3Yt<_y!}DN zY(DVKJAB>P_L+S`PN9>Fn~lI}yH>7G@lL6!xY`V|A=#hUyHm>=YY4}wNO0R}q3F&Q`c^#Vxi4o1Enpm7*J=trynn94S_}>-4{-nE8z}sNT8ExfXbsma21a6rXaV)xS3nQA?^q@h&xsKtiqMDU= zok(J*O*%DVyqTjJCBST3z{U z*YeWb33VCh>etOEPTvJSV`bBY>#C`Oq&|1>cAiDdJ=4@j!Fl91H4l-pLnSTm^zO0T zZYfuy_u;~s>#%>6Cl!MDBr^c3X#WoRX=4Q&y(+Q+g9ZVPKg)=mhi&o0C8p{|@5@wG z{gN;KrrjTf4Dm06%zYJj&}D;ZFtwMGzcrLcnYBB}2*)ggVh$XFDe*D?Y19t8z7A18}cKd->+3(=>MP>>+1RfHH5e0yx%; z*{rK*jQutbwUy+<7iZL;*w$Sc;8mAGB6&#Fs4|R@<3eKPAQ$2LSEub_o|8>EerWVb zuZlS+pKZX|bZJ|8prXr&#pTxy=Fg+-sn_b^ePZ;oYr%YVu!v?NBpO`iHxis6eaDFW zwfAbQeNXA3k@{2qs4FyZydYo7E_|(ARH#U<0qujaf7_V8n@v>~&HCY)>F2Q!`+90j zRgqP!%(-4Gc00fUzTntnMbV=4|(Q@`C>$f1qylI z-?KnZZ#|CS$`OmZqV0z_=&0l@>gFBFc{$cZ*@f;}pfq_G1!8%f!bh>b`cc@9w8&?V zIGD?Ka3!v4qy5=Xk<_BsFA95*NW)3_(v&?~RV5Ikw3A z0KSt6dw3NNX?|qCY0pZkL*IIaXpFvxQC;L1$8mpHBY`XR_E)zPl}u?)IY|nHwuXr) z&U<~Qlsam~K1@t-CZPObu^h{}A= zoDd_|)ox4i8_$9HEhMWyhZaAiL>D zQ|R`@%6@RtP5E)n3ZW9#l8fwCd3yd9-B}zKm@DBtdGmSj3PN|zlr29}l||(eD=!(d z#3b^?GEOV|-X$DcKIh!=QNSWomfa>oUYK#o3{J;Y3HnMG9|t`cs}!s1sRJ`(*pHE8?}y?zAkYc2u*q<|34`mxopxFEjJA%;f^ zeq3X+#l~ffF*N*i%O7_MX=en_S_P1^FweF$Ge7O=83qo%=ejMaZ5y!<16wT}?7yqY zJ#%)Fp`yY6o!?G~=s!|`4;LVvF)#x9xYbj0OHaQI8or%v@pAd(S zQ?|1=*sdYbm_nt~9}Y1!2uGPgezJDhZk~x#A8%@qjJxXY?gYDHVN(d|pnzrCtkzqE znde{$K5d}~r;k1oC7-e^0p}IviVfejJx*!W(c$rZ( zx#&n_sS2PeQIctdLcvGfZk`LL^1X2Eg}mchGtN9u)P>d8W6#D&>n&@jusm@WSNEu~ z3MyTj8q~>tP)}XDo7ws9_s&Zh4l718Y#`CZq;gxFU*)p7xza|=9LIu~ zbJ9>By~%l(*UBrC$GGc0p!;{*B;ZMW(o?idxXvTIe8}uxcf{2*~DA>tn8BD^%3Sot0x)Wa*r)D~?H1O-Xl5MbS(|Lrc|tGbo6f16S0wY=Raz1J$R+7k$W9?P7^({S*^N{oUE6TM0xs?_qg4&4a0cnP)RUL0Xl3Vs~d)E0ZQywn;eCZhXEijSjg z>Dv`dGDkI~ha@;!h`%R$uTCbnQWy|cM?T6~xyy^pe)>rhsjvL2pzPYGD~$ zbfIfZLZ0fC^^nAT91$4TX|cg}<+C3+#DA1#a?z!`O+oV&!|SvqZ9iFoI-`@~aZma3 z#G`wdsBJ?M7WAW0ENNtsv?4IFZWSsL8n0yd7h*WUdc*}d65pS|Ya-i1oq67U_c@h_ zTqS^!Q%Ua!zYjoJBv?*}L>l|3$Elr;a!pb`g`jHJNG`grpo$v1gY)84tqcDM=L)KX z^w!VirEr7g>)7;8VY($PI@}nHe$f~`_k`Msil{X_|ofJcVOp#w?!nybRNQQTwT1-*r~zj52#0DofNp{{)QGANqI)@C|7xJ0Im%f^aXmiL_gBUg* zh--Cm`w28$&PPJO9Lr5MWkqmBtwmWmJVe}C(-=5uES59;<{9pE-$#_aoQ2Az*?A0~ zz+B9{YTZf=ks->J()+N+)6&7bbNXsE`gE6Czd5{kWWo?jfh} z0JG^g)V}oa3OyEvJ$JZ9`v{2G?{ls6@~e@m=COB;mCE&*eoEt%Y&+!|Q*VD&BfC<; z4|!Fqp(0=^=-ENw5wX*{cK}v+T$F@(r}}z16TQttN)`0$Ua0Um80!_>og9jMW{>XR zCS7hk8}F*t7QazP(w`mLrb+6o@6UNQ^a5wRocBXj)NOUThz&CptE$xt%^mtJodln* z*O;gr-d_hdHO}}Gz0e16Oy3jr1>Am$7|3lGbzoFhQU6+b{PK&Q60?gWY4QO$ZqsX~ z3l#|DNrq))IFQ^q&Aoeo$lPxDm@PxTM^S8S!mG_^%=U!)whDZLW&#== zYcg(eANwkoRwT|^w}Ho|X!~MPuy~93gZ?Ugq*b4|7OWS>u?Ga>bYF1p-S57vNT2C@ zA!h6&eQqd*bF1#spg6_xyl=Joc-vyXKkG%`A`Vh=o1Y`Wni&cMm0(Hwg#^6pgyQ2Q zy(q-@s1SaL&n3|UV|z1^1X_RaVv-&0OnJYk8!30IFk>Rg*ok|YNP3NIeO3C@Yp)BK zJ-Jl6@+eKSIx9Um?3ZkvZt^gyQ-ID2E6|_%VpzfmJ00cXov7(suLBn2Pg!BmET-&> zzMNULx%@Sp^gwbdQg@7_mkDYr8ti*G$X1qD4lnmdJa<|zmA?}5i$u@z1JWU5ZU z`xe7DoM|X;70TDnRhr14>sS;l3hzbtUYm`j|D#BiXHKsKeC(=hJ1Z8~#w*8{>(%xo zHr!aLD>Kxjk~?=lJRYLABnszn=Z{M{suw6y`Gg~p4M}&zbdYsykByp$oM(Z{Mi!pR z4Lzz4yo#LncUy98Hce2w4#8`W@|#wT>_0hn$l2cA99ts05ZxoMTaUhy>_$2kuB9G3 zH!Kf#T*IeARu-7YnUmEnQbIn-mJ;(V)4CvMF%3OBGu@v!rp6@MUku#bUyP{lt2+-0 zj=p-alfsoouFUAQM0qi#dTg|P>^|4ve6d^Xi`E*4+&WLveL1QM!|A`>9W}Nkhu(BW z&8JnQ)1)y}m@aMm<7_y66~SAF%|VY!m{!N)bDUV~o3K-obH}r<>Ry<`{f#Ha3W=&z z=~xmNVFZ;s^y%9v(siA!PLuDB`7{zAokcNZ#4qR^V|^dG);_F{C66uKzBh#h!}iE8 zX4fkll;K|1>r;5MZ5C+@tlep@-&P(md8M?=W508r$TM%09YVi-T<7R=%+XHna7DF! zTXI0B?<}oV9N##%E(ue@1)?O{$^K)oe(up$LE!th=i>GJ>2q(foaB(-Iv#YMVMUeS zO;0^wPA8f3Tsa3_cLoRQ7Y04MByiE`*3j9`@;<5dr5yJN~q?~y&`Nv{~oSkNHX zVqed<(F4Xi?CuL_7=}G{%jKnej_apUy+P>6LV&@suE~ z7T+rfQ&-6mSg_#B(z`lZ>3n^(m|fmgW|6K&)2&v-+#8pZF>S22C7*I#tYItoCXiwj z?4TuBd~b>F**@+oEWcR~oEiSxbV*aRUf|qP)h(}H@n8L}3KB47IBDy7Lv@Ly=K$y&wT-v;gtpk$?1rs-|mh0~mz8pXt*Et7&* z-R1;~)t@T`oEV5yA|lHO!LD13J#rhlj7n3XbQT+>C54T}m%Lq53iN3_!QRIxvZqr1 z4ajK>-3Q@S+zhKWQ-O1|to~V2TYJe%VLX}29Zel(uLXUkbOi^?6dbBNN54eQqkQNSE}&{h_MLLz)hQ~gAojGFjdeOSo8o&L z8>I=2-#*hDT^*3?;4*#!jXyli5*q|^x93%n8pjlag7nIV>#1{zbND(A$rSZDTxyYw zh0$}F=e)CcR>R)(cL-s4l>3;0-gMoCPQ;^ECiC8&XmFoCt1RMRZVk{EkM-2l?#0Q= zaoAp(Y0V?82Mq*CWlftAo2t0=gmHR!_#YNhGyV9oms#Frm?Czri%xTNB*Sp$bW+-> zt44Z)#+N5>EuL%GtW$T+wyb_}<`?1H8y=7HQM+ha3}CKq8n zn>LQq$-=D7)xEWIV>oM6!i95=YYm*@Q?jHw51uN!b5s*5Et`nDU`d_&mE1N{kB}J5 zrAo%#!D0Kpct*^L;a8zX^Z8Io*VV8SU*L%|-CS8wFM-@2k~^}~;`K9yU1(2e9N($ zVDM-6?L`fOPlh!Fb7WXTkt})q++z2!ttAmGqLJJ{NjoD-xENy&vg`cIoKP2;!pT@AsMKoZnxMtR zx^P7FQ?uWmnEs@hd+=HNhgZ!{iZ~tF76W<^IP_aRIN2JuPN~C_@J;n1N_pBU3A**Z zw~6l5t$A2iEjks>Gh%FXRASmQ;9%iYgo;EOMdKNv8?~I%@wpC@w*w)eSGO~a$X1!U z(dg`Lz11RoF#IEG4c2$ZvXPnC%|FILF&}ZCiI43R0-JXFUYAGPMKyDTj&hjs=H%rn zh9c?-;ZnF2;Zo~LaaAig_X94ajI-+<$_wuce?XNvnl#ImyvV4qW5MB;#*iEg^+t^$ zZxiXm79Qk(&qa%k=F0@pwo+!`n2@GPa{(%e_lw@IcNQ zp9~sDyxsQlT6!edGAfur`nLF4qCA{#Zx92Se~Ofv0?qx|y5)De9y1>fL!L`GV*48| zp~%qL_E3qRx6+FahSX}ZvS)>yhVXgUc=?-1OLk1P*JXD*XdMX#oxAT~B_K~#i*@1p z(zH5C!SH7y6%#t}>m(jZQx3@#epx#stKw`JLxn6=b4J?7O?^1-*Ppve_mmgQ`p-)j z8@iqQsDYDFnw86YH$vk*Iv-7_BS-Oe<*$1EuX|U-;cC;w@fR$rq@Y){;1D*8)O<4< z`&Nc!Df|LBhA?ERa-{VubNi!m>i>{7HEG_@TgZ4rKnayCQMjM`)ZwX>gl`O>7Q@?_ zJeh!MuI%e<4+CK9+ zA@gLD=<~VACFK8BQ}%NXIY;v_;$vgTZx)6nA%X*Snxz~pikbeyS^H>bvZf(c>gUt$FVAf+tNt&Y-{KYHxG#J+qzJC{ z64b{oZ&+B%;ZE+56Xp3N_2R6=T}$*6`FW5h+_~Ik=9Sv@_%7*|!6x}p)X%?5LD6ir z>s+tzV#jVs7k~Wk=I<@~_uzjU;BA+)O;?#$uiVbsRlq*Kq?uoq4fp-$p$0Zho}qNlzC?cw|M%ZsJ z(fbE9zxTOA>~T;yu-)Ag>+4E1i|Lp(#Pjv_`2&U=!<{QB(S1t)sc7v#64Icn4}Wrp zpiaj;o0Aiq0j~|QqxAEB&)xUef4Btj922qIKfMWf%E`Use|i(}E>&^hJtQe!Tkxuk zNuE3G@9m@S+#j(w6euCl!uY?LE{CWX2Y0hZ!^{4{zc!g)d*HphpqPA6VC~c2tk%yf zZrCqHwjaG9!_OD}KIeC)>E^xTOmJ!Qot22~Rip2%yuTpk9u2+8`_E(j|G3j&URDwzWvD;@`&McRXbU2{8*mZ{2h}a>{z)!3?Z};3ayjJ*$XFstE{_r0# zHzzdy4?O#e$y@B(i(<3jTU!5JfD4bjp%sobTvER~Id71a6DyR~c*RbF?Be`LkWI~Q zjO5-Yr2k9oe@{-3NIvcW*6g;+jdeH+lNR%nL^0BXJhdA>{hvnO$5U)R)=9*uc=|W} zEj;dKKvK22pZ@NEjN;fS)OuWgC`L!2!#;|ACW+6@F&FGj8BEqfVbaeb+yOKWrgibIU0PQRcY||jm}COK zIEJ8)MQ>)vf1r^Gcz!yzeC2?mF&}}VD-A~@{+ln%z*`8aMvYJol;~T(`4WdB zKZ4@caTK?lVN;BbWlZnw1j z_CSflHBpNI=Pjv_ zla?0}23bYx!!NxI+GSbO;Ibz53~3Zb{krOiixzIq>-uZm$*i0G-Vd4Om(DxW+5)ybTtx;A`u9lq-|IbT@KvUtcy{)7v&&epY7>yh}_slK(`bt6P~SIsqAWkbWJHMJ;Ro+VyB- zMCa_XPuO+;xps|xw*3RIi>W#I1H^Y;@R+`zOuG{l?@v1pKjbp&BgwAo!F7kbIN43S z&#c+8zuavysnyd&%xi5Pl1@>U8T0S_td$SgHynrOTc#(m`A-T^@t&8z=q2*TD@CC( zyz$l-{AIY9Q5yCrI8docKTJQPX3qIn_V6!GxT1Un+CMczBsBCB;JqlCIQ zQ|zPuE`$n^RO56D_oXivUaaBqFVd~H`%njpL-_2v6 z-d}io+3@{IE z{WO&{!TV21Hzvw+grSXhVnsd9t1bD6mHrJ7S|o#^yiI;NTBxg(!fQk0u+nqemN7*R zE)V4qH2xh*RJ6ARa6ti_?D@{*n3t%i5J!|Y=PR)JPVu8^I#~zw^~=r#1~o}Cw=GV_ z$GOo{EXr~}A32ZX)1AoPJ^R&dc_>>6V%3qtS3Dmj`xniLJ_UUX_2ZOHiqQZ1rW0IA zb|0zG6h~nm13dh)$@e8fc#Y6S;5MBlYVs*i!(e%uiCqY0@VDE%g3k$+ES*&JEV;5WhO+!@KGIN0mSI zz8JRJpPpE1(%#h;LA+S7K&CVGUgC~brUXC+ktJjGKkN+$e2z;Z#`M==P5cKAh(9Xr zNf|l(q}4p5)~Jx7aqse4PD*j`BqvlzD&hLa_wx#ghOi|ux8qOf#JtK*TjN+_5t`N( z+mm2#OgniZIw2QBLZkH`on->gQ~%H={OiCHeS8xu+f7skHApb@i7W&WR4tyrpXg1( zem~zyD2AZg7w)L>2%4qDA-aEkIIOyV(s2FkczX(;{4Vc+;_Y0m!L}7nm zoShVy6TbMQz`vN)n;~sLl#L=|1uznNpkHzpq6q#cO{#s&EPpekWOx76N$5eku&X-a zJraf>4D!e~CTMspAfh~vN%y+a9*A^U?USjzyFFEv=(Ig4Q>mi))0lrckcI2vg!8W* z+)fp=@Z=L*N^C|>>4`^h3+I8c!r$s?92D2a2WYcg99cp zu}~5e=`;WnYI1$3!xR7>Q<2jC3vLOvU^w(D@lOgg&xYjPMXkn)SV7}{TE*DyepLVh ziL^=yr(ANtp&EK1BDx?re43VhLGv?m*#Xi<@0^+x`s)cC67=C=cF8wrs6SjEZtplX zsB=;CJYT0jySmsdYyi*g_#hRu1Wpu$>5OA+g{BKR7d`KNHzJ>|g^ZF!0gMc+~s$W#A>VTgR!?c`o8)N+wLlj1$PQ=e^^Po^EBKmZ;#pFnm-dNr!V{`I-u>385$ z>mvn;gU4kYKPTAdJ1`r?UVpj&VtaZSq4fW(1@PZFtNP7@AK+xl&7)Y()qD6NtXEo% z5gE8BOpeP&5Gh2FiNuoqxTe9>08{i0SBzPe`ln5r|H&pf4y1bK@-*l(55~IQGAlKB zUWTKksbl-M=P1O{bpqJdfDFA6d(lIXr&XGvN!X+O6J0QGU_Isx`d9p_@%qLQzcDW~ z2cV5+pgE+`+EcBLBo zDBD*XWv8QbG3=#)_Ur@ZH9E?eZ59%1Im&58TS! zk-N>*#ovCitN(-8VWL7@uzro*w@|8Y9!IPwnj_!|s|G0CYMxZK%cu@r>XGL|Kv4Yx@AtL=@RBm;UHxs@<<2-c4*ZU{%!y9gbf{W& zE~UUtr=->PyO@iSo2LfklUla1T$?*cY`e!Oj!CBa??^__mRSt#4ZrPgs{ zWFW-gAF7S%R9e!e2|16l2A=(q3P|3hPVl&7|1Ayq6C0KX;X3EBys`6qPP%8Tgdbw3 z&mE+29=L^lz_u;2Snwp_{(rEVj{xq{R|n?oMOKQhFa0y$rcN>UQ@e>0BR?lUOwpY_ zq22Fn?T)v>Ric%S8{ZXb$Hgw!RpFx4lDSNW*uoJ0m?9d`GYxw(_dgiWzviHr@4#a| z)UJ6jOK|2j$>`{Y7S%7Tt-?`M);&U{fA{`j!6 zd#}J7*fw&r*yiNgU}m;@w&Is>9AbX}KPs^2>|4!Me+B%MH;e~c$r?lQ@NnJ_<0eVDnh1$N!f)_`cf z5lg}CD2uZ%BlMXlZn$CsA+xmF8~>_t?R>Mi>Iy^B44C08L#mjUz9(!?ZWE*V4lJEs zmF(U?pwveaA0X|{_CH!tZrozt(`5!6WWFq4 z#Q`M}3imweb$qyA^hASH#o{%y*A;9Z-07$UkgBq4kDGhv8d)L73Z#@3D_dWdlX{{` zJk0u1YXqy>QnBV7PE&7^!FL*q2S)wHdujMfrCgnDHrmxeG+%S(Pf*8=AQ3gVE7S9V zR%u()>Jj~psRp&=e8UHu6$~!Tm&7NQu*jA=R4@L(Ifi3fFWASH-OCi)dVyXy0{C>> z`m+@#W?{MJ11e~e-R*m!~uJ{OyU@$eY@6phBWWw;?g8R{wKrEq0K*b%f(Rsh` zhcj+HTQ~9JaO9~0<1291K4l5aOkx9UnO!|g9t-e~N6KWu06hAa1CZvRa8;g{Z#KCD zWCYmZ6oeUqD9XT7)IUff+|Z6A!}0V{#LUMmS_=*V4N+oOh^H?`4JL?w6y`t68^Q6q(%+ zPty{wfAz6HGAmLKVY}^_+A3Ph0SjXgd9vi9$OL5=R=?dD0K`o@3`r~clo5Kj+2i{901dX;Au~Dlns9`HZTCgW6IhlZ53oPfS?NO z=A-po{fulDER-}0gqSCNyL8m8b}qSL{X+>S(OJ_8!6BH0@Lpgh&yk8e7rF1_Iw z16P+9rkkUMqh`%vYyCFQPOZgpgY7&p4-FwWXenH#q3+k0Cy)YJE!&)jSV>Q}XTR#s zx~`HcS-GY-#!IDY`2G2#OxM2Q>$^zYBNfd0?uopINj1#A z2on^TFb5_w(UHh*upcT_=XXnOgaW=fwJmHUPeYEw;Bacb35ALtx$5;fL4I0N_dK5$ z5I{2PCs5!XShMU|Lap`7o-4FlpU$@I)&L0S|M)N&1f6*4Q^+s86+7(4Tgm#b!3_yR z1y9)v@gzIE1CoFeX7P5Bmb=-UMY~LTr9XX_HpNNjuo9#j_Mo4-MtK!zhc&m5IZM26 z4@Thc3V-QszBB*kXhQ**MPZ50mt~nQ^5;!BWJ!I=-1O=P&(ev-JnJe8MqeXhpp=$? z`hcRUp23J3ya+=6SSvY>>qCsHXZ!j`qEAZh60+%#*c>q#ZX|G>Qh&6d${giBb zw+V*c@NE9Wm~D##77XGy&Z(ondUbWuz>HEoPm6VuYZnOh94EPh@ikwzDUL~Ch5Aoa z;vagN&nd_#G#cAcgi;pLq}v1038`*!1{F|^$an!6BW|9Q;vF0$KEm%k5=I-A3T^NL zf60I^l9P)a{x(8E)+cKp0w4gP^KkOmsb@0bPRFP@zEPvEY4&{E#rdAiYn< zHgdQ)-X;#VYkc=?FP@YPClG^thf%ew71Kp}I7Peb{K>2do40^ZIG%AlwzGPhd?;~HG&?$p0oczups95B)84O!k;!*frm5;oWE+67Sj9(us zPQS?_^~)HukEEdfHJ$z_I2GxvYS1j6te#&f^{+rmpW}^jpR6N4FtM~2QC0Nv;-qSh z$m`oZZU2ep3@khyKV#_Q+f9g)ui(GcpZ-Amsq{%wGuSly+4v(eKgo~ZqeD=G!bh2D z@qB-P+y=dc_u-B*u~SO}V6-4uaShA3F|iY2bUs9b)L-lfDSa|*CdNZhg|Oip;DGTZ zv!z0Y%y%M&`F-@y+gZPi!8XdX!{~sBT#zH-oQi>(WW;Fj8pwWls>dK=YR^i%o0j$`bEP4L}t5vMK^e$Wi4Nfm*tkr=nOn$aWsdS|s z?U&CejrmqFZvmv_wmLU;C~itWuGKFVT71m0K)lt-y1(heN8wK}s9nc*S;BAe6guzH zlf>y8!6m9~eozEFq8?<)q+ zxZR|BQO->`%|DvsIw2x%)6SDQ@t98USuvSuzK9$SNKGz$O<*@5d(baN*KV>iUE>=q zkgxgm&FjTk?vmtNWExoK{JDs>=FqjbLe4Me-kB>xD}WNLl(nNP^$a)sqO&KN8^PHA zzS|9J^^_A2&)xjiYgG&62KFSW{C5hRl&fPqvXt@jorkc=XG$6AU0L%evrACjS0Kg@ z?#d?-UCwqGt3#h#`o%^7@}B~4@ZT02{z&O5IB(c8(qjIFH!(QDlLVMB(KajIlRd-D zju>j$?xRc&7gt|zIy?wb3G)STF+6`qJ}0-nglJSYQ`yLa5M>9I8D@J5}Ws39l09xxnpi6DoDUZ z>Rs@JB}ia^1a$$-n|9_$WnAcGCt5Jf7wO^8SvPA>qV) zDwtjLYk>k-qU2z~;W#^w4qlb+tN)r4cIro!w0vAPg4y~KPKkC7{JvP)FcmDw{>#}q z?ZA7a8;q($tp}_9iSB3nv?5uDVqhdovvGybI2)Yi-mQJ)p>=`d4$d~gik-e&3P4{G z65&U2NLaY6Y~M?mt*UrLJlMNItR2V&wY4i!KTW9cC-k_FjXENsud zRA>?^a7$%z7&hKQiN$}HwT*TpCj2adR7i7wwV!;Wg1x=O{DE<6a3kxi?1nX1Kw&is zLwTk32wwFgS*o#-?PP_8{bB^4tYj`I-Y}Fs+UJ$sqt*rAuSqZrF7f`R6#)hS$}?7M zASU1feP8PIfdUm0{^L6nU_K|OKeVAdKtuzeAc1Q8t)l`!{~x4@g{qkh4%4wM1Dyf+md3k<<(RQ{DwT9XZCHBOpgY~}8+U5-E)z$da8(KDCQ4JvHnK<;O}mSm#gxdfsm(}%T=}Bl6`Ty7-hQD5woDu-n$26YWY&*Z|+vMR9nGcFLr8K z+3yHOJL0Kf`IZ1JLvW-U5E=wYlxKd<9KmTt4OeewGSrv7c4}5X1^jqS59fYsVVmMj zb3xHMDg>t2lQFO0?AW`U10bN=1y{Ic_t};Pow1A1^rqcRE>X)wUhD-mIbN3^Q{P$U z+rI0gof%yUeIC<%U;5xL$D6rj+MxKfUO^SlVxWZ;ivw#qq5p;g}8R#lH zKQKn#P-J|caA`U_^2&P3{u+$Mfz^mr^RBy~Zw^@R>Duq`*!a%akYZ8c?h;`&{4pYi z>ostrwb7zyLZ&`h8c0Asp=v$&*Gz~8bM8inirc$c7z1D}S5t{e_a2>8DgGM)hj$eu zncGYetP49v`}c++3fSlw@9O_;b53uT6_(UKqL^Y8c6?vHF*Jl68EB$YHWh(k2Sf(`no~x!)_zY-p_ahav zqd`671 z8+hX~SZ1$iC1pMq}A?b zUU>hH-vq}?4L&Lpb^<-{C{e)S#Tf`@OBcHhiJ5XyUG*LpjxjXdQ3KIHeu@L4JiXA) zazvjmdK*%hjwd1Tv6v%$HU!n3B>M zF9ko=7WwsQ5XIy4NC}uu{$s{8sv$>xWd8)VXO^kASKu+}O{raqq z%4Q3s={4rs8E6owM{t1M^Z|u(@N;DLuw8f->34WyBA185H(M2?^F`VEdeel)Pz$q% zwR$jsNKm99{jRsxs0EQ#mG?vAlOjFsjgbPgUQ+5_;+T_x4^jzs1Yu2deE3P&BWu&n zQl$#6=nDj|#G1?mG(IXbsv3Aixe`kwB9{k3XFq=Oy1w$|btwfxm&_D#ckOOHGv>Do z)0-^^WFl`E?qg6A@UBY}McE-ZcwQnUgQ-?ZWMduYS$KZhvq0z_y5Ky$T{XAEXa$yA z5o`{O!TR?Q#9;DhVK(B7sWmZ1cuf*k;db(JvnH6aSRT`@Iiy6eZ(_f^u7Zz53k?Gr|~w%G037<1#GL) zF&*wRs?$tcsJ1t`EVe~J_Wc#ZXZDaCUiFKdbX1P%6Ei8anv6%(8#ck6fz374A06DV zDQ7?oS>-(&aU8@GPKNpiwq+J0XD^Hy55Ue2z?IqhHC+nJOhRxs^bqVyZgz>#I~;GR!c zJwf+1a5;o_Q`kwa@whmumx{O@Yn{}A1T_D->RY4}3>WdkO*g710ivYdiJ~m<`9%C{ zfy$bNLbC@87l>ps$|w;!73P!?L=Vd9a9vIB4AzOTbBvHZli)d@2YNztC#aP7xYLgj zz8bSNMeBX>lY#_v68?crJMCGy*DI$P$tIn^1KshcB^^qX8n-2 zU{8<5h}F~Jv{W!CpPR=f+8-N~I=CFJ4R*GoCVH7c=g2_Q{~ zC07P~U{N;Y{6ggmj;ki>^a&$c0xWNlu`~XY1WxGN<-(`EuQlbFs-&CK zR11w`nz!sjRmBeb&p8cL6>i`Ry*2*XBSpeN)Z}oOdHZ9WG5dv1=_q47{dMP=4$7sg z6@buxpA@ar91DG26oZi58S2R;LPhh~qL*;{z)5z@Z1V-l%5RS^`C_Q+=TN6nM#Ykc zt3;76+y7r?_Fvf8>6gf+aqS*TVIHm5et8os`; zC;>dmc&%4Jn?%;N7NyYe^(;fi0*!03*@=Pgr*4!GOrgS89kr}4y567bj2+S(v?54Q za%XBjNkjFN|K6wh%(q5lJ1~DaOMVfs9qAvzU8YEDyA=y*9WJ+UCRtTGO2XMyf1W>m z@~*VG#OZ|dpfh4CA9cLdagV(PmgPAA&)7>+mQ(ReD{<|YvkZ?EC!O!)Q$NR3VYY%>2nlfnL^8adA-FY+R(BokDA?-D*(4t|~nWw`j zrbpU>K6`*86%Zs8EcRz!9J=lFLXem0--$5zo6zgXOqg8Q|2P0gLdE|q{p}qZlDb9eac%_R?zEd}9ySR+;3Frg)uzf#V#4s3 zI=m=gUXQWRkdJWWc5!>VzqkGyR+l%>VbdNIE$s-6IfvJ*HxVVYnz7||I=qn1V8u50 z$fZjQ!ULCkgQywgNm)o#^@e?hKk)L}R555gNMdVp{c^W;nsTc+B@ta)Hia;e*mp_p z7y0Z)udfs|YpFl^4gS^=BT)h)H-J5c z_t!6nOzse@%HcQO8)0lY&u8-VwVNf{DN8-sZ!T@&X7+O}rdirudg8?YBx}+DVGRfC zt3T@7liJ{%MHoUalCs&Duss1fjnWoryFPzKe|n4_vE~<6nyebNc2v@7l3@VxX%|bD z%u#bDg}SZI7uHSvZ&ER6xn8Tb<&`!yZx3;aMQaOl8%#A8zbX7-2*^oe6(Gev@l#%# zcxv%I68Notp#ny`>F1>VPhoaLa8 z9*6|<1i{MG2mXsSvODhb9j?P`g-i=Df)`J0MjnG~KoQbF&^OAkNe1!v89>o-3atZS zR5}`0%`pjm`}IeMc)VS&HMHu;OQ7ezkma1e;mERJs(K`)mNcEZ0Ca9|p}Cx@3#&3P zr(Pd}WPUDx31|2@bA(_=poon4=!L9v&!{#v|J*Zf&8LkC za)@f!8~YSqbL%@-(_J~*+nUR5y*kh>ispDhbA{QAoqboNcR*E{^?#|TmRJ=yZ9HUR|9&?BU(DzN^zO=Azg-*+0 z{nz6};i#fc)c@$cr8tf6R;!e-IAr{!v}R=j1lPLXo^{C5>YK7w)K(Yhc)W4LDQ;%B5{`o|ISDCUZMqFaji*huFd9`n(^9AlTEGD3g zsiXstz=-T;>1oKk<>G~Du^z9f++;>chM6$6*{?~u`lEi6OnueLg&L&uWNdavYQ4m~ z{p`%M#FUkv!h;H19)}l*7AjP>+P&Akc8aLj>(SKJ{;}*<&%K#99SL`r zB^gz!XI>jFmwUP}zN3>ReXIUy=5SMoB5&{3Ywp6??5QphdfhwoLzHM4o3p9ktO%*c*3m&&=tQ2QLhxc!^0l{47^72CuBM%Sw8C% zmp<~|GXfpqUr)6$|IbuWKC(PQj;j9gi0O)I;Yf@%*IeEnsei%3v$X96VKv>MQ2?x<;Ic^wHSy1s9ScrydW)h#ghLH{UdHHdC ztG5p>5us~Yl|Z;pdiTwJB}4;VuI;bvFS7zjj=$(yI|27}L$zm zj6Q!UG{vehU?#ewZoLD9 zcq#}7IQ8>q)d_Gt1)R?9%ehHOd?~t%+Z3bs1wQV%p@mu7+1R-OQnbXUV%UH(J{7xQ zX@z(01h+!3D9IzzG};DgyuMM3IF=TMvu`)JfV+Fe+H_zr=QPvqRum#9&^L9l`K9OP zRpENlEZzLe_(5}nN(2e8h;X=#xxD#$KRV?2Mu&wHTZPZ4({%Z^wo|p*CWtdXf;d$> z`;{KA7viemw|I}5`T0mc^s{@x&ijim<)PI_e9es6fO@NQ_Es45H|wuuxl38_{**9@ z;>mc#G>pPQmU$ux%uG#Rn3nx?gYFI2M%ela-M~a@UI|DoI5qMj+91?h?L^Y+5-Z^# zTI*+Ut=6inf#uW~C>BhM9lyVy$}9BKZ1g>YKFahc502b9O;3yul?N%T#>!NS=aT|AJXF2$$%(k~Z$ z95=Y*yBHyZULbm@px_*QEy5j;vH0B@cDF#_~Y4{n1+O+{mf8E+^7z?_t#GH5FJ9i%B;A!%T4= z5oHEkx=xVbK1)IR-7T==Ka_l@#CIHWFc*W?@33g0eldwKD@7Ld=89Rqu3pmbx#OJ_7~B5}TviZhNXB6@?S z_(geVTYFB(yX*1LYDAu!;Xxa>ZeHA-xH;W;cYJJKMP2Q=xuI8qP!@#c;RZnCGON#$ zAI$A@-o9**x{iL99rfmnR27g4yr6`1Y2^A3Zi*U2+fI~AlRof8`$bwgjFnZ+3uJ}V zf6FI1%wpu(jXgJHIP?lkQdrb)_=gfsrrsZZ_M}r_Ncz*+#$FixnbQc|ia@2s@9|^a zA)S1-0SQ(ROhuWBbUkL3Jv80p8w76gF}OpCLt(-I#yRxh-% zc>`2*9Hm!D`4_majU4*32Q$Vl)()}@Y8x)YiR zeAM35h`$|g?I=zdqrbCOW+&J>?DEVb9z^tvqi=M53rs=Y6vm;+maqS8Yw7)aG8n^H z8pFG;h5_5wf%skA8$8j~)_rW=4hpTK9(A%`;HLv47GaC&f3Oa%gOh)jA$v- zDXz~zQdq>ic!O8Qwj^uC!Hsnnz2GXd|mLsw5&v=mku9>|a%#W%KDC z<|imfLt@99w2eVaKr8HQRnhk$WQj1L1{1ERb7kUKRdtFx0^5IPT?c6D1H73C!_jor z3z^3CUM&czSZG3>^gI&mP6>~H>PP0ZZO!}5`dZRsh663|8$saVC$G?y&^-MZN_caE zY6Lm_P~Mrb4+T2wK!4m}l$BS#D%{t(p*0S;1UgkUhK6Afn)B-)YVVI+s4W~+n`?P^ z=wKX3R{d-6ik#%YXIOb4iL$8!ee6#|Sb`>Y76(3RCg`yH^4` zmE4Cn5cQ-*&pU~b1xePPJ<*mumrF@c&LhPYw(@mh;;GE6)=i-?*c~IE1bKYXOX9*f z7EdWfiftY1;$sm6srR&nCu!C@&?y__x)f*ss@)k6x9&^h80f2bXubeswuX@y|J0NS zLsK?Fj-CXZ@}}AZO~qQscAt-3c|l&Pob} zF^?blFD$4zaFwpj(BS6fg*>-ajmB*Hny;BOOa zkkcPQ0sG-2Z+(tdq^^A|oY&@@;v2Hs;%7iz z`O!l533E0Ar2IL0g-zOe82UdAGdMo%=l+yh|C^WbFK>bY@g~w<3*_IKo3{nOdQQnD z%Pnb1+Psvv5^&~1h?^wDft;H|${iV51 zkT(%fo<4%i%hN9L%d|_A$rm01#p~wPq7t5m%f;Q_A^KDEeoWy08;w>|{soM$420E7 zINJcr%(`9gj6&7!P6v(iA10hLT>)xtk>lDPq6?=p>WUYct5m`2%T>5gf|$}4FcTIG z;k3O$WOs-nLqP53Z0Ayxw%j@*-ECx}`aeCYc`Q*u>{44cO46%#Z#LGIN;TgOE$_~$ zc6Ea*zlIrPD7u`uK^i*~PoA{Y2q#j2>=0@M=|@#;xWwb@=tn;vAWo^Z0MIjhY~Y^W zAOAu@S+Py=4i0Pe(sh|FvPB+b(zcf5Yk0QvJ`T8RAl)KhN9A+GRTs{_$j56?lJP0- z##Kcg0nN_o)*#%8K)|qN0Df|LF27rY$cx35^38y04F?)D%VL|gyZ-k!FD<}w8ef36 zrogH@+tjR8Ax{m)h&S-5^7t6RvfUC$j>x_gLZpAY!6?x&l%^78-IX6Nbpx3U<$cmY z_Vp3aIp!yfWIuAgzAzAmx;}nHMj=owbBw%$qTrj1IrJ?c{6<2xfR9s zmy7d8x0V{lOKskuH(JPrWm;^<5iw7>-PrlB`PGcY;Gt|6CKH7yzOIW(e^(~|^uKBJ zF@fGWEiewf21K1>fb1oczB3MyV9Gm!@fFv~$E|JxlC;?)@owV_mwxTS{1dTc^`$5k zRH!ng?rmEO7zr+zKNy3P3_;z*lPT7_y)>i>_~Tyt36i6!o5A~qhQ7n3MyWODB$cGr zQ|`wZr@#2KED68m8dySK+AE;F3=;j2PPn)c*P3B|Se@+{hW!K?{&}cLCxuuN>2Rjb z;-Is1fZ^69;t?jvg5Q)4AXzQjqzzBupj&#&p5I@|HI*%ZP{F6*Jf~kMDXJh9mk3C| z<#=gZwl+ET<)FY{=K6kLaSfmhpq~>R(2zqd%0%2X_#9@e7@u+)dQ;!(@yc5+U=Nj$ zSJ4g~nX@s`*jsq&@wE*;xA&Ab&XJOIE8BIa|^QG50mD@S3g^?43&3Q;EAiRmpkK zra}2Si64#@ZYZ)ThfON5N7T-d$T#p$itqy{9g^GY9)fjn#kY|=M&F9?*p$%!GSz}4 z5?05mKZ0QBrg&6fu3m`GEmV^x8cK#l!+i--yY$h*}9 zTNzhXEZj;UqKq88}vk&h<}6TX2;7DNR8rzQxqJ^tmBi;$m6`=;Sikm zzG*B&IK4M|KhZg#nQD$oMyT~_H~Jzl_PTi#GlE5o3x6g3{@)m&+^0ITRziSK z6kD!MsW7+j*J=8iAyyFdulZ!f&WB462QS9~*@-RJjh}E@H~9*~Svw&$w;toxY^Rgb z8-DL08^*g{HFF2Tp2IG&x(F)Hg6SRey!Y}Jx~|E_6|4jFvGDK+N7`<*ck!P%t{IBI zL#&1wQ}|;vSg}}e3(bdLemU*!3@)|vn!vegB0VMQverp_5fDEmsHK}ZDs4-k&jt0c zyrM!Q`W)EY5;W?kT_m(pi@n@2O-<9^UW#1?N-z?zn#^k}z-fxIFOO9ZUHQ~G;Kwp7 zX4f1!&;5QT=+RE zep>__M{nmm6|OpXjd62?gdY7>*xBi?sJ=h(JlWSyRCke2Qtt~aV6CK-g2(RmjEEnZ zu-6J}eG8G$fk4f)OZb9c!)X%YzSLWDQF?ML*j9dR(opke3NkbZ&xRT50H418Ew;=#iuBBz#=Yz(y4E?Ft$}OQn3z*ZgKa!Y74&i8Ai+R z59O^yiIP%ToEKSeIvM}Wx!T%}`s(tJ&t5VC@d#g`yX5jpR7*y9=fG-H<~=3WNWD;x zAYs&ROnV`G2n~1?CB|K=5Ob#3eX0q!5~O4cDHLN1G1 zm4`pSHm40%s@81}8is-7px|!xjmCcrX4kw9F#6T5xv?LwCiaT|QHj|w(|rssP)ato zV@-kU-tZB=DK4P@eW5QsRsZVTow!$v(or|Cu}4^`LJ!dZ5ye;@(_+9I#{2o`a-@D1k z6qaebJKEHzS2MCbWNaVU8#e-zJvr0d7GkJH46CFXEsE<}<#u;I+PtmS`4zheUgq$2 zhDS=7VKB52Nh-7^OUOe2h)!-Aj1Go`l$P_lm#_cQTXKG+XZ06X@nFsQ#qi`o9vjY<$y!AW2$Q%RWJXFnY6mM*i!Wi zpfgB;N~0`aVZ&8jr^52N((+r#`%xxcEgy0#3g#GRL^I^khNpcKNCx-Q$t$`^hRodW zTReghYUKoZP|iltdfvA^Njbela>C2<39o=?6O9(MjoFf+WR~ecZ(yy=hNbXLaqazu z|CB4PnF((%en&*LAp8@r#4l$qU#mYdg7rD~Hi;KWL-Ab{aqLNCqUw(Tz7PTHZqL1V zvu~G!UXnRk`Q*s!ggvDbp$%Ss9saY00q~(Q0b0Eg!=vrdm9NR9;KKNim9)`y>o(KC zA8k{}PUO%tY;nv(lt)3=#lZnPZSmLfp;=yFVRx%#Yc~00l1N?h8%winar&8rDN!f2#N{HCOu>y%17mgwnX(?Cr z_N)56C!ty1t%TV+oT2x(u}d6`&zUvzd1LdJs6z3H_|;n|i#Q?7#7x1J4+KDrEzcNr zTVbA&G#ta?Y9gO`6iYKv@^ewh7kRi84d|%U$*KGhQ-)pWviJS7d#!!n)Ue_7txxZQ z{6<9Q(eDHI#@n(32~U2za{yv<-!*x!;MFvUBo*&Y3(3Mtb9+uZUMkV21f|$dkkX|m zu^U)vr6}UQnbMG*uiJb$1*Aa)7{>-}216IL^UrkUOHC`e7C6py@ZayxuxK~iU;~gU zzO12H6QFQ&Z@w%SFhgjM<^&&yQ!^64D+p`AAE_U zVGID#jJM0|zm_ROzy01nS}@1-uF-c--p~IHsPvyluq;>pZ8d62*xARS8rLEo$JOxA zd#)8i(5MO3OG}zI;U8H5IX3*@XEn{P^4u#beV?=V@Z;qQ=|D1mC~T^aOSb$T*-q5e zn#|SfHn08yao(d&Dz^m=Oz#DLq+6x2Huiz|F9kGiU22jk0jZM&6Vw@EgWzBn`%>wY zu5ne^Wie%@RW4J*H=57B=|G{~hid$~hOt(&BP$QNliyeSdeMc%f}?E0YijRw6V--g ztrD)gt;Sum>JhJ`__I!wr!|A(z0gZ8%fn7eep}6yM!S|oYJCVGk8-KCs1N|E0$^Us zy~xjh`1s(n+=UMS3SE>UaT2_=v&PqX)iuh8-Tab1>bSQ5R1VIxI}TOucVQ;$u(Hof zr^=8550;B?s;Px1`P=TCqf*mgIW{mljkc(ap%9rb3?KghGz-f*eu~-f3_+t7x6<6m zCg(dKj3j6VE1fI@SzL=~0r%kh-W2?Je1(h3t>C?R2a@gqvPn(ORglSrL-*jCdGSUm zuz-;qRxg{cWmuA@ zH)!e1s~!}%d3VU7#l4n zat1N4(W)+~1n28CtG{$=Lr9Zq0ggReS|!%G=VGDr*EGHWvzqfvCvSg-ILk=3ZoXPN z*<#dU?FrQ6onpO0GlEv%_+#^&0+6V$r1lX_WssJ=hEd$3gPd~%(K`ZsdDew<`AWRM zHXx91U=n@CBXW*?as@9)4_`aUY|8aoI=2m|kqm-V*SSNXgGRLe`fW5f^)OX25{HP` z4&cB35^K%w@irrm1y*l)`5`60vc4%%vljeJjnwCMZYSf#U_>xG1Fw3H6qrB)Q%~^E zFN~_4;+Uk>7)X`_%e4f4VlfDv8_&xRG~5KUcGeg31d=UwY^jLnZh?*=s)+dHF5_1q zI@0L{2ba*eMsy&U%ME6YY5L&sqJP6~(N#*Kw~7O!s3^7agg)N|$h4e>{Y+c2ql4mx ztt{P-;p{IdFQac;-Orz45(RuZ6QQjvgOwj)ns&^gHsctr))>H^9yxc{XzBS~k9bRY zfbkr^>j@omG+V@wRq(o>Fv(7s>zp?pLqU@#tLW_PlQGK0Fh$5KekQ@MAKdT%+{Dj{3A)K&x*=-^)LWG2!N$4!zJHclsf1CewO ztzrNL9MZ%ag+K2L*^XTEM#;94u@ZAgZpW;P-+;c&p^*|ms5r6J5X;eIno0O=<@B^i zqi198g6BkH$W*icEm-l#bS%;Ft2IL_em*H@KzPn^ru4|=W*^5~VwPzwgXg-$!f;`- z0bbMh=>uWns0os#QF|Xoaakefguo~&bfW04ZPmkXvIk3FU^wT5+PW3To4`MhHU~jV zf^3ZKabB}YMD1c?jsRL8Q_BPIDT9g*#Ko(Xm*VkKGKepKovISm@x!|}nQ`B!$(FGO zA1#_mLzP>Ap;Yd>lY)N;rc~Pko#Dwn zCwn%b6PeQnz46jPa44EC3^C>JZwue4aZup3UZETZ3kA*UA9zC@BfcRxjac8O0T z`wcb}M6ok7UE}u^12SNX-v@gg+cH-_k)F%sI^E4z5KQK6PKcA>)uYwQcI`T8z0ijP>KDl22on!s z)&590H6@|e$`}HbDNj*H)muS12CvWm#5E0RyhgRv=wN#ULUUZ7dv~_Zb#>*bT1wE|jUukJDgV&PMfLF^ z$!N7(e(ZOqKFk+26KV(%QI=ezbW*@rYFzm=voZFr%DQREo{QJ^`++bz7txX`uVeR( z!Hd)^_0mDs(u*=tPd6QAx{Dx2a)=bPX8!a6b$NV6mMVTt$ODQ`!cq9Y0lB~uU|8Xw z(lxu8DpXowA!HAum<9lv`?)}w;pt=$Gu2FTFpZqHKlvwKF=$iq0wSV_^s-}yerYWg zZi&LC=7Y;l$@Lew*rz!NI~1em5>U%U>1V6M(LCpbIgS5yEnffZo=0tIAbXRMHjE)}y3ls+U-fT=4=G^O}@z-!og z4`K9@#S!y8eI^VF?hrSPe=lgR81cVkF|U^dfjXlo;_{slFS?<8!0gIu(9!cal1D!w zTuEAe7Pj>ssHVF z1+Z1_n;+OkslB_;d0NI_%hE!&iKIoiFWpg`*N8cl#=(Qf&1{9A){55qa(reteJUVA@h)NnD zf^o2s&D`MS&j=_+CfrA2yOXCR@NeE(g8aOnG>9BfEhI~3|3qb1^Fz;{6CO)ELkyy1 zP`X`iE6*TFNGSx3eY+dqWVWjfbiC5BR5&O1BM`npTcx{HGZ^dlOGlqr`(TOK^RZeBYPaRzP}?= zMB`=qfICWG;en-yd!ICDHG7y0T}qLpZRL64DY7ZvBvX`CLtihzn336MvYP&E|U+?HuPD`qDn(2|2vWzqNEpYzk|3FaPwej4Mne06!&otCY2>}XX^hJ|7 zo06uJ3+VIymQ)z4hc+;@eJjiNN<|)U4m{u>-nvVmVytqyYpStJ|D15*NyXek)Zz}~ zA~;Va^`R%c0@vutqhEGx=##&u6qG-%ErX875$Njm z$I~PDj}i!&JW(C(_RYS#072?z$3U+qay9ZO1wpQL^`{F!L(Fq8UN5B`itF<6RlF`z z!tvUNz5fW12ScOW_4*Jn9CU0_MFIpjW5y`xJFhgLuxHh(S4>sv2mUr7$?`RsCpiZ6%qNqya zWN|d)McXxO`GuIK-(*+>7*`^b=Ep+-+Z5ebln`$mYzQOvFKS~@7N*{0B6n*IU=6Y2 zts!d=@y=WDE0elT8bIoT4Ou5t2XD|=9=7ucMiGL%86LwjtnxSKljB`QcR$WXEHAnf zCgdfl{q~3Y?+o?7YDa_H5i|!A)P?P^?94y}fy?QsP)QIzrTDW~M?)Jy1z3Q5-XMhb zs_e%trjgX=+yOO!dYg{)>@&d%26ANJmr}pcsyfO`mRLgM}!KfoJTVXrr{;XUXzhz@A%?3aH zN5d(Sc`EYZ1C(E5cxVVpP-_mcMv>gyeaA~ww|mpKM^cygZP8d&(_G4o?MTUoO|#cO zqB@R{SgMx(G*MC0@c^~YMp99!%ZN6Z$J?;uo81KDR=kd=c4iX{tjJbKfq0m~+Gbmi zcxSdcyc_ku&2fCDrwC#L3rM8~CdX(@DV6Eac;KhFz4SXkStV*B#};|YePn&!Bo*#2o_0W{ZEuQjpV=TY=$m#J$Q8%?>moXS}+h32fu-dPj2db9YL#QoccNsfg? ze}-Oz(KAEFn3vM;xwwC)fsX4ozi#_Rbi)o!%Y(GqOy-(y(9D=voDJ%Fmn&@gD(obO zaa|3gvtHiq$}k3e+T86!5S-O8xrk0;_OwCIsrxa4ms7vR(9v*0n}V215!G9h>=E;Q=ktGSsy$28np z;{clVBD*o+i(3iV&yIeRU~N(Al$X>PXE<_q*lHYx&xq6c6VsZxOKDPu(2IH9hM_Bk zC!+kTR=$y_#QaVAZVG;F?lFzp9|k9XZ8qj-;y*%*^6O(RC%Y)S2OC(_{&iX!%i#Wutzl|QPl!mY%Mn)bBCTu(bucGTS z;qjnl{;)b`Pr@ddC_c19iy7(2{JlAL*BSHRg0B=oPuPe_qQOg+bz2M6KEsDE)^D&; zRW)8WuJcs9z3$%BWvFS64P{!#*U7tm1BtB67W8fe)l!bl0M=o>YAG)q2B=G-8LC)Z zTHT(@(wf^^+uqo>v_}>0>jr@`k%$}TRx;kKr5})_q1kN~o?8c`@ zlce~jj$`<34r@oSyW~D=fKb-qR;zkR=jUtJ`x0A9=w{7N03lhtx_wi}l=8(MiL~l& zLhIajBwf(x%DC9!kMM?X6gXo@^7?i(-$pG%rYcJ54W~Az2HA{LT67aRC0g9fXp-$b z=`0Jr?kWEDXkTnG!i z%`~*zl*kN-t6qaF zshdSt9sr%^v+l%JW0YLEJ376UZH7?n<_yQa-oNsiugKn&mRh!O>&$mx`+4d;4B`es z`hb;EVN4q?P!*vx)&PioJ^aBgC{tH6=!(KuUtG{sJ))z$o9M}1V#;)m=&9bW)TLr@ z6yY=Am_L}T`wa`F0P}3&{wdybdO428DEm2uy>l#3>-_v1*H;s5P|M1oA#qQn8xnBE zjWtSnw!2XF)vmZ{L>!B?!Eq5!@fKVD{R|HeeO^d^2NoZm#z?{;00Pt(%0Hk1X6-{J za^+@!l5%wNjiJTMxOI4>VT3!Bqu&Z?{2!sQ^t-;)C-5InHMV`96VzIomRPqaryB*v zm%-bTk(+`!jymKJfQ!L{6FcZn7Xan9x4iP}c|jGJO!y4$p(*?vEb&)f>k#`q;r7|T ztLGq8o7rH;Mb*U=)joIXNkzViia%roT!;$tgpE`d9Wm@OlD}@TAe&>KPO_uesCk`# zv0XV(p1ITn!eMlxI^?YnuD9=PU(h1I>or#6?qs~G{v`C*H!({4QZ^xxFFf83l-=$Q z6MhbqibU6e z2gpaDT2k)b1ls{meA846Gf=>yal;vLw}2}IO8LGX|lUsqL9RLvHq)uQF`KdHhuz1hmxsH+2h^W0m1s0rpd%DpD@}2eQj^`4kfnX<9SrA9>KX?|a#wBi!qgR> z0KZmF?7jxDlyRA+SDt_X(jdsEs}x5J7i|fSbI#o}+7Fl{o0zoJOQh)ni!u>e;wBt6 zE)CWA7e49zN=oOyfc=S>UbtUcJ+mX=wHlvxtHN0aFP^YVTQ+F7hAn@qsOJDo{(_Q| z3ZjG0R!R0Q4cSi6T1z_M2oPPkdMtEgg+vseGU6_RL<$2a_ZPIgRTTCEd+5N_AIEK2 z#=S6A@#_eH&PeDlyW{r)Op!Q%N1|z5PluS7wFXEFhiwUyCJAh>Qii32nwcMrr+0NA z_r07dxNx1q-Y+y1>|N!O@(U%Ra4ei@=4TO!%{zrg^7~RWpTRaFqI=$#0x*;koO1j} z(*p?BaY+vwKvczKF%E7zI#@gOjL4HU^eMQk0V4%jyTGE;3P7QHQ;x~Q z+R54jIr@E@o~|pUL+7}_Fl&A(oDz!~-R1c%7o~*>tOSBSe1LjI2#nkzlN>Q-%-W6Q zdG^@X?QEf#YnpV8VD@eQY#DpZ#>IFAkOvC(Z+gJTHTq2Ql#h}HPyyuIzv+MqXv0{6 zC;nmzXmc1G=UMN-r4vdCX#M=qOS68L{vhGHYVqDAW$+zgLP1X-s8^6UCs(nl4}UP6 z(K^E{iSIxCp-&U?p>W@(#@%qra^1gw^Ix{9G+fn;4VWh0fPSX0a`RH!Q^qO)k9tAc z6v*C4eqANzngR%uDP#=Bvwem$fv_IG%H|LPEDFBl**&JX09?UO-jib-I%P16e%w;2 z*}z(=jXqI&)B@CgJr^mR9@s9;N_=4QIX$}rF=R)tptEqiu!m*!)J$VO+%=+3K%0IM zb8;RaVIez{`5Wx(%GahA-Ct9zEt|dHLRsYHSEm2riL2U0k zITAyKo(a@8b2xwXUT|5qYvj-Nk0GiUE=df8yj9Ak#xiZ;z|7RPh;OUmN;O4gS25)m z;eQ7}o0;d7ocs)EABpSy5WDpuf+KwCw~S)O)w2?Yp@IFXV%>oDDhEN#n27;#kGqt=dYO+v4DJ(msXm@Pan0jT~6 zs_ayUsirGyr_eDCn(}JR_tJ21?A<`btKvTV9t`loCdB&hL138zBoR}0CPVOR>O18t zATYfGxmSKBN*+8Qe^sNBOuu;ke$U#(x*kLV%X2^!u?CL8k>+~JvzO7woU*4l*Wj3? zoakQ5!58>L^$bF4RCCU37KW1s@u#cA1NgHRj9-ges5xHaewfGkU{6o0!ADKaZTX_- zEht|v0`(rCB!C-v0Zs}&vV=nLCi27DX{$aB!w}9?hR=Oi#=-$f8P34NBTV=q7Yhr! zpBH|D+7e{yTaSG;Kco*(bJnW>x7Hiniwq!ipxFTsP%kMR2A=CA_bD`k8AJ^@wX-N% z&wVS-f?i1AO#3zWg|pnbv