From 69a1c2fd2e0792cc25106686c6ec9a7d292e551c Mon Sep 17 00:00:00 2001 From: SmartMLOps HSE Date: Wed, 29 Jan 2025 16:13:51 +0300 Subject: [PATCH] initial commit --- AUTHORS.md | 8 + LICENSE.txt | 202 + README.md | 79 + build/Dockerfile | 27 + build/pipeline_validate_results.Dockerfile | 29 + controller/.dockerignore | 3 + controller/.env.sample | 67 + controller/alembic.ini | 115 + controller/alembic/README | 1 + controller/alembic/env.py | 94 + controller/alembic/script.py.mako | 26 + controller/alembic/versions/6b877d2a07a9_.py | 32 + controller/alembic/versions/8430ab0a47af_.py | 30 + controller/alembic/versions/bc8a32d54029_.py | 32 + ...pipeline_validate_results_requirements.txt | 2 + controller/requirements.txt | 17 + controller/src/apicmp/__init__.py | 0 controller/src/apicmp/config.py | 25 + controller/src/apicmp/handlers.py | 1051 + controller/src/apicmp/jinja.py | 21 + controller/src/auth.py | 67 + controller/src/basic_resources/__init__.py | 0 controller/src/basic_resources/deployments.py | 64 + controller/src/basic_resources/ingresses.py | 47 + controller/src/basic_resources/jinja.py | 14 + controller/src/basic_resources/jobs.py | 45 + controller/src/basic_resources/namespaces.py | 36 + .../src/basic_resources/network_policies.py | 44 + controller/src/basic_resources/rbac.py | 148 + controller/src/basic_resources/secrets.py | 193 + controller/src/basic_resources/services.py | 38 + controller/src/bound.py | 33 + controller/src/box/__init__.py | 0 controller/src/box/config.py | 11 + controller/src/box/handlers.py | 877 + controller/src/box/jinja.py | 18 + controller/src/cmplink/__init__.py | 0 controller/src/cmplink/basic_auth_link.py | 174 + controller/src/cmplink/handlers.py | 713 + controller/src/cmplink/keycloak_group_link.py | 136 + controller/src/cmplink/keycloak_groups.py | 612 + controller/src/cmplink/link.py | 135 + controller/src/config.py | 51 + controller/src/datasetcmp/README.md | 163 + controller/src/datasetcmp/__init__.py | 0 controller/src/datasetcmp/cli.py | 350 + controller/src/datasetcmp/config.py | 19 + controller/src/datasetcmp/files.py | 26 + controller/src/datasetcmp/handlers.py | 556 + controller/src/datasetcmp/utils.py | 26 + controller/src/datasetcmp/validation.py | 118 + controller/src/exceptions.py | 48 + controller/src/exp_pipeline/__init__.py | 0 controller/src/exp_pipeline/api.py | 400 + controller/src/exp_pipeline/api/docker.md | 16 + .../exp_pipeline/api/openapi-snapshot.json | 1756 ++ controller/src/exp_pipeline/api/openapi.yaml | 1256 + .../src/exp_pipeline/api/to-openapi-base.md | 52 + controller/src/exp_pipeline/box.py | 98 + controller/src/exp_pipeline/client_config.py | 21 + controller/src/exp_pipeline/config.py | 19 + controller/src/exp_pipeline/handlers.py | 57 + controller/src/exp_pipeline/jinja.py | 20 + controller/src/exp_pipeline/logs.py | 32 + controller/src/exp_pipeline/openapi-base.json | 1097 + controller/src/exp_pipeline/openapi.py | 542 + controller/src/exp_pipeline/pipeline.py | 1247 + .../src/exp_pipeline/results/__init__.py | 0 controller/src/exp_pipeline/results/main.py | 17 + .../results/validate_trial_results.py | 170 + controller/src/exp_pipeline/schema.py | 298 + controller/src/exp_pipeline/stage.py | 281 + .../src/exp_pipeline/storage/__init__.py | 0 controller/src/exp_pipeline/storage/config.py | 13 + controller/src/exp_pipeline/storage/db.py | 37 + controller/src/exp_pipeline/storage/models.py | 28 + controller/src/exp_pipeline/var.py | 508 + controller/src/files/__init__.py | 0 controller/src/files/api.py | 385 + controller/src/files/api/docker.md | 7 + .../src/files/api/openapi-snapshot.json | 483 + controller/src/files/api/openapi.yaml | 366 + controller/src/files/box.py | 144 + controller/src/files/config.py | 14 + controller/src/files/exceptions.py | 9 + controller/src/files/logging.py | 32 + controller/src/files/s3/aws_signing_libs.md | 31 + controller/src/files/s3/client.py | 271 + controller/src/files/s3/s3_url_notes.md | 172 + controller/src/kopf_k8s_client.py | 38 + controller/src/kube_config.py | 40 + controller/src/location.py | 64 + controller/src/main.py | 26 + controller/src/mlcmp/__init__.py | 0 controller/src/mlcmp/connected_boxes.py | 247 + controller/src/mlcmp/handlers.py | 617 + controller/src/mlcmp/jinja.py | 20 + controller/src/parse.py | 20 + controller/src/platform_app/__init__.py | 0 controller/src/platform_app/api.py | 20 + controller/src/platform_app/argocd.py | 143 + .../src/platform_app/basic_resources.py | 49 + controller/src/platform_app/box.py | 47 + controller/src/platform_app/files.py | 38 + controller/src/platform_app/handlers.py | 411 + controller/src/platform_app/jinja.py | 22 + controller/src/platform_app/repository.py | 218 + controller/src/platform_user/__init__.py | 0 controller/src/platform_user/handlers.py | 161 + controller/src/platform_user/jinja.py | 21 + controller/src/repository/__init__.py | 0 controller/src/repository/config.py | 15 + controller/src/repository/handlers.py | 595 + controller/src/repository/jinja.py | 13 + .../oauth2-proxy-deployment.yaml | 88 + .../api-component/oauth2-proxy-ingress.yaml | 46 + .../api-component/oauth2-proxy-svc.yaml | 19 + .../allow-ingress-traffic-np.yaml | 19 + .../basic-resources/another-namespace-rb.yaml | 19 + controller/templates/basic-resources/cm.yaml | 15 + .../basic-resources/external-name-svc.yaml | 14 + .../basic-resources/ingress-multi-auth.yaml | 73 + .../templates/basic-resources/namespace.yaml | 10 + controller/templates/basic-resources/rb.yaml | 18 + controller/templates/basic-resources/sa.yaml | 11 + .../templates/basic-resources/secret.yaml | 33 + controller/templates/box/csi-s3-pv.yaml | 41 + controller/templates/box/csi-s3-pvc.yaml | 20 + .../simple-pipeline-trial.yaml | 222 + .../allow-ml-cmp-ingress-traffic-np.yaml | 19 + .../ml-component/ml-component-deployment.yaml | 137 + .../ml-component/ml-component-svc.yaml | 19 + .../platform-app/allow-dns-traffic-np.yaml | 23 + .../platform-app/allow-ns-traffic-np.yaml | 26 + .../default-allow-egress-traffic-np.yaml | 17 + .../default-deny-ingress-traffic-np.yaml | 15 + controller/templates/platform-app/role.yaml | 34 + controller/templates/platform-user/role.yaml | 21 + .../delete-robots-tokens-secrets-job.yaml | 50 + .../templates/repository/robots_secrets.sh | 22 + deploy/README.md | 65 + deploy/apicmps/cors-cm.yaml | 13 + deploy/argo-cd/argo-cd-cm.yaml | 7 + .../argo-cd-credentials-secret.yaml.sample | 10 + deploy/cluster-rb.yaml | 12 + deploy/cluster-role-read.yaml | 46 + deploy/cluster-role.yaml | 45 + deploy/common/controller-cm.yaml | 7 + .../registry-credentials-secret.yaml.sample | 8 + deploy/config.md | 122 + deploy/controller.md | 211 + deploy/crd/api-component.yaml | 328 + deploy/crd/component-link.yaml | 195 + deploy/crd/data-box.yaml | 180 + deploy/crd/dataset-component.yaml | 139 + deploy/crd/experiment-pipeline.yaml | 392 + deploy/crd/ml-component.yaml | 270 + deploy/crd/platform-app.yaml | 195 + deploy/crd/platform-user.yaml | 42 + deploy/crd/repository.yaml | 148 + deploy/databoxes/databoxes-cm.yaml | 10 + deploy/datasets/datasets-cm.yaml | 12 + deploy/deployment.yaml | 75 + deploy/files/files-cm.yaml | 10 + deploy/files/files-svc.yaml | 15 + deploy/kopf/peering.yaml | 59 + deploy/ns.yaml | 4 + deploy/oidc/keycloak-robots-creds-ns.yaml | 4 + deploy/oidc/oidc-cm.yaml | 18 + .../oidc/oidc-credentials-secret.yaml.sample | 16 + deploy/pipelines/pipelines-cm.yaml | 10 + ...ipelines-db-credentials-secret.yaml.sample | 12 + deploy/pipelines/pipelines-svc.yaml | 15 + deploy/prerequisites.md | 112 + ...aws-vars-s3-credentials-secret.yaml.sample | 9 + .../s3/csi-s3-credentials-secret.yaml.sample | 12 + deploy/s3/sc.yaml | 19 + deploy/sa.yaml | 5 + docs/building.md | 50 + docs/img/hse-logo.png | Bin 0 -> 19353 bytes docs/setup/controller.md | 103 + docs/setup/files.md | 57 + docs/setup/pipelines.md | 71 + docs/testing.md | 32 + tests/data/cleanup/README.md | 11 + .../pu-user1/apps/app1/api-cmp1.yaml | 21 + .../pu-user1/apps/app1/api-cmp2.yaml | 21 + .../pu-user1/apps/app1/api-cmp3.yaml | 21 + .../pu-user1/apps/app1/api-files.yaml | 20 + .../pu-user1/apps/app1/api-pipelines.yaml | 20 + .../resources/pu-user1/apps/app1/ml-cmp1.yaml | 44 + .../resources/pu-user1/apps/app1/ml-cmp2.yaml | 39 + .../resources/pu-user1/apps/app1/ml-cmp3.yaml | 40 + .../pu-user1/apps/app1/model-s3-box.yaml | 18 + .../pu-user1/apps/app1/user-data-s3-box.yaml | 18 + .../pu-user1/apps/app2/api-cmp10.yaml | 54 + .../pu-user1/apps/app2/api-cmp11.yaml | 28 + .../pu-user1/apps/app2/api-cmp12.yaml | 27 + .../apps/app2/api-cmp6-cors-oidc.yaml | 30 + .../pu-user1/apps/app2/api-cmp6-cors.yaml | 42 + .../pu-user1/apps/app2/api-cmp6-oidc-ba.yaml | 28 + .../pu-user1/apps/app2/api-cmp6-oidc.yaml | 29 + .../pu-user1/apps/app2/api-cmp6.yaml | 27 + .../pu-user1/apps/app2/api-cmp61.yaml | 27 + .../pu-user1/apps/app2/api-cmp7-oidc-ba.yaml | 29 + .../pu-user1/apps/app2/api-cmp7-oidc.yaml | 28 + .../pu-user1/apps/app2/api-cmp7.yaml | 27 + .../pu-user1/apps/app2/api-cmp8.yaml | 25 + .../pu-user1/apps/app2/api-cmp9.yaml | 25 + .../pu-user1/apps/app2/api-files.yaml | 20 + .../pu-user1/apps/app2/api-pipelines.yaml | 20 + .../apps/app2/cors-test-env.js.sample | 7 + .../pu-user1/apps/app2/cors-test.html | 16 + .../resources/pu-user1/apps/app2/cors-test.js | 35 + .../pu-user1/apps/app2/dataset-ref.yaml | 19 + .../pu-user1/apps/app2/dataset1.yaml | 28 + .../app2/datasetcmp/samokat-lite/dataset.yaml | 20 + .../app2/datasetcmp/samokat-lite/v1/README.md | 5 + .../datasetcmp/samokat-lite/v1/files.json | 24733 ++++++++++++++++ .../datasetcmp/samokat-lite/v1/metadata.json | 31 + .../apps/app2/datasetcmp/samokat/dataset.yaml | 20 + .../apps/app2/datasetcmp/samokat/v1/README.md | 5 + .../app2/datasetcmp/samokat/v1/files.json | 24733 ++++++++++++++++ .../app2/datasetcmp/samokat/v1/metadata.json | 31 + .../pu-user1/apps/app2/exp-pipeline10.yaml | 62 + .../pu-user1/apps/app2/exp-pipeline101.yaml | 65 + .../pu-user1/apps/app2/exp-pipeline11.yaml | 103 + .../pu-user1/apps/app2/exp-pipeline12.yaml | 41 + .../pu-user1/apps/app2/exp-pipeline6.yaml | 89 + .../pu-user1/apps/app2/exp-pipeline61.yaml | 114 + .../pu-user1/apps/app2/exp-pipeline7.yaml | 73 + .../pu-user1/apps/app2/exp-pipeline8.yaml | 53 + .../pu-user1/apps/app2/exp-pipeline9.yaml | 51 + .../apps/app2/sized-default-s3-box.yaml | 14 + .../pu-user1/apps/app2/sized-s3-box.yaml | 18 + .../pu-user1/apps/app2/test-cm1.yaml | 13 + .../pu-user1/apps/app2/test-secret1.yaml | 13 + .../pu-user1/apps/app2/unsized-s3-box.yaml | 18 + .../pu-user1/apps/app2/user-data-s3-box.yaml | 18 + .../resources/pu-user1/user/apis/README.md | 6 + .../resources/pu-user1/user/apps/app1.yaml | 45 + .../resources/pu-user1/user/apps/app2.yaml | 45 + ...p-based-url-credentials-secret.yaml.sample | 13 + .../git_repository/git-source-repository.yaml | 15 + ...config-json-credentials-secret.yaml.sample | 14 + .../image_registry/docker-image-registry.yaml | 15 + .../pu-user1/user/links/ba-link1.yaml | 19 + .../pu-user1/user/links/ba-link2.yaml | 19 + .../pu-user1/user/links/ba-link3-dataset.yaml | 20 + .../user/links/config-link-robot-tokens.yaml | 17 + .../pu-user1/user/links/config-link1.yaml | 17 + .../pu-user1/user/links/config-link2.yaml | 17 + .../user/links/init-pass-secret-pod-test.yaml | 32 + .../pu-user1/user/links/init-secret-test.yaml | 9 + .../pu-user1/user/links/kg-link1.yaml | 21 + .../pu-user1/user/links/kg-link2-dataset.yaml | 22 + .../pu-user1/user/links/kg-secret1.yaml | 18 + .../pu-user1/user/links/kg-secret2.yaml | 18 + .../pu-user1/user/links/test-deployment.yaml | 28 + .../pu-user1/user/links/test-ingress.yaml | 39 + .../pu-user1/user/links/test-svc.yaml | 19 + .../resources/pu-user1/user/pu-user1.yaml | 11 + ...p-based-url-credentials-secret.yaml.sample | 13 + .../python-package-registry.yaml | 15 + ...aws-vars-s3-credentials-secret.yaml.sample | 15 + .../user/s3_storage/csi-s3-secret.yaml.sample | 18 + .../pu-user1/user/s3_storage/sc.yaml | 25 + .../user_registry/keycloak-user-registry.yaml | 18 + .../user/user_registry/reg-secret1.yaml | 9 + tests/integration/openapi/gen_spec.md | 5 + .../requests/app1/files_complete_tests.md | 111 + .../requests/app2/data/data-typed-bad.json | 34 + .../requests/app2/data/data-typed-bad2.json | 31 + .../requests/app2/data/data-typed-bad3.json | 30 + .../requests/app2/data/data-typed.json | 31 + .../integration/requests/app2/data/data.json | 27 + .../integration/requests/app2/data/data1.json | 26 + .../requests/app2/data/data11.json | 34 + .../requests/app2/data/data112.json | 31 + .../integration/requests/app2/data/data2.json | 25 + .../requests/app2/data/some_data.csv | 5 + .../requests/app2/data/status-condition.json | 7 + tests/integration/requests/app2/readme.md | 163 + .../requests/app2/resources_test.md | 25 + .../requests/app2/validate_results.md | 27 + 285 files changed, 75894 insertions(+) create mode 100644 AUTHORS.md create mode 100644 LICENSE.txt create mode 100644 README.md create mode 100644 build/Dockerfile create mode 100644 build/pipeline_validate_results.Dockerfile create mode 100644 controller/.dockerignore create mode 100644 controller/.env.sample create mode 100644 controller/alembic.ini create mode 100644 controller/alembic/README create mode 100644 controller/alembic/env.py create mode 100644 controller/alembic/script.py.mako create mode 100644 controller/alembic/versions/6b877d2a07a9_.py create mode 100644 controller/alembic/versions/8430ab0a47af_.py create mode 100644 controller/alembic/versions/bc8a32d54029_.py create mode 100644 controller/pipeline_validate_results_requirements.txt create mode 100644 controller/requirements.txt create mode 100644 controller/src/apicmp/__init__.py create mode 100644 controller/src/apicmp/config.py create mode 100644 controller/src/apicmp/handlers.py create mode 100644 controller/src/apicmp/jinja.py create mode 100644 controller/src/auth.py create mode 100644 controller/src/basic_resources/__init__.py create mode 100644 controller/src/basic_resources/deployments.py create mode 100644 controller/src/basic_resources/ingresses.py create mode 100644 controller/src/basic_resources/jinja.py create mode 100644 controller/src/basic_resources/jobs.py create mode 100644 controller/src/basic_resources/namespaces.py create mode 100644 controller/src/basic_resources/network_policies.py create mode 100644 controller/src/basic_resources/rbac.py create mode 100644 controller/src/basic_resources/secrets.py create mode 100644 controller/src/basic_resources/services.py create mode 100644 controller/src/bound.py create mode 100644 controller/src/box/__init__.py create mode 100644 controller/src/box/config.py create mode 100644 controller/src/box/handlers.py create mode 100644 controller/src/box/jinja.py create mode 100644 controller/src/cmplink/__init__.py create mode 100644 controller/src/cmplink/basic_auth_link.py create mode 100644 controller/src/cmplink/handlers.py create mode 100644 controller/src/cmplink/keycloak_group_link.py create mode 100644 controller/src/cmplink/keycloak_groups.py create mode 100644 controller/src/cmplink/link.py create mode 100644 controller/src/config.py create mode 100644 controller/src/datasetcmp/README.md create mode 100644 controller/src/datasetcmp/__init__.py create mode 100644 controller/src/datasetcmp/cli.py create mode 100644 controller/src/datasetcmp/config.py create mode 100644 controller/src/datasetcmp/files.py create mode 100644 controller/src/datasetcmp/handlers.py create mode 100644 controller/src/datasetcmp/utils.py create mode 100644 controller/src/datasetcmp/validation.py create mode 100644 controller/src/exceptions.py create mode 100644 controller/src/exp_pipeline/__init__.py create mode 100644 controller/src/exp_pipeline/api.py create mode 100644 controller/src/exp_pipeline/api/docker.md create mode 100644 controller/src/exp_pipeline/api/openapi-snapshot.json create mode 100644 controller/src/exp_pipeline/api/openapi.yaml create mode 100644 controller/src/exp_pipeline/api/to-openapi-base.md create mode 100644 controller/src/exp_pipeline/box.py create mode 100644 controller/src/exp_pipeline/client_config.py create mode 100644 controller/src/exp_pipeline/config.py create mode 100644 controller/src/exp_pipeline/handlers.py create mode 100644 controller/src/exp_pipeline/jinja.py create mode 100644 controller/src/exp_pipeline/logs.py create mode 100644 controller/src/exp_pipeline/openapi-base.json create mode 100644 controller/src/exp_pipeline/openapi.py create mode 100644 controller/src/exp_pipeline/pipeline.py create mode 100644 controller/src/exp_pipeline/results/__init__.py create mode 100644 controller/src/exp_pipeline/results/main.py create mode 100644 controller/src/exp_pipeline/results/validate_trial_results.py create mode 100644 controller/src/exp_pipeline/schema.py create mode 100644 controller/src/exp_pipeline/stage.py create mode 100644 controller/src/exp_pipeline/storage/__init__.py create mode 100644 controller/src/exp_pipeline/storage/config.py create mode 100644 controller/src/exp_pipeline/storage/db.py create mode 100644 controller/src/exp_pipeline/storage/models.py create mode 100644 controller/src/exp_pipeline/var.py create mode 100644 controller/src/files/__init__.py create mode 100644 controller/src/files/api.py create mode 100644 controller/src/files/api/docker.md create mode 100644 controller/src/files/api/openapi-snapshot.json create mode 100644 controller/src/files/api/openapi.yaml create mode 100644 controller/src/files/box.py create mode 100644 controller/src/files/config.py create mode 100644 controller/src/files/exceptions.py create mode 100644 controller/src/files/logging.py create mode 100644 controller/src/files/s3/aws_signing_libs.md create mode 100644 controller/src/files/s3/client.py create mode 100644 controller/src/files/s3/s3_url_notes.md create mode 100644 controller/src/kopf_k8s_client.py create mode 100644 controller/src/kube_config.py create mode 100644 controller/src/location.py create mode 100644 controller/src/main.py create mode 100644 controller/src/mlcmp/__init__.py create mode 100644 controller/src/mlcmp/connected_boxes.py create mode 100644 controller/src/mlcmp/handlers.py create mode 100644 controller/src/mlcmp/jinja.py create mode 100644 controller/src/parse.py create mode 100644 controller/src/platform_app/__init__.py create mode 100644 controller/src/platform_app/api.py create mode 100644 controller/src/platform_app/argocd.py create mode 100644 controller/src/platform_app/basic_resources.py create mode 100644 controller/src/platform_app/box.py create mode 100644 controller/src/platform_app/files.py create mode 100644 controller/src/platform_app/handlers.py create mode 100644 controller/src/platform_app/jinja.py create mode 100644 controller/src/platform_app/repository.py create mode 100644 controller/src/platform_user/__init__.py create mode 100644 controller/src/platform_user/handlers.py create mode 100644 controller/src/platform_user/jinja.py create mode 100644 controller/src/repository/__init__.py create mode 100644 controller/src/repository/config.py create mode 100644 controller/src/repository/handlers.py create mode 100644 controller/src/repository/jinja.py create mode 100644 controller/templates/api-component/oauth2-proxy-deployment.yaml create mode 100644 controller/templates/api-component/oauth2-proxy-ingress.yaml create mode 100644 controller/templates/api-component/oauth2-proxy-svc.yaml create mode 100644 controller/templates/basic-resources/allow-ingress-traffic-np.yaml create mode 100644 controller/templates/basic-resources/another-namespace-rb.yaml create mode 100644 controller/templates/basic-resources/cm.yaml create mode 100644 controller/templates/basic-resources/external-name-svc.yaml create mode 100644 controller/templates/basic-resources/ingress-multi-auth.yaml create mode 100644 controller/templates/basic-resources/namespace.yaml create mode 100644 controller/templates/basic-resources/rb.yaml create mode 100644 controller/templates/basic-resources/sa.yaml create mode 100644 controller/templates/basic-resources/secret.yaml create mode 100644 controller/templates/box/csi-s3-pv.yaml create mode 100644 controller/templates/box/csi-s3-pvc.yaml create mode 100644 controller/templates/experiment-pipeline/simple-pipeline-trial.yaml create mode 100644 controller/templates/ml-component/allow-ml-cmp-ingress-traffic-np.yaml create mode 100644 controller/templates/ml-component/ml-component-deployment.yaml create mode 100644 controller/templates/ml-component/ml-component-svc.yaml create mode 100644 controller/templates/platform-app/allow-dns-traffic-np.yaml create mode 100644 controller/templates/platform-app/allow-ns-traffic-np.yaml create mode 100644 controller/templates/platform-app/default-allow-egress-traffic-np.yaml create mode 100644 controller/templates/platform-app/default-deny-ingress-traffic-np.yaml create mode 100644 controller/templates/platform-app/role.yaml create mode 100644 controller/templates/platform-user/role.yaml create mode 100644 controller/templates/repository/delete-robots-tokens-secrets-job.yaml create mode 100755 controller/templates/repository/robots_secrets.sh create mode 100644 deploy/README.md create mode 100644 deploy/apicmps/cors-cm.yaml create mode 100644 deploy/argo-cd/argo-cd-cm.yaml create mode 100644 deploy/argo-cd/argo-cd-credentials-secret.yaml.sample create mode 100644 deploy/cluster-rb.yaml create mode 100644 deploy/cluster-role-read.yaml create mode 100644 deploy/cluster-role.yaml create mode 100644 deploy/common/controller-cm.yaml create mode 100644 deploy/common/registry-credentials-secret.yaml.sample create mode 100644 deploy/config.md create mode 100644 deploy/controller.md create mode 100644 deploy/crd/api-component.yaml create mode 100644 deploy/crd/component-link.yaml create mode 100644 deploy/crd/data-box.yaml create mode 100644 deploy/crd/dataset-component.yaml create mode 100644 deploy/crd/experiment-pipeline.yaml create mode 100644 deploy/crd/ml-component.yaml create mode 100644 deploy/crd/platform-app.yaml create mode 100644 deploy/crd/platform-user.yaml create mode 100644 deploy/crd/repository.yaml create mode 100644 deploy/databoxes/databoxes-cm.yaml create mode 100644 deploy/datasets/datasets-cm.yaml create mode 100644 deploy/deployment.yaml create mode 100644 deploy/files/files-cm.yaml create mode 100644 deploy/files/files-svc.yaml create mode 100644 deploy/kopf/peering.yaml create mode 100644 deploy/ns.yaml create mode 100644 deploy/oidc/keycloak-robots-creds-ns.yaml create mode 100644 deploy/oidc/oidc-cm.yaml create mode 100644 deploy/oidc/oidc-credentials-secret.yaml.sample create mode 100644 deploy/pipelines/pipelines-cm.yaml create mode 100644 deploy/pipelines/pipelines-db-credentials-secret.yaml.sample create mode 100644 deploy/pipelines/pipelines-svc.yaml create mode 100644 deploy/prerequisites.md create mode 100755 deploy/s3/aws-vars-s3-credentials-secret.yaml.sample create mode 100644 deploy/s3/csi-s3-credentials-secret.yaml.sample create mode 100644 deploy/s3/sc.yaml create mode 100644 deploy/sa.yaml create mode 100644 docs/building.md create mode 100644 docs/img/hse-logo.png create mode 100644 docs/setup/controller.md create mode 100644 docs/setup/files.md create mode 100644 docs/setup/pipelines.md create mode 100644 docs/testing.md create mode 100644 tests/data/cleanup/README.md create mode 100644 tests/data/resources/pu-user1/apps/app1/api-cmp1.yaml create mode 100644 tests/data/resources/pu-user1/apps/app1/api-cmp2.yaml create mode 100644 tests/data/resources/pu-user1/apps/app1/api-cmp3.yaml create mode 100644 tests/data/resources/pu-user1/apps/app1/api-files.yaml create mode 100644 tests/data/resources/pu-user1/apps/app1/api-pipelines.yaml create mode 100755 tests/data/resources/pu-user1/apps/app1/ml-cmp1.yaml create mode 100755 tests/data/resources/pu-user1/apps/app1/ml-cmp2.yaml create mode 100755 tests/data/resources/pu-user1/apps/app1/ml-cmp3.yaml create mode 100755 tests/data/resources/pu-user1/apps/app1/model-s3-box.yaml create mode 100755 tests/data/resources/pu-user1/apps/app1/user-data-s3-box.yaml create mode 100644 tests/data/resources/pu-user1/apps/app2/api-cmp10.yaml create mode 100644 tests/data/resources/pu-user1/apps/app2/api-cmp11.yaml create mode 100644 tests/data/resources/pu-user1/apps/app2/api-cmp12.yaml create mode 100644 tests/data/resources/pu-user1/apps/app2/api-cmp6-cors-oidc.yaml create mode 100644 tests/data/resources/pu-user1/apps/app2/api-cmp6-cors.yaml create mode 100644 tests/data/resources/pu-user1/apps/app2/api-cmp6-oidc-ba.yaml create mode 100644 tests/data/resources/pu-user1/apps/app2/api-cmp6-oidc.yaml create mode 100644 tests/data/resources/pu-user1/apps/app2/api-cmp6.yaml create mode 100644 tests/data/resources/pu-user1/apps/app2/api-cmp61.yaml create mode 100644 tests/data/resources/pu-user1/apps/app2/api-cmp7-oidc-ba.yaml create mode 100644 tests/data/resources/pu-user1/apps/app2/api-cmp7-oidc.yaml create mode 100644 tests/data/resources/pu-user1/apps/app2/api-cmp7.yaml create mode 100644 tests/data/resources/pu-user1/apps/app2/api-cmp8.yaml create mode 100644 tests/data/resources/pu-user1/apps/app2/api-cmp9.yaml create mode 100644 tests/data/resources/pu-user1/apps/app2/api-files.yaml create mode 100644 tests/data/resources/pu-user1/apps/app2/api-pipelines.yaml create mode 100644 tests/data/resources/pu-user1/apps/app2/cors-test-env.js.sample create mode 100644 tests/data/resources/pu-user1/apps/app2/cors-test.html create mode 100644 tests/data/resources/pu-user1/apps/app2/cors-test.js create mode 100755 tests/data/resources/pu-user1/apps/app2/dataset-ref.yaml create mode 100644 tests/data/resources/pu-user1/apps/app2/dataset1.yaml create mode 100644 tests/data/resources/pu-user1/apps/app2/datasetcmp/samokat-lite/dataset.yaml create mode 100644 tests/data/resources/pu-user1/apps/app2/datasetcmp/samokat-lite/v1/README.md create mode 100644 tests/data/resources/pu-user1/apps/app2/datasetcmp/samokat-lite/v1/files.json create mode 100644 tests/data/resources/pu-user1/apps/app2/datasetcmp/samokat-lite/v1/metadata.json create mode 100644 tests/data/resources/pu-user1/apps/app2/datasetcmp/samokat/dataset.yaml create mode 100644 tests/data/resources/pu-user1/apps/app2/datasetcmp/samokat/v1/README.md create mode 100644 tests/data/resources/pu-user1/apps/app2/datasetcmp/samokat/v1/files.json create mode 100644 tests/data/resources/pu-user1/apps/app2/datasetcmp/samokat/v1/metadata.json create mode 100644 tests/data/resources/pu-user1/apps/app2/exp-pipeline10.yaml create mode 100644 tests/data/resources/pu-user1/apps/app2/exp-pipeline101.yaml create mode 100644 tests/data/resources/pu-user1/apps/app2/exp-pipeline11.yaml create mode 100644 tests/data/resources/pu-user1/apps/app2/exp-pipeline12.yaml create mode 100644 tests/data/resources/pu-user1/apps/app2/exp-pipeline6.yaml create mode 100644 tests/data/resources/pu-user1/apps/app2/exp-pipeline61.yaml create mode 100644 tests/data/resources/pu-user1/apps/app2/exp-pipeline7.yaml create mode 100644 tests/data/resources/pu-user1/apps/app2/exp-pipeline8.yaml create mode 100644 tests/data/resources/pu-user1/apps/app2/exp-pipeline9.yaml create mode 100755 tests/data/resources/pu-user1/apps/app2/sized-default-s3-box.yaml create mode 100755 tests/data/resources/pu-user1/apps/app2/sized-s3-box.yaml create mode 100644 tests/data/resources/pu-user1/apps/app2/test-cm1.yaml create mode 100644 tests/data/resources/pu-user1/apps/app2/test-secret1.yaml create mode 100755 tests/data/resources/pu-user1/apps/app2/unsized-s3-box.yaml create mode 100755 tests/data/resources/pu-user1/apps/app2/user-data-s3-box.yaml create mode 100644 tests/data/resources/pu-user1/user/apis/README.md create mode 100644 tests/data/resources/pu-user1/user/apps/app1.yaml create mode 100644 tests/data/resources/pu-user1/user/apps/app2.yaml create mode 100755 tests/data/resources/pu-user1/user/git_repository/git-http-based-url-credentials-secret.yaml.sample create mode 100755 tests/data/resources/pu-user1/user/git_repository/git-source-repository.yaml create mode 100755 tests/data/resources/pu-user1/user/image_registry/docker-config-json-credentials-secret.yaml.sample create mode 100755 tests/data/resources/pu-user1/user/image_registry/docker-image-registry.yaml create mode 100644 tests/data/resources/pu-user1/user/links/ba-link1.yaml create mode 100644 tests/data/resources/pu-user1/user/links/ba-link2.yaml create mode 100644 tests/data/resources/pu-user1/user/links/ba-link3-dataset.yaml create mode 100644 tests/data/resources/pu-user1/user/links/config-link-robot-tokens.yaml create mode 100644 tests/data/resources/pu-user1/user/links/config-link1.yaml create mode 100644 tests/data/resources/pu-user1/user/links/config-link2.yaml create mode 100644 tests/data/resources/pu-user1/user/links/init-pass-secret-pod-test.yaml create mode 100644 tests/data/resources/pu-user1/user/links/init-secret-test.yaml create mode 100644 tests/data/resources/pu-user1/user/links/kg-link1.yaml create mode 100644 tests/data/resources/pu-user1/user/links/kg-link2-dataset.yaml create mode 100644 tests/data/resources/pu-user1/user/links/kg-secret1.yaml create mode 100644 tests/data/resources/pu-user1/user/links/kg-secret2.yaml create mode 100644 tests/data/resources/pu-user1/user/links/test-deployment.yaml create mode 100644 tests/data/resources/pu-user1/user/links/test-ingress.yaml create mode 100644 tests/data/resources/pu-user1/user/links/test-svc.yaml create mode 100644 tests/data/resources/pu-user1/user/pu-user1.yaml create mode 100755 tests/data/resources/pu-user1/user/python_registry/python-http-based-url-credentials-secret.yaml.sample create mode 100755 tests/data/resources/pu-user1/user/python_registry/python-package-registry.yaml create mode 100755 tests/data/resources/pu-user1/user/s3_storage/aws-vars-s3-credentials-secret.yaml.sample create mode 100644 tests/data/resources/pu-user1/user/s3_storage/csi-s3-secret.yaml.sample create mode 100644 tests/data/resources/pu-user1/user/s3_storage/sc.yaml create mode 100755 tests/data/resources/pu-user1/user/user_registry/keycloak-user-registry.yaml create mode 100644 tests/data/resources/pu-user1/user/user_registry/reg-secret1.yaml create mode 100644 tests/integration/openapi/gen_spec.md create mode 100644 tests/integration/requests/app1/files_complete_tests.md create mode 100644 tests/integration/requests/app2/data/data-typed-bad.json create mode 100644 tests/integration/requests/app2/data/data-typed-bad2.json create mode 100644 tests/integration/requests/app2/data/data-typed-bad3.json create mode 100644 tests/integration/requests/app2/data/data-typed.json create mode 100644 tests/integration/requests/app2/data/data.json create mode 100644 tests/integration/requests/app2/data/data1.json create mode 100644 tests/integration/requests/app2/data/data11.json create mode 100644 tests/integration/requests/app2/data/data112.json create mode 100644 tests/integration/requests/app2/data/data2.json create mode 100644 tests/integration/requests/app2/data/some_data.csv create mode 100644 tests/integration/requests/app2/data/status-condition.json create mode 100644 tests/integration/requests/app2/readme.md create mode 100644 tests/integration/requests/app2/resources_test.md create mode 100644 tests/integration/requests/app2/validate_results.md diff --git a/AUTHORS.md b/AUTHORS.md new file mode 100644 index 0000000..7b572d4 --- /dev/null +++ b/AUTHORS.md @@ -0,0 +1,8 @@ +Unified Platform source code is owned and published by HSE University. + +Unified Platform source code authors and project participants: + + Valentin Polezhaev + Anton Khritankov + Nikita Klimin + Alexey Masyutin \ No newline at end of file diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..90c78c9 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2023 - 2025 HSE University + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md new file mode 100644 index 0000000..cf38cbb --- /dev/null +++ b/README.md @@ -0,0 +1,79 @@ +# Единая библиотека программных и аналитических средств (фреймворк) Центра ИИ НИУ ВШЭ + +Единая библиотека программных и аналитических средств, +направленных на решение прикладных задач по тематике проектных команд Центра ИИ, +основана на **Едином MLOps фреймворке НИУ ВШЭ (Unified Platform)**. + +В настоящем репозитории размещен исходный код **Единого MLOps фреймворка НИУ ВШЭ (Unified Platform)**. + +Фреймворк Unified Platform облегчает и ускоряет +разработку и применение моделей машинного обучения и ИИ приложений. + +## Возможности +- Продуктивизация моделей машинного обучения; +- Пайплайны обучения и дообучения моделей; +- Развертывание ИИ приложений; +- Хранение и доступ к наборам данных; +- Использование облачных вычислительных ресурсов; +- Многопользовательский доступ; + +## Начало использования + +### SmartMLOps НИУ ВШЭ + +Чтобы познакомиться с фреймворком достаточно +воспользоваться платформой [SmartMLOps НИУ ВШЭ](https://mlops.hse.ru/), +которая создана на основе фреймворка. + +### Установка на платформе Kubernetes + +На основе фреймворка можно развертывать собственные MLOps платформы. +Для этого фреймворк должен быть размещен на облачной вычислительной платформе или внутреннем облаке +с наличием поддерживаемого Kubernetes. + +Для развертывания собственной MLOps платформы на основе фреймворка см. [инструкцию](./deploy/README.md) по установке. + +## Документация + +Для оператора или администратора: +- Инструкция по [установке](./deploy/README.md) фреймворка; + +Для разработчика моделей машинного обучения и ИИ приложений: +- Руководства по [использованию фреймворка](https://platform-forgejo.stratpro.hse.ru/mlops_platform/documentation) + +Для разработчика: +- Документация по [сборке](./docs/building.md) +- Документация по [тестированию](./docs/testing.md) + +## Помощь и поддержка + +По обращениям и вопросам доступна форма [обратной связи](https://mlops.hse.ru/support). + +## SmartMLOps НИУ ВШЭ + +Платформа [SmartMLOps НИУ ВШЭ](https://mlops.hse.ru/) предназначена для разработки и интеграции прикладных модулей, +использующих технологии искусственного интеллекта, +например, ИИ-помощников в образовательном и административном процессах, +в сфере управления, медицине и др. В системе размещаются интеллектуальные сервисы, +используемые в рабочих процессах, экспериментальные и учебные модели. +На базе системы возможно проведение опытной эксплуатации и внедрения результатов НИОКР лабораторий НИУ ВШЭ. +Система является площадкой для продуктивизации и коммерциализации разрабатываемых решений. + +Фреймворк служит основой для платформы [SmartMLOps НИУ ВШЭ](https://mlops.hse.ru/). + +## Спонсоры проекта + +
+
+

Национальный исследовательский университет Высшая школа экономики

+ +Фреймворк разработан при поддержке +Национального исследовательского университета «Высшая школа экономики» + +hse-logo.png +
+
+ +## Лицензия + +[Apache License 2.0](./LICENSE.txt) \ No newline at end of file diff --git a/build/Dockerfile b/build/Dockerfile new file mode 100644 index 0000000..25ae3ef --- /dev/null +++ b/build/Dockerfile @@ -0,0 +1,27 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Утилиты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +FROM python:3.10-slim-buster + +USER root + +WORKDIR / + +ADD ./controller/requirements.txt /controller/requirements.txt + +WORKDIR /controller +RUN pip install -r requirements.txt + +ADD ./controller /controller + +RUN useradd -m controller +RUN chown -R controller . + +ENV PYTHONPATH "${PYTHONPATH}:/controller/src" + +CMD kopf run ./src/main.py --verbose + +USER controller \ No newline at end of file diff --git a/build/pipeline_validate_results.Dockerfile b/build/pipeline_validate_results.Dockerfile new file mode 100644 index 0000000..9f7cccf --- /dev/null +++ b/build/pipeline_validate_results.Dockerfile @@ -0,0 +1,29 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Утилиты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +FROM python:3.10-slim-buster + +USER root + +WORKDIR / + +ADD ./controller/pipeline_validate_results_requirements.txt /pipeline_validate_results/pipeline_validate_results_requirements.txt + +WORKDIR /pipeline_validate_results +RUN pip install -r pipeline_validate_results_requirements.txt + +ADD ./controller/src/exp_pipeline/results /pipeline_validate_results/src/exp_pipeline/results +ADD ./controller/src/exp_pipeline/client_config.py /pipeline_validate_results/src/exp_pipeline/client_config.py +ADD ./controller/src/exp_pipeline/schema.py /pipeline_validate_results/src/exp_pipeline/schema.py +ADD ./controller/src/exp_pipeline/logs.py /pipeline_validate_results/src/exp_pipeline/logs.py +ADD ./controller/src/exp_pipeline/__init__.py /pipeline_validate_results/src/exp_pipeline/__init__.py + +RUN useradd -m pipeine +RUN chown -R pipeine . + +ENV PYTHONPATH "${PYTHONPATH}:/pipeline_validate_results/src" + +USER pipeine \ No newline at end of file diff --git a/controller/.dockerignore b/controller/.dockerignore new file mode 100644 index 0000000..a2ffe12 --- /dev/null +++ b/controller/.dockerignore @@ -0,0 +1,3 @@ +.env +.env.sample +venv \ No newline at end of file diff --git a/controller/.env.sample b/controller/.env.sample new file mode 100644 index 0000000..547bf14 --- /dev/null +++ b/controller/.env.sample @@ -0,0 +1,67 @@ +UNIP_BOXES_S3_DEFAULT_USER_DATA_BUCKET= +UNIP_BOXES_S3_SECRET_NAME= +UNIP_BOXES_S3_DEFAULT_HOST= +UNIP_BOXES_S3_DEFAULT_REGION= + +UNIP_DOMAIN= + +UNIP_FILES_API= +UNIP_PIPELINES_API= +UNIP_PIPELINE_VALIDATION_IMAGE= +UNIP_PIPELINE_RUN_MODE= +UNIP_DATETIME_FORMAT= + +UNIP_DATABASE_PIPELINES_USER= +UNIP_DATABASE_PIPELINES_PASSWORD= +UNIP_DATABASE_PIPELINES_HOST= +UNIP_DATABASE_PIPELINES_PORT= +UNIP_DATABASE_PIPELINES_DB= + +UNIP_BOXES_CSI_S3_SECRET_NAME= +UNIP_BOXES_CSI_S3_STORAGE_CLASS= + +ARGO_CD_USER= +ARGO_CD_PASSWORD= +ARGO_CD_ENABLED= +ARGO_CD_API= + +OIDC_END_USERS_ISSUER_URL= +OIDC_END_USERS_REALM= +OIDC_END_USERS_CLIENT_ID= +OIDC_END_USERS_CLIENT_SECRET= +OIDC_END_USERS_ADMIN_CLIENT_ID= +OIDC_END_USERS_ADMIN_CLIENT_SECRET= +OIDC_END_USERS_AUD=end-users +OIDC_END_USERS_COOKIE_SECRET= + +OIDC_ROBOTS_ISSUER_URL= +OIDC_ROBOTS_REALM= +OIDC_ROBOTS_CLIENT_ID= +OIDC_ROBOTS_CLIENT_SECRET= +OIDC_ROBOTS_ADMIN_CLIENT_ID= +OIDC_ROBOTS_ADMIN_CLIENT_SECRET= +OIDC_ROBOTS_AUD=robots + +OIDC_KEYCLOAK_HOST= +OIDC_MANAGED_GROUPS_ROOT= +OIDC_CLUSTER_GROUP_NAME= +OIDC_MODIFY= + +UNIP_REPOSITORY_KEYCLOAK_ROBOTS_CREDS_NAMESPACE= +UNIP_REPOSITORY_KEYCLOAK_ROBOTS_TOKENS_RENEWAL_PERIOD_MIN= + +FILES_API_BASE_URL= +INGRESS_RULE_HOST= +INGRESS_BACKEND_SERVICE_NAME= +INGRESS_BACKEND_SERVICE_PORT= +UNIP_DATASET_CMP_CHECK_CONTROLLER_PERMISSIONS= +UNIP_DATASET_CMP_VALIDATE= + +UNIP_API_CMP_CORS_ENABLED= +UNIP_API_CMP_APPS_CORS_ENABLED= +UNIP_API_CMP_CORS_ALLOW_METHODS= +UNIP_API_CMP_CORS_ALLOW_HEADERS= +UNIP_API_CMP_CORS_EXPOSE_HEADERS= +UNIP_API_CMP_CORS_ALLOW_ORIGIN= +UNIP_API_CMP_CORS_MAX_AGE= + diff --git a/controller/alembic.ini b/controller/alembic.ini new file mode 100644 index 0000000..8fdd575 --- /dev/null +++ b/controller/alembic.ini @@ -0,0 +1,115 @@ +# A generic, single database configuration. + +[alembic] +# path to migration scripts. +# Use forward slashes (/) also on windows to provide an os agnostic path +script_location = alembic + +# template used to generate migration file names; The default value is %%(rev)s_%%(slug)s +# Uncomment the line below if you want the files to be prepended with date and time +# file_template = %%(year)d_%%(month).2d_%%(day).2d_%%(hour).2d%%(minute).2d-%%(rev)s_%%(slug)s + +# sys.path path, will be prepended to sys.path if present. +# defaults to the current working directory. +prepend_sys_path = . + +# timezone to use when rendering the date within the migration file +# as well as the filename. +# If specified, requires the python>=3.9 or backports.zoneinfo library. +# Any required deps can installed by adding `alembic[tz]` to the pip requirements +# string value is passed to ZoneInfo() +# leave blank for localtime +# timezone = + +# max length of characters to apply to the "slug" field +# truncate_slug_length = 40 + +# set to 'true' to run the environment during +# the 'revision' command, regardless of autogenerate +# revision_environment = false + +# set to 'true' to allow .pyc and .pyo files without +# a source .py file to be detected as revisions in the +# versions/ directory +# sourceless = false + +# version location specification; This defaults +# to alembic/versions. When using multiple version +# directories, initial revisions must be specified with --version-path. +# The path separator used here should be the separator specified by "version_path_separator" below. +# version_locations = %(here)s/bar:%(here)s/bat:alembic/versions + +# version path separator; As mentioned above, this is the character used to split +# version_locations. The default within new alembic.ini files is "os", which uses os.pathsep. +# If this key is omitted entirely, it falls back to the legacy behavior of splitting on spaces and/or commas. +# Valid values for version_path_separator are: +# +# version_path_separator = : +# version_path_separator = ; +# version_path_separator = space +version_path_separator = os # Use os.pathsep. Default configuration used for new projects. + +# set to 'true' to search source files recursively +# in each "version_locations" directory +# new in Alembic version 1.10 +# recursive_version_locations = false + +# the output encoding used when revision files +# are written from script.py.mako +# output_encoding = utf-8 + +# sqlalchemy.url is overwritten in env.py +# sqlalchemy.url = driver://user:pass@localhost/dbname + + +[post_write_hooks] +# post_write_hooks defines scripts or Python functions that are run +# on newly generated revision scripts. See the documentation for further +# detail and examples + +# format using "black" - use the console_scripts runner, against the "black" entrypoint +# hooks = black +# black.type = console_scripts +# black.entrypoint = black +# black.options = -l 79 REVISION_SCRIPT_FILENAME + +# lint with attempts to fix using "ruff" - use the exec runner, execute a binary +# hooks = ruff +# ruff.type = exec +# ruff.executable = %(here)s/.venv/bin/ruff +# ruff.options = --fix REVISION_SCRIPT_FILENAME + +# Logging configuration +[loggers] +keys = root,sqlalchemy,alembic + +[handlers] +keys = console + +[formatters] +keys = generic + +[logger_root] +level = WARN +handlers = console +qualname = + +[logger_sqlalchemy] +level = WARN +handlers = +qualname = sqlalchemy.engine + +[logger_alembic] +level = INFO +handlers = +qualname = alembic + +[handler_console] +class = StreamHandler +args = (sys.stderr,) +level = NOTSET +formatter = generic + +[formatter_generic] +format = %(levelname)-5.5s [%(name)s] %(message)s +datefmt = %H:%M:%S diff --git a/controller/alembic/README b/controller/alembic/README new file mode 100644 index 0000000..e0d0858 --- /dev/null +++ b/controller/alembic/README @@ -0,0 +1 @@ +Generic single-database configuration with an async dbapi. \ No newline at end of file diff --git a/controller/alembic/env.py b/controller/alembic/env.py new file mode 100644 index 0000000..5cfa2cd --- /dev/null +++ b/controller/alembic/env.py @@ -0,0 +1,94 @@ +import asyncio +from logging.config import fileConfig + +from alembic import context +from dotenv import load_dotenv +from sqlalchemy import pool +from sqlalchemy.engine import Connection +from sqlalchemy.ext.asyncio import async_engine_from_config + +load_dotenv() + +# this is the Alembic Config object, which provides +# access to the values within the .ini file in use. +config = context.config + +from exp_pipeline.storage.db import SQLALCHEMY_DATABASE_URL as UNIP_DATABASE_PIPELINES_URI +config.set_main_option('sqlalchemy.url', UNIP_DATABASE_PIPELINES_URI) + +# Interpret the config file for Python logging. +# This line sets up loggers basically. +if config.config_file_name is not None: + fileConfig(config.config_file_name) + +# add your model's MetaData object here +# for 'autogenerate' support +from exp_pipeline.storage import models +target_metadata = models.Base.metadata +# target_metadata = None + +# other values from the config, defined by the needs of env.py, +# can be acquired: +# my_important_option = config.get_main_option("my_important_option") +# ... etc. + + +def run_migrations_offline() -> None: + """Run migrations in 'offline' mode. + + This configures the context with just a URL + and not an Engine, though an Engine is acceptable + here as well. By skipping the Engine creation + we don't even need a DBAPI to be available. + + Calls to context.execute() here emit the given string to the + script output. + + """ + url = config.get_main_option("sqlalchemy.url") + context.configure( + url=url, + target_metadata=target_metadata, + literal_binds=True, + dialect_opts={"paramstyle": "named"}, + ) + + with context.begin_transaction(): + context.run_migrations() + + +def do_run_migrations(connection: Connection) -> None: + context.configure(connection=connection, target_metadata=target_metadata) + + with context.begin_transaction(): + context.run_migrations() + + +async def run_async_migrations() -> None: + """In this scenario we need to create an Engine + and associate a connection with the context. + + """ + + connectable = async_engine_from_config( + config.get_section(config.config_ini_section, {}), + prefix="sqlalchemy.", + poolclass=pool.NullPool, + ) + + async with connectable.connect() as connection: + await connection.run_sync(do_run_migrations) + + await connectable.dispose() + + +def run_migrations_online() -> None: + """Run migrations in 'online' mode.""" + + asyncio.run(run_async_migrations()) + + +if context.is_offline_mode(): + run_migrations_offline() +else: + run_migrations_online() diff --git a/controller/alembic/script.py.mako b/controller/alembic/script.py.mako new file mode 100644 index 0000000..fbc4b07 --- /dev/null +++ b/controller/alembic/script.py.mako @@ -0,0 +1,26 @@ +"""${message} + +Revision ID: ${up_revision} +Revises: ${down_revision | comma,n} +Create Date: ${create_date} + +""" +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa +${imports if imports else ""} + +# revision identifiers, used by Alembic. +revision: str = ${repr(up_revision)} +down_revision: Union[str, None] = ${repr(down_revision)} +branch_labels: Union[str, Sequence[str], None] = ${repr(branch_labels)} +depends_on: Union[str, Sequence[str], None] = ${repr(depends_on)} + + +def upgrade() -> None: + ${upgrades if upgrades else "pass"} + + +def downgrade() -> None: + ${downgrades if downgrades else "pass"} diff --git a/controller/alembic/versions/6b877d2a07a9_.py b/controller/alembic/versions/6b877d2a07a9_.py new file mode 100644 index 0000000..1c5c4e8 --- /dev/null +++ b/controller/alembic/versions/6b877d2a07a9_.py @@ -0,0 +1,32 @@ +"""empty message + +Revision ID: 6b877d2a07a9 +Revises: bc8a32d54029 +Create Date: 2024-08-21 14:36:12.101684 + +""" +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision: str = '6b877d2a07a9' +down_revision: Union[str, None] = 'bc8a32d54029' +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('pipeline_trials', sa.Column('next_tracking_id', sa.String(), nullable=True)) + op.drop_column('pipeline_trials', 'status_date_time') + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('pipeline_trials', sa.Column('status_date_time', postgresql.TIMESTAMP(), autoincrement=False, nullable=False)) + op.drop_column('pipeline_trials', 'next_tracking_id') + # ### end Alembic commands ### diff --git a/controller/alembic/versions/8430ab0a47af_.py b/controller/alembic/versions/8430ab0a47af_.py new file mode 100644 index 0000000..a08233e --- /dev/null +++ b/controller/alembic/versions/8430ab0a47af_.py @@ -0,0 +1,30 @@ +"""empty message + +Revision ID: 8430ab0a47af +Revises: +Create Date: 2024-07-29 10:42:57.684023 + +""" +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision: str = '8430ab0a47af' +down_revision: Union[str, None] = None +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column('pipeline_trials', 'tracking_token') + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('pipeline_trials', sa.Column('tracking_token', sa.VARCHAR(), autoincrement=False, nullable=False)) + # ### end Alembic commands ### diff --git a/controller/alembic/versions/bc8a32d54029_.py b/controller/alembic/versions/bc8a32d54029_.py new file mode 100644 index 0000000..91c7edf --- /dev/null +++ b/controller/alembic/versions/bc8a32d54029_.py @@ -0,0 +1,32 @@ +"""Значения переменных ассоциированы с корнем триала + +Revision ID: bc8a32d54029 +Revises: 8430ab0a47af +Create Date: 2024-08-14 16:38:05.542362 + +""" +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision: str = 'bc8a32d54029' +down_revision: Union[str, None] = '8430ab0a47af' +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('pipeline_trials', sa.Column('vars', postgresql.JSONB(astext_type=sa.Text()), nullable=True)) + op.drop_column('pipeline_trials', 'stages') + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('pipeline_trials', sa.Column('stages', postgresql.JSONB(astext_type=sa.Text()), autoincrement=False, nullable=False)) + op.drop_column('pipeline_trials', 'vars') + # ### end Alembic commands ### diff --git a/controller/pipeline_validate_results_requirements.txt b/controller/pipeline_validate_results_requirements.txt new file mode 100644 index 0000000..b7e0287 --- /dev/null +++ b/controller/pipeline_validate_results_requirements.txt @@ -0,0 +1,2 @@ +requests>=2.31 +pydantic>=2.6 \ No newline at end of file diff --git a/controller/requirements.txt b/controller/requirements.txt new file mode 100644 index 0000000..6772bb9 --- /dev/null +++ b/controller/requirements.txt @@ -0,0 +1,17 @@ +jinja2>=3.1 +kopf>=1.37 +kubernetes>=29 +python-dotenv>=1.0.1 +minio>=7.2 +fastapi>=0.110 +hypercorn>=0.16 +sqlalchemy>=2.0.28 +asyncpg>=0.29 +aws-request-signer>=1.2 +httpx>=0.27 +kubernetes-asyncio>=29 +lxml>=5.2 +jsonschema>=4.23 +bcrypt>=4 +packaging +pydantic-settings \ No newline at end of file diff --git a/controller/src/apicmp/__init__.py b/controller/src/apicmp/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/controller/src/apicmp/config.py b/controller/src/apicmp/config.py new file mode 100644 index 0000000..f22f291 --- /dev/null +++ b/controller/src/apicmp/config.py @@ -0,0 +1,25 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: APIComponent +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2025 г. +# ============================================================ +import os + + +_UNIP_API_CMP_CORS_ENABLED = os.getenv('UNIP_API_CMP_CORS_ENABLED', 'False') +UNIP_API_CMP_CORS_ENABLED = \ + True if _UNIP_API_CMP_CORS_ENABLED == 'True' or _UNIP_API_CMP_CORS_ENABLED == 'true' else False +_UNIP_API_CMP_APPS_CORS_ENABLED = os.getenv('UNIP_API_CMP_APPS_CORS_ENABLED') +if _UNIP_API_CMP_APPS_CORS_ENABLED is None: + UNIP_API_CMP_APPS_CORS_ENABLED = UNIP_API_CMP_CORS_ENABLED +else: + UNIP_API_CMP_APPS_CORS_ENABLED = \ + True if _UNIP_API_CMP_APPS_CORS_ENABLED == 'True' or _UNIP_API_CMP_APPS_CORS_ENABLED == 'true' else False + +UNIP_API_CMP_CORS_ALLOW_METHODS = os.getenv('UNIP_API_CMP_CORS_ALLOW_METHODS') +UNIP_API_CMP_CORS_ALLOW_HEADERS = os.getenv('UNIP_API_CMP_CORS_ALLOW_HEADERS') +UNIP_API_CMP_CORS_EXPOSE_HEADERS = os.getenv('UNIP_API_CMP_CORS_EXPOSE_HEADERS') +UNIP_API_CMP_CORS_ALLOW_ORIGIN = os.getenv('UNIP_API_CMP_CORS_ALLOW_ORIGIN') +_api_cmp_cors_max_age = os.getenv('UNIP_API_CMP_CORS_MAX_AGE') +UNIP_API_CMP_CORS_MAX_AGE = int(_api_cmp_cors_max_age) if _api_cmp_cors_max_age else None diff --git a/controller/src/apicmp/handlers.py b/controller/src/apicmp/handlers.py new file mode 100644 index 0000000..c76ffdb --- /dev/null +++ b/controller/src/apicmp/handlers.py @@ -0,0 +1,1051 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: APIComponent +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2025 г. +# ============================================================ +import base64 +import posixpath +import secrets +import string +import urllib.parse + +import kopf +import yaml +from kubernetes.client import ApiClient + +from apicmp.config import UNIP_API_CMP_CORS_ENABLED, UNIP_API_CMP_APPS_CORS_ENABLED, UNIP_API_CMP_CORS_ALLOW_METHODS, \ + UNIP_API_CMP_CORS_ALLOW_HEADERS, UNIP_API_CMP_CORS_EXPOSE_HEADERS, UNIP_API_CMP_CORS_ALLOW_ORIGIN, \ + UNIP_API_CMP_CORS_MAX_AGE +from apicmp.jinja import basic_jinja_env, api_cmp_jinja_env +from auth import create_htpasswd_password +from basic_resources.deployments import delete_deployment_if_exists, create_or_update_deployment +from basic_resources.ingresses import delete_ingress_if_exists, create_or_update_ingress +from basic_resources.network_policies import delete_network_policy_if_exists, create_or_update_network_policy +from basic_resources.secrets import prepare_secret_manifest, delete_secret_if_exists, \ + create_or_update_secret +from basic_resources.services import delete_svc_if_exists, create_or_update_service +from bound import not_dev_namespace +from cmplink.basic_auth_link import get_basic_auth_joint_secret_name, create_or_update_basic_auth_joint_secret +from cmplink.keycloak_group_link import get_oauth2_proxy_deployment_name, create_or_update_groups_joint_secret, \ + get_groups_joint_secret_name +from config import UNIP_DOMAIN, PIPELINES_SERVICE_PORT, PIPELINES_EXTERNAL_SERVICE_NAME, OIDC_END_USERS_CLIENT_SECRET, \ + OIDC_END_USERS_ISSUER_URL, OIDC_END_USERS_CLIENT_ID, OIDC_END_USERS_COOKIE_SECRET, OIDC_ROBOTS_AUD, \ + OIDC_ROBOTS_ISSUER_URL, OIDC_END_USERS_AUD +from exceptions import InputValidationPermanentError +from exp_pipeline.client_config import INTERNAL_API_USER_ID +from exp_pipeline.pipeline import INTERNAL_API_SECRET_SUFFIX +from kopf_k8s_client import api_client +from parse import get_user_namespace + +ML_CMP_SERVICE_PORT = 80 +FILES_SERVICE_PORT = 80 +OAUTH2_PROXY_SERVICE_PORT = 4180 +OAUTH2_PROXY_CONTAINER_PORT = 4180 + +INTERNAL_API_BA_SECRET_SUFFIX = '-internal-ba-cred' + + +def join_url_segments(parts): + return "/".join(map(lambda x: str(x).strip("/"), parts)) + + +def _prepare_manifest(template_name, variables): + template = basic_jinja_env.get_template(template_name) + text = template.render(variables) + data = yaml.safe_load(text) + return data + + +def _prepare_manifest_api_cmp_env(template_name, variables): + template = api_cmp_jinja_env.get_template(template_name) + text = template.render(variables) + data = yaml.safe_load(text) + return data + + +def _get_ingress_name(name): + return f'{name}-ingress' + + +def _get_oauth2_proxy_ingress_name(name): + return f'{name}-oauth2-ingress' + + +def _get_internal_ingress_name(name): + return f'{name}-internal-ingress' + + +def _get_mlcmp_paths(namespace, restful_api_section): + if 'path' not in restful_api_section: + raise InputValidationPermanentError('MLComponent requires path in restfulApi section') + path = restful_api_section['path'] + prefix = '/' + namespace + '/' + path + prefix = posixpath.normpath(prefix) + quoted_prefix = urllib.parse.quote(prefix) + + return [ + f'{quoted_prefix}/(predict/?)', + f'{quoted_prefix}/(modelversion/.*/license/?)', + f'{quoted_prefix}/(modelversion/?)' + ] + + +def _get_files_paths(namespace): + return ['/' + namespace + '/files'] + + +def _get_pipelines_general_paths(namespace): + pipelines = '/' + namespace + '/pipelines' + trials = '/' + namespace + '/trials' + name = '[0-9A-Za-z_-]+' + return [ + f'{trials}/{name}', + f'{trials}', + f'{pipelines}' + ] + + +def _get_pipeline_internal_paths(namespace, pipeline_name): + pipelines = '/' + namespace + '/pipelines' + name = '[0-9A-Za-z_-]+' + return [ + f'{pipelines}/{pipeline_name}/check', + f'{pipelines}/{pipeline_name}/trials/continue', + f'{pipelines}/{pipeline_name}/trials/{name}/status/conditions' + ] + + +def _get_pipeline_paths(namespace, pipeline_name): + pipelines = '/' + namespace + '/pipelines' + return [ + f'{pipelines}/{pipeline_name}/version', + f'{pipelines}/{pipeline_name}/trials', + f'{pipelines}/{pipeline_name}' + ] + + +def _get_oauth2_proxy_path_prefix(namespace, upstream_name): + return '/' + namespace + '/proxies/' + upstream_name + + +def _get_oauth2_proxy_path(namespace, upstream_name): + return _get_oauth2_proxy_path_prefix(namespace, upstream_name) + '(/|$)(.*)' + + +def _get_mlcmp_rewrite_target(): + return '/$1' + + +def _get_mlcmp_service_name(mlcmp_name): + return f'{mlcmp_name}-svc' + + +def _get_files_service_name(): + return 'files-svc' + + +def _get_pipelines_general_service_name(): + return 'pipelines-svc' + + +def _get_pipeline_internal_service_name(name): + return f'{name}-internal-svc' + + +def _get_pipeline_service_name(name): + return f'{name}-svc' + + +def _get_files_external_service_name(): + # todo: использовать константу аналогично PIPELINES_EXTERNAL_SERVICE_NAME + return 'files-svc.unip-system-controller' + + +def _get_oauth2_proxy_service_name(name): + return f'{name}-oauth2-svc' + + +def _get_oauth2_proxy_selector_label(name): + return f'{name}-oauth2-proxy' + + +def _get_oauth2_proxy_np_name(name): + return f'ingress-{name}-oauth2-traffic' + + +def _append_oidc_to_ingress_model(name, namespace, ingress_model: dict, oidc: dict | None): + if oidc is None: + return ingress_model + if not oidc.get('enabled', True): + return ingress_model + base_url = 'https://$host/' + + proxy_path_prefix = _get_oauth2_proxy_path_prefix(namespace, name) + + auth_url_parts = [proxy_path_prefix, 'oauth2/auth'] + auth_url = join_url_segments(auth_url_parts) + auth_url = urllib.parse.urljoin(base_url, auth_url) + + auth_signin_parts = [proxy_path_prefix, 'oauth2/start?rd=$escaped_request_uri'] + auth_signin = join_url_segments(auth_signin_parts) + auth_signin = urllib.parse.urljoin(base_url, auth_signin) + + ingress_model['oidc'] = { + 'auth_url': auth_url, + 'auth_signin': auth_signin + } + + +def _append_basic_to_ingress_model(name, ingress_model: dict, basic: dict | None): + if basic is None: + return ingress_model + if not basic.get('enabled', True): + return ingress_model + + ingress_model['basic'] = { + 'secret_name': get_basic_auth_joint_secret_name(name) + } + + +def _parse_cors_config_param(cors_enabled, app_cors_enabled, cors, config_value, spec_param_name, default_value, + preprocess=None): + + def process_param_values(values_): + vals = map(lambda m: m.strip(), values_) + if preprocess: + vals = map(preprocess, vals) + res = set(vals) + return res + + result = set() + if cors_enabled: + if config_value: + result = process_param_values(config_value.split(',')) + else: + if app_cors_enabled: + if not cors or spec_param_name in cors: + result = default_value + if app_cors_enabled: + if cors and spec_param_name in cors: + to_join = process_param_values(cors[spec_param_name]) + result = result | to_join + elif config_value: + to_join = process_param_values(config_value.split(',')) + result = result | to_join + result = ','.join(result) + return result + + +def _parse_cors_max_age_param(cors_enabled, app_cors_enabled, cors): + result = None + if cors_enabled: + if UNIP_API_CMP_CORS_MAX_AGE: + result = UNIP_API_CMP_CORS_MAX_AGE + if app_cors_enabled: + if cors and 'maxAge' in cors: + result = cors['maxAge'] + elif UNIP_API_CMP_CORS_MAX_AGE: + result = UNIP_API_CMP_CORS_MAX_AGE + return result + + +def _append_cors_to_ingress_model(ingress_model, cors: dict | None): + cors_enabled = UNIP_API_CMP_CORS_ENABLED + app_cors_enabled = UNIP_API_CMP_APPS_CORS_ENABLED + if cors: + app_cors_enabled = cors.get('enabled', app_cors_enabled) + if not cors_enabled and not app_cors_enabled: + return + + allow_methods_default = {'GET', 'PUT', 'POST', 'DELETE', 'PATCH', 'OPTIONS'} + allow_methods = _parse_cors_config_param(cors_enabled, app_cors_enabled, cors, + UNIP_API_CMP_CORS_ALLOW_METHODS, 'allowMethods', + allow_methods_default) + allow_headers_default = {'DNT', 'Keep-Alive', 'User-Agent', 'X-Requested-With', 'If-Modified-Since', + 'Cache-Control', 'Content-Type', 'Range', 'Authorization'} + allow_headers = _parse_cors_config_param(cors_enabled, app_cors_enabled, cors, + UNIP_API_CMP_CORS_ALLOW_HEADERS, 'allowHeaders', + allow_headers_default) + expose_headers = _parse_cors_config_param(cors_enabled, app_cors_enabled, cors, + UNIP_API_CMP_CORS_EXPOSE_HEADERS, 'exposeHeaders', + set()) + allow_origin = _parse_cors_config_param(cors_enabled, app_cors_enabled, cors, + UNIP_API_CMP_CORS_ALLOW_ORIGIN, 'allowOrigin', + set(), preprocess=lambda m: m.rstrip('/')) + max_age = _parse_cors_max_age_param(cors_enabled, app_cors_enabled, cors) + + cors_model = {} + if allow_methods: + cors_model['allow_methods'] = allow_methods + if allow_headers: + cors_model['allow_headers'] = allow_headers + if expose_headers: + cors_model['expose_headers'] = expose_headers + if allow_origin: + cors_model['allow_origin'] = allow_origin + if max_age: + cors_model['max_age'] = max_age + ingress_model['cors'] = cors_model + + +def _construct_files_ingress_model(name: str, namespace: str, spec: dict, + basic: dict | None, oidc: dict | None, + cors: dict | None): + restful_api = spec['restfulApi'] + auth = restful_api['auth'] + ingress_model = { + 'name': _get_ingress_name(name), + 'namespace': namespace, + 'auth_realm': name, + 'paths': _get_files_paths(namespace), + 'service_name': _get_files_service_name(), + 'service_port': FILES_SERVICE_PORT, + 'identity_pass_through': auth['identityPassThrough'], + 'domain': UNIP_DOMAIN + } + _append_oidc_to_ingress_model(name, namespace, ingress_model, oidc) + _append_basic_to_ingress_model(name, ingress_model, basic) + _append_cors_to_ingress_model(ingress_model, cors) + return ingress_model + + +def _construct_pipelines_general_ingress_model(name: str, namespace: str, spec: dict, + basic: dict | None, oidc: dict | None, + cors: dict | None): + restful_api = spec['restfulApi'] + auth = restful_api['auth'] + ingress_model = { + 'name': _get_ingress_name(name), + 'namespace': namespace, + 'auth_realm': name, + 'paths': _get_pipelines_general_paths(namespace), + 'service_name': _get_pipelines_general_service_name(), + 'service_port': PIPELINES_SERVICE_PORT, + 'identity_pass_through': auth['identityPassThrough'], + 'domain': UNIP_DOMAIN + } + _append_oidc_to_ingress_model(name, namespace, ingress_model, oidc) + _append_basic_to_ingress_model(name, ingress_model, basic) + _append_cors_to_ingress_model(ingress_model, cors) + return ingress_model + + +def _construct_pipeline_internal_ingress_model(name: str, namespace: str, spec: dict): + pipeline = spec['experimentPipeline'] + pipeline_name = pipeline['name'] + + ingress_model = { + 'name': _get_internal_ingress_name(name), + 'namespace': namespace, + 'secret_name': _get_internal_api_ba_secret_name(name), + 'auth_realm': name, + 'paths': _get_pipeline_internal_paths(namespace, pipeline_name), + 'service_name': _get_pipeline_internal_service_name(name), + 'service_port': PIPELINES_SERVICE_PORT, + 'identity_pass_through': True, + 'domain': UNIP_DOMAIN + } + return ingress_model + + +def _construct_pipeline_ingress_model(name: str, namespace: str, spec: dict, + basic: dict | None, oidc: dict | None, + cors: dict | None): + pipeline = spec['experimentPipeline'] + pipeline_name = pipeline['name'] + + ingress_model = { + 'name': _get_ingress_name(name), + 'namespace': namespace, + 'auth_realm': name, + 'paths': _get_pipeline_paths(namespace, pipeline_name), + 'service_name': _get_pipeline_service_name(name), + 'service_port': PIPELINES_SERVICE_PORT, + 'identity_pass_through': True, + 'domain': UNIP_DOMAIN + } + _append_oidc_to_ingress_model(name, namespace, ingress_model, oidc) + _append_basic_to_ingress_model(name, ingress_model, basic) + _append_cors_to_ingress_model(ingress_model, cors) + return ingress_model + + +def _construct_mlcmp_ingress_model(name: str, namespace: str, spec: dict, + basic: dict | None, oidc: dict | None, + cors: dict | None): + restful_api = spec['restfulApi'] + auth = restful_api['auth'] + ml_cmp = spec['mlComponent'] + + ingress_model = { + 'name': _get_ingress_name(name), + 'namespace': namespace, + 'auth_realm': name, + 'rewrite_target': _get_mlcmp_rewrite_target(), + 'paths': _get_mlcmp_paths(namespace, restful_api), + 'service_name': _get_mlcmp_service_name(ml_cmp['name']), + 'service_port': ML_CMP_SERVICE_PORT, + 'identity_pass_through': auth['identityPassThrough'], + 'domain': UNIP_DOMAIN + } + _append_oidc_to_ingress_model(name, namespace, ingress_model, oidc) + _append_basic_to_ingress_model(name, ingress_model, basic) + _append_cors_to_ingress_model(ingress_model, cors) + + return ingress_model + + +def _construct_oauth2_proxy_ingress_model(name: str, namespace: str, cors: dict | None): + ingress_model = { + 'name': _get_oauth2_proxy_ingress_name(name), + 'namespace': namespace, + 'domain': UNIP_DOMAIN, + 'path': _get_oauth2_proxy_path(namespace, name), + 'service_name': _get_oauth2_proxy_service_name(name), + 'service_port': OAUTH2_PROXY_SERVICE_PORT + } + + _append_cors_to_ingress_model(ingress_model, cors) + + return ingress_model + + +def _construct_oauth2_proxy_deployment_model(name: str, namespace: str, oidc: dict): + base_url = 'https://' + UNIP_DOMAIN + + proxy_path_prefix = _get_oauth2_proxy_path_prefix(namespace, name) + redirect_url_parts = [proxy_path_prefix, 'oauth2/callback'] + redirect_url = join_url_segments(redirect_url_parts) + redirect_url = urllib.parse.urljoin(base_url, redirect_url) + + proxy_prefix_parts = [proxy_path_prefix, 'oauth2'] + proxy_prefix = '/' + join_url_segments(proxy_prefix_parts) + + oidc_extra_audience = f'{OIDC_END_USERS_AUD},{OIDC_ROBOTS_AUD}' \ + if OIDC_END_USERS_AUD != OIDC_ROBOTS_AUD \ + else OIDC_END_USERS_AUD + extra_jwt_issuers = f'{OIDC_END_USERS_ISSUER_URL}={OIDC_END_USERS_AUD},{OIDC_ROBOTS_ISSUER_URL}={OIDC_ROBOTS_AUD}' \ + if OIDC_END_USERS_AUD != OIDC_ROBOTS_AUD \ + else f'{OIDC_END_USERS_ISSUER_URL}={OIDC_END_USERS_AUD}' + + deployment_model = { + 'deployment_name': get_oauth2_proxy_deployment_name(name), + 'selector_label': _get_oauth2_proxy_selector_label(name), + 'namespace': namespace, + 'client_secret': OIDC_END_USERS_CLIENT_SECRET, + 'client_id': OIDC_END_USERS_CLIENT_ID, + 'cookie_secret': OIDC_END_USERS_COOKIE_SECRET, + 'redirect_url': redirect_url, + 'oidc_issuer_url': OIDC_END_USERS_ISSUER_URL, + 'oidc_extra_audience': oidc_extra_audience, + 'extra_jwt_issuers': extra_jwt_issuers, + 'proxy_prefix': proxy_prefix, + 'container_port': OAUTH2_PROXY_CONTAINER_PORT, + 'groups_secret_name': get_groups_joint_secret_name(name) + } + + if 'roles' in oidc: + deployment_model['roles'] = ','.join(oidc['roles']) + + return deployment_model + + +def _construct_oauth2_proxy_service_model(name: str, namespace: str): + service_model = { + 'selector_label': _get_oauth2_proxy_selector_label(name), + 'namespace': namespace, + 'service_name': _get_oauth2_proxy_service_name(name), + 'service_port': OAUTH2_PROXY_SERVICE_PORT, + 'container_port': OAUTH2_PROXY_CONTAINER_PORT + } + + return service_model + + +def _construct_oauth2_proxy_np(name: str, namespace: str): + np_model = { + 'np_name': _get_oauth2_proxy_np_name(name), + 'selector_label': _get_oauth2_proxy_selector_label(name), + 'namespace': namespace + } + + return np_model + + +def _create_or_update_ingress(api_client_: ApiClient, name, namespace, ingress_model, logger): + ingress_manifest = _prepare_manifest('ingress-multi-auth.yaml', ingress_model) + create_or_update_ingress(api_client_, name, namespace, ingress_manifest, logger) + + +def _create_or_update_oauth2_proxy_ingress(api_client_: ApiClient, name, namespace, ingress_model, logger): + ingress_manifest = _prepare_manifest_api_cmp_env('oauth2-proxy-ingress.yaml', ingress_model) + create_or_update_ingress(api_client_, name, namespace, ingress_manifest, logger) + + +def _create_or_update_external_name_files_service(api_client_: ApiClient, namespace, logger): + svc_name = _get_files_service_name() + svc_model = { + 'service_name': _get_files_service_name(), + 'namespace': namespace, + 'external_service_name': _get_files_external_service_name() + } + svc_manifest = _prepare_manifest('external-name-svc.yaml', svc_model) + create_or_update_service(api_client_, svc_name, namespace, svc_manifest, logger) + + +def _create_or_update_external_name_pipelines_service(api_client_: ApiClient, namespace, svc_name, logger): + svc_model = { + 'service_name': svc_name, + 'namespace': namespace, + 'external_service_name': PIPELINES_EXTERNAL_SERVICE_NAME + } + svc_manifest = _prepare_manifest('external-name-svc.yaml', svc_model) + create_or_update_service(api_client_, svc_name, namespace, svc_manifest, logger) + + +def _create_or_update_external_name_pipelines_general_service(api_client_: ApiClient, namespace, logger): + svc_name = _get_pipelines_general_service_name() + _create_or_update_external_name_pipelines_service(api_client_, namespace, svc_name, logger) + + +def _create_or_update_external_name_pipeline_internal_service(api_client_: ApiClient, name, namespace, logger): + svc_name = _get_pipeline_internal_service_name(name) + _create_or_update_external_name_pipelines_service(api_client_, namespace, svc_name, logger) + + +def _create_or_update_external_name_pipeline_service(api_client_: ApiClient, name, namespace, logger): + svc_name = _get_pipeline_service_name(name) + _create_or_update_external_name_pipelines_service(api_client_, namespace, svc_name, logger) + + +def _create_or_update_oauth2_proxy_deployment(api_client_: ApiClient, name, namespace, deployment_model, logger): + deployment_manifest = _prepare_manifest_api_cmp_env('oauth2-proxy-deployment.yaml', deployment_model) + create_or_update_deployment(api_client_, name, namespace, deployment_manifest, logger) + + +def _create_or_update_oauth2_proxy_service(api_client_: ApiClient, name, namespace, service_model, logger): + svc_manifest = _prepare_manifest_api_cmp_env('oauth2-proxy-svc.yaml', service_model) + create_or_update_service(api_client_, name, namespace, svc_manifest, logger) + + +def _create_or_update_oauth2_proxy_np(api_client_: ApiClient, name, namespace, np_model, logger): + np_manifest = _prepare_manifest('allow-ingress-traffic-np.yaml', np_model) + create_or_update_network_policy(api_client_, name, namespace, np_manifest, logger) + + +_passwords_alphabet = string.ascii_letters + string.digits + string.punctuation + + +def _create_password(): + return ''.join(secrets.choice(_passwords_alphabet) for _ in range(10)) + + +def _get_internal_api_secret_name(name): + return name + INTERNAL_API_SECRET_SUFFIX + + +def _get_internal_api_ba_secret_name(name): + return name + INTERNAL_API_BA_SECRET_SUFFIX + + +def _create_pipeline_internal_api_secrets(api_client_: ApiClient, name, namespace, logger): + password = _create_password() + + record = f'{INTERNAL_API_USER_ID}:{password}' + encoded_value = base64.b64encode(record.encode('utf-8')).decode('ascii') + data = [{'key': 'credentials', 'value': encoded_value}] + + secret_name = _get_internal_api_secret_name(name) + manifest = prepare_secret_manifest(name=secret_name, + namespace=namespace, + type_='Opaque', + data=data, + data_attr='data') + create_or_update_secret(api_client=api_client_, + name=secret_name, + namespace=namespace, + manifest=manifest, + logger=logger) + + encrypted_password = create_htpasswd_password(password) + htpasswd_record = f'{INTERNAL_API_USER_ID}:{encrypted_password}' + encoded_value = base64.b64encode(htpasswd_record.encode('utf-8')).decode('ascii') + basic_auth_data = [ + {'key': 'auth', 'value': encoded_value} + ] + secret_name = _get_internal_api_ba_secret_name(name) + manifest = prepare_secret_manifest(name=secret_name, + namespace=namespace, + type_='Opaque', + data=basic_auth_data, + data_attr='data') + create_or_update_secret(api_client=api_client_, + name=secret_name, + namespace=namespace, + manifest=manifest, + logger=logger) + + +def _delete_ingress_if_exists(api_client_: ApiClient, name: str, namespace: str, + logger): + ingress_name = _get_ingress_name(name) + delete_ingress_if_exists(api_client=api_client_, name=ingress_name, namespace=namespace, logger=logger) + + +def _delete_oauth2_proxy_ingress_if_exists(api_client_: ApiClient, name: str, namespace: str, + logger): + ingress_name = _get_oauth2_proxy_ingress_name(name) + delete_ingress_if_exists(api_client=api_client_, name=ingress_name, namespace=namespace, logger=logger) + + +def _delete_internal_ingress_if_exists(api_client_: ApiClient, name: str, namespace: str, + logger): + ingress_name = _get_internal_ingress_name(name) + delete_ingress_if_exists(api_client=api_client_, name=ingress_name, namespace=namespace, logger=logger) + + +def _delete_files_svc_if_exists(api_client_: ApiClient, namespace: str, logger): + svc_name = _get_files_service_name() + delete_svc_if_exists(api_client_, namespace, svc_name, logger) + + +def _delete_pipelines_general_svc_if_exists(api_client_: ApiClient, namespace: str, logger): + svc_name = _get_pipelines_general_service_name() + delete_svc_if_exists(api_client_, namespace, svc_name, logger) + + +def _delete_pipeline_svc_if_exists(api_client_: ApiClient, name: str, namespace: str, logger): + svc_name = _get_pipeline_service_name(name) + delete_svc_if_exists(api_client_, namespace, svc_name, logger) + + +def _delete_pipeline_internal_svc_if_exists(api_client_: ApiClient, name: str, namespace: str, logger): + svc_name = _get_pipeline_internal_service_name(name) + delete_svc_if_exists(api_client_, namespace, svc_name, logger) + + +def _delete_pipeline_internal_api_secrets_if_exist(api_client_: ApiClient, name: str, namespace: str, logger): + secret_name = _get_internal_api_secret_name(name) + delete_secret_if_exists(api_client=api_client_, name=secret_name, namespace=namespace, logger=logger) + + secret_name = _get_internal_api_ba_secret_name(name) + delete_secret_if_exists(api_client=api_client_, name=secret_name, namespace=namespace, logger=logger) + + +def _delete_oauth2_proxy_deployment_if_exists(api_client_: ApiClient, name: str, namespace: str, logger): + deployment_name = get_oauth2_proxy_deployment_name(name) + delete_deployment_if_exists(api_client_, namespace, deployment_name, logger) + + +def _delete_oauth2_proxy_service_if_exists(api_client_: ApiClient, name: str, namespace: str, logger): + service_name = _get_oauth2_proxy_service_name(name) + delete_svc_if_exists(api_client_, namespace, service_name, logger) + + +def _delete_oauth2_proxy_np_if_exists(api_client_: ApiClient, name: str, namespace: str, logger): + np_name = _get_oauth2_proxy_np_name(name) + delete_network_policy_if_exists(api_client_, np_name, namespace, logger) + + +def _get_oidc_from_spec(spec): + restful_api = spec['restfulApi'] + auth = restful_api['auth'] + return auth.get('oidc') + + +def _get_basic_from_spec(spec): + restful_api = spec['restfulApi'] + auth = restful_api['auth'] + return auth.get('basic') + + +def _get_cors_from_spec(spec): + restful_api = spec['restfulApi'] + return restful_api.get('cors') + + +def _should_api_be_published(spec): + published_flag = spec['published'] + if not published_flag: + return False + basic = _get_basic_from_spec(spec) + basic_enabled = basic.get('enabled', True) if basic is not None else False + oidc = _get_oidc_from_spec(spec) + oidc_enabled = oidc.get('enabled', True) if oidc is not None else False + if basic_enabled or oidc_enabled: + return True + # пока считаем, что если любая аутентификация выключена, то доступ закрыт + return False + + +@kopf.on.create('unified-platform.cs.hse.ru', 'apicomponents', retries=18, when=not_dev_namespace) +def create_api_component(name, namespace, spec, patch, logger, **_): + """ + Обработчик создания ресурса APIComponent. + Создает ресурсы Service, Ingress для предоставления доступа к сервисам фреймворка и сервисам приложения. + При спецификации OIDC аутентификации настраивает подчиненные ресурсы Deployment, Service, Ingress + для OAuth2 Proxy. + Обновляет объединенный секрет с реквизитами Basic аутентификации. + + :param spec: спецификация ресурса APIComponent + :param name: имя ресурса APIComponent + :param namespace: пространство имен ресурса APIComponent + :param patch: объект patch фреймворка kopf + :param logger: kopf logger + :param _: остальные параметры kopf, которые не используются обработчиком + :return: None + """ + published = _should_api_be_published(spec) + oidc = _get_oidc_from_spec(spec) + basic = _get_basic_from_spec(spec) + cors = _get_cors_from_spec(spec) + + if 'status' not in patch: + patch['status'] = {} + + user_namespace = get_user_namespace(namespace) + ingress_name = _get_ingress_name(name) + + _update_oauth2_proxy(name, namespace, spec, oidc, cors, logger) + + @kopf.subhandler(id=f'create-or-update-ba-joint-secret-for-{namespace}.{name}', retries=3) + def _create_or_update_ba_joint_secret_handler(**_): + create_or_update_basic_auth_joint_secret(api_client=api_client, + target=name, + target_namespace=namespace, + user_namespace=user_namespace, + logger=logger) + + if 'mlComponent' in spec and published: + @kopf.subhandler(id=f'create-ingress-{name}', retries=3) + def _create_mlcmp_ingress_handler(**_): + ingress_model = _construct_mlcmp_ingress_model(name, namespace, spec, basic, oidc, cors) + _create_or_update_ingress(api_client, ingress_name, namespace, ingress_model, logger) + elif 'files' in spec: + files = spec['files'] + enabled = files['enabled'] + if enabled: + @kopf.subhandler(id=f'create-files-svc-{name}', retries=3) + def _create_files_svc_handler(**_): + _create_or_update_external_name_files_service(api_client, namespace, logger) + + if published: + @kopf.subhandler(id=f'create-ingress-{name}', retries=3) + def _create_files_ingress_handler(**_): + ingress_model = _construct_files_ingress_model(name, namespace, spec, basic, oidc, cors) + _create_or_update_ingress(api_client, ingress_name, namespace, ingress_model, logger) + elif 'pipelines' in spec: + pipelines = spec['pipelines'] + enabled = pipelines['enabled'] + if enabled: + @kopf.subhandler(id=f'create-pipelines-svc-{name}', retries=3) + def _create_pipelines_svc_handler(**_): + _create_or_update_external_name_pipelines_general_service(api_client, namespace, logger) + + if published: + @kopf.subhandler(id=f'create-ingress-{name}', retries=3) + def _create_pipelines_general_ingress_handler(**_): + ingress_model = _construct_pipelines_general_ingress_model(name, namespace, spec, basic, oidc, cors) + _create_or_update_ingress(api_client, ingress_name, namespace, ingress_model, logger) + elif 'experimentPipeline' in spec and published: + @kopf.subhandler(id=f'create-ingress-{name}', retries=3) + def _create_pipeline_ingress_handler(**_): + ingress_model = _construct_pipeline_ingress_model(name, namespace, spec, basic, oidc, cors) + _create_or_update_ingress(api_client, ingress_name, namespace, ingress_model, logger) + + @kopf.subhandler(id=f'create-pipeline-svc-{name}', retries=3) + def _create_pipeline_svc_handler(**_): + _create_or_update_external_name_pipeline_service(api_client, name, namespace, logger) + + @kopf.subhandler(id=f'create-ingress-internal-{name}', retries=3) + def _create_pipeline_internal_ingress_handler(**_): + ingress_model = _construct_pipeline_internal_ingress_model(name, namespace, spec) + _create_or_update_ingress(api_client, ingress_name, namespace, ingress_model, logger) + + @kopf.subhandler(id=f'create-pipeline-internal-svc-{name}', retries=3) + def _create_pipeline_internal_svc_handler(**_): + _create_or_update_external_name_pipeline_internal_service(api_client, name, namespace, logger) + + @kopf.subhandler(id=f'create-pipeline-internal-secrets-{name}', retries=3) + def _create_pipeline_internal_secrets_handler(**_): + patch['status'].setdefault('experimentPipeline', {}) + patch['status']['experimentPipeline']['internalApiSecretName'] = _get_internal_api_secret_name(name) + _create_pipeline_internal_api_secrets(api_client, name, namespace, logger) + else: + if not published: + logger.info('Published if False, ingress is not created') + else: + raise InputValidationPermanentError('Only files, pipelines, experimentPipeline or mlComponent ' + 'are supported now, but not specified') + + +@kopf.on.delete('unified-platform.cs.hse.ru', 'apicomponents', retries=3, + when=not_dev_namespace) +def delete_api_component(spec, name, namespace, logger, **_): + """ + Обработчик удаления ресурса APIComponent. + Удаляет ресурсы Service, Ingress, которые использовались для предоставления доступа + к сервисам фреймворка и сервисам приложения. + Если была специфицирована OIDC аутентификация, удаляет подчиненные ресурсы + Deployment, Service, Ingress OAuth2 Proxy. + Обновляет объединенный секрет с реквизитами Basic аутентификации. + + :param spec: спецификация ресурса APIComponent + :param name: имя ресурса APIComponent + :param namespace: пространство имен ресурса APIComponent + :param patch: объект patch фреймворка kopf + :param logger: kopf logger + :param _: остальные параметры kopf, которые не используются обработчиком + :return: None + """ + _delete_ingress_if_exists(api_client, name, namespace, logger) + user_namespace = get_user_namespace(namespace) + + _delete_oauth2_proxy(name, namespace, logger) + + if 'files' in spec: + _delete_files_svc_if_exists(api_client, namespace, logger) + if 'pipelines' in spec: + _delete_pipelines_general_svc_if_exists(api_client, namespace, logger) + if 'experimentPipeline' in spec: + _delete_pipeline_svc_if_exists(api_client, name, namespace, logger) + # дополнительно удаляется internal ingress для ExperimentPipeline, + # потому что у APIComponent для ExperimentPipeline есть два ингресса ("обычный" и internal) + # internal_ingress, internal_svc - специальный случай; + _delete_internal_ingress_if_exists(api_client, name, namespace, logger) + _delete_pipeline_internal_svc_if_exists(api_client, name, namespace, logger) + _delete_pipeline_internal_api_secrets_if_exist(api_client, name, namespace, logger) + + if 'mlComponent': + # удалять mlcmp svc не нужно, потому что он управляется контроллером MLComponent, + # это может измениться в будущем + pass + + # обновить общий basic auth секрет + create_or_update_basic_auth_joint_secret(api_client=api_client, + target=name, + target_namespace=namespace, + user_namespace=user_namespace, + logger=logger, + exclude_direct_spec=True) + + +@kopf.on.update('unified-platform.cs.hse.ru', 'apicomponents', + retries=24, when=not_dev_namespace, field='spec') +def update_api_component(name, namespace, old, new, patch, logger, **_): + """ + Обработчик изменения ресурса APIComponent. + Обновляет ресурсы Service, Ingress для предоставления доступа к сервисам фреймворка и сервисам приложения. + При спецификации OIDC аутентификации настраивает подчиненные ресурсы Deployment, Service, Ingress + для OAuth2 Proxy. + Обновляет объединенный секрет с реквизитами Basic аутентификации. + + С небольшими доработками update_api_component и create_api_component + могут быть объединены. С точки зрения level-based triggering не так важно, + какое именно событие инициирует изменение (создание или изменение). + Важно только перевести текущее состояние в целевое, событие - + это просто дополнительная информация. + + :param old: предыдущая версия спецификации ресурса APIComponent + :param new: новая версия спецификации ресурса APIComponent + :param name: имя ресурса APIComponent + :param namespace: пространство имен ресурса APIComponent + :param patch: объект patch фреймворка kopf + :param logger: kopf logger + :param _: остальные параметры kopf, которые не используются обработчиком + :return: None + """ + old_spec = old if old else {} + spec = new + oidc = _get_oidc_from_spec(spec) + basic = _get_basic_from_spec(spec) + cors = _get_cors_from_spec(spec) + + published = _should_api_be_published(spec) + if 'status' not in patch: + patch['status'] = {} + + ingress_name = _get_ingress_name(name) + + _update_oauth2_proxy(name, namespace, spec, oidc, cors, logger) + + @kopf.subhandler(id=f'update-ingress-{name}', retries=3) + def _update_ingress_handler(**_): + # здесь и в других местах можно в целом более гранулярно управлять распространением изменений - + # не удалять и создавать целые подчиненные ресурсы; + _delete_ingress_if_exists(api_client, name, namespace, logger) + ingress_model = None + if 'mlComponent' in spec and published: + ingress_model = _construct_mlcmp_ingress_model(name, namespace, spec, basic, oidc, cors) + elif 'files' in spec and published: + files = spec['files'] + enabled = files['enabled'] + if enabled: + ingress_model = _construct_files_ingress_model(name, namespace, spec, basic, oidc, cors) + elif 'pipelines' in spec and published: + pipelines = spec['pipelines'] + enabled = pipelines['enabled'] + if enabled: + ingress_model = _construct_pipelines_general_ingress_model(name, namespace, spec, basic, oidc, cors) + elif 'experimentPipeline' in spec and published: + ingress_model = _construct_pipeline_ingress_model(name, namespace, spec, basic, oidc, cors) + else: + if not published: + logger.info('Published if False, ingress is not created') + else: + raise InputValidationPermanentError( + 'Only files, pipelines, experimentPipeline or mlComponent are supported ' + 'now, but not specified') + if ingress_model: + _create_or_update_ingress(api_client, ingress_name, namespace, ingress_model, logger) + + @kopf.subhandler(id=f'update-files-svc-{name}', retries=3) + def _update_files_svc_handler(**_): + if 'files' in old_spec: + _delete_files_svc_if_exists(api_client, namespace, logger) + if 'files' in spec and published: + files = spec['files'] + enabled = files['enabled'] + if enabled: + _create_or_update_external_name_files_service(api_client, namespace, logger) + + @kopf.subhandler(id=f'update-pipeline-svc-{name}', retries=3) + def _update_pipeline_svc_handler(**_): + if 'experimentPipeline' in old_spec: + _delete_pipeline_svc_if_exists(api_client, name, namespace, logger) + if 'experimentPipeline' in spec and published: + _create_or_update_external_name_pipeline_service(api_client, name, namespace, logger) + + @kopf.subhandler(id=f'update-pipelines-general-svc-{name}', retries=3) + def _update_pipelines_general_svc_handler(**_): + if 'pipelines' in old_spec: + _delete_pipelines_general_svc_if_exists(api_client, namespace, logger) + if 'pipelines' in spec and published: + pipelines = spec['pipelines'] + enabled = pipelines['enabled'] + if enabled: + _create_or_update_external_name_pipelines_general_service(api_client, namespace, logger) + + @kopf.subhandler(id=f'update-internal-ingress-{name}', retries=3) + def _update_internal_ingress_handler(**_): + # для internal ingress нужен отдельный обработчик, это специальный случай, + # поскольку у APIComponent для ExperimentPipeline два ингресса; + # а общий обработчик update_ingress обрабатывает обновление одного ингресса; + if 'experimentPipeline' in old_spec: + _delete_internal_ingress_if_exists(api_client, name, namespace, logger) + if 'experimentPipeline' in spec and published: + ingress_model = _construct_pipeline_internal_ingress_model(name, namespace, spec) + _create_or_update_ingress(api_client, ingress_name, namespace, ingress_model, logger) + + @kopf.subhandler(id=f'update-pipeline-internal-svc-{name}', retries=3) + def _update_pipeline_internal_svc_handler(**_): + if 'experimentPipeline' in old_spec: + _delete_pipeline_internal_svc_if_exists(api_client, name, namespace, logger) + if 'experimentPipeline' in spec and published: + _create_or_update_external_name_pipeline_internal_service(api_client, name, namespace, logger) + + @kopf.subhandler(id=f'update-pipeline-internal-secrets-{name}', retries=3) + def _update_pipeline_internal_secrets_handler(**_): + if 'experimentPipeline' in old_spec: + _delete_pipeline_internal_api_secrets_if_exist(api_client, name, namespace, logger) + if 'experimentPipeline' in spec and published: + patch['status'].setdefault('experimentPipeline', {}) + patch['status']['experimentPipeline']['internalApiSecretName'] = _get_internal_api_secret_name(name) + _create_pipeline_internal_api_secrets(api_client, name, namespace, logger) + + @kopf.subhandler(id=f'create-or-update-joint-ba-secret-for-{namespace}.{name}', retries=3) + def _create_or_update_ba_joint_secret_handler(**_): + # теоретически, можно выделить в отдельный обработчик @kopf.on.field + + old_api = old_spec['restfulApi'] + old_auth = old_api['auth'] + old_basic = old_auth.get('basic') + old_secret = old_basic.get('credentials') if old_basic else None + + api = spec['restfulApi'] + auth = api['auth'] + new_basic = auth.get('basic') + new_secret = new_basic.get('credentials') if basic else None + + if old_secret != new_secret: + user_namespace = get_user_namespace(namespace) + create_or_update_basic_auth_joint_secret(api_client=api_client, + target=name, + target_namespace=namespace, + user_namespace=user_namespace, + logger=logger) + + +def _should_oauth2_proxy_be_created(api_cmp_spec, new_oidc): + if new_oidc is None: + return False + if not new_oidc.get('enabled', True): + return False + published = api_cmp_spec['published'] + if 'mlComponent' in api_cmp_spec and published: + return True + elif 'experimentPipeline' in api_cmp_spec and published: + return True + elif 'files' in api_cmp_spec and published: + files = api_cmp_spec['files'] + enabled = files['enabled'] + if enabled: + return True + elif 'pipelines' in api_cmp_spec and published: + pipelines = api_cmp_spec['pipelines'] + enabled = pipelines['enabled'] + if enabled: + return True + else: + if published: + raise InputValidationPermanentError( + 'Only files, pipelines, experimentPipeline or mlComponent are supported ' + 'now, but not specified') + return False + + +def _update_oauth2_proxy(api_cmp_name, namespace, api_cmp_spec, new_oidc, cors, logger): + create_oauth2_proxy = _should_oauth2_proxy_be_created(api_cmp_spec, new_oidc) + + @kopf.subhandler(id=f'update-oauth2-proxy-ingress-{api_cmp_name}', retries=3) + def _update_oauth2_proxy_ingress_handler(**_): + _delete_oauth2_proxy_ingress_if_exists(api_client, api_cmp_name, namespace, logger) + if create_oauth2_proxy: + ingress_name = _get_oauth2_proxy_ingress_name(api_cmp_name) + ingress_model = _construct_oauth2_proxy_ingress_model(api_cmp_name, namespace, cors) + _create_or_update_oauth2_proxy_ingress(api_client, ingress_name, namespace, ingress_model, + logger) + + @kopf.subhandler(id=f'update-oauth2-proxy-deployment-{api_cmp_name}', retries=3) + def _update_oauth2_proxy_deployment_handler(**_): + _delete_oauth2_proxy_deployment_if_exists(api_client, api_cmp_name, namespace, logger) + if create_oauth2_proxy: + deployment_name = get_oauth2_proxy_deployment_name(api_cmp_name) + deployment_model = _construct_oauth2_proxy_deployment_model(api_cmp_name, namespace, new_oidc) + user_namespace = get_user_namespace(namespace) + create_or_update_groups_joint_secret(api_client, api_cmp_name, namespace, user_namespace, logger) + _create_or_update_oauth2_proxy_deployment(api_client, deployment_name, namespace, deployment_model, logger) + + @kopf.subhandler(id=f'update-oauth2-proxy-service-{api_cmp_name}', retries=3) + def _update_oauth2_proxy_service_handler(**_): + _delete_oauth2_proxy_service_if_exists(api_client, api_cmp_name, namespace, logger) + if create_oauth2_proxy: + service_name = _get_oauth2_proxy_service_name(api_cmp_name) + service_model = _construct_oauth2_proxy_service_model(api_cmp_name, namespace) + _create_or_update_oauth2_proxy_service(api_client, service_name, namespace, service_model, logger) + + @kopf.subhandler(id=f'update-oauth2-proxy-np-{api_cmp_name}', retries=3) + def _update_oauth2_proxy_np_handler(**_): + _delete_oauth2_proxy_np_if_exists(api_client, api_cmp_name, namespace, logger) + if create_oauth2_proxy: + np_name = _get_oauth2_proxy_np_name(api_cmp_name) + np_model = _construct_oauth2_proxy_np(api_cmp_name, namespace) + _create_or_update_oauth2_proxy_np(api_client, np_name, namespace, np_model, logger) + + +def _delete_oauth2_proxy(api_cmp_name, namespace, logger): + _delete_oauth2_proxy_ingress_if_exists(api_client, api_cmp_name, namespace, logger) + _delete_oauth2_proxy_deployment_if_exists(api_client, api_cmp_name, namespace, logger) + _delete_oauth2_proxy_service_if_exists(api_client, api_cmp_name, namespace, logger) + _delete_oauth2_proxy_np_if_exists(api_client, api_cmp_name, namespace, logger) diff --git a/controller/src/apicmp/jinja.py b/controller/src/apicmp/jinja.py new file mode 100644 index 0000000..d355b62 --- /dev/null +++ b/controller/src/apicmp/jinja.py @@ -0,0 +1,21 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: APIComponent +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +from jinja2 import Environment, FileSystemLoader + +basic_jinja_env = Environment( + loader=FileSystemLoader('templates/basic-resources'), + lstrip_blocks=True, + trim_blocks=True +) + + +api_cmp_jinja_env = Environment( + loader=FileSystemLoader('templates/api-component'), + lstrip_blocks=True, + trim_blocks=True +) + diff --git a/controller/src/auth.py b/controller/src/auth.py new file mode 100644 index 0000000..8fedd7d --- /dev/null +++ b/controller/src/auth.py @@ -0,0 +1,67 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Утилиты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +import base64 +import logging +from string import ascii_uppercase, ascii_lowercase + +import bcrypt +from fastapi import HTTPException +from starlette.requests import Request + +from exp_pipeline.client_config import INTERNAL_API_USER_ID + +# https://datatracker.ietf.org/doc/html/rfc3986#section-2.3 +ALLOWED_USER_NAME_SYMBOLS = set(ascii_uppercase) | set(ascii_lowercase) | set('0123456789') | {'-', '.', '_', '~'} + + +logger = logging.getLogger(__name__) + + +def _get_user_id_from_basic(basic): + try: + credentials = base64.b64decode(basic).decode(encoding='utf-8') + sep_index = credentials.index(':') + except ValueError: + raise HTTPException(status_code=401, detail='Invalid Basic Authorization credentials format') + except Exception: + raise HTTPException(status_code=401, detail='Invalid Basic Authorization credentials') + user_name = credentials[:sep_index] + return user_name + + +def get_user_id(request: Request): + if 'Authorization' not in request.headers: + raise HTTPException(status_code=401, detail='User identity not passed') + authorization = request.headers['Authorization'] + parts = authorization.split(' ') + if parts[0] != 'Basic' or len(parts) < 2: + raise HTTPException(status_code=401, detail='Only Basic Authorization schema is supported now') + user_name = None + if parts[0] == 'Basic': + user_name = _get_user_id_from_basic(parts[1]) + if not user_name or any([s not in ALLOWED_USER_NAME_SYMBOLS for s in user_name]): + raise HTTPException(status_code=401, detail='Invalid user name') + return user_name + + +def allowed_to_platform_user(request: Request): + user_name = get_user_id(request) + if user_name != INTERNAL_API_USER_ID: + raise HTTPException(status_code=403, detail=f'Forbidden for user {user_name}') + + +def create_htpasswd_password(password: str) -> str: + return bcrypt.hashpw(password.encode('utf-8'), + bcrypt.gensalt(rounds=5, prefix=b'2b')).decode('utf-8') + + +def get_basic_auth_credentials(credentials_lines: str) -> tuple[str, str]: + records = base64.b64decode(credentials_lines).decode('utf-8').split('\n') + first_record = records[0] + sep_index = first_record.find(':') + user_id, user_password = first_record[:sep_index], first_record[sep_index + 1:] + return user_id, user_password diff --git a/controller/src/basic_resources/__init__.py b/controller/src/basic_resources/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/controller/src/basic_resources/deployments.py b/controller/src/basic_resources/deployments.py new file mode 100644 index 0000000..19c3e0e --- /dev/null +++ b/controller/src/basic_resources/deployments.py @@ -0,0 +1,64 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Управления базовыми объектами Kubernetes +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2025 г. +# ============================================================ +from datetime import datetime, timezone + +from kubernetes.client import ApiClient, CoreV1Api, ApiException, AppsV1Api + + +def delete_deployment_if_exists(api_client: ApiClient, namespace: str, deployment_name: str, logger): + apps_v1_api: AppsV1Api = AppsV1Api(api_client) + try: + apps_v1_api.delete_namespaced_deployment(name=deployment_name, namespace=namespace) + except ApiException as exc: + if exc.status == 404: + logger.info(f"Deployment {deployment_name} doesnt exist, do nothing") + return + raise exc + logger.info(f"Deployment {deployment_name} is deleted") + + +def create_deployment(api_client: ApiClient, namespace, manifest): + apps_v1_api: AppsV1Api = AppsV1Api(api_client) + apps_v1_api.create_namespaced_deployment(namespace=namespace, body=manifest) + + +def create_or_update_deployment(api_client: ApiClient, name: str, namespace: str, manifest, logger): + apps_v1_api: AppsV1Api = AppsV1Api(api_client) + + try: + apps_v1_api.create_namespaced_deployment(namespace=namespace, body=manifest) + logger.info(f"Deployment {name} is created") + except ApiException as exc: + if exc.status == 409: + logger.warning(f'Deployment {name} already exists, will be replaced') + apps_v1_api.replace_namespaced_deployment(name=name, namespace=namespace, body=manifest) + logger.info(f"Deployment {name} is replaced") + + +def restart_deployment_if_exists(api_client: ApiClient, name: str, namespace: str, logger): + apps_v1_api: AppsV1Api = AppsV1Api(api_client) + now = datetime.now(timezone.utc).replace(tzinfo=None) + now = now.isoformat("T") + "Z" + patch = { + 'spec': { + 'template': { + 'metadata': { + 'annotations': { + 'kubectl.kubernetes.io/restartedAt': now + } + } + } + } + } + try: + apps_v1_api.patch_namespaced_deployment(name, namespace, patch) + except ApiException as exc: + if exc.status == 404: + logger.warn(f"Deployment {namespace}.{name} doesnt exist, do nothing") + return + raise exc + logger.info(f"Deployment {namespace}.{name} scheduled for restart") \ No newline at end of file diff --git a/controller/src/basic_resources/ingresses.py b/controller/src/basic_resources/ingresses.py new file mode 100644 index 0000000..8142133 --- /dev/null +++ b/controller/src/basic_resources/ingresses.py @@ -0,0 +1,47 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Управления базовыми объектами Kubernetes +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +from kubernetes.client import ApiClient, NetworkingV1Api, ApiException + + +def delete_ingress_if_exists(api_client: ApiClient, name: str, namespace: str, + logger): + networking_v1_api = NetworkingV1Api(api_client) + + try: + networking_v1_api.delete_namespaced_ingress(name=name, namespace=namespace) + except ApiException as exc: + if exc.status == 404: + logger.info(f"Ingress {name} doesnt exist, do nothing") + return + raise exc + logger.info(f"Ingress {name} is deleted") + + +def create_or_update_ingress(api_client: ApiClient, name: str, namespace: str, manifest, + logger): + networking_v1_api = NetworkingV1Api(api_client) + + try: + networking_v1_api.create_namespaced_ingress(namespace=namespace, body=manifest) + logger.info(f"Ingress {name} is created") + except ApiException as exc: + if exc.status == 409: + logger.warning(f'Ingress {name} already exists, will be replaced') + networking_v1_api.replace_namespaced_ingress(name=name, namespace=namespace, body=manifest) + logger.info(f"Ingress {name} is replaced") + + +def read_ingress_if_exists(api_client: ApiClient, name, namespace, logger): + networking_v1_api = NetworkingV1Api(api_client) + try: + ingress = networking_v1_api.read_namespaced_ingress(name=name, namespace=namespace) + return ingress + except ApiException as exc: + if exc.status == 404: + logger.info(f'Ingress {namespace}.{name} does not exist') + return None + raise exc diff --git a/controller/src/basic_resources/jinja.py b/controller/src/basic_resources/jinja.py new file mode 100644 index 0000000..d8cb60b --- /dev/null +++ b/controller/src/basic_resources/jinja.py @@ -0,0 +1,14 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Управления базовыми объектами Kubernetes +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +from jinja2 import Environment, FileSystemLoader + +basic_jinja_env = Environment( + loader=FileSystemLoader('templates/basic-resources'), + lstrip_blocks=True, + trim_blocks=True +) + diff --git a/controller/src/basic_resources/jobs.py b/controller/src/basic_resources/jobs.py new file mode 100644 index 0000000..055d982 --- /dev/null +++ b/controller/src/basic_resources/jobs.py @@ -0,0 +1,45 @@ +from kubernetes.client import BatchV1Api, ApiClient, ApiException + +from exceptions import ObjectAlreadyExistsTemporaryError + + +def create_cron_job(api_client: ApiClient, name, namespace, manifest, logger): + batch_v1_api = BatchV1Api(api_client) + try: + batch_v1_api.create_namespaced_cron_job(namespace, body=manifest) + except ApiException as exc: + if exc.status == 409: + raise ObjectAlreadyExistsTemporaryError + raise exc + + +def update_cron_job(api_client: ApiClient, name, namespace, manifest, logger): + batch_v1_api = BatchV1Api(api_client) + batch_v1_api.replace_namespaced_cron_job(name=name, namespace=namespace, body=manifest) + + +def delete_cron_job_if_exists(api_client: ApiClient, name, namespace, logger): + batch_v1_api = BatchV1Api(api_client) + try: + batch_v1_api.delete_namespaced_cron_job(name=name, namespace=namespace) + except ApiException as exc: + if exc.status == 404: + logger.info(f"CronJob {name} doesnt exist, do nothing") + return + raise exc + logger.info(f"CronJob {name} is deleted") + + +def create_or_update_cron_job(api_client: ApiClient, name, namespace, manifest, logger): + try: + create_cron_job(api_client=api_client, + name=name, + namespace=namespace, + manifest=manifest, + logger=logger) + except ObjectAlreadyExistsTemporaryError as exc: + update_cron_job(api_client=api_client, + name=name, + namespace=namespace, + manifest=manifest, + logger=logger) diff --git a/controller/src/basic_resources/namespaces.py b/controller/src/basic_resources/namespaces.py new file mode 100644 index 0000000..164a3ff --- /dev/null +++ b/controller/src/basic_resources/namespaces.py @@ -0,0 +1,36 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Управления базовыми объектами Kubernetes +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +""" +Namespaces basic resources module. Implements reusable namespaces-related functions. +""" + +from kubernetes.client import CoreV1Api, ApiException + + +def create_namespace(api_client, name, manifest, logger): + """ + Создает новое пространство имен с заданным именем + и в соответствии с переданным манифестом. + + Функция является идемпотентной. + Если пространство имен существует, то обновляет его. + Если пространство имен отсутствует, то создает его. + + :param api_client: Kubernetes API клиент + :param name: Имя пространства имен + :param manifest: Спецификация пространства имен + :param logger: kopf logger + :return: None + """ + core_v1_api = CoreV1Api(api_client) + try: + core_v1_api.create_namespace(body=manifest) + except ApiException as exc: + if exc.status == 409: + core_v1_api.replace_namespace(name=name, body=manifest) + return + raise exc diff --git a/controller/src/basic_resources/network_policies.py b/controller/src/basic_resources/network_policies.py new file mode 100644 index 0000000..244096a --- /dev/null +++ b/controller/src/basic_resources/network_policies.py @@ -0,0 +1,44 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Управления базовыми объектами Kubernetes +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +""" +Network policies module. Implements reusable network policies-related functions. +""" + +from kubernetes.client import NetworkingV1Api, ApiException, ApiClient + + +def create_network_policy(api_client: ApiClient, manifest, namespace, logger): + networking_v1_api = NetworkingV1Api(api_client) + data = manifest + np = networking_v1_api.create_namespaced_network_policy(namespace=namespace, body=data) + logger.info(f"NetworkPolicy is created: {np}") + + +def delete_network_policy_if_exists(api_client: ApiClient, np_name, namespace, logger): + networking_v1_api = NetworkingV1Api(api_client) + try: + networking_v1_api.delete_namespaced_network_policy(name=np_name, namespace=namespace) + except ApiException as exc: + if exc.status == 404: + logger.info(f"NetworkPolicy {np_name} doesnt exist, do nothing") + return + raise exc + logger.info(f"NetworkPolicy {np_name} is deleted") + + +def create_or_update_network_policy(api_client: ApiClient, name: str, namespace: str, manifest, + logger): + networking_v1_api = NetworkingV1Api(api_client) + + try: + networking_v1_api.create_namespaced_network_policy(namespace=namespace, body=manifest) + logger.info(f"Network policy {name} is created") + except ApiException as exc: + if exc.status == 409: + logger.warning(f'Network policy {name} already exists, will be replaced') + networking_v1_api.replace_namespaced_network_policy(name=name, namespace=namespace, body=manifest) + logger.info(f"Network policy {name} is replaced") diff --git a/controller/src/basic_resources/rbac.py b/controller/src/basic_resources/rbac.py new file mode 100644 index 0000000..274410e --- /dev/null +++ b/controller/src/basic_resources/rbac.py @@ -0,0 +1,148 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Управления базовыми объектами Kubernetes +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +""" +RBAC basic resources module. Implements reusable RBAC-related functions. +""" + +import kopf +from kubernetes.client import RbacAuthorizationV1Api, ApiException, CoreV1Api, ApiClient + +_DEFAULT_SA_NAME = 'default' + + +def update_default_sa(api_client, namespace, manifest, logger): + """ + Обновляет сервисный аккаунт (ServiceAccount) 'default'. + + Функция является идемпотентной. + + Если сервисный аккаунт отсутствует, то обработчик выбрасывает + исключение kopf.TemporaryError, что приводит к повторному + вызову метода спустия заданную задержку. + + Если сервисный аккаунт существует, то его спецификация + замещается переданной в параметре `manifest`. + + :api_client: Kubernetes API клиент + :param namespace: Пространство имен + :param manifest: Спецификация сервисного аккаунта + :param logger: kopf logger + :return: None. + """ + core_v1_api = CoreV1Api(api_client) + try: + core_v1_api.read_namespaced_service_account(_DEFAULT_SA_NAME, namespace) + except ApiException as exc: + if exc.status == 404: + # SA с именем 'default' всегда существует и создается Kubernetes, + # если отсутствует - нужно подождать + logger.info(f'SA {_DEFAULT_SA_NAME} does not exists.') + raise kopf.TemporaryError(f"Waiting for SA {_DEFAULT_SA_NAME} " + f"to be created by Kubernetes system...", + delay=10) + raise exc + logger.info(f"SA {_DEFAULT_SA_NAME} exists, trying to replace...") + core_v1_api.replace_namespaced_service_account(name=_DEFAULT_SA_NAME, namespace=namespace, body=manifest) + + +def delete_sa_if_exists(api_client: ApiClient, name, namespace, logger): + core_v1_api = CoreV1Api(api_client) + try: + # не имеет смысла для default SA - будет пересоздан Kubernetes + # оставлено для общего соответствия и на случай изменения имени SA + core_v1_api.delete_namespaced_service_account(name=name, namespace=namespace) + except ApiException as exc: + if exc.status == 404: + logger.warn(f"SA {name} doesnt exist, do nothing") + return + raise exc + logger.info(f"SA {name} is deleted") + + +def create_role(api_client, name, namespace, manifest): + """ + Создает роль (Role). + + Функция является идемпотентной. Если роль существует, + то она будет обновлена. + + :param api_client: Kubernetes API клиент + :param name: Имя роли + :param namespace: Пространство имен + :param manifest: Спецификация роли + :return: None. + """ + rbac_v1_api = RbacAuthorizationV1Api(api_client) + rbac_v1_api.replace_namespaced_role(name=name, namespace=namespace, body=manifest) + + +def delete_role_if_exists(api_client, name, namespace, logger): + """ + Удаляет роль (Role), если она существует. + + Функция является идемпотентной. + Если роль существует, то она будет удалена. + Если роль не существует, то ничего не произойдет. + + :param api_client: Kuberentes API клиент + :param name: Имя роли + :param namespace: Пространство имен + :param logger: kopf logger + :return: None + """ + rbac_v1_api = RbacAuthorizationV1Api(api_client) + try: + rbac_v1_api.delete_namespaced_role(name=name, namespace=namespace) + except ApiException as exc: + if exc.status == 404: + logger.warn(f"Role {name} doesnt exist, do nothing") + return + raise exc + logger.info(f"Role {name} is deleted") + + +def create_rb(api_client, name, namespace, manifest): + """ + Создает привязку роли (RoleBinding). + + Функция является идемпотентной. Если привязка роли существует, + то она будет обновлена. + + :param api_client: Kubernetes API клиент + :param name: Имя привязки роли + :param namespace: Пространство имен + :param manifest: Спецификация привязки роли + :return: None. + """ + rbac_v1_api = RbacAuthorizationV1Api(api_client) + rbac_v1_api.replace_namespaced_role_binding(name=name, namespace=namespace, body=manifest) + + +def delete_rb_if_exists(api_client, name, namespace, logger): + """ + Удаляет привязку роли (RoleBinding), если она существует. + + Функция является идемпотентной. + Если привязка роли существует, то она будет удалена. + Если привязка роли не существует, то ничего не произойдет. + + :param api_client: Kuberentes API клиент + :param name: Имя привязки роли + :param namespace: Пространство имен + :param logger: kopf logger + :return: None + """ + rbac_v1_api = RbacAuthorizationV1Api(api_client) + try: + rbac_v1_api.delete_namespaced_role_binding(name=name, + namespace=namespace) + except ApiException as exc: + if exc.status == 404: + logger.warn(f"RoleBinding {name} doesnt exist, do nothing") + return + raise exc + logger.info(f"RoleBinding {name} is deleted") diff --git a/controller/src/basic_resources/secrets.py b/controller/src/basic_resources/secrets.py new file mode 100644 index 0000000..4d5322c --- /dev/null +++ b/controller/src/basic_resources/secrets.py @@ -0,0 +1,193 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Управления базовыми объектами Kubernetes +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +import base64 + +import yaml +from kubernetes.client import ApiClient, CoreV1Api, ApiException, V1Secret, V1SecretList + +from basic_resources.jinja import basic_jinja_env +from exceptions import ObjectAlreadyExistsTemporaryError + +SECRET_TEMPLATE = 'secret.yaml' + + +def prepare_secret_manifest(name, namespace, type_, data: list[dict], data_attr='data', labels=None, annotations=None): + template = basic_jinja_env.get_template(SECRET_TEMPLATE) + variables = { + 'name': name, + 'namespace': namespace, + 'type': type_, + 'data': data, + 'data_attr': data_attr + } + if labels: + variables['labels'] = labels + if annotations: + variables['annotations'] = annotations + text = template.render(variables) + manifest = yaml.safe_load(text) + return manifest + + +def create_secret_if_not_exists(api_client: ApiClient, name, namespace, manifest, logger): + core_v1_api = CoreV1Api(api_client) + try: + core_v1_api.read_namespaced_secret(name, namespace) + except ApiException as exc: + if exc.status == 404: + core_v1_api.create_namespaced_secret(namespace, body=manifest) + return + raise exc + logger.info(f"Secret {name} already exists, do nothing") + + +def try_create_secret(api_client: ApiClient, name, namespace, manifest, logger): + core_v1_api = CoreV1Api(api_client) + try: + core_v1_api.create_namespaced_secret(namespace, body=manifest) + except ApiException as exc: + if exc.status == 409: + logger.info(f"Secret {name} already exists, do nothing") + raise exc + + +def delete_secret_if_exists(api_client: ApiClient, name, namespace, logger): + core_v1_api = CoreV1Api(api_client) + try: + core_v1_api.delete_namespaced_secret(name=name, namespace=namespace) + except ApiException as exc: + if exc.status == 404: + logger.info(f"Secret {name} doesnt exist, do nothing") + return + raise exc + logger.info(f"Secret {name} is deleted") + + +def create_secret(api_client: ApiClient, name, namespace, manifest, logger): + core_v1_api = CoreV1Api(api_client) + try: + core_v1_api.create_namespaced_secret(namespace, body=manifest) + except ApiException as exc: + if exc.status == 409: + raise ObjectAlreadyExistsTemporaryError + raise exc + + +def update_secret(api_client: ApiClient, name, namespace, manifest, logger): + core_v1_api = CoreV1Api(api_client) + core_v1_api.replace_namespaced_secret(name=name, namespace=namespace, body=manifest) + + +def create_or_update_secret(api_client: ApiClient, name, namespace, manifest, logger): + try: + create_secret(api_client=api_client, + name=name, + namespace=namespace, + manifest=manifest, + logger=logger) + except ObjectAlreadyExistsTemporaryError as exc: + update_secret(api_client=api_client, + name=name, + namespace=namespace, + manifest=manifest, + logger=logger) + + +def read_secret_if_exists(api_client: ApiClient, name, namespace) -> V1Secret | None: + core_v1_api = CoreV1Api(api_client) + try: + secret = core_v1_api.read_namespaced_secret(name, namespace) + return secret + except ApiException as exc: + if exc.status == 404: + return None + raise exc + + +def list_secrets(api_client: ApiClient, namespace, labels: dict) -> V1SecretList: + core_v1_api = CoreV1Api(api_client) + label_selector = ','.join(f'{label}={value}' for label, value in labels.items()) if labels else None + if label_selector: + secrets = core_v1_api.list_namespaced_secret(namespace, label_selector=label_selector) + else: + secrets = core_v1_api.list_namespaced_secret(namespace) + return secrets + + +def patch_secret_if_exists(api_client: ApiClient, name, namespace, patch) -> V1Secret | None: + core_v1_api = CoreV1Api(api_client) + try: + secret = core_v1_api.patch_namespaced_secret(name, namespace, patch) + return secret + except ApiException as exc: + if exc.status == 404: + return None + raise exc + + +def set_secret_annotations_and_labels(api_client: ApiClient, name, namespace, annotations, labels, logger): + secret = read_secret_if_exists(api_client, name, namespace) + if not secret: + logger.warning(f'Secret {namespace}.{name} does not exist') + return + + patch = {'metadata': {'annotations': annotations, 'labels': labels}} + + patch_secret_if_exists(api_client, name, namespace, patch) + + +def copy_secret_data(api_client: ApiClient, source_secret_body, dest_secret_name, + dest_namespace, logger): + data = [{'key': item[0], 'value': item[1]} for item in source_secret_body['data'].items()] + manifest = prepare_secret_manifest(dest_secret_name, dest_namespace, source_secret_body['type'], data) + + create_or_update_secret(api_client=api_client, + name=dest_secret_name, + namespace=dest_namespace, + manifest=manifest, + logger=logger) + + +def copy_secret_silently(api_client: ApiClient, source_secret_name, source_namespace, dest_secret_name, + dest_namespace, logger): + secret_obj = read_secret_if_exists(api_client, source_secret_name, source_namespace) + if not secret_obj: + logger.warning(f'source secret {source_namespace}.{source_secret_name} does not exist, ' + f'copying skipped') + return + + secret_body = secret_obj.to_dict() + + copy_secret_data(api_client, secret_body, dest_secret_name, dest_namespace, logger) + + +def read_basic_auth_credentials_from_secret(secret, secret_name, secret_namespace, logger, + creds_attr_name='credentials'): + secret_data = secret.to_dict()['data'] + if creds_attr_name not in secret_data: + logger.warning(f'{creds_attr_name} field in secret {secret_namespace}.{secret_name} ' + f'does not exist') + return + + secret_creds = secret_data[creds_attr_name] + secret_creds_decoded = base64.b64decode(secret_creds).decode('utf-8').strip() + + if not secret_creds_decoded: + logger.warning(f'auth field in secret {secret_namespace}.{secret_name} ' + f'is empty') + return + + result = [] + for cred in secret_creds_decoded.split('\n'): + if ':' not in cred: + logger.warning(f'wrong credentials format in secret {secret_namespace}.{secret_name}, ' + f'some credentials may be omitted') + continue + sep_index = cred.find(':') + user, password = cred[:sep_index], cred[sep_index + 1:] + result.append((user, password)) + return result diff --git a/controller/src/basic_resources/services.py b/controller/src/basic_resources/services.py new file mode 100644 index 0000000..20d704a --- /dev/null +++ b/controller/src/basic_resources/services.py @@ -0,0 +1,38 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Управления базовыми объектами Kubernetes +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2025 г. +# ============================================================ +from kubernetes.client import ApiClient, CoreV1Api, ApiException + + +def delete_svc_if_exists(api_client: ApiClient, namespace: str, svc_name: str, logger): + core_v1_api = CoreV1Api(api_client) + try: + core_v1_api.delete_namespaced_service(name=svc_name, namespace=namespace) + except ApiException as exc: + if exc.status == 404: + logger.info(f"Service {svc_name} doesnt exist, do nothing") + return + raise exc + logger.info(f"Service {svc_name} is deleted") + + +def create_service(api_client: ApiClient, namespace, manifest): + core_v1_api = CoreV1Api(api_client) + core_v1_api.create_namespaced_service(namespace=namespace, body=manifest) + + +def create_or_update_service(api_client: ApiClient, name: str, namespace: str, manifest, + logger): + core_v1_api = CoreV1Api(api_client) + + try: + core_v1_api.create_namespaced_service(namespace=namespace, body=manifest) + logger.info(f"Service {name} is created") + except ApiException as exc: + if exc.status == 409: + logger.warning(f'Service {name} already exists, will be replaced') + core_v1_api.replace_namespaced_service(name=name, namespace=namespace, body=manifest) + logger.info(f"Service {name} is replaced") \ No newline at end of file diff --git a/controller/src/bound.py b/controller/src/bound.py new file mode 100644 index 0000000..e1d0a26 --- /dev/null +++ b/controller/src/bound.py @@ -0,0 +1,33 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Утилиты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +from config import UNIP_CONTROLLER_DEV + + +def not_dev_namespace(body, **_): + if UNIP_CONTROLLER_DEV == 'True' or UNIP_CONTROLLER_DEV is True: + return True + metadata = body.get('metadata', None) + if not metadata: + return False + namespace: str = metadata.get('namespace', None) + if not namespace: + return False + if namespace.startswith('dev-'): + return False + return True + + +def in_pu_namespace(body, **_): + metadata = body.get('metadata', None) + if not metadata: + return False + namespace: str = metadata.get('namespace', None) + if not namespace: + return False + if (namespace.startswith('pu-') or '-pu-' in namespace) and '-pa-' not in namespace: + return True + return False \ No newline at end of file diff --git a/controller/src/box/__init__.py b/controller/src/box/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/controller/src/box/config.py b/controller/src/box/config.py new file mode 100644 index 0000000..337bd9e --- /dev/null +++ b/controller/src/box/config.py @@ -0,0 +1,11 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: DataBox +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +import os + +UNIP_BOXES_S3_DEFAULT_USER_DATA_BUCKET = os.getenv('UNIP_BOXES_S3_DEFAULT_USER_DATA_BUCKET') +UNIP_BOXES_CSI_S3_SECRET_NAME = os.getenv('UNIP_BOXES_CSI_S3_SECRET_NAME') +UNIP_BOXES_CSI_S3_STORAGE_CLASS = os.getenv('UNIP_BOXES_CSI_S3_STORAGE_CLASS') \ No newline at end of file diff --git a/controller/src/box/handlers.py b/controller/src/box/handlers.py new file mode 100644 index 0000000..b0cc6fa --- /dev/null +++ b/controller/src/box/handlers.py @@ -0,0 +1,877 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: DataBox +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +import base64 +import uuid +from datetime import datetime, timezone +from typing import Sequence, Union + +import kopf +import yaml +from kopf import PermanentError, TemporaryError +from kubernetes.client import CoreV1Api, V1Secret, ApiException, V1PersistentVolumeList, CustomObjectsApi +from minio import Minio + +from bound import not_dev_namespace +from box.config import UNIP_BOXES_S3_DEFAULT_USER_DATA_BUCKET, UNIP_BOXES_CSI_S3_SECRET_NAME, \ + UNIP_BOXES_CSI_S3_STORAGE_CLASS +from box.jinja import jinja_env +from exceptions import InputValidationPermanentError, \ + ObjectDoesNotExistTemporaryError, InternalErrorPermanentError, InputValidationTemporaryError +from kopf_k8s_client import api_client + +UNIP_CONTROLLER_NAMESPACE = 'unip-system-controller' + +S3_PLATFORM_USER_SECRET_NAME = 'csi-s3-secret' + +CSI_S3_PV_NAME_SUFFIX = '-csi-s3-pv' +CSI_S3_PVC_NAME_SUFFIX = '-csi-s3-pvc' +PV_FULL_NAME_LABEL = 'unified-platform.cs.hse.ru/pv-full-name' +PV_FULL_NAME_TEMPLATE = '{platform_app_name}-{box_name}{suffix}' + +CSI_S3_PLATFORM_USER_STORAGE_CLASS_NAME_SUFFIX = '-csi-s3-sc' + +BOX_OWNER_NAME = 'developer' + +WAITING_PVC_READINESS = 'WaitingPVCReadiness' +WAITING_PV_READINESS = 'WaitingPVReadiness' +PVC_IS_READY = 'PVCIsReady' +PV_IS_READY = 'PVIsReady' +PVC_FAILED = 'PVCAllocationFailed' +PV_FAILED = 'PVAllocationFailed' +WAITING_PVC_IS_DELETED = 'WaitingPVCIsDeleted' +WAITING_PV_IS_DELETED = 'WaitingPVIsDeleted' +PVC_IS_DELETED = 'PVCIsDeleted' +PV_IS_DELETED = 'PVIsDeleted' + +FAILURE = 'Failure' +READY = 'Ready' +DELETING = 'Deleting' + +MAX_RETRIES = 10 + + +class PVIsNotSet(PermanentError): + pass + + +class PVorPVCAlreadyExists(PermanentError): + pass + + +class PVorPVCAllocationTimeout(PermanentError): + pass + + +class AllocationFailedError(PermanentError): + pass + + +class AllocationTimeoutError(PermanentError): + pass + + +class WaitingAllocationError(TemporaryError): + pass + + +class WaitingDeletionError(TemporaryError): + pass + + +def _prepare_manifest(template_name, variables): + template = jinja_env.get_template(template_name) + text = template.render(variables) + data = yaml.safe_load(text) + return data + + +def _check_box_has_valid_kind(spec): + if 's3Storage' not in spec \ + and 's3DefaultStorage' not in spec \ + and 'datasetReference' not in spec: + raise InputValidationPermanentError('Only s3Storage, s3DefaultStorage, datasetReference are implemented now') + + +def _get_s3_client_from_secret(secret_body: dict): + if 'data' not in secret_body: + raise InputValidationPermanentError(f'data not set in secret {S3_PLATFORM_USER_SECRET_NAME}') + data = secret_body['data'] + if not (req_fields := {'accessKeyID', 'secretAccessKey', 'endpoint'}) <= data.keys(): + raise InputValidationPermanentError(f'some of {req_fields} not set in secret {S3_PLATFORM_USER_SECRET_NAME}') + + access_key = base64.b64decode(data['accessKeyID']).decode('utf-8') + secret_key = base64.b64decode(data['secretAccessKey']).decode('utf-8') + endpoint = base64.b64decode(data['endpoint']).decode('utf-8') + endpoint = endpoint.replace('https://', '').replace('http://', '') + + s3_client = Minio(endpoint=endpoint, access_key=access_key, secret_key=secret_key) + return s3_client + + +def _get_s3_client_using_s3_platform_user_creds(core_v1_api: CoreV1Api, namespace): + try: + secret: V1Secret = core_v1_api.read_namespaced_secret(name=S3_PLATFORM_USER_SECRET_NAME, + namespace=namespace) + secret_body = secret.to_dict() + except ApiException as exc: + if exc.status == 404: + raise InputValidationTemporaryError(f'CSI S3 Secret not found, used secret name: ' + f'{S3_PLATFORM_USER_SECRET_NAME}', delay=15) + raise exc + + s3_client = _get_s3_client_from_secret(secret_body) + return s3_client + + +def _get_s3_client_using_controller_creds(core_v1_api: CoreV1Api): + try: + secret: V1Secret = core_v1_api.read_namespaced_secret(name=UNIP_BOXES_CSI_S3_SECRET_NAME, + namespace=UNIP_CONTROLLER_NAMESPACE) + secret_body = secret.to_dict() + except ApiException as exc: + if exc.status == 404: + raise InputValidationPermanentError(f'Controller S3 Secret not found, used secret name: ' + f'{UNIP_BOXES_CSI_S3_SECRET_NAME}') + raise exc + + s3_client = _get_s3_client_from_secret(secret_body) + return s3_client + + +def _get_s3_box(co_api: CustomObjectsApi, name, namespace): + try: + box_obj = co_api.get_namespaced_custom_object( + "unified-platform.cs.hse.ru", "v1", namespace, + "databoxes", name) + except ApiException as exc: + if exc.status == 404: + raise ObjectDoesNotExistTemporaryError( + f'DatasetReference box {name} doesnt exist in namespace {namespace}') + raise exc + + box_spec = box_obj['spec'] + if 's3Storage' not in box_spec and 's3DefaultStorage' not in box_spec: + raise InputValidationPermanentError(f'Dataset box {namespace}.{name} ' + f'is not s3Storage and not s3DefaultStorage') + return box_obj + + +def _get_dataset(co_api: CustomObjectsApi, spec, namespace): + dataset_ref = spec['datasetReference'] + dataset_cmp_ref = dataset_ref['datasetComponentRef'] + dataset_name = dataset_cmp_ref['name'] + dataset_namespace = dataset_cmp_ref.get('namespace', namespace) + + try: + dataset_obj = co_api.get_namespaced_custom_object( + "unified-platform.cs.hse.ru", "v1", dataset_namespace, + "datasetcomponents", dataset_name) + return dataset_obj + except ApiException as exc: + if exc.status == 404: + raise ObjectDoesNotExistTemporaryError( + f'DatasetReference {dataset_name} doesnt exist in namespace {dataset_namespace}') + raise exc + +def _get_s3_box_from_dataset_ref(co_api: CustomObjectsApi, spec, namespace): + dataset_obj = _get_dataset(co_api, spec, namespace) + dataset_namespace = dataset_obj['metadata']['namespace'] + dataset_spec = dataset_obj['spec'] + box_name = dataset_spec['box'] + + box_obj = _get_s3_box(co_api, box_name, dataset_namespace) + return box_obj + + +def _check_if_dataset_exists(core_v1_api: CoreV1Api, co_api: CustomObjectsApi, spec, namespace): + dataset_ref = spec['datasetReference'] + dataset_cmp_ref = dataset_ref['datasetComponentRef'] + dataset_namespace = dataset_cmp_ref.get('namespace', namespace) + + box_obj = _get_s3_box_from_dataset_ref(co_api, spec, namespace) + box_spec = box_obj['spec'] + + _check_if_bucket_exists(core_v1_api, box_spec, dataset_namespace) + + +def _check_if_bucket_exists(core_v1_api: CoreV1Api, spec, namespace): + s3_client = None + bucket_name = None + + if 's3Storage' in spec: + s3_storage = spec['s3Storage'] + bucket = s3_storage['bucket'] + bucket_name = bucket['name'] + s3_client = _get_s3_client_using_s3_platform_user_creds(core_v1_api, namespace) + if 's3DefaultStorage' in spec: + bucket_name = UNIP_BOXES_S3_DEFAULT_USER_DATA_BUCKET + if not bucket_name: + raise InternalErrorPermanentError('Platform default user data bucket not specified') + s3_client = _get_s3_client_using_controller_creds(core_v1_api) + + if not s3_client.bucket_exists(bucket_name): + raise ObjectDoesNotExistTemporaryError(f'Bucket {bucket_name} does not exist') + + +def _check_if_related_objects_exist(core_v1_api: CoreV1Api, co_api: CustomObjectsApi, spec, namespace): + if 's3Storage' in spec or 's3DefaultStorage' in spec: + _check_if_bucket_exists(core_v1_api, spec, namespace) + elif 'datasetReference' in spec: + _check_if_dataset_exists(core_v1_api, co_api, spec, namespace) + else: + raise InputValidationPermanentError('Only s3Storage, s3DefaultStorage, datasetReference are implemented now') + + +def _get_pv_full_name(platform_app_name, box_name): + pv_full_name = PV_FULL_NAME_TEMPLATE.format(platform_app_name=platform_app_name, + box_name=box_name, + suffix=CSI_S3_PV_NAME_SUFFIX) + return pv_full_name + + +def _get_pvc_name(box_name): + pvc_name = box_name + CSI_S3_PVC_NAME_SUFFIX + return pvc_name + + +def _check_if_pv_is_set(status): + if 's3Storage' in status: + return ('csiS3PersistentVolumeName' in status['s3Storage']) \ + and (status['s3Storage']['csiS3PersistentVolumeName'] is not None) + return False + + +def _check_if_pvc_is_set(status): + if 's3Storage' in status: + return ('csiS3PersistentVolumeClaimName' in status['s3Storage']) and \ + (status['s3Storage']['csiS3PersistentVolumeClaimName'] is not None) + return False + + +def _check_if_pv_does_not_exist(core_v1_api: CoreV1Api, pv_full_name, logger): + pvs: V1PersistentVolumeList = core_v1_api.list_persistent_volume( + label_selector=f'{PV_FULL_NAME_LABEL}={pv_full_name}') + if len(pvs.items) != 0: + logger.error(f"Persistent volume with label {PV_FULL_NAME_LABEL}={pv_full_name} already exists") + return False + return True + + +def _check_if_pvc_does_not_exist(core_v1_api: CoreV1Api, pvc_name, namespace, logger): + try: + core_v1_api.read_namespaced_persistent_volume_claim(pvc_name, namespace) + except ApiException as exc: + if exc.status == 404: + return True + raise exc + logger.error(f"PVC {pvc_name} in namespace {namespace} already exists") + return False + + +def _get_condition(type_, reason, message): + return { + 'type': type_, + 'conditionStatus': 'True', + 'lastTransitionTime': datetime.now(timezone.utc).isoformat(), + 'reason': reason, + 'message': message + } + + +def _get_failed_condition(reason, message): + return _get_condition(FAILURE, reason, message) + + +def _get_waiting_pv_ready_condition(): + return _get_condition(WAITING_PV_READINESS, "", "") + + +def _get_pv_is_ready_condition(): + return _get_condition(PV_IS_READY, "", "") + + +def _get_pv_failed_condition(): + return _get_condition(PV_FAILED, "", "") + + +def _get_waiting_pv_is_deleted_condition(): + return _get_condition(WAITING_PV_IS_DELETED, "", "") + + +def _get_pv_is_deleted_condition(): + return _get_condition(PV_IS_DELETED, "", "") + + +def _get_waiting_pvc_ready_condition(): + return _get_condition(WAITING_PVC_READINESS, "", "") + + +def _get_pvc_is_ready_condition(): + return _get_condition(PVC_IS_READY, "", "") + + +def _get_pvc_failed_condition(): + return _get_condition(PVC_FAILED, "", "") + + +def _get_waiting_pvc_is_deleted_condition(): + return _get_condition(WAITING_PVC_IS_DELETED, "", "") + + +def _get_pvc_is_deleted_condition(): + return _get_condition(PVC_IS_DELETED, "", "") + + +def _get_box_is_ready_condition(): + return _get_condition(READY, "", "") + + +def _get_box_failure_condition(reason="", message=""): + return _get_condition(FAILURE, reason, message) + + +def _get_box_deleting_condition(reason="", message=""): + return _get_condition(DELETING, reason, message) + + +def _make_condition_transition(patch, condition_from_type: Union[Sequence, str], condition_to): + conditions_patch = patch['status']['conditions'] + conditions_from = [condition_from_type] if isinstance(condition_from_type, str) else condition_from_type + for condition_from in conditions_from: + for c in conditions_patch: + if c['type'] == condition_from and c['conditionStatus'] == 'True': + c['conditionStatus'] = 'False' + c['lastTransitionTime'] = datetime.now(timezone.utc).isoformat() + conditions_patch.append(condition_to) + + +def _set_pvc_is_ready(patch): + _make_condition_transition(patch, WAITING_PVC_READINESS, _get_pvc_is_ready_condition()) + + +def _set_pvc_failed(patch): + _make_condition_transition(patch, WAITING_PVC_READINESS, _get_pvc_failed_condition()) + + +def _set_pv_is_ready(patch): + _make_condition_transition(patch, WAITING_PV_READINESS, _get_pv_is_ready_condition()) + + +def _set_pv_failed(patch): + _make_condition_transition(patch, WAITING_PV_READINESS, _get_pv_failed_condition()) + + +def _set_box_is_ready(patch): + conditions_patch = patch['status']['conditions'] + conditions_patch.append(_get_box_is_ready_condition()) + + +def _set_box_failure(patch, reason="", message=""): + _make_condition_transition(patch, READY, _get_box_failure_condition(reason, message)) + + +def _get_and_update_pvc_status(core_v1_api: CoreV1Api, namespace, patch): + pvc_is_ready = False + pvc_failed = False + status = patch['status'] + conditions = status['conditions'] + for c in conditions: + if c['type'] == PVC_IS_READY and c['conditionStatus'] == 'True': + pvc_is_ready = True + break + if c['type'] == PVC_FAILED and c['conditionStatus'] == 'True': + pvc_failed = True + break + if c['type'] == WAITING_PVC_READINESS and c['conditionStatus'] == 'True': + pvc_name = status['s3Storage']['csiS3PersistentVolumeClaimName'] + pvc = core_v1_api.read_namespaced_persistent_volume_claim(name=pvc_name, namespace=namespace) + if pvc.status.phase in {'Available', 'Bound'}: + _set_pvc_is_ready(patch) + pvc_is_ready = True + break + if pvc.status.phase == 'Failed': + _set_pvc_failed(patch) + pvc_failed = True + break + return pvc_is_ready, pvc_failed + + +def _get_and_update_pv_status(core_v1_api: CoreV1Api, patch): + pv_is_ready = False + pv_failed = False + status = patch['status'] + conditions = status['conditions'] + for c in conditions: + if c['type'] == PV_IS_READY and c['conditionStatus'] == 'True': + pv_is_ready = True + break + if c['type'] == PV_FAILED and c['conditionStatus'] == 'True': + pv_failed = True + break + if c['type'] == WAITING_PV_READINESS and c['conditionStatus'] == 'True': + pv_name = status['s3Storage']['csiS3PersistentVolumeName'] + pv = core_v1_api.read_persistent_volume(name=pv_name) + if pv.status.phase in {'Available', 'Bound'}: + _set_pv_is_ready(patch) + pv_is_ready = True + break + if pv.status.phase == 'Failed': + _set_pv_failed(patch) + pv_failed = True + break + return pv_is_ready, pv_failed + + +def _check_box_is_ready(status): + conditions = status['conditions'] + return any(c['conditionStatus'] == 'True' for c in conditions if c['type'] == READY) + + +def _check_box_failure(status): + conditions = status['conditions'] + return any(c['conditionStatus'] == 'True' for c in conditions if c['type'] == FAILURE) + + +def _check_allocation_and_change_status(core_v1_api: CoreV1Api, namespace, patch, retry_num): + patch_status = patch['status'] + + pvc_is_ready, pvc_failed = _get_and_update_pvc_status(core_v1_api, namespace, patch) + pv_is_ready, pv_failed = _get_and_update_pv_status(core_v1_api, patch) + + if pvc_is_ready and pv_is_ready: + _set_box_is_ready(patch) + return + + if pv_failed or pvc_failed: + _set_box_failure(patch) + raise AllocationFailedError + + if _check_box_is_ready(patch_status): + return + if _check_box_failure(patch_status): + return + + if retry_num >= MAX_RETRIES - 1: + _set_box_failure(patch) + raise AllocationTimeoutError + + raise WaitingAllocationError(delay=30) + + +def _create_pv_resource(core_v1_api: CoreV1Api, pv_full_name, + manifest, logger): + pvs: V1PersistentVolumeList = core_v1_api.list_persistent_volume( + label_selector=f'{PV_FULL_NAME_LABEL}={pv_full_name}') + if len(pvs.items) != 0: + logger.info(f"Persistent volume with label {PV_FULL_NAME_LABEL}={pv_full_name} already exists, do nothing") + return + core_v1_api.create_persistent_volume(body=manifest) + + +def _get_s3_storage_attrs(spec): + s3_storage = spec['s3Storage'] + capacity = s3_storage['capacity'] + bucket = s3_storage['bucket'] + bucket_name = bucket['name'] + if 'subPath' in bucket: + bucket_mount_sub_path = bucket['subPath'] + bucket_path = bucket_name + '/' + bucket_mount_sub_path if bucket_mount_sub_path[0] != '/' \ + else bucket_name + bucket_mount_sub_path + else: + bucket_path = bucket_name + return capacity, bucket_name, bucket_path + +def _get_s3_default_storage_attrs(spec, namespace, box_name): + s3_storage = spec['s3DefaultStorage'] + capacity = s3_storage['capacity'] + bucket_name = UNIP_BOXES_S3_DEFAULT_USER_DATA_BUCKET + bucket_path = bucket_name + '/' + namespace + '/' + box_name + return capacity, bucket_name, bucket_path + + +def _create_csi_s3_pv(core_v1_api: CoreV1Api, co_api: CustomObjectsApi, namespace, box_name, spec): + if 's3Storage' in spec: + capacity, bucket_name, bucket_path = _get_s3_storage_attrs(spec) + storage_class = namespace + CSI_S3_PLATFORM_USER_STORAGE_CLASS_NAME_SUFFIX + pv_namespace = namespace + elif 's3DefaultStorage' in spec: + capacity, bucket_name, bucket_path = _get_s3_default_storage_attrs(spec, namespace, box_name) + storage_class = UNIP_BOXES_CSI_S3_STORAGE_CLASS + pv_namespace = UNIP_CONTROLLER_NAMESPACE + elif 'datasetReference' in spec: + dataset_ref = spec['datasetReference'] + dataset_cmp_ref = dataset_ref['datasetComponentRef'] + box_obj = _get_s3_box_from_dataset_ref(co_api, spec, namespace) + box_spec = box_obj['spec'] + dataset_box_name = box_obj['metadata']['name'] + dataset_box_namespace = dataset_cmp_ref.get('namespace', namespace) + if 's3Storage' in box_spec: + capacity, bucket_name, bucket_path = _get_s3_storage_attrs(box_spec) + storage_class = dataset_box_namespace + CSI_S3_PLATFORM_USER_STORAGE_CLASS_NAME_SUFFIX + pv_namespace = dataset_box_namespace + elif 's3DefaultStorage' in box_spec: + capacity, bucket_name, bucket_path = _get_s3_default_storage_attrs(box_spec, dataset_box_namespace, dataset_box_name) + storage_class = UNIP_BOXES_CSI_S3_STORAGE_CLASS + pv_namespace = UNIP_CONTROLLER_NAMESPACE + else: + raise InputValidationPermanentError('DatasetReference must reference s3Storage or s3DefaultStorage') + bucket_path = bucket_path.rstrip('/') + bucket_path = bucket_path + '/users/' + BOX_OWNER_NAME + '/file_groups' + else: + raise InputValidationPermanentError('Only s3Storage, s3DefaultStorage, datasetReference are implemented now') + + pv_full_name = _get_pv_full_name(platform_app_name=namespace, box_name=box_name) + pv_name = str(uuid.uuid4()) + CSI_S3_PV_NAME_SUFFIX + pvc_name = _get_pvc_name(box_name=box_name) + + pv_vars = { + 'name': pv_name, + 'namespace': pv_namespace, + 'storage_class': storage_class, + 'capacity': capacity, + 'pvc_namespace': namespace, + 'pvc_name': pvc_name, + 'bucket_name_with_path_inside_bucket': bucket_path, + 'labels': [{'key': PV_FULL_NAME_LABEL, 'value': pv_full_name}] + } + + pv_manifest = _prepare_manifest('csi-s3-pv.yaml', pv_vars) + + pv = core_v1_api.create_persistent_volume(body=pv_manifest) + return pv.metadata.uid, pv_name + + +def _create_csi_s3_pvc(core_v1_api: CoreV1Api, co_api: CustomObjectsApi, namespace, box_name, spec, pv_name): + pvc_name = _get_pvc_name(box_name=box_name) + + if 's3Storage' in spec: + s3_storage = spec['s3Storage'] + capacity = s3_storage['capacity'] + elif 's3DefaultStorage' in spec: + s3_storage = spec['s3DefaultStorage'] + capacity = s3_storage['capacity'] + elif 'datasetReference' in spec: + box_obj = _get_s3_box_from_dataset_ref(co_api, spec, namespace) + box_spec = box_obj['spec'] + if 's3Storage' in box_spec: + s3_storage = spec['s3Storage'] + capacity = s3_storage['capacity'] + elif 's3DefaultStorage' in box_spec: + s3_storage = box_spec['s3DefaultStorage'] + capacity = s3_storage['capacity'] + else: + raise InputValidationPermanentError('datasetReference must reference s3Storage or s3DefaultStorage') + else: + raise InputValidationPermanentError('Only s3Storage, s3DefaultStorage, datasetReference are implemented now') + + pvc_vars = { + 'name': pvc_name, + 'namespace': namespace, + 'pv_name': pv_name, + 'capacity': capacity + } + + pvc_manifest = _prepare_manifest('csi-s3-pvc.yaml', pvc_vars) + + pvc = core_v1_api.create_namespaced_persistent_volume_claim(namespace=namespace, body=pvc_manifest) + return pvc.metadata.uid, pvc_name + + +def _create_csi_s3_pv_and_set_status(patch, core_v1_api: CoreV1Api, co_api: CustomObjectsApi, + name, spec, namespace): + pv_id, pv_name = _create_csi_s3_pv(core_v1_api, co_api, namespace, name, spec) + patch['status'].setdefault('s3Storage', {}) + patch['status']['s3Storage']['csiS3PersistentVolumeUID'] = pv_id + patch['status']['s3Storage']['csiS3PersistentVolumeName'] = pv_name + condition = _get_waiting_pv_ready_condition() + patch['status']['conditions'].append(condition) + + +def _create_csi_s3_pvc_and_set_status(patch, core_v1_api: CoreV1Api, co_api: CustomObjectsApi, + name, spec, pv_name, namespace): + pvc_id, pvc_name = _create_csi_s3_pvc(core_v1_api, co_api, namespace, name, spec, pv_name) + patch['status'].setdefault('s3Storage', {}) + patch['status']['s3Storage']['csiS3PersistentVolumeClaimUID'] = pvc_id + patch['status']['s3Storage']['csiS3PersistentVolumeClaimName'] = pvc_name + condition = _get_waiting_pvc_ready_condition() + patch['status']['conditions'].append(condition) + + +def _create_s3_pv_and_pvc(patch, core_v1_api: CoreV1Api, co_api: CustomObjectsApi, + name, spec, status, namespace, logger, retry): + pv_full_name = _get_pv_full_name(platform_app_name=namespace, box_name=name) + pvc_name = _get_pvc_name(box_name=name) + + if status: + if 'conditions' in status: + patch['status']['conditions'] = status['conditions'] + if 's3Storage' in status: + patch['status']['s3Storage'] = status['s3Storage'] + + patch_status = patch['status'] + + if not _check_if_pv_is_set(patch_status): + pv_does_not_exist = _check_if_pv_does_not_exist(core_v1_api, pv_full_name, logger) + if not pv_does_not_exist: + # todo: более корректно сохранять в аннотации PV uid ящика, и определять принадлежность по нему; + # потому что обновление статуса box после создания PV может не произойти из-за отказа kopf; + # поэтому важно связывать ящик и PV одной операцией, такая операция - указывать + # в аннотации PV uid ящика; + # todo: другой вариант - 1) записывать в статус родителя "начало создания", + # 2) выполнять создание дочернего ресурса, 3) подтверждать создание (при отказе на любом из шагов, + # состояние можно восстановить) + reason = message = f'PV with given label {pv_full_name} already exists' + _set_box_failure(patch, reason, message) + raise PVorPVCAlreadyExists + _create_csi_s3_pv_and_set_status(patch, core_v1_api, co_api, name, spec, namespace) + + if not _check_if_pvc_is_set(patch_status): + pvc_does_not_exist = _check_if_pvc_does_not_exist(core_v1_api, pvc_name, namespace, logger) + if not pvc_does_not_exist: + reason = message = f'PVC {pvc_name} already exists' + _set_box_failure(patch, reason, message) + raise PVorPVCAlreadyExists + pv_name = patch_status['s3Storage']['csiS3PersistentVolumeName'] + + _create_csi_s3_pvc_and_set_status(patch, core_v1_api, co_api, name, spec, pv_name, namespace) + + _check_allocation_and_change_status(core_v1_api, namespace, patch, retry) + + +def _check_pv_is_ready(conditions): + return any(c['conditionStatus'] == 'True' for c in conditions if c['type'] in {PV_IS_READY, WAITING_PV_READINESS}) + + +def _check_pvc_is_ready(conditions): + return any(c['conditionStatus'] == 'True' for c in conditions if c['type'] in {PVC_IS_READY, WAITING_PVC_READINESS}) + + +def _check_waiting_pv_is_deleted(conditions): + return any(c['conditionStatus'] == 'True' for c in conditions if c['type'] == WAITING_PV_IS_DELETED) + + +def _check_waiting_pvc_is_deleted(conditions): + return any(c['conditionStatus'] == 'True' for c in conditions if c['type'] == WAITING_PVC_IS_DELETED) + + +def _check_pv_is_deleted(conditions): + return any(c['conditionStatus'] == 'True' for c in conditions if c['type'] == PV_IS_DELETED) + + +def _check_pvc_is_deleted(conditions): + return any(c['conditionStatus'] == 'True' for c in conditions if c['type'] == PVC_IS_DELETED) + + +def _check_box_is_deleting(conditions): + return any(c['conditionStatus'] == 'True' for c in conditions if c['type'] == DELETING) + + +def _check_can_delete_pv(core_v1_api: CoreV1Api, status, logger): + pv_name = status['s3Storage']['csiS3PersistentVolumeName'] + try: + core_v1_api.read_persistent_volume(pv_name) + except ApiException as exc: + if exc.status == 404: + logger.warn(f'PV {pv_name} doesnt exist, nothing to delete') + return True + else: + raise exc + # здесь может быть любая проверка + # if pv.status.phase == 'Failed': + # return False + return True + + +def _check_can_delete_pvc(core_v1_api: CoreV1Api, namespace, status, logger): + pvc_name = status['s3Storage']['csiS3PersistentVolumeClaimName'] + try: + core_v1_api.read_namespaced_persistent_volume_claim(pvc_name, namespace) + except ApiException as exc: + if exc.status == 404: + logger.warn(f'PVC {pvc_name} doesnt exist, nothing to delete') + return True + else: + raise exc + # здесь может быть любая проверка + # if pvc.status.phase == 'Failed': + # return False + return True + + +def _delete_pv(core_v1_api: CoreV1Api, status, logger): + pv_name = status['s3Storage']['csiS3PersistentVolumeName'] + try: + core_v1_api.delete_persistent_volume(pv_name) + except ApiException as exc: + if exc.status == 404: + logger.warn(f'PV {pv_name} doesnt exist, nothing to delete') + return True + else: + raise exc + return True + + +def _delete_pvc(core_v1_api: CoreV1Api, namespace, status, logger): + pvc_name = status['s3Storage']['csiS3PersistentVolumeClaimName'] + try: + core_v1_api.delete_namespaced_persistent_volume_claim(pvc_name, namespace) + except ApiException as exc: + if exc.status == 404: + logger.warn(f'PVC {pvc_name} doesnt exist, nothing to delete') + return True + else: + raise exc + return True + + +def _check_pv_resource_is_deleted(core_v1_api: CoreV1Api, status): + pv_name = status['s3Storage']['csiS3PersistentVolumeName'] + try: + core_v1_api.read_persistent_volume(pv_name) + except ApiException as exc: + if exc.status == 404: + return True + else: + raise exc + return False + + +def _check_pvc_resource_is_deleted(core_v1_api: CoreV1Api, namespace, status): + pvc_name = status['s3Storage']['csiS3PersistentVolumeClaimName'] + try: + core_v1_api.read_namespaced_persistent_volume_claim(namespace, pvc_name) + except ApiException as exc: + if exc.status == 404: + return True + else: + raise exc + return False + + +def _try_delete_pv_and_update_status(patch, core_v1_api: CoreV1Api, status, logger): + conditions = patch['status']['conditions'] + if _check_pv_is_ready(conditions): + if _check_can_delete_pv(core_v1_api, status, logger): + _delete_pv(core_v1_api, status, logger) + _make_condition_transition(patch, [WAITING_PV_READINESS, PV_IS_READY], + _get_waiting_pv_is_deleted_condition()) + else: + return False + if _check_waiting_pv_is_deleted(conditions): + if _check_pv_resource_is_deleted(core_v1_api, status): + _make_condition_transition(patch, WAITING_PV_IS_DELETED, _get_pv_is_deleted_condition()) + else: + return False + if _check_pv_is_deleted(conditions): + return True + return False + + +def _try_delete_pvc_and_update_status(patch, core_v1_api: CoreV1Api, namespace, status, logger): + conditions = patch['status']['conditions'] + if _check_pvc_is_ready(conditions): + if _check_can_delete_pvc(core_v1_api, namespace, status, logger): + _delete_pvc(core_v1_api, namespace, status, logger) + _make_condition_transition(patch, [WAITING_PVC_READINESS, PVC_IS_READY], + _get_waiting_pvc_is_deleted_condition()) + else: + return False + if _check_waiting_pvc_is_deleted(conditions): + if _check_pvc_resource_is_deleted(core_v1_api, namespace, status): + _make_condition_transition(patch, WAITING_PVC_IS_DELETED, _get_pvc_is_deleted_condition()) + else: + return False + if _check_pvc_is_deleted(conditions): + return True + return False + + +def _check_can_finish_deletion(patch): + conditions = patch['status']['conditions'] + if _check_pv_is_deleted(conditions) and _check_pvc_is_deleted(conditions): + return + raise WaitingDeletionError(delay=10) + + +def _update_box_deletion_status(patch): + status = patch['status'] + if _check_box_is_ready(status) or _check_box_failure(status): + condition = _get_box_deleting_condition() + _make_condition_transition(patch, [READY, FAILURE], condition) + + +def _delete_s3_pv_and_pvc(patch, core_v1_api: CoreV1Api, status, namespace, logger): + if not _check_if_pv_is_set(status): + reason = message = 'PV is not set, but expected' + _set_box_failure(patch, reason, message) + raise InternalErrorPermanentError(message) + + if not _check_if_pvc_is_set(status): + reason = message = 'PVC is not set, but expected' + _set_box_failure(patch, reason, message) + raise InternalErrorPermanentError(message) + + if 'status' not in patch: + patch['status'] = {} + + patch['status'].setdefault('conditions', []) + if status: + if 'conditions' in status: + patch['status']['conditions'] = status['conditions'] + + _update_box_deletion_status(patch) + + pv_deleted = _try_delete_pv_and_update_status(patch, core_v1_api, status, logger) + pvc_deleted = _try_delete_pvc_and_update_status(patch, core_v1_api, namespace, status, logger) + if not pv_deleted or not pvc_deleted: + raise WaitingDeletionError(delay=10) + + _check_can_finish_deletion(patch) + + +@kopf.on.create('unified-platform.cs.hse.ru', 'databoxes', retries=7, + field='spec.s3Storage', value=kopf.PRESENT, when=not_dev_namespace) +@kopf.on.create('unified-platform.cs.hse.ru', 'databoxes', retries=7, + field='spec.s3DefaultStorage', value=kopf.PRESENT, when=not_dev_namespace) +@kopf.on.create('unified-platform.cs.hse.ru', 'databoxes', retries=7, + field='spec.datasetReference', value=kopf.PRESENT, when=not_dev_namespace) +def create_s3_box(name, namespace, spec, status, patch, logger, retry, **_): + + if 'status' not in patch: + patch['status'] = {} + + # patch['status'] заполняется используемыми и изменяемыми атрибутами из status, чтобы можно было за один такт + # обработчика выполнить все необходимые операции; в противном случае нужно либо 1) учитывать, что часть атрибутов + # находится в patch (что изменено в текущей итерации), а часть - в status; либо 2) выполнять лишние итерации, + # чтобы все атрибуты были перенесены в status. + # кроме этого, заполнить patch['status']['conditions'] атрибутами из status['conditions'] нужно в любом случае, + # потому что kopf не умеет мерджить списки (что происходит при примнении патча), а согласно API Conventions, + # status.conditions должен быть списком; + patch['status'].setdefault('conditions', []) + patch['status'].setdefault('s3Storage', {}) + # для dataset правильнее хранить атрибуты в 'datasetReference', а не 's3Storage' + + # код выше вынесен из метода _create_s3_pv_and_pvc, потому что должен быть выполнен даже в случае отказа в + # _check_box_is_s3_storage и _check_if_bucket_exists + + _check_box_has_valid_kind(spec) + core_v1_api = CoreV1Api(api_client) + co_api = CustomObjectsApi(api_client) + _check_if_related_objects_exist(core_v1_api, co_api, spec, namespace) + _create_s3_pv_and_pvc(patch, core_v1_api, co_api, name, spec, status, namespace, logger, retry) + + +@kopf.on.delete('unified-platform.cs.hse.ru', 'databoxes', retries=7, field='spec.s3Storage', + value=kopf.PRESENT, when=not_dev_namespace) +@kopf.on.delete('unified-platform.cs.hse.ru', 'databoxes', retries=7, field='spec.s3DefaultStorage', + value=kopf.PRESENT, when=not_dev_namespace) +@kopf.on.delete('unified-platform.cs.hse.ru', 'databoxes', retries=7, field='spec.datasetReference', + value=kopf.PRESENT, when=not_dev_namespace) +def delete_s3_box(namespace, status, patch, logger, **_): + core_v1_api = CoreV1Api(api_client) + _delete_s3_pv_and_pvc(patch, core_v1_api, status, namespace, logger) + diff --git a/controller/src/box/jinja.py b/controller/src/box/jinja.py new file mode 100644 index 0000000..f86458c --- /dev/null +++ b/controller/src/box/jinja.py @@ -0,0 +1,18 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: DataBox +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +""" +Box object jinja module. +""" + +from jinja2 import Environment, FileSystemLoader + +jinja_env = Environment( + loader=FileSystemLoader('templates/box'), + lstrip_blocks=True, + trim_blocks=True +) + diff --git a/controller/src/cmplink/__init__.py b/controller/src/cmplink/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/controller/src/cmplink/basic_auth_link.py b/controller/src/cmplink/basic_auth_link.py new file mode 100644 index 0000000..23f355e --- /dev/null +++ b/controller/src/cmplink/basic_auth_link.py @@ -0,0 +1,174 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: ComponentLink +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +import base64 +import logging +from typing import Mapping + +from kubernetes.client import ApiClient, CustomObjectsApi, ApiException + +from auth import create_htpasswd_password +from basic_resources.secrets import prepare_secret_manifest, read_secret_if_exists, \ + create_or_update_secret, read_basic_auth_credentials_from_secret +from cmplink.link import get_links_given_predicate, get_target_resource_if_exists, get_secret_name_from_link, \ + does_target_specified_in_link, TARGET_KIND_TO_CODE + +logger = logging.getLogger(__name__) + + +def _append_credentials_from_secret(creds_dict, secret, secret_name, secret_namespace, logger): + users_passwords = read_basic_auth_credentials_from_secret(secret, secret_name, secret_namespace, logger) + for user, password in users_passwords: + if user in creds_dict: + if creds_dict[user] != password: + logger.warning(f'user password from secret {secret_namespace}.{secret_name} ' + f'may differ from password of same user in another used secret') + creds_dict[user] = password + + +def _get_basic_auth_links_given_target(api_client: ApiClient, target, target_namespace, + target_kind, user_namespace): + def predicate(link): + link_spec = link['spec'] + if 'basicAuth' not in link_spec: + return False + + target_specified = does_target_specified_in_link(target, target_namespace, target_kind, link_spec) + return target_specified + + filtered_list = get_links_given_predicate(api_client, user_namespace, predicate) + return filtered_list + + +def _build_credentials(api_client: ApiClient, target, target_namespace, target_kind, user_namespace, logger, + exclude_links_names): + links_list = _get_basic_auth_links_given_target(api_client, target, target_namespace, target_kind, user_namespace) + + creds_dict = {} + + for link in links_list: + link_metadata = link['metadata'] + link_name = link_metadata['name'] + if link_name in exclude_links_names: + continue + + secret_name = get_secret_name_from_link(link) + if not secret_name: + continue + + secret = read_secret_if_exists(api_client, secret_name, user_namespace) + if not secret: + logger.info(f'Target link secret {user_namespace}.{secret_name} ' + f'does not exist') + continue + + _append_credentials_from_secret(creds_dict, secret, secret_name, user_namespace, logger) + + return [{'user': k, 'password': v} for k, v in creds_dict.items()] + + +def get_basic_auth_joint_secret_name(target, target_kind=None): + secret_name = target + '-ba-joint-cred' if not target_kind \ + else f'{target}-{TARGET_KIND_TO_CODE[target_kind]}-ba-joint-cred' + return secret_name + + +def _creds_records_to_htpasswd_strings(records: list[Mapping]) -> list[str]: + htpasswd_lines = [] + for record in records: + user = record['user'] + password = record['password'] + encrypted_password = create_htpasswd_password(password) + htpasswd_record = f'{user}:{encrypted_password}' + htpasswd_lines.append(htpasswd_record) + return htpasswd_lines + + +def _get_basic_auth_secret_from_direct_spec(api_client: ApiClient, target, target_namespace, target_kind): + api_obj = get_target_resource_if_exists(api_client, target, target_namespace, target_kind, logger) + if not api_obj: + return None + + api_spec = api_obj['spec'] + restful_api = api_spec['restfulApi'] + auth = restful_api['auth'] + basic = auth.get('basic') + secret_name = basic.get('credentials') if basic else None + return secret_name + + +def _append_creds_from_direct_spec(api_client: ApiClient, htpasswd_lines, target, target_namespace, target_kind): + secret_name = _get_basic_auth_secret_from_direct_spec(api_client, target, target_namespace, target_kind) + if not secret_name: + return + + secret_obj = read_secret_if_exists(api_client, secret_name, target_namespace) + if not secret_obj: + logger.info(f'Application {target_namespace} {target} (target_kind = {target_kind}) secret' + f' {secret_name} specified directly does not exist') + return + + existing_users = set(line[:line.find(':')] for line in htpasswd_lines if ':' in line) + + secret_data = secret_obj.to_dict()['data'] + + secret_creds = secret_data.get('auth') + if not secret_creds: + logger.warning(f'auth field in secret {target_namespace}.{secret_name} ' + f'has empty value or does not exist') + return + + secret_creds_decoded = base64.b64decode(secret_creds).decode('utf-8') + for cred in secret_creds_decoded.split('\n'): + if not cred.strip(): + logger.warning(f'credentials record in secret {target_namespace}.{secret_name} ' + f'is empty') + continue + + if ':' not in cred: + logger.warning(f'wrong credentials format in secret {target_namespace}.{secret_name}, ' + f'some credentials may be omitted') + continue + + sep_index = cred.find(':') + user, password = cred[:sep_index], cred[sep_index + 1:] + if user in existing_users: + logger.warning(f'user {user} from secret {target_namespace}.{secret_name} ' + f'is already presented in links credentials') + continue + + htpasswd_lines.append(cred) + + +def create_or_update_basic_auth_joint_secret(api_client: ApiClient, target, target_namespace, user_namespace, logger, + exclude_links_names=None, exclude_direct_spec=False, target_kind=None): + # exclude_links_names нужно, потому что обработчик удаления ссылки отрабатывает перед фактическим удалением - + # в списке прочитанных ссылок будет "удаляемая" ссылка + if exclude_links_names is None: + exclude_links_names = [] + creds = _build_credentials(api_client, target, target_namespace, target_kind, + user_namespace, logger, exclude_links_names) + htpasswd_lines = _creds_records_to_htpasswd_strings(creds) + if not exclude_direct_spec: + # от добавления явно указанных секретов можно будет отказаться + _append_creds_from_direct_spec(api_client, htpasswd_lines, target, target_namespace, target_kind) + htpasswd_string = '"' + '\\n'.join(htpasswd_lines) + '\\n"' + basic_auth_data = [] + if htpasswd_string: + basic_auth_data.append({'key': 'auth', 'value': htpasswd_string}) + secret_name = get_basic_auth_joint_secret_name(target, target_kind) + + manifest = prepare_secret_manifest(name=secret_name, + namespace=target_namespace, + type_='Opaque', + data=basic_auth_data, + data_attr='stringData') + + create_or_update_secret(api_client=api_client, + name=secret_name, + namespace=target_namespace, + manifest=manifest, + logger=logger) diff --git a/controller/src/cmplink/handlers.py b/controller/src/cmplink/handlers.py new file mode 100644 index 0000000..1a52ca2 --- /dev/null +++ b/controller/src/cmplink/handlers.py @@ -0,0 +1,713 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: ComponentLink +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2025 г. +# ============================================================ +import kopf +from kubernetes.client import CustomObjectsApi, ApiException + +from basic_resources.secrets import set_secret_annotations_and_labels, delete_secret_if_exists, copy_secret_silently, \ + copy_secret_data +from bound import not_dev_namespace, in_pu_namespace +from cmplink.basic_auth_link import create_or_update_basic_auth_joint_secret +from cmplink.keycloak_group_link import get_accounts_from_secret, \ + create_or_update_groups_joint_secret_and_restart_proxy +from cmplink.keycloak_groups import set_group_groups_chain, delete_group, \ + set_group_accounts +from cmplink.link import get_secret_name_from_link, get_links_given_predicate, get_links_if_exist, \ + unset_secret_anno_and_label, get_secret_name_if_set, TARGET_KIND_API_COMPONENT +from config import OIDC_MODIFY +from kopf_k8s_client import api_client + +_KEYCLOAK_GROUP_ANNO_PREFIX = 'keycloakgroup.componentlink.unified-platform.cs.hse.ru' +_KEYCLOAK_GROUP_LABEL = 'keycloakgroup.componentlink.unified-platform.cs.hse.ru' +_BASIC_AUTH_ANNO_PREFIX = 'basicauth.componentlink.unified-platform.cs.hse.ru' +_BASIC_AUTH_LABEL = 'basicauth.componentlink.unified-platform.cs.hse.ru' +_CONFIG_ANNO_PREFIX = 'config.componentlink.unified-platform.cs.hse.ru' +_CONFIG_LABEL = 'config.componentlink.unified-platform.cs.hse.ru' + + +def is_keycloak_group_link(spec, **_): + return 'keycloakGroup' in spec + + +def is_basic_auth_link(spec, **_): + return 'basicAuth' in spec + + +def is_config_link(spec, **_): + return 'config' in spec + + +def _set_group_ids_in_status_by_patch(patch, group_ids): + if 'status' not in patch: + patch['status'] = {} + + patch['status'].setdefault('keycloakGroup', {}) + status_kg = patch['status']['keycloakGroup'] + status_kg['groupIds'] = group_ids + + +def _set_group_ids_in_status_by_client(kg_link_name, namespace, group_ids, logger): + # groupIds используются для явной ассоциации KeycloakGroup ComponentLink (KGL) и группы Keycloak, + # это может быть полезно при перемещении группы, если будет добавлена поддержка иерархии KGL; + # до этого момента использование groupIds, хранимых в status, может быть заменено на поиск группы по полному пути; + co_api = CustomObjectsApi(api_client) + patch = {'status': {'keycloakGroup': {'groupIds': group_ids}}} + try: + co_api.patch_namespaced_custom_object_status('unified-platform.cs.hse.ru', 'v1', + namespace, 'componentlinks', kg_link_name, patch) + except ApiException as exc: + if exc.status == 404: + logger.warning(f'KeycloakGroup ComponentLink {namespace}.{kg_link_name} ' + f'does not exist. Cannot set groupIds') + return + raise exc + + +def _unset_keycloak_group_secret_anno_and_label(link_name, secret_name, namespace, logger): + unset_secret_anno_and_label(api_client, + _KEYCLOAK_GROUP_ANNO_PREFIX, + _KEYCLOAK_GROUP_LABEL, + link_name, + secret_name, + namespace, + logger) + + +def _unset_basic_auth_secret_anno_and_label(link_name, secret_name, namespace, logger): + unset_secret_anno_and_label(api_client, + _BASIC_AUTH_ANNO_PREFIX, + _BASIC_AUTH_LABEL, + link_name, + secret_name, + namespace, + logger) + + +def _unset_config_secret_anno_and_label(link_name, secret_name, namespace, logger): + unset_secret_anno_and_label(api_client, + _CONFIG_ANNO_PREFIX, + _CONFIG_LABEL, + link_name, + secret_name, + namespace, + logger) + + +def _set_keycloak_group_secret_anno_and_label(link_name, secret_name, namespace, logger): + anno = {f'{_KEYCLOAK_GROUP_ANNO_PREFIX}/{link_name}': 'true'} + labels = {_KEYCLOAK_GROUP_LABEL: 'true'} + set_secret_annotations_and_labels(api_client, secret_name, namespace, anno, labels, logger) + + +def _set_basic_auth_secret_anno_and_label(link_name, secret_name, namespace, logger): + anno = {f'{_BASIC_AUTH_ANNO_PREFIX}/{link_name}': 'true'} + labels = {_BASIC_AUTH_LABEL: 'true'} + set_secret_annotations_and_labels(api_client, secret_name, namespace, anno, labels, logger) + + +def _set_many_basic_auth_secrets_anno_and_label(ba_links, secret_name, namespace, logger): + for ba_link in ba_links: + link_name = ba_link['metadata']['name'] + anno = {f'{_BASIC_AUTH_ANNO_PREFIX}/{link_name}': 'true'} + labels = {_BASIC_AUTH_LABEL: 'true'} + set_secret_annotations_and_labels(api_client, secret_name, namespace, anno, labels, logger) + + +def _set_config_secret_anno_and_label(link_name, secret_name, namespace, logger): + anno = {f'{_CONFIG_ANNO_PREFIX}/{link_name}': 'true'} + labels = {_CONFIG_LABEL: 'true'} + set_secret_annotations_and_labels(api_client, secret_name, namespace, anno, labels, logger) + + +def _get_keycloak_user_registry_name(spec): + keycloak_group = spec['keycloakGroup'] + user_registry_ref = keycloak_group['userRegistryRef'] + kg_user_registry = user_registry_ref['name'] + return kg_user_registry + + +def _set_group_and_accounts(name, user_namespace, spec, logger): + keycloak_group_name = name + user_registry_name = _get_keycloak_user_registry_name(spec) + secret_name = get_secret_name_if_set(spec) + group_ids = set_group_groups_chain(user_namespace, keycloak_group_name, logger, OIDC_MODIFY) + _set_group_ids_in_status_by_client(name, user_namespace, group_ids, logger) + if secret_name: + # todo: здесь читается секрет, но, если _set_group_and_accounts вызывается из обработчика секрета, + # то повторно читать секрет может быть лишним, можно сделать два метода _set_group_and_accounts, + # использовать set_group_id_in_status_by_patch вместо set_group_id_in_status_by_client, + # если _set_group_and_accounts вызывается из обработчика KeycloakGroup ComponentLink + # (чтобы не вызывать лишний раз patch) + usernames, emails, robots = get_accounts_from_secret(api_client, secret_name, user_namespace, + user_registry_name, logger) + set_group_accounts(group_ids, usernames, emails, robots, OIDC_MODIFY, logger) + else: + set_group_accounts(group_ids, None, None, None, OIDC_MODIFY, logger) + + +def _unset_group_accounts(group_ids, logger): + set_group_accounts(group_ids, None, None, None, OIDC_MODIFY, logger) + + +def _set_keycloak_group_link_targets_joint_secrets(spec, namespace, exclude_links_names, logger): + app = spec['platformAppName'] + targets = spec['targets'] + for target_spec in targets: + target = target_spec['name'] + target_namespace = target_spec['platformAppName'] if 'platformAppName' in target_spec else app + target_kind = target_spec.get('kind') + create_or_update_groups_joint_secret_and_restart_proxy(api_client=api_client, + target=target, + target_namespace=target_namespace, + target_kind=target_kind, + user_namespace=namespace, + logger=logger, + exclude_links_names=exclude_links_names) + + +def _set_basic_auth_link_targets_joint_secrets(spec, namespace, exclude_links_names, logger): + app = spec['platformAppName'] + targets = spec['targets'] + for target_spec in targets: + target = target_spec['name'] + target_namespace = target_spec['platformAppName'] if 'platformAppName' in target_spec else app + target_kind = target_spec.get('kind') + create_or_update_basic_auth_joint_secret(api_client=api_client, + target=target, + target_namespace=target_namespace, + target_kind=target_kind, + user_namespace=namespace, + logger=logger, + exclude_links_names=exclude_links_names) + + +def _set_many_basic_auth_links_targets_joint_secrets(ba_links, namespace, exclude_links, logger): + + all_targets = set() + + def get_target_kind(_target_spec): + _target_kind = _target_spec.get('kind') + if _target_kind == TARGET_KIND_API_COMPONENT: + _target_kind = None + return _target_kind + + for ba_link in ba_links: + link_spec = ba_link['spec'] + link_app = link_spec['platformAppName'] + link_targets = link_spec['targets'] + targets = {(t['name'], + t['platformAppName'] if 'platformAppName' in t else link_app, + get_target_kind(t)) for t in link_targets} + all_targets = all_targets | targets + + exclude_links_names = [ba_link['metadata']['name'] for ba_link in exclude_links] if exclude_links else None + + for target, target_namespace, target_kind in all_targets: + create_or_update_basic_auth_joint_secret(api_client=api_client, + target=target, + target_namespace=target_namespace, + target_kind=target_kind, + user_namespace=namespace, + logger=logger, + exclude_links_names=exclude_links_names) + + +def _set_config_link_secret(spec, name, namespace, logger): + dest_namespace = spec['platformAppName'] + + secret_name = get_secret_name_if_set(spec) + if secret_name: + copy_secret_silently(api_client=api_client, + source_secret_name=secret_name, + source_namespace=namespace, + dest_secret_name=name, + dest_namespace=dest_namespace, + logger=logger) + + +def _set_config_link_secret_from_secret(spec, name, source_secret_body, logger): + dest_namespace = spec['platformAppName'] + + copy_secret_data(api_client=api_client, + source_secret_body=source_secret_body, + dest_secret_name=name, + dest_namespace=dest_namespace, + logger=logger) + + +def _delete_config_link_secret(spec, name, logger): + secret_namespace = spec['platformAppName'] + delete_secret_if_exists(api_client, name, secret_namespace, logger) + + +@kopf.on.create('unified-platform.cs.hse.ru', 'componentlinks', + when=kopf.all_([not_dev_namespace, + in_pu_namespace, + is_keycloak_group_link])) +def create_keycloak_group_link(spec, name, namespace, body, patch, logger, **_): + logger.debug(f"A create_keycloak_group_link handler is called with body: {body}") + + @kopf.subhandler(id=f'set-group-and-accounts-{namespace}.{name}') + def _set_group_and_accounts_handler(**_): + _set_group_and_accounts(name, namespace, spec, logger) + + @kopf.subhandler(id=f'update-keycloak-group-secret-{namespace}.{name}') + def _set_keycloak_group_secret_anno_and_label_handler(**_): + secret_name = get_secret_name_if_set(spec) + if secret_name: + _set_keycloak_group_secret_anno_and_label(name, secret_name, namespace, logger) + + @kopf.subhandler(id=f'set-targets-joint-secrets-{namespace}.{name}') + def _create_or_update_joint_secrets_handler(**_): + _set_keycloak_group_link_targets_joint_secrets(spec, namespace, None, logger) + + +@kopf.on.delete('unified-platform.cs.hse.ru', 'componentlinks', + when=kopf.all_([not_dev_namespace, + in_pu_namespace, + is_keycloak_group_link])) +def delete_keycloak_group_link(spec, name, namespace, status, body, logger, **_): + logger.debug(f"A delete_keycloak_group_link handler is called with body: {body}") + + group_ids = status.get('keycloakGroup', {}).get('groupIds') + if group_ids: + delete_group(group_ids, logger, OIDC_MODIFY) + + secret_name = get_secret_name_if_set(spec) + if secret_name: + _unset_keycloak_group_secret_anno_and_label(name, secret_name, namespace, logger) + + _set_keycloak_group_link_targets_joint_secrets(spec, namespace, {name}, logger) + + +def _secret_is_changed(diff, **_): + secret_ref_changed = any(d[1] == ('spec', 'secretRef') for d in diff) + secret_name_changed = any(d[1] == ('spec', 'secretRef', 'name') for d in diff) + return secret_ref_changed or secret_name_changed + + +def _secret_is_not_changed(diff, **_): + return not _secret_is_changed(diff) + + +def _app_name_or_targets_are_changed(diff, **_): + targets_changed = any(d[1] == ('spec', 'targets') for d in diff) + app_changed = any(d[1] == ('spec', 'platformAppName') for d in diff) + return targets_changed or app_changed + + +def _app_name_is_changed(diff, **_): + app_changed = any(d[1] == ('spec', 'platformAppName') for d in diff) + return app_changed + + +@kopf.on.update('unified-platform.cs.hse.ru', 'componentlinks', + when=kopf.all_([not_dev_namespace, + in_pu_namespace, + is_keycloak_group_link, + _secret_is_changed])) +def update_keycloak_group_link(old, new, status, name, namespace, body, patch, logger, **_): + logger.debug(f"A update_keycloak_group_link handler is called with body: {body}") + + old_spec = old['spec'] + new_spec = new['spec'] + + secret_name = get_secret_name_if_set(new_spec) + old_secret_name = get_secret_name_if_set(old_spec) + + # установлен фильтр _secret_is_changed, значит Secret изменился - нужно обновить состав группы и установить метку; + # set_group, update_secrets - отдельные subhandlers, потому что могут выполняться независимо друг от друга; + + @kopf.subhandler(id=f'set-group-and-accounts-{namespace}.{name}') + def _set_group_and_accounts_handler(**_): + _set_group_and_accounts(name, namespace, new_spec, logger) + + @kopf.subhandler(id=f'update-keycloak-group-secrets-{namespace}.{name}') + def _update_keycloak_group_secrets_anno_and_label_handler(**_): + if old_secret_name is not None: + _unset_keycloak_group_secret_anno_and_label(name, old_secret_name, namespace, logger) + if secret_name: + _set_keycloak_group_secret_anno_and_label(name, secret_name, namespace, logger) + + +@kopf.on.update('unified-platform.cs.hse.ru', 'componentlinks', + when=kopf.all_([not_dev_namespace, + in_pu_namespace, + is_keycloak_group_link, + _app_name_or_targets_are_changed])) +def update_keycloak_group_link_targets(old, new, status, name, namespace, body, patch, logger, **_): + old_spec = old['spec'] + new_spec = new['spec'] + + _set_keycloak_group_link_targets_joint_secrets(old_spec, namespace, None, logger) + _set_keycloak_group_link_targets_joint_secrets(new_spec, namespace, None, logger) + + +@kopf.on.create('unified-platform.cs.hse.ru', 'componentlinks', + when=kopf.all_([not_dev_namespace, + in_pu_namespace, + is_basic_auth_link])) +def create_basic_auth_link(spec, name, namespace, body, patch, logger, **_): + logger.debug(f"A create_basic_auth_link handler is called with body: {body}") + + @kopf.subhandler(id=f'update-basic-auth-secret-{namespace}.{name}') + def _set_basic_auth_secret_anno_and_label_handler(**_): + secret_name = get_secret_name_if_set(spec) + if secret_name: + _set_basic_auth_secret_anno_and_label(name, secret_name, namespace, logger) + + @kopf.subhandler(id=f'set-targets-joint-secrets-{namespace}.{name}') + def _create_or_update_joint_secrets_handler(**_): + _set_basic_auth_link_targets_joint_secrets(spec, namespace, None, logger) + + +@kopf.on.delete('unified-platform.cs.hse.ru', 'componentlinks', + when=kopf.all_([not_dev_namespace, + in_pu_namespace, + is_basic_auth_link])) +def delete_basic_auth_link(spec, name, namespace, status, body, logger, **_): + logger.debug(f"A delete_basic_auth_link handler is called with body: {body}") + + secret_name = get_secret_name_if_set(spec) + if secret_name: + _unset_basic_auth_secret_anno_and_label(name, secret_name, namespace, logger) + + _set_basic_auth_link_targets_joint_secrets(spec, namespace, {name}, logger) + + +@kopf.on.update('unified-platform.cs.hse.ru', 'componentlinks', + when=kopf.all_([not_dev_namespace, + in_pu_namespace, + is_basic_auth_link, + kopf.any_([_secret_is_changed, _app_name_or_targets_are_changed]) + ])) +def update_basic_auth_link(old, new, status, name, namespace, body, patch, logger, **_): + logger.debug(f"A update_basic_auth_link handler is called with body: {body}") + + old_spec = old['spec'] + new_spec = new['spec'] + + secret_name = get_secret_name_if_set(new_spec) + old_secret_name = get_secret_name_if_set(old_spec) + + # отдельные subhandlers, потому что могут выполняться независимо друг от друга + @kopf.subhandler(id=f'update-basic-auth-secrets-{namespace}.{name}') + def _update_basic_auth_secrets_anno_and_label_handler(**_): + if secret_name == old_secret_name: + return + if old_secret_name is not None: + _unset_basic_auth_secret_anno_and_label(name, old_secret_name, namespace, logger) + if secret_name: + _set_basic_auth_secret_anno_and_label(name, secret_name, namespace, logger) + + @kopf.subhandler(id=f'set-targets-joint-secrets-{namespace}.{name}') + def _create_or_update_joint_secrets_handler(**_): + _set_basic_auth_link_targets_joint_secrets(old_spec, namespace, None, logger) + _set_basic_auth_link_targets_joint_secrets(new_spec, namespace, None, logger) + + +@kopf.on.update('unified-platform.cs.hse.ru', 'componentlinks', + when=kopf.all_([not_dev_namespace, + in_pu_namespace, + is_basic_auth_link, + kopf.any_([_secret_is_not_changed, _app_name_or_targets_are_changed]) + ])) +def update_basic_auth_link_targets(old, new, status, name, namespace, body, patch, logger, **_): + logger.debug(f"A update_basic_auth_link_targets handler is called with body: {body}") + + old_spec = old['spec'] + new_spec = new['spec'] + + _set_basic_auth_link_targets_joint_secrets(old_spec, namespace, None, logger) + _set_basic_auth_link_targets_joint_secrets(new_spec, namespace, None, logger) + + +@kopf.on.create('unified-platform.cs.hse.ru', 'componentlinks', + when=kopf.all_([not_dev_namespace, + in_pu_namespace, + is_config_link]), + field='spec.secretRef', + value=kopf.PRESENT) +# !!! если в обработчике on.create при использовании параметра field не указать value=kopf.PRESENT, +# то в аргумент spec будет передано только значение атрибута, указанного в field +def create_config_link_with_secret(spec, name, namespace, body, logger, **_): + logger.debug(f"A create_config_link_with_secret handler is called with body: {body}") + + @kopf.subhandler(id=f'update-config-secret-{namespace}.{name}') + def _set_config_secret_anno_and_label_handler(**_): + secret_name = get_secret_name_if_set(spec) + _set_config_secret_anno_and_label(name, secret_name, namespace, logger) + + @kopf.subhandler(id=f'set-config-secret-{namespace}.{name}') + def _copy_secret_handler(**_): + _set_config_link_secret(spec, name, namespace, logger) + + +@kopf.on.delete('unified-platform.cs.hse.ru', 'componentlinks', + when=kopf.all_([not_dev_namespace, + in_pu_namespace, + is_config_link]), + field='spec.secretRef', + value=kopf.PRESENT) +# !!! если в обработчике on.update при использовании параметра field не указать value=kopf.PRESENT, +# то в аргумент spec будет передано только значение атрибута, указанного в field +def delete_config_link_with_secret(spec, name, namespace, body, logger, **_): + logger.debug(f"A delete_config_link_with_secret handler is called with body: {body}") + + secret_name = get_secret_name_if_set(spec) + _unset_config_secret_anno_and_label(name, secret_name, namespace, logger) + _delete_config_link_secret(spec, name, logger) + + +@kopf.on.update('unified-platform.cs.hse.ru', 'componentlinks', + when=kopf.all_([not_dev_namespace, + in_pu_namespace, + is_config_link, + kopf.any_([_secret_is_changed, _app_name_is_changed])])) +def update_config_link_with_secret(old, new, name, namespace, body, logger, **_): + logger.debug(f"A update_config_link_with_secret handler is called with body: {body}") + + old_spec = old['spec'] + new_spec = new['spec'] + + secret_name = get_secret_name_if_set(new_spec) + old_secret_name = get_secret_name_if_set(old_spec) + old_app = old_spec['platformAppName'] + new_app = new_spec['platformAppName'] + + @kopf.subhandler(id=f'update-config-secrets-{namespace}.{name}') + def _update_config_secrets_anno_and_label_handler(**_): + if secret_name == old_secret_name: + return + if old_secret_name is not None: + _unset_config_secret_anno_and_label(name, old_secret_name, namespace, logger) + if secret_name: + _set_config_secret_anno_and_label(name, secret_name, namespace, logger) + + @kopf.subhandler(id=f'set-config-secret-{namespace}.{name}') + def _copy_secret_handler(**_): + if old_app != new_app: + _delete_config_link_secret(old_spec, name, logger) + _set_config_link_secret(new_spec, name, namespace, logger) + + +def _get_keycloak_group_links_given_secret(secret_name, secret_namespace): + def predicate(link): + link_spec = link['spec'] + if 'keycloakGroup' not in link_spec: + return False + link_secret = get_secret_name_from_link(link) + return secret_name == link_secret + + filtered_list = get_links_given_predicate(api_client, secret_namespace, predicate) + return filtered_list + + +def _get_config_links_given_secret(secret_name, secret_namespace): + def predicate(link): + link_spec = link['spec'] + if 'config' not in link_spec: + return False + link_secret = get_secret_name_from_link(link) + return secret_name == link_secret + + filtered_list = get_links_given_predicate(api_client, secret_namespace, predicate) + return filtered_list + + +def _get_basic_auth_links_given_secret(secret_name, secret_namespace): + def predicate(link): + link_spec = link['spec'] + if 'basicAuth' not in link_spec: + return False + link_secret = get_secret_name_from_link(link) + return secret_name == link_secret + + filtered_list = get_links_given_predicate(api_client, secret_namespace, predicate) + return filtered_list + + +@kopf.on.create('', 'secrets', + when=kopf.all_([not_dev_namespace, in_pu_namespace])) +def create_link_secret(spec, name, namespace, body, logger, **_): + kg_links = _get_keycloak_group_links_given_secret(name, namespace) + if kg_links: + for config_link in kg_links: + link_spec = config_link['spec'] + link_name = config_link['metadata']['name'] + + @kopf.subhandler(id=f'set-keycloak-group-group-and-accounts-{namespace}.{link_name}') + def _set_keycloak_group_and_accounts_handler(**_): + _set_group_and_accounts(link_name, namespace, link_spec, logger) + + @kopf.subhandler(id=f'update-keycloak-group-secret-{namespace}.{link_name}') + def _set_keycloak_group_secret_anno_and_label_handler(**_): + _set_keycloak_group_secret_anno_and_label(link_name, name, namespace, logger) + + ba_links = _get_basic_auth_links_given_secret(name, namespace) + if ba_links: + @kopf.subhandler(id=f'update-many-basic-auth-secrets-{namespace}.{name}') + def _set_basic_auth_group_secret_anno_and_label_handler(**_): + _set_many_basic_auth_secrets_anno_and_label(ba_links, name, namespace, logger) + + @kopf.subhandler(id=f'set-many-ba-targets-joint-secrets-{namespace}.{name}') + def _create_or_update_basic_auth_joint_secrets_handler(**_): + _set_many_basic_auth_links_targets_joint_secrets(ba_links, namespace, None, logger) + + config_links = _get_config_links_given_secret(name, namespace) + if config_links: + for config_link in config_links: + link_spec = config_link['spec'] + link_name = config_link['metadata']['name'] + + @kopf.subhandler(id=f'update-config-secret-{namespace}.{link_name}') + def _set_config_secret_anno_and_label_handler(**_): + _set_config_secret_anno_and_label(link_name, name, namespace, logger) + + @kopf.subhandler(id=f'set-config-secret-{namespace}.{link_name}') + def _copy_secret_handler(**_): + _set_config_link_secret_from_secret(link_spec, link_name, body, logger) + + +def _get_links_given_secret_metadata(metadata, namespace, anno, link_type, logger): + if 'annotations' not in metadata: + return None + annotations = metadata.get('annotations') + links_names = [a[len(anno) + 1:] + for a in annotations + if a.startswith(anno)] + links = get_links_if_exist(api_client, links_names, namespace, logger) + filtered = [] + for link in links: + link_spec = link['spec'] + link_name = link['metadata']['name'] + if link_type in link_spec: + filtered.append(link) + else: + logger.warning(f'ComponentLink "{namespace}.{link_name}" is not a {link_type}, but expected') + return filtered + + +def _get_keycloak_group_links_given_secret_metadata(metadata, namespace, logger): + return _get_links_given_secret_metadata(metadata, namespace, _KEYCLOAK_GROUP_ANNO_PREFIX, + 'keycloakGroup', logger) + + +def _get_basic_auth_links_given_secret_metadata(metadata, namespace, logger): + return _get_links_given_secret_metadata(metadata, namespace, _BASIC_AUTH_ANNO_PREFIX, + 'basicAuth', logger) + + +def _get_config_links_given_secret_metadata(metadata, namespace, logger): + return _get_links_given_secret_metadata(metadata, namespace, _CONFIG_ANNO_PREFIX, + 'config', logger) + + +@kopf.on.update('', 'secrets', + when=kopf.all_([not_dev_namespace, in_pu_namespace]), + labels={_KEYCLOAK_GROUP_LABEL: 'true'}, + field='data') +def update_keycloak_group_link_secret(spec, name, namespace, body, logger, **_): + metadata = body['metadata'] + kg_links = _get_keycloak_group_links_given_secret_metadata(metadata, namespace, logger) + if not kg_links: + return + + for kg_link in kg_links: + link_spec = kg_link['spec'] + link_name = kg_link['metadata']['name'] + + @kopf.subhandler(id=f'set-keycloak-group-and-accounts-{namespace}.{link_name}') + def _set_keycloak_group_and_accounts_handler(**_): + _set_group_and_accounts(link_name, namespace, link_spec, logger) + + +@kopf.on.update('', 'secrets', + when=kopf.all_([not_dev_namespace, in_pu_namespace]), + labels={_BASIC_AUTH_LABEL: 'true'}, + field='data') +@kopf.on.delete('', 'secrets', + when=kopf.all_([not_dev_namespace, in_pu_namespace]), + labels={_BASIC_AUTH_LABEL: 'true'}, + param={'event': 'delete'}) +def update_or_delete_basic_auth_link_secret(spec, name, namespace, body, param, logger, **_): + metadata = body['metadata'] + ba_links = _get_basic_auth_links_given_secret_metadata(metadata, namespace, logger) + if not ba_links: + return + + exclude_links = ba_links if 'event' in param and param['event'] == 'delete' else None + + @kopf.subhandler(id=f'set-many-ba-targets-joint-secrets-{namespace}.{name}') + def _create_or_update_basic_auth_joint_secrets_handler(**_): + _set_many_basic_auth_links_targets_joint_secrets(ba_links, namespace, exclude_links, logger) + + +@kopf.on.update('', 'secrets', + when=kopf.all_([not_dev_namespace, in_pu_namespace]), + labels={_CONFIG_LABEL: 'true'}, + field='data') +def update_config_link_secret(spec, name, namespace, body, logger, **_): + metadata = body['metadata'] + config_links = _get_config_links_given_secret_metadata(metadata, namespace, logger) + if not config_links: + return + + for config_link in config_links: + link_spec = config_link['spec'] + link_name = config_link['metadata']['name'] + + @kopf.subhandler(id=f'set-config-secret-{namespace}.{link_name}') + def _copy_secret_handler(**_): + _set_config_link_secret_from_secret(link_spec, link_name, body, logger) + + +@kopf.on.delete('', 'secrets', + when=kopf.all_([not_dev_namespace, in_pu_namespace]), + labels={_KEYCLOAK_GROUP_LABEL: 'true'}) +def delete_keycloak_group_link_secret(spec, name, namespace, body, logger, **_): + metadata = body['metadata'] + kg_links = _get_keycloak_group_links_given_secret_metadata(metadata, namespace, logger) + if not kg_links: + return + + for kg_link in kg_links: + link_status = kg_link.get('status', {}) + link_name = kg_link['metadata']['name'] + + @kopf.subhandler(id=f'unset-keycloak-group-accounts-{namespace}.{link_name}') + def _unset_keycloak_group_accounts_handler(**_): + group_ids = link_status.get('keycloakGroup', {}).get('groupIds') + if group_ids: + _unset_group_accounts(group_ids, logger) + + +@kopf.on.delete('', 'secrets', + when=kopf.all_([not_dev_namespace, in_pu_namespace]), + labels={_CONFIG_LABEL: 'true'}) +def delete_config_link_secret(spec, name, namespace, body, logger, **_): + metadata = body['metadata'] + config_links = _get_config_links_given_secret_metadata(metadata, namespace, logger) + if not config_links: + return + + for config_link in config_links: + link_spec = config_link['spec'] + link_name = config_link['metadata']['name'] + + @kopf.subhandler(id=f'delete-config-secret-{namespace}.{link_name}') + def _delete_config_secret_handler(**_): + _delete_config_link_secret(link_spec, link_name, logger) + + +# todo: реализация обработчиков config link для secret позволяет +# реализовать по аналогии обработчики config link для config map +# (буквально аналогичные обработчики, никак не пересекаются с Secret, +# в обработчике update Secret возможная поддержка ConfigMap уже заложена) + + + + diff --git a/controller/src/cmplink/keycloak_group_link.py b/controller/src/cmplink/keycloak_group_link.py new file mode 100644 index 0000000..f53a09f --- /dev/null +++ b/controller/src/cmplink/keycloak_group_link.py @@ -0,0 +1,136 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: ComponentLink +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2025 г. +# ============================================================ +from kubernetes.client import ApiClient + +from basic_resources.deployments import restart_deployment_if_exists +from basic_resources.secrets import read_secret_if_exists, prepare_secret_manifest, create_or_update_secret +from cmplink.keycloak_groups import get_accounts_from_secret_attr, get_full_robot_name, get_full_group_path +from cmplink.link import get_links_given_predicate, get_target_resource_if_exists, does_target_specified_in_link, \ + TARGET_KIND_TO_CODE + + +def get_accounts_from_secret(api_client: ApiClient, secret_name, namespace, user_registry_name, logger): + secret = read_secret_if_exists(api_client, secret_name, namespace) + if not secret: + logger.info(f'KeycloakGroup link secret {namespace}.{secret_name} ' + f'does not exist') + return (None,) * 3 + + secret_data = secret.to_dict()['data'] + usernames = None + emails = None + robots = None + if 'usernames' in secret_data: + usernames = get_accounts_from_secret_attr(secret_data, 'usernames') + if 'emails' in secret_data: + emails = get_accounts_from_secret_attr(secret_data, 'emails') + if 'robots' in secret_data: + robots = get_accounts_from_secret_attr(secret_data, 'robots') + robots = [get_full_robot_name(namespace, user_registry_name, r) for r in robots] + result = usernames, emails, robots + if not any(result): + logger.warning(f'No accounts found in KeycloakGroup link Secret {namespace}.{secret_name}') + return result + + +def _get_keycloak_group_links_given_target(api_client: ApiClient, target, target_namespace, + target_kind, user_namespace): + def predicate(link): + link_spec = link['spec'] + if 'keycloakGroup' not in link_spec: + return False + target_specified = does_target_specified_in_link(target, target_namespace, target_kind, link_spec) + return target_specified + + filtered_list = get_links_given_predicate(api_client, user_namespace, predicate) + return filtered_list + + +def _build_groups_names_given_target(api_client: ApiClient, target, target_namespace, + target_kind, user_namespace, exclude_links_names): + links_list = _get_keycloak_group_links_given_target(api_client, target, target_namespace, + target_kind, user_namespace) + links_names = {link['metadata']['name'] for link in links_list} + links_names = links_names - exclude_links_names + groups_names = {'/' + get_full_group_path(name, user_namespace) for name in links_names} + return groups_names + + +def _get_groups_names_from_direct_spec(api_client: ApiClient, target, target_namespace, target_kind, + user_namespace, logger): + api_obj = get_target_resource_if_exists(api_client, target, target_namespace, target_kind, logger) + if not api_obj: + return set() + + api_spec = api_obj['spec'] + restful_api = api_spec['restfulApi'] + auth = restful_api['auth'] + oidc = auth.get('oidc') + if not oidc: + return set() + groups = oidc.get('groups') + if not groups: + return set() + + groups_names = {'/' + get_full_group_path(name, user_namespace) for name in groups if not name.startswith('/')} + groups_names = groups_names | {name for name in groups if name.startswith('/')} + return groups_names + + +def get_groups_joint_secret_name(target_name, target_kind=None): + secret_name = target_name + '-oidc-joint-cred' if not target_kind \ + else f'{target_name}-{TARGET_KIND_TO_CODE[target_kind]}-oidc-joint-cred' + return secret_name + + +def get_oauth2_proxy_deployment_name(target_name, target_kind=None): + deployment_name = f'{target_name}-oauth2-deployment' if not target_kind \ + else f'{target_name}-{TARGET_KIND_TO_CODE[target_kind]}-oauth2-deployment' + return deployment_name + + +def _restart_oauth2_proxy(api_client: ApiClient, target, target_namespace, target_kind, logger): + deployment_name = get_oauth2_proxy_deployment_name(target, target_kind) + restart_deployment_if_exists(api_client, deployment_name, target_namespace, logger) + + +def create_or_update_groups_joint_secret(api_client: ApiClient, target, target_namespace, + user_namespace, logger, exclude_links_names=None, + target_kind=None): + # exclude_links_names нужно, потому что обработчик удаления ссылки отрабатывает перед фактическим удалением - + # в списке прочитанных ссылок будет "удаляемая" ссылка + if exclude_links_names is None: + exclude_links_names = set() + full_groups_names = _build_groups_names_given_target(api_client, target, target_namespace, + target_kind, user_namespace, exclude_links_names) + full_groups_names_to_add = _get_groups_names_from_direct_spec(api_client, target, target_namespace, + target_kind, user_namespace, logger) + full_groups_names = list(full_groups_names | full_groups_names_to_add) + secret_data = [{'key': 'groups', 'value': '"' + '\\n'.join(full_groups_names) + '\\n"'}] + + secret_name = get_groups_joint_secret_name(target, target_kind) + + manifest = prepare_secret_manifest(name=secret_name, + namespace=target_namespace, + type_='Opaque', + data=secret_data, + data_attr='stringData') + + create_or_update_secret(api_client=api_client, + name=secret_name, + namespace=target_namespace, + manifest=manifest, + logger=logger) + + +def create_or_update_groups_joint_secret_and_restart_proxy(api_client: ApiClient, target, target_namespace, + target_kind, user_namespace, logger, + exclude_links_names=None): + create_or_update_groups_joint_secret(api_client, target, target_namespace, + user_namespace, logger, exclude_links_names, + target_kind) + _restart_oauth2_proxy(api_client, target, target_namespace, target_kind, logger) diff --git a/controller/src/cmplink/keycloak_groups.py b/controller/src/cmplink/keycloak_groups.py new file mode 100644 index 0000000..9dc3aed --- /dev/null +++ b/controller/src/cmplink/keycloak_groups.py @@ -0,0 +1,612 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: ComponentLink +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2025 г. +# ============================================================ +import base64 +import secrets +import string + +import requests + +from config import OIDC_KEYCLOAK_HOST, OIDC_ROBOTS_REALM, OIDC_ROBOTS_ADMIN_CLIENT_ID, OIDC_ROBOTS_ADMIN_CLIENT_SECRET, \ + OIDC_MANAGED_GROUPS_ROOT, OIDC_CLUSTER_GROUP_NAME, OIDC_END_USERS_REALM, OIDC_END_USERS_ADMIN_CLIENT_ID, \ + OIDC_END_USERS_ADMIN_CLIENT_SECRET, OIDC_ROBOTS_CLIENT_ID +from exceptions import PlatformServiceTemporaryError + +_OIDC_GROUPS_URL_TEMPLATE = f'{OIDC_KEYCLOAK_HOST}/admin/realms/{{0}}/groups' +_OIDC_GROUP_BY_PATH_URL_TEMPLATE = f'{OIDC_KEYCLOAK_HOST}/admin/realms/{{0}}/group-by-path' +_OIDC_USERS_URL_TEMPLATE = f'{OIDC_KEYCLOAK_HOST}/admin/realms/{{0}}/users' + + +def auth_keycloak_robots(): + # todo: оптимизировать выпуск и хранение токенов, сейчас токенов выпускается слишком много + # плюс ожно оптимизировать - обновлять токен только по истечению + auth_url = f'{OIDC_KEYCLOAK_HOST}/realms/{OIDC_ROBOTS_REALM}/protocol/openid-connect/token' + data = {'client_id': OIDC_ROBOTS_ADMIN_CLIENT_ID, + 'client_secret': OIDC_ROBOTS_ADMIN_CLIENT_SECRET, + 'grant_type': 'client_credentials'} + token = _auth_keycloak(auth_url, data) + return token + + +def auth_keycloak_end_users(): + auth_url = f'{OIDC_KEYCLOAK_HOST}/realms/{OIDC_END_USERS_REALM}/protocol/openid-connect/token' + data = {'client_id': OIDC_END_USERS_ADMIN_CLIENT_ID, + 'client_secret': OIDC_END_USERS_ADMIN_CLIENT_SECRET, + 'grant_type': 'client_credentials'} + token = _auth_keycloak(auth_url, data) + return token + + +def _auth_keycloak(auth_url, data): + res = requests.post(auth_url, data=data) + if res.status_code != 200: + raise PlatformServiceTemporaryError(f'Cannot authenticate. API response text: {res.text}') + res_data = res.json() + return res_data['access_token'] + + +def get_full_robot_name_prefix(user_namespace, user_registry_name): + return f'robot_{user_namespace}+{user_registry_name}' + + +def get_full_robot_name(user_namespace, user_registry_name, name): + prefix = get_full_robot_name_prefix(user_namespace, user_registry_name) + return f'{prefix}+{name}' + + +def get_full_group_path(group_name, user_namespace): + group_path = f'{OIDC_MANAGED_GROUPS_ROOT}/{OIDC_CLUSTER_GROUP_NAME}/{user_namespace}/{group_name}' + return group_path + + +def _get_parent_group(realm, parent_path, headers, logger): + parent_group = _get_group_by_path_if_exists(realm, parent_path, headers, logger) + if not parent_group: + raise PlatformServiceTemporaryError(f'Parent group "{parent_path}" not found in realm "{realm}".') + return parent_group + + +def _get_group_by_path_if_exists(realm, group_path, headers, logger): + group_by_path_url = f'{_OIDC_GROUP_BY_PATH_URL_TEMPLATE.format(realm)}/{group_path}' + res = requests.get(group_by_path_url, headers=headers) + if res.status_code == 404: + logger.warning(f'Group "{group_path}" doesnt exist in realm "{realm}') + return None + elif not res.ok: + raise PlatformServiceTemporaryError(f'Cannot get group "{group_path}" in realm "{OIDC_ROBOTS_REALM}". ' + f'Response: {res.text}') + group = res.json() + return group + + +def _create_group(realm, group_path, group_name, parent_group_id, headers): + group_by_path_url = f'{_OIDC_GROUP_BY_PATH_URL_TEMPLATE.format(realm)}/{group_path}' + + group = {'name': group_name} + if parent_group_id: + groups_children_url = f'{_OIDC_GROUPS_URL_TEMPLATE.format(realm)}/{parent_group_id}/children' + res = requests.post(groups_children_url, json=group, headers=headers) # 204 ok + else: + res = requests.post(_OIDC_GROUPS_URL_TEMPLATE.format(realm), json=group, headers=headers) + if not res.ok: + raise PlatformServiceTemporaryError(f'Cannot create group "{group_path}" in realm "{realm}". ' + f'Response: {res.text}') + res = requests.get(group_by_path_url, headers=headers) + if not res.ok: + raise PlatformServiceTemporaryError(f'Cannot create group "{group_path}" in realm "{realm}". ' + f'Response: {res.text}') + return res + + +def _parse_group_path(group_path): + group_path = group_path.strip('/') + parts = group_path.split('/') + group_name = parts[-1] + parent_path = '/'.join(parts[:-1]) if len(parts) > 1 else None + return group_name, parent_path + + +def _set_group(realm, access_token, group_path, logger, modify=False): + """ + Проверяет, что группа по пути group_path есть. + Если, группа отсутствует и modify=True, то создает группу по пути group_path. + + Возвращает id существующей или созданной группы. + Если modify=False и проверка приводит к отрицательному результату, + записывает ошибку в лог. + """ + headers = {"Authorization": f"Bearer {access_token}"} + + group_name, parent_path = _parse_group_path(group_path) + parent_group_id = None + + if parent_path: + parent_group = _get_parent_group(realm, parent_path, headers, logger) + parent_group_id = parent_group['id'] + + group_url = f'{_OIDC_GROUP_BY_PATH_URL_TEMPLATE.format(realm)}/{group_path}' + res = requests.get(group_url, headers=headers) + + if res.status_code == 404: + if not modify: + logger.error(f'Group "{group_path}" does not exist in realm "{realm}", ' + f'and modify is False. ' + f'API response text: {res.text}') + return + + res = _create_group(realm, group_path, group_name, parent_group_id, headers) + if not res.ok: + raise PlatformServiceTemporaryError(f'Cannot create group "{group_path}" ' + f'exists in realm "{realm}". ' + f'API response text: {res.text}') + elif not res.ok: + raise PlatformServiceTemporaryError(f'Cannot check if group "{group_path}" ' + f'exists in realm "{realm}". ' + f'API response text: {res.text}') + group = res.json() + return group['id'] + + +def _move_or_create_group(realm, access_token, group_path, logger, group_id=None, modify=False): + """ + Если group_id не задан, то проверяет, что группа по пути group_path есть. + Если, при этом, modify=True, то создает группу по пути group_path. + + Возвращает id существующей или созданной группы. + Если modify=False и проверка приводит к отрицательному результату, + записывает ошибку в лог. + + Если group_id задан, то проверяет, что группа с заданным идентификатором + существует и находится по пути group_path. + Если группа с заданным идентификатором отсутствует и, при этом, modify=True, + то создает группу по пути group_path. + Если группа с заданным идентификатором существует, но находится по другому пути, + то перемещает группу по пути group_path (считая, что все сегменты кроме последнего + образуют имя родительской группы, а последний сегмент - имя; имя не изменяется). + + Возвращает id существующей или созданной группы. + Если modify=False и проверка приводит к отрицательному результату, + записывает ошибку в лог. + """ + headers = {"Authorization": f"Bearer {access_token}"} + + group_name, parent_path = _parse_group_path(group_path) + parent_group_id = None + new_group_id = group_id + + if group_id: + + if parent_path: + parent_group = _get_parent_group(realm, parent_path, headers, logger) + parent_group_id = parent_group['id'] + + group_url = f'{_OIDC_GROUPS_URL_TEMPLATE.format(realm)}/{group_id}' + res = requests.get(group_url, headers=headers) + + if res.status_code == 404: + # если group_id задан, но группа отсутствует, если modify=True, + # создаем ее, возвращаем новый id группы; + if not modify: + logger.error(f'Group "{group_id}" does not exist in realm "{realm}", ' + f'and modify is False. ' + f'API response text: {res.text}') + return + res = _create_group(realm, group_path, group_name, parent_group_id, headers) + group = res.json() + new_group_id = group['id'] + elif res.status_code == 200: + # если group_id задан, группа существует, + # нужно проверить по какому пути она находится; + group = res.json() + current_path = group['path'].strip('/') + # если путь корректный, то возвращаем текущий id группы, + # иначе, если modify=True, переносим группу в другую родительскую группу; + if group_path == current_path: + return group_id + if not modify: + logger.error(f'Group "{group_id}" ' + f'path "{group_path}" (realm "{realm}") does not match ' + f'current path "{current_path}" ' + f'and modify is False.') + return + move_group = { + 'id': group_id, + 'name': group['name'] + } + if parent_path: + groups_children_url = f'{_OIDC_GROUPS_URL_TEMPLATE.format(realm)}/{parent_group_id}/children' + res = requests.post(groups_children_url, json=move_group, headers=headers) # 204 ok + else: + # таким образом фактически происходит перемещение группы в корень; + res = requests.post(_OIDC_GROUPS_URL_TEMPLATE.format(realm), json=move_group, headers=headers) + if not res.ok: + raise PlatformServiceTemporaryError(f'Cannot move group "{group_id}" ' + f'to parent "{parent_path}" in realm "{realm}". ' + f'API response text: {res.text}') + else: + raise PlatformServiceTemporaryError(f'Cannot get group "{group_id}" in realm "{realm}". ' + f'API response text: {res.text}') + else: + # если group_id не задан, нужно проверить, что группа по пути group_path есть, + # или создать ее, если она отсутствует и modify=True; + new_group_id = _set_group(realm, access_token, group_path, logger, modify) + return new_group_id + + +def delete_group(group_ids, logger, modify): + token = auth_keycloak_end_users() + group_id = group_ids[OIDC_END_USERS_REALM] + _delete_group_in_realm(OIDC_END_USERS_REALM, token, group_id, logger, modify) + if OIDC_END_USERS_REALM != OIDC_ROBOTS_REALM: + token = auth_keycloak_robots() + group_id = group_ids[OIDC_ROBOTS_REALM] + _delete_group_in_realm(OIDC_ROBOTS_REALM, token, group_id, logger, modify) + + +def delete_group_in_robots_realm_by_path(group_path, logger, modify): + token = auth_keycloak_robots() + + _delete_group_in_realm_by_path(OIDC_ROBOTS_REALM, token, group_path, logger, modify) + + +def _delete_group_in_realm(realm, access_token, group_id, logger, modify=False): + if not modify: + logger.info(f'modify is False, will not delete group {group_id} in realm {realm}') + return + headers = {"Authorization": f"Bearer {access_token}"} + group_url = f'{_OIDC_GROUPS_URL_TEMPLATE.format(realm)}/{group_id}' + res = requests.delete(group_url, headers=headers) + if res.status_code == 404: + logger.warning(f'Group "{group_id}" doesnt exist in realm "{realm}') + elif not res.ok: + raise PlatformServiceTemporaryError(f'Cannot delete group "{group_id}" in realm "{realm}". ' + f'API response text: {res.text}') + + +def _delete_group_in_realm_by_path(realm, access_token, group_path, logger, modify=False): + if not modify: + logger.info(f'modify is False, will not delete group "{group_path}" in realm {realm}') + return + headers = {"Authorization": f"Bearer {access_token}"} + + group_by_path_url = f'{_OIDC_GROUP_BY_PATH_URL_TEMPLATE.format(OIDC_ROBOTS_REALM)}/{group_path}' + res = requests.get(group_by_path_url, headers=headers) + if res.status_code == 404: + logger.warning(f'Group "{group_path}" doesnt exist in realm "{realm}') + return + elif not res.ok: + raise PlatformServiceTemporaryError(f'Cannot get group "{group_path}" in realm "{OIDC_ROBOTS_REALM}". ' + f'Response: {res.text}') + + data = res.json() + group_id = data['id'] + + group_url = f'{_OIDC_GROUPS_URL_TEMPLATE.format(realm)}/{group_id}' + res = requests.delete(group_url, headers=headers) + if res.status_code == 404: + logger.warning(f'Group "{group_id}" doesnt exist in realm "{realm}') + elif not res.ok: + raise PlatformServiceTemporaryError(f'Cannot delete group "{group_id}" in realm "{realm}". ' + f'API response text: {res.text}') + + +def set_group_groups_chain(user_namespace, group_name, logger, modify): + token = auth_keycloak_end_users() + end_users_group_id = _set_group_groups_chain_in_realm(OIDC_END_USERS_REALM, token, user_namespace, group_name, + logger, modify) + result = {OIDC_END_USERS_REALM: end_users_group_id} + if OIDC_END_USERS_REALM != OIDC_ROBOTS_REALM: + token = auth_keycloak_robots() + robots_group_id = _set_group_groups_chain_in_realm(OIDC_ROBOTS_REALM, token, user_namespace, group_name, + logger, modify) + result[OIDC_ROBOTS_REALM] = robots_group_id + return result + + +def set_group_groups_chain_in_robots_realm(user_namespace, group_name, logger, modify): + token = auth_keycloak_robots() + robots_group_id = _set_group_groups_chain_in_realm(OIDC_ROBOTS_REALM, token, user_namespace, group_name, + logger, modify) + return robots_group_id + + +def get_accounts_from_secret_attr(secret_data_, attr): + secret_accounts = secret_data_[attr] + secret_accounts_decoded = base64.b64decode(secret_accounts).decode('utf-8').strip() + accounts = secret_accounts_decoded.split('\n') + accounts = map(lambda s: s.strip(), accounts) + return accounts + + +def _set_group_groups_chain_in_realm(realm, access_token, user_namespace, group_name, logger, modify): + _set_group(realm, access_token, OIDC_MANAGED_GROUPS_ROOT, logger, modify) + cluster_group_path = f'{OIDC_MANAGED_GROUPS_ROOT}/{OIDC_CLUSTER_GROUP_NAME}' + _set_group(realm, access_token, f'{OIDC_MANAGED_GROUPS_ROOT}/{OIDC_CLUSTER_GROUP_NAME}', logger, modify) + user_group_path = f'{cluster_group_path}/{user_namespace}' + _set_group(realm, access_token, user_group_path, logger, modify) + group_path = f'{user_group_path}/{group_name}' + group_id = _set_group(realm, access_token, group_path, logger, modify) + return group_id + + +def _clear_group_accounts(realm, group_id, headers, modify, logger): + if not modify: + logger.info(f'modify is False, will not clear group {group_id} accounts in realm {realm}') + return + group_members_url = f'{_OIDC_GROUPS_URL_TEMPLATE.format(realm)}/{group_id}/members' + res = requests.get(group_members_url, headers=headers) + if res.status_code == 404: + logger.warning(f'Group "{group_id}" doesnt exist in realm "{realm}". ' + f'Cannot remove users from group') + return + elif not res.ok: + raise PlatformServiceTemporaryError(f'Cannot remove users from group "{group_id}" in realm "{realm}". ' + f'API response text: {res.text}') + + data = res.json() + for user in data: + user_id = user['id'] + user_group_url = f'{_OIDC_USERS_URL_TEMPLATE.format(realm)}/{user_id}/groups/{group_id}' + res = requests.delete(user_group_url, headers=headers) + if res.status_code == 404: + logger.warning(f'Group "{group_id}" or user "{user_id}" doesnt exist in realm "{realm}". ' + f'Cannot remove user from group') + elif not res.ok: + raise PlatformServiceTemporaryError(f'Cannot remove user "{user_id}" from group "{group_id}" ' + f'in realm "{realm}". ' + f'API response text: {res.text}') + + +def _set_user_to_group(realm, username, user_id, group_id, headers, modify, logger): + if modify: + user_group_url = f'{_OIDC_USERS_URL_TEMPLATE.format(realm)}/{user_id}/groups/{group_id}' + res = requests.put(user_group_url, headers=headers) + if not res.ok: + raise PlatformServiceTemporaryError(f'Cannot set user "{user_id}" to group "{group_id}" ' + f'in realm "{realm}". ' + f'API response text: {res.text}') + else: + user_groups_url = f'{_OIDC_USERS_URL_TEMPLATE.format(realm)}/{user_id}/groups' + res = requests.get(user_groups_url, headers=headers) + if not res.ok: + raise PlatformServiceTemporaryError(f'Cannot get user "{user_id}" in realm "{realm}". ' + f'API response text: {res.text}') + res_data = res.json() + if not any(map(lambda g: g['id'] == group_id, res_data)): + logger.error(f'User "{username}" is not member of group "{group_id}" in realm "{realm}" ' + f'and modify is False.') + + +def _get_user_by_param_if_exists(realm, user_param, param_name, headers, logger): + users_url = _OIDC_USERS_URL_TEMPLATE.format(realm) + params = {param_name: user_param, 'exact': 'true'} + res = requests.get(users_url, params=params, headers=headers) + if not res.ok: + raise PlatformServiceTemporaryError(f'Cannot get users by {param_name} "{user_param}" ' + f'in realm "{realm}". ' + f'API response text: {res.text}') + res_data = res.json() + if not res_data: + return None + user = res_data[0] + if len(res_data) > 1: + user_id = user['id'] + logger.warning(f'There are more than one users with {param_name} "{user_param}" in realm "{realm}", ' + f'user with id {user_id} is selected') + return user + + +def _get_users_by_param(realm, user_param, param_name, headers, logger): + users_url = _OIDC_USERS_URL_TEMPLATE.format(realm) + params = {param_name: user_param} + res = requests.get(users_url, params=params, headers=headers) + if not res.ok: + raise PlatformServiceTemporaryError(f'Cannot get users by {param_name} "{user_param}" ' + f'in realm "{realm}". ' + f'API response text: {res.text}') + users = res.json() + return users + + +def _set_users_to_group_by_params(realm, group_id, users_params, param_name, headers, modify, logger): + + for user_param in users_params: + user = _get_user_by_param_if_exists(realm, user_param, param_name, headers, logger) + if not user: + logger.info(f'User with {param_name} "{user_param}" not found in realm "{realm}"') + continue + + user_id = user['id'] + _set_user_to_group(realm, user_param, user_id, group_id, headers, modify, logger) + + +def set_group_accounts(group_ids, usernames, emails, robots_full_names, modify, logger): + end_users_group_id = group_ids[OIDC_END_USERS_REALM] + robots_group_id = group_ids[OIDC_ROBOTS_REALM] + token = auth_keycloak_end_users() + headers = {"Authorization": f"Bearer {token}"} + robots_headers = headers + + _clear_group_accounts(OIDC_END_USERS_REALM, end_users_group_id, headers, modify, logger) + if OIDC_END_USERS_REALM != OIDC_ROBOTS_REALM: + robots_token = auth_keycloak_robots() + robots_headers = {"Authorization": f"Bearer {robots_token}"} + _clear_group_accounts(OIDC_ROBOTS_REALM, robots_group_id, robots_headers, modify, logger) + if usernames: + _set_users_to_group_by_params(OIDC_END_USERS_REALM, end_users_group_id, usernames, 'username', headers, modify, logger) + if emails: + _set_users_to_group_by_params(OIDC_END_USERS_REALM, end_users_group_id, emails, 'email', headers, modify, logger) + if robots_full_names: + _set_users_to_group_by_params(OIDC_ROBOTS_REALM, robots_group_id, robots_full_names, 'username', robots_headers, modify, logger) + + +def set_group_accounts_in_robots_realm(group_id, robots_full_names, modify, logger): + token = auth_keycloak_robots() + headers = {"Authorization": f"Bearer {token}"} + robots_headers = headers + + _clear_group_accounts(OIDC_ROBOTS_REALM, group_id, headers, modify, logger) + if robots_full_names: + _set_users_to_group_by_params(OIDC_ROBOTS_REALM, group_id, robots_full_names, 'username', robots_headers, + modify, logger) + + +def set_group_accounts_in_robots_realm_by_path(group_path, robots_full_names, modify, logger): + token = auth_keycloak_robots() + headers = {"Authorization": f"Bearer {token}"} + + group = _get_group_by_path_if_exists(OIDC_ROBOTS_REALM, group_path, headers, logger) + if not group: + return + group_id = group['id'] + + _clear_group_accounts(OIDC_ROBOTS_REALM, group_id, headers, modify, logger) + if robots_full_names: + _set_users_to_group_by_params(OIDC_ROBOTS_REALM, group_id, robots_full_names, 'username', headers, + modify, logger) + + +def _set_user_email(realm, user, email, headers): + user_id = user['id'] + user_url = f'{_OIDC_USERS_URL_TEMPLATE.format(realm)}/{user_id}' + user['email'] = email + res = requests.put(user_url, json=user, headers=headers) + if not res.ok: + raise PlatformServiceTemporaryError(f'Cannot set email for user "{user["username"]}" in realm "{realm}", ' + f'user id = "{user_id}".' + f'API response text: {res.text}') + + +def _create_user(realm, username, email, headers): + users_url = _OIDC_USERS_URL_TEMPLATE.format(realm) + user = {'username': username, 'email': email, 'enabled': True, 'emailVerified': True, + 'firstName': username, 'lastName': username} + res = requests.post(users_url, json=user, headers=headers) + if not res.ok: + raise PlatformServiceTemporaryError(f'Cannot create user "{username} ({email})" in realm "{realm}".' + f'API response text: {res.text}') + + loc = res.headers.get('Location') + if not loc or '/' not in loc: + raise PlatformServiceTemporaryError(f'User "{username} ({email})" in realm "{realm}" ' + f'is created, but Location header is absent or has wrong format.' + f'API response text: {res.text}') + user_id = loc[loc.rfind('/') + 1:] + return user_id + + +_passwords_alphabet = string.ascii_letters + string.digits + + +def _create_password(): + return ''.join(secrets.choice(_passwords_alphabet) for _ in range(20)) + + +def _set_user_password(realm, user_id, headers): + user_url = f'{_OIDC_USERS_URL_TEMPLATE.format(realm)}/{user_id}/reset-password' + raw_password = _create_password() + credentials = { + 'value': raw_password, + 'temporary': False + } + res = requests.put(user_url, json=credentials, headers=headers) + if not res.ok: + raise PlatformServiceTemporaryError(f'Cannot set password for user in realm "{realm}", ' + f'user id = "{user_id}".' + f'API response text: {res.text}') + return raw_password + + +def _set_user(realm, username, email, headers, modify, logger): + + user_by_name = _get_user_by_param_if_exists(realm, username, 'username', headers, logger) + user_by_email = _get_user_by_param_if_exists(realm, email, 'email', headers, logger) + if not user_by_name and user_by_email: + raise PlatformServiceTemporaryError(f'User with username "{username}" does not exist,' + f'but user with email "{email}" exists in realm "{realm}". ' + f'User id = {user_by_email["id"]}.') + user = user_by_name + user_id = None + if user: + user_id = user['id'] + user_email = user_id['email'] + if user_email != email: + if not modify: + logger.error(f'User with username "{username}" exists, but email differs from expected, ' + f'and modify is False. User id = {user_id}, user email = {user_email}.') + else: + _set_user_email(realm, user, email, headers) + else: + if not modify: + logger.error(f'User with username "{username}" does not exist in realm "{realm}", ' + f'and modify is False.') + else: + user_id = _create_user(realm, username, email, headers) + return user_id + + +def _set_users(realm, username_email_pairs, headers, modify, logger): + for username, email in username_email_pairs: + _set_user(realm, username, email, headers, modify, logger) + + +def _set_users_with_password(realm, username_email_pairs, headers, modify, logger): + username_password_pairs = [] + for username, email in username_email_pairs: + user_id = _set_user(realm, username, email, headers, modify, logger) + if user_id: + password = _set_user_password(realm, user_id, headers) + username_password_pairs.append((username, password)) + return username_password_pairs + + +def _delete_accounts(realm, username_substr, headers, modify, logger): + if not modify: + logger.info(f'modify is False, will not delete accounts ' + f'with usernames containing "{username_substr}" in realm {realm}') + return + + users = _get_users_by_param(realm, username_substr, 'username', headers, logger) + for user in users: + user_id = user['id'] + user_url = f'{_OIDC_USERS_URL_TEMPLATE.format(realm)}/{user_id}' + res = requests.delete(user_url, headers=headers) + if res.status_code == 404: + logger.warning(f'User "{user_id}" doesnt exist in realm "{realm}". ' + f'Cannot delete user.') + elif not res.ok: + raise PlatformServiceTemporaryError(f'Cannot delete user "{user_id}" ' + f'from realm "{realm}". ' + f'API response text: {res.text}') + + +def set_robot_accounts(robots_full_name_prefix, robots_full_name_email_pairs, modify, logger): + token = auth_keycloak_robots() + headers = {"Authorization": f"Bearer {token}"} + + _delete_accounts(OIDC_ROBOTS_REALM, robots_full_name_prefix, headers, modify, logger) + if robots_full_name_email_pairs: + robots_full_name_password_pairs = \ + _set_users_with_password(OIDC_ROBOTS_REALM, robots_full_name_email_pairs, headers, modify, logger) + # если пароль не нужно устанвливать - использовать _set_users + # _set_users(OIDC_ROBOTS_REALM, robots_full_name_email_pairs, headers, modify, logger) + return robots_full_name_password_pairs + + +# если в будущем получится использовать выпуск токена клиентом robots-admin с имперсонификацией по клиенту и субъекту, +# то пароль не потребуется; +def create_robot_tokens(robot_name, robot_password): + token_url = f'{OIDC_KEYCLOAK_HOST}/realms/{OIDC_ROBOTS_REALM}/protocol/openid-connect/token' + data = {'client_id': OIDC_ROBOTS_CLIENT_ID, + 'grant_type': 'password', + 'username': robot_name, + 'password': robot_password} + + res = requests.post(token_url, data=data) + if res.status_code != 200: + raise PlatformServiceTemporaryError(f'Cannot create robot tokens. API response text: {res.text}') + res_data = res.json() + return res_data diff --git a/controller/src/cmplink/link.py b/controller/src/cmplink/link.py new file mode 100644 index 0000000..ce29eaf --- /dev/null +++ b/controller/src/cmplink/link.py @@ -0,0 +1,135 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: ComponentLink +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +from kubernetes.client import CustomObjectsApi, ApiClient, ApiException + +from basic_resources.secrets import read_secret_if_exists, patch_secret_if_exists + +TARGET_KIND_DATASET_COMPONENT = 'DatasetComponent' +TARGET_KIND_API_COMPONENT = 'APIComponent' +# TARGET_KIND_API_COMPONENT не включается в маппинг +TARGET_KIND_TO_CODE = {TARGET_KIND_DATASET_COMPONENT: 'datasetcmp'} + + +def get_secret_name_from_link(link: dict): + link_spec = link['spec'] + if 'secretRef' not in link_spec: + return None + secret_ref = link_spec['secretRef'] + secret_name = secret_ref['name'] + return secret_name + + +def get_links_given_predicate(api_client: ApiClient, namespace, predicate): + # вместо прохода по списку начиная с версии 1.31 можно использовать CRD selectable fields: + # https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/#crd-selectable-fields + # co_api = CustomObjectsApi(api_client) + # field_selector = f'spec.target.credentials={secret_name}' + # links_list, _, _ = co_api.list_namespaced_custom_object_with_http_info( + # "unified-platform.cs.hse.ru", "v1", secret_namespace, + # "componentlinks", field_selector=field_selector) + # return links_list['items'] + + co_api = CustomObjectsApi(api_client) + links_list, _, _ = co_api.list_namespaced_custom_object_with_http_info( + "unified-platform.cs.hse.ru", "v1", namespace, + "componentlinks") + if not links_list['items']: + return [] + + filtered_list = [] + for link in links_list['items']: + if predicate(link): + filtered_list.append(link) + + return filtered_list + + +def get_links_if_exist(api_client: ApiClient, names, namespace, logger): + co_api = CustomObjectsApi(api_client) + result = [] + for name in names: + try: + link_res = co_api.get_namespaced_custom_object( + "unified-platform.cs.hse.ru", "v1", namespace, + "componentlinks", name) + result.append(link_res) + except ApiException as exc: + if exc.status == 404: + logger.warning(f'KeycloakGroup ComponentLink "{namespace}.{name}" does not exist') + else: + raise exc + return result + + +def get_target_resource_if_exists(api_client: ApiClient, target, target_namespace, target_kind, logger): + resource_kind = target_kind if target_kind else TARGET_KIND_API_COMPONENT + resource_kind_plural = resource_kind.lower() + 's' + co_api = CustomObjectsApi(api_client) + try: + api_obj, _, _ = co_api.get_namespaced_custom_object_with_http_info( + "unified-platform.cs.hse.ru", "v1", target_namespace, + resource_kind_plural, target) + return api_obj + except ApiException as exc: + if exc.status == 404: + logger.info(f'Application {target_namespace} {resource_kind} {target} does not exist.') + return None + raise exc + + +def does_target_specified_in_link(target, target_namespace, target_kind, link_spec): + targets = link_spec.get('targets') + app_name = link_spec['platformAppName'] + + if not targets: + return False + for target_spec in targets: + link_target = target_spec['name'] + link_target_app = target_spec['platformAppName'] if 'platformAppName' in target_spec else app_name + passed_target_kind = target_kind or TARGET_KIND_API_COMPONENT + link_target_kind = target_spec.get('kind', TARGET_KIND_API_COMPONENT) + if link_target == target and link_target_app == target_namespace and link_target_kind == passed_target_kind: + return True + + return False + + +def unset_secret_anno_and_label(api_client, anno_prefix, label, ref_name, secret_name, namespace, logger): + secret = read_secret_if_exists(api_client, secret_name, namespace) + if not secret: + return + + patch = None + + if secret.metadata.annotations is not None: + ref_anno = f'{anno_prefix}/{ref_name}' + if ref_anno in secret.metadata.annotations: + patch = {'metadata': {'annotations': {ref_anno: None}}} + secret.metadata.annotations.pop(ref_anno) + + if secret.metadata.labels is not None: + another_refs = False + if secret.metadata.annotations is not None: + for anno in secret.metadata.annotations: + if anno.startswith(anno_prefix): + another_refs = True + break + if not another_refs: + if not patch: + patch = {'metadata': {}} + patch['metadata']['labels'] = {label: None} + + if patch: + patch_secret_if_exists(api_client, secret_name, namespace, patch) + + +def get_secret_name_if_set(spec): + secret_name = None + if 'secretRef' in spec: + secret_ref = spec['secretRef'] + secret_name = secret_ref['name'] + return secret_name \ No newline at end of file diff --git a/controller/src/config.py b/controller/src/config.py new file mode 100644 index 0000000..8429f5e --- /dev/null +++ b/controller/src/config.py @@ -0,0 +1,51 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Утилиты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +import os + +from dotenv import load_dotenv + +PIPELINES_SERVICE_PORT = 80 +PIPELINES_EXTERNAL_SERVICE_NAME = 'pipelines-svc.unip-system-controller' + +load_dotenv() + +UNIP_DOMAIN = os.getenv('UNIP_DOMAIN') + +ARGO_CD_API = os.getenv('ARGO_CD_API') +ARGO_CD_USER = os.getenv('ARGO_CD_USER') +ARGO_CD_PASSWORD = os.getenv('ARGO_CD_PASSWORD') +UNIP_CONTROLLER_DEV = os.getenv('UNIP_CONTROLLER_DEV', 'False') + +argo_cd_enabled_var = os.getenv('ARGO_CD_ENABLED', 'True') +if argo_cd_enabled_var in {'True', 'False'}: + ARGO_CD_ENABLED = False if argo_cd_enabled_var == 'False' else True +else: + ARGO_CD_ENABLED = False + +OIDC_END_USERS_ISSUER_URL = os.getenv('OIDC_END_USERS_ISSUER_URL') +OIDC_END_USERS_REALM = os.getenv('OIDC_END_USERS_REALM') +OIDC_END_USERS_CLIENT_ID = os.getenv('OIDC_END_USERS_CLIENT_ID') +OIDC_END_USERS_CLIENT_SECRET = os.getenv('OIDC_END_USERS_CLIENT_SECRET') +OIDC_END_USERS_ADMIN_CLIENT_ID = os.getenv('OIDC_END_USERS_ADMIN_CLIENT_ID') +OIDC_END_USERS_ADMIN_CLIENT_SECRET = os.getenv('OIDC_END_USERS_ADMIN_CLIENT_SECRET') +OIDC_END_USERS_COOKIE_SECRET = os.getenv('OIDC_END_USERS_COOKIE_SECRET') +OIDC_END_USERS_AUD = os.getenv('OIDC_END_USERS_AUD') + +OIDC_ROBOTS_ISSUER_URL = os.getenv('OIDC_ROBOTS_ISSUER_URL') +OIDC_ROBOTS_REALM = os.getenv('OIDC_ROBOTS_REALM') +OIDC_ROBOTS_CLIENT_ID = os.getenv('OIDC_ROBOTS_CLIENT_ID') +OIDC_ROBOTS_CLIENT_SECRET = os.getenv('OIDC_ROBOTS_CLIENT_SECRET') +OIDC_ROBOTS_ADMIN_CLIENT_ID = os.getenv('OIDC_ROBOTS_ADMIN_CLIENT_ID') +OIDC_ROBOTS_ADMIN_CLIENT_SECRET = os.getenv('OIDC_ROBOTS_ADMIN_CLIENT_SECRET') +OIDC_ROBOTS_AUD = os.getenv('OIDC_ROBOTS_AUD') + +OIDC_KEYCLOAK_HOST = os.getenv('OIDC_KEYCLOAK_HOST') +OIDC_MANAGED_GROUPS_ROOT = os.getenv('OIDC_MANAGED_GROUPS_ROOT', 'unip') +OIDC_CLUSTER_GROUP_NAME = os.getenv('OIDC_CLUSTER_GROUP_NAME', 'default') +_OIDC_MODIFY = os.getenv('OIDC_MODIFY', False) +OIDC_MODIFY = True if _OIDC_MODIFY == 'True' or _OIDC_MODIFY == 'true' else False + diff --git a/controller/src/datasetcmp/README.md b/controller/src/datasetcmp/README.md new file mode 100644 index 0000000..1fa1335 --- /dev/null +++ b/controller/src/datasetcmp/README.md @@ -0,0 +1,163 @@ +--- +**Система**: Единая библиотека, Центр ИИ НИУ ВШЭ + +**Модуль**: DatasetComponent + +**Авторы**: Климин Н.А., Полежаев В.А., Хританков А.С. + +**Дата создания**: 2024 г. + +--- + +# DatasetComponent + +## Конфигурация контроллера + +- `FILES_API_BASE_URL` - URL к Files API +- `INGRESS_RULE_HOST` - хост правила ингресса +- `INGRESS_BACKEND_SERVICE_NAME` - backend-сервис для правила +- `INGRESS_BACKEND_SERVICE_PORT` - порт backend-сервиса для правила +- `UNIP_DATASET_CMP_CHECK_CONTROLLER_PERMISSIONS` - включает или выключает (`True` \ `False`) проверку прав контроллера; +- `UNIP_DATASET_CMP_VALIDATE` - включает или выключает (`True` \ `False`) валидацию датасета; + +## Алгоритм работы + +Среди обработчиков контроллера есть: + +- `set_dataset_component_rules` - обрабатывает создание и изменение модуля +- `unset_dataset_component_rules` - обрабатывает удаление модуля + +### `set_dataset_component_rules` + +1. Валидируются данные в манифесте модуля (запрашиваются файлы из API, хэшируются и валидируются) в `validate_metadata` +2. Валидируется файл метаданных на основе [JSON-схем schema.org](https://raw.githubusercontent.com/charlestati/schema-org-json-schemas/89ed608d2bd03548c10a086c58af27090920bcc5/schemas) +3. Валидируется файл со списокм файлов (запрашиваются локации из API) +4. Запрашивается конфигурация ингресса +5. Создаются или удаляются правила в `patch_rules` + - Если была добавлена версия, то для нее добавляются правила + - Если была удалена версия, то правила связанные с ней удаляются (поиск удаленных версий происходит на основе имени ящика) + +### `unset_dataset_component_rules` + +1. Если ингресс содержит правила только к данному датасету, то удаляется весь ингресс +2. Если ингресс содержит правила из других датасетов, то удаляются только правила удаленного датасета + +## Пример манифеста модуля DatasetComponent + +```yaml +apiVersion: unified-platform.cs.hse.ru/v1 +kind: DatasetComponent +metadata: + name: samokat + namespace: example-namespace +spec: + box: default-s3-box + filesApiSecret: basic-auth-credentials-not-hashed + restfulApi: + auth: + basic: + credentials: basic-auth-datacmp-credentials + versions: + - name: v1 + contents: + files: + sha256: 4575809932e33e0e88108d8296daec4e19223e85a87c101701dfd5efdb324931 + metadata: + sha256: 88439bb7372a7d5913b3c0fcbf6a78f997eb05cb61fd4aa6a07e49b4799dc8d4 + readme: + path: samokat_readme.md + sha256: a6792b14c9b7f112055c64e296d940476cab7d24ed4fadd732c356e750de2ec0 +``` + +## CLI + +Для простоты создания манифеста модуля и загрузки данных в Files API был создан скрипт `datasetcmp/cli.py` + +## Развертывание модуля данных и использование + +Для развертывания модуля данных требуется выполнить следущие пункты: + +1. Создать файл метаданных, файл со списокм файлов модуля и файлом с текстовым описанием (например, в формате Markdown). +2. Загрузить файлы модуля через файловое API. +3. Создать манифест для развертывания. +4. Развернуть в кластере Kubernetes. + +Для части пунктов можно восипользоваться скриптом `datasetcmp/cli.py`. + +```shell +python datasetcmp/cli.py -h +``` + +### Создание файлов с метаданными, списком файлов и текстовым описанием + +Файл с метаданными имеет JSON-LD формат с схемой [schema.org/Dataset](https://schema.org/Dataset) валидация происходит с использованием [JSON-схем](https://raw.githubusercontent.com/charlestati/schema-org-json-schemas/89ed608d2bd03548c10a086c58af27090920bcc5/schemas). Для создания файла можно воспользоваться любым текстовым редактором или специализированным для JSON-LD формата. + +Стоит отметить что пользоваться валидатором schema.org не рекомендуется, так как он имеет позволяет лишние поля или неправильные данные в них. Для валидации можно воспользоваться скриптом упомянутым выше. + +```shell +python datasetcmp/cli.py --verbose metadata -m tests/datasetcmp/v1/metadata.json +``` + +Файл со списком файлов также можно создать используя подготовленный скрипт. Формат на текщуий может быть любым, но рекомендуется воспользоваться скриптом для создания точного описания всех файлов. + +```shell +python datasetcmp/cli.py files tests/datasetcmp/v1/data ./files.json +``` + +Файл с текстовым описанием может быть в любом формате, однако рекомендуется использовать Markdown. + +### Загрузить файлы модуля через файловое API + +Подготовленный скрипт позволяет загрузить файлы через файловое API. Можно воспользоваться любыми другими способами, в том числе и обращаясь к API напрямую. + +В примере ниже загружаются файлы из директории `tests/datasetcmp/v1` с файлами с метаданными, со списком файлов и текстовым описанием в приложение `test-dataset-controlle` в ящик `default-s3-box` в локацию `v1`. В данном случае команда используется для создания версии `v1`. + +```shell +python datasetcmp/cli.py upload -a "test-dataset-controller" -b "default-s3-box" -l "v1" -u user -p password "tests/datasetcmp/v1" +``` + +В примере ниже загружаются файлы из директории `tests/datasetcmp/data` с файлами датасета в приложение `test-dataset-controlle` в ящик `default-s3-box` в локацию `data`. Вложенность сохраняется. В случае если файлов много и произошла ошибка можно начать загрузку с того файла на котором произошла ошибка (ключи `--fr` и `--to`). + +```shell +python datasetcmp/cli.py upload -a "test-dataset-controller" -b "default-s3-box" -l "data" -u user -p password "tests/datasetcmp/data" +``` + +### Создать манифест для развертывания + +Для создания манифеста можно воспользоваться скриптом. Аналогично другим пунктам, можно создать файл самим используя пример и CRD как основу. + +```shell +python datasetcmp/cli.py manifest -h +``` + +В примере ниже создается манифейст для версии `v1` куда передаются файлы из примеров выше, а также секрет разработчика, который позволит контроллеру работать с файловым API. + +```shell +python datasetcmp/cli.py manifest -a "test-dataset-controller" -b "default-s3-box" -v "v1" -r "tests/datasetcmp/v1/weapons_dataset.md" -f "tests/datasetcmp/v1/files.json" -m "tests/datasetcmp/v1/metadata.json" -n weapons_dataset -N example-namespace "tests/datasetcmp/dataset.yaml" --secrets-developer basic-auth-credentials-not-hashed +``` + +Стоит отметить пункт, что секрет разработчика не должен быть захэширован, так как контроллер должен отправлять данные для авторизации в API. + +Другим важным пунктом является секрет пользователя ([htpasswd](https://kubernetes.github.io/ingress-nginx/examples/auth/basic/) секрет), если ключ `--secrets-user` в скрипте не указан или в манифесте не указан спосов авторизации, то контроллер возьмет секреты для авторизации из `-joint-cred`, где `name` - название создаваемого модуля данных (поле `metadata.name` в манифесте модуля). + +### Развернуть в кластере Kubernetes + +Перед развертыванием требуется проверить, что файл сгенерирован со всеми нужными параметрами, далее можно развернуть используя `kubectl` или любой другой интерфейс. + +```shell +kubectl apply -f tests/datasetcmp/dataset.yaml +``` + +### Рекомендация по структуре файлов + +Пересекающиеся файлы версий можно расположить в общей директории `data`. В директориях с метаданными версии также можно расположить файлы, однако рекомендуется все файлы датасета расположить внутри `data` + +``` +// + v1/ # версия 1 (файлы с метаданными, файлы датасета для версии 1) + v2/ # версия 2 (файлы с метаданными, файлы датасета для версии 2) + data/ # общие файлы для всех версий (файлы датасета) + test/ + train/ + ... +``` \ No newline at end of file diff --git a/controller/src/datasetcmp/__init__.py b/controller/src/datasetcmp/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/controller/src/datasetcmp/cli.py b/controller/src/datasetcmp/cli.py new file mode 100644 index 0000000..3e0a3a2 --- /dev/null +++ b/controller/src/datasetcmp/cli.py @@ -0,0 +1,350 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: DatasetComponent +# Авторы: Климин Н.А. +# Дата создания: 2025 г. +# ============================================================ +import argparse +from functools import cache +import json +import pathlib +import re +import hashlib +import yaml +import sys +import mimetypes + +# pip install jsonschema requests +import requests +from requests.auth import HTTPBasicAuth +from referencing import Registry, Resource +import jsonschema +import jsonschema.exceptions + + +mimetypes.add_type("text/markdown", ".md") + +BASE_URL = "https://platform-dev-cs-hse.objectoriented.ru" +APP_BOX_PATTERN = re.compile(r"^[a-zA-Z0-9_-]{1,50}$") + + +def parse_arguments(): + parser = argparse.ArgumentParser(description="Prepare data for DataSet component") + parser.add_argument("--verbose", help="Verbose output", action="store_true") + subparsers = parser.add_subparsers() + + metadata_parser = subparsers.add_parser("metadata", help="Process metadata") + metadata_parser.add_argument( + "-m", + "--metadata", + help="Path to dataset metadata", + required=True, + ) + metadata_parser.set_defaults(subparser="metadata") + + files_parser = subparsers.add_parser("files", help="Process files") + files_parser.add_argument("files", help="Directory containing files") + files_parser.add_argument("output", help="Name of output file") + files_parser.set_defaults(subparser="files") + + manifest_parser = subparsers.add_parser("manifest", help="Generate manifest") + manifest_parser.add_argument("-a", "--app", help="Application name", required=True) + manifest_parser.add_argument("-b", "--box", help="Box name", required=True) + manifest_parser.add_argument("-v", "--version", help="Version name", required=True) + manifest_parser.add_argument( + "-r", + "--readme", + help="Path to dataset human readable info", + required=True, + ) + manifest_parser.add_argument( + "-f", + "--files", + help="Path to dataset contents file", + required=True, + ) + manifest_parser.add_argument( + "-m", + "--metadata", + help="Path to dataset metadata", + required=True, + ) + manifest_parser.add_argument( + "-n", + "--name", + help="Resource name", + required=True, + ) + manifest_parser.add_argument( + "-N", + "--namespace", + help="Resource namespace", + required=True, + ) + manifest_parser.add_argument( + "--secrets-developer", + help="Developer auth secret in namespace", + required=True, + ) + manifest_parser.add_argument( + "--secrets-user", + help="User auth secret (hashed) in namespace", + ) + manifest_parser.add_argument("output", help="Name of output file") + manifest_parser.set_defaults(subparser="manifest") + + upload_parser = subparsers.add_parser("upload", help="Upload files to server") + upload_parser.add_argument("-a", "--app", help="Application name", required=True) + upload_parser.add_argument("-b", "--box", help="Box name", required=True) + upload_parser.add_argument("-l", "--location", help="Location (in API)", required=True) + upload_parser.add_argument("files", help="Directory containing files") + upload_parser.add_argument("-u", "--username", help="Username for authentication") + upload_parser.add_argument("-p", "--password", help="Password for authentication") + upload_parser.add_argument("--base-url", help="Files API URL", default=BASE_URL) + upload_parser.add_argument("--fr", help="First file index", type=int, default=0) + upload_parser.add_argument("--to", help="Last file index (including)", type=int, default=-1) + upload_parser.set_defaults(subparser="upload") + + args = parser.parse_args() + + if args.subparser in ["manifest", "upload"]: + if APP_BOX_PATTERN.fullmatch(args.app) is None: + parser.error( + f"Application name is invalid, should match {APP_BOX_PATTERN.pattern}" + ) + + if APP_BOX_PATTERN.fullmatch(args.box) is None: + parser.error( + f"Box name is invalid, should match {APP_BOX_PATTERN.pattern}" + ) + + if args.subparser == "manifest": + if APP_BOX_PATTERN.fullmatch(args.name) is None: + parser.error( + f"Resource name is invalid, should match {APP_BOX_PATTERN.pattern}" + ) + if APP_BOX_PATTERN.fullmatch(args.namespace) is None: + parser.error( + f"Resource namespace is invalid, should match {APP_BOX_PATTERN.pattern}" + ) + + args.output = pathlib.Path(args.output) + args.readme = pathlib.Path(args.readme) + args.files = pathlib.Path(args.files) + args.metadata = pathlib.Path(args.metadata) + if args.output.is_dir(): + parser.error("Output path is directory") + if not args.readme.is_file(): + parser.error("Dataset human readable info is not a file or doesn't exists") + if not args.files.is_file(): + parser.error("Dataset contents file is not a file or doesn't exists") + if not args.metadata.is_file(): + parser.error("Dataset metadata is not a file or doesn't exists") + + if args.subparser == "upload": + args.files = pathlib.Path(args.files) + if not args.files.is_dir(): + parser.error("Dataset files path is not a directory or doesn't exists") + if args.username is not None and args.password is None: + parser.error("Both username and password should be set or unset") + if args.username is None and args.password is not None: + parser.error("Username and password should be both set or both unset") + + if args.subparser == "metadata": + args.metadata = pathlib.Path(args.metadata) + if not args.metadata.is_file(): + parser.error("Dataset metadata is not a file or doesn't exists") + + if args.subparser == "files": + args.output = pathlib.Path(args.output) + args.files = pathlib.Path(args.files) + if args.output.is_dir(): + parser.error("Output path is directory") + if not args.files.is_dir(): + parser.error("Dataset files path is not a directory or doesn't exists") + + return args + + +def get_checksum(data): + return hashlib.sha256(data).hexdigest() + + +def generate_manifest(args): + new_version = { + "name": args.version, + "contents": { + "readme": { + "path": args.readme.name, + "sha256": get_checksum(args.readme.read_bytes()), + }, + "metadata": { + "path": args.metadata.name, + "sha256": get_checksum(args.metadata.read_bytes()), + }, + "files": { + "path": args.files.name, + "sha256": get_checksum(args.files.read_bytes()), + }, + }, + } + data = { + "apiVersion": "unified-platform.cs.hse.ru/v1", + "kind": "DatasetComponent", + "metadata": { + "name": args.name, + "namespace": args.namespace, + }, + "spec": { + "box": args.box, + "versions": [ + new_version + ] + }, + } + if args.output.exists(): + try: + existing_data = yaml.safe_load(args.output.read_text()) + for i, version in enumerate(existing_data["spec"]["versions"]): + if version["name"] == args.version: + existing_data["spec"]["versions"][i] = new_version + break + else: + existing_data["spec"]["versions"].append(new_version) + data = existing_data + except Exception as e: + print(f"Invalid output file! Rewriting file!") + if args.secrets_developer is not None: + data["spec"]["filesApiSecret"] = args.secrets_developer + if args.secrets_user is not None: + data["spec"]["restfulApi"] = {"auth": {"basic": {"credentials": args.secrets_user}}} + args.output.write_text(yaml.safe_dump(data)) + if args.verbose: + print("Done!") + +def upload_files(args): + auth = None + if args.username is not None: + auth = HTTPBasicAuth(args.username, args.password) + files = sorted(list(args.files.glob("**/*"))) + if args.to == -1: + args.to = len(files) + for i, file in enumerate(files[args.fr:args.to]): + rel_file = file.relative_to(args.files) + if file.is_file(): + path = f"{args.base_url}/{args.app}/files/{args.box}/{args.location}/{str(rel_file)}" + response = requests.put(path, auth=auth) + if response.status_code != 200: + print(f"Error while creating location {str(rel_file)}: {response.text}") + return 1 + urls = response.json() + headers = {} + mime_type = mimetypes.guess_type(path)[0] + if mime_type is not None: + headers["content-type"] = mime_type + response = requests.put( + urls["presigned_put_url"], + data=file.read_bytes(), + auth=auth, + headers=headers, + ) + if response.status_code != 200: + print(f"Error while uploading {str(rel_file)}: {response.text}") + return 1 + elif args.verbose: + print(f"{i+1+args.fr:>8} / {args.to}. Upload for file '{file}' to '{path}' completed") + if args.verbose: + print("Done!") + + +def validate_metadata_file(args): + schemas = "https://raw.githubusercontent.com/charlestati/schema-org-json-schemas/89ed608d2bd03548c10a086c58af27090920bcc5/schemas" + remote_schemas = schemas.startswith("https://") or schemas.startswith("http://") + prefix = "schema:" + + @cache + def retrieve_schema(uri): + path = f"{schemas}/{uri.removeprefix(prefix)}.schema.json" + if remote_schemas: + response = requests.get(path) + if response.status_code != 200: + print(f"Error while retrieving schema {uri}: {response.text}") + exit(-1) + schema = response.json() + else: + file = pathlib.Path(path) + if not file.is_file(): + print(f"Error while retrieving schema {uri}: {file} is not a file") + exit(-1) + schema = json.loads(file.read_text()) + return Resource.opaque(schema) + + registry = Registry(retrieve=retrieve_schema) + schema = retrieve_schema("Dataset").contents + json_ld = json.loads(args.metadata.read_text()) + + v = jsonschema.Draft202012Validator(schema, registry=registry) + errors = sorted(v.iter_errors(json_ld), key=lambda e: e.path) + if not len(errors): + if args.verbose: + print("Ok!") + return + print("Validation error:") + for i, error in enumerate(errors): + print(f"{i+1}) {error.json_path} \n {error.message}") + exit(-1) + + +def create_files_file(args): + def search_files(_path: pathlib.Path): + files = [] + for path in _path.iterdir(): + if path.is_file(): + files.append( + { + "kind": "file", + "path": path.name, + "sha256": get_checksum(path.read_bytes()), + } + ) + else: + files.append( + { + "kind": "directory", + "path": path.name, + "files": search_files(path), + } + ) + if args.verbose: + print(f"Path '{path}' processed") + return files + + args.output.write_text( + json.dumps( + { + "kind": "directory", + "path": args.files.name, + "files": search_files(args.files), + }, + ensure_ascii=False, + indent=2, + ) + ) + if args.verbose: + print("Done!") + + +def cli(args): + if args.subparser == "manifest": + generate_manifest(args) + elif args.subparser == "upload": + upload_files(args) + elif args.subparser == "metadata": + validate_metadata_file(args) + elif args.subparser == "files": + create_files_file(args) + return 0 + + +if __name__ == "__main__": + sys.exit(cli(parse_arguments())) diff --git a/controller/src/datasetcmp/config.py b/controller/src/datasetcmp/config.py new file mode 100644 index 0000000..3e0bf05 --- /dev/null +++ b/controller/src/datasetcmp/config.py @@ -0,0 +1,19 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: DatasetComponent +# Авторы: Полежаев В.А., Климин Н.А., Хританков А.С. +# Дата создания: 2025 г. +# ============================================================ +import os + +check_controller_permissions = os.getenv('UNIP_DATASET_CMP_CHECK_CONTROLLER_PERMISSIONS', 'True') +if check_controller_permissions in {'True', 'False'}: + UNIP_DATASET_CMP_CHECK_CONTROLLER_PERMISSIONS = False if check_controller_permissions == 'False' else True +else: + UNIP_DATASET_CMP_CHECK_CONTROLLER_PERMISSIONS = False + +validate = os.getenv('UNIP_DATASET_CMP_VALIDATE', 'True') +if validate in {'True', 'False'}: + UNIP_DATASET_CMP_VALIDATE = False if validate == 'False' else True +else: + UNIP_DATASET_CMP_VALIDATE = False diff --git a/controller/src/datasetcmp/files.py b/controller/src/datasetcmp/files.py new file mode 100644 index 0000000..eb2579b --- /dev/null +++ b/controller/src/datasetcmp/files.py @@ -0,0 +1,26 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: DatasetComponent +# Авторы: Климин Н.А., Полежаев В.А., Хританков А.С. +# Дата создания: 2025 г. +# ============================================================ +from logging import Logger + +import requests +from requests.auth import HTTPBasicAuth + +from datasetcmp.utils import settings + + +def get_location(username_password: tuple[str, str], app: str, box: str, location: str, logger: Logger): + url = settings.files_api_base_url + f"/{app}/files/{box}/{location}" + auth = HTTPBasicAuth(username_password[0], username_password[1]) + response = requests.get(url, auth=auth) + logger.info(f"Response from '{url}' with status '{response.status_code}'") + return response + + +def get_content(url: str, logger: "Logger") -> bytes: + response = requests.get(url) + logger.info(f"Response from '{url}' with status '{response.status_code}'") + return response.content diff --git a/controller/src/datasetcmp/handlers.py b/controller/src/datasetcmp/handlers.py new file mode 100644 index 0000000..99b4a91 --- /dev/null +++ b/controller/src/datasetcmp/handlers.py @@ -0,0 +1,556 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: DatasetComponent +# Авторы: Полежаев В.А., Климин Н.А., Хританков А.С. +# Дата создания: 2025 г. +# ============================================================ +import base64 +import urllib.parse + +import kopf +from kubernetes.client import ApiClient, NetworkingV1Api, V1HTTPIngressPath, V1IngressBackend, V1IngressServiceBackend, \ + V1ServiceBackendPort, V1IngressRule, V1HTTPIngressRuleValue, AuthorizationV1Api, V1SelfSubjectRulesReview, \ + CoreV1Api, ApiException, V1IngressTLS, V1IngressSpec, V1ObjectMeta, V1Ingress + +# DatasetComponent имеет тесную связь с APIComponent, поэтому доступ к защищенным методам допустим +# noinspection PyProtectedMember +from apicmp.handlers import _construct_oauth2_proxy_deployment_model as construct_api_cmp_oauth2_proxy_deployment_model, \ + _construct_oauth2_proxy_ingress_model as construct_api_cmp_oauth2_proxy_ingress_model, \ + _construct_oauth2_proxy_service_model as construct_api_cmp_oauth2_proxy_service_model, \ + _construct_oauth2_proxy_np as construct_api_cmp_oauth2_proxy_np, \ + join_url_segments, _create_or_update_oauth2_proxy_ingress, _create_or_update_oauth2_proxy_deployment, \ + _create_or_update_oauth2_proxy_service, _create_or_update_oauth2_proxy_np, _get_oidc_from_spec, \ + _get_basic_from_spec +from auth import get_basic_auth_credentials +from basic_resources.deployments import delete_deployment_if_exists +from basic_resources.ingresses import delete_ingress_if_exists, read_ingress_if_exists +from basic_resources.network_policies import delete_network_policy_if_exists +from basic_resources.services import delete_svc_if_exists +from bound import not_dev_namespace +from cmplink.basic_auth_link import create_or_update_basic_auth_joint_secret, get_basic_auth_joint_secret_name +from cmplink.keycloak_group_link import get_oauth2_proxy_deployment_name, get_groups_joint_secret_name, \ + create_or_update_groups_joint_secret +from cmplink.link import TARGET_KIND_DATASET_COMPONENT +from config import UNIP_DOMAIN +from datasetcmp.config import UNIP_DATASET_CMP_CHECK_CONTROLLER_PERMISSIONS, UNIP_DATASET_CMP_VALIDATE +from datasetcmp.utils import settings, required_permissions, ProcessingError +from datasetcmp.validation import validate_metadata +from kopf_k8s_client import api_client +from parse import get_user_namespace + + +def _get_dataset_cmp_ingress_name(name): + return f'{name}-datasetcmp-ingress' + + +def _get_oauth2_proxy_ingress_name(name): + return f'{name}-datasetcmp-oauth2-ingress' + + +def _get_oauth2_proxy_path_prefix(namespace, upstream_name): + return '/' + namespace + '/proxies/datasetcmp-' + upstream_name + + +def _get_oauth2_proxy_path(namespace, upstream_name): + return _get_oauth2_proxy_path_prefix(namespace, upstream_name) + '(/|$)(.*)' + + +def _get_oauth2_proxy_service_name(name): + return f'{name}-datasetcmp-oauth2-svc' + + +def _get_oauth2_proxy_selector_label(name): + return f'{name}-datasetcmp-oauth2-proxy' + + +def _get_oauth2_proxy_np_name(name): + return f'datasetcmp-ingress-{name}-oauth2-traffic' + + +def _construct_oauth2_proxy_ingress_model(name: str, namespace: str): + + ingress_model = construct_api_cmp_oauth2_proxy_ingress_model(name, namespace) + ingress_model['name'] = _get_oauth2_proxy_ingress_name(name) + ingress_model['path'] = _get_oauth2_proxy_path(namespace, name) + ingress_model['service_name'] = _get_oauth2_proxy_service_name(name) + + return ingress_model + + +def _construct_oauth2_proxy_deployment_model(name: str, namespace: str, oidc: dict): + + deployment_model = construct_api_cmp_oauth2_proxy_deployment_model(name, namespace, oidc) + + base_url = 'https://' + UNIP_DOMAIN + + proxy_path_prefix = _get_oauth2_proxy_path_prefix(namespace, name) + redirect_url_parts = [proxy_path_prefix, 'oauth2/callback'] + redirect_url = join_url_segments(redirect_url_parts) + redirect_url = urllib.parse.urljoin(base_url, redirect_url) + + proxy_prefix_parts = [proxy_path_prefix, 'oauth2'] + proxy_prefix = '/' + join_url_segments(proxy_prefix_parts) + + deployment_model['deployment_name'] = get_oauth2_proxy_deployment_name(name, TARGET_KIND_DATASET_COMPONENT) + deployment_model['selector_label'] = _get_oauth2_proxy_selector_label(name) + deployment_model['redirect_url'] = redirect_url + deployment_model['proxy_prefix'] = proxy_prefix + deployment_model['groups_secret_name'] = get_groups_joint_secret_name(name, TARGET_KIND_DATASET_COMPONENT) + + return deployment_model + + +def _construct_oauth2_proxy_service_model(name: str, namespace: str): + service_model = construct_api_cmp_oauth2_proxy_service_model(name, namespace) + service_model['selector_label'] = _get_oauth2_proxy_selector_label(name) + service_model['service_name'] = _get_oauth2_proxy_service_name(name) + + return service_model + + +def _construct_oauth2_proxy_np(name: str, namespace: str): + np_model = construct_api_cmp_oauth2_proxy_np(name, namespace) + np_model['np_name'] = _get_oauth2_proxy_np_name(name) + np_model['selector_label'] = _get_oauth2_proxy_selector_label(name) + return np_model + + +def _delete_oauth2_proxy_ingress_if_exists(api_client_: ApiClient, name: str, namespace: str, + logger): + ingress_name = _get_oauth2_proxy_ingress_name(name) + delete_ingress_if_exists(api_client=api_client_, name=ingress_name, namespace=namespace, logger=logger) + + +def _delete_oauth2_proxy_deployment_if_exists(api_client_: ApiClient, name: str, namespace: str, logger): + deployment_name = get_oauth2_proxy_deployment_name(name, TARGET_KIND_DATASET_COMPONENT) + delete_deployment_if_exists(api_client_, namespace, deployment_name, logger) + + +def _delete_oauth2_proxy_service_if_exists(api_client_: ApiClient, name: str, namespace: str, logger): + service_name = _get_oauth2_proxy_service_name(name) + delete_svc_if_exists(api_client_, namespace, service_name, logger) + + +def _delete_oauth2_proxy_np_if_exists(api_client_: ApiClient, name: str, namespace: str, logger): + np_name = _get_oauth2_proxy_np_name(name) + delete_network_policy_if_exists(api_client_, np_name, namespace, logger) + + +def _should_oauth2_proxy_be_created(new_oidc): + if new_oidc is None: + return False + return new_oidc.get('enabled', True) + + +def _update_oauth2_proxy(dataset_cmp_name, namespace, new_oidc, logger): + create_oauth2_proxy = _should_oauth2_proxy_be_created(new_oidc) + + @kopf.subhandler(id=f'update-oauth2-proxy-ingress-{dataset_cmp_name}') + def _update_oauth2_proxy_ingress_handler(**_): + _delete_oauth2_proxy_ingress_if_exists(api_client, dataset_cmp_name, namespace, logger) + if create_oauth2_proxy: + ingress_name = _get_oauth2_proxy_ingress_name(dataset_cmp_name) + ingress_model = _construct_oauth2_proxy_ingress_model(dataset_cmp_name, namespace) + _create_or_update_oauth2_proxy_ingress(api_client, ingress_name, namespace, ingress_model, + logger) + + @kopf.subhandler(id=f'update-oauth2-proxy-deployment-{dataset_cmp_name}') + def _update_oauth2_proxy_deployment_handler(**_): + _delete_oauth2_proxy_deployment_if_exists(api_client, dataset_cmp_name, namespace, logger) + if create_oauth2_proxy: + deployment_name = get_oauth2_proxy_deployment_name(dataset_cmp_name) + deployment_model = _construct_oauth2_proxy_deployment_model(dataset_cmp_name, namespace, new_oidc) + user_namespace = get_user_namespace(namespace) + create_or_update_groups_joint_secret(api_client, dataset_cmp_name, namespace, user_namespace, logger, + None, TARGET_KIND_DATASET_COMPONENT) + _create_or_update_oauth2_proxy_deployment(api_client, deployment_name, namespace, deployment_model, logger) + + @kopf.subhandler(id=f'update-oauth2-proxy-service-{dataset_cmp_name}') + def _update_oauth2_proxy_service_handler(**_): + _delete_oauth2_proxy_service_if_exists(api_client, dataset_cmp_name, namespace, logger) + if create_oauth2_proxy: + service_name = _get_oauth2_proxy_service_name(dataset_cmp_name) + service_model = _construct_oauth2_proxy_service_model(dataset_cmp_name, namespace) + _create_or_update_oauth2_proxy_service(api_client, service_name, namespace, service_model, logger) + + @kopf.subhandler(id=f'update-oauth2-proxy-np-{dataset_cmp_name}') + def _update_oauth2_proxy_np_handler(**_): + _delete_oauth2_proxy_np_if_exists(api_client, dataset_cmp_name, namespace, logger) + if create_oauth2_proxy: + np_name = _get_oauth2_proxy_np_name(dataset_cmp_name) + np_model = _construct_oauth2_proxy_np(dataset_cmp_name, namespace) + _create_or_update_oauth2_proxy_np(api_client, np_name, namespace, np_model, logger) + + +def _delete_oauth2_proxy(api_cmp_name, namespace, logger): + _delete_oauth2_proxy_ingress_if_exists(api_client, api_cmp_name, namespace, logger) + _delete_oauth2_proxy_deployment_if_exists(api_client, api_cmp_name, namespace, logger) + _delete_oauth2_proxy_service_if_exists(api_client, api_cmp_name, namespace, logger) + _delete_oauth2_proxy_np_if_exists(api_client, api_cmp_name, namespace, logger) + + +@kopf.on.create('unified-platform.cs.hse.ru', 'datasetcomponents', when=not_dev_namespace) +def create_dataset_component(name, namespace, spec, patch, logger, **_): + oidc = _get_oidc_from_spec(spec) + user_namespace = get_user_namespace(namespace) + + _update_oauth2_proxy(name, namespace, oidc, logger) + + @kopf.subhandler(id=f'create-or-update-ba-joint-secret-for-{namespace}.{name}') + def _create_or_update_ba_joint_secret_handler(**_): + create_or_update_basic_auth_joint_secret(api_client=api_client, + target=name, + target_namespace=namespace, + user_namespace=user_namespace, + logger=logger, + exclude_direct_spec=False, + target_kind=TARGET_KIND_DATASET_COMPONENT) + + +@kopf.on.delete('unified-platform.cs.hse.ru', 'datasetcomponents', when=not_dev_namespace) +def delete_dataset_component(spec, name, namespace, logger, **_): + user_namespace = get_user_namespace(namespace) + _delete_oauth2_proxy(name, namespace, logger) + + create_or_update_basic_auth_joint_secret(api_client=api_client, + target=name, + target_namespace=namespace, + user_namespace=user_namespace, + logger=logger, + exclude_direct_spec=True, + target_kind=TARGET_KIND_DATASET_COMPONENT) + + +@kopf.on.update('unified-platform.cs.hse.ru', 'datasetcomponents', + when=not_dev_namespace, field='spec') +def update_dataset_component(name, namespace, old, new, patch, logger, **_): + old_spec = old if old else {} + spec = new + oidc = _get_oidc_from_spec(spec) + basic = _get_basic_from_spec(spec) + + _update_oauth2_proxy(name, namespace, oidc, logger) + + @kopf.subhandler(id=f'create-or-update-joint-ba-secret-for-{namespace}.{name}', retries=3) + def _create_or_update_ba_joint_secret_handler(**_): + # теоретически, можно выделить в отдельный обработчик @kopf.on.field + + old_api = old_spec['restfulApi'] + old_auth = old_api['auth'] + old_basic = old_auth.get('basic') + old_secret = old_basic.get('credentials') if old_basic else None + + api = spec['restfulApi'] + auth = api['auth'] + new_basic = auth.get('basic') + new_secret = new_basic.get('credentials') if basic else None + + if old_secret != new_secret: + user_namespace = get_user_namespace(namespace) + create_or_update_basic_auth_joint_secret(api_client=api_client, + target=name, + target_namespace=namespace, + user_namespace=user_namespace, + logger=logger, + exclude_direct_spec=False, + target_kind=TARGET_KIND_DATASET_COMPONENT) + + +# todo: использовать для datasetcmp шаблоны Jinja вместо объектов (здесь и далее) +# - для соответствия с остальной частью контроллера (см. контроллеры MLComponent, APIComponent) +def to_ingress_host_path(path, path_type="Exact"): + return V1HTTPIngressPath( + backend=V1IngressBackend( + service=V1IngressServiceBackend( + name=settings.ingress_backend_service_name, + port=V1ServiceBackendPort( + number=int(settings.ingress_backend_service_port) + ), + ) + ), + path=path, + path_type=path_type, + ) + + +def _should_api_be_published(spec): + basic = _get_basic_from_spec(spec) + basic_enabled = basic.get('enabled', True) if basic else False + oidc = _get_oidc_from_spec(spec) + oidc_enabled = oidc.get('enabled', True) if oidc else False + if basic_enabled or oidc_enabled: + return True + # пока считаем, что если любая аутентификация выключена, то доступ закрыт + return False + + +def _append_auth_annotations(annotations, name, namespace, basic, oidc): + if basic and basic.get('enabled', True): + annotations["nginx.ingress.kubernetes.io/auth-type"] = "basic" + annotations["nginx.ingress.kubernetes.io/auth-secret"] = \ + get_basic_auth_joint_secret_name(name, TARGET_KIND_DATASET_COMPONENT) + if oidc and oidc.get('enabled', True): + annotations["nginx.ingress.kubernetes.io/satisfy"] = "any" + base_url = 'https://$host' + proxy_path_prefix = _get_oauth2_proxy_path_prefix(namespace, name) + auth_url = base_url + proxy_path_prefix + '/oauth2/auth' + auth_signin = base_url + proxy_path_prefix + '/oauth2/start?rd=$escaped_request_uri' + annotations["nginx.ingress.kubernetes.io/auth-url"] = auth_url + annotations["nginx.ingress.kubernetes.io/auth-signin"] = auth_signin + + +def _construct_ingress_model(name: str, namespace: str, rules, files_basic_creds: str, + basic: dict | None, oidc: dict | None): + configuration_snippet = f"""\ +proxy_set_header Authorization "{files_basic_creds}"; +proxy_pass_header Authorization; +proxy_pass_header Content-Type; +if ($request_method != GET) {{ + return 403; +}} +rewrite ^(.+?)/datasets/(.+) $1/files/$2 break;\ +""" + + annotations = { + "nginx.ingress.kubernetes.io/use-regex": "true", + "nginx.ingress.kubernetes.io/configuration-snippet": configuration_snippet, + "nginx.ingress.kubernetes.io/auth-realm": "Authentication Required - datasets", + } + + _append_auth_annotations(annotations, name, namespace, basic, oidc) + + return V1Ingress( + api_version="networking.k8s.io/v1", + kind="Ingress", + metadata=V1ObjectMeta( + name=_get_dataset_cmp_ingress_name(name), + namespace=namespace, + annotations=annotations + ), + spec=V1IngressSpec( + ingress_class_name="nginx", + rules=rules, + tls=[V1IngressTLS(hosts=[settings.ingress_rule_host])], + ), + ) + + +def _construct_rules_patch(app: str, rules, dataset_spec, operation): + box: str = dataset_spec["box"] + rule_base_path = f"/{app}/datasets/{box}" + if operation == "update": + data_path = f"{rule_base_path}/data" + datacmp_ingress_paths = {rule_base_path: to_ingress_host_path(data_path, "ImplementationSpecific")} + for version in dataset_spec["versions"]: + version_name: str = version["name"] + version_path = f"{rule_base_path}/{version_name}" + datacmp_ingress_paths[f"{rule_base_path}/{version_name}"] = \ + to_ingress_host_path(version_path, "ImplementationSpecific") + if len(rules): + for j, path in reversed(list(enumerate(rules[0].http.paths))): + if path.path.startswith(rule_base_path) and path.path not in datacmp_ingress_paths: + rules[0].http.paths.pop(j) + rule = rules[0] + for j, path in enumerate(rule.http.paths): + if path.path in datacmp_ingress_paths: + rules[0].http.paths[j] = datacmp_ingress_paths.pop(path.path) + for new_path in datacmp_ingress_paths.values(): + rules[0].http.paths.append(new_path) + else: + rules.append( + V1IngressRule( + host=settings.ingress_rule_host, + http=V1HTTPIngressRuleValue( + paths=list(datacmp_ingress_paths.values()) + ), + ) + ) + elif operation == "remove": + rule = rules[0] + for j, path in reversed(list(enumerate(rule.http.paths))): + if path.path.startswith(rule_base_path): + rules[0].http.paths.pop(j) + if len(rules[0].http.paths) == 0: + return [] + return rules + + +def _construct_auth_annotations_patch(name, namespace, basic: dict | None, oidc: dict | None): + annotations = {"nginx.ingress.kubernetes.io/auth-type": None, + "nginx.ingress.kubernetes.io/auth-secret": None, + "nginx.ingress.kubernetes.io/satisfy": None, + "nginx.ingress.kubernetes.io/auth-url": None, + "nginx.ingress.kubernetes.io/auth-signin": None} + + _append_auth_annotations(annotations, name, namespace, basic, oidc) + + patch = {"metadata": {"annotations": annotations}} + return patch + + +def _get_controller_permissions(namespace: str = None): + auth_v1_api = AuthorizationV1Api(api_client) + + response: V1SelfSubjectRulesReview = \ + auth_v1_api.create_self_subject_rules_review(body={"spec": {"namespace": namespace}}) + + output = {} + for rule in response.status.resource_rules: + for api_group in rule.api_groups: + for resource in rule.resources: + output.setdefault(f"{api_group}:{resource}", set()).update(set(rule.verbs)) + + return output + + +def _get_files_username_password(namespace, spec): + core_v1_api = CoreV1Api(api_client) + auth_secret = core_v1_api.read_namespaced_secret(spec["filesApiSecret"], namespace) + secret_creds = list(auth_secret.data.items())[0] # creds ~ (auth, ) + credentials_lines = secret_creds[1] + username, password = get_basic_auth_credentials(credentials_lines) + return username, password + + +def _username_password_to_basic_creds(username_password): + username, password = username_password + basic_auth_creds = f'{username}:{password}' + basic_auth_creds = 'Basic ' + base64.b64encode(basic_auth_creds.encode('utf-8')).decode('ascii') + return basic_auth_creds + + +def _create_ingress(name, namespace, spec, files_username_password, logger): + networking_v1_api = NetworkingV1Api(api_client) + rules = _construct_rules_patch(namespace, [], spec, "update") + restful_api_auth = spec["restfulApi"]["auth"] + basic = restful_api_auth.get('basic') + oidc = restful_api_auth.get('oidc') + + files_basic_creds = _username_password_to_basic_creds(files_username_password) + + ingress_model = _construct_ingress_model(name, namespace, rules, + files_basic_creds=files_basic_creds, + basic=basic, oidc=oidc) + + networking_v1_api.create_namespaced_ingress(namespace=namespace, body=ingress_model) + logger.info(f"Ingress for DatasetComponent '{name}' created") + + +def _patch_ingress_rules(name, namespace, ingress_name, ingress, rules, logger): + networking_v1_api = NetworkingV1Api(api_client) + ingress.spec.rules = rules + networking_v1_api.patch_namespaced_ingress(name=ingress_name, namespace=namespace, body=ingress) + logger.info(f"Ingress for DatasetComponent '{name}' patched") + + +def _patch_ingress_auth(name, namespace, spec, ingress_name, logger): + networking_v1_api = NetworkingV1Api(api_client) + restful_api_auth = spec["restfulApi"]["auth"] + basic = restful_api_auth.get('basic') + oidc = restful_api_auth.get('oidc') + anno_patch = _construct_auth_annotations_patch(name, namespace, basic, oidc) + networking_v1_api.patch_namespaced_ingress(name=ingress_name, namespace=namespace, body=anno_patch) + # todo: для оптимизации можно объединить с патчем выше + # (аналогичный _patch_ingress_rules подход для патчинга метаданных не работает), + # объединить в один общий метод по аналогии с create_ingress + logger.info(f"Ingress for DatasetComponent '{name}' patched") + + +def _check_required_permissions(namespace: str = None): + permissions = _get_controller_permissions(namespace) + for resource, verbs in required_permissions.items(): + if resource not in permissions: + raise ProcessingError(f"Insufficient permissions for resource '{resource}'") + existing_verbs = permissions[resource] + for verb in verbs: + if verb not in existing_verbs: + raise ProcessingError(f"Insufficient permissions for resource '{resource}' verb '{verb}'") + + +def _check_controller_has_permissions(namespace, logger): + if not UNIP_DATASET_CMP_CHECK_CONTROLLER_PERMISSIONS: + return + try: + _check_required_permissions(namespace) + except ProcessingError as exc: + msg = exc.args[0] + logger.error(msg) + raise kopf.TemporaryError(msg) + except ApiException as exc: + msg = f"Got error while retrieving permissions for namespace '{namespace}'" + logger.error(msg) + raise kopf.TemporaryError(msg) + + +def _check_metadata(spec, name, namespace, logger, username_password): + if not UNIP_DATASET_CMP_VALIDATE: + logger.info('Metadata validation is disabled in controller') + return + try: + validate_metadata(namespace, username_password, spec, logger) + except ProcessingError as e: + logger.warning(f"DatasetComponent '{name}' has invalid metadata") + return { + "metadataStatus": e.args[0], + "ingressStatus": "Unknown", + } + + +# обработчики DatasetComponent разделены (вместо одного общего on.create, on.update, ...), +# потому что исходно настройка Ingress для DatasetComponent была реализована в другом проекте; +@kopf.on.create("unified-platform.cs.hse.ru", "v1", "datasetcomponents") +@kopf.on.update("unified-platform.cs.hse.ru", "v1", "datasetcomponents") +def set_dataset_component_rules(spec, name: str, namespace: str, logger, **_): + _check_controller_has_permissions(namespace, logger) + + files_username_password = _get_files_username_password(namespace, spec) + ingress_name = _get_dataset_cmp_ingress_name(name) + + error_status = _check_metadata(spec, name, namespace, logger, files_username_password) + if error_status: + return error_status + metadata_status = "OK" + ingress_status = "Unknown" + + ingress = read_ingress_if_exists(api_client, ingress_name, namespace, logger) + published = _should_api_be_published(spec) + + if ingress is None and published: + _create_ingress(name, namespace, spec, files_username_password, logger) + ingress_status = "Created" + if ingress is None and not published: + logger.info(f"Auth for DatasetComponent '{name}' disabled, ingress not created") + ingress_status = "NotCreated" + if ingress and published: + rules = _construct_rules_patch(namespace, ingress.spec.rules, spec, "update") + _patch_ingress_rules(name, namespace, ingress_name, ingress, rules, logger) + _patch_ingress_auth(name, namespace, spec, ingress_name, logger) + ingress_status = "Patched" + if ingress and not published: + # если publish == False, то независимо ни от чего, ингресс нужно удалить + delete_ingress_if_exists(api_client, ingress_name, namespace, logger) + ingress_status = "Deleted" + + return { + "metadataStatus": metadata_status, + "ingressStatus": ingress_status, + } + + +@kopf.on.delete("unified-platform.cs.hse.ru", "v1", "datasetcomponents") +def unset_dataset_component_rules(spec, name: str, namespace: str, logger, **_): + _check_controller_has_permissions(namespace, logger) + + ingress_name = _get_dataset_cmp_ingress_name(name) + ingress = read_ingress_if_exists(api_client, ingress_name, namespace, logger) + if not ingress: + return + + published = _should_api_be_published(spec) + rules = _construct_rules_patch(namespace, ingress.spec.rules, spec, "remove") + if rules and published: + # это соответствует разработанной ранее логике, с поправкой на обработку условия publish + _patch_ingress_rules(name, namespace, ingress_name, ingress, rules, logger) + _patch_ingress_auth(name, namespace, spec, ingress_name, logger) + else: + delete_ingress_if_exists(api_client, ingress_name, namespace, logger) \ No newline at end of file diff --git a/controller/src/datasetcmp/utils.py b/controller/src/datasetcmp/utils.py new file mode 100644 index 0000000..68ea2f5 --- /dev/null +++ b/controller/src/datasetcmp/utils.py @@ -0,0 +1,26 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: DatasetComponent +# Авторы: Климин Н.А., Полежаев В.А., Хританков А.С. +# Дата создания: 2025 г. +# ============================================================ +from pydantic_settings import BaseSettings +# todo: конфигурировать при помощи чистого Python, не использовать pydantic_settings + + +class ProcessingError(BaseException): + pass + + +class Settings(BaseSettings): + files_api_base_url: str = "https://platform-test.stratpro.hse.ru" + ingress_rule_host: str = "platform-test.stratpro.hse.ru" + ingress_backend_service_name: str = "files-svc" + ingress_backend_service_port: int = 80 + + +settings = Settings() +required_permissions = { + ":secrets": {"get"}, + "networking.k8s.io:ingresses": {"get", "create", "update", "patch", "delete"}, +} diff --git a/controller/src/datasetcmp/validation.py b/controller/src/datasetcmp/validation.py new file mode 100644 index 0000000..defde08 --- /dev/null +++ b/controller/src/datasetcmp/validation.py @@ -0,0 +1,118 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: DatasetComponent +# Авторы: Климин Н.А., Полежаев В.А., Хританков А.С. +# Дата создания: 2025 г. +# ============================================================ +import hashlib +import json +import pathlib +from functools import cache + +import jsonschema +import referencing +import requests + +from datasetcmp.files import get_content, get_location +from datasetcmp.utils import ProcessingError + + +def validate_checksum(data, hash_sum: str): + return hashlib.sha256(data).hexdigest() == hash_sum + + +_DEFAULT_SCHEMA = "https://raw.githubusercontent.com/charlestati/schema-org-json-schemas/89ed608d2bd03548c10a086c58af27090920bcc5/schemas" + + +def validate_metadata_file(json_ld: dict, logger, schemas: str = _DEFAULT_SCHEMA): + remote_schemas = schemas.startswith("https://") or schemas.startswith("http://") + prefix = "schema:" + + @cache + def retrieve_schema(uri: str): + path = f"{schemas}/{uri.removeprefix(prefix)}.schema.json" + if remote_schemas: + response = requests.get(path) + if response.status_code != 200: + raise ProcessingError(f"Internal error. Error while retrieving schema {uri}: {response.text}") + schema_ = response.json() + else: + file = pathlib.Path(path) + if not file.is_file(): + raise ProcessingError(f"Internal error. Error while retrieving schema {uri}: {file} is not a file") + schema_ = json.loads(file.read_text()) + return referencing.Resource.opaque(schema_) + + registry = referencing.Registry(retrieve=retrieve_schema) + schema = retrieve_schema("Dataset").contents + + v = jsonschema.Draft202012Validator(schema, registry=registry) + errors = sorted(v.iter_errors(json_ld), key=lambda e: e.path) + if len(errors): + raise ProcessingError(f"Metadata file is invalid, " + f"validation errors messages: {[error.message for error in errors]}") + + +def validate_files(directory: dict, base_path: str, app: str, box: str, version: str, + username_password: tuple[str, str], logger): + directory_path = f"{app}/files/{box}/{version}/{base_path}{directory['path']}" + files = set() + for file in directory["files"]: + if file["kind"] == "directory": + validate_files(file, base_path + f"{directory['path']}/", app, box, version, username_password, logger) + continue + files.add(f"{directory_path}/{file['path']}") + + location_str = f"{version}/{base_path}/{directory['path']}/" + location = get_location(username_password=username_password, app=app, box=box, + location=location_str, logger=logger) + + if location.status_code != 200: + raise ProcessingError(f"Location '{location_str}' is inaccessible") + + for file in location.json()["files"]: + if file["name"] not in files: + logger.warning(f"Extra file found in location '{location_str}'") + else: + files.remove(file["name"]) + + if len(files) > 5: + files_str = "', '".join(sorted(files)[:5]) + raise ProcessingError(f"Location '{location_str}' missing {len(files)} files, first 5: '{files_str}'") + elif len(files) != 0: + files_str = "', '".join(sorted(files)) + raise ProcessingError(f"Location '{location_str}' missing some files: '{files_str}'") + + +def validate_metadata(app: str, username_password: tuple[str, str], spec, logger): + box: str = spec["box"] + for version in spec["versions"]: + version_name: str = version["name"] + contents: dict = version["contents"] + metadata_json_ld = {} + files_json = {} + for k, v in contents.items(): + path = v["path"] + hash_sum = v["sha256"] + location = get_location(username_password=username_password, app=app, box=box, + location=f"{version_name}/{path}", logger=logger) + if location.status_code != 200: + raise ProcessingError(f"Location '{version_name}/{path}' is inaccessible") + presigned_get_url = location.json()["presigned_get_url"] + content = get_content(presigned_get_url, logger) + if k == "metadata": + try: + metadata_json_ld = json.loads(content) + except json.JSONDecodeError: + raise ProcessingError(f"Metadata file '{version_name}/{path}' cannot be decoded") + elif k == "files": + try: + files_json = json.loads(content) + except json.JSONDecodeError: + raise ProcessingError(f"Files file '{version_name}/{path}' cannot be decoded") + if not validate_checksum(content, hash_sum): + raise ProcessingError(f"Hashsum for '{version_name}/{path}' is invalid") + validate_metadata_file(metadata_json_ld, logger) + # Files API currently do not return all files for location and there is no pagination + # Waiting for updates + # validate_files(files_json, "data", app, box, version_name, username_password, logger) diff --git a/controller/src/exceptions.py b/controller/src/exceptions.py new file mode 100644 index 0000000..1e7df3f --- /dev/null +++ b/controller/src/exceptions.py @@ -0,0 +1,48 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Утилиты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ + +from kopf import TemporaryError, PermanentError + + +class InputValidationPermanentError(PermanentError): + pass + + +class InputValidationTemporaryError(TemporaryError): + pass + + +class RelatedObjectNotReadyTemporaryError(TemporaryError): + pass + + +class ObjectAlreadyExistsTemporaryError(TemporaryError): + pass + + +class ObjectDoesNotExistTemporaryError(TemporaryError): + pass + + +class ObjectDoesNotExistPermanentError(PermanentError): + pass + + +class PlatformServicePermanentError(PermanentError): + pass + + +class PlatformServiceTemporaryError(TemporaryError): + pass + + +class InternalErrorPermanentError(PermanentError): + pass + + +class RelatedObjectValuePermanentError(PermanentError): + pass \ No newline at end of file diff --git a/controller/src/exp_pipeline/__init__.py b/controller/src/exp_pipeline/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/controller/src/exp_pipeline/api.py b/controller/src/exp_pipeline/api.py new file mode 100644 index 0000000..2e5d1a4 --- /dev/null +++ b/controller/src/exp_pipeline/api.py @@ -0,0 +1,400 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: ExperimentPipeline +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +import logging +import urllib.parse +from contextlib import asynccontextmanager + +from fastapi import FastAPI, Depends, HTTPException +from httpx import AsyncClient +from jsonschema.validators import Draft202012Validator +from kubernetes_asyncio.client import ApiClient +from sqlalchemy.ext.asyncio import AsyncSession +from starlette.responses import Response + +from auth import get_user_id, allowed_to_platform_user +from config import UNIP_DOMAIN +from exp_pipeline.logs import configure_logging +from exp_pipeline.pipeline import start_trial, get_trial, get_pipeline_resource, \ + list_pipeline_resources, list_trials, add_condition_to_status, get_trial_user_id, OpenAPISpecCache, \ + get_api_resource, set_next_started +from exp_pipeline.schema import CreateTrialRequest, PipelineTrial, \ + PipelineVersionResponse, PipelinesResponse, PipelinesLinks, Link, PipelineLinks, EmbeddedPipeline, \ + PipelinesEmbedded, PipelineResponse, TrialsResponse, TrialsLinks, TrialsEmbedded, CreateStatusConditionRequest +from exp_pipeline.storage.db import init_db, get_db +from kube_config import async_unip_load_kube_config + +_http_client: AsyncClient | None = None +_k8s_api_client: ApiClient | None = None + +configure_logging() + +logger = logging.getLogger(__name__) + + +@asynccontextmanager +async def _lifespan(app: FastAPI): + global _http_client, _k8s_api_client + await async_unip_load_kube_config(logger) + _http_client = AsyncClient(timeout=30) + _k8s_api_client = ApiClient() + yield + await _http_client.aclose() + await _k8s_api_client.close() + + +app = FastAPI(lifespan=_lifespan) + + +# альтернативный вариант, per-request: +# async def _get_http_client(): +# with AsyncClient() as http_client: +# yield http_client +# +# def path_op(http_client: AsyncClient = Depends(_get_http_client)) +# ... + + +@app.on_event("startup") +async def init_db_on_start(): + await init_db() + + +openapi_spec_cache = OpenAPISpecCache.get_spec_cache() + + +def _validate_create_trial_request(create_trial_request: CreateTrialRequest, openapi_spec: dict): + components = openapi_spec['components'] + schemas = components['schemas'] + openapi_spec = schemas['CreateTrialRequest'] + + validator = Draft202012Validator(openapi_spec) + request_obj = create_trial_request.model_dump(exclude_none=True) + + if not validator.is_valid(request_obj): + errors = sorted(validator.iter_errors(request_obj), key=lambda e: e.path) + errors_strs = [] + errors_model = [] + for error in errors: + s, m = list(error.schema_path), error.message + error_struct = {'path': s, 'message': m} + errors_strs.append('{0}, {1}'.format(s, m)) + nested_errors = [] + for sub_error in sorted(error.context, key=lambda e: e.schema_path): + s, m = list(sub_error.schema_path), sub_error.message + errors_strs.append('{0}, {1}'.format(s, m)) + nested_errors.append({'path': s, 'message': m}) + error_struct['sub'] = nested_errors + errors_model.append(error_struct) + error_msg = '\n'.join(errors_strs) + logger.info(f'Validation error: {error_msg}') + raise HTTPException(status_code=400, detail=errors_model) + + +async def start_trial_op(app_name: str, + pipeline_name: str, + create_trial_request: CreateTrialRequest, + db: AsyncSession, + user_id: str): + pipeline_resource = await get_pipeline_resource(api_client=_k8s_api_client, + app_name=app_name, + pipeline_name=pipeline_name) + api_resource = await get_api_resource(api_client=_k8s_api_client, + app_name=app_name, + pipeline_name=pipeline_name) + + openapi_spec = await openapi_spec_cache.get_pipeline_api_spec(k8s_api_client=_k8s_api_client, + app_name=app_name, + api_resource=api_resource) + + _validate_create_trial_request(create_trial_request, openapi_spec) + + trial = await start_trial(db=db, + http_client=_http_client, + api_client=_k8s_api_client, + app_name=app_name, + user_id=user_id, + pipeline_name=pipeline_name, + api_resource=api_resource, + pipeline_resource=pipeline_resource, + trial_inputs=create_trial_request.inputs, + trial_output_vars=create_trial_request.output_vars) + + return trial + + +@app.post("/{app_name}/pipelines/{pipeline_name}/trials", response_model=PipelineTrial) +async def post_trial_op(app_name: str, + pipeline_name: str, + create_trial_request: CreateTrialRequest, + db: AsyncSession = Depends(get_db), + user_id: str = Depends(get_user_id)): + trial = await start_trial_op(app_name=app_name, + pipeline_name=pipeline_name, + create_trial_request=create_trial_request, + db=db, + user_id=user_id) + + return trial + + +@app.post("/{app_name}/pipelines/{pipeline_name}/trials/continue", + response_model=PipelineTrial, + dependencies=[Depends(allowed_to_platform_user)]) +async def post_next_trial_op(app_name: str, + pipeline_name: str, + next_pipeline_name: str, + tracking_id: str, + create_trial_request: CreateTrialRequest, + db: AsyncSession = Depends(get_db)): + user_id = await get_trial_user_id(db=db, + app_name=app_name, + pipeline_name=None, + tracking_id=tracking_id) + + next_trial = await start_trial_op(app_name=app_name, + pipeline_name=next_pipeline_name, + create_trial_request=create_trial_request, + db=db, + user_id=user_id) + + await set_next_started(db=db, + tracking_id=tracking_id, + app_name=app_name, + pipeline_name=pipeline_name, + next_tracking_id=next_trial.tracking_id) + + return next_trial + + +@app.get("/{app_name}/pipelines/{pipeline_name}/check", + dependencies=[Depends(allowed_to_platform_user)]) +async def check_op(app_name: str, + pipeline_name: str): + return Response() + + +@app.get("/{app_name}/trials/{tracking_id}", + response_model=PipelineTrial) +async def get_trial_op(app_name: str, + tracking_id: str, + db: AsyncSession = Depends(get_db), + user_id: str = Depends(get_user_id)): + trial = await get_trial(db=db, + app_name=app_name, + pipeline_name=None, + tracking_id=tracking_id, + user_id=user_id) + + return trial + + +@app.post("/{app_name}/pipelines/{pipeline_name}/trials/{tracking_id}/status/conditions", + dependencies=[Depends(allowed_to_platform_user)]) +async def post_trial_status_condition_op(response: Response, + app_name: str, + pipeline_name: str, + tracking_id: str, + create_condition_request: CreateStatusConditionRequest, + db: AsyncSession = Depends(get_db)): + modified = await add_condition_to_status(db=db, + tracking_id=tracking_id, + type_=create_condition_request.type, + message=create_condition_request.message, + reason=create_condition_request.reason, + transition_time=create_condition_request.transition_time, + stage=create_condition_request.stage, + app_name=app_name, + pipeline_name=pipeline_name) + response.status_code = 200 if modified else 204 + return + + +@app.get('/{app_name}/pipelines/{pipeline_name}/version', + response_model=PipelineVersionResponse, + dependencies=[Depends(get_user_id)]) +async def get_pipeline_version_op(app_name: str, + pipeline_name: str): + api_resource = await get_api_resource(api_client=_k8s_api_client, + app_name=app_name, + pipeline_name=pipeline_name) + + try: + openapi_spec = await openapi_spec_cache.get_pipeline_api_spec(k8s_api_client=_k8s_api_client, + app_name=app_name, + api_resource=api_resource) + except Exception as exc: + logger.exception('OpenAPI specification generation error, ' + 'specification not available', exc_info=exc) + openapi_spec = None + + return PipelineVersionResponse(openapi_spec=openapi_spec, + license=None) + + +def _get_list_request_self_link(cursor, limit, uri): + query_params = [] + if cursor: + query_params.append(f'cursor={cursor}') + if limit: + query_params.append(f'limit={limit}') + self_href = urllib.parse.urljoin(f'https://{UNIP_DOMAIN}', uri) + if query_params: + query = '&'.join(query_params) + self_href += f'?{query}' + + self_link = Link(href=self_href) + return self_link + + +def _get_list_request_next_link(new_cursor, limit_set, uri): + if new_cursor: + query_params = [f'cursor={new_cursor}', f'limit={limit_set}'] + query = '&'.join(query_params) + cursor_href = urllib.parse.urljoin(f'https://{UNIP_DOMAIN}', f'{uri}?{query}') + cursor_link = Link(href=cursor_href) + else: + cursor_link = None + return cursor_link + + +@app.get('/{app_name}/pipelines/{pipeline_name}/trials', + response_model=TrialsResponse, + dependencies=[Depends(get_user_id)]) +async def get_pipeline_trials_op(app_name: str, + pipeline_name: str, + db: AsyncSession = Depends(get_db), + user_id: str = Depends(get_user_id), + cursor: int | None = None, + limit: int | None = None): + limit_set = limit or 10 + if limit_set > 30: + limit_set = 30 + if limit_set < 0: + limit_set = 10 + trials, new_cursor, counts = await list_trials(db=db, + app_name=app_name, + pipeline_name=pipeline_name, + user_id=user_id, + cursor=cursor, + limit=limit_set) + + total_item_count, remaining_item_count = counts + + uri = f'{app_name}/pipelines/{pipeline_name}/trials' + self_link = _get_list_request_self_link(cursor, limit, uri) + cursor_link = _get_list_request_next_link(new_cursor, limit_set, uri) + + links = TrialsLinks(self=self_link, next=cursor_link) + + te = TrialsEmbedded(trials=trials) + + resp = TrialsResponse(_links=links, + total_item_count=total_item_count, + remaining_item_count=remaining_item_count, + _embedded=te) + + return resp + + +@app.get('/{app_name}/trials', + response_model=TrialsResponse, + dependencies=[Depends(get_user_id)]) +async def get_trials_op(app_name: str, + db: AsyncSession = Depends(get_db), + user_id: str = Depends(get_user_id), + cursor: int | None = None, + limit: int | None = None): + limit_set = limit or 10 + if limit_set > 30: + limit_set = 30 + if limit_set < 0: + limit_set = 10 + trials, new_cursor, counts = await list_trials(db=db, + app_name=app_name, + user_id=user_id, + cursor=cursor, + limit=limit_set) + + total_item_count, remaining_item_count = counts + + uri = f'{app_name}/trials' + self_link = _get_list_request_self_link(cursor, limit, uri) + cursor_link = _get_list_request_next_link(new_cursor, limit_set, uri) + + links = TrialsLinks(self=self_link, next=cursor_link) + + te = TrialsEmbedded(trials=trials) + + resp = TrialsResponse(_links=links, + total_item_count=total_item_count, + remaining_item_count=remaining_item_count, + _embedded=te) + + return resp + + +def _get_pipeline_links(app_name, pipeline_name): + self_href = urllib.parse.urljoin(f'https://{UNIP_DOMAIN}', f'{app_name}/pipelines/{pipeline_name}') + self_link = Link(href=self_href) + trials_href = f'{self_href}/trials' + trials_link = Link(href=trials_href) + version_href = f'{self_href}/version' + version_link = Link(href=version_href) + pl = PipelineLinks(self=self_link, trials=trials_link, version=version_link) + return pl + + +@app.get('/{app_name}/pipelines', + response_model=PipelinesResponse, + dependencies=[Depends(get_user_id)]) +async def get_pipelines_op(response: Response, + app_name: str, + cursor: str | None = None, + limit: int | None = None): + limit_set = limit or 10 + pipelines, new_cursor, remaining_item_count, expired = await list_pipeline_resources(api_client=_k8s_api_client, + app_name=app_name, + cursor=cursor, + limit=limit_set) + + uri = f'{app_name}/pipelines' + self_link = _get_list_request_self_link(cursor, limit, uri) + cursor_link = _get_list_request_next_link(new_cursor, limit_set, uri) + + links = PipelinesLinks(self=self_link, next=cursor_link) + + embedded_pipelines = [] + + for p in pipelines: + pipeline_name = p['metadata']['name'] + pl = _get_pipeline_links(app_name, pipeline_name) + ep = EmbeddedPipeline(name=pipeline_name, _links=pl) + embedded_pipelines.append(ep) + + pe = PipelinesEmbedded(pipelines=embedded_pipelines) + + resp = PipelinesResponse(_links=links, remaining_item_count=remaining_item_count, _embedded=pe) + if expired: + response.status_code = 410 + return resp + + +@app.get('/{app_name}/pipelines/{pipeline_name}', + response_model=PipelineResponse, + dependencies=[Depends(get_user_id)]) +async def get_pipeline_op(app_name: str, + pipeline_name: str): + pipeline_res = await get_pipeline_resource(api_client=_k8s_api_client, + app_name=app_name, + pipeline_name=pipeline_name) + pipeline_name = pipeline_res['metadata']['name'] + pipeline_links = _get_pipeline_links(app_name, pipeline_name) + pipeline_definition = pipeline_res['spec'] + + resp = PipelineResponse(name=pipeline_name, _links=pipeline_links, definition=pipeline_definition) + + return resp diff --git a/controller/src/exp_pipeline/api/docker.md b/controller/src/exp_pipeline/api/docker.md new file mode 100644 index 0000000..ba601c7 --- /dev/null +++ b/controller/src/exp_pipeline/api/docker.md @@ -0,0 +1,16 @@ +``` +docker run --rm -p 8080:8080 \ +--name swagger-unip-pipeline \ +-e SWAGGER_FILE=/api/openapi.yaml \ +-e PORT=8080 \ +-v $PWD/controller/src/exp_pipeline/api:/api swaggerapi/swagger-editor +``` + +Для использования спецификации 3.1: + +``` +docker run --rm -p 8080:80 \ +--name swagger-unip-pipeline \ +-e SWAGGER_FILE=/api/openapi.yaml \ +-v $PWD/controller/src/exp_pipeline/api:/api swaggerapi/swagger-editor:next-v5 +``` \ No newline at end of file diff --git a/controller/src/exp_pipeline/api/openapi-snapshot.json b/controller/src/exp_pipeline/api/openapi-snapshot.json new file mode 100644 index 0000000..e9f11a4 --- /dev/null +++ b/controller/src/exp_pipeline/api/openapi-snapshot.json @@ -0,0 +1,1756 @@ +{ + "openapi": "3.1.0", + "info": { + "title": "Experiment Pipeline - OpenAPI 3.1", + "description": "Спецификция сервиса Experiment Pipeline", + "termsOfService": "https://platform-dev-cs-hse.objectoriented.ru/terms/", + "contact": { + "email": "apiteam@platform-dev-cs-hse.objectoriented.ru" + }, + "version": "1.0.0" + }, + "servers": [ + { + "url": "http://localhost:8001" + }, + { + "url": "https://platform-dev-cs-hse.objectoriented.ru/app/pipelines" + } + ], + "tags": [ + { + "name": "pipelines", + "description": "Операции с пайплайнами", + "externalDocs": { + "description": "Подробнее", + "url": "https://platform-dev-cs-hse.objectoriented.ru" + } + }, + { + "name": "trials", + "description": "Операции с запусками пайплайнов", + "externalDocs": { + "description": "Подробнее", + "url": "https://platform-dev-cs-hse.objectoriented.ru" + } + } + ], + "security": [ + { + "basic_auth": [] + } + ], + "paths": { + "/{app}/trials/{tracking_id}": { + "parameters": [ + { + "name": "X-Request-Id", + "in": "header", + "schema": { + "$ref": "#/components/headers/request_id" + }, + "description": "Идентификатор для диагностики запроса", + "examples": { + "example": { + "summary": "Идентификатор из нулей", + "description": "Идентификатор в формате UUID", + "value": "00000000-0000-0000-0000-000000000000" + } + } + }, + { + "name": "app", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Имя приложения PlatformApp" + }, + { + "name": "tracking_id", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Идентификатор отслеживания запуска пайплайна" + } + ], + "get": { + "tags": [ + "trials" + ], + "summary": "Получить запуск пайплайна", + "description": "Возвращает запуск пайплайна, включая текущий статус и значения входных и выходных переменных этапов.", + "operationId": "get_trial", + "responses": { + "200": { + "$ref": "#/components/responses/trial" + }, + "401": { + "description": "Аутентификация не пройдена", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "headers": { + "X-Request-Id": { + "$ref": "#/components/headers/request_id" + } + } + }, + "404": { + "description": "Не найден запрошенный ресурс.\nВозможные причины: \n- Указанный запуск пайплайна не существует;\n", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "headers": { + "X-Request-Id": { + "$ref": "#/components/headers/request_id" + } + } + }, + "default": { + "$ref": "#/components/responses/trial" + } + } + } + }, + "/{app}/pipelines/{pipeline}/trials": { + "parameters": [ + { + "name": "X-Request-Id", + "in": "header", + "schema": { + "$ref": "#/components/headers/request_id" + }, + "description": "Идентификатор для диагностики запроса", + "examples": { + "example": { + "summary": "Идентификатор из нулей", + "description": "Идентификатор в формате UUID", + "value": "00000000-0000-0000-0000-000000000000" + } + } + }, + { + "name": "app", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Имя приложения PlatformApp" + }, + { + "name": "pipeline", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Имя пайплайна ExperimentPipeline" + } + ], + "get": { + "tags": [ + "trials", + "pipelines" + ], + "summary": "Получить запуски пайплайна", + "description": "Возвращает запуски пайплайна. Для каждого запуска возвращает текущий статус и значения входных и выходных переменных этапов", + "operationId": "get_pipeline_trials", + "responses": { + "200": { + "description": "Операция завершена успешно", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TrialsResponse" + } + } + }, + "headers": { + "X-Request-Id": { + "$ref": "#/components/headers/request_id" + } + } + }, + "401": { + "description": "Аутентификация не пройдена", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "headers": { + "X-Request-Id": { + "$ref": "#/components/headers/request_id" + } + } + }, + "404": { + "description": "Не найден запрошенный ресурс.\nВозможные причины: \n- Указанный пайплайн не существует;\n", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "headers": { + "X-Request-Id": { + "$ref": "#/components/headers/request_id" + } + } + }, + "default": { + "description": "Операция завершена успешно", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TrialsResponse" + } + } + }, + "headers": { + "X-Request-Id": { + "$ref": "#/components/headers/request_id" + } + } + } + } + }, + "post": { + "tags": [ + "trials" + ], + "summary": "Запустить пайплайн", + "description": "Запускает выполнение пайплайна, при этом создается объект, который содержит информацию о запуске и ходе выполнения", + "operationId": "post_trial", + "requestBody": { + "description": "Тело запроса", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateTrialRequest" + }, + "examples": { + "simple": { + "summary": "Запуск простого пайплайна", + "description": "Запуск пайплайна с одной входной и одной выходной переменной", + "value": { + "inputs": [ + { + "name": "input1", + "data": "[1.0, 2.0, 3.0, 4.0]", + "datatype": "FP32", + "shape": [ + 1, + 4 + ] + } + ], + "output_vars": [ + { + "name": "output1", + "data": "outputs/" + } + ] + } + } + } + } + }, + "required": true + }, + "responses": { + "201": { + "$ref": "#/components/responses/trial" + }, + "401": { + "description": "Аутентификация не пройдена", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "headers": { + "X-Request-Id": { + "$ref": "#/components/headers/request_id" + } + } + }, + "404": { + "description": "Ошибка входных данных.\nВозможные причины: \n- Указанный пайплайн не существует;\n", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "headers": { + "X-Request-Id": { + "$ref": "#/components/headers/request_id" + } + } + }, + "503": { + "description": "Сервис недоступен.\n", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "headers": { + "X-Request-Id": { + "$ref": "#/components/headers/request_id" + } + } + }, + "default": { + "$ref": "#/components/responses/trial" + } + } + } + }, + "/{app}/trials": { + "parameters": [ + { + "name": "X-Request-Id", + "in": "header", + "schema": { + "$ref": "#/components/headers/request_id" + }, + "description": "Идентификатор для диагностики запроса", + "examples": { + "example": { + "summary": "Идентификатор из нулей", + "description": "Идентификатор в формате UUID", + "value": "00000000-0000-0000-0000-000000000000" + } + } + }, + { + "name": "app", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Имя приложения PlatformApp" + } + ], + "get": { + "tags": [ + "trials" + ], + "summary": "Получить все запуски пайплайна пользователя", + "description": "Возвращает запуски пайплайна. Для каждого запуска возвращает текущий статус и значения входных и выходных переменных этапов", + "operationId": "get_trials", + "responses": { + "200": { + "description": "Операция завершена успешно", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TrialsResponse" + } + } + }, + "headers": { + "X-Request-Id": { + "$ref": "#/components/headers/request_id" + } + } + }, + "401": { + "description": "Аутентификация не пройдена", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "headers": { + "X-Request-Id": { + "$ref": "#/components/headers/request_id" + } + } + }, + "default": { + "description": "Операция завершена успешно", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TrialsResponse" + } + } + }, + "headers": { + "X-Request-Id": { + "$ref": "#/components/headers/request_id" + } + } + } + } + } + }, + "/{app}/pipelines/{pipeline}/trials/continue": { + "parameters": [ + { + "name": "X-Request-Id", + "in": "header", + "schema": { + "$ref": "#/components/headers/request_id" + }, + "description": "Идентификатор для диагностики запроса", + "examples": { + "example": { + "summary": "Идентификатор из нулей", + "description": "Идентификатор в формате UUID", + "value": "00000000-0000-0000-0000-000000000000" + } + } + }, + { + "name": "app", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Имя приложения PlatformApp" + }, + { + "name": "pipeline", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Имя пайплайна предшествующего запуска" + }, + { + "name": "tracking_id", + "in": "query", + "required": true, + "schema": { + "type": "string" + }, + "description": "Идентификатор отслеживания предшествующего запуска" + }, + { + "name": "next_pipeline_name", + "in": "query", + "required": true, + "schema": { + "type": "string" + }, + "description": "Имя пайплайна, который нужно запустить" + } + ], + "post": { + "tags": [ + "trials" + ], + "summary": "Запустить следующий пайплайн", + "description": "Запускает выполнение пайплайна, при этом создается объект, который содержит информацию о запуске и ходе выполнения", + "operationId": "post_trial_continue", + "requestBody": { + "description": "Тело запроса", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateTrialRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "$ref": "#/components/responses/trial" + }, + "401": { + "description": "Аутентификация не пройдена", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "headers": { + "X-Request-Id": { + "$ref": "#/components/headers/request_id" + } + } + }, + "404": { + "description": "Ошибка входных данных.\nВозможные причины: \n- Указанный пайплайн не существует;\n", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "headers": { + "X-Request-Id": { + "$ref": "#/components/headers/request_id" + } + } + }, + "default": { + "$ref": "#/components/responses/trial" + } + } + } + }, + "/{app}/pipelines": { + "parameters": [ + { + "name": "X-Request-Id", + "in": "header", + "schema": { + "$ref": "#/components/headers/request_id" + }, + "description": "Идентификатор для диагностики запроса", + "examples": { + "example": { + "summary": "Идентификатор из нулей", + "description": "Идентификатор в формате UUID", + "value": "00000000-0000-0000-0000-000000000000" + } + } + }, + { + "name": "app", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Имя приложения PlatformApp" + } + ], + "get": { + "tags": [ + "pipelines" + ], + "summary": "Получить доступные пайплайны приложения", + "description": "Возвращает пайплайны приложения, которые можно выполнить", + "operationId": "get_pipelines", + "responses": { + "200": { + "description": "Операция завершена успешно", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PipelinesResponse" + } + } + }, + "headers": { + "X-Request-Id": { + "$ref": "#/components/headers/request_id" + } + } + }, + "401": { + "description": "Аутентификация не пройдена", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "headers": { + "X-Request-Id": { + "$ref": "#/components/headers/request_id" + } + } + }, + "410": { + "description": "Ресурс устарел.\nВозможные причины:\n- Устарел курсор;\n", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "headers": { + "X-Request-Id": { + "$ref": "#/components/headers/request_id" + } + } + }, + "default": { + "description": "Операция завершена успешно", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PipelinesResponse" + } + } + }, + "headers": { + "X-Request-Id": { + "$ref": "#/components/headers/request_id" + } + } + } + } + } + }, + "/{app}/pipelines/{pipeline}": { + "parameters": [ + { + "name": "X-Request-Id", + "in": "header", + "schema": { + "$ref": "#/components/headers/request_id" + }, + "description": "Идентификатор для диагностики запроса", + "examples": { + "example": { + "summary": "Идентификатор из нулей", + "description": "Идентификатор в формате UUID", + "value": "00000000-0000-0000-0000-000000000000" + } + } + }, + { + "name": "app", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Имя приложения PlatformApp" + }, + { + "name": "pipeline", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Имя пайплайна ExperimentPipeline" + } + ], + "get": { + "tags": [ + "pipelines" + ], + "summary": "Получить пайплайн", + "description": "Возвращает информацию о пайплайне.", + "operationId": "get_pipeline", + "responses": { + "200": { + "description": "Операция завершена успешно", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PipelineResponse" + } + } + }, + "headers": { + "X-Request-Id": { + "$ref": "#/components/headers/request_id" + } + } + }, + "401": { + "description": "Аутентификация не пройдена", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "headers": { + "X-Request-Id": { + "$ref": "#/components/headers/request_id" + } + } + }, + "404": { + "description": "Не найден запрошенный ресурс.\nВозможные причины: \n- Указанный пайплайн не существует;\n", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "headers": { + "X-Request-Id": { + "$ref": "#/components/headers/request_id" + } + } + }, + "default": { + "description": "Операция завершена успешно", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PipelineResponse" + } + } + }, + "headers": { + "X-Request-Id": { + "$ref": "#/components/headers/request_id" + } + } + } + } + } + }, + "/{app}/pipelines/{pipeline}/trials/{tracking_id}/status/conditions": { + "parameters": [ + { + "name": "X-Request-Id", + "in": "header", + "schema": { + "$ref": "#/components/headers/request_id" + }, + "description": "Идентификатор для диагностики запроса", + "examples": { + "example": { + "summary": "Идентификатор из нулей", + "description": "Идентификатор в формате UUID", + "value": "00000000-0000-0000-0000-000000000000" + } + } + }, + { + "name": "app", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Имя приложения PlatformApp" + }, + { + "name": "pipeline", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Имя пайплайна" + }, + { + "name": "tracking_id", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Идентификатор отслеживания запуска пайплайна" + } + ], + "post": { + "tags": [ + "trials" + ], + "summary": "Добавить условие в статус запуска пайплайна", + "description": "Добавляет условие в статус запуска пайплайна. Если условие с таким типом уже существует в статусе, то оно не добавляется.", + "operationId": "post_trial_status_condition", + "requestBody": { + "description": "Тело запроса", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateStatusConditionRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Операция завершена успешно", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmptyResponse" + } + } + }, + "headers": { + "X-Request-Id": { + "$ref": "#/components/headers/request_id" + } + } + }, + "204": { + "description": "Статус не изменен", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmptyResponse" + } + } + }, + "headers": { + "X-Request-Id": { + "$ref": "#/components/headers/request_id" + } + } + }, + "401": { + "description": "Аутентификация не пройдена", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "headers": { + "X-Request-Id": { + "$ref": "#/components/headers/request_id" + } + } + }, + "404": { + "description": "Не найден запрошенный ресурс.\nВозможные причины: \n- Указанный запуск не существует;\n", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "headers": { + "X-Request-Id": { + "$ref": "#/components/headers/request_id" + } + } + }, + "default": { + "description": "Операция завершена успешно", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmptyResponse" + } + } + }, + "headers": { + "X-Request-Id": { + "$ref": "#/components/headers/request_id" + } + } + } + } + } + }, + "/{app}/pipelines/{pipeline}/version": { + "parameters": [ + { + "name": "X-Request-Id", + "in": "header", + "schema": { + "$ref": "#/components/headers/request_id" + }, + "description": "Идентификатор для диагностики запроса", + "examples": { + "example": { + "summary": "Идентификатор из нулей", + "description": "Идентификатор в формате UUID", + "value": "00000000-0000-0000-0000-000000000000" + } + } + }, + { + "name": "app", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Имя приложения PlatformApp" + }, + { + "name": "pipeline", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Имя пайплайна ExperimentPipeline" + } + ], + "get": { + "tags": [ + "pipelines" + ], + "summary": "Получить версию пайплайна", + "description": "Возвращает версию пайплайна, что включает OpenAPI спецификацию для запуска пайплайна, версию и лицензию по использованию пайплайна.", + "operationId": "get_pipeline_version", + "responses": { + "200": { + "description": "Операция завершена успешно", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PipelineVersionResponse" + } + } + }, + "headers": { + "X-Request-Id": { + "$ref": "#/components/headers/request_id" + } + } + }, + "401": { + "description": "Аутентификация не пройдена", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "headers": { + "X-Request-Id": { + "$ref": "#/components/headers/request_id" + } + } + }, + "404": { + "description": "Не найден запрошенный ресурс.\nВозможные причины: \n- Указанный пайплайн не существует;\n", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "headers": { + "X-Request-Id": { + "$ref": "#/components/headers/request_id" + } + } + }, + "default": { + "description": "Операция завершена успешно", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PipelineVersionResponse" + } + } + }, + "headers": { + "X-Request-Id": { + "$ref": "#/components/headers/request_id" + } + } + } + } + } + }, + "/{app}/pipelines/{pipeline}/check": { + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Имя приложения PlatformApp" + }, + { + "name": "pipeline", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Имя пайплайна ExperimentPipeline" + } + ], + "get": { + "tags": [ + "pipelines" + ], + "summary": "Проверить наличие доступа", + "description": "Используется для проверки доступа контейнеров пользователей к API Pipelines.", + "operationId": "get_pipeline_check", + "responses": { + "200": { + "description": "Операция завершена успешно", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmptyResponse" + } + } + } + }, + "401": { + "description": "Аутентификация не пройдена", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Доступ запрещен", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "default": { + "description": "Операция завершена успешно", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmptyResponse" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "Link": { + "description": "Ссылка на ресурс", + "type": "object", + "properties": { + "href": { + "type": "string" + }, + "templated": { + "type": "boolean" + } + }, + "required": [ + "href" + ] + }, + "EmptyResponse": { + "description": "Пустой ответ", + "type": "object", + "properties": { + "additional_info": { + "type": "object", + "additionalProperties": false, + "minProperties": 0, + "maxProperties": 0 + } + } + }, + "TrialResponse": { + "description": "Запуск пайплайна", + "type": "object", + "properties": { + "app_name": { + "description": "Имя приложения PlatformApp", + "type": "string" + }, + "user_id": { + "description": "Идентификатор пользователя, который запустил пайплайн", + "type": "string" + }, + "tracking_id": { + "description": "Идентификатор отслеживания запуска", + "type": "string" + }, + "pipeline_name": { + "description": "Имя пайплайна ExperimentPipeline", + "type": "string" + }, + "pipeline_version": { + "description": "Версия ресурса ExperimentPipeline, используемая для запуска", + "type": "string" + }, + "next_tracking_id": { + "description": "Идентификатор отслеживания запуска следующего пайплайна", + "type": "string" + }, + "next_pipeline_name": { + "description": "Имя следующего пайплайна ExperimentPipeline", + "type": "string" + }, + "vars": { + "description": "Значения входных и выходных переменные запуска.", + "type": "object", + "properties": { + "inputs": { + "description": "Значения входных переменных. В списке содержатся только те входные переменные, значения для которых передаются и были переданы при запуске пайплайна.\nВходные переменные, ассоциированные в спецификации пайплайна с данными в ящиках, не содержатся в списке.", + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "description": "Имя входной переменной", + "type": "string" + }, + "box_name": { + "description": "Имя ассоциированного ящика DataBox", + "type": "string" + }, + "data": { + "description": "Значение входной переменной.\n\nЛокация в сервисе Files, по которой можно получить значение входной переменной.\nМожет указывать как на файл, так и на файловую группу.\n\nЕсли при запуске пайплайна входное значение было\nпередано с datatype не из {'FILE', 'WEBSITE'}, то значением атрибута\nявляется локация созданного файла, в который записано\nпереданное значение.", + "type": "string" + }, + "datatype": { + "description": "Тип значения входной переменной", + "type": "string", + "enum": [ + "FILE", + "FP32", + "FP64", + "INT32", + "str", + "dict", + "WEBSITE" + ] + }, + "content_type": { + "type": "string", + "description": "Тип содержимого файла или файлов входной переменной.\n\nЕсли при запуске пайплайна входное значение было\nпередано с datatype != 'FILE', то тип содержимого файла, в который сохранено переданное значение, соответствует установленному предопределенному типу для этого datatype." + } + }, + "required": [ + "name", + "box_name", + "data", + "datatype", + "content_type" + ] + } + }, + "outputs": { + "description": "Значения выходных переменных. В списке содержатся только те выходные переменные, параметры которых были переданы при запуске пайплайна.", + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "description": "Имя выходной переменной", + "type": "string" + }, + "box_name": { + "description": "Имя ассоциированного ящика DataBox", + "type": "string" + }, + "data": { + "description": "Имя ассоциированной локации в сервисе Files. Локация соответствует файловой группе. Если запуск еще не завершен, то результаты в файловой группе будут отсутствовать.", + "type": "string" + }, + "datatype": { + "description": "Тип значения выходной переменной", + "type": "string", + "enum": [ + "FILE", + "WEBSITE" + ] + }, + "content_type": { + "description": "Тип содержимого файла или файлов выходной переменной.\nТип содержимого определяется в атрибутах content_type объектов списка output_vars, переданных при запуске пайплайна.", + "type": "string" + } + }, + "required": [ + "name", + "box_name", + "data" + ] + } + } + } + }, + "status": { + "$ref": "#/components/schemas/TrialStatus" + }, + "_links": { + "description": "Ссылки на связанные ресурсы", + "type": "object", + "properties": { + "self": { + "$ref": "#/components/schemas/Link" + }, + "pipeline": { + "$ref": "#/components/schemas/Link" + } + } + } + }, + "required": [ + "app_name", + "user_id", + "tracking_id", + "pipeline_name", + "pipeline_version", + "status", + "_links" + ] + }, + "EmbeddedTrial": { + "description": "Краткое представление запуска пайплайна", + "type": "object", + "properties": { + "app_name": { + "description": "Имя приложения PlatformApp", + "type": "string" + }, + "user_id": { + "description": "Идентификатор пользователя, который запустил пайплайн", + "type": "string" + }, + "tracking_id": { + "description": "Идентификатор отслеживания запуска", + "type": "string" + }, + "pipeline_name": { + "description": "Имя пайплайна ExperimentPipeline", + "type": "string" + }, + "pipeline_version": { + "description": "Версия ресурса ExperimentPipeline, используемая для запуска", + "type": "string" + }, + "next_tracking_id": { + "description": "Идентификатор отслеживания запуска следующего пайплайна", + "type": "string" + }, + "next_pipeline_name": { + "description": "Имя следующего пайплайна ExperimentPipeline", + "type": "string" + }, + "status": { + "$ref": "#/components/schemas/TrialStatus" + }, + "_links": { + "description": "Ссылки на связанные ресурсы", + "type": "object", + "properties": { + "self": { + "$ref": "#/components/schemas/Link" + }, + "pipeline": { + "$ref": "#/components/schemas/Link" + } + } + } + }, + "required": [ + "app_name", + "user_id", + "tracking_id", + "pipeline_name", + "pipeline_version", + "status", + "_links" + ] + }, + "TrialStatus": { + "description": "Статус запуска пайплайна", + "type": "object", + "properties": { + "status_date_time": { + "description": "Время последнего изменения статуса в формате ISO", + "type": "string" + }, + "conditions": { + "description": "Список условий, составляющих статус запуска", + "type": "array", + "items": { + "type": "object", + "properties": { + "type": { + "description": "Тип условия", + "type": "string" + }, + "condition_status": { + "description": "Статус условия", + "type": "string", + "enum": [ + "True", + "False", + "Unknown" + ] + }, + "last_transition_time": { + "description": "Время последнего изменения статуса условия в формате ISO", + "type": "string" + }, + "message": { + "description": "Подробное описание условия, понятное человеку", + "type": "string" + }, + "reason": { + "description": "Содержит программный идентификатор, являющийся индикатором причины последнего изменения статуса условия", + "type": "string" + }, + "stage": { + "description": "Опциональное имя этапа, к которому относится условие", + "type": "string" + } + }, + "required": [ + "type", + "condition_status", + "last_transition_time", + "message", + "reason" + ] + } + } + }, + "required": [ + "status_date_time" + ] + }, + "CreateStatusConditionRequest": { + "description": "Запрос добавления условия в статус запуска пайплайна", + "type": "object", + "properties": { + "type": { + "description": "Тип условия", + "type": "string" + }, + "message": { + "description": "Подробное описание условия, понятное человеку", + "type": "string" + }, + "reason": { + "description": "Содержит программный идентификатор, являющийся индикатором причины последнего изменения статуса условия", + "type": "string" + }, + "transition_time": { + "description": "Время условия статуса условия с часовым поясом в формате ISO", + "type": "string" + }, + "stage": { + "description": "Опциональное имя этапа, к которому относится условие", + "type": "string" + } + }, + "required": [ + "type" + ] + }, + "TrialsResponse": { + "description": "Список запусков пайплайнов", + "type": "object", + "properties": { + "_links": { + "description": "Ссылки на связанные ресурсы", + "type": "object", + "properties": { + "self": { + "$ref": "#/components/schemas/Link" + }, + "next": { + "$ref": "#/components/schemas/Link" + } + } + }, + "remaining_item_count": { + "description": "Оставшееся число элементов перед курсором", + "type": "integer" + }, + "total_item_count": { + "description": "Общее число элементов", + "type": "integer" + }, + "_embedded": { + "type": "object", + "properties": { + "trials": { + "description": "Список запусков", + "type": "array", + "items": { + "$ref": "#/components/schemas/EmbeddedTrial" + } + } + }, + "required": [ + "trials" + ] + } + }, + "required": [ + "_links", + "_embedded", + "remaining_item_count", + "total_item_count" + ] + }, + "CreateTrialRequest": { + "description": "Запрос запуска пайплайна", + "type": "object", + "properties": { + "inputs": { + "description": "Список значений входных переменных.\n\nЕсли значение входной переменной не задано,\nто оно не будет передано в пайплайн, \nи переменная не будет сохранена в запуске пайплайна.", + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "description": "Имя входной переменной", + "type": "string" + }, + "data": { + "description": "Значение входной переменной.\n\nЕсли datatype из {'FILE', 'WEBSITE'}, то содержит локацию в сервисе Files,\nпо которой можно получить значение входной переменной.\nМожет указывать как на файл, так и на файловую группу.\n\nЕсли datatype не из {'FILE', 'WEBSITE'}, то содержит строку с сериализованным \nзначением входной переменной, которое будет сохранено в файл. \n\nДля каждого datatype != 'FILE' для файла,\nв который сохраняется значение переменной,\nустановлен предопределенный тип содержимого (content_type).", + "type": "object" + }, + "datatype": { + "description": "Тип значения входной переменной", + "type": "string", + "enum": [ + "FILE", + "FP32", + "FP64", + "INT32", + "str", + "dict", + "WEBSITE" + ] + }, + "content_type": { + "description": "Тип содержимого файла или файлов, при типе входной переменной\ndatatype == \\\"FILE\\\". Тип содержимого файла должен быть задан\nпри запуске пайплайна.\n\nПри типе входной переменной datatype != \\\"FILE\\\" переданный тип содержимого \nфайла игнорируется. Для каждого datatype установлен предопределенный тип содержимого.", + "type": "string" + }, + "shape": { + "description": "Размерность, как массива, значения входной переменной. Применимо к любым типам данных входной переменной.", + "oneOf": [ + { + "type": "integer" + }, + { + "type": "array", + "items": { + "type": "integer" + }, + "minItems": 1, + "maxItems": 32 + } + ] + } + }, + "required": [ + "name", + "data", + "datatype", + "shape" + ] + } + }, + "output_vars": { + "type": "array", + "description": "Список параметров для выходных переменных.\n\nЕсли параметры выходной переменной не заданы,\nто они не будет переданы в пайплайн,\nпайплайн не вычислит значений выходной переменной,\nи переменная не будет сохранена в запуске пайплайна.", + "items": { + "description": "Параметры выходной переменной", + "type": "object", + "properties": { + "name": { + "description": "Имя выходной переменной", + "type": "string" + }, + "data": { + "description": "Локация выходной переменной в сервисе Files.\n\nУказывает, куда должны быть сохранены значения выходной\nпеременной. Должна соответствовать файловой группе.\n\nМожет быть не указана, тогда будет создана файловая группа со \nсгенерированным именем.", + "type": "string" + }, + "datatype": { + "description": "Тип значения выходной переменной", + "type": "string", + "enum": [ + "FILE", + "WEBSITE" + ] + }, + "content_type": { + "type": "string", + "description": "Ожидаемый тип содержимого файла или файлов выходной переменной." + } + }, + "required": [ + "name" + ] + } + } + } + }, + "PipelineResponse": { + "description": "Пайплайн ExperimentPipeline", + "type": "object", + "properties": { + "name": { + "description": "Имя пайплайна", + "type": "string" + }, + "_links": { + "description": "Ссылки на связанные ресурсы", + "type": "object", + "properties": { + "self": { + "$ref": "#/components/schemas/Link" + }, + "trials": { + "$ref": "#/components/schemas/Link" + }, + "version": { + "$ref": "#/components/schemas/Link" + } + } + }, + "definition": { + "description": "Спецификация пайплайна в формате JSON", + "type": "object" + } + }, + "required": [ + "name", + "_links", + "definition" + ] + }, + "PipelinesResponse": { + "description": "Список пайплайнов", + "type": "object", + "properties": { + "_links": { + "description": "Ссылки на связанные ресурсы", + "type": "object", + "properties": { + "self": { + "$ref": "#/components/schemas/Link" + }, + "next": { + "$ref": "#/components/schemas/Link" + } + } + }, + "remaining_item_count": { + "description": "Оставшееся число элементов перед курсором", + "type": "integer" + }, + "_embedded": { + "type": "object", + "properties": { + "pipelines": { + "description": "Список пайплайнов", + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "description": "Имя пайплайна", + "type": "string" + }, + "_links": { + "description": "Ссылки на связанные ресурсы", + "type": "object", + "properties": { + "self": { + "$ref": "#/components/schemas/Link" + }, + "trials": { + "$ref": "#/components/schemas/Link" + }, + "version": { + "$ref": "#/components/schemas/Link" + } + } + } + } + } + } + }, + "required": [ + "pipelines" + ] + } + }, + "required": [ + "_links", + "remaining_item_count", + "_embedded" + ] + }, + "PipelineVersionResponse": { + "description": "Версия пайплайна ExperimentPipeline", + "type": "object", + "properties": { + "openapi_spec": { + "description": "OpenAPI спецификация API для запуска пайплайна и получения информации о пайплайне", + "type": "object" + }, + "license": { + "description": "Адрес для получения текста лицензии по использованию пайплайна", + "type": "string" + }, + "pipeline_version": { + "description": "Версия пайплайна", + "type": "string" + } + }, + "required": [ + "openapi_spec", + "license", + "pipeline_version" + ] + }, + "ErrorResponse": { + "description": "Объект с результатом операции, которая не завершилась успешно", + "type": "object", + "properties": { + "errors": { + "description": "Список ошибок", + "type": "array", + "items": { + "description": "Ошибка при выполнении операции инференса", + "type": "object", + "properties": { + "type": { + "description": "Тип ошибки", + "type": "string" + }, + "message": { + "description": "Сообщение с описанием ошибки", + "type": "string" + } + }, + "required": [ + "type", + "message" + ] + }, + "maxItems": 10 + } + } + } + }, + "headers": { + "request_id": { + "description": "Идентификатор для диагностики запроса", + "schema": { + "type": "string", + "format": "uuid" + }, + "examples": { + "example": { + "summary": "Идентификатор из нулей", + "value": "00000000-0000-0000-0000-000000000000" + } + } + } + }, + "responses": { + "trial": { + "description": "Операция получения запуска успешно завершена", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TrialResponse" + }, + "examples": { + "simple": { + "summary": "Запуск пайплайна с одним этапом", + "description": "Запуск пайплайна с одной входной и одной выходной переменными", + "value": { + "app_name": "app", + "user_id": "1-2-3", + "tracking_id": "x-y-z", + "pipeline_name": "pipeline", + "pipeline_version": "456", + "vars": { + "inputs": [ + { + "name": "input_var1", + "box_name": "box", + "data": "inputs/input.csv" + } + ], + "outputs": [ + { + "name": "output_var2", + "box_name": "box", + "data": "outputs/stage1/" + } + ] + }, + "status": { + "conditions": [], + "status_date_time": "2024-01-01T02:00:00.000000" + } + } + }, + "error": { + "summary": "Ошибка", + "description": "Ошибка", + "value": { + "errors": [ + { + "type": "Доступ запрещен", + "message": "Реквизиты не предоставлены" + }, + { + "type": "Ресурс не найден", + "message": "Указанная локация отсутствует" + } + ] + } + } + } + } + }, + "headers": { + "X-Request-Id": { + "$ref": "#/components/headers/request_id" + } + } + } + }, + "securitySchemes": { + "basic_auth": { + "description": "Базовая аутентификация", + "type": "http", + "scheme": "basic" + } + } + } +} \ No newline at end of file diff --git a/controller/src/exp_pipeline/api/openapi.yaml b/controller/src/exp_pipeline/api/openapi.yaml new file mode 100644 index 0000000..67c08f7 --- /dev/null +++ b/controller/src/exp_pipeline/api/openapi.yaml @@ -0,0 +1,1256 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: ExperimentPipeline +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +openapi: 3.1.0 +info: + title: Experiment Pipeline - OpenAPI 3.1 + description: Спецификция сервиса Pipelines + termsOfService: https://mlops.hse.ru/ + contact: + email: support-mlops@hse.ru + version: 1.0.0 +servers: + - url: http://localhost:8001 +tags: + - name: pipelines + description: Операции с пайплайнами + externalDocs: + description: Подробнее + url: https://mlops.hse.ru/ + - name: trials + description: Операции с запусками пайплайнов + externalDocs: + description: Подробнее + url: https://mlops.hse.ru/ +security: + - basic_auth: [] +paths: + /{app}/trials/{tracking_id}: + parameters: + - name: X-Request-Id + in: header + schema: + $ref: '#/components/headers/request_id' + description: Идентификатор для диагностики запроса + examples: + example: + summary: Идентификатор из нулей + description: Идентификатор в формате UUID + value: 00000000-0000-0000-0000-000000000000 + - name: app + in: path + required: true + schema: + type: string + description: Имя приложения PlatformApp + - name: tracking_id + in: path + required: true + schema: + type: string + description: Идентификатор отслеживания запуска пайплайна + get: + tags: + - trials + summary: Получить запуск пайплайна + description: >- + Возвращает запуск пайплайна, включая текущий статус и значения входных и выходных + переменных этапов. + operationId: get_trial + responses: + '200': + $ref: '#/components/responses/trial' + '401': + description: Аутентификация не пройдена + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + headers: + X-Request-Id: + $ref: '#/components/headers/request_id' + '404': + description: | + Не найден запрошенный ресурс. + Возможные причины: + - Указанный запуск пайплайна не существует; + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + headers: + X-Request-Id: + $ref: '#/components/headers/request_id' + default: + $ref: '#/components/responses/trial' + /{app}/pipelines/{pipeline}/trials: + parameters: + - name: X-Request-Id + in: header + schema: + $ref: '#/components/headers/request_id' + description: Идентификатор для диагностики запроса + examples: + example: + summary: Идентификатор из нулей + description: Идентификатор в формате UUID + value: 00000000-0000-0000-0000-000000000000 + - name: app + in: path + required: true + schema: + type: string + description: Имя приложения PlatformApp + - name: pipeline + in: path + required: true + schema: + type: string + description: Имя пайплайна ExperimentPipeline + get: + tags: + - trials + - pipelines + summary: Получить запуски пайплайна + description: >- + Возвращает запуски пайплайна. Для каждого запуска возвращает текущий + статус и значения входных и выходных переменных этапов + operationId: get_pipeline_trials + responses: + '200': + description: Операция завершена успешно + content: + application/json: + schema: + $ref: '#/components/schemas/TrialsResponse' + headers: + X-Request-Id: + $ref: '#/components/headers/request_id' + '401': + description: Аутентификация не пройдена + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + headers: + X-Request-Id: + $ref: '#/components/headers/request_id' + '404': + description: | + Не найден запрошенный ресурс. + Возможные причины: + - Указанный пайплайн не существует; + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + headers: + X-Request-Id: + $ref: '#/components/headers/request_id' + default: + description: Операция завершена успешно + content: + application/json: + schema: + $ref: '#/components/schemas/TrialsResponse' + headers: + X-Request-Id: + $ref: '#/components/headers/request_id' + post: + tags: + - trials + summary: Запустить пайплайн + description: >- + Запускает выполнение пайплайна, при этом создается объект, который + содержит информацию о запуске и ходе выполнения + operationId: post_trial + requestBody: + description: Тело запроса + content: + application/json: + schema: + $ref: '#/components/schemas/CreateTrialRequest' + examples: + simple: + summary: Запуск простого пайплайна + description: >- + Запуск пайплайна с одной входной и одной выходной + переменной + value: + inputs: + - name: input1 + data: '[1.0, 2.0, 3.0, 4.0]' + datatype: FP32 + shape: + - 1 + - 4 + output_vars: + - name: output1 + data: outputs/ + required: true + responses: + '201': + $ref: '#/components/responses/trial' + '401': + description: Аутентификация не пройдена + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + headers: + X-Request-Id: + $ref: '#/components/headers/request_id' + '404': + description: | + Ошибка входных данных. + Возможные причины: + - Указанный пайплайн не существует; + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + headers: + X-Request-Id: + $ref: '#/components/headers/request_id' + '503': + description: | + Сервис недоступен. + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + headers: + X-Request-Id: + $ref: '#/components/headers/request_id' + default: + $ref: '#/components/responses/trial' + /{app}/trials: + parameters: + - name: X-Request-Id + in: header + schema: + $ref: '#/components/headers/request_id' + description: Идентификатор для диагностики запроса + examples: + example: + summary: Идентификатор из нулей + description: Идентификатор в формате UUID + value: 00000000-0000-0000-0000-000000000000 + - name: app + in: path + required: true + schema: + type: string + description: Имя приложения PlatformApp + get: + tags: + - trials + summary: Получить все запуски пайплайна пользователя + description: >- + Возвращает запуски пайплайна. Для каждого запуска возвращает текущий + статус и значения входных и выходных переменных этапов + operationId: get_trials + responses: + '200': + description: Операция завершена успешно + content: + application/json: + schema: + $ref: '#/components/schemas/TrialsResponse' + headers: + X-Request-Id: + $ref: '#/components/headers/request_id' + '401': + description: Аутентификация не пройдена + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + headers: + X-Request-Id: + $ref: '#/components/headers/request_id' + default: + description: Операция завершена успешно + content: + application/json: + schema: + $ref: '#/components/schemas/TrialsResponse' + headers: + X-Request-Id: + $ref: '#/components/headers/request_id' + /{app}/pipelines/{pipeline}/trials/continue: + parameters: + - name: X-Request-Id + in: header + schema: + $ref: '#/components/headers/request_id' + description: Идентификатор для диагностики запроса + examples: + example: + summary: Идентификатор из нулей + description: Идентификатор в формате UUID + value: 00000000-0000-0000-0000-000000000000 + - name: app + in: path + required: true + schema: + type: string + description: Имя приложения PlatformApp + - name: pipeline + in: path + required: true + schema: + type: string + description: Имя пайплайна предшествующего запуска + - name: tracking_id + in: query + required: true + schema: + type: string + description: Идентификатор отслеживания предшествующего + запуска + - name: next_pipeline_name + in: query + required: true + schema: + type: string + description: Имя пайплайна, который нужно запустить + post: + tags: + - trials + summary: Запустить следующий пайплайн + description: >- + Запускает выполнение пайплайна, при этом создается объект, который + содержит информацию о запуске и ходе выполнения + operationId: post_trial_continue + requestBody: + description: Тело запроса + content: + application/json: + schema: + $ref: '#/components/schemas/CreateTrialRequest' + required: true + responses: + '201': + $ref: '#/components/responses/trial' + '401': + description: Аутентификация не пройдена + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + headers: + X-Request-Id: + $ref: '#/components/headers/request_id' + '404': + description: | + Ошибка входных данных. + Возможные причины: + - Указанный пайплайн не существует; + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + headers: + X-Request-Id: + $ref: '#/components/headers/request_id' + default: + $ref: '#/components/responses/trial' + /{app}/pipelines: + parameters: + - name: X-Request-Id + in: header + schema: + $ref: '#/components/headers/request_id' + description: Идентификатор для диагностики запроса + examples: + example: + summary: Идентификатор из нулей + description: Идентификатор в формате UUID + value: 00000000-0000-0000-0000-000000000000 + - name: app + in: path + required: true + schema: + type: string + description: Имя приложения PlatformApp + get: + tags: + - pipelines + summary: Получить доступные пайплайны приложения + description: Возвращает пайплайны приложения, которые можно выполнить + operationId: get_pipelines + responses: + '200': + description: Операция завершена успешно + content: + application/json: + schema: + $ref: '#/components/schemas/PipelinesResponse' + headers: + X-Request-Id: + $ref: '#/components/headers/request_id' + '401': + description: Аутентификация не пройдена + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + headers: + X-Request-Id: + $ref: '#/components/headers/request_id' + '410': + description: | + Ресурс устарел. + Возможные причины: + - Устарел курсор; + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + headers: + X-Request-Id: + $ref: '#/components/headers/request_id' + default: + description: Операция завершена успешно + content: + application/json: + schema: + $ref: '#/components/schemas/PipelinesResponse' + headers: + X-Request-Id: + $ref: '#/components/headers/request_id' + /{app}/pipelines/{pipeline}: + parameters: + - name: X-Request-Id + in: header + schema: + $ref: '#/components/headers/request_id' + description: Идентификатор для диагностики запроса + examples: + example: + summary: Идентификатор из нулей + description: Идентификатор в формате UUID + value: 00000000-0000-0000-0000-000000000000 + - name: app + in: path + required: true + schema: + type: string + description: Имя приложения PlatformApp + - name: pipeline + in: path + required: true + schema: + type: string + description: Имя пайплайна ExperimentPipeline + get: + tags: + - pipelines + summary: Получить пайплайн + description: >- + Возвращает информацию о пайплайне. + operationId: get_pipeline + responses: + '200': + description: Операция завершена успешно + content: + application/json: + schema: + $ref: '#/components/schemas/PipelineResponse' + headers: + X-Request-Id: + $ref: '#/components/headers/request_id' + '401': + description: Аутентификация не пройдена + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + headers: + X-Request-Id: + $ref: '#/components/headers/request_id' + '404': + description: | + Не найден запрошенный ресурс. + Возможные причины: + - Указанный пайплайн не существует; + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + headers: + X-Request-Id: + $ref: '#/components/headers/request_id' + default: + description: Операция завершена успешно + content: + application/json: + schema: + $ref: '#/components/schemas/PipelineResponse' + headers: + X-Request-Id: + $ref: '#/components/headers/request_id' + /{app}/pipelines/{pipeline}/trials/{tracking_id}/status/conditions: + parameters: + - name: X-Request-Id + in: header + schema: + $ref: '#/components/headers/request_id' + description: Идентификатор для диагностики запроса + examples: + example: + summary: Идентификатор из нулей + description: Идентификатор в формате UUID + value: 00000000-0000-0000-0000-000000000000 + - name: app + in: path + required: true + schema: + type: string + description: Имя приложения PlatformApp + - name: pipeline + in: path + required: true + schema: + type: string + description: Имя пайплайна + - name: tracking_id + in: path + required: true + schema: + type: string + description: Идентификатор отслеживания запуска пайплайна + post: + tags: + - trials + summary: Добавить условие в статус запуска пайплайна + description: Добавляет условие в статус запуска пайплайна. + Если условие с таким типом уже существует в статусе, то оно не добавляется. + operationId: post_trial_status_condition + requestBody: + description: Тело запроса + content: + application/json: + schema: + $ref: '#/components/schemas/CreateStatusConditionRequest' + required: true + responses: + '200': + description: Операция завершена успешно + content: + application/json: + schema: + $ref: '#/components/schemas/EmptyResponse' + headers: + X-Request-Id: + $ref: '#/components/headers/request_id' + '204': + description: Статус не изменен + content: + application/json: + schema: + $ref: '#/components/schemas/EmptyResponse' + headers: + X-Request-Id: + $ref: '#/components/headers/request_id' + '401': + description: Аутентификация не пройдена + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + headers: + X-Request-Id: + $ref: '#/components/headers/request_id' + '404': + description: | + Не найден запрошенный ресурс. + Возможные причины: + - Указанный запуск не существует; + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + headers: + X-Request-Id: + $ref: '#/components/headers/request_id' + default: + description: Операция завершена успешно + content: + application/json: + schema: + $ref: '#/components/schemas/EmptyResponse' + headers: + X-Request-Id: + $ref: '#/components/headers/request_id' + /{app}/pipelines/{pipeline}/version: + parameters: + - name: X-Request-Id + in: header + schema: + $ref: '#/components/headers/request_id' + description: Идентификатор для диагностики запроса + examples: + example: + summary: Идентификатор из нулей + description: Идентификатор в формате UUID + value: 00000000-0000-0000-0000-000000000000 + - name: app + in: path + required: true + schema: + type: string + description: Имя приложения PlatformApp + - name: pipeline + in: path + required: true + schema: + type: string + description: Имя пайплайна ExperimentPipeline + get: + tags: + - pipelines + summary: Получить версию пайплайна + description: >- + Возвращает версию пайплайна, что включает OpenAPI спецификацию для запуска пайплайна, + версию и лицензию по использованию пайплайна. + operationId: get_pipeline_version + responses: + '200': + description: Операция завершена успешно + content: + application/json: + schema: + $ref: '#/components/schemas/PipelineVersionResponse' + headers: + X-Request-Id: + $ref: '#/components/headers/request_id' + '401': + description: Аутентификация не пройдена + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + headers: + X-Request-Id: + $ref: '#/components/headers/request_id' + '404': + description: | + Не найден запрошенный ресурс. + Возможные причины: + - Указанный пайплайн не существует; + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + headers: + X-Request-Id: + $ref: '#/components/headers/request_id' + default: + description: Операция завершена успешно + content: + application/json: + schema: + $ref: '#/components/schemas/PipelineVersionResponse' + headers: + X-Request-Id: + $ref: '#/components/headers/request_id' + /{app}/pipelines/{pipeline}/check: + parameters: + - name: app + in: path + required: true + schema: + type: string + description: Имя приложения PlatformApp + - name: pipeline + in: path + required: true + schema: + type: string + description: Имя пайплайна ExperimentPipeline + get: + tags: + - pipelines + summary: Проверить наличие доступа + description: >- + Используется для проверки доступа контейнеров + пользователей к API Pipelines. + operationId: get_pipeline_check + responses: + '200': + description: Операция завершена успешно + content: + application/json: + schema: + $ref: '#/components/schemas/EmptyResponse' + '401': + description: Аутентификация не пройдена + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Доступ запрещен + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + default: + description: Операция завершена успешно + content: + application/json: + schema: + $ref: '#/components/schemas/EmptyResponse' +components: + schemas: + Link: + description: Ссылка на ресурс + type: object + properties: + href: + type: string + templated: + type: boolean + required: [ "href" ] + EmptyResponse: + description: Пустой ответ + type: object + properties: + additional_info: + type: object + additionalProperties: false + minProperties: 0 + maxProperties: 0 + TrialResponse: + description: Запуск пайплайна + type: object + properties: + app_name: + description: Имя приложения PlatformApp + type: string + user_id: + description: Идентификатор пользователя, который запустил пайплайн + type: string + tracking_id: + description: Идентификатор отслеживания запуска + type: string + pipeline_name: + description: Имя пайплайна ExperimentPipeline + type: string + pipeline_version: + description: Версия ресурса ExperimentPipeline, используемая для запуска + type: string + next_tracking_id: + description: Идентификатор отслеживания запуска следующего пайплайна + type: string + next_pipeline_name: + description: Имя следующего пайплайна ExperimentPipeline + type: string + vars: + description: Значения входных и выходных переменные + запуска. + type: object + properties: + inputs: + description: >- + Значения входных переменных. В списке содержатся только те + входные переменные, значения для которых передаются и были переданы + при запуске пайплайна. + + Входные переменные, ассоциированные в спецификации пайплайна с + данными в ящиках, не содержатся в списке. + type: array + items: + type: object + properties: + name: + description: Имя входной переменной + type: string + box_name: + description: Имя ассоциированного ящика DataBox + type: string + data: + description: |- + Значение входной переменной. + + Локация в сервисе Files, по которой можно получить значение входной переменной. + Может указывать как на файл, так и на файловую группу. + + Если при запуске пайплайна входное значение было + передано с datatype не из {'FILE', 'WEBSITE'}, то значением атрибута + является локация созданного файла, в который записано + переданное значение. + type: string + datatype: + description: Тип значения входной переменной + type: string + enum: + - FILE + - FP32 + - FP64 + - INT32 + - str + - dict + - WEBSITE + content_type: + type: string + description: |- + Тип содержимого файла или файлов входной переменной. + + Если при запуске пайплайна входное значение было + передано с datatype != 'FILE', то тип содержимого файла, в который сохранено переданное значение, соответствует установленному предопределенному типу для этого datatype. + required: + - name + - box_name + - data + - datatype + - content_type + outputs: + description: >- + Значения выходных переменных. В списке содержатся только те выходные переменные, параметры которых были переданы при запуске пайплайна. + type: array + items: + type: object + properties: + name: + description: Имя выходной переменной + type: string + box_name: + description: Имя ассоциированного ящика DataBox + type: string + data: + description: >- + Имя ассоциированной локации в сервисе Files. Локация соответствует файловой группе. Если запуск еще не завершен, то результаты в файловой группе будут отсутствовать. + type: string + datatype: + description: Тип значения выходной переменной + type: string + enum: + - FILE + - WEBSITE + content_type: + description: |- + Тип содержимого файла или файлов выходной переменной. + Тип содержимого определяется в атрибутах content_type объектов списка output_vars, переданных при запуске пайплайна. + type: string + required: + - name + - box_name + - data + status: + $ref: '#/components/schemas/TrialStatus' + _links: + description: Ссылки на связанные ресурсы + type: object + properties: + self: + $ref: '#/components/schemas/Link' + pipeline: + $ref: '#/components/schemas/Link' + required: + - app_name + - user_id + - tracking_id + - pipeline_name + - pipeline_version + - status + - _links + EmbeddedTrial: + description: Краткое представление запуска пайплайна + type: object + properties: + app_name: + description: Имя приложения PlatformApp + type: string + user_id: + description: Идентификатор пользователя, который запустил пайплайн + type: string + tracking_id: + description: Идентификатор отслеживания запуска + type: string + pipeline_name: + description: Имя пайплайна ExperimentPipeline + type: string + pipeline_version: + description: Версия ресурса ExperimentPipeline, используемая для запуска + type: string + next_tracking_id: + description: Идентификатор отслеживания запуска следующего пайплайна + type: string + next_pipeline_name: + description: Имя следующего пайплайна ExperimentPipeline + type: string + status: + $ref: '#/components/schemas/TrialStatus' + _links: + description: Ссылки на связанные ресурсы + type: object + properties: + self: + $ref: '#/components/schemas/Link' + pipeline: + $ref: '#/components/schemas/Link' + required: + - app_name + - user_id + - tracking_id + - pipeline_name + - pipeline_version + - status + - _links + TrialStatus: + description: Статус запуска пайплайна + type: object + properties: + status_date_time: + description: Время последнего изменения статуса в формате ISO + type: string + conditions: + description: Список условий, составляющих статус запуска + type: array + items: + type: object + properties: + type: + description: Тип условия + type: string + condition_status: + description: Статус условия + type: string + enum: + - 'True' + - 'False' + - Unknown + last_transition_time: + description: Время последнего изменения статуса условия в формате ISO + type: string + message: + description: Подробное описание условия, понятное человеку + type: string + reason: + description: >- + Содержит программный идентификатор, являющийся индикатором + причины последнего изменения статуса условия + type: string + required: + - type + - condition_status + - last_transition_time + - message + - reason + required: + - status_date_time + CreateStatusConditionRequest: + description: Запрос добавления условия в статус запуска + пайплайна + type: object + properties: + type: + description: Тип условия + type: string + message: + description: Подробное описание условия, понятное человеку + type: string + reason: + description: >- + Содержит программный идентификатор, являющийся индикатором + причины последнего изменения статуса условия + type: string + required: ["type"] + TrialsResponse: + description: Список запусков пайплайнов + type: object + properties: + _links: + description: Ссылки на связанные ресурсы + type: object + properties: + self: + $ref: '#/components/schemas/Link' + next: + $ref: '#/components/schemas/Link' + remaining_item_count: + description: Оставшееся число элементов перед курсором + type: integer + total_item_count: + description: Общее число элементов + type: integer + _embedded: + type: object + properties: + trials: + description: Список запусков + type: array + items: + $ref: '#/components/schemas/EmbeddedTrial' + required: ["trials"] + required: ["_links", "_embedded", "remaining_item_count", "total_item_count"] + CreateTrialRequest: + description: Запрос запуска пайплайна + type: object + properties: + inputs: + description: |- + Список значений входных переменных. + + Если значение входной переменной не задано, + то оно не будет передано в пайплайн, + и переменная не будет сохранена в запуске пайплайна. + type: array + items: + type: object + properties: + name: + description: Имя входной переменной + type: string + data: + description: |- + Значение входной переменной. + + Если datatype из {'FILE', 'WEBSITE'}, то содержит локацию в сервисе Files, + по которой можно получить значение входной переменной. + Может указывать как на файл, так и на файловую группу. + + Если datatype не из {'FILE', 'WEBSITE'}, то содержит строку с сериализованным + значением входной переменной, которое будет сохранено в файл. + + Для каждого datatype != 'FILE' для файла, + в который сохраняется значение переменной, + установлен предопределенный тип содержимого (content_type). + type: object + datatype: + description: Тип значения входной переменной + type: string + enum: + - FILE + - FP32 + - FP64 + - INT32 + - str + - dict + - WEBSITE + content_type: + description: |- + Тип содержимого файла или файлов, при типе входной переменной + datatype == \"FILE\". Тип содержимого файла должен быть задан + при запуске пайплайна. + + При типе входной переменной datatype != \"FILE\" переданный тип содержимого + файла игнорируется. Для каждого datatype установлен предопределенный тип содержимого. + type: string + shape: + description: >- + Размерность, как массива, значения входной переменной. + Применимо к любым типам данных входной переменной. + oneOf: + - type: integer + - type: array + items: + type: integer + minItems: 1 + maxItems: 32 + required: + - name + - data + - datatype + - shape + output_vars: + type: array + description: |- + Список параметров для выходных переменных. + + Если параметры выходной переменной не заданы, + то они не будет переданы в пайплайн, + пайплайн не вычислит значений выходной переменной, + и переменная не будет сохранена в запуске пайплайна. + items: + description: Параметры выходной переменной + type: object + properties: + name: + description: Имя выходной переменной + type: string + data: + description: |- + Локация выходной переменной в сервисе Files. + + Указывает, куда должны быть сохранены значения выходной + переменной. Должна соответствовать файловой группе. + + Может быть не указана, тогда будет создана файловая группа со + сгенерированным именем. + type: string + datatype: + description: Тип значения выходной переменной + type: string + enum: + - FILE + - WEBSITE + content_type: + type: string + description: >- + Ожидаемый тип содержимого файла или файлов выходной + переменной. + required: + - name + PipelineResponse: + description: Пайплайн ExperimentPipeline + type: object + properties: + name: + description: Имя пайплайна + type: string + _links: + description: Ссылки на связанные ресурсы + type: object + properties: + self: + $ref: '#/components/schemas/Link' + trials: + $ref: '#/components/schemas/Link' + version: + $ref: '#/components/schemas/Link' + definition: + description: Спецификация пайплайна в формате JSON + type: object + required: + - name + - _links + - definition + PipelinesResponse: + description: Список пайплайнов + type: object + properties: + _links: + description: Ссылки на связанные ресурсы + type: object + properties: + self: + $ref: '#/components/schemas/Link' + next: + $ref: '#/components/schemas/Link' + remaining_item_count: + description: Оставшееся число элементов перед курсором + type: integer + _embedded: + type: object + properties: + pipelines: + description: Список пайплайнов + type: array + items: + type: object + properties: + name: + description: Имя пайплайна + type: string + _links: + description: Ссылки на связанные ресурсы + type: object + properties: + self: + $ref: '#/components/schemas/Link' + trials: + $ref: '#/components/schemas/Link' + version: + $ref: '#/components/schemas/Link' + required: ["pipelines"] + required: ["_links", "remaining_item_count", "_embedded"] + PipelineVersionResponse: + description: Версия пайплайна ExperimentPipeline + type: object + properties: + openapi_spec: + description: OpenAPI спецификация API для запуска пайплайна и получения информации о пайплайне + type: object + license: + description: Адрес для получения текста лицензии по использованию пайплайна + type: string + pipeline_version: + description: Версия пайплайна + type: string + required: ["openapi_spec", "license", "pipeline_version"] + ErrorResponse: + description: Объект с результатом операции, которая не завершилась успешно + type: object + properties: + errors: + description: Список ошибок + type: array + items: + description: Ошибка при выполнении операции инференса + type: object + properties: + type: + description: Тип ошибки + type: string + message: + description: Сообщение с описанием ошибки + type: string + required: + - type + - message + maxItems: 10 + headers: + request_id: + description: Идентификатор для диагностики запроса + schema: + type: string + format: uuid + examples: + example: + summary: Идентификатор из нулей + value: 00000000-0000-0000-0000-000000000000 + responses: + trial: + description: Операция получения запуска успешно завершена + content: + application/json: + schema: + $ref: '#/components/schemas/TrialResponse' + examples: + simple: + summary: Запуск пайплайна с одним этапом + description: >- + Запуск пайплайна с одной входной и одной выходной + переменными + value: + app_name: app + user_id: 1-2-3 + tracking_id: x-y-z + pipeline_name: pipeline + pipeline_version: '456' + vars: + inputs: + - name: input_var1 + box_name: box + data: inputs/input.csv + outputs: + - name: output_var2 + box_name: box + data: outputs/stage1/ + status: + conditions: [] + status_date_time: '2024-01-01T02:00:00.000000' + error: + summary: Ошибка + description: Ошибка + value: + errors: + - type: Доступ запрещен + message: Реквизиты не предоставлены + - type: Ресурс не найден + message: Указанная локация отсутствует + headers: + X-Request-Id: + $ref: '#/components/headers/request_id' + securitySchemes: + basic_auth: + description: Базовая аутентификация + type: http + scheme: basic diff --git a/controller/src/exp_pipeline/api/to-openapi-base.md b/controller/src/exp_pipeline/api/to-openapi-base.md new file mode 100644 index 0000000..6624831 --- /dev/null +++ b/controller/src/exp_pipeline/api/to-openapi-base.md @@ -0,0 +1,52 @@ +# Инструкция по созданию базовой OpenAPI спецификации + +Базовая спецификация используется для генерации OpenAPI спецификации для конкретных пайплайнов. + +**Удаление секций "examples" рекурсивно** + +```jq +walk(if type == "object" and has("examples") then del(.examples) else . end) +``` + +**Удалить все примеры (атрибуты examples)** + +```shell +cat openapi-base.json | jq 'walk(if type == "object" and has("examples") then del(.examples) else . end)' > openapi-base-fixed.json +``` + +**Удалить все, что связано с X-Request-Id (все headers, пока X-Request-Id является единственным заголовком)** + +Удалить атрибуты headers: + +```shell +cat openapi-base-fixed.json | jq 'walk(if type == "object" and has("headers") then del(.headers) else . end)' > openapi-base-fixed.json +``` + +Удалить X-Request-Id из параметров: + +```shell +cat openapi-base-fixed.json | jq 'walk(if type=="object" and .name == "X-Request-Id" then empty else . end)' > openapi-base-fixed.json +``` + +**Удалить непубличные пути** + +```shell +cat openapi-base-fixed.json | jq 'del(.paths/"/{app}/pipelines/{pipeline}/trials/continue")' > openapi-base-fixed.json +cat openapi-base-fixed.json | jq 'del(.paths/"/{app}/pipelines/{pipeline}/check")' > openapi-base-fixed.json +cat openapi-base-fixed.json | jq 'del(.paths/"/{app}/pipelines/{pipeline}/trials/{tracking_id}/status/conditions")' > openapi-base-fixed.json +cat openapi-base-fixed.json | jq 'del(.components/schemas/CreateStatusConditionRequest)' > openapi-base-fixed.json +``` + +Команды вместе: + +```shell +jq 'walk(if type == "object" and has("examples") then del(.examples) else . end) | + walk(if type == "object" and has("headers") then del(.headers) else . end) | + walk(if type == "object" and .name == "X-Request-Id" then empty else . end) | + del(.paths."/{app}/pipelines/{pipeline}/trials/continue") | + del(.paths."/{app}/pipelines/{pipeline}/check") | + del(.paths."/{app}/pipelines/{pipeline}/trials/{tracking_id}/status/conditions") | + del(.components.schemas.CreateStatusConditionRequest) + ' openapi-base.json \ + > openapi-base-fixed.json +``` \ No newline at end of file diff --git a/controller/src/exp_pipeline/box.py b/controller/src/exp_pipeline/box.py new file mode 100644 index 0000000..f02978c --- /dev/null +++ b/controller/src/exp_pipeline/box.py @@ -0,0 +1,98 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: ExperimentPipeline +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +import logging +import posixpath +from uuid import UUID + +from fastapi import HTTPException +from kubernetes_asyncio.client import CustomObjectsApi, ApiException, ApiClient + +from exp_pipeline.schema import ConnectedBox + +logger = logging.getLogger(__name__) + + +async def _get_s3_box_resource(api_client: ApiClient, s3_box_name, namespace): + co_api = CustomObjectsApi(api_client) + try: + # метод get_namespaced_custom_object возвращает объект, а не сопрограмму + s3_box_res, _, _ = await co_api.get_namespaced_custom_object_with_http_info( + "unified-platform.cs.hse.ru", "v1", namespace, + "databoxes", s3_box_name) + except ApiException as exc: + if exc.status == 404: + logger.error(f'Box {s3_box_name} not found in namespace {namespace}') + raise HTTPException(status_code=503, detail="Service unavailable") + raise exc + + if 's3Storage' not in s3_box_res['status']: + logger.error(f'Box {s3_box_name} in namespace {namespace} doesnt have status') + raise HTTPException(status_code=500, detail='Internal server error') + + return s3_box_res + + +async def _get_s3_box_attrs(api_client: ApiClient, s3_box_name, namespace): + s3_box_res = await _get_s3_box_resource(api_client, s3_box_name, namespace) + + s3_box_uid = UUID(s3_box_res['metadata']['uid']) + + s3_storage_status = s3_box_res['status']['s3Storage'] + if ('csiS3PersistentVolumeClaimName' not in s3_storage_status) \ + or (not s3_storage_status['csiS3PersistentVolumeClaimName']): + logger.error(f'Box {s3_box_name} in namespace {namespace} ' + f'csiS3PersistentVolumeClaimName not set') + raise HTTPException(status_code=500, detail='Internal server error') + + return s3_box_uid, s3_storage_status['csiS3PersistentVolumeClaimName'] + + +async def construct_connected_box(api_client: ApiClient, connected_box_section: dict, + namespace: str) -> ConnectedBox: + connected_box_name = connected_box_section['name'] + if 'mountS3Box' in connected_box_section: + mount_s3_box = connected_box_section['mountS3Box'] + box_name = mount_s3_box['s3BoxName'] + s3_box_name, dataset_ref_box_name = box_name, None + elif 'mountDataset' in connected_box_section: + mount_dataset = connected_box_section['mountDataset'] + box_name = mount_dataset['datasetReferenceName'] + s3_box_name, dataset_ref_box_name = None, box_name + else: + logger.error(f'Connected box {connected_box_name} may be mountS3Box or mountDataset') + raise HTTPException(status_code=503, detail='Service unavailable') + mode = 'mount' + _, pvc_name = await _get_s3_box_attrs(api_client, box_name, namespace) + cb = ConnectedBox(name=connected_box_name, + mode=mode, + s3_box_name=s3_box_name, + dataset_ref_box_name=dataset_ref_box_name, + pvc_name=pvc_name) + if 'path' in connected_box_section: + cb.mount_path = connected_box_section['path'] + if 'default' in connected_box_section and 'mountS3Box' in connected_box_section: + cb.default = bool(connected_box_section['default']) + return cb + + +def get_default_box(user_id: str, + pipeline_name: str, + connected_boxes: list[ConnectedBox] + ) -> ConnectedBox: + if not connected_boxes: + logger.error(f'No connected boxes specified for pipeline {pipeline_name}, but at least one required') + raise HTTPException(status_code=503, detail="Service unavailable") + + for cb in connected_boxes: + if cb.default: + return cb + # todo: возможно, следует проверять, что это не mountDataset + return connected_boxes[0] + + +def get_path_inside_box(user_id, location): + return posixpath.join('users', user_id, 'file_groups', location) diff --git a/controller/src/exp_pipeline/client_config.py b/controller/src/exp_pipeline/client_config.py new file mode 100644 index 0000000..26a0078 --- /dev/null +++ b/controller/src/exp_pipeline/client_config.py @@ -0,0 +1,21 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: ExperimentPipeline +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +import os + +APP_NAME_VAR_NAME = 'UNIP_PIPELINE_APP_NAME' +UNIP_PIPELINE_APP_NAME = os.getenv(APP_NAME_VAR_NAME) + +PIPELINE_VAR_NAME = 'UNIP_PIPELINE_PIPELINE_NAME' +UNIP_PIPELINE_PIPELINE_NAME = os.getenv(PIPELINE_VAR_NAME) + +API_VAR_NAME = 'UNIP_PIPELINE_API' +UNIP_PIPELINE_API = os.getenv(API_VAR_NAME) + +TRACKING_ID_VAR_NAME = 'UNIP_TRACKING_ID' +UNIP_TRACKING_ID = os.getenv(TRACKING_ID_VAR_NAME) + +INTERNAL_API_USER_ID = 'platform-user' \ No newline at end of file diff --git a/controller/src/exp_pipeline/config.py b/controller/src/exp_pipeline/config.py new file mode 100644 index 0000000..d52d857 --- /dev/null +++ b/controller/src/exp_pipeline/config.py @@ -0,0 +1,19 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: ExperimentPipeline +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +import os + +UNIP_PIPELINE_RUN_MODE = os.getenv('UNIP_PIPELINE_RUN_MODE') + +UNIP_FILES_API = os.getenv('UNIP_FILES_API') + +UNIP_PIPELINES_API = os.getenv('UNIP_PIPELINES_API') + +UNIP_DATETIME_FORMAT = os.getenv('UNIP_DATETIME_FORMAT', '%Y-%m-%dT%H:%M:%S.%f%z') + +UNIP_PIPELINE_VALIDATION_IMAGE = os.getenv('UNIP_PIPELINE_VALIDATION_IMAGE') + + diff --git a/controller/src/exp_pipeline/handlers.py b/controller/src/exp_pipeline/handlers.py new file mode 100644 index 0000000..2a36d16 --- /dev/null +++ b/controller/src/exp_pipeline/handlers.py @@ -0,0 +1,57 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: ExperimentPipeline +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ + +import kopf + +from bound import not_dev_namespace +from exp_pipeline.pipeline import set_trial_failed, \ + set_trial_completed +from exp_pipeline.storage.db import AsyncDbSession +from kopf_k8s_client import async_api_client + +PRIVATE_API_BA_SECRET_NAME_TEMPLATE = 'pipeline-{0}-api-ba-cred' + + +def _job_kind_event_filter(body, **_): return body['involvedObject']['kind'] == 'Job' + + +def _completed_reason_event_filter(body, **_): return body['reason'] == 'Completed' + + +def _backoff_limit_exceeded_reason_event_filter(body, **_): return body['reason'] == 'BackoffLimitExceeded' + + +# @kopf.on.create('v1', 'events', field='involvedObject.kind', value='Job', retries=3) +@kopf.on.create('v1', + 'events', + when=kopf.all_([_job_kind_event_filter, + _completed_reason_event_filter, + not_dev_namespace]), + retries=3) +async def set_trial_completed_on_job_event(body, **_): + job_ref = body['involvedObject'] + job_name = job_ref['name'] + job_namespace = job_ref['namespace'] + + async with AsyncDbSession() as db: + await set_trial_completed(db, async_api_client, job_name, job_namespace) + + +@kopf.on.create('v1', + 'events', + when=kopf.all_([_job_kind_event_filter, + _backoff_limit_exceeded_reason_event_filter, + not_dev_namespace]), + retries=3) +async def set_trial_failed_on_job_event(body, **_): + job_ref = body['involvedObject'] + job_name = job_ref['name'] + job_namespace = job_ref['namespace'] + + async with AsyncDbSession() as db: + await set_trial_failed(db, async_api_client, job_name, job_namespace) + diff --git a/controller/src/exp_pipeline/jinja.py b/controller/src/exp_pipeline/jinja.py new file mode 100644 index 0000000..09482e2 --- /dev/null +++ b/controller/src/exp_pipeline/jinja.py @@ -0,0 +1,20 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: ExperimentPipeline +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +from jinja2 import Environment, FileSystemLoader + +jinja_env = Environment( + loader=FileSystemLoader('templates/experiment-pipeline'), + lstrip_blocks=True, + trim_blocks=True +) + + +basic_jinja_env = Environment( + loader=FileSystemLoader('templates/basic-resources'), + lstrip_blocks=True, + trim_blocks=True +) diff --git a/controller/src/exp_pipeline/logs.py b/controller/src/exp_pipeline/logs.py new file mode 100644 index 0000000..78f9fbe --- /dev/null +++ b/controller/src/exp_pipeline/logs.py @@ -0,0 +1,32 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: ExperimentPipeline +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +from logging.config import dictConfig + + +def configure_logging(): + dictConfig({ + 'version': 1, + 'disable_existing_loggers': False, + 'formatters': { + 'default': { + 'format': '[%(asctime)s] [%(levelname)s] [%(name)s]: %(message)s', + } + }, + 'handlers': { + 'default': { + 'class': 'logging.StreamHandler', + 'stream': 'ext://sys.stdout', + 'formatter': 'default' + } + }, + 'loggers': { + 'root': { + 'level': 'INFO', + 'handlers': ['default'] + } + } + }) diff --git a/controller/src/exp_pipeline/openapi-base.json b/controller/src/exp_pipeline/openapi-base.json new file mode 100644 index 0000000..c5cd461 --- /dev/null +++ b/controller/src/exp_pipeline/openapi-base.json @@ -0,0 +1,1097 @@ +{ + "openapi": "3.1.0", + "info": { + "title": "Experiment Pipeline - OpenAPI 3.1", + "description": "Спецификция сервиса Experiment Pipeline", + "termsOfService": "https://platform-dev-cs-hse.objectoriented.ru/terms/", + "contact": { + "email": "apiteam@platform-dev-cs-hse.objectoriented.ru" + }, + "version": "1.0.0" + }, + "servers": [ + { + "url": "http://localhost:8001" + }, + { + "url": "https://platform-dev-cs-hse.objectoriented.ru/app/pipelines" + } + ], + "tags": [ + { + "name": "pipelines", + "description": "Операции с пайплайнами", + "externalDocs": { + "description": "Подробнее", + "url": "https://platform-dev-cs-hse.objectoriented.ru" + } + }, + { + "name": "trials", + "description": "Операции с запусками пайплайнов", + "externalDocs": { + "description": "Подробнее", + "url": "https://platform-dev-cs-hse.objectoriented.ru" + } + } + ], + "security": [ + { + "basic_auth": [] + } + ], + "paths": { + "/{app}/trials/{tracking_id}": { + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Имя приложения PlatformApp" + }, + { + "name": "tracking_id", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Идентификатор отслеживания запуска пайплайна" + } + ], + "get": { + "tags": [ + "trials" + ], + "summary": "Получить запуск пайплайна", + "description": "Возвращает запуск пайплайна, включая текущий статус и значения входных и выходных переменных этапов.", + "operationId": "get_trial", + "responses": { + "200": { + "$ref": "#/components/responses/trial" + }, + "401": { + "description": "Аутентификация не пройдена", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Не найден запрошенный ресурс.\nВозможные причины: \n- Указанный запуск пайплайна не существует;\n", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "default": { + "$ref": "#/components/responses/trial" + } + } + } + }, + "/{app}/pipelines/{pipeline}/trials": { + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Имя приложения PlatformApp" + }, + { + "name": "pipeline", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Имя пайплайна ExperimentPipeline" + } + ], + "get": { + "tags": [ + "trials", + "pipelines" + ], + "summary": "Получить запуски пайплайна", + "description": "Возвращает запуски пайплайна. Для каждого запуска возвращает текущий статус и значения входных и выходных переменных этапов", + "operationId": "get_pipeline_trials", + "responses": { + "200": { + "description": "Операция завершена успешно", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TrialsResponse" + } + } + } + }, + "401": { + "description": "Аутентификация не пройдена", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Не найден запрошенный ресурс.\nВозможные причины: \n- Указанный пайплайн не существует;\n", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "default": { + "description": "Операция завершена успешно", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TrialsResponse" + } + } + } + } + } + }, + "post": { + "tags": [ + "trials" + ], + "summary": "Запустить пайплайн", + "description": "Запускает выполнение пайплайна, при этом создается объект, который содержит информацию о запуске и ходе выполнения", + "operationId": "post_trial", + "requestBody": { + "description": "Тело запроса", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateTrialRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "$ref": "#/components/responses/trial" + }, + "401": { + "description": "Аутентификация не пройдена", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Ошибка входных данных.\nВозможные причины: \n- Указанный пайплайн не существует;\n", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "503": { + "description": "Сервис недоступен.\n", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "default": { + "$ref": "#/components/responses/trial" + } + } + } + }, + "/{app}/trials": { + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Имя приложения PlatformApp" + } + ], + "get": { + "tags": [ + "trials" + ], + "summary": "Получить все запуски пайплайна пользователя", + "description": "Возвращает запуски пайплайна. Для каждого запуска возвращает текущий статус и значения входных и выходных переменных этапов", + "operationId": "get_trials", + "responses": { + "200": { + "description": "Операция завершена успешно", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TrialsResponse" + } + } + } + }, + "401": { + "description": "Аутентификация не пройдена", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "default": { + "description": "Операция завершена успешно", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TrialsResponse" + } + } + } + } + } + } + }, + "/{app}/pipelines": { + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Имя приложения PlatformApp" + } + ], + "get": { + "tags": [ + "pipelines" + ], + "summary": "Получить доступные пайплайны приложения", + "description": "Возвращает пайплайны приложения, которые можно выполнить", + "operationId": "get_pipelines", + "responses": { + "200": { + "description": "Операция завершена успешно", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PipelinesResponse" + } + } + } + }, + "401": { + "description": "Аутентификация не пройдена", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "410": { + "description": "Ресурс устарел.\nВозможные причины:\n- Устарел курсор;\n", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "default": { + "description": "Операция завершена успешно", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PipelinesResponse" + } + } + } + } + } + } + }, + "/{app}/pipelines/{pipeline}": { + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Имя приложения PlatformApp" + }, + { + "name": "pipeline", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Имя пайплайна ExperimentPipeline" + } + ], + "get": { + "tags": [ + "pipelines" + ], + "summary": "Получить пайплайн", + "description": "Возвращает информацию о пайплайне.", + "operationId": "get_pipeline", + "responses": { + "200": { + "description": "Операция завершена успешно", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PipelineResponse" + } + } + } + }, + "401": { + "description": "Аутентификация не пройдена", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Не найден запрошенный ресурс.\nВозможные причины: \n- Указанный пайплайн не существует;\n", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "default": { + "description": "Операция завершена успешно", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PipelineResponse" + } + } + } + } + } + } + }, + "/{app}/pipelines/{pipeline}/version": { + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Имя приложения PlatformApp" + }, + { + "name": "pipeline", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Имя пайплайна ExperimentPipeline" + } + ], + "get": { + "tags": [ + "pipelines" + ], + "summary": "Получить версию пайплайна", + "description": "Возвращает версию пайплайна, что включает OpenAPI спецификацию для запуска пайплайна, версию и лицензию по использованию пайплайна.", + "operationId": "get_pipeline_version", + "responses": { + "200": { + "description": "Операция завершена успешно", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PipelineVersionResponse" + } + } + } + }, + "401": { + "description": "Аутентификация не пройдена", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Не найден запрошенный ресурс.\nВозможные причины: \n- Указанный пайплайн не существует;\n", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "default": { + "description": "Операция завершена успешно", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PipelineVersionResponse" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "Link": { + "description": "Ссылка на ресурс", + "type": "object", + "properties": { + "href": { + "type": "string" + }, + "templated": { + "type": "boolean" + } + }, + "required": [ + "href" + ] + }, + "EmptyResponse": { + "description": "Пустой ответ", + "type": "object", + "properties": { + "additional_info": { + "type": "object", + "additionalProperties": false, + "minProperties": 0, + "maxProperties": 0 + } + } + }, + "TrialResponse": { + "description": "Запуск пайплайна", + "type": "object", + "properties": { + "app_name": { + "description": "Имя приложения PlatformApp", + "type": "string" + }, + "user_id": { + "description": "Идентификатор пользователя, который запустил пайплайн", + "type": "string" + }, + "tracking_id": { + "description": "Идентификатор отслеживания запуска", + "type": "string" + }, + "pipeline_name": { + "description": "Имя пайплайна ExperimentPipeline", + "type": "string" + }, + "pipeline_version": { + "description": "Версия ресурса ExperimentPipeline, используемая для запуска", + "type": "string" + }, + "next_tracking_id": { + "description": "Идентификатор отслеживания запуска следующего пайплайна", + "type": "string" + }, + "next_pipeline_name": { + "description": "Имя следующего пайплайна ExperimentPipeline", + "type": "string" + }, + "vars": { + "description": "Значения входных и выходных переменные запуска.", + "type": "object", + "properties": { + "inputs": { + "description": "Значения входных переменных. В списке содержатся только те входные переменные, значения для которых передаются и были переданы при запуске пайплайна.\nВходные переменные, ассоциированные в спецификации пайплайна с данными в ящиках, не содержатся в списке.", + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "description": "Имя входной переменной", + "type": "string" + }, + "box_name": { + "description": "Имя ассоциированного ящика DataBox", + "type": "string" + }, + "data": { + "description": "Значение входной переменной.\n\nЛокация в сервисе Files, по которой можно получить значение входной переменной.\nМожет указывать как на файл, так и на файловую группу.\n\nЕсли при запуске пайплайна входное значение было\nпередано с datatype не из {'FILE', 'WEBSITE'}, то значением атрибута\nявляется локация созданного файла, в который записано\nпереданное значение.", + "type": "string" + }, + "datatype": { + "description": "Тип значения входной переменной", + "type": "string", + "enum": [ + "FILE", + "FP32", + "FP64", + "INT32", + "str", + "dict", + "WEBSITE" + ] + }, + "content_type": { + "type": "string", + "description": "Тип содержимого файла или файлов входной переменной.\n\nЕсли при запуске пайплайна входное значение было\nпередано с datatype != 'FILE', то тип содержимого файла, в который сохранено переданное значение, соответствует установленному предопределенному типу для этого datatype." + } + }, + "required": [ + "name", + "box_name", + "data", + "datatype", + "content_type" + ] + } + }, + "outputs": { + "description": "Значения выходных переменных. В списке содержатся только те выходные переменные, параметры которых были переданы при запуске пайплайна.", + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "description": "Имя выходной переменной", + "type": "string" + }, + "box_name": { + "description": "Имя ассоциированного ящика DataBox", + "type": "string" + }, + "data": { + "description": "Имя ассоциированной локации в сервисе Files. Локация соответствует файловой группе. Если запуск еще не завершен, то результаты в файловой группе будут отсутствовать.", + "type": "string" + }, + "datatype": { + "description": "Тип значения выходной переменной", + "type": "string", + "enum": [ + "FILE", + "WEBSITE" + ] + }, + "content_type": { + "description": "Тип содержимого файла или файлов выходной переменной.\nТип содержимого определяется в атрибутах content_type объектов списка output_vars, переданных при запуске пайплайна.", + "type": "string" + } + }, + "required": [ + "name", + "box_name", + "data" + ] + } + } + } + }, + "status": { + "$ref": "#/components/schemas/TrialStatus" + }, + "_links": { + "description": "Ссылки на связанные ресурсы", + "type": "object", + "properties": { + "self": { + "$ref": "#/components/schemas/Link" + }, + "pipeline": { + "$ref": "#/components/schemas/Link" + } + } + } + }, + "required": [ + "app_name", + "user_id", + "tracking_id", + "pipeline_name", + "pipeline_version", + "status", + "_links" + ] + }, + "EmbeddedTrial": { + "description": "Краткое представление запуска пайплайна", + "type": "object", + "properties": { + "app_name": { + "description": "Имя приложения PlatformApp", + "type": "string" + }, + "user_id": { + "description": "Идентификатор пользователя, который запустил пайплайн", + "type": "string" + }, + "tracking_id": { + "description": "Идентификатор отслеживания запуска", + "type": "string" + }, + "pipeline_name": { + "description": "Имя пайплайна ExperimentPipeline", + "type": "string" + }, + "pipeline_version": { + "description": "Версия ресурса ExperimentPipeline, используемая для запуска", + "type": "string" + }, + "next_tracking_id": { + "description": "Идентификатор отслеживания запуска следующего пайплайна", + "type": "string" + }, + "next_pipeline_name": { + "description": "Имя следующего пайплайна ExperimentPipeline", + "type": "string" + }, + "status": { + "$ref": "#/components/schemas/TrialStatus" + }, + "_links": { + "description": "Ссылки на связанные ресурсы", + "type": "object", + "properties": { + "self": { + "$ref": "#/components/schemas/Link" + }, + "pipeline": { + "$ref": "#/components/schemas/Link" + } + } + } + }, + "required": [ + "app_name", + "user_id", + "tracking_id", + "pipeline_name", + "pipeline_version", + "status", + "_links" + ] + }, + "TrialStatus": { + "description": "Статус запуска пайплайна", + "type": "object", + "properties": { + "status_date_time": { + "description": "Время последнего изменения статуса в формате ISO", + "type": "string" + }, + "conditions": { + "description": "Список условий, составляющих статус запуска", + "type": "array", + "items": { + "type": "object", + "properties": { + "type": { + "description": "Тип условия", + "type": "string" + }, + "condition_status": { + "description": "Статус условия", + "type": "string", + "enum": [ + "True", + "False", + "Unknown" + ] + }, + "last_transition_time": { + "description": "Время последнего изменения статуса условия в формате ISO", + "type": "string" + }, + "message": { + "description": "Подробное описание условия, понятное человеку", + "type": "string" + }, + "reason": { + "description": "Содержит программный идентификатор, являющийся индикатором причины последнего изменения статуса условия", + "type": "string" + }, + "stage": { + "description": "Опциональное имя этапа, к которому относится условие", + "type": "string" + } + }, + "required": [ + "type", + "condition_status", + "last_transition_time", + "message", + "reason" + ] + } + } + }, + "required": [ + "status_date_time" + ] + }, + "TrialsResponse": { + "description": "Список запусков пайплайнов", + "type": "object", + "properties": { + "_links": { + "description": "Ссылки на связанные ресурсы", + "type": "object", + "properties": { + "self": { + "$ref": "#/components/schemas/Link" + }, + "next": { + "$ref": "#/components/schemas/Link" + } + } + }, + "remaining_item_count": { + "description": "Оставшееся число элементов перед курсором", + "type": "integer" + }, + "total_item_count": { + "description": "Общее число элементов", + "type": "integer" + }, + "_embedded": { + "type": "object", + "properties": { + "trials": { + "description": "Список запусков", + "type": "array", + "items": { + "$ref": "#/components/schemas/EmbeddedTrial" + } + } + }, + "required": [ + "trials" + ] + } + }, + "required": [ + "_links", + "_embedded", + "remaining_item_count", + "total_item_count" + ] + }, + "CreateTrialRequest": { + "description": "Запрос запуска пайплайна", + "type": "object", + "properties": { + "inputs": { + "description": "Список значений входных переменных.\n\nЕсли значение входной переменной не задано,\nто оно не будет передано в пайплайн, \nи переменная не будет сохранена в запуске пайплайна.", + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "description": "Имя входной переменной", + "type": "string" + }, + "data": { + "description": "Значение входной переменной.\n\nЕсли datatype из {'FILE', 'WEBSITE'}, то содержит локацию в сервисе Files,\nпо которой можно получить значение входной переменной.\nМожет указывать как на файл, так и на файловую группу.\n\nЕсли datatype не из {'FILE', 'WEBSITE'}, то содержит строку с сериализованным \nзначением входной переменной, которое будет сохранено в файл. \n\nДля каждого datatype != 'FILE' для файла,\nв который сохраняется значение переменной,\nустановлен предопределенный тип содержимого (content_type).", + "type": "object" + }, + "datatype": { + "description": "Тип значения входной переменной", + "type": "string", + "enum": [ + "FILE", + "FP32", + "FP64", + "INT32", + "str", + "dict", + "WEBSITE" + ] + }, + "content_type": { + "description": "Тип содержимого файла или файлов, при типе входной переменной\ndatatype == \\\"FILE\\\". Тип содержимого файла должен быть задан\nпри запуске пайплайна.\n\nПри типе входной переменной datatype != \\\"FILE\\\" переданный тип содержимого \nфайла игнорируется. Для каждого datatype установлен предопределенный тип содержимого.", + "type": "string" + }, + "shape": { + "description": "Размерность, как массива, значения входной переменной. Применимо к любым типам данных входной переменной.", + "oneOf": [ + { + "type": "integer" + }, + { + "type": "array", + "items": { + "type": "integer" + }, + "minItems": 1, + "maxItems": 32 + } + ] + } + }, + "required": [ + "name", + "data", + "datatype", + "shape" + ] + } + }, + "output_vars": { + "type": "array", + "description": "Список параметров для выходных переменных.\n\nЕсли параметры выходной переменной не заданы,\nто они не будет переданы в пайплайн,\nпайплайн не вычислит значений выходной переменной,\nи переменная не будет сохранена в запуске пайплайна.", + "items": { + "description": "Параметры выходной переменной", + "type": "object", + "properties": { + "name": { + "description": "Имя выходной переменной", + "type": "string" + }, + "data": { + "description": "Локация выходной переменной в сервисе Files.\n\nУказывает, куда должны быть сохранены значения выходной\nпеременной. Должна соответствовать файловой группе.\n\nМожет быть не указана, тогда будет создана файловая группа со \nсгенерированным именем.", + "type": "string" + }, + "datatype": { + "description": "Тип значения выходной переменной", + "type": "string", + "enum": [ + "FILE", + "WEBSITE" + ] + }, + "content_type": { + "type": "string", + "description": "Ожидаемый тип содержимого файла или файлов выходной переменной." + } + }, + "required": [ + "name" + ] + } + } + } + }, + "PipelineResponse": { + "description": "Пайплайн ExperimentPipeline", + "type": "object", + "properties": { + "name": { + "description": "Имя пайплайна", + "type": "string" + }, + "_links": { + "description": "Ссылки на связанные ресурсы", + "type": "object", + "properties": { + "self": { + "$ref": "#/components/schemas/Link" + }, + "trials": { + "$ref": "#/components/schemas/Link" + }, + "version": { + "$ref": "#/components/schemas/Link" + } + } + }, + "definition": { + "description": "Спецификация пайплайна в формате JSON", + "type": "object" + } + }, + "required": [ + "name", + "_links", + "definition" + ] + }, + "PipelinesResponse": { + "description": "Список пайплайнов", + "type": "object", + "properties": { + "_links": { + "description": "Ссылки на связанные ресурсы", + "type": "object", + "properties": { + "self": { + "$ref": "#/components/schemas/Link" + }, + "next": { + "$ref": "#/components/schemas/Link" + } + } + }, + "remaining_item_count": { + "description": "Оставшееся число элементов перед курсором", + "type": "integer" + }, + "_embedded": { + "type": "object", + "properties": { + "pipelines": { + "description": "Список пайплайнов", + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "description": "Имя пайплайна", + "type": "string" + }, + "_links": { + "description": "Ссылки на связанные ресурсы", + "type": "object", + "properties": { + "self": { + "$ref": "#/components/schemas/Link" + }, + "trials": { + "$ref": "#/components/schemas/Link" + }, + "version": { + "$ref": "#/components/schemas/Link" + } + } + } + } + } + } + }, + "required": [ + "pipelines" + ] + } + }, + "required": [ + "_links", + "remaining_item_count", + "_embedded" + ] + }, + "PipelineVersionResponse": { + "description": "Версия пайплайна ExperimentPipeline", + "type": "object", + "properties": { + "openapi_spec": { + "description": "OpenAPI спецификация API для запуска пайплайна и получения информации о пайплайне", + "type": "object" + }, + "license": { + "description": "Адрес для получения текста лицензии по использованию пайплайна", + "type": "string" + }, + "pipeline_version": { + "description": "Версия пайплайна", + "type": "string" + } + }, + "required": [ + "openapi_spec", + "license", + "pipeline_version" + ] + }, + "ErrorResponse": { + "description": "Объект с результатом операции, которая не завершилась успешно", + "type": "object", + "properties": { + "errors": { + "description": "Список ошибок", + "type": "array", + "items": { + "description": "Ошибка при выполнении операции инференса", + "type": "object", + "properties": { + "type": { + "description": "Тип ошибки", + "type": "string" + }, + "message": { + "description": "Сообщение с описанием ошибки", + "type": "string" + } + }, + "required": [ + "type", + "message" + ] + }, + "maxItems": 10 + } + } + } + }, + "responses": { + "trial": { + "description": "Операция получения запуска успешно завершена", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TrialResponse" + } + } + } + } + }, + "securitySchemes": { + "basic_auth": { + "description": "Базовая аутентификация", + "type": "http", + "scheme": "basic" + } + } + } +} diff --git a/controller/src/exp_pipeline/openapi.py b/controller/src/exp_pipeline/openapi.py new file mode 100644 index 0000000..e4794ec --- /dev/null +++ b/controller/src/exp_pipeline/openapi.py @@ -0,0 +1,542 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: ExperimentPipeline +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +import json +import logging +import os +from copy import copy, deepcopy +from typing import Literal, Optional, List, Iterable, get_args + +from pydantic import BaseModel + +from exp_pipeline.schema import DATATYPES, DATATYPE_TO_CONTENT_TYPE, OUTPUT_DATATYPES + +_base_spec = None +logger = logging.getLogger(__name__) + + +class ApiVar(BaseModel): + kind: Literal["input", "output"] + name: str + description: Optional[str] = None + datatypes: List[DATATYPES] + content_types: Optional[List[str]] = None + required: Optional[bool] = None + + +def _extend_content_types_given_datatypes(content_types, datatypes): + datatypes = set(datatypes) - {'FILE'} + content_types_to_add = {v for k, v in DATATYPE_TO_CONTENT_TYPE.items() if k in datatypes} + content_types_to_add = {ct for ct in content_types_to_add if ct not in content_types} + content_types += content_types_to_add + return content_types + + +def _create_var_datatypes_content_types(section, supported_datatypes): + if 'type' in section: + type_section = section['type'] + if 'datatypes' in type_section: + datatypes = type_section['datatypes'] + datatypes = [d for d in datatypes if d in supported_datatypes] + if 'FILE' not in datatypes: + datatypes.append('FILE') + else: + datatypes = copy(supported_datatypes) + if 'contentTypes' in type_section: + content_types = type_section['contentTypes'] + _extend_content_types_given_datatypes(content_types, datatypes) + else: + content_types = None + else: + datatypes = copy(supported_datatypes) + content_types = None + return datatypes, content_types + + +def _create_input_var(input_section: dict, supported_datatypes) -> ApiVar: + var_attrs = { + 'kind': 'input', + 'name': input_section['name'], + 'description': input_section.get('description') or None, + } + required = True + if 'required' in input_section: + required = input_section['required'] == 'true' or \ + input_section['required'] is True + + datatypes, content_types = _create_var_datatypes_content_types(input_section, supported_datatypes) + + var_attrs.update({ + 'content_types': content_types, + 'datatypes': datatypes, + 'required': required + }) + api_var = ApiVar(**var_attrs) + return api_var + + +def _create_output_var(output_section: dict, supported_datatypes) -> ApiVar: + var_attrs = { + 'kind': 'output', + 'name': output_section['name'], + 'description': output_section.get('description') or None, + } + + datatypes, content_types = _create_var_datatypes_content_types(output_section, supported_datatypes) + + var_attrs.update({ + 'content_types': content_types, + 'datatypes': datatypes + }) + api_var = ApiVar(**var_attrs) + return api_var + + +def _check_box_path(input_section): + if 'mountFrom' in input_section: + mount_from = input_section['mountFrom'] + box = mount_from['box'] + return 'boxPath' in box + return False + + +def _get_name(api_var: ApiVar): + var_char = 'входной' if api_var.kind == 'input' else 'выходной' + return { + 'const': api_var.name, + 'description': f'Имя {var_char} переменной.' + } + + +def _get_var_base(api_var: ApiVar): + openapi_spec = { + 'type': 'object', + 'properties': { + 'name': _get_name(api_var) + }, + 'required': [ + 'name' + ] + } + if api_var.description: + openapi_spec['description'] = api_var.description + + return openapi_spec + + +def _get_input_var_datatype(api_var: ApiVar): + return { + 'type': 'string', + 'description': f'Тип значения входной переменной.', + 'enum': api_var.datatypes + } + + +def _get_output_var_datatype(api_var: ApiVar): + return { + 'type': 'string', + 'description': f'Тип значения выходной переменной.', + 'enum': api_var.datatypes + } + + +def _get_start_input_var_data(api_var: ApiVar): + description = """Значение входной переменной. + Если datatype из {'FILE', 'WEBSITE'}, то содержит локацию в сервисе Files, + по которой можно получить значение входной переменной. + Может указывать как на файл, так и на файловую группу. + Если datatype не из {'FILE', 'WEBSITE'}, то содержит строку с сериализованным + значением входной переменной, которое будет сохранено в файл. + Для каждого datatype != 'FILE' для файла, + в который сохраняется значение переменной, + установлен предопределенный тип содержимого (content_type).""" + return { + # 'type': any, if type not specified + 'description': description + } + + +def _get_start_output_var_data(api_var: ApiVar): + description = """Локация выходной переменной в сервисе Files. + Указывает, куда должны быть сохранены значения выходной + переменной. Должна соответствовать файловой группе. + Может быть не указана, тогда будет создана файловая группа со + сгенерированным именем.""" + return { + 'type': 'string', + 'description': description + } + + +def _get_result_input_var_data(api_var: ApiVar): + description = \ + """Значение входной переменной. + Локация в сервисе Files, по которой можно получить значение входной переменной. + Может указывать как на файл, так и на файловую группу. + Если при запуске пайплайна входное значение было + передано с datatype не из {'FILE', 'WEBSITE'}, то значением атрибута + является локация созданного файла, в который записано + переданное значение.""" + return { + 'type': 'string', + 'description': description + } + + +def _get_result_output_var_data(api_var: ApiVar): + description = """Имя ассоциированной локации в сервисе Files. + Локация соответствует файловой группе. + Если запуск еще не завершен, то + результаты в файловой группе будут + отсутствовать.""" + return { + 'type': 'string', + 'description': description + } + + +def _get_result_var_data_box(api_var: ApiVar): + description = 'Имя ассоциированного ящика DataBox' + return { + 'type': 'string', + 'description': description + } + + +def _get_start_var_shape(api_var: ApiVar): + var_char = 'входной' if api_var.kind == 'input' else 'выходной' + description = f'Размерность значения {var_char} переменной.\n' \ + 'Применимо к любым типам данных входной переменной.\n' + return { + 'description': description, + 'oneOf': [ + { + 'type': 'array', + 'items': { + 'type': 'integer' + }, + 'minItems': 1, + 'maxItems': 32 + }, + { + 'type': 'integer' + } + ] + } + + +def _get_start_input_var_content_type(api_var: ApiVar): + description = """Тип содержимого файла или файлов, при типе входной переменной + datatype == \"FILE\". Тип содержимого файла должен быть задан + при запуске пайплайна. + При типе входной переменной datatype != \"FILE\" переданный тип содержимого + файла игнорируется. Для каждого datatype установлен предопределенный тип содержимого.""" + spec = { + 'type': 'string', + 'description': description + } + if api_var.content_types: + spec['enum'] = api_var.content_types + return spec + + +def _get_result_input_var_content_type(api_var: ApiVar): + description = f"""Тип содержимого файла или файлов входной переменной. + Если при запуске пайплайна входное значение было + передано с datatype != 'FILE', то тип содержимого файла, + в который сохранено переданное значение, соответствует + установленному предопределенному типу для этого datatype.""" + spec = { + 'type': 'string', + 'description': description + } + if api_var.content_types: + spec['enum'] = api_var.content_types + return spec + + +def _get_result_output_var_content_type(api_var: ApiVar): + description = f"""Тип содержимого файла или файлов выходной переменной. + Тип содержимого определяется в атрибутах content_type + объектов списка output_vars, переданных при запуске пайплайна.""" + spec = { + 'type': 'string', + 'description': description + } + if api_var.content_types: + spec['enum'] = api_var.content_types + return spec + + +def _get_start_output_var_content_type(api_var: ApiVar): + spec = { + 'type': 'string', + 'description': 'Ожидаемый тип содержимого файла или файлов ' + 'выходной переменной.' + } + if api_var.content_types: + spec['enum'] = api_var.content_types + return spec + + +def _construct_start_input_var(api_var: ApiVar): + openapi_spec = _get_var_base(api_var) + openapi_spec['properties']['datatype'] = _get_input_var_datatype(api_var) + openapi_spec['required'].append('datatype') + openapi_spec['properties']['data'] = _get_start_input_var_data(api_var) + openapi_spec['required'].append('data') + shape = _get_start_var_shape(api_var) + openapi_spec['properties']['shape'] = shape + openapi_spec['required'].append('shape') + content_type = _get_start_input_var_content_type(api_var) + openapi_spec['properties']['content_type'] = content_type + return openapi_spec + + +def _construct_start_output_var(api_var: ApiVar): + openapi_spec = _get_var_base(api_var) + openapi_spec['properties']['datatype'] = _get_output_var_datatype(api_var) + openapi_spec['properties']['data'] = _get_start_output_var_data(api_var) + openapi_spec['properties']['content_type'] = _get_start_output_var_content_type(api_var) + return openapi_spec + + +def _construct_result_input_var(api_var: ApiVar): + openapi_spec = _get_var_base(api_var) + openapi_spec['properties']['datatype'] = _get_input_var_datatype(api_var) + openapi_spec['required'].append('datatype') + openapi_spec['properties']['data'] = _get_result_input_var_data(api_var) + openapi_spec['required'].append('data') + openapi_spec['properties']['data_box'] = _get_result_var_data_box(api_var) + openapi_spec['required'].append('data_box') + openapi_spec['properties']['content_type'] = _get_result_input_var_content_type(api_var) + openapi_spec['required'].append('content_type') + return openapi_spec + + +def _construct_result_output_var(api_var: ApiVar): + openapi_spec = _get_var_base(api_var) + openapi_spec['properties']['datatype'] = _get_output_var_datatype(api_var) + openapi_spec['properties']['data'] = _get_result_output_var_data(api_var) + openapi_spec['required'].append('data') + openapi_spec['properties']['data_box'] = _get_result_var_data_box(api_var) + openapi_spec['required'].append('data_box') + openapi_spec['properties']['content_type'] = _get_result_output_var_content_type(api_var) + return openapi_spec + + +def _create_api_vars_from_k8s_resource(resource: dict, continue_with: Iterable[dict] = None): + api_vars = [] + input_vars_names = set() + output_vars_names = set() + + _append_api_vars_from_k8s_resource(api_vars, input_vars_names, output_vars_names, resource) + + if continue_with: + for res in continue_with: + _append_api_vars_from_k8s_resource(api_vars, input_vars_names, output_vars_names, res) + + return api_vars + + +def _append_api_vars_from_k8s_resource(api_vars, input_vars_names, output_vars_names, resource: dict): + supported_input_datatypes = get_args(DATATYPES) + supported_output_datatypes = get_args(OUTPUT_DATATYPES) + if 'inputs' in resource: + for input_section in resource['inputs']: + var_name = input_section['name'] + if var_name in input_vars_names: + continue + if _check_box_path(input_section): + continue + api_var = _create_input_var(input_section, supported_input_datatypes) + api_vars.append(api_var) + input_vars_names.add(var_name) + if 'outputs' in resource: + for output_section in resource['outputs']: + var_name = output_section['name'] + if var_name in output_vars_names: + continue + api_var = _create_output_var(output_section, supported_output_datatypes) + api_vars.append(api_var) + output_vars_names.add(var_name) + + +def _construct_result_inputs_outputs(spec_vars: list[ApiVar]): + input_vars = [spec_var for spec_var in spec_vars + if spec_var.kind == 'input'] + result_inputs_spec = None + if input_vars: + result_inputs_spec = { + 'description': """Значения входных переменных. В списке содержатся только те + входные переменные, значения для которых передаются и были переданы + при запуске пайплайна. + Входные переменные, ассоциированные в спецификации пайплайна с + данными в ящиках, не содержатся в списке.""", + 'type': 'array', + 'items': {'oneOf': []} + } + required_input_vars = [spec_var for spec_var in input_vars + if spec_var.required] + required_input_vars_names = [spec_var.name for spec_var in required_input_vars] + required_input_vars_str = f'\n\nОбязательные переменные: {", ".join(required_input_vars_names)}' + result_inputs_spec['description'] += required_input_vars_str + optional_input_vars = [spec_var for spec_var in input_vars + if not spec_var.required] + inputs = [_construct_result_input_var(v) for v in required_input_vars] + inputs_min_items = len(inputs) + inputs += [_construct_result_input_var(v) for v in optional_input_vars] + result_inputs_spec['items']['oneOf'] = inputs + result_inputs_spec['minItems'] = inputs_min_items + + output_vars = [spec_var for spec_var in spec_vars + if spec_var.kind == 'output'] + result_outputs_spec = None + if output_vars: + result_outputs_spec = { + 'description': 'Значения выходных переменных. ' + 'В списке содержатся только те выходные переменные, ' + 'параметры которых были переданы при запуске пайплайна. ', + 'type': 'array', + 'items': {'oneOf': []} + } + outputs = [_construct_result_output_var(v) for v in output_vars] + result_outputs_spec['items']['oneOf'] = outputs + + return result_inputs_spec, result_outputs_spec + + +def _construct_start_inputs_outputs(spec_vars: list[ApiVar]): + required_input_vars = [spec_var for spec_var in spec_vars + if spec_var.required and spec_var.kind == 'input'] + optional_input_vars = [spec_var for spec_var in spec_vars + if not spec_var.required and spec_var.kind == 'input'] + output_vars = [spec_var for spec_var in spec_vars + if spec_var.kind == 'output'] + start_inputs = [_construct_start_input_var(v) for v in required_input_vars] + start_inputs_min_items = len(start_inputs) + start_inputs += [_construct_start_input_var(v) for v in optional_input_vars] + start_outputs = [_construct_start_output_var(v) for v in output_vars] + start_outputs_max_items = len(start_outputs) + + start_outputs_spec = { + 'description': 'Список параметров для выходных переменных.\n\n' + 'Если параметры выходной переменной не заданы, то они не будет переданы в пайплайн, ' + 'пайплайн не вычислит значений выходной переменной, ' + 'и переменная не будет сохранена в запуске пайплайна.\n\n' + 'Если спецификация пайплайна включает следующий пайплайн, ' + 'то в список включаются все выходные переменные всех ' + 'последующих пайплайнов.', + 'type': 'array', + 'items': {'oneOf': start_outputs}, + 'maxItems': start_outputs_max_items + } + + start_inputs_spec = { + 'description': 'Список значений входных переменных.\n\n' + 'Если значение входной переменной не задано, то оно не будет передано в пайплайн, ' + 'и переменная не будет сохранена в запуске пайплайна. ' + 'Если не задано значение обязательной переменной, то пайплайн не будет запущен.\n\n' + 'Если спецификация пайплайна включает следующий пайплайн, ' + 'то в список включаются все входные переменные всех ' + 'последующих пайплайнов.', + 'type': 'array', + 'items': {'oneOf': start_inputs}, + 'minItems': start_inputs_min_items + } + + required_input_vars_names = [spec_var.name for spec_var in required_input_vars] + required_input_vars_str = f'\n\nОбязательные переменные: {", ".join(required_input_vars_names)}' + start_inputs_spec['description'] += required_input_vars_str + + return start_inputs_spec, start_outputs_spec + + +def _fill_api_spec_sections(base_spec: dict, + api_vars: list[ApiVar]): + result_inputs, result_outputs = _construct_result_inputs_outputs(api_vars) + + schemas = base_spec['components']['schemas'] + trial_response = schemas['TrialResponse'] + trial_response_properties = trial_response['properties'] + if not result_inputs and not result_outputs: + del trial_response_properties['vars'] + if result_inputs: + trial_response_properties['vars']['properties']['inputs'] = result_inputs + else: + del trial_response_properties['vars']['properties']['inputs'] + if result_outputs: + trial_response_properties['vars']['properties']['outputs'] = result_outputs + else: + del trial_response_properties['vars']['properties']['outputs'] + + start_inputs, start_outputs = _construct_start_inputs_outputs(api_vars) + start_trial = schemas['CreateTrialRequest'] + start_trial_properties = start_trial['properties'] + if start_inputs: + start_trial_properties['inputs'] = start_inputs + else: + del start_trial_properties['inputs'] + if start_outputs: + start_trial_properties['output_vars'] = start_outputs + else: + del start_trial_properties['output_vars'] + + return base_spec + + +def _get_base_spec(): + global _base_spec + if not _base_spec: + try: + base_dir = os.path.dirname(os.path.realpath(__file__)) + json_path = os.path.join(base_dir, 'openapi-base.json') + with open(json_path) as f: + _base_spec = json.load(f) + except Exception as exc: + logger.exception('Cannot load base OpenAPI spec', exc_info=exc) + raise exc + return _base_spec + + +def create_openapi_spec(api_resource: dict, continue_with=None) -> dict: + base_spec = _get_base_spec() + + spec = api_resource['spec'] + api_spec = spec.get('apiSpec') + + cw_specs = filter(lambda x: x is not None, [cw['spec'].get('apiSpec') for cw in continue_with]) \ + if continue_with \ + else None + api_vars = [] + if api_spec: + api_vars = _create_api_vars_from_k8s_resource(api_spec, + cw_specs) + + api_spec = _fill_api_spec_sections(deepcopy(base_spec), api_vars) + + return api_spec + + +if __name__ == '__main__': + + def _load_example_pipeline_spec(path): + import yaml + with open(path) as f: + res = yaml.safe_load(f) + return res + + + import sys + + if len(sys.argv) != 3: + raise SyntaxError('input spec path and output path must be provided') + pipeline_spec = _load_example_pipeline_spec(sys.argv[1]) + + spec = create_openapi_spec(pipeline_spec) + + with open(sys.argv[2], 'w', encoding='utf-8') as f: + json.dump(spec, f, ensure_ascii=False, indent=2) diff --git a/controller/src/exp_pipeline/pipeline.py b/controller/src/exp_pipeline/pipeline.py new file mode 100644 index 0000000..3b7fae8 --- /dev/null +++ b/controller/src/exp_pipeline/pipeline.py @@ -0,0 +1,1247 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: ExperimentPipeline +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +import logging +import os +import posixpath +import urllib.parse +import uuid +from collections.abc import Sequence +from datetime import datetime, timezone +from uuid import uuid4 + +import yaml +from fastapi import HTTPException +from httpx import AsyncClient +from kubernetes.client import V1Secret +from kubernetes_asyncio.client import CustomObjectsApi, BatchV1Api, ApiException, ApiClient, CoreV1Api +from sqlalchemy import select, func, Select +from sqlalchemy.ext.asyncio import AsyncSession +from sqlalchemy.orm.attributes import flag_modified + +from auth import get_basic_auth_credentials +from config import UNIP_DOMAIN +from exceptions import ObjectDoesNotExistPermanentError, RelatedObjectValuePermanentError +from exp_pipeline.box import construct_connected_box, get_default_box, get_path_inside_box +from exp_pipeline.client_config import TRACKING_ID_VAR_NAME, \ + API_VAR_NAME, APP_NAME_VAR_NAME, PIPELINE_VAR_NAME +from exp_pipeline.config import UNIP_PIPELINE_RUN_MODE, UNIP_FILES_API, UNIP_PIPELINES_API, UNIP_DATETIME_FORMAT, \ + UNIP_PIPELINE_VALIDATION_IMAGE +from exp_pipeline.jinja import jinja_env +from exp_pipeline.openapi import create_openapi_spec +from exp_pipeline.results.validate_trial_results import get_output_var_validation_mount_path, \ + get_start_request_data_mount_path, START_REQUEST_DATA_FILE_NAME, \ + get_validation_vars_data_mount_path, VALIDATION_VARS_DATA_FILE_NAME, get_internal_api_secret_mount_path +from exp_pipeline.schema import TrialInput, TrialOutputVar, TrialStatus, StatusCondition, TrialStart, PipelineTrial, \ + TrialStartStage, BoxMount, CreateTrialRequest, ConnectedBox, TrialLinks, \ + Link, ValidationInput, ValidationVars, TrialStartVars, TrialVar, \ + TrialVars, TrialStageOutput, StartConfigFrom +from exp_pipeline.stage import construct_start_stage +from exp_pipeline.storage.models import PipelineTrialModel +from exp_pipeline.var import construct_start_vars, UNIP_FILES_USER_PASSWORD +from parse import extract_domain + +ENV_VAR_PREFIX = 'UNIP_PIPELINE_' +ENV_VAR_PATH_SUFFIX = '_PATH' +ENV_VAR_DATA_FILE_NAME = 'data' +VAR_LIST_ENV_VAR = ENV_VAR_PREFIX + 'VARS' +ENV_VAR_CONTENT_TYPE_SUFFIX = '_CONTENT_TYPE' +ENV_VAR_SHAPE_SUFFIX = '_SHAPE' + +TRACKING_ID_LABEL_NAME = 'unified-platform.cs.hse.ru/tracking-id' +TRACKING_ID_ANNO_NAME = 'unified-platform.cs.hse.ru/tracking-id' +IS_SYSTEM_NODE_TAINT_NAME = 'node.unified-platform.cs.hse.ru/is-system-node' +IS_GPU_AVAILABLE_TAINT_NAME = 'node.unified-platform.cs.hse.ru/is-gpu-available' +IS_INTERRUPTIBLE_TAINT_NAME = 'node.unified-platform.cs.hse.ru/is-interruptible' +GPU_LABEL_NAME = 'node.unified-platform.cs.hse.ru/resources.gpu' +PIPELINE_NODE_LABEL_NAME = 'node.unified-platform.cs.hse.ru/components.experimentpipeline' + +LIST_PIPELINES_MAX_RETRIES = 5 + +INTERNAL_API_SECRET_SUFFIX = '-internal-cred' + +_VALIDATION_CONTAINER_RESOURCE_CPU = '250m' +_VALIDATION_CONTAINER_RESOURCE_MEMORY = '128M' +_VALIDATION_CONTAINER_INTERNAL_API_SECRET_VOLUME = 'internal-api-secret' + +SECRET_SUFFIX = '-cred' + +logger = logging.getLogger(__name__) + + +class OpenAPISpecCache(dict): + def __init__(self, *args, size=1000, **kwargs): + self.__size = size + super().__init__(*args, **kwargs) + + def __setitem__(self, key, value): + dict.__setitem__(self, key, value) + if self.__size > 0: + if len(self) > self.__size: + self.pop(next(iter(self))) + + _instance = None + + async def _extract_attrs(self, k8s_api_client: ApiClient, app_name, api_resource): + spec = api_resource['spec'] + pipeline = spec['experimentPipeline'] + pipeline_name = pipeline['name'] + + pipeline_resource = await get_pipeline_resource(api_client=k8s_api_client, + app_name=app_name, + pipeline_name=pipeline_name) + + pipeline_spec = pipeline_resource['spec'] + continue_with = pipeline_spec['continueWith']['name'] if 'continueWith' in pipeline_spec else None + return pipeline_name, continue_with + + async def _get_pipelines_chain(self, k8s_api_client: ApiClient, app_name, api_resource): + pipeline_name, continue_with = await self._extract_attrs(k8s_api_client=k8s_api_client, + app_name=app_name, + api_resource=api_resource) + chain = [] + found_pipelines_names = {pipeline_name} + while continue_with and continue_with not in found_pipelines_names: + logger.info(f'For pipeline {app_name}.{pipeline_name} ' + f'found continueWith {continue_with} pipeline') + api_resource = await get_api_resource(api_client=k8s_api_client, + app_name=app_name, + pipeline_name=continue_with) + chain.append(api_resource) + pipeline_name, continue_with = await self._extract_attrs(k8s_api_client=k8s_api_client, + app_name=app_name, + api_resource=api_resource) + found_pipelines_names.add(pipeline_name) + if not chain: + return None + return chain + + async def get_pipeline_api_spec(self, k8s_api_client: ApiClient, app_name, api_resource): + metadata = api_resource['metadata'] + spec = api_resource['spec'] + pipeline = spec['experimentPipeline'] + pipeline_name = pipeline['name'] + version = metadata['resourceVersion'] + key = f'{app_name}:{pipeline_name}:{version}' + if key in self: + return self[key] + + continue_with = await self._get_pipelines_chain(k8s_api_client, app_name, api_resource) + + openapi_spec = create_openapi_spec(api_resource=api_resource, + continue_with=continue_with) + self[key] = openapi_spec + return openapi_spec + + @classmethod + def get_spec_cache(cls): + if OpenAPISpecCache._instance is None: + OpenAPISpecCache._instance = OpenAPISpecCache() + return OpenAPISpecCache._instance + + +def _prepare_manifest(template_name, variables): + template = jinja_env.get_template(template_name) + text = template.render(variables) + data = yaml.safe_load(text) + return data + + +def _get_image_registries_creds(stages: list[TrialStartStage]) -> list[str]: + img_reg_creds = [] + validation_img_reg = extract_domain(UNIP_PIPELINE_VALIDATION_IMAGE) + if validation_img_reg: + validation_img_reg_secret = validation_img_reg + SECRET_SUFFIX + img_reg_creds.append(validation_img_reg_secret) + img_reg_creds += list({stage.image.credentials_name for stage in stages}) + return img_reg_creds + + +async def get_pipeline_resource(api_client: ApiClient, app_name: str, pipeline_name: str) -> dict: + co_api = CustomObjectsApi(api_client) + try: + # get_namespaced_custom_object возвращает объект, а не сопрограмму + pipeline_resource, _, _ = await co_api.get_namespaced_custom_object_with_http_info( + "unified-platform.cs.hse.ru", "v1", app_name, + "experimentpipelines", pipeline_name) + except ApiException as exc: + if exc.status == 404: + raise HTTPException(status_code=404, detail=f'Application {app_name} pipeline {pipeline_name} ' + f'not found') + raise exc + return pipeline_resource + + +async def get_api_resource(api_client: ApiClient, app_name: str, pipeline_name: str) -> dict: + co_api = CustomObjectsApi(api_client) + + # get_namespaced_custom_object возвращает объект, а не сопрограмму + list_resource, _, _ = await co_api.list_namespaced_custom_object_with_http_info( + "unified-platform.cs.hse.ru", "v1", app_name, + "apicomponents") + + if not list_resource['items']: + raise HTTPException(status_code=404, detail=f'Application {app_name} API Component for' + f' pipeline {pipeline_name} not found') + + for item in list_resource['items']: + spec = item['spec'] + if 'experimentPipeline' not in spec: + continue + name = spec['experimentPipeline']['name'] + if name == pipeline_name: + return item + + raise HTTPException(status_code=404, detail=f'Application {app_name} API Component for' + f' pipeline {pipeline_name} not found') + + +async def list_pipeline_resources(api_client: ApiClient, + app_name: str, + cursor: str = None, + limit: int = 10) -> tuple[list[dict], str | None, int | None, bool]: + co_api = CustomObjectsApi(api_client) + + expired = False + + def _parse_response(_resource): + metadata = _resource['metadata'] + _cursor = None + _remaining_item_count = 0 + if 'continue' in metadata: + _cursor = metadata['continue'] + if 'remainingItemCount' in metadata: + _remaining_item_count = metadata['remainingItemCount'] + _result = _resource['items'] + return _result, _cursor, _remaining_item_count + + try: + result_response, _, hdrs = await co_api.list_namespaced_custom_object_with_http_info( + "unified-platform.cs.hse.ru", "v1", app_name, + "experimentpipelines", _continue=cursor, limit=limit) + except ApiException as exc: + if exc.status == 410: + logger.warning(f'Status code 410 when listing app {app_name} pipelines') + resource = exc.body + result, new_cursor, remaining_item_count = _parse_response(resource) + expired = True + return result, new_cursor, remaining_item_count, expired + raise exc + + result, new_cursor, remaining_item_count = _parse_response(result_response) + return result, new_cursor, remaining_item_count, expired + + +async def _save_data_to_file(http_client: AsyncClient, + app_name: str, + user_id: str, + s3_box_name: str, + file_name: str, + data: str): + # имя новой файловой группы + file_group = str(uuid.uuid4()) + # локация для новой файловой группы и файла с фиксированным именем в ней + path = file_group + '/' + file_name + + url_prefix = f'/{app_name}/files/{s3_box_name}' + url_prefix = posixpath.join(url_prefix, path) + create_file_url = urllib.parse.urljoin(UNIP_FILES_API, url_prefix) + + res = await http_client.put(create_file_url, auth=(user_id, UNIP_FILES_USER_PASSWORD)) + if res.status_code != 200: + logger.error(f'Files API request error (create file with given name); PUT {create_file_url}; ' + f'Returned code: {res.status_code}') + logger.error(f'Response content {res.content}') + raise HTTPException(status_code=503, detail="Service unavailable") + + res_data = res.json() + put_url = res_data['presigned_put_url'] + binary_data = data.encode('utf-8') + data_len = len(data) + + headers = {'Content-Type': 'application/json', 'Content-Length': str(data_len)} + res = await http_client.put(put_url, content=binary_data, headers=headers, + auth=(user_id, UNIP_FILES_USER_PASSWORD)) + + if res.status_code != 201 and res.status_code != 200: + logger.error(f'S3 request error (put file content); PUT {put_url}; ' + f'Returned code: {res.status_code}') + logger.error(f'Response content {res.content}') + raise HTTPException(status_code=503, detail="Service unavailable") + + return file_group + + +def _get_validation_input_box_mount(user_id: str, + s3_box_name: str, + location: str, + mount_path: str) -> BoxMount: + bm = BoxMount() + bm.box_name = s3_box_name + bm.in_box_path = get_path_inside_box(user_id, location) + bm.read_only = False + bm.mount_path = mount_path + return bm + + +def _get_start_request_data_box_mount(user_id: str, + s3_box_name: str, + location: str) -> BoxMount: + mount_path = get_start_request_data_mount_path() + return _get_validation_input_box_mount(user_id, s3_box_name, location, mount_path) + + +def _get_validation_vars_data_box_mount(user_id: str, + s3_box_name: str, + location: str) -> BoxMount: + mount_path = get_validation_vars_data_mount_path() + return _get_validation_input_box_mount(user_id, s3_box_name, location, mount_path) + + +async def _filter_next_pipeline_request_data(api_client: ApiClient, + app_name: str, + next_pipeline_name: str, + trial_inputs: list[TrialInput] | None, + trial_output_vars: list[TrialOutputVar] | None): + if not next_pipeline_name or (not trial_inputs and not trial_output_vars): + return + openapi_spec_cache = OpenAPISpecCache.get_spec_cache() + api_resource = await get_api_resource(api_client=api_client, + app_name=app_name, + pipeline_name=next_pipeline_name) + pipeline_spec = await openapi_spec_cache.get_pipeline_api_spec(k8s_api_client=api_client, + app_name=app_name, + api_resource=api_resource) + + def _get_new_vars(trial_inputs_outputs, ctr_trial_inputs_outputs): + if trial_inputs_outputs: + if 'oneOf' not in ctr_trial_inputs_outputs: + new_trial_inputs_outputs = trial_inputs_outputs + else: + new_trial_inputs_outputs = [] + ctr_inputs_outputs_oneof = ctr_trial_inputs_outputs['oneOf'] + inputs_outputs_vars_names = [v['properties']['name']['const'] for v in ctr_inputs_outputs_oneof] + for v in trial_inputs_outputs: + if v.name in inputs_outputs_vars_names: + new_trial_inputs_outputs.append(v) + else: + new_trial_inputs_outputs = trial_inputs_outputs + return new_trial_inputs_outputs + + ctr = pipeline_spec['components']['schemas']['CreateTrialRequest'] + ctr_inputs = ctr['properties']['inputs']['items'] + ctr_output_vars = ctr['properties']['output_vars']['items'] + + new_trial_inputs = _get_new_vars(trial_inputs, ctr_inputs) + new_trial_output_vars = _get_new_vars(trial_output_vars, ctr_output_vars) + + return new_trial_inputs, new_trial_output_vars + + +async def _save_start_request_data(http_client: AsyncClient, + api_client: ApiClient, + app_name: str, + user_id: str, + pipeline_name: str, + next_pipeline_name: str, + connected_boxes: list[ConnectedBox], + passed_trial_inputs: list[TrialInput] | None, + passed_trial_output_vars: list[TrialOutputVar] | None) -> BoxMount: + if next_pipeline_name: + passed_trial_inputs, passed_trial_output_vars = await _filter_next_pipeline_request_data(api_client=api_client, + app_name=app_name, + next_pipeline_name=next_pipeline_name, + trial_inputs=passed_trial_inputs, + trial_output_vars=passed_trial_output_vars) + + request_data = CreateTrialRequest(inputs=passed_trial_inputs, + output_vars=passed_trial_output_vars) + str_data = request_data.model_dump_json(exclude_unset=True, + exclude_none=True) + box = get_default_box(user_id=user_id, + pipeline_name=pipeline_name, + connected_boxes=connected_boxes) + location = await _save_data_to_file(http_client=http_client, + app_name=app_name, + user_id=user_id, + s3_box_name=box.s3_box_name, + file_name=START_REQUEST_DATA_FILE_NAME, + data=str_data) + bm = _get_start_request_data_box_mount(user_id, box.name, location) + logger.info(f'App {app_name} pipeline {pipeline_name} user {user_id} request data saved ' + f'to s3 box {box.s3_box_name} to location {location}') + return bm + + +async def _save_validation_vars_data(http_client: AsyncClient, + app_name: str, + user_id: str, + pipeline_name: str, + connected_boxes: list[ConnectedBox], + trial_start_stages: list[TrialStartStage] | None, + next_pipeline_name: str | None) -> BoxMount: + stages_outputs = [] + if trial_start_stages: + for stage in trial_start_stages: + output_vars = set(o.name for o in stage.outputs) + tso = TrialStageOutput(stage_name=stage.name, output_vars=output_vars) + stages_outputs.append(tso) + vv = ValidationVars(trial_outputs=stages_outputs, next_pipeline=next_pipeline_name) + + str_data = vv.model_dump_json(exclude_none=True) + + box = get_default_box(user_id=user_id, + pipeline_name=pipeline_name, + connected_boxes=connected_boxes) + + location = await _save_data_to_file(http_client=http_client, + app_name=app_name, + user_id=user_id, + s3_box_name=box.s3_box_name, + file_name=VALIDATION_VARS_DATA_FILE_NAME, + data=str_data) + bm = _get_validation_vars_data_box_mount(user_id, box.name, location) + logger.info(f'App {app_name} pipeline {pipeline_name} user {user_id} validation vars data saved ' + f'to s3 box {box.s3_box_name} to location {location}') + return bm + + +def _get_internal_api_secret_name(app_name, pipeline_name, api_obj: dict): + secret_name = None + api_status = api_obj['status'] + if 'experimentPipeline' in api_status: + api_pipeline_status = api_status['experimentPipeline'] + secret_name = api_pipeline_status.get('internalApiSecretName', None) + if not secret_name: + logger.error(f'APIComponent for Pipeline {app_name}.{pipeline_name} has no internalApiSecretName specified') + raise HTTPException(status_code=503, detail="Service unavailable") + return secret_name + + +async def _construct_trial_start(http_client: AsyncClient, + api_client: ApiClient, + app_name: str, + user_id: str, + pipeline_name: str, + api_resource: dict, + pipeline_resource: dict, + passed_trial_inputs: list[TrialInput] | None, + pased_trial_output_vars: list[TrialOutputVar] | None) -> TrialStart: + pipeline_metadata = pipeline_resource['metadata'] + pipeline_spec = pipeline_resource['spec'] + pipeline_api_spec = api_resource['spec'] + + tracking_id = str(uuid4()) + + connected_boxes = [await construct_connected_box(api_client, cbs, app_name) + for cbs in pipeline_spec['connectedBoxes']] + + input_vars, output_vars, internal_vars = \ + await construct_start_vars(http_client=http_client, + app_name=app_name, + user_id=user_id, + pipeline_name=pipeline_name, + pipeline_api_spec=pipeline_api_spec, + pipeline_spec=pipeline_spec, + connected_boxes=connected_boxes, + passed_trial_inputs=passed_trial_inputs, + passed_trial_output_vars=pased_trial_output_vars) + + input_vars_by_name = {v.name: v for v in input_vars} + output_vars_by_name = {v.name: v for v in output_vars} + internal_vars_by_name = {v.name: v for v in internal_vars} + + trial_start_vars = TrialStartVars(inputs=input_vars, + outputs=output_vars, + internals=internal_vars) + + stages = [construct_start_stage(stage_section=stage_section, + input_vars_by_name=input_vars_by_name, + output_vars_by_name=output_vars_by_name, + internal_vars_by_name=internal_vars_by_name) + for stage_section in pipeline_spec['stages']] + img_reg_creds = _get_image_registries_creds(stages) + + next_pipeline_name = None + if 'continueWith' in pipeline_spec: + next_pipeline_name = pipeline_spec['continueWith']['name'] + + start_request_bm = await _save_start_request_data(http_client=http_client, + api_client=api_client, + app_name=app_name, + user_id=user_id, + pipeline_name=pipeline_name, + next_pipeline_name=next_pipeline_name, + connected_boxes=connected_boxes, + passed_trial_inputs=passed_trial_inputs, + passed_trial_output_vars=pased_trial_output_vars) + + validation_vars_bm = await _save_validation_vars_data(http_client=http_client, + app_name=app_name, + user_id=user_id, + pipeline_name=pipeline_name, + connected_boxes=connected_boxes, + trial_start_stages=stages, + next_pipeline_name=next_pipeline_name) + + internal_api_secret = _get_internal_api_secret_name(app_name, pipeline_name, api_resource) + + validation_input = ValidationInput(start_request=start_request_bm, + validation_vars=validation_vars_bm, + internal_api_secret=internal_api_secret) + now = datetime.now(timezone.utc).strftime(UNIP_DATETIME_FORMAT) + status = TrialStatus(conditions=[StatusCondition(type="Started", + condition_status='True', + last_transition_time=now)], + status_date_time=now) + + return TrialStart(app_name=app_name, + user_id=user_id, + tracking_id=tracking_id, + pipeline_name=pipeline_name, + pipeline_version=pipeline_metadata['resourceVersion'], + next_pipeline_name=next_pipeline_name, + connected_boxes=connected_boxes, + stages=stages, + vars=trial_start_vars, + image_registries_creds=img_reg_creds, + status=status, + validation_input=validation_input) + + +def _construct_volume_mount(box_mount: BoxMount) -> dict: + vm = { + 'volume_name': box_mount.box_name.replace('_', '-'), + 'mount_path': box_mount.mount_path, + 'read_only': box_mount.read_only, + 'sub_path': box_mount.in_box_path + } + return vm + + +def _get_config_volume_name(stage: TrialStartStage, config_from: StartConfigFrom): + base_name = stage.name.replace('_', '-') + + if config_from.source_kind == 'Secret': + source_kind_segment = '-secret-' + elif config_from.source_kind == 'ConfigMap': + source_kind_segment = '-cm-' + else: + logger.error(f'Unknown config kind {config_from.source_kind}') + raise HTTPException(status_code=503, detail="Service unavailable") + + idx = next((i for i, cf in enumerate(stage.config_from) if cf is config_from), None) + name = base_name + source_kind_segment + config_from.source_name.replace('_', '-') + '-vol-' + str(idx) + return name + + +def _construct_config_volume_mount(stage: TrialStartStage, config_from: StartConfigFrom): + vm = { + 'volume_name': _get_config_volume_name(stage, config_from), + 'mount_path': config_from.mount_path, + 'read_only': True + } + return vm + + +def _construct_stage_volume_mounts(stage: TrialStartStage) -> list[dict]: + res = [] + + for stage_var in stage.inputs + stage.outputs: + vm = _construct_volume_mount(stage_var.box_mount) + res.append(vm) + + for config_from in stage.config_from: + vm = _construct_config_volume_mount(stage, config_from) + res.append(vm) + + return res + + +def _construct_stage_resource_limits(stage: TrialStartStage) -> dict: + rl = { + 'cpu': stage.comp_resources.cpu, + 'memory': stage.comp_resources.memory + } + if stage.comp_resources.gpu: + rl['gpu'] = stage.comp_resources.gpu + return rl + + +def _construct_stage_resource_requests(stage: TrialStartStage) -> dict: + rr = { + 'cpu': "0m" + } + if stage.comp_resources.gpu: + rr['gpu'] = stage.comp_resources.gpu + return rr + + +def _construct_stage_env_vars(trial_start: TrialStart, stage: TrialStartStage) -> list[dict]: + res_model = [] + inputs_names = [] + all_stage_vars = stage.inputs + stage.outputs + for psv in all_stage_vars: + var_name = psv.name.replace('-', '_') + var_env_var_name = ENV_VAR_PREFIX + var_name.upper() + var_env_var_val = os.path.join('/', psv.box_mount.mount_path) + res_model.append({ + 'name': var_env_var_name, + 'value': var_env_var_val + }) + + if psv.content_type: + ct_env_var_name = ENV_VAR_PREFIX + var_name.upper() + ENV_VAR_CONTENT_TYPE_SUFFIX + res_model.append({ + 'name': ct_env_var_name, + 'value': psv.content_type + }) + + if psv.shape: + shape_env_var_name = ENV_VAR_PREFIX + var_name.upper() + ENV_VAR_SHAPE_SUFFIX + res_model.append({ + 'name': shape_env_var_name, + 'value': psv.shape + }) + + inputs_names.append(var_name) + + res_model.append({ + 'name': VAR_LIST_ENV_VAR, + 'value': ','.join(inputs_names) + }) + + if stage.env_vars: + for ev in stage.env_vars: + res_model.append({'name': ev.name, + 'value': ev.value}) + + tenvs = _get_client_env_vars(trial_start) + res_model += tenvs + return res_model + + +def _construct_stage_env_from(stage: TrialStartStage) -> list[dict]: + res_model = [{'key': ef.key, 'body': ef.body} for ef in stage.env_from] + return res_model + + +def _get_client_env_vars(trial_start: TrialStart) -> list[dict]: + env = [ + { + 'name': TRACKING_ID_VAR_NAME, + 'value': trial_start.tracking_id + }, + { + 'name': API_VAR_NAME, + 'value': UNIP_PIPELINES_API + }, + { + 'name': APP_NAME_VAR_NAME, + 'value': trial_start.app_name + }, + { + 'name': PIPELINE_VAR_NAME, + 'value': trial_start.pipeline_name + } + ] + return env + + +def _construct_validation_model(trial_start: TrialStart) -> dict: + stages = trial_start.stages + + volume_mounts = [] + for s in stages: + for output_var in s.outputs: + box_mount = output_var.box_mount + vm = { + 'volume_name': box_mount.box_name.replace('_', '-'), + 'mount_path': get_output_var_validation_mount_path(s.name, output_var.name), + 'read_only': True, + 'sub_path': box_mount.in_box_path + } + volume_mounts.append(vm) + + start_request_bm = trial_start.validation_input.start_request + vm = { + 'volume_name': start_request_bm.box_name.replace('_', '-'), + 'mount_path': start_request_bm.mount_path, + 'read_only': True, + 'sub_path': start_request_bm.in_box_path + } + volume_mounts.append(vm) + + validation_vars_bm = trial_start.validation_input.validation_vars + vm = { + 'volume_name': validation_vars_bm.box_name.replace('_', '-'), + 'mount_path': validation_vars_bm.mount_path, + 'read_only': True, + 'sub_path': validation_vars_bm.in_box_path + } + volume_mounts.append(vm) + + vm = { + 'volume_name': _VALIDATION_CONTAINER_INTERNAL_API_SECRET_VOLUME, + 'mount_path': get_internal_api_secret_mount_path(), + 'read_only': True + } + volume_mounts.append(vm) + + env = _get_client_env_vars(trial_start) + + resource_limits = { + 'cpu': _VALIDATION_CONTAINER_RESOURCE_CPU, + 'memory': _VALIDATION_CONTAINER_RESOURCE_MEMORY + } + + validation_model = { + 'image_name': UNIP_PIPELINE_VALIDATION_IMAGE, + 'volume_mounts': volume_mounts, + 'env': env, + 'env_from': None, + 'resource_limits': resource_limits + } + + return validation_model + + +def _construct_tolerations(trial_start: TrialStart) -> list[dict] | None: + tolerations = [{ + 'key': IS_INTERRUPTIBLE_TAINT_NAME, + 'operator': 'Equal', + 'value': 'true', + 'effect': 'NoSchedule' + }] + + if not any(s.comp_resources.gpu for s in trial_start.stages): + return tolerations + + tolerations.append({ + 'key': IS_GPU_AVAILABLE_TAINT_NAME, + 'operator': 'Equal', + 'value': 'true', + 'effect': 'NoSchedule' + }) + return tolerations + + +def _construct_node_affinity(trial_start: TrialStart) -> dict | None: + pipeline_expr = {'key': PIPELINE_NODE_LABEL_NAME, 'operator': 'In', 'vals': ['true']} + node_affinity = {'expressions': [pipeline_expr]} + gpu_required = any(s.comp_resources.gpu for s in trial_start.stages) + if not gpu_required: + return node_affinity + gpu_expr = {'key': GPU_LABEL_NAME, 'operator': 'In', 'vals': ['true']} + node_affinity['expressions'].append(gpu_expr) + return node_affinity + + +def _construct_config_volumes(trial_start: TrialStart): + volumes = [] + stages = trial_start.stages + for stage in stages: + for config_from in stage.config_from: + + if config_from.source_kind == 'Secret': + volume_det = 'secret' + elif config_from.source_kind == 'ConfigMap': + volume_det = 'configmap' + else: + logger.error(f'Unknown config kind {config_from.source_kind}') + raise HTTPException(status_code=503, detail="Service unavailable") + + volume_name = _get_config_volume_name(stage, config_from) + + volume_items = [{'key': i.key, 'path': i.mount_sub_path} for i in config_from.items] \ + if config_from.items else None + volume_det_field = volume_det + '_name' + volume = { + 'volume_name': volume_name, + volume_det_field: config_from.source_name + } + if volume_items: + volume['volume_items'] = volume_items + volumes.append(volume) + + return volumes + + +def _construct_trial_manifest_model(trial_start: TrialStart) -> dict: + stages = trial_start.stages + stages_model = [ + { + 'name': s.name, + 'image': s.image.name, + 'cmd': s.entry_point.cmd if s.entry_point else None, + 'volume_mounts': _construct_stage_volume_mounts(s), + 'resource_limits': _construct_stage_resource_limits(s), + 'resource_requests': _construct_stage_resource_requests(s), + 'env': _construct_stage_env_vars(trial_start, s), + 'env_from': _construct_stage_env_from(s) + } + for s in stages + ] + trial_boxes = trial_start.connected_boxes + + volumes = [ + { + 'volume_name': ps.name.replace('_', '-'), + 'pvc_name': ps.pvc_name + } + for ps in trial_boxes + ] + internal_api_secret_vol = {'volume_name': _VALIDATION_CONTAINER_INTERNAL_API_SECRET_VOLUME, + 'secret_name': trial_start.validation_input.internal_api_secret} + volumes.append(internal_api_secret_vol) + config_volumes = _construct_config_volumes(trial_start) + volumes += config_volumes + job_name = f'pipeline-{trial_start.pipeline_name}-{str(uuid4())}' + validation_model = _construct_validation_model(trial_start) if UNIP_PIPELINE_RUN_MODE != 'Debug' else None + annotations = {TRACKING_ID_ANNO_NAME: trial_start.tracking_id} + labels = {TRACKING_ID_LABEL_NAME: trial_start.tracking_id} + trial_model = { + 'job_name': job_name, + 'namespace': trial_start.app_name, + 'annotations': annotations, + 'labels': labels, + 'stages': stages_model, + 'volumes': volumes, + 'image_reg_creds': trial_start.image_registries_creds, + 'validation': validation_model, + 'tolerations': _construct_tolerations(trial_start), + 'node_affinity': _construct_node_affinity(trial_start) + } + return trial_model + + +async def _schedule_trial(api_client: ApiClient, trial_start: TrialStart): + batch_v1_api = BatchV1Api(api_client) + manifest_model = _construct_trial_manifest_model(trial_start) + manifest = _prepare_manifest('simple-pipeline-trial.yaml', manifest_model) + await batch_v1_api.create_namespaced_job(trial_start.app_name, manifest) + + +async def _save_pipeline_trial(db: AsyncSession, trial_start: TrialStart) -> int: + inputs = [TrialVar(name=i.name, + box_name=i.box_path.box.s3_box_name, + data=i.files_location, + datatype=i.datatype, + content_type=i.content_type) for i in trial_start.vars.inputs + if i.files_location is not None] + outputs = [TrialVar(name=o.name, + box_name=o.box_path.box.s3_box_name, + data=o.files_location, + datatype=o.datatype, + content_type=o.content_type) for o in trial_start.vars.outputs] + tv = TrialVars(inputs=inputs, outputs=outputs) + + ptm = PipelineTrialModel() + ptm.user_id = trial_start.user_id + ptm.app_name = trial_start.app_name + ptm.tracking_id = trial_start.tracking_id + ptm.pipeline_name = trial_start.pipeline_name + ptm.pipeline_version = trial_start.pipeline_version + ptm.next_pipeline_name = trial_start.next_pipeline_name + ptm.vars = tv.model_dump() + ptm.status = trial_start.status.model_dump() + + db.add(ptm) + + await db.commit() + + return ptm.id + + +def _prepare_trial_query(q: Select | None = None, + app_name: str | None = None, + pipeline_name: str | None = None, + user_id: str | None = None) -> Select: + query = q if q is not None else select(PipelineTrialModel) + if app_name: + query = query.where(PipelineTrialModel.app_name == app_name) + if pipeline_name: + query = query.where(PipelineTrialModel.pipeline_name == pipeline_name) + if user_id: + query = query.where(PipelineTrialModel.user_id == user_id) + return query + + +async def _get_trial_model(db: AsyncSession, + tracking_id: str, + app_name: str | None = None, + pipeline_name: str | None = None, + user_id: str | None = None, + for_update: bool = False) -> PipelineTrialModel | None: + query = select(PipelineTrialModel) \ + .where(PipelineTrialModel.tracking_id == tracking_id) + query = _prepare_trial_query(query, app_name, pipeline_name, user_id) + if for_update: + query = query.with_for_update() + result = (await db.execute(query)).first() + ptm: PipelineTrialModel = result[0] if result else None + + return ptm + + +async def _get_trials_models(db: AsyncSession, + app_name: str | None = None, + pipeline_name: str | None = None, + user_id: str | None = None, + cursor: int | None = None, + limit: int | None = None) -> \ + tuple[Sequence[PipelineTrialModel], int | None, tuple[int, int]]: + if not limit: + limit = 10 + # main query + base_query = _prepare_trial_query(None, app_name, pipeline_name, user_id) + query = base_query + if cursor: + query = query.where(PipelineTrialModel.id <= cursor) + query = query.order_by(PipelineTrialModel.id.desc()) + query = query.limit(limit + 1) + rows = (await db.execute(query)).all() + items: Sequence[PipelineTrialModel] = [r[0] for r in rows] + + if len(items) == limit + 1: + new_cursor = items[-2].id - 1 + items = items[:-1] + else: + new_cursor = None + + if new_cursor: + count_next_query = base_query.where(PipelineTrialModel.id <= new_cursor) + count_next_query = select(func.count()).select_from(count_next_query.subquery()) + count_next = (await db.execute(count_next_query)).scalar_one() + else: + count_next = 0 + + count_total_query = select(func.count()).select_from(base_query.subquery()) + total_count = (await db.execute(count_total_query)).scalar_one() + + counts = total_count, count_next + + return items, new_cursor, counts + + +def _get_trial_links(pt: PipelineTrialModel | PipelineTrial): + self_href = urllib.parse.urljoin(f'https://{UNIP_DOMAIN}', f'{pt.app_name}/trials/{pt.tracking_id}') + self_link = Link(href=self_href) + pipeline_href = urllib.parse.urljoin(f'https://{UNIP_DOMAIN}', f'{pt.app_name}/pipelines/{pt.pipeline_name}') + pipeline_link = Link(href=pipeline_href) + next_trial_link = None + if pt.next_tracking_id: + next_trial_href = urllib.parse.urljoin(f'https://{UNIP_DOMAIN}', f'{pt.app_name}/trials/{pt.next_tracking_id}') + next_trial_link = Link(href=next_trial_href) + tl = TrialLinks(self=self_link, pipeline=pipeline_link, next_trial=next_trial_link) + return tl + + +async def get_trial_user_id(db: AsyncSession, + tracking_id: str, + app_name: str | None = None, + pipeline_name: str | None = None) -> str: + ptm = await _get_trial_model(db=db, + tracking_id=tracking_id, + app_name=app_name, + pipeline_name=pipeline_name) + if not ptm: + raise HTTPException(status_code=404, detail="Pipeline trial not found") + + return ptm.user_id + + +async def get_trial(db: AsyncSession, + tracking_id: str, + app_name: str | None = None, + pipeline_name: str | None = None, + user_id: str | None = None) -> PipelineTrial: + ptm = await _get_trial_model(db=db, + tracking_id=tracking_id, + app_name=app_name, + pipeline_name=pipeline_name, + user_id=user_id) + if not ptm: + raise HTTPException(status_code=404, detail="Pipeline trial not found") + + tl = _get_trial_links(ptm) + # todo: PipelineTrial используется и как модель ответа, + # возможно возвращать из модуля pipeline.py PipelineTrialModel, + # собирать PipelineTrial в api.py + pt = PipelineTrial.model_validate(ptm) + pt.links = tl + + return pt + + +async def list_trials(db: AsyncSession, + app_name: str | None = None, + pipeline_name: str | None = None, + user_id: str | None = None, + cursor: int | None = None, + limit: int | None = None) -> tuple[list[PipelineTrial], int | None, tuple[int, int]]: + ptms, new_cursor, counts = await _get_trials_models(db=db, + app_name=app_name, + pipeline_name=pipeline_name, + user_id=user_id, + cursor=cursor, + limit=limit) + + pts = [] + for ptm in ptms: + tl = _get_trial_links(ptm) + pt = PipelineTrial.model_validate(ptm) + pt.links = tl + pts.append(pt) + + return pts, new_cursor, counts + + +async def add_condition_to_status(db: AsyncSession, + tracking_id: str, + type_: str, + message: str, + reason: str, + transition_time: datetime | None, + stage: str | None, + app_name: str | None = None, + pipeline_name: str | None = None): + ptm = await _get_trial_model(db=db, + tracking_id=tracking_id, + app_name=app_name, + pipeline_name=pipeline_name, + for_update=True) + + if not ptm: + raise HTTPException(status_code=404, detail="Pipeline trial not found") + + ts = TrialStatus.model_validate(ptm.status) + + if any(c.type == type_ for c in ts.conditions): + logger.info(f'Pipeline {app_name}.{pipeline_name} trial {tracking_id} ' + f'status condition {type_} already set') + return False + + if transition_time is None: + transition_time = datetime.now(timezone.utc) + else: + transition_time = transition_time.astimezone(tz=timezone.utc) + + transition_time = transition_time.strftime(UNIP_DATETIME_FORMAT) + + new_condition = StatusCondition(type=type_, + condition_status='True', + last_transition_time=transition_time, + message=message, + reason=reason, + stage=stage) + ts.conditions.append(new_condition) + ts.status_date_time = transition_time + + ptm.status = ts.model_dump() + flag_modified(ptm, 'status') + + await db.commit() + logger.info(f'Pipeline {app_name}.{pipeline_name} trial {tracking_id} ' + f'status condition {type_} added') + + return True + + +async def _get_pipelines_api_access_creds(api: ApiClient, namespace, pipeline_name, api_resource): + core_v1_api = CoreV1Api(api) + + secret_name = _get_internal_api_secret_name(namespace, pipeline_name, api_resource) + + try: + secret: V1Secret = await core_v1_api.read_namespaced_secret(name=secret_name, + namespace=namespace) + secret_body = secret.to_dict() + except ApiException as exc: + if exc.status == 404: + logger.error(f'APIComponent for Pipeline {namespace}.{pipeline_name} not found') + raise HTTPException(status_code=503, detail="Service unavailable") + raise exc + + if 'data' not in secret_body: + logger.error(f'Pipeline {namespace}.{pipeline_name} secret {secret_name} has no data' + f' to access internal Pipelines API') + raise HTTPException(status_code=503, detail="Service unavailable") + data = secret_body['data'] + credentials = data.get('credentials', None) + if not credentials: + logger.error(f'Pipeline {namespace}.{pipeline_name} internal API access secret {secret_name} ' + f'field "credentials" not set or empty') + raise HTTPException(status_code=503, detail="Service unavailable") + + try: + user_id, user_password = get_basic_auth_credentials(credentials) + return user_id, user_password + except Exception as exc: + logger.error(f'Pipeline {namespace}.{pipeline_name} internal API access secret {secret_name} ' + f'field "credentials" has wrong format', exc_info=exc) + raise HTTPException(status_code=503, detail="Service unavailable") + + +async def _check_pipelines_api_access(http_client: AsyncClient, api: ApiClient, app_name, pipeline_name, api_resource): + user_id, user_password = await _get_pipelines_api_access_creds(api, app_name, pipeline_name, api_resource) + check_uri = f'/{app_name}/pipelines/{pipeline_name}/check' + get_url = urllib.parse.urljoin(UNIP_PIPELINES_API, check_uri) + + res = await http_client.get(get_url, auth=(user_id, user_password)) + if res.status_code in {200}: + logger.info(f'Pipeline {app_name}.{pipeline_name} internal API is available and access is allowed') + return + if res.status_code in {401, 403}: + logger.info(f'Cannot access pipeline {app_name}.{pipeline_name} internal API; ' + f'code: {res.status_code}; response: {res.text}') + raise HTTPException(status_code=503, detail="Service unavailable") + + logger.error(f'Unexpected response on pipeline {app_name}.{pipeline_name} internal API access check;' + f'code: {res.status_code}; response: {res.text}') + raise HTTPException(status_code=503, detail="Service unavailable") + + +async def start_trial(db: AsyncSession, + http_client: AsyncClient, + api_client: ApiClient, + app_name: str, + user_id: str, + pipeline_name: str, + api_resource: dict, + pipeline_resource: dict, + trial_inputs: list[TrialInput] | None, + trial_output_vars: list[TrialOutputVar] | None) -> PipelineTrial: + await _check_pipelines_api_access(http_client, api_client, app_name, pipeline_name, api_resource) + trial_start = await _construct_trial_start(http_client=http_client, + api_client=api_client, + app_name=app_name, + user_id=user_id, + pipeline_name=pipeline_name, + api_resource=api_resource, + pipeline_resource=pipeline_resource, + passed_trial_inputs=trial_inputs, + pased_trial_output_vars=trial_output_vars) + # сохраняется в базу перед запуском, чтобы гарантировать, + # что в базе есть запись во время выполнения триала (последний шаг валидации обращается к API) + await _save_pipeline_trial(db, trial_start) + await _schedule_trial(api_client, trial_start) + trial = await get_trial(db=db, + app_name=app_name, + pipeline_name=pipeline_name, + user_id=user_id, + tracking_id=trial_start.tracking_id) + + tl = _get_trial_links(trial) + trial.links = tl + return trial + + +def _append_condition(ptm: PipelineTrialModel, condition_type: str): + current_status = ptm.status + + existing_conditions = None + if 'conditions' in current_status: + existing_conditions = [c for c in current_status['conditions'] + if c['type'] == condition_type] + else: + current_status['conditions'] = [] + + if existing_conditions: + return + + now = datetime.now(timezone.utc) + transition_time = now.strftime(UNIP_DATETIME_FORMAT) + new_condition = StatusCondition(type=condition_type, + condition_status='True', + last_transition_time=transition_time) + new_condition_dump = new_condition.model_dump() + + current_status['conditions'].append(new_condition_dump) + current_status['status_date_time'] = transition_time + flag_modified(ptm, 'status') + + +async def _get_tracking_id_from_job(api_client: ApiClient, + job_name: str, + job_namespace: str): + batch_v1_api = BatchV1Api(api_client) + try: + job_res = await batch_v1_api.read_namespaced_job(name=job_name, namespace=job_namespace) + except ApiException as exc: + if exc.status == 404: + raise ObjectDoesNotExistPermanentError(f'Job {job_name} doesnt exist in namespace {job_namespace}') + raise exc + job_res = job_res.to_dict() + job_metadata = job_res['metadata'] + if 'annotations' not in job_metadata: + raise RelatedObjectValuePermanentError(f'Job {job_name} in namespace {job_namespace} doesnt have ' + f'annotations') + job_anno = job_metadata['annotations'] + if TRACKING_ID_ANNO_NAME not in job_anno: + raise RelatedObjectValuePermanentError(f'Annotation {TRACKING_ID_ANNO_NAME} doesnt exist in ' + f'job {job_name} in namespace {job_namespace}') + tracking_id = job_anno[TRACKING_ID_ANNO_NAME] + return tracking_id + + +async def _set_trial_status_condition(db: AsyncSession, + api_client: ApiClient, + job_name: str, + job_namespace: str, + condition_type: str): + tracking_id = await _get_tracking_id_from_job(api_client, job_name, job_namespace) + + ptm = await _get_trial_model(db=db, + tracking_id=tracking_id, + app_name=job_namespace, + for_update=True) + + if not ptm: + raise ObjectDoesNotExistPermanentError(f'Pipeline trial given tracking_id \'{tracking_id}\' not found') + + _append_condition(ptm, condition_type) + + await db.commit() + + +async def set_trial_completed(db: AsyncSession, + api_client: ApiClient, + job_name: str, + job_namespace: str): + await _set_trial_status_condition(db=db, api_client=api_client, + job_name=job_name, + job_namespace=job_namespace, + condition_type="Completed") + + +async def set_trial_failed(db: AsyncSession, + api_client: ApiClient, + job_name: str, + job_namespace: str): + await _set_trial_status_condition(db=db, api_client=api_client, + job_name=job_name, + job_namespace=job_namespace, + condition_type="Failed") + + +async def set_next_started(db: AsyncSession, + tracking_id: str, + app_name: str, + pipeline_name: str, + next_tracking_id: str): + ptm = await _get_trial_model(db=db, + tracking_id=tracking_id, + app_name=app_name, + pipeline_name=pipeline_name, + for_update=True) + + if not ptm: + raise HTTPException(status_code=404, detail="Pipeline trial not found") + + ptm.next_tracking_id = next_tracking_id + _append_condition(ptm, "NextStarted") + await db.commit() diff --git a/controller/src/exp_pipeline/results/__init__.py b/controller/src/exp_pipeline/results/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/controller/src/exp_pipeline/results/main.py b/controller/src/exp_pipeline/results/main.py new file mode 100644 index 0000000..daad44a --- /dev/null +++ b/controller/src/exp_pipeline/results/main.py @@ -0,0 +1,17 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: ExperimentPipeline +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +from exp_pipeline.logs import configure_logging +from exp_pipeline.results.validate_trial_results import validate_trial_results, \ + start_next_pipeline, add_status_condition, get_internal_api_credentials + +if __name__ == '__main__': + configure_logging() + user_id, user_password = get_internal_api_credentials() + status_condition, validated, next_pipeline_name = validate_trial_results() + add_status_condition(status_condition, user_id, user_password) + if validated and next_pipeline_name: + start_next_pipeline(next_pipeline_name, user_id, user_password) diff --git a/controller/src/exp_pipeline/results/validate_trial_results.py b/controller/src/exp_pipeline/results/validate_trial_results.py new file mode 100644 index 0000000..a449036 --- /dev/null +++ b/controller/src/exp_pipeline/results/validate_trial_results.py @@ -0,0 +1,170 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: ExperimentPipeline +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +import json +import logging +import os +import urllib.parse + +import requests + +from exp_pipeline.client_config import UNIP_PIPELINE_API, UNIP_TRACKING_ID, \ + UNIP_PIPELINE_APP_NAME, UNIP_PIPELINE_PIPELINE_NAME +from exp_pipeline.schema import CreateStatusConditionRequest + + +START_REQUEST_DATA_FILE_NAME = 'request.json' +VALIDATION_VARS_DATA_FILE_NAME = 'validation-vars.json' + +logger = logging.getLogger(__name__) + + +def get_output_var_validation_mount_path(stage_name: str, output_var_name: str): + return f'/stages/{stage_name}/outputs/{output_var_name}' + + +def get_start_request_data_mount_path(): + return f'/start_request' + + +def get_validation_vars_data_mount_path(): + return f'/validation_vars' + + +def get_internal_api_secret_mount_path(): + return f'/internal_api_secret' + + +def _validate_trial_outputs(trial_outputs): + outputs_are_validated = True + index = 0 + while index < len(trial_outputs) and outputs_are_validated: + stage = trial_outputs[index] + index += 1 + stage_name = stage["stage_name"] + logger.info(f'stage {stage_name} outputs:') + logger.info(stage["output_vars"]) + for output_var in stage["output_vars"]: + mount_path = get_output_var_validation_mount_path(stage_name, output_var) + results = os.listdir(mount_path) + logger.info(f'stage {stage_name} output name {output_var} files:') + logger.info(results) + if not results: + outputs_are_validated = False + break + return outputs_are_validated + + +def _get_status_condition_type(results_are_validated): + type_ = "OutputsAreValidated" if results_are_validated else "OutputsErrors" + return type_ + + +def start_next_pipeline(next_pipeline_name, user_id, user_password): + app_name = UNIP_PIPELINE_APP_NAME + pipeline_name = UNIP_PIPELINE_PIPELINE_NAME + next_trial_uri = f'/{app_name}/pipelines/{pipeline_name}/trials/continue' + post_url = urllib.parse.urljoin(UNIP_PIPELINE_API, next_trial_uri) + + logger.info(f'Starting next pipeline {next_pipeline_name}...') + + rd_dir = get_start_request_data_mount_path() + logger.info('Listing request data dir:') + logger.info('\n'.join(os.listdir(rd_dir))) + request_data_path = os.path.join(rd_dir, START_REQUEST_DATA_FILE_NAME) + with open(request_data_path) as f: + request_data = f.read().strip() + + params = {'tracking_id': UNIP_TRACKING_ID, 'next_pipeline_name': next_pipeline_name} + + logger.info(f'Requesting URL {post_url}') + response = requests.post(post_url, params=params, data=request_data, auth=(user_id, user_password)) + + if response.status_code != 201 and response.status_code != 200: + logger.error(f'Pipelines API error (start new trial); POST {post_url}; ' + f'Returned code: {response.status_code}') + logger.error(response.status_code) + logger.error(response.content) + return + + logger.info('Response:') + logger.info(response.status_code) + logger.info(response.content) + + +def _read_validation_vars(): + vv_dir = get_validation_vars_data_mount_path() + logger.info('Listing validation vars dir:') + logger.info('\n'.join(os.listdir(vv_dir))) + vv_data_path = os.path.join(vv_dir, VALIDATION_VARS_DATA_FILE_NAME) + logger.info(f'Reading {vv_data_path}...') + with open(vv_data_path) as f: + vv = json.load(f) + next_pipeline_name = vv.get('next_pipeline') + logger.info(f'Validation vars file content:\n{vv}') + return vv['trial_outputs'], next_pipeline_name + + +def validate_trial_results() -> tuple[str, bool, str]: + trial_outputs, next_pipeline_name = _read_validation_vars() + + outputs_are_validated = _validate_trial_outputs(trial_outputs) + + sct = _get_status_condition_type(outputs_are_validated) + + return sct, outputs_are_validated, next_pipeline_name + + +def _get_basic_auth_credentials(credentials_lines: str) -> tuple[str, str]: + records = credentials_lines.split('\n') + first_record = records[0] + sep_index = first_record.find(':') + user_id, user_password = first_record[:sep_index], first_record[sep_index + 1:] + return user_id, user_password + + +def _read_internal_api_credentials(path): + try: + with open(path) as f: + creds_lines = f.read() + user_id, user_password = _get_basic_auth_credentials(creds_lines) + return user_id, user_password + except IOError as exc: + logger.error(f'Error reading internal API credentials file {path}', exc_info=exc) + return None + except Exception as exc: + logger.error(f'Error parsing internal API credentials file {path}', exc_info=exc) + return None + + +def get_internal_api_credentials(): + cred_dir = get_internal_api_secret_mount_path() + cred_path = os.path.join(cred_dir, 'credentials') + if not os.path.exists(cred_path): + logger.error(f'Internal API credentials path {cred_path} doesnt exist') + return None + if not os.path.isfile(cred_path): + logger.error(f'Internal API credentials path {cred_path} is not file') + return None + user_id, user_password = _read_internal_api_credentials(cred_path) + return user_id, user_password + + +def add_status_condition(type_: str, user_id, user_password): + app_name = UNIP_PIPELINE_APP_NAME + pipeline_name = UNIP_PIPELINE_PIPELINE_NAME + tracking_id = UNIP_TRACKING_ID + conditions_uri = f'/{app_name}/pipelines/{pipeline_name}/trials/{tracking_id}/status/conditions' + post_url = urllib.parse.urljoin(UNIP_PIPELINE_API, conditions_uri) + request = CreateStatusConditionRequest(type=type_) + payload = request.model_dump_json() + logger.info('Adding status condition to trial:') + logger.info(conditions_uri) + logger.info(payload) + resp = requests.post(post_url, data=payload, auth=(user_id, user_password)) + logger.info('Response:') + logger.info(resp.status_code) + logger.info(resp.content) diff --git a/controller/src/exp_pipeline/schema.py b/controller/src/exp_pipeline/schema.py new file mode 100644 index 0000000..b43b396 --- /dev/null +++ b/controller/src/exp_pipeline/schema.py @@ -0,0 +1,298 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: ExperimentPipeline +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +from typing import Literal + +from pydantic import BaseModel, ConfigDict, Field, AwareDatetime + +DATATYPES = Literal["FILE", "FP32", "FP64", "INT32", "dict", "str", "WEBSITE"] +OUTPUT_DATATYPES = Literal["FILE", "WEBSITE"] +DATATYPE_TO_CONTENT_TYPE = {'FP32': 'application/json', + 'FP64': 'application/json', + 'INT32': 'application/json', + 'dict': 'application/json', + 'str': 'application/json', + 'WEBSITE': 'text/html'} + + +class Link(BaseModel): + href: str + templated: bool | None = None + + +class ConnectedBox(BaseModel): + name: str + mode: str + dataset_ref_box_name: str | None = None + s3_box_name: str | None = None + pvc_name: str + # это путь куда монтировать ящик в контейнер, для ящика по умолчанию + # (если не указано явно для переменной) + mount_path: str = None + default: bool = False + + +class TrialInput(BaseModel): + name: str + data: object + datatype: DATATYPES + content_type: str | None = None + shape: list[int] | int | None = None + + +class TrialOutputVar(BaseModel): + name: str + data: str | None = None + datatype: OUTPUT_DATATYPES | None = None + content_type: str | None = None + + +class EntryPoint(BaseModel): + cmd: list[str] + + +class BoxMount(BaseModel): + box_name: str = None + mount_path: str = None + in_box_path: str = None + read_only: bool = None + + +class StartStageVar(BaseModel): + name: str + box_mount: BoxMount + content_type: str | None = None + shape: str | None = None + + +class StartStageImage(BaseModel): + name: str + registry_name: str + credentials_name: str + + +class StartEnvVar(BaseModel): + name: str + value: str + + +class StartEnvFrom(BaseModel): + key: str + body: str + + +class StartConfigFromItem(BaseModel): + key: str + mount_sub_path: str + + +class StartConfigFrom(BaseModel): + mount_path: str + source_kind: str + source_name: str + items: list[StartConfigFromItem] | None = None + + +class StartVarBoxPath(BaseModel): + in_box_path: str + mount_path: str | None = None + box: ConnectedBox + + +class TrialVar(BaseModel): + name: str + box_name: str + data: str + datatype: str | None = None # datatype is required, but remains optional for backward compatibility + content_type: str | None = None + + +class TrialStartVar(BaseModel): + name: str + box_path: StartVarBoxPath + files_location: str | None = None + datatype: str + content_type: str | None = None + shape: int | list[int] | None = None + + +class StartStageCompResources(BaseModel): + cpu: str + memory: str + gpu: str | None = None + + +class TrialStartStage(BaseModel): + name: str + image: StartStageImage | None = None + inputs: list[StartStageVar] + outputs: list[StartStageVar] + entry_point: EntryPoint | None = None + env_vars: list[StartEnvVar] | None = None + env_from: list[StartEnvFrom] | None = None + config_from: list[StartConfigFrom] | None = None + comp_resources: StartStageCompResources + + +class TrialVars(BaseModel): + inputs: list[TrialVar] + outputs: list[TrialVar] + + +class TrialStartVars(BaseModel): + inputs: list[TrialStartVar] + outputs: list[TrialStartVar] + internals: list[TrialStartVar] + + +class StatusCondition(BaseModel): + type: str + condition_status: Literal["True", "False", "Unknown"] + last_transition_time: str + message: str = "" + reason: str = "" + stage: str | None = None + + +class TrialStatus(BaseModel): + conditions: list[StatusCondition] + status_date_time: str | None = None + + +class TrialStageOutput(BaseModel): + stage_name: str + output_vars: list[str] + + +class ValidationVars(BaseModel): + trial_outputs: list[TrialStageOutput] + next_pipeline: str | None = None + + +class ValidationInput(BaseModel): + start_request: BoxMount + validation_vars: BoxMount + internal_api_secret: str + + +class TrialStart(BaseModel): + app_name: str + user_id: str + tracking_id: str + pipeline_name: str + pipeline_version: str + next_pipeline_name: str | None + stages: list[TrialStartStage] + vars: TrialStartVars + connected_boxes: list[ConnectedBox] + image_registries_creds: list[str] + status: TrialStatus + validation_input: ValidationInput + + +class TrialLinks(BaseModel): + self: Link + pipeline: Link + next_trial: Link | None + + +class PipelineTrial(BaseModel): + model_config = ConfigDict(from_attributes=True) + + app_name: str + user_id: str + tracking_id: str + pipeline_name: str + pipeline_version: str + next_pipeline_name: str | None + next_tracking_id: str | None + vars: TrialVars | None + status: TrialStatus + + links: TrialLinks | None = Field(alias='_links', default=None) + + +class CreateTrialRequest(BaseModel): + inputs: list[TrialInput] | None = None + output_vars: list[TrialOutputVar] | None = None + + +class CreateStatusConditionRequest(BaseModel): + type: str + message: str = "" + reason: str = "" + transition_time: AwareDatetime | None = None + stage: str | None = None + + +class PipelineVersionResponse(BaseModel): + openapi_spec: dict | None + license: str | None + pipeline_version: str = '1' + + +class PipelineLinks(BaseModel): + self: Link + trials: Link + version: Link + + +class PipelineResponse(BaseModel): + name: str + links: PipelineLinks = Field(alias='_links') + definition: dict + + +class PipelinesLinks(BaseModel): + self: Link + next: Link | None + + +class EmbeddedPipeline(BaseModel): + name: str + links: PipelineLinks = Field(alias='_links') + + +class PipelinesEmbedded(BaseModel): + pipelines: list[EmbeddedPipeline] + + +class PipelinesResponse(BaseModel): + links: PipelinesLinks = Field(alias='_links') + remaining_item_count: int + embedded: PipelinesEmbedded = Field(alias='_embedded') + + +class TrialsLinks(BaseModel): + self: Link + next: Link | None + + +class EmbeddedTrial(BaseModel): + model_config = ConfigDict(from_attributes=True) + + app_name: str + user_id: str + tracking_id: str + pipeline_name: str + pipeline_version: str + next_pipeline_name: str | None + next_tracking_id: str | None + status: TrialStatus + + links: TrialLinks | None = Field(alias='_links', default=None, validation_alias='links') + + +class TrialsEmbedded(BaseModel): + trials: list[EmbeddedTrial] + + +class TrialsResponse(BaseModel): + links: TrialsLinks = Field(alias='_links') + remaining_item_count: int + total_item_count: int + embedded: TrialsEmbedded = Field(alias='_embedded') + diff --git a/controller/src/exp_pipeline/stage.py b/controller/src/exp_pipeline/stage.py new file mode 100644 index 0000000..1bdab4f --- /dev/null +++ b/controller/src/exp_pipeline/stage.py @@ -0,0 +1,281 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: ExperimentPipeline +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +import json +import logging +import os +from pathlib import Path + +from fastapi import HTTPException + +from exp_pipeline.schema import BoxMount, StartStageVar, TrialStartStage, StartStageImage, EntryPoint, StartEnvVar, \ + StartStageCompResources, StartEnvFrom, StartConfigFrom, StartConfigFromItem +from exp_pipeline.schema import TrialStartVar +from parse import extract_domain + +_DEFAULT_MOUNT_PATH = '/unip' + + +SECRET_SUFFIX = '-cred' + +_STAGE_RESOURCE_CPU_DEFAULT = '500m' +_STAGE_RESOURCE_MEMORY_DEFAULT = '256M' + +logger = logging.getLogger(__name__) + + +def _construct_stage_image(image_section): + image_name = image_section['existingImageName'] + image_registry_name = extract_domain(image_name) + stage_image = StartStageImage(name=image_name, + registry_name=image_registry_name, + credentials_name=image_registry_name + SECRET_SUFFIX) + return stage_image + + +def _construct_entry_point(entry_point_section): + return EntryPoint(cmd=entry_point_section['cmd']) + + +def _construct_var_box_mount(stage_var_section: dict, + start_var: TrialStartVar, + read_only: bool) -> BoxMount: + var_name = start_var.name + start_var_box = start_var.box_path.box + + if 'path' in stage_var_section: + mount_path = stage_var_section['path'] + elif start_var.box_path.mount_path is not None: + mount_path = start_var.box_path.mount_path + elif start_var_box.mount_path is not None: + mount_path = os.path.join(start_var_box.mount_path, var_name) + else: + mount_path = _DEFAULT_MOUNT_PATH + '/' + var_name + + vbm = BoxMount() + vbm.box_name = start_var_box.name + vbm.mount_path = mount_path + vbm.in_box_path = start_var.box_path.in_box_path + vbm.read_only = read_only + + return vbm + + +def _construct_input_var_box_mount(stage_var_section: dict, + start_var: TrialStartVar) -> BoxMount: + vbm = _construct_var_box_mount(stage_var_section=stage_var_section, + start_var=start_var, + read_only=True) + return vbm + + +def _construct_output_var_box_mount(stage_var_section: dict, + start_var: TrialStartVar) -> BoxMount: + vbm = _construct_var_box_mount(stage_var_section=stage_var_section, + start_var=start_var, + read_only=False) + return vbm + + +def _get_stage_var_shape(start_var: TrialStartVar): + shape = None + if start_var.shape: + if isinstance(start_var.shape, int): + shape = str(start_var.shape) + else: + shape = json.dumps(start_var.shape) + return shape + + +def _construct_output_stage_var(stage_name: str, + stage_var_section: dict, + output_vars_by_name: dict[str, TrialStartVar], + internal_vars_by_name: dict[str, TrialStartVar]) -> StartStageVar | None: + var_name = stage_var_section['name'] + + if var_name in output_vars_by_name: + start_var = output_vars_by_name[var_name] + elif var_name in internal_vars_by_name: + start_var = internal_vars_by_name[var_name] + if start_var.box_path.box.dataset_ref_box_name: + logger.info(f'Stage {stage_name} output var {var_name} cannot be dataset, skipped') + return None + else: + logger.info(f'Stage {stage_name} output var {var_name} not passed') + return None + + var_box_mount = _construct_output_var_box_mount(stage_var_section=stage_var_section, + start_var=start_var) + + logger.info(f'Stage: {stage_name}; output var: {var_name}; mount path: {var_box_mount}') + + shape = _get_stage_var_shape(start_var) + + sv = StartStageVar(name=var_name, box_mount=var_box_mount, content_type=start_var.content_type, shape=shape) + + return sv + + +def _construct_input_stage_var(stage_name: str, + stage_var_section: dict, + input_vars_by_name: dict[str, TrialStartVar], + internal_vars_by_name: dict[str, TrialStartVar]) -> StartStageVar | None: + var_name = stage_var_section['name'] + + if var_name in input_vars_by_name: + start_var = input_vars_by_name[var_name] + elif var_name in internal_vars_by_name: + start_var = internal_vars_by_name[var_name] + else: + logger.info(f'Stage {stage_name} input var {var_name} not passed') + return None + + var_box_mount = _construct_input_var_box_mount(stage_var_section=stage_var_section, + start_var=start_var) + + logger.info(f'Stage: {stage_name}; input var: {var_name}; mount path: {var_box_mount}') + + shape = _get_stage_var_shape(start_var) + + sv = StartStageVar(name=var_name, box_mount=var_box_mount, content_type=start_var.content_type, shape=shape) + + return sv + + +def _check_mounts_are_not_prefix_each_other(mount_paths: list[str]): + smp = [Path(mp) for mp in sorted(mount_paths)] + for index in range(len(smp) - 1): + mp = smp[index] + next_mp = smp[index + 1] + if mp == next_mp or mp in next_mp.parents: + return False + return True + + +def _check_mounts(input_vars: list[StartStageVar], output_vars: list[StartStageVar]): + all_vars = input_vars + output_vars + if not _check_mounts_are_not_prefix_each_other([v.box_mount.mount_path for v in all_vars]): + logger.error(f'Some mount paths are prefixes of others') + #paths = [v.box_mount.mount_path for v in all_vars] + #logger.debug(f'Mount paths:\n{paths}') + raise HTTPException(status_code=503, detail="Service unavailable") + + +def _construct_env_vars(spec) -> list[StartEnvVar]: + env_section = spec.get('env') + envs = [] + if env_section: + envs = [StartEnvVar(name=env_var['name'], value=env_var['value']) for env_var in env_section] + return envs + + +def _construct_stage_env_from(spec) -> list[StartEnvFrom]: + res = [] + env_from_section = spec.get('envFrom') + if env_from_section is None: + return res + + # elem: {'configMapRef': {'name': 'env-configmap'}} + for elem in env_from_section: + # key_and_body: [('configMapRef', {'name': 'env-configmap'})] + key_and_body = list(elem.items()) + # key: "configMapRef" + key = key_and_body[0][0] + # body: {'name': 'env-configmap'} + body = key_and_body[0][1] + # body_str: "name: env-configmap" + body_str = str(body).replace('{', '').replace('}', '').replace('\'', '') + item = StartEnvFrom(key=key, body=body_str) + res.append(item) + return res + + +def _construct_stage_config_from(spec) -> list[StartConfigFrom]: + res = [] + config_from_section = spec.get('configFrom') + if config_from_section is None: + return res + + mount_paths = set() + + for elem in config_from_section: + if 'configMap' in elem: + source_kind = 'ConfigMap' + source_section = elem['configMap'] + elif 'secret' in elem: + source_kind = 'Secret' + source_section = elem['secret'] + else: + logger.error(f'Unknown source kind of {elem}') + raise HTTPException(status_code=503, detail="Service unavailable") + source_name = source_section['name'] + mount_path = elem['path'] + if mount_path in mount_paths: + logger.error(f'Duplicate path "{mount_path}" in configFrom') + raise HTTPException(status_code=503, detail="Service unavailable") + mount_paths.add(mount_path) + items = None + if 'items' in source_section: + items = [StartConfigFromItem(key=i['key'], mount_sub_path=i['path']) for i in source_section['items']] + config_from = StartConfigFrom(mount_path=mount_path, + source_kind=source_kind, + source_name=source_name, + items=items) + res.append(config_from) + + return res + + +def _construct_comp_resources(spec) -> StartStageCompResources: + if 'resourceLimits' not in spec: + return StartStageCompResources(cpu=_STAGE_RESOURCE_CPU_DEFAULT, + memory=_STAGE_RESOURCE_MEMORY_DEFAULT) + resource_limits = spec['resourceLimits'] + cpu = resource_limits.get('cpu', _STAGE_RESOURCE_CPU_DEFAULT) + memory = resource_limits.get('memory', _STAGE_RESOURCE_MEMORY_DEFAULT) + gpu = resource_limits.get('gpu') + return StartStageCompResources(cpu=cpu, memory=memory, gpu=gpu) + + +def construct_start_stage( + stage_section: dict, + input_vars_by_name: dict[str, TrialStartVar], + output_vars_by_name: dict[str, TrialStartVar], + internal_vars_by_name: dict[str, TrialStartVar] +) -> TrialStartStage: + name = stage_section['name'] + + stage_image = _construct_stage_image(stage_section['image']) + stage_inputs = [_construct_input_stage_var(stage_name=name, + stage_var_section=s, + input_vars_by_name=input_vars_by_name, + internal_vars_by_name=internal_vars_by_name) + for s in stage_section['inputs']] + stage_inputs = [i for i in stage_inputs if i is not None] + + stage_outputs = [_construct_output_stage_var( + stage_name=name, + stage_var_section=s, + output_vars_by_name=output_vars_by_name, + internal_vars_by_name=internal_vars_by_name + ) + for s in stage_section['outputs']] + stage_outputs = [o for o in stage_outputs if o is not None] + + _check_mounts(stage_inputs, stage_outputs) + + entry_point = _construct_entry_point(stage_section['entryPoint']) if 'entryPoint' in stage_section else None + env_vars = _construct_env_vars(stage_section) + env_from = _construct_stage_env_from(stage_section) + config_from = _construct_stage_config_from(stage_section) + + comp_resources = _construct_comp_resources(stage_section) + + stage = TrialStartStage(name=name, image=stage_image, + inputs=stage_inputs, outputs=stage_outputs, entry_point=entry_point, + env_vars=env_vars, comp_resources=comp_resources, + env_from=env_from, config_from=config_from) + return stage diff --git a/controller/src/exp_pipeline/storage/__init__.py b/controller/src/exp_pipeline/storage/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/controller/src/exp_pipeline/storage/config.py b/controller/src/exp_pipeline/storage/config.py new file mode 100644 index 0000000..de9f1e2 --- /dev/null +++ b/controller/src/exp_pipeline/storage/config.py @@ -0,0 +1,13 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: ExperimentPipeline +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +import os + +UNIP_DATABASE_PIPELINES_USER = os.getenv('UNIP_DATABASE_PIPELINES_USER') +UNIP_DATABASE_PIPELINES_PASSWORD = os.getenv('UNIP_DATABASE_PIPELINES_PASSWORD') +UNIP_DATABASE_PIPELINES_HOST = os.getenv('UNIP_DATABASE_PIPELINES_HOST') +UNIP_DATABASE_PIPELINES_PORT = os.getenv('UNIP_DATABASE_PIPELINES_PORT', 5432) +UNIP_DATABASE_PIPELINES_DB = os.getenv('UNIP_DATABASE_PIPELINES_DB') diff --git a/controller/src/exp_pipeline/storage/db.py b/controller/src/exp_pipeline/storage/db.py new file mode 100644 index 0000000..97ef4b8 --- /dev/null +++ b/controller/src/exp_pipeline/storage/db.py @@ -0,0 +1,37 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: ExperimentPipeline +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker + +from exp_pipeline.storage.config import UNIP_DATABASE_PIPELINES_USER, UNIP_DATABASE_PIPELINES_PASSWORD, \ + UNIP_DATABASE_PIPELINES_DB, UNIP_DATABASE_PIPELINES_PORT, \ + UNIP_DATABASE_PIPELINES_HOST +from exp_pipeline.storage.models import Base + +SQLALCHEMY_DATABASE_URL = \ + f'postgresql+asyncpg://{UNIP_DATABASE_PIPELINES_USER}:{UNIP_DATABASE_PIPELINES_PASSWORD}@' \ + f'{UNIP_DATABASE_PIPELINES_HOST}:{UNIP_DATABASE_PIPELINES_PORT}/{UNIP_DATABASE_PIPELINES_DB}' + +async_engine = create_async_engine(SQLALCHEMY_DATABASE_URL) + + +AsyncDbSession = async_sessionmaker(bind=async_engine, expire_on_commit=False) + + +async def get_db(): + async with AsyncDbSession() as session: + yield session + + +async def recreate_db(): + async with async_engine.begin() as async_conn: + await async_conn.run_sync(Base.metadata.drop_all) + await async_conn.run_sync(Base.metadata.create_all) + + +async def init_db(): + async with async_engine.begin() as async_conn: + await async_conn.run_sync(Base.metadata.create_all) diff --git a/controller/src/exp_pipeline/storage/models.py b/controller/src/exp_pipeline/storage/models.py new file mode 100644 index 0000000..f8cde50 --- /dev/null +++ b/controller/src/exp_pipeline/storage/models.py @@ -0,0 +1,28 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: ExperimentPipeline +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +from sqlalchemy import Integer, String, DateTime +from sqlalchemy.dialects.postgresql import JSONB +from sqlalchemy.orm import DeclarativeBase, mapped_column + + +class Base(DeclarativeBase): + pass + + +class PipelineTrialModel(Base): + __tablename__ = "pipeline_trials" + + id = mapped_column(Integer, primary_key=True) + user_id = mapped_column(String, nullable=False) + app_name = mapped_column(String, nullable=False) + tracking_id = mapped_column(String, nullable=False, index=True, unique=True) + pipeline_name = mapped_column(String, nullable=False) + next_pipeline_name = mapped_column(String, nullable=True) + next_tracking_id = mapped_column(String, nullable=True) + pipeline_version = mapped_column(String, nullable=False) + vars = mapped_column(JSONB, nullable=True) + status = mapped_column(JSONB, nullable=False) diff --git a/controller/src/exp_pipeline/var.py b/controller/src/exp_pipeline/var.py new file mode 100644 index 0000000..70f74c4 --- /dev/null +++ b/controller/src/exp_pipeline/var.py @@ -0,0 +1,508 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: ExperimentPipeline +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +import json +import logging +import posixpath +import urllib.parse +import uuid +from functools import reduce +from operator import mul + +from fastapi import HTTPException +from httpx import AsyncClient + +from exp_pipeline.box import get_path_inside_box, get_default_box +from exp_pipeline.config import UNIP_FILES_API +from exp_pipeline.schema import ConnectedBox, TrialInput, TrialOutputVar, TrialStartVar, StartVarBoxPath, \ + DATATYPE_TO_CONTENT_TYPE +from location import parse_location + + +UNIP_FILES_USER_PASSWORD = '**' + +logger = logging.getLogger(__name__) + + +def _reshape(lst: list, shape: list[int]): + if len(shape) == 1: + return lst + n = reduce(mul, shape[1:]) + return [_reshape(lst[i * n:(i + 1) * n], shape[1:]) for i in range(len(lst) // n)] + + +async def _save_data_to_file(http_client: AsyncClient, + app_name: str, + user_id: str, + s3_box_name: str, + input_data: object, + shape: list[int], + content_type: str) -> str: + data = input_data + if isinstance(data, list): + data = _reshape(data, shape) + + # в текущей реализации все сохраняется в текст в формате JSON + str_data = json.dumps(data) + content_type = 'application/json' + + # создание файла в заданной файловой группе, + # если файловой группы нет, то files API создаст ее + url_prefix = f'{app_name}/files/{s3_box_name}/' + create_file_url = urllib.parse.urljoin(UNIP_FILES_API, + url_prefix) + + res = await http_client.post(create_file_url, auth=(user_id, UNIP_FILES_USER_PASSWORD)) + if res.status_code != 201: + logger.error(f'Files API request error (create file); PUT {create_file_url}; ' + f'Returned code: {res.status_code}') + logger.error(f'Response content {res.content}') + raise HTTPException(status_code=503, detail="Service unavailable") + + res_data = res.json() + put_url = res_data['presigned_put_url'] + new_file_name: str = res_data['name'] + if new_file_name.startswith(url_prefix): + new_file_name = new_file_name[len(url_prefix):] + path = new_file_name + binary_data = str_data.encode('utf-8') + data_len = len(str_data) + + headers = {'Content-Type': content_type, 'Content-Length': str(data_len)} + res = await http_client.put(put_url, content=binary_data, headers=headers, + auth=(user_id, UNIP_FILES_USER_PASSWORD)) + + if res.status_code != 201 and res.status_code != 200: + logger.error(f'S3 request error (put file content); PUT {put_url}; ' + f'Returned code: {res.status_code}') + logger.error(f'Response content {res.content}') + raise HTTPException(status_code=503, detail="Service unavailable") + + # await asyncio.sleep(5) + + return path + + +def _get_var_box(user_id: str, + pipeline_name: str, + connected_boxes: list[ConnectedBox], + box_section: dict | None + ) -> ConnectedBox: + connected_boxes_by_name = {cb.name: cb for cb in connected_boxes} + if box_section and 'name' in box_section: + name = box_section['name'] + if name not in connected_boxes_by_name: + logger.error(f'Connected box {name} not specified in pipeline {pipeline_name}') + raise HTTPException(status_code=503, detail="Service unavailable") + return connected_boxes_by_name[name] + return get_default_box(user_id, pipeline_name, connected_boxes) + + +async def _get_input_var_location(http_client: AsyncClient, + app_name: str, + user_id: str, + var_box: ConnectedBox, + passed_var_input: TrialInput) -> tuple[str, str]: + if passed_var_input.datatype in {"FILE", "WEBSITE"}: + if not isinstance(passed_var_input.data, str): + raise HTTPException(status_code=400, detail=f"Passed input var {passed_var_input.name} " + f"datatype is {passed_var_input.datatype}," + f" but data is not instance of 'str'") + if passed_var_input.datatype == 'FILE' and not passed_var_input.content_type: + raise HTTPException(status_code=400, detail=f"Passed input var {passed_var_input.name} " + f"datatype is FILE, content_type is required") + if passed_var_input.datatype == 'WEBSITE': + passed_var_input.content_type = DATATYPE_TO_CONTENT_TYPE['WEBSITE'] + + file_group_name, file_name = parse_location(passed_var_input.data) + if not file_group_name: + raise HTTPException(status_code=400, + detail=f"At least file group must be passed for input of var {passed_var_input.name}, " + f"given: {passed_var_input.data}") + if not file_name: + # parse_location возвращает значения, которые не начинаются и не заканчиваются символом '/'; + # если передано имя файловой группы, то путь должен оканчиваться '/' - + # монтируется папка; + path = file_group_name + '/' + else: + # если передано имя файловой группы и имя файла, то объединяем их - + # монтируется файл; + path = posixpath.join(file_group_name, file_name) + return path, passed_var_input.content_type + else: + if not passed_var_input.data: + raise HTTPException(status_code=400, detail=f"Passed input var {passed_var_input.name} " + f"datatype is {passed_var_input.datatype}, but data not passed") + # создается временный файл во временной файловой группе, путь к нему возвращается - + # монтируется файл; + path = await _save_data_to_file(http_client=http_client, + app_name=app_name, + user_id=user_id, + s3_box_name=var_box.s3_box_name, + input_data=passed_var_input.data, + shape=passed_var_input.shape, + content_type=passed_var_input.content_type) + return path, 'application/json' + + +def _get_input_var_datatype(passed_var_input: TrialInput): + if passed_var_input.datatype == 'WEBSITE': + return 'WEBSITE' + return 'FILE' + + +def _get_input_var_in_box_path(user_id: str, + input_location: str | None) -> str: + in_box_path = get_path_inside_box(user_id, input_location) + return in_box_path + + +def _get_var_mount_path(var_section: dict): + return var_section.get('path', None) + + +async def _construct_input_var(http_client: AsyncClient, + app_name: str, + user_id: str, + pipeline_name: str, + connected_boxes: list[ConnectedBox], + var_section: dict, + var_input: TrialInput) -> TrialStartVar: + var_name = var_section['name'] + + box_section = None + if 'mountFrom' in var_section: + mount_from_section = var_section['mountFrom'] + if 'box' in mount_from_section: + box_section = mount_from_section['box'] + + var_box = _get_var_box(user_id=user_id, + pipeline_name=pipeline_name, + connected_boxes=connected_boxes, + box_section=box_section) + if var_box.dataset_ref_box_name: + logger.info(f'Input var {var_name} connected box {var_box.name} cannot be dataset') + raise HTTPException(status_code=503, detail="Service unavailable") + + input_location, content_type = await _get_input_var_location(http_client=http_client, + app_name=app_name, + user_id=user_id, + var_box=var_box, + passed_var_input=var_input) + datatype = _get_input_var_datatype(passed_var_input=var_input) + logger.info(f'Input var: {var_name}; input location: {input_location}') + + in_box_path = _get_input_var_in_box_path(user_id=user_id, input_location=input_location) + mount_path = _get_var_mount_path(var_section=var_section) + var_box_path = StartVarBoxPath(in_box_path=in_box_path, box=var_box, mount_path=mount_path) + + sv = TrialStartVar(name=var_name, box_path=var_box_path, files_location=input_location, + datatype=datatype, content_type=content_type, shape=var_input.shape) + + return sv + + +async def _create_file_group(http_client: AsyncClient, + app_name: str, + user_id: str, + box_name: str, + location: str): + url_prefix = f'/{app_name}/files/{box_name}' + url_prefix = posixpath.join(url_prefix, location) + create_fg_url = urllib.parse.urljoin(UNIP_FILES_API, url_prefix) + + res = await http_client.put(create_fg_url, auth=(user_id, UNIP_FILES_USER_PASSWORD)) + if res.status_code != 200: + logger.error(f'Files API request error (create file-group); PUT {create_fg_url}; ' + f'Returned code: {res.status_code}') + logger.error(f'Response content {res.content}') + raise HTTPException(status_code=503, detail="Service unavailable") + + +async def _get_output_var_location(http_client: AsyncClient, + app_name: str, + user_id: str, + var_box: ConnectedBox, + passed_var: TrialOutputVar | None): + passed = passed_var.data if passed_var else None + file_group_name, file_name = parse_location(passed) + + if file_name: + # выходные переменные всегда должны быть файловыми группами + raise HTTPException(status_code=400, + detail=f'File name must NOT be specified for output var {passed_var.name}; ' + f'given location {passed}') + + if passed_var.datatype == 'WEBSITE': + passed_var.content_type = DATATYPE_TO_CONTENT_TYPE['WEBSITE'] + + if not file_group_name: + # если передана пустая локация, то генерируется уникальное имя файловой группы, + # Files API не поддерживает генерацию имен при создании пустых файловых групп; + path = str(uuid.uuid4()) + '/' + else: + # если передана файловая группа, то нужно дописать '/', + # посколькуо parse_location всегда возвращает значения, которые не начинаются + # и не оканчиваются '/' + path = file_group_name + '/' + + await _create_file_group(http_client, app_name, user_id, var_box.s3_box_name, path) + + return path, passed_var.content_type + + +def _get_output_var_in_box_path( + user_id: str, + + output_location: str | None +) -> str: + in_box_path = get_path_inside_box(user_id, output_location) + return in_box_path + + +def _get_output_var_datatype(passed_var: TrialOutputVar): + if not passed_var.datatype: + return 'FILE' + return passed_var.datatype + + +async def _construct_output_var(http_client: AsyncClient, + app_name: str, + user_id: str, + pipeline_name: str, + connected_boxes: list[ConnectedBox], + var_section: dict, + trial_output_var: TrialOutputVar) -> TrialStartVar: + var_name = var_section['name'] + + box_section = None + if 'mountFrom' in var_section: + mount_from_section = var_section['mountFrom'] + if 'box' in mount_from_section: + box_section = mount_from_section['box'] + + var_box = _get_var_box(user_id=user_id, + pipeline_name=pipeline_name, + connected_boxes=connected_boxes, + box_section=box_section) + if var_box.dataset_ref_box_name: + logger.info(f'Output var {var_name} connected box {var_box.name} cannot be dataset') + raise HTTPException(status_code=503, detail="Service unavailable") + + output_location, content_type = await _get_output_var_location(http_client=http_client, + app_name=app_name, + user_id=user_id, + var_box=var_box, + passed_var=trial_output_var) + datatype = _get_output_var_datatype(passed_var=trial_output_var) + + logger.info(f'Output var: {var_name}; output location: {output_location}') + + in_box_path = _get_output_var_in_box_path(user_id=user_id, output_location=output_location) + mount_path = _get_var_mount_path(var_section=var_section) + var_box_path = StartVarBoxPath(in_box_path=in_box_path, box=var_box, mount_path=mount_path) + + sv = TrialStartVar(name=var_name, box_path=var_box_path, files_location=output_location, + datatype=datatype, content_type=content_type) + + return sv + + +async def _get_internal_var_location(http_client: AsyncClient, + app_name: str, + user_id: str, + var_box: ConnectedBox, + var_section: dict): + var_name = var_section['name'] + + if var_box.dataset_ref_box_name: + logger.info(f'For internal var {var_name} dataset is used') + return None + + box_section = None + if 'mountFrom' in var_section: + mount_from_section = var_section['mountFrom'] + if 'box' in mount_from_section: + box_section = mount_from_section['box'] + + # если задан boxPath, то локация не создается + if box_section and ('boxPath' in box_section): + logger.info(f'For internal var {var_name} boxPath is used') + return None + + # иначе нужно создать пустую локацию; генерируется уникальное имя файловой группы, + # Files API не поддерживает генерацию имен при создании пустых файловых групп; + path = str(uuid.uuid4()) + '/' + + await _create_file_group(http_client, app_name, user_id, var_box.s3_box_name, path) + + logger.info(f'Internal var: {var_name}; internal location: {path}') + + return path + + +def _get_internal_var_in_box_path(user_id: str, + var_box: ConnectedBox, + var_section: dict, + internal_location: str | None): + var_name = var_section['name'] + + box_section = None + if 'mountFrom' in var_section: + mount_from_section = var_section['mountFrom'] + if 'box' in mount_from_section: + box_section = mount_from_section['box'] + + static_box_path = var_box.dataset_ref_box_name or (box_section and ('boxPath' in box_section)) + + if static_box_path and internal_location: + logger.error(f'Bug. Cannot use internal var {var_name} location' + f' if boxPath or mountDataset is defined in pipeline specification') + raise HTTPException(status_code=500, + detail=f'Internal server error') + if not static_box_path and not internal_location: + logger.error(f'Bug. Internal var location not passed and bot boxPath, mountDataset not specified ' + f'for internal var {var_name}.') + raise HTTPException(status_code=500, + detail=f'Internal server error') + + in_box_path = None + # либо boxPath и mountDataset не указаны в спецификации, и создается пустая файловая группа, + # internal_location содержит ее значение; + if internal_location: + in_box_path = get_path_inside_box(user_id, internal_location) + # либо boxPath или mountDataset указаны в спецификации; + if static_box_path: + if var_box.dataset_ref_box_name: + in_box_path = "" + elif box_section and ('boxPath' in box_section): + in_box_path = box_section['boxPath'] + if in_box_path is not None and in_box_path.startswith('/'): + in_box_path = in_box_path.lstrip('/') + + return in_box_path + + +def _get_internal_var_datatype(): + return 'FILE' + + +async def _construct_internal_var(http_client: AsyncClient, + app_name: str, + user_id: str, + pipeline_name: str, + connected_boxes: list[ConnectedBox], + var_section: dict) -> TrialStartVar: + var_name = var_section['name'] + + box_section = None + if 'mountFrom' in var_section: + mount_from_section = var_section['mountFrom'] + if 'box' in mount_from_section: + box_section = mount_from_section['box'] + + var_box = _get_var_box(user_id=user_id, + pipeline_name=pipeline_name, + connected_boxes=connected_boxes, + box_section=box_section) + + internal_location = await _get_internal_var_location(http_client=http_client, + app_name=app_name, + user_id=user_id, + var_box=var_box, + var_section=var_section) + datatype = _get_internal_var_datatype() + + in_box_path = _get_internal_var_in_box_path(user_id=user_id, + var_box=var_box, + var_section=var_section, + internal_location=internal_location) + mount_path = _get_var_mount_path(var_section=var_section) + var_box_path = StartVarBoxPath(in_box_path=in_box_path, box=var_box, mount_path=mount_path) + + sv = TrialStartVar(name=var_name, box_path=var_box_path, files_location=internal_location, + datatype=datatype) + + return sv + + +def _determine_start_vars_spec(pipeline_api_spec, pipeline_spec): + result = input_vars_specs, output_vars_specs, internal_vars_specs = {}, {}, {} + + if 'apiSpec' not in pipeline_api_spec: + return result + + pipeline_vars = pipeline_spec['vars'] + api_spec = pipeline_api_spec['apiSpec'] + + inputs_names = {i['name'] for i in api_spec['inputs']} if 'inputs' in api_spec else set() + input_vars_specs.update({v['name']: v for v in pipeline_vars if v['name'] in inputs_names}) + + outputs_names = {o['name'] for o in api_spec['outputs']} if 'outputs' in api_spec else set() + output_vars_specs.update({v['name']: v for v in pipeline_vars if v['name'] in outputs_names}) + + internal_vars_specs.update({v['name']: v for v in pipeline_vars if v['name'] not in (inputs_names | outputs_names)}) + + return result + + +async def construct_start_vars(http_client: AsyncClient, + app_name: str, + user_id: str, + pipeline_name: str, + pipeline_api_spec: dict, + pipeline_spec: dict, + connected_boxes: list[ConnectedBox], + passed_trial_inputs: list[TrialInput], + passed_trial_output_vars: list[TrialOutputVar]) \ + -> tuple[list[TrialStartVar], list[TrialStartVar], list[TrialStartVar]]: + input_vars_specs, output_vars_specs, internal_vars_specs = _determine_start_vars_spec(pipeline_api_spec, + pipeline_spec) + + input_vars = [] + # входные данные прошли валидацию, поэтому считаются корректными; + # поэтому для каждого переданного входа отыскивается спецификация в ресурсе пайплайна; + for i in passed_trial_inputs: + # исключение - когда за пайплайном следует другой пайплайн, и переданные данные + # относятся к нему; + if i.name not in input_vars_specs: + continue + input_var_spec = input_vars_specs[i.name] + input_var = await _construct_input_var(http_client=http_client, + app_name=app_name, + user_id=user_id, + pipeline_name=pipeline_name, + connected_boxes=connected_boxes, + var_section=input_var_spec, + var_input=i) + input_vars.append(input_var) + + output_vars = [] + # аналогично + for o in passed_trial_output_vars: + if o.name not in output_vars_specs: + continue + output_var_spec = output_vars_specs[o.name] + output_var = await _construct_output_var(http_client=http_client, + app_name=app_name, + user_id=user_id, + pipeline_name=pipeline_name, + connected_boxes=connected_boxes, + var_section=output_var_spec, + trial_output_var=o) + output_vars.append(output_var) + + # а в данном случае берутся все внутренние переменные, + # которые специфицированы в пайплайне (входные значения для них не передаются) + internal_vars = [await _construct_internal_var(http_client=http_client, + app_name=app_name, + user_id=user_id, + pipeline_name=pipeline_name, + connected_boxes=connected_boxes, + var_section=v) + for v in internal_vars_specs.values()] + + return input_vars, output_vars, internal_vars diff --git a/controller/src/files/__init__.py b/controller/src/files/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/controller/src/files/api.py b/controller/src/files/api.py new file mode 100644 index 0000000..a482b9e --- /dev/null +++ b/controller/src/files/api.py @@ -0,0 +1,385 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Files +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +import logging +import posixpath +import uuid +from contextlib import asynccontextmanager +from typing import Annotated + +import httpx +from fastapi import FastAPI, Response, status, Depends, HTTPException +from kubernetes_asyncio.client import ApiClient +from pydantic import BaseModel + +from auth import get_user_id +from files.box import get_box, get_box_name, DataBox, _get_s3_box_creds +from files.logging import configure_logging +from files.s3.client import AsyncS3Client +from kube_config import async_unip_load_kube_config +from location import parse_location + +_k8s_api_client: ApiClient | None = None +_async_http_client: httpx.AsyncClient | None = None + +configure_logging() +logger = logging.getLogger() + + +@asynccontextmanager +async def _lifespan(app: FastAPI): + global _k8s_api_client, _async_http_client + await async_unip_load_kube_config(logger) + _k8s_api_client = ApiClient() + _async_http_client = httpx.AsyncClient(timeout=30) + yield + await _async_http_client.aclose() + await _k8s_api_client.close() + + +app = FastAPI(lifespan=_lifespan) + + +class ReadFileResponse(BaseModel): + name: str + presigned_get_url: str + + +class WriteFileResponse(BaseModel): + name: str + presigned_put_url: str + + +class FileGroup(BaseModel): + name: str + files: list[ReadFileResponse | WriteFileResponse] + + +async def _get_async_s3_client(box: DataBox): + endpoint, access_key, secret_key, region = await _get_s3_box_creds(_k8s_api_client, box) + async_s3_client = AsyncS3Client(http_client=_async_http_client, + endpoint=endpoint, + access_key=access_key, + secret_key=secret_key, + region=region) + return async_s3_client + + +def _get_in_storage_path(box, user_id, file_group_name): + """ + Конструирует путь к файловой группе пользователя внутри ящика. + + Обеспечивается, что возвращаемая строка не начинается с символа '/'. + """ + storage_sub_path = box.storage_sub_path.lstrip('/') if box.storage_sub_path else '' + return posixpath.join(storage_sub_path, 'users', user_id, 'file_groups', file_group_name) + + +def _get_path_public_name(app_name: str, box: DataBox, file_group_name: str, file_name: str | None): + """ + Формирует путь к файловой группе или файлу, который вернется пользователю в ответе. + + Требует, чтобы file_group_name, file_name не оканчивались символом '/'. + """ + + if not file_group_name.endswith('/'): + file_group_name = file_group_name + '/' + if file_name: + if file_name.endswith('/'): + file_name = file_name.rstrip('/') + public_name = posixpath.join(app_name, 'files', box.name, file_group_name, file_name) + else: + public_name = posixpath.join(app_name, 'files', box.name, file_group_name) + return public_name + + +async def _get_file(app_name: str, user_id: str, box: DataBox, file_group_name: str, file_name: str) \ + -> ReadFileResponse | None: + """ + Возвращает файл, что соответствует существующему в "директории" объекту. + + Если файл отсутствует, то возвращается None. + + Требует, чтобы file_name не оканчивалось символом '/'. + """ + + # эти проверки обеспечивают, что в реализации нет ошибок, связанных с разбором переданной + # локации и формированием имен файловой группы и файла + if not file_name: + raise ValueError + if file_name: + if file_name.endswith('/'): + raise ValueError + + in_storage_path = _get_in_storage_path(box, user_id, file_group_name) + + object_name = posixpath.join(in_storage_path, file_name) + bucket_name = box.storage_name + async_s3_client = await _get_async_s3_client(box) + try: + _ = await async_s3_client.head_object(box.storage_name, object_name) + except httpx.HTTPStatusError as exc: + if exc.response.status_code == 404: + return None + raise exc + + get_url = async_s3_client.presigned_get_object(bucket_name=bucket_name, object_name=object_name) + public_name = _get_path_public_name(app_name, box, file_group_name, file_name) + + return ReadFileResponse(name=public_name, presigned_get_url=get_url) + + +async def _get_file_group_with_files(app_name: str, user_id: str, box: DataBox, file_group_name: str, + file_response_cls) \ + -> FileGroup | None: + """ + Возвращает файловую группу и ее содержимое, что соответствует существующим в "директории" объектам. + + Для формирования результата рекурсивный обход не осуществляется. + + Если файловая группа является пустой (то есть соответствует пустой "директории"), + то возвращается файловая группа с пустым списком файлов. + + Если файловая группа отсутствует (отсутствует даже пустая "директория"), то возвращается None. + + Требует, чтобы file_group_name не оканчивалась символом '/'. + """ + + # эти проверки обеспечивают, что в реализации нет ошибок, связанных с разбором переданной + # локации и формированием имен файловой группы и файла + if not file_group_name: + raise ValueError + if file_group_name.endswith('/'): + raise ValueError + + # важно, чтобы в запросе url оканчивался на '/' иначе вместо папки будет осуществляться поиск файла + file_group_name = file_group_name + '/' + in_storage_path = _get_in_storage_path(box, user_id, file_group_name) + + bucket_name = box.storage_name + async_s3_client = await _get_async_s3_client(box) + + s3_objects = await async_s3_client.list_objects(box.storage_name, in_storage_path) + + # пустой результат, если ни пустой файловой директории, ни файлов с такими префиксами нет + if not s3_objects: + return None + + files = [] + fg_public_name = _get_path_public_name(app_name, box, file_group_name, None) + for s3_obj in s3_objects: + # если есть пустая директория вернется один объект с is_dir == True, она не возвращается; + # могут быть вложенные пустые директории (объекты с is_dir == True), они тоже не возвращаются; + if s3_obj.is_dir: + continue + + rel_path = posixpath.relpath(s3_obj.object_name, in_storage_path) + public_file_name = fg_public_name + rel_path + if file_response_cls is ReadFileResponse: + get_url = async_s3_client.presigned_get_object(bucket_name=bucket_name, object_name=s3_obj.object_name) + f = ReadFileResponse(name=public_file_name, presigned_get_url=get_url) + else: + put_url = async_s3_client.presigned_put_object(bucket_name=bucket_name, object_name=s3_obj.object_name) + f = WriteFileResponse(name=public_file_name, presigned_put_url=put_url) + files.append(f) + + fg = FileGroup(name=fg_public_name, files=files) + + return fg + + +async def _create_path(app_name: str, user_id: str, box: DataBox, file_group_name: str, + file_name: str | None) -> WriteFileResponse | FileGroup: + """ + Создает пустой файл или пустую "директорию". + + Требует, чтобы file_group_name, file_name не начинались и не оканчивались символом '/'. + """ + + # эти проверки обеспечивают, что в реализации нет ошибок, связанных с разбором переданной + # локации и формированием имен файловой группы и файла + if not file_group_name: + raise ValueError + if file_group_name.startswith('/') or file_group_name.endswith('/'): + raise ValueError + if file_name: + if file_name.startswith('/') or file_name.endswith('/'): + raise ValueError + + in_storage_path = _get_in_storage_path(box, user_id, file_group_name) + + if file_name: + # если имя файла задано, то создать нужно пустой файл + object_name = posixpath.join(in_storage_path, file_name) + else: + # иначе нужно создать пустую директорию, + # для этого нужно дописать '/' к имени объекта + if not in_storage_path.endswith('/'): + in_storage_path = in_storage_path + '/' + object_name = in_storage_path + + bucket_name = box.storage_name + async_s3_client = await _get_async_s3_client(box) + + _ = await async_s3_client.put_object(bucket_name, object_name) + + if file_name: + # если создан файл + public_name = _get_path_public_name(app_name, box, file_group_name, file_name) + put_url = async_s3_client.presigned_put_object(bucket_name=bucket_name, object_name=object_name) + return WriteFileResponse(name=public_name, presigned_put_url=put_url) + else: + # если создана пустая директория + public_name = _get_path_public_name(app_name, box, file_group_name, None) + return FileGroup(name=public_name, files=[]) + + +async def _create_file(app_name: str, user_id: str, box: DataBox): + """ + Создает пустой файл со сгненерированным именем внутри файловой группы + со сгенерированным именем. + """ + file_group_name = str(uuid.uuid4()) + file_name = str(uuid.uuid4()) + file = await _create_path(app_name, user_id, box, file_group_name, file_name) + return file + + +async def _create_file_inside_file_group(app_name: str, user_id: str, box: DataBox, file_group_name: str): + """ + Создает пустой файл со сгненерированным именем внутри файловой группы + с заданным именем. + """ + file_name = str(uuid.uuid4()) + file = await _create_path(app_name, user_id, box, file_group_name, file_name) + return file + + +async def _create_file_put_presigned_url(app_name: str, user_id: str, box: DataBox, file_group_name: str, + file_name: str) -> WriteFileResponse: + in_storage_path = _get_in_storage_path(box, user_id, file_group_name) + object_name = posixpath.join(in_storage_path, file_name) + + bucket_name = box.storage_name + async_s3_client = await _get_async_s3_client(box) + + public_name = _get_path_public_name(app_name, box, file_group_name, file_name) + put_url = async_s3_client.presigned_put_object(bucket_name=bucket_name, object_name=object_name) + + file = WriteFileResponse(name=public_name, presigned_put_url=put_url) + + return file + + +async def _create_file_group(app_name: str, user_id: str, box: DataBox, file_group_name: str) -> FileGroup: + fg = await _create_path(app_name, user_id, box, file_group_name, None) + return fg + + +@app.put("/{app_name}/files/{box_name}/{location:path}", + response_model=FileGroup | WriteFileResponse) +async def put_location_op(response: Response, + app_name: str, + box_name: str, + user_id: Annotated[str, Depends(get_user_id)], + location: str | None = None): + file_group_name, file_name = parse_location(location) + box_name = get_box_name(box_name, app_name, user_id) + + box = await get_box(_k8s_api_client, box_name, app_name) + + file = None + fg = None + + if not file_group_name and not file_name: + raise HTTPException(status_code=400, detail=f'Location not specified') + + if file_name: + # если задано имя файла, то генерируются подписанные URL, пустой файл не создается + file = await _create_file_put_presigned_url(app_name, user_id, box, file_group_name, file_name) + else: + # если задано только имя файловой группы, то создается пустая директория, + # возвращается ее содержимое (наиболее вероятно, что пустое) + _ = await _create_file_group(app_name, user_id, box, file_group_name) + fg = await _get_file_group_with_files(app_name, user_id, box, file_group_name, WriteFileResponse) + + if file: + resp = file + else: + resp = fg + + return resp + + +@app.post("/{app_name}/files/{box_name}/{location:path}", + response_model=FileGroup | WriteFileResponse) +@app.post("/{app_name}/files/{box_name}", + response_model=FileGroup | WriteFileResponse) +async def post_location_op(response: Response, + app_name: str, + box_name: str, + user_id: Annotated[str, Depends(get_user_id)], + location: str | None = None): + file_group_name, file_name = parse_location(location) + box_name = get_box_name(box_name, app_name, user_id) + + box = await get_box(_k8s_api_client, box_name, app_name) + + if file_name: + # POST поддерживается только для файловых групп, или если переданная локация пустая, + # file_name не должен быть явно указан в локации + raise HTTPException(status_code=400, detail=f'Not supported location \'{location}\' for POST; ' + f'file name must not be specified; given \'{file_name}\'') + + if not file_group_name: + # соответствует пустой локации; создается пустой файл и файловая группа + # со сгенерированными именами; + file = await _create_file(app_name, user_id, box) + else: + # соответствует location='/file_group/'; создается пустой файл + # со сгенерированным именем в заданной файловой группе + file = await _create_file_inside_file_group(app_name, user_id, box, file_group_name) + + response.status_code = status.HTTP_201_CREATED + return file + + +@app.get("/{app_name}/files/{box_name}/{location:path}", + response_model=FileGroup | ReadFileResponse) +async def get_location_op(response: Response, + app_name: str, + box_name: str, + user_id: Annotated[str, Depends(get_user_id)], + location: str | None = None): + file_group_name, file_name = parse_location(location) + box_name = get_box_name(box_name, app_name, user_id) + + box = await get_box(_k8s_api_client, box_name, app_name) + + file = None + fg = None + + if not file_group_name and not file_name: + raise HTTPException(status_code=404, detail=f'Location not specified') + + if file_name and file_name != '*': + file = await _get_file(app_name, user_id, box, file_group_name, file_name) + if not file: + raise HTTPException(status_code=404, detail=f'File \'{posixpath.join(file_group_name, file_name)}\' ' + f'doesnt exist') + + else: + fg = await _get_file_group_with_files(app_name, user_id, box, file_group_name, ReadFileResponse) + if not fg: + raise HTTPException(status_code=404, detail=f'File group \'{file_group_name}\' ' + f'doesnt exist') + + if file: + resp = file + else: + resp = fg + + return resp diff --git a/controller/src/files/api/docker.md b/controller/src/files/api/docker.md new file mode 100644 index 0000000..889174a --- /dev/null +++ b/controller/src/files/api/docker.md @@ -0,0 +1,7 @@ +``` +docker run --rm -p 8080:8080 \ +--name swagger-unip-files \ +-e SWAGGER_FILE=/api/openapi.yaml \ +-e PORT=8080 \ +-v $PWD/controller/src/files/api:/api swaggerapi/swagger-editor +``` \ No newline at end of file diff --git a/controller/src/files/api/openapi-snapshot.json b/controller/src/files/api/openapi-snapshot.json new file mode 100644 index 0000000..de29133 --- /dev/null +++ b/controller/src/files/api/openapi-snapshot.json @@ -0,0 +1,483 @@ +{ + "openapi": "3.0.3", + "info": { + "title": "ML Component - OpenAPI 3.0", + "description": "Спецификция сервиса Files", + "termsOfService": "https://platform-dev-cs-hse.objectoriented.ru/terms/", + "contact": { + "email": "apiteam@platform-dev-cs-hse.objectoriented.ru" + }, + "version": "1.0.0" + }, + "servers": [ + { + "url": "http://localhost:8000" + }, + { + "url": "https://platform-dev-cs-hse.objectoriented.ru/app/files" + } + ], + "tags": [ + { + "name": "files", + "description": "Операции с файлами и файловыми группами", + "externalDocs": { + "description": "Подробнее", + "url": "https://platform-dev-cs-hse.objectoriented.ru" + } + } + ], + "security": [ + { + "basic_auth": [] + } + ], + "paths": { + "/{app}/files/{box}/{location}": { + "parameters": [ + { + "name": "X-Request-Id", + "in": "header", + "schema": { + "$ref": "#/components/headers/request_id" + }, + "description": "Идентификатор для диагностики запроса", + "examples": { + "example": { + "summary": "Идентификатор из нулей", + "description": "Идентификатор в формате UUID", + "value": "00000000-0000-0000-0000-000000000000" + } + } + }, + { + "name": "location", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Путь к файловой группе или к файлу.\n\nВ общем случае имеет вид /, причем\nимя , если задано, может состоять из одного или нескольких сегментов.\nИмя , если задано, может состоять только из одного сегмента.\n\nМожет принимать значения в следующих форматах:\n- '' (новые файловая группа и файл в ней со сгенерированными именами)\n- 'a/ (файловая группа a/)\n- 'a' (файловая группа a/)\n- 'a/b/' (файловая группа a/b/)\n- 'a/b' (файл b в файловой группе a/)\n- 'a/b/c' (файл c в файловой группе a/b/)\n", + "examples": { + "empty": { + "summary": "Пустое значение", + "value": "", + "description": "Используется при создании новой файловой группы,\nи нового файла в ней. Их имена генерируются автоматически.\n" + }, + "file_group": { + "summary": "Файловая группа с простым именем", + "value": "a/", + "description": "Соответствует файловой группе, имя которой состоит из одного сегмента.\n" + }, + "file_group_complex": { + "summary": "Файловая группа с составным именем", + "value": "a/b/", + "description": "Соответствует файловой группе, имя которой состоит из двух сегментов.\n" + }, + "file": { + "summary": "Файл в файловой группе", + "value": "a/b", + "description": "Соответствует файлу в файловой группе, имя которой состоит из одного сегмента.\n" + } + } + }, + { + "name": "box", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Имя ящика DataBox" + }, + { + "name": "app", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Имя приложения PlatformApp" + } + ], + "get": { + "tags": [ + "files" + ], + "summary": "Получить файл или файловую группу", + "description": "Возвращает файл или файловую группу.\n\nЕсли локация соответствует файловой группе, то возвращает файловую группу\nсо всеми файлами в ней.\n\nЕсли локация соответствует файлу, то возвращает файл.\n\nПустая локация в GET не поддерживается.", + "operationId": "get_files", + "responses": { + "200": { + "$ref": "#/components/responses/successful-read" + }, + "400": { + "description": "Ошибка входных данных.\nВозможные причины: \n- Передана пустая локация;\n", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "headers": { + "X-Request-Id": { + "$ref": "#/components/headers/request_id" + } + } + }, + "401": { + "description": "Аутентификация не пройдена", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "headers": { + "X-Request-Id": { + "$ref": "#/components/headers/request_id" + } + } + }, + "404": { + "description": "Не найден запрошенный ресурс.\nВозможные причины: \n- Указанная локация не существует;\n", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "headers": { + "X-Request-Id": { + "$ref": "#/components/headers/request_id" + } + } + }, + "default": { + "$ref": "#/components/responses/successful-read" + } + } + }, + "post": { + "tags": [ + "files" + ], + "summary": "Создать файл или файловую группу", + "description": "Создает файл или файловую группу.\n\nЛокация может быть пустой, или соответствовать файловой группе.\nЛокации, соответствующие файлу, в POST не поддерживаются.\n\nЕсли локация соответствует файловой группе, то создает новый пустой файл\nсо сгенерированным именем в заданной файловой группе.\n\nЕсли локация задана пустая, то создает файловую группу и файл в ней \nсо сгенерированными именами.", + "operationId": "post_files", + "responses": { + "201": { + "$ref": "#/components/schemas/WriteFileResponse" + }, + "400": { + "description": "Ошибка входных данных.\nВозможные причины: \n- Передана локация, соответствующая файлу;\n", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "headers": { + "X-Request-Id": { + "$ref": "#/components/headers/request_id" + } + } + }, + "401": { + "description": "Аутентификация не пройдена", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "headers": { + "X-Request-Id": { + "$ref": "#/components/headers/request_id" + } + } + }, + "default": { + "$ref": "#/components/schemas/WriteFileResponse" + } + } + }, + "put": { + "tags": [ + "files" + ], + "summary": "Разместить файл или файловую группу", + "description": "Размещает файл или файловую группу.\n\nЕсли локация соответствует файловой группе, то создает новую пустую \nфайловую группу с заданным именем.\nЕсли файловая группа существует, ничего не делает.\n\nЕсли локация соответствует файлу, то создает подписанные ссылки\nдля чтения и записи содержимого файла. Файл не создается.\n\nПустая локация в PUT не поддерживается.", + "operationId": "put_files", + "responses": { + "200": { + "$ref": "#/components/responses/successful-write" + }, + "400": { + "description": "Ошибка входных данных.\nВозможные причины: \n- Передана пустая локация;\n", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "headers": { + "X-Request-Id": { + "$ref": "#/components/headers/request_id" + } + } + }, + "401": { + "description": "Аутентификация не пройдена", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "headers": { + "X-Request-Id": { + "$ref": "#/components/headers/request_id" + } + } + }, + "default": { + "$ref": "#/components/responses/successful-write" + } + } + } + } + }, + "components": { + "schemas": { + "ReadFileResponse": { + "description": "Файл со ссылкой для получения содержимого", + "type": "object", + "properties": { + "name": { + "description": "Имя", + "type": "string" + }, + "presigned_get_url": { + "description": "Подписанная ссылка для получения содержимого файла", + "type": "string" + } + }, + "required": [ + "name", + "presigned_get_url" + ] + }, + "WriteFileResponse": { + "description": "Файл со ссылкой для загрузки содержимого", + "type": "object", + "properties": { + "name": { + "description": "Имя", + "type": "string" + }, + "presigned_put_url": { + "description": "Подписанная ссылка для загрузки содержимого файла", + "type": "string" + } + }, + "required": [ + "name", + "presigned_put_url" + ] + }, + "ReadFileGroupResponse": { + "description": "Файловая группа.", + "type": "object", + "properties": { + "name": { + "description": "Имя.", + "type": "string" + }, + "files": { + "description": "Список файлов в файловой группе.", + "type": "array", + "items": { + "$ref": "#/components/schemas/ReadFileResponse" + } + } + }, + "required": [ + "name", + "files" + ] + }, + "WriteFileGroupResponse": { + "description": "Файловая группа.", + "type": "object", + "properties": { + "name": { + "description": "Имя.", + "type": "string" + }, + "files": { + "description": "Список файлов в файловой группе.", + "type": "array", + "items": { + "$ref": "#/components/schemas/WriteFileResponse" + } + } + }, + "required": [ + "name", + "files" + ] + }, + "ErrorResponse": { + "description": "Объект с результатом операции инференса, которая не завершилась успешно.", + "type": "object", + "properties": { + "errors": { + "description": "Список ошибок.", + "type": "array", + "items": { + "description": "Ошибка при выполнении операции инференса.", + "type": "object", + "properties": { + "type": { + "description": "Тип ошибки.", + "type": "string" + }, + "message": { + "description": "Сообщение с описанием ошибки.", + "type": "string" + } + }, + "required": [ + "type", + "message" + ] + }, + "maxItems": 10 + } + } + } + }, + "headers": { + "request_id": { + "description": "Идентификатор для диагностики запроса", + "schema": { + "type": "string", + "format": "uuid" + }, + "examples": { + "example": { + "summary": "Идентификатор из нулей", + "value": "00000000-0000-0000-0000-000000000000" + } + } + } + }, + "responses": { + "successful-read": { + "description": "Операция завершена успешно", + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/ReadFileResponse" + }, + { + "$ref": "#/components/schemas/WriteFileGroupResponse" + } + ] + }, + "examples": { + "file": { + "summary": "Файл", + "description": "Файл", + "value": { + "name": "file_group1/file1", + "presigned_get_url": "" + } + }, + "file_group": { + "summary": "Файловая группа", + "description": "Файловая группа с файлами", + "value": { + "name": "file_group1", + "files": [ + { + "name": "file1", + "presigned_get_url": "" + }, + { + "name": "file2", + "presigned_get_url": "" + } + ] + } + }, + "empty_file_group": { + "summary": "Пустая файловая группа", + "description": "Файловая группа без файлов", + "value": { + "name": "file_group2", + "files": [] + } + }, + "error": { + "summary": "Ошибка", + "description": "Ошибка", + "value": { + "errors": [ + { + "type": "Доступ запрещен", + "message": "Реквизиты не предоставлены" + }, + { + "type": "Ресурс не найден", + "message": "Указанная локация отсутствует" + } + ] + } + } + } + } + } + }, + "successful-write": { + "description": "Операция завершена успешно", + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/WriteFileResponse" + }, + { + "$ref": "#/components/schemas/WriteFileGroupResponse" + } + ] + } + } + }, + "headers": { + "X-Request-Id": { + "$ref": "#/components/headers/request_id" + } + } + } + }, + "securitySchemes": { + "basic_auth": { + "description": "Базовая аутентификация", + "type": "http", + "scheme": "basic" + } + } + } +} \ No newline at end of file diff --git a/controller/src/files/api/openapi.yaml b/controller/src/files/api/openapi.yaml new file mode 100644 index 0000000..d99845d --- /dev/null +++ b/controller/src/files/api/openapi.yaml @@ -0,0 +1,366 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Files +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +openapi: 3.0.3 +info: + title: ML Component - OpenAPI 3.0 + description: |- + Спецификция сервиса Files + termsOfService: https://mlops.hse.ru/ + contact: + email: support-mlops@hse.ru + version: 1.0.0 +#externalDocs: +# description: Find out more about Swagger +# url: http://swagger.io +servers: + - url: http://localhost:8000 +tags: + - name: files + description: Операции с файлами и файловыми группами + externalDocs: + description: Подробнее + url: https://mlops.hse.ru/ +security: + - basic_auth: [] +paths: + '/{app}/files/{box}/{location}': + parameters: + - name: X-Request-Id + in: header + schema: + $ref: '#/components/headers/request_id' + description: Идентификатор для диагностики запроса + examples: + example: + summary: Идентификатор из нулей + description: Идентификатор в формате UUID + value: 00000000-0000-0000-0000-000000000000 + - name: location + in: path + required: true + schema: + type: string + description: | + Путь к файловой группе или к файлу. + + В общем случае имеет вид /, причем + имя , если задано, может состоять из одного или нескольких сегментов. + Имя , если задано, может состоять только из одного сегмента. + + Может принимать значения в следующих форматах: + - '' (новые файловая группа и файл в ней со сгенерированными именами) + - 'a/ (файловая группа a/) + - 'a' (файловая группа a/) + - 'a/b/' (файловая группа a/b/) + - 'a/b' (файл b в файловой группе a/) + - 'a/b/c' (файл c в файловой группе a/b/) + examples: + empty: + summary: Пустое значение + value: '' + description: | + Используется при создании новой файловой группы, + и нового файла в ней. Их имена генерируются автоматически. + file_group: + summary: Файловая группа с простым именем + value: 'a/' + description: | + Соответствует файловой группе, имя которой состоит из одного сегмента. + file_group_complex: + summary: Файловая группа с составным именем + value: 'a/b/' + description: | + Соответствует файловой группе, имя которой состоит из двух сегментов. + file: + summary: Файл в файловой группе + value: 'a/b' + description: | + Соответствует файлу в файловой группе, имя которой состоит из одного сегмента. + - name: box + in: path + required: true + schema: + type: string + description: Имя ящика DataBox + - name: app + in: path + required: true + schema: + type: string + description: Имя приложения PlatformApp + get: + tags: + - files + summary: Получить файл или файловую группу + description: |- + Возвращает файл или файловую группу. + + Если локация соответствует файловой группе, то возвращает файловую группу + со всеми файлами в ней. + + Если локация соответствует файлу, то возвращает файл. + + Пустая локация в GET не поддерживается. + operationId: get_files + responses: + '200': + $ref: '#/components/responses/successful-read' + '400': + description: | + Ошибка входных данных. + Возможные причины: + - Передана пустая локация; + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + headers: + X-Request-Id: + $ref: '#/components/headers/request_id' + '401': + description: Аутентификация не пройдена + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + headers: + X-Request-Id: + $ref: '#/components/headers/request_id' + '404': + description: | + Не найден запрошенный ресурс. + Возможные причины: + - Указанная локация не существует; + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + headers: + X-Request-Id: + $ref: '#/components/headers/request_id' + default: + $ref: '#/components/responses/successful-read' + post: + tags: + - files + summary: Создать файл или файловую группу + description: |- + Создает файл или файловую группу. + + Локация может быть пустой, или соответствовать файловой группе. + Локации, соответствующие файлу, в POST не поддерживаются. + + Если локация соответствует файловой группе, то создает новый пустой файл + со сгенерированным именем в заданной файловой группе. + + Если локация задана пустая, то создает файловую группу и файл в ней + со сгенерированными именами. + operationId: post_files + responses: + '201': + $ref: '#/components/schemas/WriteFileResponse' + '400': + description: | + Ошибка входных данных. + Возможные причины: + - Передана локация, соответствующая файлу; + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + headers: + X-Request-Id: + $ref: '#/components/headers/request_id' + '401': + description: Аутентификация не пройдена + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + headers: + X-Request-Id: + $ref: '#/components/headers/request_id' + default: + $ref: '#/components/schemas/WriteFileResponse' + put: + tags: + - files + summary: Разместить файл или файловую группу + description: |- + Размещает файл или файловую группу. + + Если локация соответствует файловой группе, то создает новую пустую + файловую группу с заданным именем. + Если файловая группа существует, ничего не делает. + + Если локация соответствует файлу, то создает подписанные ссылки + для чтения и записи содержимого файла. Файл не создается. + + Пустая локация в PUT не поддерживается. + operationId: put_files + responses: + '200': + $ref: '#/components/responses/successful-write' + '400': + description: | + Ошибка входных данных. + Возможные причины: + - Передана пустая локация; + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + headers: + X-Request-Id: + $ref: '#/components/headers/request_id' + '401': + description: Аутентификация не пройдена + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + headers: + X-Request-Id: + $ref: '#/components/headers/request_id' + default: + $ref: '#/components/responses/successful-write' +components: + schemas: + ReadFileResponse: + description: Файл со ссылкой для получения содержимого + type: object + properties: + name: + description: Имя + type: string + presigned_get_url: + description: Подписанная ссылка для получения содержимого файла + type: string + required: ["name", "presigned_get_url"] + WriteFileResponse: + description: Файл со ссылкой для загрузки содержимого + type: object + properties: + name: + description: Имя + type: string + presigned_put_url: + description: Подписанная ссылка для загрузки содержимого файла + type: string + required: ["name", "presigned_put_url"] + ReadFileGroupResponse: + description: Файловая группа. + type: object + properties: + name: + description: Имя. + type: string + files: + description: Список файлов в файловой группе. + type: array + items: + $ref: '#/components/schemas/ReadFileResponse' + required: ["name", "files"] + WriteFileGroupResponse: + description: Файловая группа. + type: object + properties: + name: + description: Имя. + type: string + files: + description: Список файлов в файловой группе. + type: array + items: + $ref: '#/components/schemas/WriteFileResponse' + required: ["name", "files"] + ErrorResponse: + description: Объект с результатом операции инференса, которая не завершилась успешно. + type: object + properties: + errors: + description: Список ошибок. + type: array + items: + description: Ошибка при выполнении операции инференса. + type: object + properties: + type: + description: Тип ошибки. + type: string + message: + description: Сообщение с описанием ошибки. + type: string + required: ["type", "message"] + maxItems: 10 + headers: + request_id: + description: Идентификатор для диагностики запроса + schema: + type: string + format: uuid + examples: + example: + summary: Идентификатор из нулей + value: 00000000-0000-0000-0000-000000000000 + responses: + successful-read: + description: Операция завершена успешно + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/ReadFileResponse' + - $ref: '#/components/schemas/WriteFileGroupResponse' + examples: + file: + summary: Файл + description: Файл + value: + name: file_group1/file1 + presigned_get_url: "" + file_group: + summary: Файловая группа + description: Файловая группа с файлами + value: + name: file_group1 + files: + - name: file1 + presigned_get_url: "" + - name: file2 + presigned_get_url: "" + empty_file_group: + summary: Пустая файловая группа + description: Файловая группа без файлов + value: + name: file_group2 + files: [] + error: + summary: Ошибка + description: Ошибка + value: + errors: + - type: Доступ запрещен + message: Реквизиты не предоставлены + - type: Ресурс не найден + message: Указанная локация отсутствует + successful-write: + description: Операция завершена успешно + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/WriteFileResponse' + - $ref: '#/components/schemas/WriteFileGroupResponse' + headers: + X-Request-Id: + $ref: '#/components/headers/request_id' + securitySchemes: + basic_auth: + description: Базовая аутентификация + type: http + scheme: basic diff --git a/controller/src/files/box.py b/controller/src/files/box.py new file mode 100644 index 0000000..bdc9cf7 --- /dev/null +++ b/controller/src/files/box.py @@ -0,0 +1,144 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Files +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +import base64 +from typing import Optional +from uuid import UUID + +from fastapi import HTTPException +from kubernetes_asyncio.client import CustomObjectsApi, ApiException, CoreV1Api, V1Secret, ApiClient +from pydantic import BaseModel + +from files.config import UNIP_BOXES_S3_SECRET_NAME, UNIP_BOXES_S3_DEFAULT_USER_DATA_BUCKET, \ + UNIP_BOXES_S3_DEFAULT_HOST, UNIP_BOXES_S3_DEFAULT_REGION +from files.exceptions import UnipFilesException + +APP_USER_DATA_DEFAULT_BOX_SUFFIX = '-user-data' +UNIP_CONTROLLER_NAMESPACE = 'unip-system-controller' + + +class DataBox(BaseModel): + namespace: str + name: str + uid: UUID + creds_secret_name: str + creds_secret_namespace: str + storage_sub_path: Optional[str] + storage_host: str + storage_name: str + + +def get_box_name(passed_box_name: str, app_name: str, user_id: str) -> str: + """ + Определяет имя используемого ящика в зависимости от значений переданных параметров. + + :param passed_box_name: Переданное в запросе имя ящика. + :param app_name: Имя приложения PlatformApp. + :param user_id: Идентификатор пользователя. + :return: :class:`str ` Имя ящика, который нужно использовать. + """ + if passed_box_name and passed_box_name != '_': + return passed_box_name + return app_name + APP_USER_DATA_DEFAULT_BOX_SUFFIX + + +async def _get_s3_box_creds(api: ApiClient, box: DataBox) -> tuple[str, str, str, str]: + core_v1_api = CoreV1Api(api) + try: + secret: V1Secret = await core_v1_api.read_namespaced_secret(name=box.creds_secret_name, + namespace=box.creds_secret_namespace) + secret_body = secret.to_dict() + except ApiException as exc: + if exc.status == 404: + raise UnipFilesException(f'S3 credentials secret "{box.creds_secret_name}" not found') + raise exc + + if 'data' not in secret_body: + raise UnipFilesException(f'data not set in secret {box.creds_secret_name}') + data = secret_body['data'] + if not (req_fields := {'AWS_ACCESS_KEY_ID', 'AWS_SECRET_ACCESS_KEY'}) <= data.keys(): + raise UnipFilesException(f'some of {req_fields} not set in secret {box.creds_secret_name}') + + access_key = base64.b64decode(data['AWS_ACCESS_KEY_ID']).decode('utf-8') + secret_key = base64.b64decode(data['AWS_SECRET_ACCESS_KEY']).decode('utf-8') + endpoint = box.storage_host + if 'AWS_REGION' in data: + region = base64.b64decode(data['AWS_REGION']).decode('utf-8') + else: + region = UNIP_BOXES_S3_DEFAULT_REGION + return endpoint, access_key, secret_key, region + + +async def _get_box_resource(co_api: CustomObjectsApi, box_name, namespace): + try: + # "обычный" метод + # co_api.get_namespaced_custom_object("unified-platform.cs.hse.ru", "v1", namespace, "databoxes", box_name) + # не является асинхронным по неизвестным причинам, поэтому вызывается "_with_http_info" метод + s3_box_res, _, _ = \ + await co_api.get_namespaced_custom_object_with_http_info("unified-platform.cs.hse.ru", + "v1", + namespace, + "databoxes", + box_name) + except ApiException as exc: + if exc.status == 404: + raise HTTPException(status_code=404, detail=f'Box \'{box_name}\' does not exist') + raise exc + + return s3_box_res + + +async def get_box(api: ApiClient, box_name, app_name) -> DataBox: + """ + Возвращает ящик данных. + + :param api: Асинхронный Kubernetes клиент. + :param box_name: Переданное в запросе имя ящика. + :param app_name: Имя приложения PlatformApp. + :return: :class:`DataBox ` Ящик данных. + """ + co_api = CustomObjectsApi(api) + box_res = await _get_box_resource(co_api, box_name, app_name) + box_spec = box_res['spec'] + + if 's3Storage' not in box_spec \ + and 's3DefaultStorage' not in box_spec \ + and 'datasetReference' not in box_spec: + raise UnipFilesException(f's3Storage, s3DefaultStorage, datasetReference inside Box {box_name} is expected, ' + f'but not presented') + if 's3Storage' in box_spec: + s3_storage = box_spec['s3Storage'] + if 'awsVarsS3Credentials' not in s3_storage: + raise UnipFilesException(f's3Storage inside Box {box_name} is expected, but not presented') + + creds_secret_name = s3_storage['awsVarsS3Credentials'] + storage_host = s3_storage['host'] + bucket = s3_storage['bucket'] + storage_name = bucket['name'] + namespace = creds_secret_namespace = app_name + if 'subPath' in bucket: + storage_sub_path = s3_storage['bucket']['subPath'] + else: + storage_sub_path = None + elif 's3DefaultStorage' in box_spec: + creds_secret_name = UNIP_BOXES_S3_SECRET_NAME + creds_secret_namespace = UNIP_CONTROLLER_NAMESPACE + namespace = app_name + storage_sub_path = app_name + '/' + box_name + storage_name = UNIP_BOXES_S3_DEFAULT_USER_DATA_BUCKET + storage_host = UNIP_BOXES_S3_DEFAULT_HOST + elif 'datasetReference' in box_spec: + raise HTTPException(status_code=404, detail=f'Box \'{box_name}\' does not exist') + else: + raise UnipFilesException(f's3Storage, s3DefaultStorage or datasetReference inside Box {box_name} is expected, ' + f'but not presented') + + box_uid = UUID(box_res['metadata']['uid']) + + return DataBox(name=box_name, uid=box_uid, creds_secret_name=creds_secret_name, + creds_secret_namespace=creds_secret_namespace, + namespace=namespace, storage_sub_path=storage_sub_path, storage_name=storage_name, + storage_host=storage_host) diff --git a/controller/src/files/config.py b/controller/src/files/config.py new file mode 100644 index 0000000..5e26904 --- /dev/null +++ b/controller/src/files/config.py @@ -0,0 +1,14 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Files +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +import os + +UNIP_FILES_RUN_MODE = os.getenv('UNIP_FILES_RUN_MODE') + +UNIP_BOXES_S3_DEFAULT_USER_DATA_BUCKET = os.getenv('UNIP_BOXES_S3_DEFAULT_USER_DATA_BUCKET') +UNIP_BOXES_S3_SECRET_NAME = os.getenv('UNIP_BOXES_S3_SECRET_NAME') +UNIP_BOXES_S3_DEFAULT_HOST = os.getenv('UNIP_BOXES_S3_DEFAULT_HOST') +UNIP_BOXES_S3_DEFAULT_REGION = os.getenv('UNIP_BOXES_S3_DEFAULT_REGION') # "ru-central1" diff --git a/controller/src/files/exceptions.py b/controller/src/files/exceptions.py new file mode 100644 index 0000000..36fe9e8 --- /dev/null +++ b/controller/src/files/exceptions.py @@ -0,0 +1,9 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Files +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ + +class UnipFilesException(Exception): + pass diff --git a/controller/src/files/logging.py b/controller/src/files/logging.py new file mode 100644 index 0000000..f3b849d --- /dev/null +++ b/controller/src/files/logging.py @@ -0,0 +1,32 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Files +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +from logging.config import dictConfig + + +def configure_logging(): + dictConfig({ + 'version': 1, + 'disable_existing_loggers': False, + 'formatters': { + 'default': { + 'format': '[%(asctime)s] [%(levelname)s] [%(name)s]: %(message)s', + } + }, + 'handlers': { + 'default': { + 'class': 'logging.StreamHandler', + 'stream': 'ext://sys.stdout', + 'formatter': 'default' + } + }, + 'loggers': { + 'root': { + 'level': 'INFO', + 'handlers': ['default'] + } + } + }) diff --git a/controller/src/files/s3/aws_signing_libs.md b/controller/src/files/s3/aws_signing_libs.md new file mode 100644 index 0000000..7c21874 --- /dev/null +++ b/controller/src/files/s3/aws_signing_libs.md @@ -0,0 +1,31 @@ +# aws-request-signer + +Используемая библиотека. + +https://github.com/iksteen/aws-request-signer + +Структурированный код, нет зависимостей от HTTP библиотек. + +https://github.com/iksteen/aws-request-signer/blob/master/aws_request_signer/__init__.py + +# Minio + +Только синхронная реализация. Пример интерфейса и реализации + +minio/api.py + +# fastaws + +Зависимость от HTTP библиотеки, пример реализации. + +https://github.com/waydegg/fastaws/blob/master/src/fastaws/core.py +https://github.com/waydegg/fastaws/blob/master/src/fastaws/s3/client.py + +# requests-auth-aws-sigv4 + +https://github.com/andrewjroth/requests-auth-aws-sigv4 + +Зависимость от HTTP библиотек, код плохо структурирован. + +https://github.com/iksteen/aws-request-signer +https://github.com/iksteen/aws-request-signer/blob/master/aws_request_signer/__init__.py \ No newline at end of file diff --git a/controller/src/files/s3/client.py b/controller/src/files/s3/client.py new file mode 100644 index 0000000..f250459 --- /dev/null +++ b/controller/src/files/s3/client.py @@ -0,0 +1,271 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Files +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +import hashlib +import json +import logging +import posixpath +import urllib.parse +from typing import Optional, List, Union + +import httpx +from aws_request_signer import AwsRequestSigner, UNSIGNED_PAYLOAD +from lxml import etree +from lxml.etree import Element + +XML_NAMESPACES = {'s3': 'http://s3.amazonaws.com/doc/2006-03-01/'} + + +class S3Object: + + def __init__(self, bucket_name: str, object_name: Optional[str]): + self.__bucket_name: str = bucket_name + self.__object_name: Optional[str] = object_name + + @property + def bucket_name(self) -> str: + return self.__bucket_name + + @property + def object_name(self) -> Optional[str]: + return self.__object_name + + @property + def is_dir(self) -> bool: + return self.__object_name is not None and self.__object_name.endswith("/") + + +class AsyncS3Client: + """ + Асинхронный клиент для выполнения операций с объектами S3. + + Использует HTTP клиент, правление жизненным циклом которого + осуществляется вне AsyncS3Client. + Это может быть изменено в будущем. + + :param http_client: Асинхронный HTTP клиент. + :param endpoint: Имя хоста S3 сервиса. + :param access_key: Ключ доступа. + :param secret_key: Секрет. + :param region: Регион. + """ + + def __init__(self, + http_client: httpx.AsyncClient, + endpoint: str, + access_key: str, + secret_key: str, + region: str, + logger=None): + if not endpoint.startswith('http'): + endpoint = 'https://' + endpoint + + self.logger = logger if logger else logging.getLogger(__name__) + + endpoint = endpoint.rstrip('/') + self.__endpoint = endpoint + self.__access_key = access_key + self.__secret_key = secret_key + self.__region = region + self.__signer = AwsRequestSigner(access_key_id=access_key, + secret_access_key=secret_key, + region=region, + service='s3') + self.__http_client = http_client + + async def list_objects(self, bucket_name: str, prefix: Optional[str] = None, recursive: bool = False, + max_keys: Optional[int] = None) -> List[S3Object]: + """ + Возвращает список S3 объектов в результате вызова метода GET c URL + {endpoint}/{bucket_name}?prefix={prefix} + + Если результат запроса пустой, то возвращается пустой список. + + Не выполняет нормализацию префикса, то есть префиксы 'obj' и 'obj/' приведут + к различным результатам. + + :param bucket_name: Имя бакета. + :param prefix: Значение параметра запроса prefix. + :param recursive: Если False, то добавляет параметр запроса delimiter со значением '/'. + :param max_keys: Значение параметра запроса max-keys. + :return: :class:`List[S3Object] ` список S3 объектов. + :raises: + httpx.HTTPStatusError: если код ответа отличается от 200. + """ + delimiter = None if recursive else "/" + query_params = {} + if prefix: + query_params["prefix"] = prefix + if max_keys: + query_params["max-keys"] = max_keys + if delimiter: + query_params["delimiter"] = delimiter + + bucket_name = posixpath.normpath(bucket_name) + + query_string_items = [] + if query_params: + for key, value in query_params.items(): + if isinstance(value, str): + value_qs = urllib.parse.quote(value, safe="") + else: + value_qs = value + param_qs = f"{key}={value_qs}" + query_string_items.append(param_qs) + query_string = '&'.join(query_string_items) + + url = f'{self.__endpoint}/{bucket_name}?{query_string}' + + method = 'GET' + headers = self.__signer.sign_with_headers(method=method, url=url) + + response = await self.__http_client.request(method=method, + url=url, + headers=headers) + + if response.status_code != 200: + response.raise_for_status() + + root: Element = etree.XML(response.content) + + s3_objects = [] + content_elements = root.findall(".//s3:Contents", XML_NAMESPACES) + for ce in content_elements: + key = ce.find('s3:Key', XML_NAMESPACES).text + s3_object = S3Object(bucket_name=bucket_name, + object_name=key) + s3_objects.append(s3_object) + + return s3_objects + + async def head_object(self, bucket_name: str, object_name: str) -> S3Object: + """ + Выполняет запрос HEAD c URL + {endpoint}/{bucket_name}/{object_name} + + Если объект существует, возвращает его. + + Если объект не существует, то выбрасывается исключение httpx.HTTPStatusError + с кодом 404. + + Не выполняет нормализацию object_name, то есть имена объектов 'obj' и 'obj/' приведут + к различным результатам. + + :param bucket_name: Имя бакета. + :param object_name: Имя (ключ) объекта.. + :return: :class:`S3Object ` S3 объект. + :raises: + httpx.HTTPStatusError: если код ответа отличается от 200. + """ + + url = f'{self.__endpoint}/{bucket_name}/{object_name}' + + method = 'HEAD' + headers = self.__signer.sign_with_headers(method=method, url=url) + bucket_name = posixpath.normpath(bucket_name) + + response = await self.__http_client.request(method=method, + url=url, + headers=headers) + + if response.status_code != 200: + response.raise_for_status() + + return S3Object(bucket_name=bucket_name, object_name=object_name) + + async def put_object(self, bucket_name: str, object_name: str, data: Optional[Union[dict, str, bytes]] = None): + """ + Выполняет запрос PUT запрос с URL {endpoint}/{bucket_name}/{object_name}, + сохраняет переданные данные как содержимое объекта. + + Не выполняет нормализацию object_name, то есть имена объектов 'obj' и 'obj/' приведут + к различным результатам. + + Если данные data не переданы, то в теле запроса будет передано пустое содержимое. + + Если данные data переданы типа bytes, то они передаются в теле запроса без изменений. + + Если данные data переданы типа str, то они кодируются (переводятся в bytes), используя + кодировку 'utf-8'. + + Если данные data переданы типа dict, то они сначала сериализуются в строку, используя + json.dumps(data). + + :param bucket_name: Имя бакета. + :param object_name: Имя (ключ) объекта. + :param data: Содержимое объекта. + :return: None. + :raises: + httpx.HTTPStatusError: если код ответа отличается от 200. + """ + content = b"" + if data is not None: + if isinstance(data, dict): + content = json.dumps(data).encode('utf-8') + elif isinstance(data, bytes): + content = data + elif isinstance(data, str): + content = data.encode('utf-8') + + bucket_name = posixpath.normpath(bucket_name) + url = f'{self.__endpoint}/{bucket_name}/{object_name}' + method = 'PUT' + + content_hash = hashlib.sha256(content).hexdigest() + + headers = self.__signer.sign_with_headers(method=method, url=url, content_hash=content_hash) + self.logger.info(f'put object {url}') + response = await self.__http_client.request(method=method, + url=url, + headers=headers, + content=content) + + if response.status_code != 200: + response.raise_for_status() + + def presigned_get_object(self, bucket_name: str, object_name: str, expires: int = 86400): + """ + Генерирует подписанную ссылку для получения содержимого объекта по URL + {endpoint}/{bucket_name}/{object_name} + + Не выполняет нормализацию object_name, то есть имена объектов 'obj' и 'obj/' приведут + к различным результатам. + + Не выполняет обращения к удаленному хранилищу. + + Не выполняет подписывание содержимого. + + :param bucket_name: Имя бакета. + :param object_name: Имя (ключ) объекта. + :param expires: Время жизни URL в секундах. По умолчанию равно 24 часам. + :return: :class:`str ` Подписанная ссылка. + """ + bucket_name = posixpath.normpath(bucket_name) + url = f'{self.__endpoint}/{bucket_name}/{object_name}' + method = 'GET' + return self.__signer.presign_url(method=method, url=url, content_hash=UNSIGNED_PAYLOAD, expires=expires) + + def presigned_put_object(self, bucket_name: str, object_name: str, expires: int = 86400): + """ + Генерирует подписанную ссылку для загрузки содержимого объекта по URL + {endpoint}/{bucket_name}/{object_name} + + Не выполняет нормализацию object_name, то есть имена объектов 'obj' и 'obj/' приведут + к различным результатам. + + Не выполняет обращения к удаленному хранилищу. + + Не выполняет подписывание содержимого. + + :param bucket_name: Имя бакета. + :param object_name: Имя (ключ) объекта. + :param expires: Время жизни URL в секундах. По умолчанию равно 24 часам. + :return: :class:`str ` Подписанная ссылка. + """ + bucket_name = posixpath.normpath(bucket_name) + url = f'{self.__endpoint}/{bucket_name}/{object_name}' + method = 'PUT' + return self.__signer.presign_url(method=method, url=url, content_hash=UNSIGNED_PAYLOAD, expires=expires) diff --git a/controller/src/files/s3/s3_url_notes.md b/controller/src/files/s3/s3_url_notes.md new file mode 100644 index 0000000..f4a2231 --- /dev/null +++ b/controller/src/files/s3/s3_url_notes.md @@ -0,0 +1,172 @@ +--- +**Система**: Единая библиотека, Центр ИИ НИУ ВШЭ + +**Модуль**: Files + +**Авторы**: Полежаев В.А., Хританков А.С. + +**Дата создания**: 2024 г. + +--- + +# Директории (папки) + +Понятия директории нет, но префиксы имен (ключ Key) существующих объектов можно считать директориями. + +## Получение директорий и содержимого + +Получить содержимое "директории" можно только при помощи запроса listObjects (или listObjectsV2) +с префиксом, соответствующим имени директории. + +Глубиной возвращаемых результатов (рекурсией) управляет параметр delimeter. +Можно сформулировать правило: +`delimiter = '/' if not recursive else None` + +При этом префикс должен оканчиваться '/'. + +Если обратиться к директории без prefix (то есть как к объекту), +то при существовании директории (как префикса хотя бы одного объекта, +или как пустой директории, см. ниже) вернется 200 и пустой ответ. +Если директория не существует (нет объектов с соответствующим префиксом, нет пустой директории), +то вернется 404. + +Примеры: + +Содержимое директории fg3 (список объектов в директории): +``` +GET https://storage.hosting.net/bucket?prefix=path/fg3/&delimiter=/ +``` +При наличии объектов сама директория как объект в результате-списке не представляется. + +Вернет пустой результат (пустой список), если нет объектов с префиксом fg3 в имени, +иначе вернет их: +``` +GET https://storage.hosting.net/bucket?prefix=path/fg3&delimiter=/ +``` + +Если директории fg3 нет, то вернется пустой результат (пустой список) с кодом 200: +``` +GET https://storage.hosting.net/bucket?prefix=path/fg3/&delimiter=/ +``` + +Вернет 200 и пустой ответ, если директория существует (как префикс существующих объектов, +или как пустая директория), 404 иначе: +``` +GET https://storage.hosting.net/bucket/path/fg3/ +``` + +В последнем примере можно использовать HEAD. +Можно отметить, что запрос такого вида можно использовать одновременно для проверки наличия и директории, +и файла. + +## Создание директории + +Создать директорию можно неявно, создав объект, для имени которого имя "директории" будет являться +префиксом. + +Или явно как пустую директорию, см. ниже. + +## Пустые директории + +Понятия директории нет, но есть "пустые" директории. + +Это объекты: +1) имя которых (ключ Key) оканчивается на '/', и при этом +2) имя которых не является префиксом для других объектов + +### Создание + +"Пустую" директорию можно создать, если: +1) выполнить PUT с именем (ключом), которое оканчивается на '/', +2) ключ не является префиксом для других существующих объектов (не других пустых директорий) +3) передать в теле пустое содержимое (опционально, если имя оканчиается на '/', то пустая +директория будет создана при любом содержимом) + +``` +PUT https://storage.hosting.net/bucket/path/fg4/ +``` + +### Получение + +"Пустую" директорию как объект можно получить в результате запроса +(аналогично "обычным" директориям, см. выше, используя GET с prefix +или GET без prefix) + +Содержимое пустой директории fg4 - один объект fg4/ с размером 0 (список с одним объектом): +``` +GET https://storage.hosting.net/bucket?prefix=path/fg4/&delimiter=/ +``` + +Пустой результат (пустой список), если нет объектов с префиксом fg4: +``` +GET https://storage.hosting.net/bucket?prefix=path/fg4&delimiter=/ +``` + +Вернет 200 и пустой ответ, если директория существует, 404 иначе: +``` +GET https://storage.hosting.net/bucket/path/fg3/ +``` + +### Действия + +Если в "пустую" директорию добавить "настоящий" объект, то директория как объект исчезнет из результата запроса. +Возвращаться будет только один добавленный объект. + +Если в "пустую" директорию добавить вложенную "пустую" директорию, то директория останется в результате запроса. +Также в результат запроса добавится созданная вложенная "пустая" директория. + +Если при наличии "пустой" директории fg4/ добавить файл fg4, то они будут существовать одновременно +(как "пустая" директория и объект): + +``` +PUT https://storage.hosting.net/bucket/path/fg4/ +PUT https://storage.hosting.net/bucket/path/fg4 +``` + +# Объекты + +Имена объектов (ключи Key) не должны оканчиваться '/'. Тогда объект можно создать: + +``` +PUT https://storage.hosting.net/bucket/path/f5 +``` + +Можно создать пустой файл, если в теле запроса не передать содержимое. + +Можно повторно положить объект, заменив существующий (семантика PUT). + +Если при создании объекта, имя объекта оканчивается на '/', то независимо от переданного содержимого +будет создана пустая директория. + +# Пример тестового запроса + +``` +import hashlib + +import requests +from aws_request_signer import AwsRequestSigner + +AWS_REGION = "ru-central1" +AWS_ACCESS_KEY_ID = "" +AWS_SECRET_ACCESS_KEY = "" + +content = b"Hello, World!\n" # can be empty +content_hash = hashlib.sha256(content).hexdigest() + +request_signer = AwsRequestSigner( + AWS_REGION, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, "s3" +) + +URL = "https://storage.host.net/bucket/path/fg/" +#URL = "https://storage.host.net/bucket&prefix=path/fg/&delimiter=/" + +headers = request_signer.sign_with_headers("GET", URL) +# for method with body +# headers = request_signer.sign_with_headers("PUT", URL, content_hash=content_hash) + +r = requests.get(URL, headers=headers) +#r = requests.put(URL, headers=headers, data=content) + +print(r.text) +print(r.status_code) +``` diff --git a/controller/src/kopf_k8s_client.py b/controller/src/kopf_k8s_client.py new file mode 100644 index 0000000..21f88b7 --- /dev/null +++ b/controller/src/kopf_k8s_client.py @@ -0,0 +1,38 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Утилиты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +import kopf +import kubernetes +import kubernetes_asyncio + +from kube_config import unip_load_kube_config, async_unip_load_kube_config + +api_client: kubernetes.client.ApiClient | None = None +async_api_client: kubernetes_asyncio.client.ApiClient | None = None + + +@kopf.on.startup(id='setup-k8s-client') +def setup_k8s_api_client(logger, **kwargs): + unip_load_kube_config(logger) + global api_client + api_client = kubernetes.client.ApiClient() + + +@kopf.on.cleanup(id='teardown-k8s-client') +def tear_down_k8s_api_client(logger, **kwargs): + api_client.close() + + +@kopf.on.startup(id='setup-async-k8s-client') +async def setup_async_k8s_api_client(logger, **kwargs): + await async_unip_load_kube_config(logger) + global async_api_client + async_api_client = kubernetes_asyncio.client.ApiClient() + + +@kopf.on.cleanup(id='teardown-async-k8s-client') +async def tear_down_async_k8s_api_client(logger, **kwargs): + await async_api_client.close() diff --git a/controller/src/kube_config.py b/controller/src/kube_config.py new file mode 100644 index 0000000..34d48e5 --- /dev/null +++ b/controller/src/kube_config.py @@ -0,0 +1,40 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Утилиты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +import kubernetes +import kubernetes_asyncio + + +def unip_load_kube_config(logger): + logger.info("Sync load kubeconfig") + try: + kubernetes.config.load_incluster_config() + logger.info("Client is configured in cluster with service account.") + except kubernetes.config.ConfigException as exc1: + logger.debug('Cannot configure client in-cluster', exc_info=exc1) + try: + kubernetes.config.load_kube_config() + logger.info("Client is configured via kubeconfig file.") + except kubernetes.config.ConfigException as exc2: + logger.debug('Cannot configure client via kubeconfig', exc_info=exc2) + raise Exception("Cannot authenticate the client library " + "neither in-cluster, nor via kubeconfig.") + + +async def async_unip_load_kube_config(logger): + logger.info("Async load kubeconfig") + try: + kubernetes_asyncio.config.load_incluster_config() + logger.info("Async client is configured in cluster with service account.") + except kubernetes_asyncio.config.ConfigException as exc1: + logger.debug('Cannot configure async client in-cluster', exc_info=exc1) + try: + await kubernetes_asyncio.config.load_kube_config() + logger.info("Async client is configured via kubeconfig file.") + except kubernetes_asyncio.config.ConfigException as exc2: + logger.debug('Cannot configure async client via kubeconfig', exc_info=exc2) + raise Exception("Cannot authenticate the async client library " + "neither in-cluster, nor via kubeconfig.") diff --git a/controller/src/location.py b/controller/src/location.py new file mode 100644 index 0000000..2e78075 --- /dev/null +++ b/controller/src/location.py @@ -0,0 +1,64 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Утилиты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +import urllib.parse +import posixpath + + +def parse_location(location: str) -> tuple[str | None, str | None]: + """ + Выполняет парсинг строки локации, чтобы выделить имя файловой группы + и имя файла. + + Если локация является пустой ('', '/', None), то файловая группа = None, файл = None. + + Если локация состоит из одного сегмента ('fg', 'fg/', то файловая группа = fg, файл = None. + + Если локация состоит из любого числа сегментов, но оканчивается на '/' + ('f/g/', 'f/g/h/'), то файловая группа = локация целиком, файл = None. + + Если локация состоит из более чем одного сегмента и не оканчивается на '/' ( + ('fg/f1', 'f/g/f2'), то файловая группа = все сегменты, кроме последнего, + файл - последний сегмент. + + Имена файловой группы и файла, которые возвращаются, всегда не начинаются с символа '/' + и всегда не знаканчиваются символом '/'. + + >>> parse_location('/') + (None, None) + + >>> parse_location('/a') + ('a', None) + + >>> parse_location('a') + ('a', None) + + >>> parse_location('a/b/') + ('a/b', None) + + >>> parse_location('a/b') + ('a', 'b') + """ + file_group_name = None + file_name = None + + if location in {'/', '', None}: + return file_group_name, file_name + + loc_unquoted = urllib.parse.unquote(location) + loc_norm = posixpath.normpath(loc_unquoted) + if loc_norm.startswith('/'): + loc_norm = loc_norm[1:] + left_part, right_segment = posixpath.split(loc_norm) + if left_part == '': + file_group_name = right_segment + elif loc_unquoted.endswith(posixpath.sep): + file_group_name = loc_norm + else: + file_group_name = left_part + file_name = right_segment + + return file_group_name, file_name \ No newline at end of file diff --git a/controller/src/main.py b/controller/src/main.py new file mode 100644 index 0000000..6354361 --- /dev/null +++ b/controller/src/main.py @@ -0,0 +1,26 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Утилиты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +# noinspection PyUnresolvedReferences +import config +# noinspection PyUnresolvedReferences +import platform_user.handlers +# noinspection PyUnresolvedReferences +import mlcmp.handlers +# noinspection PyUnresolvedReferences +import platform_app.handlers +# noinspection PyUnresolvedReferences +import box.handlers +# noinspection PyUnresolvedReferences +import exp_pipeline.handlers +# noinspection PyUnresolvedReferences +import apicmp.handlers +# noinspection PyUnresolvedReferences +import cmplink.handlers +# noinspection PyUnresolvedReferences +import repository.handlers +# noinspection PyUnresolvedReferences +import datasetcmp.handlers diff --git a/controller/src/mlcmp/__init__.py b/controller/src/mlcmp/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/controller/src/mlcmp/connected_boxes.py b/controller/src/mlcmp/connected_boxes.py new file mode 100644 index 0000000..1e2ec39 --- /dev/null +++ b/controller/src/mlcmp/connected_boxes.py @@ -0,0 +1,247 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: MLComponent +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +import base64 +import os +from dataclasses import dataclass + +from kubernetes.client import CoreV1Api, ApiException, V1Secret, CustomObjectsApi, ApiClient + +from exceptions import InputValidationPermanentError, ObjectDoesNotExistTemporaryError, \ + RelatedObjectNotReadyTemporaryError + + +# todo: MLComponentEnvVar можно перенести в handlers, убрать завиимость connected_boxes от MLComponentEnvVar +@dataclass +class MLComponentEnvVar: + name: str + value: str + + +def _check_pvc_exists(core_v1_api: CoreV1Api, namespace, name, logger): + try: + core_v1_api.read_namespaced_persistent_volume_claim(name, namespace) + except ApiException as exc: + if exc.status == 404: + raise ObjectDoesNotExistTemporaryError(f"PVC {name} in namespace {namespace} doesnt exist") + raise exc + logger.info(f"PVC {name} in namespace {namespace} exists, ok") + + +def _get_csi_s3_pvcs(core_v1_api: CoreV1Api, logger, namespace, + connected_box_name, mount_path, sub_path, pvc_name): + _check_pvc_exists(core_v1_api, namespace, pvc_name, logger) + + # todo: validate connected box name (earlier?) + volume_in_spec_name = connected_box_name.replace('_', '-') + + volume_spec_to_use = {'volume_in_spec_name': volume_in_spec_name, + 'mount_path': mount_path, + 'sub_path': sub_path, + 'pvc_name': pvc_name} + + return volume_spec_to_use + + +def _get_s3_box(co_api: CustomObjectsApi, s3_box_name, namespace, expected_box_types=None): + try: + s3_box_res = co_api.get_namespaced_custom_object("unified-platform.cs.hse.ru", "v1", namespace, + "databoxes", s3_box_name) + except ApiException as exc: + if exc.status == 404: + raise InputValidationPermanentError(f'Box {s3_box_name} does not exist, but required') + raise exc + + if not expected_box_types: + expected_box_types = {'s3Storage', 's3DefaultStorage'} + + if not any(et in s3_box_res['spec'] for et in expected_box_types): + raise InputValidationPermanentError(f' One of {expected_box_types} is expected, but not presented ' + f'in repository box {s3_box_name}') + if 's3Storage' not in s3_box_res['status']: + raise InputValidationPermanentError(f's3Storage {s3_box_name} status is expected, but not presented') + + s3_box_status_conditions = s3_box_res['status']['conditions'] + ready = [c for c in s3_box_status_conditions if c['type'] == 'Ready'] + if not ready or ready[0]['conditionStatus'] != 'True': + raise RelatedObjectNotReadyTemporaryError(f'Box {s3_box_name} not ready', delay=30) + + return s3_box_res + + +def _get_s3_params_from_box(co_api: CustomObjectsApi, s3_box_name, namespace): + data = {} + + s3_box_res = _get_s3_box(co_api, s3_box_name, namespace, {'s3Storage', 's3DefaultStorage'}) + + s3_storage_status = s3_box_res['status']['s3Storage'] + if ('csiS3PersistentVolumeClaimName' not in s3_storage_status) \ + or (not s3_storage_status['csiS3PersistentVolumeClaimName']): + raise InputValidationPermanentError(f's3Storage {s3_box_name} csiS3PersistentVolumeClaimName not set') + + data['pvc_name'] = s3_storage_status['csiS3PersistentVolumeClaimName'] + return data + + +def _process_connected_boxes_section(co_api: CustomObjectsApi, namespace, connected_boxes_section): + results = [] + for box in connected_boxes_section: + data = {} + box_name = box['name'] + data['connected_box_name'] = box_name + if 'mountS3Box' in box: + if 'path' not in box: + raise InputValidationPermanentError(f'path is required for mountS3Box') + data['mount_path'] = box['path'] + mount_s3_box = box['mountS3Box'] + s3_box_name = mount_s3_box['s3BoxName'] + data['sub_path'] = mount_s3_box.get('subPath', None) + + s3_params = _get_s3_params_from_box(co_api, s3_box_name, namespace) + data |= s3_params + results.append(('s3Box.mount', data)) + + return results + + +get_functions_registry = { + 's3Box.mount': _get_csi_s3_pvcs +} + + +def get_volumes_specs(api_client: ApiClient, logger, namespace, connected_boxes_section): + core_v1_api = CoreV1Api(api_client) + co_api = CustomObjectsApi(api_client) + volumes_specs_to_use = [] + connected_boxes = _process_connected_boxes_section(co_api, namespace, connected_boxes_section) + for key, data in connected_boxes: + if key not in get_functions_registry: + logger.warning(f'get function for key {key} not registered') + continue + connected_box_name = data.pop('connected_box_name') + get_func = get_functions_registry[key] + volume_spec_to_use = get_func(core_v1_api=core_v1_api, logger=logger, namespace=namespace, + connected_box_name=connected_box_name, **data) + volumes_specs_to_use.append(volume_spec_to_use) + return volumes_specs_to_use + + +def _get_s3_aws_creds_from_secret(core_v1_api: CoreV1Api, co_api: CustomObjectsApi, s3_box_name, namespace): + s3_box_res = _get_s3_box(co_api, s3_box_name, namespace, {'s3Storage'}) + s3_storage = s3_box_res['spec']['s3Storage'] + if 'awsVarsS3Credentials' not in s3_storage: + raise InputValidationPermanentError(f'awsVarsS3Credentials is expected, but not presented ' + f'in box {s3_box_name}') + s3_storage_secret_name = s3_storage['awsVarsS3Credentials'] + secret: V1Secret = core_v1_api.read_namespaced_secret(name=s3_storage_secret_name, namespace=namespace) + credentials = secret.to_dict()['data'] + access_key_id = base64.b64decode(credentials['AWS_ACCESS_KEY_ID']).decode('utf-8') + secret_access_key = base64.b64decode(credentials['AWS_SECRET_ACCESS_KEY']).decode('utf-8') + return access_key_id, secret_access_key + + +def get_file_box_env(file_box_name, + connected_boxes_section) \ + -> list[MLComponentEnvVar]: + # для поддержки режима монтирования (сейчас только копирование) + # реализация может быть аналогична get_model_storage_env + for box in connected_boxes_section: + if box['name'] == file_box_name: + if 'copyS3Box' not in box: + raise InputValidationPermanentError('Only support of copyS3Box for fileExchange ' + 'is implemented now') + api_files_s3_box = box['copyS3Box'] + s3_box_name = api_files_s3_box['s3BoxName'] + + envs = [MLComponentEnvVar(name='FILES_S3_BOX_NAME', + value=s3_box_name), + MLComponentEnvVar(name='FILES_S3_MODE', + value='COPY')] + return envs + + raise InputValidationPermanentError(f'Box with name {file_box_name} not found in connectedBoxes section') + + +def get_file_exchange_copy_flag(file_box_name, connected_boxes_section) -> bool: + for box in connected_boxes_section: + if box['name'] == file_box_name: + if 'copyS3Box' not in box: + raise InputValidationPermanentError('Only support of copyS3Box for fileExchange ' + 'is implemented now') + # сейчас поддерживается только режим копирования + return True + return False + + +def _get_s3_aws_creds_envs(core_v1_api: CoreV1Api, co_api: CustomObjectsApi, s3_box_name, + namespace, envs_prefix='MODEL_S3_'): + envs = [] + access_key_id, secret_access_key = _get_s3_aws_creds_from_secret(core_v1_api, co_api, s3_box_name, + namespace) + envs.append(MLComponentEnvVar(name=envs_prefix + 'AWS_ACCESS_KEY_ID', value=access_key_id)) + envs.append(MLComponentEnvVar(name=envs_prefix + 'AWS_SECRET_ACCESS_KEY', value=secret_access_key)) + return envs + + +def _get_s3_config_envs(co_api: CustomObjectsApi, s3_box_name, namespace, + envs_prefix='MODEL_S3_'): + s3_box_res = _get_s3_box(co_api, s3_box_name, namespace, {'s3Storage'}) + s3_storage = s3_box_res['spec']['s3Storage'] + config_data = {'host_port': s3_storage['host'], + 'bucket_name': s3_storage['bucket']['name']} + if 'subPath' in s3_storage['bucket']: + config_data['bucket_sub_path'] = s3_storage['bucket']['subPath'] + + envs = [MLComponentEnvVar(name=envs_prefix + 'HOST_PORT', value=s3_storage['host']), + MLComponentEnvVar(name=envs_prefix + 'BUCKET_NAME', value=s3_storage['bucket']['name'])] + return config_data, envs + + +def get_model_box_env(api_client: ApiClient, namespace, + model_box_name, connected_boxes_section) \ + -> list[MLComponentEnvVar]: + core_v1_api = CoreV1Api(api_client) + co_api = CustomObjectsApi(api_client) + for box in connected_boxes_section: + if box['name'] == model_box_name: + if not any(supported_boxes := {'copyS3Box', 'mountS3Box'} & box.keys()): + raise InputValidationPermanentError(f'No supported boxes {supported_boxes} found') + if 'copyS3Box' in box: + if 'path' not in box: + raise InputValidationPermanentError(f'path is expected, but not presented ' + f'in connected box {model_box_name}') + envs = [MLComponentEnvVar(name='MODEL_S3_COPY_LOCAL_PATH', value=box['path']), + MLComponentEnvVar(name='MODEL_S3_MODE', value='COPY')] + copy_s3_box = box['copyS3Box'] + s3_box_name = copy_s3_box['s3BoxName'] + envs += _get_s3_aws_creds_envs(core_v1_api, co_api, s3_box_name, namespace) + + config_data, config_envs = _get_s3_config_envs(co_api, s3_box_name, + namespace) + envs += config_envs + model_s3_copy_bucket_path = '' + if 'subPath' in copy_s3_box: + model_s3_copy_bucket_path = copy_s3_box['subPath'] + if 'bucket_sub_path' in config_data: + model_s3_copy_bucket_path = os.path.join(config_data['bucket_sub_path'], + model_s3_copy_bucket_path) + + envs.append(MLComponentEnvVar(name='MODEL_S3_COPY_BUCKET_PATH', value=model_s3_copy_bucket_path)) + return envs + if 'mountS3Box' in box: + envs = [MLComponentEnvVar(name='MODEL_S3_MODE', value='MOUNT')] + return envs + + raise InputValidationPermanentError(f'Box with name {model_box_name} not found in connectedBoxes section') + + +def get_download_model_flag(model_box_name, connected_boxes_section): + for box in connected_boxes_section: + if box['name'] == model_box_name: + if 'copyS3Box' in box: + return True + return False + return False diff --git a/controller/src/mlcmp/handlers.py b/controller/src/mlcmp/handlers.py new file mode 100644 index 0000000..446e412 --- /dev/null +++ b/controller/src/mlcmp/handlers.py @@ -0,0 +1,617 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: MLComponent +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +""" +MLComponent object module. Handles all actions with MLComponent Kubernetes objects. +""" + +import base64 +import dataclasses +from dataclasses import dataclass +from typing import Optional + +import kopf +import yaml +from kubernetes.client import AppsV1Api, CoreV1Api, V1Secret, ApiException, V1ConfigMap +from packaging.specifiers import SpecifierSet, InvalidSpecifier + +from basic_resources.network_policies import create_network_policy, delete_network_policy_if_exists +from bound import not_dev_namespace +from exceptions import InputValidationPermanentError +from kopf_k8s_client import api_client +from mlcmp.connected_boxes import get_volumes_specs, get_file_box_env, \ + get_model_box_env, get_download_model_flag, get_file_exchange_copy_flag, \ + MLComponentEnvVar +from mlcmp.jinja import jinja_env +from parse import extract_domain + +ALLOW_ML_CMP_INGRESS_TRAFFIC_NP_TEMPLATE = 'allow-ml-cmp-ingress-traffic-np.yaml' +SERVICE_PORT = 80 +FILES_CONFIG_MAP_NAME = 'files-cfg' + +CONFIG_MAP_SUFFIX = '-cfg' +SECRET_SUFFIX = '-cred' + +IS_GPU_AVAILABLE_TAINT_NAME = 'node.unified-platform.cs.hse.ru/is-gpu-available' +IS_INTERRUPTIBLE_TAINT_NAME = 'node.unified-platform.cs.hse.ru/is-interruptible' +GPU_LABEL_NAME = 'node.unified-platform.cs.hse.ru/resources.gpu' +MLCMP_NODE_LABEL_NAME = 'node.unified-platform.cs.hse.ru/components.mlcomponent' + + +@dataclass +class MLComponentEnvFromItem: + key: str + body: str + + +@dataclass +class MLComponentVolume: + volume_name: str + pvc_name: str + + +@dataclass +class MLComponentVolumeMount: + volume_name: str + mount_path: str + sub_path: Optional[str] + + +@dataclass +class MLComponentResourceLimits: + cpu: Optional[str] + memory: Optional[str] + gpu: Optional[str] + + +@dataclass +class MLComponentResourceRequests: + cpu: Optional[str] + memory: Optional[str] + gpu: Optional[str] + + +@dataclass +class MLComponentToleration: + key: str + operator: str + value: str + effect: str + + +@dataclass +class MLComponentNodeAffinityExpression: + key: str + operator: str + vals: list[str] + + +@dataclass +class MLComponentNodeAffinity: + expressions: list[MLComponentNodeAffinityExpression] + + +@dataclass +class MLComponent: + name: str + namespace: str + deployment_name: str + service_name: str + image_name: str + python_package_registry_credentials: str + python_package_registry_host: str + python_package_version: Optional[str] + container_port: int + service_port: int + env: list[MLComponentEnvVar] + env_from: list[MLComponentEnvFromItem] + image_registry_credentials_secret_name: str + volumes: list[MLComponentVolume] + volume_mounts: list[MLComponentVolumeMount] + download_model: bool + file_exchange_copy: bool + resource_requests: Optional[MLComponentResourceRequests] + resource_limits: Optional[MLComponentResourceLimits] + tolerations: list[MLComponentToleration] + node_affinity: MLComponentNodeAffinity + + +@dataclass +class AllowIngressTrafficNetworkPolicy: + name: str + namespace: str + ml_component_name: str + + +def _get_deployment_name(name): + return f'{name}-deployment' + + +def _get_service_name(name): + return f'{name}-svc' + + +def _check_ml_component_is_ml_service(spec): + if 'mlService' not in spec: + raise InputValidationPermanentError('Only mlService is implemented now') + + +def _get_image_reg_and_image_name_frm_image_section(spec): + image = spec['image'] + if 'existingImageName' not in image: + raise InputValidationPermanentError('Only support of existing images is implemented now') + + image_name = image['existingImageName'] + image_registry_name = extract_domain(image_name) + image_registry_cred_name = image_registry_name + SECRET_SUFFIX + + return image_registry_cred_name, image_name + + +def _get_env_from_model_section(namespace, model_section, + connected_boxes_section) \ + -> list[MLComponentEnvVar]: + model_path = model_section['modelPath'] + model_path_env_var = MLComponentEnvVar(name='INFERENCE_MODEL_PATH', value=model_path) + envs = [model_path_env_var] + if 'modelKind' in model_section: + model_kind = model_section['modelKind'] + model_kind_env_var = MLComponentEnvVar(name='INFERENCE_MODEL_KIND', value=model_kind) + envs.append(model_kind_env_var) + model_box_name = model_section['modelBox'] + if connected_boxes_section: + envs += get_model_box_env(api_client, namespace, model_box_name, connected_boxes_section) + return envs + + +def _get_env_from_file_exchange_section(file_exchange_section, + connected_boxes_section) -> list[MLComponentEnvVar]: + file_box_name = file_exchange_section['fileBox'] + inference_files_path = file_exchange_section['inferenceFilesPath'] + envs = [MLComponentEnvVar(name='FILES_S3_COPY_INFERENCE_FILES_DIR', value=inference_files_path)] + if not connected_boxes_section: + return envs + envs += get_file_box_env(file_box_name=file_box_name, + connected_boxes_section=connected_boxes_section) + return envs + + +def _get_file_exchange_copy_flag(file_exchange_section, + connected_boxes_section) -> bool: + file_box_name = file_exchange_section['fileBox'] + if connected_boxes_section: + return get_file_exchange_copy_flag(file_box_name, connected_boxes_section) + return False + + +def _get_env_from_entry_point_section(entry_point_section) -> list[MLComponentEnvVar]: + envs = [] + if 'pythonPath' in entry_point_section: + envs.append(MLComponentEnvVar(name='PYTHONPATH_EXTENSION', value=entry_point_section['pythonPath'])) + envs.append(MLComponentEnvVar(name='INFERENCE_FUNCTION', value=entry_point_section['pythonFunction'])) + return envs + + +def _get_env_from_env_section(spec) -> list[MLComponentEnvVar]: + env_section = spec.get('env') + envs = [] + if env_section: + envs = [MLComponentEnvVar(name=env_var['name'], value=env_var['value']) for env_var in env_section] + return envs + + +def _get_env_from_license_section(ml_service_section) -> list[MLComponentEnvVar]: + license_section = ml_service_section.get('license') + envs = [] + if license_section: + if 'licenseLocalPath' in license_section: + return [MLComponentEnvVar(name='LICENSE_LOCAL_PATH', value=license_section['licenseLocalPath'])] + return envs + + +def _get_env_from_api_section(ml_service_section) -> list[MLComponentEnvVar]: + api_section = ml_service_section.get('api') + envs = [] + if api_section: + if 'prefix' in api_section: + return [MLComponentEnvVar(name='UNIP_MLCMP_PATH_PREFIX', value=api_section['prefix'])] + return envs + + +def _get_spec_resource_limits(spec) -> dict: + if 'resourceLimits' not in spec: + raise InputValidationPermanentError(f"resourceLimits must be set") + resource_limits: dict = spec['resourceLimits'] + return resource_limits + + +def _get_resource_limits(spec) -> Optional[MLComponentResourceLimits]: + resource_limits = _get_spec_resource_limits(spec) + if 'cpu' not in resource_limits and 'memory' not in resource_limits: + raise InputValidationPermanentError(f"cpu and memory must be set") + cpu = resource_limits.get('cpu', None) + memory = resource_limits.get('memory', None) + gpu = resource_limits.get('gpu', None) + return MLComponentResourceLimits(cpu=cpu, memory=memory, gpu=gpu) + + +def _get_resource_requests(spec) -> Optional[MLComponentResourceRequests]: + resource_limits = _get_spec_resource_limits(spec) + gpu = resource_limits.get('gpu', None) + return MLComponentResourceRequests(cpu="0m", memory=None, gpu=gpu) + + +def _get_node_affinity(spec) -> MLComponentNodeAffinity: + resource_limits = _get_spec_resource_limits(spec) + gpu = resource_limits.get('gpu', None) + mlcmp_expr = MLComponentNodeAffinityExpression(key=MLCMP_NODE_LABEL_NAME, + operator='In', + vals=['true']) + node_affinity = MLComponentNodeAffinity(expressions=[mlcmp_expr]) + + if gpu: + gpu_expr = MLComponentNodeAffinityExpression(key=GPU_LABEL_NAME, operator='In', vals=['true']) + node_affinity.expressions.append(gpu_expr) + + return node_affinity + + +def _get_tolerations(spec) -> list[MLComponentToleration]: + resource_limits = _get_spec_resource_limits(spec) + gpu = resource_limits.get('gpu', None) + + tolerations = [MLComponentToleration(key=IS_INTERRUPTIBLE_TAINT_NAME, + operator='Equal', + value='true', + effect='NoSchedule')] + + if gpu: + tolerations.append(MLComponentToleration( + key=IS_GPU_AVAILABLE_TAINT_NAME, + operator='Equal', + value='true', + effect='NoSchedule')) + + return tolerations + + +def _get_env_from_from_env_from_section(spec) -> list[MLComponentEnvFromItem]: + res = [] + env_from_section = spec.get('envFrom') + if env_from_section is None: + return res + + for elem in env_from_section: + # elem: {'configMapRef': {'name': 'env-configmap'}} + key_and_body = list(elem.items()) + # key_and_body: [('configMapRef', {'name': 'env-configmap'})] + key = key_and_body[0][0] + # key: "configMapRef" + body = key_and_body[0][1] + # body: {'name': 'env-configmap'} + body_str = str(body).replace('{', '').replace('}', '').replace('\'', '') + # body_str: "name: env-configmap" + item = MLComponentEnvFromItem(key=key, body=body_str) + res.append(item) + return res + + +def _get_env_from_for_files_cm() -> list[MLComponentEnvFromItem]: + # key_and_body: [('configMapRef', {'name': 'env-configmap'})] + key = "configMapRef" + # key: "configMapRef" + body = {'name': FILES_CONFIG_MAP_NAME} + # body: {'name': 'env-configmap'} + body_str = str(body).replace('{', '').replace('}', '').replace('\'', '') + # body_str: "name: env-configmap" + env_from = MLComponentEnvFromItem(key=key, body=body_str) + return [env_from] + + +def _get_py_package_reg_cred_and_host(core_v1_api: CoreV1Api, spec, namespace): + package_registry_name = spec['mlService']['packageRegistryName'] + package_registry_cred_name = package_registry_name + SECRET_SUFFIX + package_registry_cm_name = package_registry_name + CONFIG_MAP_SUFFIX + + secret: V1Secret = core_v1_api.read_namespaced_secret(name=package_registry_cred_name, namespace=namespace) + secret_body = secret.to_dict() + credentials = base64.b64decode(secret_body['data']['credentials']).decode('utf-8') + + config_map: V1ConfigMap = core_v1_api.read_namespaced_config_map(name=package_registry_cm_name, namespace=namespace) + config_map_body = config_map.to_dict() + host = config_map_body['data']['host'] + + return credentials, host + + +def _get_py_package_version_spec(spec, logger): + ml_service = spec['mlService'] + if 'packageVersionSpec' not in ml_service: + return None + version_str = ml_service['packageVersionSpec'] + try: + SpecifierSet(version_str) + except InvalidSpecifier as exc: + logger.error(exc) + raise InputValidationPermanentError from exc + return version_str + + +def _get_mlcmp_package_app_name_env() -> list[MLComponentEnvVar]: + return [MLComponentEnvVar(name='MLCMP_PACKAGE_APP_NAME', value='unip.mlcmp.api:app')] + + +def _get_app_name_env(app_name) -> list[MLComponentEnvVar]: + return [MLComponentEnvVar(name='UNIP_MLCMP_APP_NAME', value=app_name)] + + +def _get_ml_component_service_port(spec): + ml_component_service_port = spec.get('servicePort') + if not ml_component_service_port: + raise InputValidationPermanentError(f"Service port must be set. Got {ml_component_service_port!r}.") + return ml_component_service_port + + +def _get_volumes_and_volume_mounts(spec, namespace, logger) \ + -> tuple[list[MLComponentVolume], list[MLComponentVolumeMount]]: + if 'connectedBoxes' not in spec: + return [], [] + + volumes = [] + volume_mounts = [] + volumes_specs_to_use = get_volumes_specs(api_client, logger, namespace, spec['connectedBoxes']) + for volume_spec in volumes_specs_to_use: + volumes.append(MLComponentVolume(volume_name=volume_spec['volume_in_spec_name'], + pvc_name=volume_spec['pvc_name'])) + volume_mounts.append(MLComponentVolumeMount(volume_name=volume_spec['volume_in_spec_name'], + mount_path=volume_spec['mount_path'], + sub_path=volume_spec['sub_path'])) + return volumes, volume_mounts + + +def _create_deployment(apps_v1_api: AppsV1Api, namespace, manifest): + apps_v1_api.create_namespaced_deployment(namespace=namespace, body=manifest) + + +def _create_service(core_v1_api: CoreV1Api, namespace, manifest): + core_v1_api.create_namespaced_service(namespace=namespace, body=manifest) + + +def _delete_deployment_if_exists(apps_v1_api: AppsV1Api, name, namespace, logger): + deployment_name = _get_deployment_name(name) + try: + apps_v1_api.delete_namespaced_deployment(name=deployment_name, namespace=namespace) + except ApiException as exc: + if exc.status == 404: + logger.warn(f"Deployment {deployment_name} doesnt exist, do nothing") + return + raise exc + logger.info(f"Deployment {deployment_name} is deleted") + + +def _delete_service_if_exists(core_v1_api: CoreV1Api, name, namespace, logger): + service_name = _get_service_name(name) + try: + core_v1_api.delete_namespaced_service(name=service_name, namespace=namespace) + except ApiException as exc: + if exc.status == 404: + logger.warn(f"Service {service_name} doesnt exist, do nothing") + return + raise exc + logger.info(f"Service {service_name} is deleted") + + +def _get_download_model_flag(model_section, connected_boxes_section): + model_box_name = model_section['modelBox'] + if connected_boxes_section: + return get_download_model_flag(model_box_name, connected_boxes_section) + return False + + +def _construct_ml_component(core_v1_api: CoreV1Api, + spec, name, namespace, logger) -> MLComponent: + _check_ml_component_is_ml_service(spec) + + image_registry_cred_name, image_name = _get_image_reg_and_image_name_frm_image_section(spec) + py_package_reg_cred, py_package_reg_host = _get_py_package_reg_cred_and_host(core_v1_api, spec, namespace) + + py_package_version = _get_py_package_version_spec(spec, logger) + + volumes, volume_mounts = _get_volumes_and_volume_mounts(spec, namespace, logger) + + ml_component_service_port = _get_ml_component_service_port(spec) + + env = _get_env_from_model_section(namespace, spec['mlService']['inference']['model'], + spec.get('connectedBoxes')) + + download_model = _get_download_model_flag(spec['mlService']['inference']['model'], spec.get('connectedBoxes')) + + file_exchange_copy = _get_file_exchange_copy_flag(spec['mlService']['inference']['fileExchange'], + spec.get('connectedBoxes')) + + env += _get_env_from_file_exchange_section(spec['mlService']['inference']['fileExchange'], + spec.get('connectedBoxes')) + env += _get_env_from_entry_point_section(spec['mlService']['inference']['entryPoint']) + + env += _get_env_from_license_section(spec['mlService']) + + env += _get_env_from_api_section(spec['mlService']) + + env += _get_app_name_env(namespace) + + env += _get_env_from_env_section(spec) + + env += _get_mlcmp_package_app_name_env() + + env_from = _get_env_from_for_files_cm() + + env_from += _get_env_from_from_env_from_section(spec) + + deployment_name = _get_deployment_name(name) + + service_name = _get_service_name(name) + + resource_limits = _get_resource_limits(spec) + resource_requests = _get_resource_requests(spec) + + node_affinity = _get_node_affinity(spec) + tolerations = _get_tolerations(spec) + + service_port = SERVICE_PORT + + ml_component = MLComponent(name=name, namespace=namespace, deployment_name=deployment_name, image_name=image_name, + python_package_registry_credentials=py_package_reg_cred, + python_package_registry_host=py_package_reg_host, + python_package_version=py_package_version, + container_port=ml_component_service_port, + env=env, env_from=env_from, + image_registry_credentials_secret_name=image_registry_cred_name, + volumes=volumes, volume_mounts=volume_mounts, service_name=service_name, + service_port=service_port, download_model=download_model, + file_exchange_copy=file_exchange_copy, + resource_limits=resource_limits, + resource_requests=resource_requests, + tolerations=tolerations, + node_affinity=node_affinity) + + return ml_component + + +def _construct_deployment_manifest(ml_component: MLComponent): + template = jinja_env.get_template('ml-component-deployment.yaml') + text = template.render(dataclasses.asdict(ml_component)) + data = yaml.safe_load(text) + return data + + +def _construct_service_manifest(ml_component: MLComponent): + template = jinja_env.get_template('ml-component-svc.yaml') + text = template.render(dataclasses.asdict(ml_component)) + data = yaml.safe_load(text) + return data + + +def _create_ml_component_deployment(core_v1_api, apps_v1_api, spec, name, namespace, logger): + ml_component = _construct_ml_component(core_v1_api, spec, name, namespace, logger) + deployment_manifest = _construct_deployment_manifest(ml_component) + _create_deployment(apps_v1_api, namespace, deployment_manifest) + + +def _create_ml_component_service(core_v1_api, spec, name, namespace, logger): + ml_component = _construct_ml_component(core_v1_api, spec, name, namespace, logger) + service_manifest = _construct_service_manifest(ml_component) + _create_service(core_v1_api, namespace, service_manifest) + + +def _get_allow_ingress_traffic_np_name(name): + return f'ingress-{name}-traffic' + + +def _construct_allow_ingress_traffic_np_manifest(np: AllowIngressTrafficNetworkPolicy): + template = jinja_env.get_template(ALLOW_ML_CMP_INGRESS_TRAFFIC_NP_TEMPLATE) + text = template.render(dataclasses.asdict(np)) + data = yaml.safe_load(text) + return data + + +def _create_allow_ingress_traffic_np(name, namespace, logger): + np_name = _get_allow_ingress_traffic_np_name(name) + np = AllowIngressTrafficNetworkPolicy(name=np_name, namespace=namespace, ml_component_name=name) + manifest = _construct_allow_ingress_traffic_np_manifest(np) + create_network_policy(api_client=api_client, manifest=manifest, namespace=namespace, + logger=logger) + + +def _delete_allow_ingress_traffic_np(name, namespace, logger): + np_name = _get_allow_ingress_traffic_np_name(name) + delete_network_policy_if_exists(api_client=api_client, np_name=np_name, namespace=namespace, + logger=logger) + + +@kopf.on.create('unified-platform.cs.hse.ru', 'mlcomponents', + when=not_dev_namespace, + retries=12) +def create_ml_component(spec, name, namespace, body, logger, **_): + """ + Handler for MLComponent object creation event. + + Creates service, deployment and service exposing network policy. + + Implements create-subhandler pattern. + Creates subobjects by subhandlers in sequential order. Retries failed subhandlers, but does not repeat succeeded. + In case of kopf failure, inconsistent state can be fixed via MLComponent resource delete followed by repeated + create. + + :param spec: spec from MLComponent resource + :param name: name from MLComponent resource + :param namespace: namespace from MLComponent resource + :param body: body from MLComponent resource + :param logger: kopf logger + :param _: other parameters passed by kopf which are of no interest + :return: None + """ + logger.debug(f"A create_ml_component handler is called with body: {body}") + + apps_v1_api = AppsV1Api(api_client) + core_v1_api = CoreV1Api(api_client) + + @kopf.subhandler(id=f'create-deployment-{name}', retries=3) + def _create_deployment_handler(**_): + _create_ml_component_deployment(core_v1_api, apps_v1_api, spec, name, namespace, logger) + + @kopf.subhandler(id=f'create-service-{name}', retries=3) + def _create_service_handler(**_): + _create_ml_component_service(core_v1_api, spec, name, namespace, logger) + + @kopf.subhandler(id='create-allow-ingress-traffic-network-policy', retries=3) + def _create_allow_ingress_traffic_np_handler(**__): + _create_allow_ingress_traffic_np(name=name, namespace=namespace, + logger=logger) + + +@kopf.on.delete('unified-platform.cs.hse.ru', 'mlcomponents', + retries=5, + when=not_dev_namespace) +def delete_ml_component(name, namespace, logger, **_): + """ + Handler for MLComponent object deletion event. + + Deletes service, deployment and service exposing network policy. + + Implements delete pattern. + Deletes subobjects in sequential order (without subhandlers). Retries whole handler (all subobjects deletion) + in case of error, but already deleted objects are skipped, hence no error is raised. + + Implementation is idempotent. In case of kopf failure, inconsistent state can be fixed via repeated delete. + + :param name: name of MLComponent object + :param namespace: namespace of MLComponent object + :param logger: kopf logger + :param _: other parameters passed by kopf which are of no interest + :return: None + """ + logger.debug(f"A delete_ml_component handler is called for namespace.name: {namespace}.{name}") + + apps_v1_api = AppsV1Api(api_client) + core_v1_api = CoreV1Api(api_client) + + _delete_deployment_if_exists(apps_v1_api, name, namespace, logger) + _delete_service_if_exists(core_v1_api, name, namespace, logger) + _delete_allow_ingress_traffic_np(name, namespace, logger) + + +@kopf.on.update('unified-platform.cs.hse.ru', 'mlcomponents', + retries=3, + when=not_dev_namespace) +def update_ml_component(spec, name, namespace, body, logger, **_): + apps_v1_api = AppsV1Api(api_client) + core_v1_api = CoreV1Api(api_client) + + _delete_deployment_if_exists(apps_v1_api, name, namespace, logger) + + @kopf.subhandler(id=f'create-deployment-{name}', retries=3) + def _create_deployment_handler(**_): + _create_ml_component_deployment(core_v1_api, apps_v1_api, spec, name, namespace, logger) diff --git a/controller/src/mlcmp/jinja.py b/controller/src/mlcmp/jinja.py new file mode 100644 index 0000000..3ad9f2a --- /dev/null +++ b/controller/src/mlcmp/jinja.py @@ -0,0 +1,20 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: MLComponent +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +""" +MLComponent object jinja module. +""" + +from jinja2 import Environment, FileSystemLoader + +jinja_env = Environment( + loader=FileSystemLoader('templates/ml-component'), + lstrip_blocks=True, + trim_blocks=True +) + + + diff --git a/controller/src/parse.py b/controller/src/parse.py new file mode 100644 index 0000000..8b8aedf --- /dev/null +++ b/controller/src/parse.py @@ -0,0 +1,20 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Утилиты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +import posixpath + + +def extract_domain(url: str) -> str: + prev = rest = url + while rest != '' and rest != '/': + prev = rest + rest, _ = posixpath.split(rest) + return prev + + +def get_user_namespace(app_namespace: str): + user_namespace = app_namespace[:app_namespace.find('-pa-')] + return user_namespace diff --git a/controller/src/platform_app/__init__.py b/controller/src/platform_app/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/controller/src/platform_app/api.py b/controller/src/platform_app/api.py new file mode 100644 index 0000000..a3339f8 --- /dev/null +++ b/controller/src/platform_app/api.py @@ -0,0 +1,20 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: PlatformApp +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +from kubernetes.client import ApiClient + +from platform_app.basic_resources import copy_secret, SECRET_SUFFIX + + +def create_apis_secrets(api_client: ApiClient, spec, user_namespace, secret_namespace, logger): + if 'apisCredentials' in spec: + for api_cred in spec['apisCredentials']: + api_cred_name = api_cred['name'] + new_secret_name = api_cred_name + SECRET_SUFFIX + secret_ref = api_cred['secretRef'] + secret_name = secret_ref['name'] + copy_secret(api_client, secret_name, user_namespace, + new_secret_name, secret_namespace, logger) \ No newline at end of file diff --git a/controller/src/platform_app/argocd.py b/controller/src/platform_app/argocd.py new file mode 100644 index 0000000..c17182f --- /dev/null +++ b/controller/src/platform_app/argocd.py @@ -0,0 +1,143 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: PlatformApp +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +""" +PlatformApp object argocd module. Implements methods to CRUD Argo Applications for PlatformApp object. +""" + +import requests +from kopf import TemporaryError + +from exceptions import PlatformServicePermanentError +from config import ARGO_CD_API, ARGO_CD_USER, ARGO_CD_PASSWORD + + +class ArgoCDTemporaryError(TemporaryError): + pass + + +def _create_app_resource(name, repo_url, path, revision): + return { + 'metadata': { + 'name': name + }, + 'spec': { + 'destination': { + 'server': 'https://kubernetes.default.svc' + }, + 'project': 'default', + 'revisionHistoryLimit': 10, + 'source': { + 'path': path, + 'repoUrl': repo_url, + 'targetRevision': revision + }, + 'syncPolicy': { + 'automated': { + 'allowEmpty': True, + 'prune': True, + 'selfHeal': True + } + }, + 'retry': { + 'backoff': { + 'duration': "5m", + 'factor': 1.5, + 'maxDuration': "1h" + }, + 'limit': 3 # no retries + }, + # 'syncOptions': ["Validate=false"] + } + } + + +def _auth(): + # можно оптимизировать - обновлять токен только по истечению + auth_url = f'{ARGO_CD_API}/session' + payload = {'username': ARGO_CD_USER, 'password': ARGO_CD_PASSWORD} + res = requests.post(auth_url, json=payload) + if res.status_code != 200: + raise PlatformServicePermanentError(f'Cannot authenticate. Response: {res.json()}') + return res.json()['token'] + + +def create_app(name, repo_url, repository_path, revision=None, logger=None): + """ + Creates Argo Application. + + Throws PlatformServicePermanentError if cant create Argo Application. + + :param name: name of Argo Application + :param repo_url: application Git repository + :param repository_path: path inside Git repository with application source code + :param revision: Git revision to sync, HEAD is used if None is passed + :param logger: kopf logger + :return: None + """ + app_resource = _create_app_resource(name, repo_url, repository_path, revision) + post_url = f'{ARGO_CD_API}/applications' + token = _auth() + headers = {"Authorization": f"Bearer {token}"} + res = requests.post(post_url, json=app_resource, headers=headers) + if res.status_code != 200: + raise PlatformServicePermanentError(f'Cannot create app. Response: {res.json()}') + if logger: + logger.info(f"App {name} is created") + + +def update_app(name, repo_url, repository_path, revision=None, logger=None): + """ + Updates Argo Application. + + Throws PlatformServicePermanentError if cant update Argo Application. + + :param name: name of Argo Application + :param repo_url: application Git repository + :param repository_path: path inside Git repository with application source code + :param revision: Git revision to sync, HEAD is used if None is passed + :param logger: kopf logger + :return: None + """ + put_url = f'{ARGO_CD_API}/applications/{name}' + token = _auth() + headers = {"Authorization": f"Bearer {token}"} + app_resource = _create_app_resource(name, repo_url, repository_path, revision) + # теоретически, возможно реализовать обновление через patch + res = requests.put(put_url, json=app_resource, headers=headers) + if res.status_code != 200: + raise PlatformServicePermanentError(f'Cannot update app. Response: {res.json()}') + if logger: + logger.info(f"App {name} is updated") + + +def delete_app_if_exists(name, logger=None): + """ + Deletes Argo Application. + + Throws ArgoCDTemporaryError if Argo Application exist but deletion was not succeeded. + + :param name: name of Argo Application + :param logger: kopf logger + :return: None + """ + get_delete_url = f'{ARGO_CD_API}/applications/{name}' + # указывать проект обязательно, иначе ошибки 403/404 + # https://argo-cd.readthedocs.io/en/stable/developer-guide/api-docs/ + params = {'project': 'default'} + token = _auth() + headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"} + res = requests.get(get_delete_url, params=params, headers=headers) + if res.status_code == 404: + if logger: + logger.warn(f"App {name} doesnt exist, do nothing") + return + res = requests.delete(get_delete_url, params=params, headers=headers) + if res.status_code == 200: + if logger: + logger.info(f"App {name} is deleted") + return + raise ArgoCDTemporaryError(f'Cannot delete app. Response code: {res.status_code}, text: {res.text}') diff --git a/controller/src/platform_app/basic_resources.py b/controller/src/platform_app/basic_resources.py new file mode 100644 index 0000000..0fb21ee --- /dev/null +++ b/controller/src/platform_app/basic_resources.py @@ -0,0 +1,49 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: PlatformApp +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +from kubernetes.client import CoreV1Api, ApiException, V1Secret, ApiClient + +from basic_resources.secrets import create_secret_if_not_exists, prepare_secret_manifest + +SECRET_SUFFIX = '-cred' + + +def create_config_map_if_not_exists(api_client: ApiClient, name, namespace, manifest, logger): + core_v1_api = CoreV1Api(api_client) + try: + core_v1_api.read_namespaced_config_map(name, namespace) + except ApiException as exc: + if exc.status == 404: + core_v1_api.create_namespaced_config_map(namespace, body=manifest) + return + raise exc + logger.info(f"ConfigMap {name} already exists, do nothing") + + +def delete_config_map(api_client: ApiClient, name, namespace, logger): + core_v1_api = CoreV1Api(api_client) + try: + core_v1_api.delete_namespaced_config_map(name=name, namespace=namespace) + except ApiException as exc: + if exc.status == 404: + logger.warn(f"ConfigMap {name} doesnt exist, do nothing") + return + raise exc + logger.info(f"ConfigMap {name} is deleted") + + +def copy_secret(api_client: ApiClient, source_secret_name, namespace_from, + target_secret_name, namespace_to, logger): + core_v1_api = CoreV1Api(api_client) + secret: V1Secret = core_v1_api.read_namespaced_secret(name=source_secret_name, + namespace=namespace_from) + secret_body = secret.to_dict() + + data = [{'key': item[0], 'value': item[1]} for item in secret_body['data'].items()] + manifest = prepare_secret_manifest(target_secret_name, namespace_to, secret_body['type'], data) + + create_secret_if_not_exists(api_client=api_client, + name=target_secret_name, namespace=namespace_to, manifest=manifest, logger=logger) diff --git a/controller/src/platform_app/box.py b/controller/src/platform_app/box.py new file mode 100644 index 0000000..ada41e7 --- /dev/null +++ b/controller/src/platform_app/box.py @@ -0,0 +1,47 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: PlatformApp +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +from kubernetes.client import CoreV1Api, V1Secret, ApiException, ApiClient + +from platform_app.basic_resources import create_secret_if_not_exists, prepare_secret_manifest, SECRET_SUFFIX, \ + copy_secret + +S3_PLATFORM_USER_SECRET_NAME = 'csi-s3-secret' + + +def copy_csi_s3_secret(api_client: ApiClient, user_namespace, secret_namespace, logger): + core_v1_api = CoreV1Api(api_client) + try: + secret: V1Secret = core_v1_api.read_namespaced_secret(name=S3_PLATFORM_USER_SECRET_NAME, + namespace=user_namespace) + except ApiException as exc: + if exc.status == 404: + logger.info(f'Secret {S3_PLATFORM_USER_SECRET_NAME} not found in namespace {user_namespace}, ' + f'will not be copied') + return + raise exc + + secret_body = secret.to_dict() + + data = [{'key': item[0], 'value': item[1]} for item in secret_body['data'].items()] + manifest = prepare_secret_manifest(S3_PLATFORM_USER_SECRET_NAME, secret_namespace, secret_body['type'], data) + create_secret_if_not_exists(api_client=api_client, + name=S3_PLATFORM_USER_SECRET_NAME, + namespace=secret_namespace, + manifest=manifest, + logger=logger) + + +def create_boxes_secrets(api_client: ApiClient, spec, user_namespace, secret_namespace, logger): + if 'boxesCredentials' in spec: + for box_cred in spec['boxesCredentials']: + box_cred_name = box_cred['name'] + new_secret_name = box_cred_name + SECRET_SUFFIX + secret_ref = box_cred['secretRef'] + secret_name = secret_ref['name'] + copy_secret(api_client, secret_name, user_namespace, + new_secret_name, secret_namespace, logger) + diff --git a/controller/src/platform_app/files.py b/controller/src/platform_app/files.py new file mode 100644 index 0000000..306cfdc --- /dev/null +++ b/controller/src/platform_app/files.py @@ -0,0 +1,38 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: PlatformApp +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +import yaml +from kubernetes.client import ApiClient + +from platform_app.basic_resources import create_config_map_if_not_exists +from platform_app.jinja import basic_jinja_env + +CONFIG_MAP_SUFFIX = '-cfg' +CONFIG_MAP_TEMPLATE = 'cm.yaml' + + +def _prepare_config_map_manifest(name, namespace, data: list[dict]): + template = basic_jinja_env.get_template(CONFIG_MAP_TEMPLATE) + variables = { + 'name': name, + 'namespace': namespace, + 'data': data + } + text = template.render(variables) + manifest = yaml.safe_load(text) + return manifest + + +# todo: это, скорее всего, не нужно +def create_files_api_config_map(api_client: ApiClient, namespace, logger): + name = 'files' + CONFIG_MAP_SUFFIX + data = [{'key': 'UNIP_FILES_API', 'value': 'http://files-svc.unip-system-controller'}] + manifest = _prepare_config_map_manifest(name, namespace, data) + create_config_map_if_not_exists(api_client=api_client, + name=name, + namespace=namespace, + manifest=manifest, + logger=logger) \ No newline at end of file diff --git a/controller/src/platform_app/handlers.py b/controller/src/platform_app/handlers.py new file mode 100644 index 0000000..17a3579 --- /dev/null +++ b/controller/src/platform_app/handlers.py @@ -0,0 +1,411 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: PlatformApp +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +""" +PlatformApp object module. Handles all actions with PlatformApp Kubernetes objects. +""" + +import base64 + +import kopf +import yaml +from kubernetes.client import CoreV1Api, CustomObjectsApi, ApiException, V1Secret + +from basic_resources.namespaces import create_namespace +from basic_resources.network_policies import create_network_policy, delete_network_policy_if_exists +from basic_resources.rbac import update_default_sa, create_role, create_rb, delete_rb_if_exists, delete_sa_if_exists, \ + delete_role_if_exists +from bound import not_dev_namespace +from config import ARGO_CD_ENABLED +from exceptions import InputValidationPermanentError +from kopf_k8s_client import api_client +from platform_app.api import create_apis_secrets +from platform_app.argocd import create_app, delete_app_if_exists, update_app +from platform_app.box import copy_csi_s3_secret, create_boxes_secrets +from platform_app.files import create_files_api_config_map +from platform_app.jinja import basic_jinja_env, jinja_env +from platform_app.repository import create_repositories_config_maps, delete_repositories_config_maps, \ + create_repositories_secrets, delete_repositories_secrets + +_NAMESPACE_TEMPLATE = 'namespace.yaml' +_SA_TEMPLATE = 'sa.yaml' +_ROLE_TEMPLATE = 'role.yaml' +_ROLE_PLATFORM_APP_SA_RB_TEMPLATE = 'rb.yaml' +_ROLE_PLATFORM_USER_SA_RB_TEMPLATE = 'another-namespace-rb.yaml' + +_SA_NAME = 'default' +_ROLE_NAME = 'default' +_ROLE_PLATFORM_APP_SA_RB_NAME = 'default-pa-default-sa-rb' +_ROLE_PLATFORM_USER_SA_RB_NAME = 'default-pu-default-sa-rb' + +_DEFAULT_ALLOW_EGRESS_TRAFFIC_NP_TEMPLATE = 'default-allow-egress-traffic-np.yaml' +_DEFAULT_DENY_INGRESS_TRAFFIC_NP_TEMPLATE = 'default-deny-ingress-traffic-np.yaml' +_ALLOW_NS_TRAFFIC_NP_TEMPLATE = 'allow-ns-traffic-np.yaml' +_ALLOW_DNS_TRAFFIC_NP_TEMPLATE = 'allow-dns-traffic-np.yaml' + +_DEFAULT_ALLOW_EGRESS_TRAFFIC_NP_NAME = 'default-allow-egress-traffic' +_DEFAULT_DENY_INGRESS_TRAFFIC_NP_NAME = 'default-deny-ingress-traffic' +_ALLOW_NS_TRAFFIC_NP_NAME = 'allow-inner-namespace-traffic' +_ALLOW_DNS_TRAFFIC_NP_NAME = 'allow-dns-traffic' + + +def _prepare_namespace_manifest(template_name, name): + template = basic_jinja_env.get_template(template_name) + variables = { + 'name': name + } + text = template.render(variables) + data = yaml.safe_load(text) + return data + + +def _prepare_manifest_with_jinja_env(jinja_env, template_name, name, namespace, **kwargs): + template = jinja_env.get_template(template_name) + variables = { + 'name': name, + 'namespace': namespace + } + variables.update(**kwargs) + text = template.render(variables) + data = yaml.safe_load(text) + return data + + +def _prepare_manifest_from_basic(template_name, name, namespace, **kwargs): + return _prepare_manifest_with_jinja_env(basic_jinja_env, template_name, name, namespace, **kwargs) + + +def _prepare_manifest(template_name, name, namespace, **kwargs): + return _prepare_manifest_with_jinja_env(jinja_env, template_name, name, namespace, **kwargs) + + +def _prepare_network_policy_manifest(template_name, namespace): + template = jinja_env.get_template(template_name) + variables = { + 'namespace': namespace + } + text = template.render(variables) + data = yaml.safe_load(text) + return data + + +def _create_default_allow_egress_traffic_np(namespace, logger): + manifest = _prepare_network_policy_manifest(_DEFAULT_ALLOW_EGRESS_TRAFFIC_NP_TEMPLATE, namespace) + create_network_policy(api_client=api_client, manifest=manifest, namespace=namespace, logger=logger) + + +def delete_default_allow_egress_traffic_np(namespace, logger): + delete_network_policy_if_exists(api_client=api_client, np_name=_DEFAULT_ALLOW_EGRESS_TRAFFIC_NP_NAME, + namespace=namespace, logger=logger) + + +def _create_default_deny_ingress_traffic_np(namespace, logger): + manifest = _prepare_network_policy_manifest(_DEFAULT_DENY_INGRESS_TRAFFIC_NP_TEMPLATE, namespace) + create_network_policy(api_client=api_client, manifest=manifest, namespace=namespace, logger=logger) + + +def delete_default_deny_ingress_traffic_np(namespace, logger): + delete_network_policy_if_exists(api_client=api_client, np_name=_DEFAULT_DENY_INGRESS_TRAFFIC_NP_NAME, + namespace=namespace, logger=logger) + + +def _create_allow_ns_traffic_np(namespace, logger): + manifest = _prepare_network_policy_manifest(_ALLOW_NS_TRAFFIC_NP_TEMPLATE, namespace) + create_network_policy(api_client=api_client, manifest=manifest, namespace=namespace, + logger=logger) + + +def delete_allow_ns_traffic_np(namespace, logger): + delete_network_policy_if_exists(api_client=api_client, np_name=_ALLOW_NS_TRAFFIC_NP_NAME, + namespace=namespace, logger=logger) + + +def _create_allow_dns_traffic_np(namespace, logger): + manifest = _prepare_network_policy_manifest(_ALLOW_DNS_TRAFFIC_NP_TEMPLATE, namespace) + create_network_policy(api_client=api_client, manifest=manifest, namespace=namespace, + logger=logger) + + +def delete_allow_dns_traffic_np(namespace, logger): + delete_network_policy_if_exists(api_client=api_client, np_name=_ALLOW_DNS_TRAFFIC_NP_NAME, + namespace=namespace, logger=logger) + + +def _delete_default_network_policies(namespace, logger): + delete_default_allow_egress_traffic_np(namespace=namespace, logger=logger) + delete_default_deny_ingress_traffic_np(namespace=namespace, logger=logger) + delete_allow_ns_traffic_np(namespace=namespace, logger=logger) + delete_allow_dns_traffic_np(namespace=namespace, logger=logger) + + +def _get_repo_url(user_namespace, app_source_code_section): + core_v1_api = CoreV1Api(api_client) + co_api = CustomObjectsApi(api_client) + repository_ref = app_source_code_section['sourceRepositoryRef'] + repository_name = repository_ref['name'] + repository_type = 'sourceRepository' + credentials_property = repository_ref['sourceRepositoryKind'] + repository_ref['credentialsKind'] + try: + repository_res = co_api.get_namespaced_custom_object("unified-platform.cs.hse.ru", "v1", user_namespace, + "repositories", repository_name) + except ApiException as exc: + if exc.status == 404: + raise InputValidationPermanentError(f'Repository {repository_name} does not exist, but required') + raise exc + if repository_type not in repository_res['spec']: + raise InputValidationPermanentError( + f'{repository_type} is expected, but not presented in repository {repository_name}') + + if credentials_property not in repository_res['spec'][repository_type]: + raise InputValidationPermanentError( + f'{credentials_property} is expected, but not presented in {repository_type} ' + f'{repository_name}') + + cred_secret_name = repository_res['spec'][repository_type][credentials_property] + + secret: V1Secret = core_v1_api.read_namespaced_secret(cred_secret_name, user_namespace) + + secret_body = secret.to_dict()['data'] + if 'credentials' not in secret_body: + raise InputValidationPermanentError(f'credentials is expected, but not presented in secret {cred_secret_name}') + + repo_url_secret = secret_body['credentials'] + repo_url = base64.b64decode(repo_url_secret).decode('utf-8') + return repo_url + + +def _process_app_source_code_section(app_name, repo_url, app_source_code_section): + res = {'name': app_name, + 'repository_path': app_source_code_section['repositoryPath']} + if 'revision' in app_source_code_section: + res['revision'] = app_source_code_section['revision'] + + res['repo_url'] = repo_url + return res + + +@kopf.on.create('unified-platform.cs.hse.ru', 'platformapps', retries=30, when=not_dev_namespace) +def create_platform_app(name, namespace, body, spec, logger, **_): + """ + Handler for PlatformApp object creation event. + + Creates namespace if not exists, role, role binding, secrets, config maps, network policies, Argo Application. + Updates default service account. + + Implements create-subhandler pattern. + Creates subobjects by subhandlers in sequential order. Retries failed subhandlers, but does not repeat succeeded. + In case of kopf failure, inconsistent state can be fixed via PlatformApp resource delete followed by repeated + create. + + :param name: name from PlatformApp resource + :param namespace: namespace from PlatformApp resource + :param body: body from PlatformApp resource + :param spec: spec from PlatformApp resource + :param logger: kopf PlatformApp + :param _: other parameters passed by kopf which are of no interest + :return: None. + """ + logger.debug(f"A create_platform_app handler is called with body: {body}") + + # имя PlatformApp соответствует создаваемому пространству имен + + # сразу проверяется, что есть конфигурация репозитория, иначе ничего делать не нужно + repo_url = _get_repo_url(namespace, spec['appSourceCode']) + + @kopf.subhandler(id=f'{name}-namespace', retries=3) + def _create_namespace(**_): + manifest = _prepare_namespace_manifest(_NAMESPACE_TEMPLATE, name) + create_namespace(api_client=api_client, + name=name, + manifest=manifest, + logger=logger) + + @kopf.subhandler(id=f'{name}-sa', retries=3) + def _update_default_sa(**_): + manifest = _prepare_manifest_from_basic(_SA_TEMPLATE, _SA_NAME, name) + update_default_sa(api_client=api_client, namespace=name, manifest=manifest, logger=logger) + + @kopf.subhandler(id=f'{name}-role', retries=3) + def _create_role(**_): + manifest = _prepare_manifest(_ROLE_TEMPLATE, _ROLE_NAME, name) + create_role(name=_ROLE_NAME, api_client=api_client, namespace=name, manifest=manifest) + + @kopf.subhandler(id=f'platform-app-{name}-rb', retries=3) + def _create_platform_app_rb(**_): + manifest = _prepare_manifest_from_basic(_ROLE_PLATFORM_APP_SA_RB_TEMPLATE, + _ROLE_PLATFORM_APP_SA_RB_NAME, + name, + role_name=_ROLE_NAME, + subject_name=_SA_NAME) + create_rb(api_client=api_client, name=_ROLE_PLATFORM_APP_SA_RB_NAME, namespace=name, manifest=manifest) + + @kopf.subhandler(id=f'platform-user-{namespace}-rb', retries=3) + def _create_platform_user_rb(**_): + # namespace - это имя пользователя PlatformUser, где сейчас создается PlatformApp + # name - это имя нового пространства имен для объектов PlatformApp + manifest = _prepare_manifest_from_basic(_ROLE_PLATFORM_USER_SA_RB_TEMPLATE, + _ROLE_PLATFORM_USER_SA_RB_NAME, + name, + role_name=_ROLE_NAME, + subject_name=_SA_NAME, + subject_namespace=namespace) + create_rb(api_client=api_client, name=_ROLE_PLATFORM_USER_SA_RB_NAME, namespace=name, manifest=manifest) + + @kopf.subhandler(id=f'{name}-secrets', retries=3) + def _create_secrets(**_): + create_repositories_secrets(api_client=api_client, spec=spec, user_namespace=namespace, + secret_namespace=name, logger=logger) + copy_csi_s3_secret(api_client=api_client, user_namespace=namespace, secret_namespace=name, + logger=logger) + create_boxes_secrets(api_client=api_client, spec=spec, user_namespace=namespace, + secret_namespace=name, logger=logger) + create_apis_secrets(api_client=api_client, spec=spec, user_namespace=namespace, secret_namespace=name, + logger=logger) + + @kopf.subhandler(id=f'{name}-config-maps', retries=3) + def _create_config_maps(**_): + create_repositories_config_maps(api_client=api_client, spec=spec, user_namespace=namespace, + cm_namespace=name, logger=logger) + create_files_api_config_map(api_client=api_client, namespace=name, logger=logger) + + # каждая сетевая политика создается отдельно, чтобы subhandler был ассоциирован с одной политикой; + # это соответствует выбранной политике по отказоустойчивости и управлению состоянием + # либо переделать по аналогии с секретами и конфигмапами, предварительно проверив логику + # - возможно для большого числа ресурсов типа конфигурации не имеет смысла создавать отдельные обработчики + # имя PlatformApp соответствует имени пространства имен + + @kopf.subhandler(id=f'{name}-allow-egress-traffic-np', retries=3) + def _create_default_allow_egress_traffic_np_handler(**_): + _create_default_allow_egress_traffic_np(namespace=name, logger=logger) + + @kopf.subhandler(id=f'{name}-deny-ingress-traffic-np', retries=3) + def _create_default_deny_ingress_traffic_np_handler(**_): + _create_default_deny_ingress_traffic_np(namespace=name, logger=logger) + + @kopf.subhandler(id=f'{name}-allow-ns-traffic_np', retries=3) + def _create_allow_ns_traffic_np_handler(**_): + _create_allow_ns_traffic_np(namespace=name, logger=logger) + + @kopf.subhandler(id=f'{name}-allow-dns-traffic_np', retries=3) + def _create_allow_dns_traffic_np_handler(**_): + _create_allow_dns_traffic_np(namespace=name, logger=logger) + + if ARGO_CD_ENABLED: + # @kopf.subhandler(id=f'argo-cd-app', retries=3) + # def _create_argo_cd_app(**_): + kwargs = _process_app_source_code_section(name, repo_url, spec['appSourceCode']) + create_app(logger=logger, **kwargs) + else: + logger.debug(f"Argo CD is disabled, Argo CD Application is not created") + + +@kopf.on.delete('unified-platform.cs.hse.ru', 'platformapps', retries=5, when=not_dev_namespace) +def delete_platform_app(name, body, logger, **_): + """ + Handler for PlatformApp object deletion event. + + Deletes role binding, service account, role, network policies, Argo Application, secrets, config maps. + + Implements delete pattern. + Deletes subobjects in sequential order (without subhandlers). Retries whole handler (all subobjects deletion) + in case of error, but already deleted objects are skipped, hence no error is raised. + + Implementation is idempotent. In case of kopf failure, inconsistent state can be fixed via repeated delete. + + :param name: name of PlatformApp object + :param body: name of PlatformApp object + :param logger: kopf logger + :param _: other parameters passed by kopf which are of no interest + :return: None. + """ + logger.debug(f"A delete_platform_app handler is called with body: {body}") + # имя (name) PlatformApp соответствует имени пространства имен + delete_rb_if_exists(api_client=api_client, name=_ROLE_PLATFORM_APP_SA_RB_NAME, namespace=name, logger=logger) + delete_rb_if_exists(api_client=api_client, name=_ROLE_PLATFORM_USER_SA_RB_NAME, namespace=name, logger=logger) + delete_sa_if_exists(api_client=api_client, name=_SA_NAME, namespace=name, logger=logger) + delete_role_if_exists(api_client=api_client, name=_ROLE_NAME, namespace=name, logger=logger) + _delete_default_network_policies(namespace=name, logger=logger) + if ARGO_CD_ENABLED: + delete_app_if_exists(name=name, logger=logger) + else: + logger.debug(f"Argo CD is disabled, Argo CD Application is not deleted") + delete_repositories_secrets(api_client=api_client, app_namespace=name, logger=logger) + delete_repositories_config_maps(api_client=api_client, app_namespace=name, logger=logger) + # пространство имен намеренно не удаляется + + +@kopf.on.update('unified-platform.cs.hse.ru', 'platformapps', retries=3, + field='spec.appSourceCode', when=not_dev_namespace) +def update_app_source_code(new, namespace, name, logger, **_): + """ + Handler for update of appSourceCode attribute of PlatformApp`s spec. + + :param new: new value + :param namespace: PlatformApp resource namespace + :param name: PlatformApp name + :param logger: kopf logger + :param _: other parameters passed by kopf which are of no interest + :return: None + """ + logger.debug(f"An update_app_source_code handler is called with new value: {new}") + + if ARGO_CD_ENABLED: + repo_url = _get_repo_url(namespace, new) + kwargs = _process_app_source_code_section(name, repo_url, new) + update_app(logger=logger, **kwargs) + else: + logger.debug(f"Argo CD is disabled, Argo CD Application is not updated") + + +@kopf.on.update('unified-platform.cs.hse.ru', 'platformapps', retries=6, + field='spec.repositories', when=not_dev_namespace) +def update_repositories(new, spec, name, namespace, body, logger, **_): + """ + Handler for update of repositories attribute of PlatformApp` spec. + + Deletes old subobjects and creates new ones. + + Implements create-subhandler pattern. + Creates subobjects by subhandlers in sequential order. Retries failed subhandlers, but does not repeat succeeded. + In case of kopf failure, inconsistent state can be fixed via PlatformApp resource delete followed by repeated + create. + + :param new: new value + :param name: PlatformApp name + :param namespace: PlatformApp resource namespace + :param body: body of whole PlatformApp resource with new value + :param logger: kopf logger + :param _: other parameters passed by kopf which are of no interest + :return: None + """ + logger.debug(f"An update_repositories_and_boxes handler is called with body: {body}") + + # пересоздаются все секреты и конфигмапы - для репозиториев и ящиков, + # более точно было бы пересоздавать секреты и конфигмапы только для репозиториев + # или даже для удаленных и добавленных репозиториев + + new_spec = spec + + @kopf.subhandler(id=f'{name}-secrets', retries=3) + def _update_secrets(**_): + delete_repositories_secrets(api_client=api_client, app_namespace=name, logger=logger) + create_repositories_secrets(api_client=api_client, spec=new_spec, user_namespace=namespace, + secret_namespace=name, logger=logger) + # todo: временный фикс - delete_repositories_secrets удаляет все секреты + copy_csi_s3_secret(api_client=api_client, user_namespace=namespace, secret_namespace=name, + logger=logger) + create_boxes_secrets(api_client=api_client, spec=new_spec, user_namespace=namespace, + secret_namespace=name, logger=logger) + create_apis_secrets(api_client=api_client, spec=new_spec, user_namespace=namespace, secret_namespace=name, + logger=logger) + + @kopf.subhandler(id=f'{name}-config-maps', retries=3) + def _update_config_maps(**_): + delete_repositories_config_maps(api_client=api_client, app_namespace=name, logger=logger) + create_repositories_config_maps(api_client=api_client, spec=new_spec, user_namespace=namespace, + cm_namespace=name, logger=logger) + # todo: временный фикс - delete_repositories_config_maps удаляет все cms + create_files_api_config_map(api_client=api_client, namespace=name, logger=logger) diff --git a/controller/src/platform_app/jinja.py b/controller/src/platform_app/jinja.py new file mode 100644 index 0000000..dc811f9 --- /dev/null +++ b/controller/src/platform_app/jinja.py @@ -0,0 +1,22 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: PlatformApp +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +""" +PlatformApp jinja envs module. +""" + +from jinja2 import Environment, FileSystemLoader + +jinja_env = Environment( + loader=FileSystemLoader('templates/platform-app'), + lstrip_blocks=True, + trim_blocks=True +) + +basic_jinja_env = Environment( + loader=FileSystemLoader('templates/basic-resources') +) + diff --git a/controller/src/platform_app/repository.py b/controller/src/platform_app/repository.py new file mode 100644 index 0000000..a5b2aa2 --- /dev/null +++ b/controller/src/platform_app/repository.py @@ -0,0 +1,218 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: PlatformApp +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +import yaml +from kubernetes.client import CustomObjectsApi, CoreV1Api, ApiException, V1Secret, V1SecretList, V1ConfigMapList, \ + ApiClient + +from basic_resources.secrets import delete_secret_if_exists, prepare_secret_manifest +from exceptions import InputValidationPermanentError +from platform_app.basic_resources import delete_config_map, create_config_map_if_not_exists, \ + create_secret_if_not_exists +from platform_app.jinja import basic_jinja_env + +SECRET_SUFFIX = '-cred' +SECRET_TEMPLATE = 'secret.yaml' +CONFIG_MAP_SUFFIX = '-cfg' +CONFIG_MAP_TEMPLATE = 'cm.yaml' + + +def _prepare_config_map_manifest(name, namespace, data: list[dict]): + template = basic_jinja_env.get_template(CONFIG_MAP_TEMPLATE) + variables = { + 'name': name, + 'namespace': namespace, + 'data': data + } + text = template.render(variables) + manifest = yaml.safe_load(text) + return manifest + + +def _create_repository_secret_manifest(api_client: ApiClient, parent_obj_type, credentials_property, parent_obj_ref, + parent_obj_res, + namespace_from, namespace_to, name): + parent_obj_name = parent_obj_ref['name'] + if credentials_property not in parent_obj_res['spec'][parent_obj_type]: + raise InputValidationPermanentError( + f'{credentials_property} is expected, but not presented in {parent_obj_type} ' + f'{parent_obj_name}') + + cred_secret_name = parent_obj_res['spec'][parent_obj_type][credentials_property] + + core_v1_api = CoreV1Api(api_client) + secret: V1Secret = core_v1_api.read_namespaced_secret(name=cred_secret_name, + namespace=namespace_from) + secret_body = secret.to_dict() + + data = [{'key': item[0], 'value': item[1]} for item in secret_body['data'].items()] + manifest = prepare_secret_manifest(name, namespace_to, secret_body['type'], data) + return manifest + + +def _copy_repository_secret(api_client: ApiClient, repository_type, + credentials_property, in_app_repository_name, + namespace_from, namespace_to, repository_ref, logger): + repository_name = repository_ref['name'] + co_api = CustomObjectsApi(api_client) + try: + repository_res = co_api.get_namespaced_custom_object("unified-platform.cs.hse.ru", "v1", namespace_from, + "repositories", repository_name) + except ApiException as exc: + if exc.status == 404: + raise InputValidationPermanentError(f'Repository {repository_name} does not exist, but required') + raise exc + if repository_type not in repository_res['spec']: + raise InputValidationPermanentError( + f'{repository_type} is expected, but not presented in repository {repository_name}') + + if repository_type == 'imageRegistry': + repository_host = repository_res['spec'][repository_type]['host'] + new_secret_name = repository_host + SECRET_SUFFIX + else: + new_secret_name = in_app_repository_name + SECRET_SUFFIX + + manifest = _create_repository_secret_manifest(api_client=api_client, parent_obj_type=repository_type, + credentials_property=credentials_property, + parent_obj_ref=repository_ref, + parent_obj_res=repository_res, namespace_from=namespace_from, + namespace_to=namespace_to, name=new_secret_name) + + create_secret_if_not_exists(api_client=api_client, name=new_secret_name, namespace=namespace_to, + manifest=manifest, logger=logger) + + +def _create_repository_config_map(api_client: ApiClient, repository_type, + in_app_repository_name, extract_data_func, + repo_namespace, cm_namespace, repository_ref, logger): + repository_name = repository_ref['name'] + co_api = CustomObjectsApi(api_client) + try: + repository_res = co_api.get_namespaced_custom_object("unified-platform.cs.hse.ru", "v1", repo_namespace, + "repositories", repository_name) + except ApiException as exc: + if exc.status == 404: + raise InputValidationPermanentError(f'Repository {repository_name} does not exist, but required') + raise exc + if repository_type not in repository_res['spec']: + raise InputValidationPermanentError( + f'{repository_type} is expected, but not presented in repository {repository_name}') + + name = in_app_repository_name + CONFIG_MAP_SUFFIX + data = extract_data_func(repository_res['spec'][repository_type]) + manifest = _prepare_config_map_manifest(name, cm_namespace, data) + + create_config_map_if_not_exists(api_client=api_client, name=name, namespace=cm_namespace, manifest=manifest, + logger=logger) + + +def create_repositories_secrets(api_client: ApiClient, spec, user_namespace, secret_namespace, logger): + """ + Creates secrets for specified repositories and boxes of PlatformApp. + + New secrets in new namespace are created by copying content of corresponding secrets from source (user) namespace + given repositories and boxes. + + Does not create secrets if secrets with same name already exist. + + :param spec: PlatformApp spec + :param user_namespace: source secrets namespace, namespace of PlatformUser + :param secret_namespace: targe namespace, namespace of PlatformApp + :param logger: kopf logger + :return: None + """ + + if 'repositories' in spec: + for repository in spec['repositories']: + repo_name = repository['name'] + repository_ref, credentials_property, repository_type = None, None, None + if 'packageRegistryRef' in repository: + repository_ref = repository['packageRegistryRef'] + credentials_property = repository_ref['packageKind'] + repository_ref['credentialsKind'] + repository_type = 'packageRegistry' + if 'imageRegistryRef' in repository: + repository_ref = repository['imageRegistryRef'] + credentials_property = repository_ref['imageKind'] + repository_ref['credentialsKind'] + repository_type = 'imageRegistry' + if 'sourceRepositoryRef' in repository: + repository_ref = repository['sourceRepositoryRef'] + credentials_property = repository_ref['sourceRepositoryKind'] + repository_ref['credentialsKind'] + repository_type = 'sourceRepository' + if repository_ref: + _copy_repository_secret(api_client=api_client, repository_type=repository_type, + credentials_property=credentials_property, in_app_repository_name=repo_name, + namespace_from=user_namespace, namespace_to=secret_namespace, + repository_ref=repository_ref, logger=logger) + + +def delete_repositories_secrets(api_client: ApiClient, app_namespace, logger): + """ + Deletes all secrets from specified namespace. Implementation is idempotent. + :param app_namespace: namespace to delete secrets from + :param logger: kopf logger + :return: None + """ + # todo: переработать, чтобы удалять только секреты репозиториев (пока есть только они) + # если нужно удалять выборочно секреты, то можно использовать метки, добавляя их при создании + core_v1_api = CoreV1Api(api_client) + secrets: V1SecretList = core_v1_api.list_namespaced_secret(app_namespace) + for secret in secrets.items: + delete_secret_if_exists(api_client=api_client, name=secret.metadata.name, + namespace=app_namespace, logger=logger) + + +def _package_registry_extract_data_func(package_registry: dict): + return [ + { + 'key': 'host', + 'value': package_registry['host'] + } + ] + + +def create_repositories_config_maps(api_client: ApiClient, spec, user_namespace, cm_namespace, logger): + """ + Creates config maps for specified repositories and boxes of PlatformApp. + + New config maps in new namespace are created by extracting values of corresponding repositories and boxes + from source (user) namespace. + + Does not create config maps if config maps with same name already exist. + + :param spec: PlatformApp spec + :param user_namespace: source resources namespace, namespace of PlatformUser + :param cm_namespace: targe namespace, namespace of PlatformApp + :param logger: kopf logger + :return: None + """ + if 'repositories' in spec: + for repository in spec['repositories']: + repo_name = repository['name'] + repository_ref, credentials_property, repository_type = None, None, None + if 'packageRegistryRef' in repository: + repository_ref = repository['packageRegistryRef'] + repository_type = 'packageRegistry' + if repository_ref: + extract_data_func = _package_registry_extract_data_func + _create_repository_config_map(api_client=api_client, repository_type=repository_type, + in_app_repository_name=repo_name, + extract_data_func=extract_data_func, + repo_namespace=user_namespace, + cm_namespace=cm_namespace, repository_ref=repository_ref, logger=logger) + + +def delete_repositories_config_maps(api_client: ApiClient, app_namespace, logger): + """ + Deletes all config maps from specified namespace. Implementation is idempotent. + :param app_namespace: namespace to delete config maps from + :param logger: kopf logger + :return: None + """ + # todo: реализовать выборочное удаление (не всех configmap) + core_v1_api = CoreV1Api(api_client) + cms: V1ConfigMapList = core_v1_api.list_namespaced_config_map(app_namespace) + for cm in cms.items: + delete_config_map(api_client, cm.metadata.name, app_namespace, logger) diff --git a/controller/src/platform_user/__init__.py b/controller/src/platform_user/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/controller/src/platform_user/handlers.py b/controller/src/platform_user/handlers.py new file mode 100644 index 0000000..9d23f61 --- /dev/null +++ b/controller/src/platform_user/handlers.py @@ -0,0 +1,161 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: PlatformUser +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +""" +Модуль объекта PlatformUser. Обрабатывает све события с объектом Kubernetes PlatformUser. +""" + +import kopf +import yaml + +from basic_resources.namespaces import create_namespace +from basic_resources.rbac import update_default_sa, create_role, create_rb, delete_rb_if_exists, delete_role_if_exists +from bound import not_dev_namespace +from kopf_k8s_client import api_client +from platform_user.jinja import basic_jinja_env, jinja_env + +_SA_NAME = 'default' +_ROLE_NAME = 'default' +_ROLE_SA_RB_NAME = 'default-default-sa-rb' + +_NAMESPACE_TEMPLATE = 'namespace.yaml' +_SA_TEMPLATE = 'sa.yaml' +_ROLE_TEMPLATE = 'role.yaml' +_ROLE_SA_RB_TEMPLATE = 'rb.yaml' + + +def _prepare_namespace_manifest(template_name, name): + template = basic_jinja_env.get_template(template_name) + variables = { + 'name': name + } + text = template.render(variables) + data = yaml.safe_load(text) + return data + + +def _prepare_manifest_using_jinja(jinja_env, template_name, name, namespace, **kwargs): + template = jinja_env.get_template(template_name) + variables = { + 'name': name, + 'namespace': namespace + } + variables.update(**kwargs) + text = template.render(variables) + data = yaml.safe_load(text) + return data + + +def _prepare_manifest_from_basic(template_name, name, namespace, **kwargs): + return _prepare_manifest_using_jinja(basic_jinja_env, template_name, name, namespace, **kwargs) + + +def _prepare_manifest(template_name, name, namespace, **kwargs): + return _prepare_manifest_using_jinja(jinja_env, template_name, name, namespace, **kwargs) + + +@kopf.on.create('unified-platform.cs.hse.ru', 'platformusers', retries=24, when=not_dev_namespace) +def create_platform_user(name, body, logger, **_): + """ + Обработчик события создания объкта PlatformUser. + + Создает пространство имен (Namespace) для хранения ресурсов пользователя, + если оно отсутствует. + В пространстве имен создает роль (Role) и привязку роли (RoleBinding) + к сервисному аккаунту default, который создается Kubernetes автоматически + при создании пространства имен. + + Обработчик является идемпотентым. + + Использует дочерние обработчики для создания подчиненных ресурсов. + + В случае отказа в обработчике или дочернем обработчике, обработчик + и дочерние обработчики будут выполнены повторно. + При этом успешно завершенные дочерние обработчики не будут выполнены + повторно. + + В случае отказа kopf при выполнении обработчика, + объект PlatformUser может оказаться в несогласованном состоянии. + При восстановлении kopf объект PlatformUser вернется в согласованное состояние + автоматически. + + :param name: Имя объекта PlatformUser + :param body: Спецификация объекта PlatformUser + :param logger: kopf logger + :param _: Остальные параметры, которые передаются kopf, но не используются + :return: None. + """ + logger.debug(f"A create_platform_user handler is called with body: {body}") + + # имя PlatformApp соответствует создаваемому пространству имен + @kopf.subhandler(id=f'{name}-namespace', retries=3) + def _create_namespace_if_not_exists(**_): + create_namespace(api_client=api_client, + name=name, + manifest=_prepare_namespace_manifest(_NAMESPACE_TEMPLATE, name), + logger=logger) + + @kopf.subhandler(id=f'{name}-sa', retries=3) + def _update_default_sa(**_): + # сервисный аккаунт default создается автоматически Kubernetes, + # но может обновиться при необходимости + update_default_sa(api_client=api_client, + namespace=name, + manifest=_prepare_manifest_from_basic(_SA_TEMPLATE, _SA_NAME, name), + logger=logger) + + @kopf.subhandler(id=f'{name}-role', retries=3) + def _create_role(**_): + create_role(api_client=api_client, + name=_ROLE_NAME, + namespace=name, + manifest=_prepare_manifest(_ROLE_TEMPLATE, _ROLE_NAME, name)) + + @kopf.subhandler(id=f'{name}-rb', retries=3) + def _create_rb(**_): + create_rb(api_client=api_client, + name=_ROLE_SA_RB_NAME, + namespace=name, + manifest=_prepare_manifest_from_basic(_ROLE_SA_RB_TEMPLATE, + _ROLE_SA_RB_NAME, name, + role_name=_ROLE_NAME, + subject_name=_SA_NAME)) + + +@kopf.on.delete('unified-platform.cs.hse.ru', 'platformusers', retries=5, when=not_dev_namespace) +def delete_platform_user(name, body, logger, **_): + """ + Обработчик события удаления объекта PlatformUser. + + Удаляет роль (Role) и привязку роли (RoleBinding) + к севисному аккаунту 'default'. + + Обработчик является идемпотентым. + + Использует "обычные" синхронные функции для удаления подчиненных ресурсов, + вызывает их последовательно. + + В случае отказа в обработчике, включая любую из вызываемых функций, + весь обработчик будет выполнено повторно, при этом повторное выполнение + не приведет к ошибке. + + В случае отказа kopf при выполнении обработчика, + объект PlatformUser может оказаться в несогласованном состоянии. + При восстановлении kopf объект PlatformUser вернется в согласованное состояние + автоматически. + + :param name: Имя объекта PlatformUser + :param body: Спецификация объекта PlatformUser + :param logger: kopf logger + :param _: Остальные параметры, которые передаются kopf, но не используются + :return: None. + """ + logger.debug(f"A delete_platform_user handler is called with body: {body}") + # имя (name) PlatformUser соответствует имени пространства имен + delete_rb_if_exists(api_client=api_client, name=_ROLE_SA_RB_NAME, namespace=name, logger=logger) + delete_role_if_exists(api_client=api_client, name=_ROLE_NAME, namespace=name, logger=logger) + # пространство имен намеренно не удаляется + # сервисный аккаунт не удаляется, потому что будет пересоздан Kubernetes diff --git a/controller/src/platform_user/jinja.py b/controller/src/platform_user/jinja.py new file mode 100644 index 0000000..6440219 --- /dev/null +++ b/controller/src/platform_user/jinja.py @@ -0,0 +1,21 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: PlatformUser +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +""" +PlatformUser object jinja module. Holds jinja environments used by PlatformUser handlers. +""" + +from jinja2 import Environment, FileSystemLoader + +jinja_env = Environment( + loader=FileSystemLoader('templates/platform-user'), + lstrip_blocks=True, + trim_blocks=True +) + +basic_jinja_env = Environment( + loader=FileSystemLoader('templates/basic-resources') +) diff --git a/controller/src/repository/__init__.py b/controller/src/repository/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/controller/src/repository/config.py b/controller/src/repository/config.py new file mode 100644 index 0000000..6be3216 --- /dev/null +++ b/controller/src/repository/config.py @@ -0,0 +1,15 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Repository +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2025 г. +# ============================================================ +import os + +_keycloak_robots_tokens_renewal_period_min = \ + os.getenv('UNIP_REPOSITORY_KEYCLOAK_ROBOTS_TOKENS_RENEWAL_PERIOD_MIN', 1440) + +UNIP_REPOSITORY_KEYCLOAK_ROBOTS_TOKENS_RENEWAL_PERIOD_MIN = int(_keycloak_robots_tokens_renewal_period_min) + +UNIP_REPOSITORY_KEYCLOAK_ROBOTS_CREDS_NAMESPACE = os.getenv('UNIP_REPOSITORY_KEYCLOAK_ROBOTS_CREDS_NAMESPACE', + 'unip-app-keycloak-robots-creds') diff --git a/controller/src/repository/handlers.py b/controller/src/repository/handlers.py new file mode 100644 index 0000000..814c761 --- /dev/null +++ b/controller/src/repository/handlers.py @@ -0,0 +1,595 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Repository +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2025 г. +# ============================================================ +import base64 +from time import sleep + +import kopf +import yaml +from kubernetes.client import ApiClient, CustomObjectsApi, ApiException + +from basic_resources.jobs import create_or_update_cron_job, delete_cron_job_if_exists +from basic_resources.secrets import read_secret_if_exists, set_secret_annotations_and_labels, prepare_secret_manifest, \ + create_or_update_secret, try_create_secret, read_basic_auth_credentials_from_secret, delete_secret_if_exists, \ + list_secrets +from bound import not_dev_namespace, in_pu_namespace +from cmplink.keycloak_group_link import get_accounts_from_secret +from cmplink.keycloak_groups import set_group_groups_chain_in_robots_realm, get_full_robot_name, \ + get_accounts_from_secret_attr, \ + set_group_accounts_in_robots_realm, delete_group_in_robots_realm_by_path, \ + get_full_robot_name_prefix, \ + set_robot_accounts, create_robot_tokens +from cmplink.link import get_links_given_predicate, unset_secret_anno_and_label, get_secret_name_if_set +from config import OIDC_MODIFY, OIDC_MANAGED_GROUPS_ROOT, OIDC_CLUSTER_GROUP_NAME, UNIP_DOMAIN, OIDC_ROBOTS_REALM +from kopf_k8s_client import api_client +from repository.config import UNIP_REPOSITORY_KEYCLOAK_ROBOTS_TOKENS_RENEWAL_PERIOD_MIN, \ + UNIP_REPOSITORY_KEYCLOAK_ROBOTS_CREDS_NAMESPACE +from repository.jinja import jinja_env + +_KEYCLOAK_USER_REGISTRY_ANNO_PREFIX = 'keycloak.userregistry.repository.unified-platform.cs.hse.ru' +_KEYCLOAK_USER_REGISTRY_LABEL = 'keycloak.userregistry.repository.unified-platform.cs.hse.ru' + +# применяется к Secret, указывает, что это Secret с токенами одного робот аккаунта +_KEYCLOAK_USER_REGISTRY_ROBOT_TOKENS_LABEL = \ + 'keycloak.userregistry.repository.unified-platform.cs.hse.ru/robot-tokens' # true +# применяется к Secret с токенами одного робот аккаунта, +# указывает, с каким реестром пользователей этот Secret ассоциирован +_ROBOT_TOKENS_OF_KEYCLOAK_USER_REGISTRY_LABEL = \ + 'keycloak.userregistry.repository.unified-platform.cs.hse.ru/robot-tokens-of' # +# применяется к Secret с токенами одного робот аккаунта, +# указывает, с каким робот аккаунтом этот Secret ассоциирован +_KEYCLOAK_USER_REGISTRY_ROBOT_ANNO = 'keycloak.userregistry.repository.unified-platform.cs.hse.ru/robot' +# применяется к Secret с токенами одного робот аккаунта, +# указывает, с каким реестром пользователей этот Secret ассоциирован +_KEYCLOAK_USER_REGISTRY_ANNO = 'keycloak.userregistry.repository.unified-platform.cs.hse.ru' + + +def _get_user_registry_keycloak_group_name(user_registry_name): + return f'robots_{user_registry_name}' + + +def _get_robot_tokens_secret_name(user_namespace, robot_name): + name = robot_name.lstrip(f'robot_{user_namespace}+') + name = name.replace('+', '-') + return f'robot-{name}-cred' + + +def _get_user_registry_keycloak_group_path(user_namespace, user_registry_name): + group_name = _get_user_registry_keycloak_group_name(user_registry_name) + cluster_group_path = f'{OIDC_MANAGED_GROUPS_ROOT}/{OIDC_CLUSTER_GROUP_NAME}' + user_group_path = f'{cluster_group_path}/{user_namespace}' + group_path = f'{user_group_path}/{group_name}' + return group_path + + +def _get_keycloak_robots_secret_name_if_set(spec): + user_registry = spec.get('userRegistry') + if not user_registry: + return None + keycloak_spec = user_registry.get('keycloak') + if not keycloak_spec: + return None + robots_spec = keycloak_spec.get('robots') + if not robots_spec: + return None + secret_name = None + if 'secretRef' in robots_spec: + secret_ref = robots_spec['secretRef'] + secret_name = secret_ref['name'] + return secret_name + + +def _get_keycloak_robot_accounts_from_secret(secret_name, namespace, user_registry_name, logger): + secret = read_secret_if_exists(api_client, secret_name, namespace) + if not secret: + logger.info(f'Keycloak userRegistry secret {namespace}.{secret_name} ' + f'does not exist') + return None + + secret_data = secret.to_dict()['data'] + robots = None + if 'robots' in secret_data: + robots = get_accounts_from_secret_attr(secret_data, 'robots') + robots = [get_full_robot_name(namespace, user_registry_name, r) for r in robots] + if not robots: + logger.warning(f'No accounts found in KeycloakGroup link Secret {namespace}.{secret_name}') + return robots + + +def _get_delete_robots_tokens_secrets_job_name(name): + return f'del-robots-tokens-{name}' + + +def _construct_delete_robots_tokens_secrets_job_manifest(name, user_namespace): + template = jinja_env.get_template('delete-robots-tokens-secrets-job.yaml') + job_name = _get_delete_robots_tokens_secrets_job_name(name) + variables = { + 'job_name': job_name, + 'namespace': user_namespace, + 'schedule': f'*/{UNIP_REPOSITORY_KEYCLOAK_ROBOTS_TOKENS_RENEWAL_PERIOD_MIN} * * * *', + 'secrets_namespace': user_namespace, + 'secrets_label': f'{_ROBOT_TOKENS_OF_KEYCLOAK_USER_REGISTRY_LABEL}={name}' + } + text = template.render(variables) + data = yaml.safe_load(text) + return data + + +def _set_delete_robots_tokens_secrets_job(name, user_namespace, logger): + manifest = _construct_delete_robots_tokens_secrets_job_manifest(name, user_namespace) + create_or_update_cron_job(api_client, name, user_namespace, manifest, logger) + + +def _prepare_robot_tokens_secret_manifest(name, user_namespace, robot_name, robot_password): + token_data = create_robot_tokens(robot_name, robot_password) + + secret_data = [{'key': 'accessToken', 'value': token_data['access_token']}, + {'key': 'refreshToken', 'value': token_data['refresh_token']}] + secret_name = _get_robot_tokens_secret_name(user_namespace, robot_name) + labels = [{'key': _KEYCLOAK_USER_REGISTRY_ROBOT_TOKENS_LABEL, 'value': 'true'}, + {'key': _ROBOT_TOKENS_OF_KEYCLOAK_USER_REGISTRY_LABEL, 'value': name}] + annotations = [{'key': _KEYCLOAK_USER_REGISTRY_ANNO, 'value': name}, + {'key': _KEYCLOAK_USER_REGISTRY_ROBOT_ANNO, 'value': robot_name}] + + manifest = prepare_secret_manifest(name=secret_name, + namespace=user_namespace, + type_='Opaque', + data=secret_data, + data_attr='stringData', + labels=labels, + annotations=annotations) + return manifest + + +def _set_robots_tokens_secrets(name, user_namespace, robots_names_and_passwords, logger): + for robot_name, robot_password in robots_names_and_passwords: + manifest = _prepare_robot_tokens_secret_manifest(name, user_namespace, robot_name, robot_password) + secret_name = _get_robot_tokens_secret_name(user_namespace, robot_name) + + create_or_update_secret(api_client=api_client, + name=secret_name, + namespace=user_namespace, + manifest=manifest, + logger=logger) + + _set_delete_robots_tokens_secrets_job(name, user_namespace, logger) + + +def _set_robot_tokens_secret_if_not_set(name, user_namespace, robot_name, robot_password, logger): + manifest = _prepare_robot_tokens_secret_manifest(name, user_namespace, robot_name, robot_password) + secret_name = _get_robot_tokens_secret_name(user_namespace, robot_name) + + # один из обработчиков реестра пользователей уже мог создать Secret, + # в таком случае не обновляем Secret - обработчик реестра пользователей имеет приоритет; + try_create_secret(api_client=api_client, + name=secret_name, + namespace=user_namespace, + manifest=manifest, + logger=logger) + + +def _delete_robots_tokens_secrets(name, user_namespace, logger): + job_name = _get_delete_robots_tokens_secrets_job_name(name) + delete_cron_job_if_exists(api_client, job_name, user_namespace, logger) + + labels = {_ROBOT_TOKENS_OF_KEYCLOAK_USER_REGISTRY_LABEL: name} + tokens_secrets = list_secrets(api_client, user_namespace, labels) + for secret in tokens_secrets.items: + secret = secret.to_dict() + metadata = secret['metadata'] + secret_name = metadata['name'] + # чтобы не вызвать повторное создание секрета, секрет со списком роботов с паролями должен быть уже удален + delete_secret_if_exists(api_client, secret_name, user_namespace, logger) + + +def _get_robots_passwords_secret_name(name, user_namespace): + return f'robots-passwords-{user_namespace}-{name}' + + +def _set_robots_passwords_secret(robots_names_and_passwords, name, user_namespace, logger): + creds = [f'{pair[0]}:{pair[1]}' for pair in robots_names_and_passwords] + creds_string = '\n'.join(creds) + encoded_creds = base64.b64encode(creds_string.encode('utf-8')).decode('ascii') + data = [{'key': 'credentials', 'value': encoded_creds}] + + secret_name = _get_robots_passwords_secret_name(name, user_namespace) + manifest = prepare_secret_manifest(name=secret_name, + namespace=UNIP_REPOSITORY_KEYCLOAK_ROBOTS_CREDS_NAMESPACE, + type_='Opaque', + data=data, + data_attr='data') + + create_or_update_secret(api_client=api_client, + name=secret_name, + namespace=UNIP_REPOSITORY_KEYCLOAK_ROBOTS_CREDS_NAMESPACE, + manifest=manifest, + logger=logger) + + +def _get_robot_password_if_exists(robot_name, name, user_namespace, logger): + secret_name = _get_robots_passwords_secret_name(name, user_namespace) + secret = read_secret_if_exists(api_client, secret_name, UNIP_REPOSITORY_KEYCLOAK_ROBOTS_CREDS_NAMESPACE) + if not secret: + return + robots_passwords = read_basic_auth_credentials_from_secret(secret, secret_name, + UNIP_REPOSITORY_KEYCLOAK_ROBOTS_CREDS_NAMESPACE, + logger) + robots_passwords_dict = {pair[0]: pair[1] for pair in robots_passwords} + robot_password = robots_passwords_dict.get(robot_name) + return robot_password + + +def _delete_robots_passwords_secret(name, user_namespace, logger): + secret_name = _get_robots_passwords_secret_name(name, user_namespace) + delete_secret_if_exists(api_client, secret_name, UNIP_REPOSITORY_KEYCLOAK_ROBOTS_CREDS_NAMESPACE, logger) + + +def _set_robots_tokens(robots_names_and_passwords, name, user_namespace, logger): + # todo: если в будущем получится отказаться от хранения паролей (например, используя keycloak token exchange) + # то логика почти не изменится - выпуск токенов, сохранение их в Secret, запуск Job - все останется без изменений; + # будут только удалены методы _set_robots_passwords_secret, _delete_robots_passwords_secret, + # _get_robot_password_if_exists; + _delete_robots_passwords_secret(name, user_namespace, logger) + _delete_robots_tokens_secrets(name, user_namespace, logger) + if robots_names_and_passwords: + _set_robots_passwords_secret(robots_names_and_passwords, name, user_namespace, logger) + _set_robots_tokens_secrets(name, user_namespace, robots_names_and_passwords, logger) + + +def _set_keycloak_group_and_accounts(name, user_namespace, spec, logger): + group_name = _get_user_registry_keycloak_group_name(name) + group_id = set_group_groups_chain_in_robots_realm(user_namespace, group_name, logger, OIDC_MODIFY) + secret_name = _get_keycloak_robots_secret_name_if_set(spec) + robot_name_prefix = get_full_robot_name_prefix(user_namespace, name) + if secret_name: + robots = _get_keycloak_robot_accounts_from_secret(secret_name, user_namespace, + name, logger) + robots_names_and_emails = [(r, r + '@' + UNIP_DOMAIN) for r in robots] + robots_names_and_passwords = \ + set_robot_accounts(robot_name_prefix, robots_names_and_emails, OIDC_MODIFY, logger) + set_group_accounts_in_robots_realm(group_id, robots, OIDC_MODIFY, logger) + _set_robot_accounts_in_keycloak_group_links_groups(name, user_namespace, robots, + OIDC_MODIFY, logger) + _set_robots_tokens(robots_names_and_passwords, name, user_namespace, logger) + else: + set_robot_accounts(robot_name_prefix, None, OIDC_MODIFY, logger) + set_group_accounts_in_robots_realm(group_id, None, OIDC_MODIFY, logger) + _set_robots_tokens(None, name, user_namespace, logger) + + +def _unset_keycloak_accounts(name, user_namespace, logger): + robot_name_prefix = get_full_robot_name_prefix(user_namespace, name) + set_robot_accounts(robot_name_prefix, None, OIDC_MODIFY, logger) + _set_robots_tokens(None, name, user_namespace, logger) + + +def _set_keycloak_secret_anno_and_label(name, secret_name, namespace, logger): + anno = {f'{_KEYCLOAK_USER_REGISTRY_ANNO_PREFIX}/{name}': 'true'} + labels = {_KEYCLOAK_USER_REGISTRY_LABEL: 'true'} + set_secret_annotations_and_labels(api_client, secret_name, namespace, anno, labels, logger) + + +def _unset_keycloak_secret_anno_and_label(user_registry_name, secret_name, namespace, logger): + unset_secret_anno_and_label(api_client, + _KEYCLOAK_USER_REGISTRY_ANNO_PREFIX, + _KEYCLOAK_USER_REGISTRY_LABEL, + user_registry_name, + secret_name, + namespace, + logger) + + +def _get_keycloak_links_given_user_registry(user_registry_name, user_namespace): + def predicate(link): + link_spec = link['spec'] + link_keycloak_group = link_spec.get('keycloakGroup') + if not link_keycloak_group: + return False + link_user_registry = link_keycloak_group.get('userRegistryRef') + if not link_user_registry: + return False + link_user_registry_name = link_user_registry['name'] + return link_user_registry_name == user_registry_name + + filtered_list = get_links_given_predicate(api_client, user_namespace, predicate) + return filtered_list + + +def _get_robot_realm_group_id(keycloak_group_link): + status = keycloak_group_link.get('status') + if not status: + return None + keycloak_group = status.get('keycloakGroup') + if not keycloak_group: + return None + group_ids = keycloak_group.get('groupIds') + if not group_ids: + return None + if OIDC_ROBOTS_REALM not in group_ids: + return None + return group_ids[OIDC_ROBOTS_REALM] + + +def _set_robot_accounts_in_keycloak_group_links_groups(name, user_namespace, robots_full_names, modify, logger): + keycloak_group_links = _get_keycloak_links_given_user_registry(name, user_namespace) + for kgl in keycloak_group_links: + kgl_name = kgl['metadata']['name'] + group_id = _get_robot_realm_group_id(kgl) + if not group_id: + logger.warning(f'KeycloakGroup ComponentLink "{user_namespace}.{kgl_name}" ' + f'references Keycloak userRegistry "{name}", ' + 'but has no groupId in status.') + continue + kgl_spec = kgl['spec'] + secret_name = get_secret_name_if_set(kgl_spec) + _, _, kgl_robots = get_accounts_from_secret(api_client, secret_name, user_namespace, name, logger) + if not (set(robots_full_names) & set(kgl_robots)): + logger.info(f'KeycloakGroup ComponentLink "{user_namespace}.{kgl_name}" ' + f'references Keycloak userRegistry "{name}", ' + 'but has no robots accounts specified in userRegistry.') + continue + set_group_accounts_in_robots_realm(group_id, kgl_robots, modify, logger) + + +@kopf.on.create('unified-platform.cs.hse.ru', 'repositories', + when=kopf.all_([not_dev_namespace, in_pu_namespace]), + field='spec.userRegistry.keycloak', + value=kopf.PRESENT) +def create_keycloak_user_registry(name, namespace, spec, patch, logger, **_): + @kopf.subhandler(id=f'set-keycloak-group-and-accounts-{namespace}.{name}') + def _set_keycloak_group_and_accounts_handler(**_): + _set_keycloak_group_and_accounts(name, namespace, spec, logger) + + @kopf.subhandler(id=f'update-keycloak-secret-{namespace}.{name}') + def _set_keycloak_secret_anno_and_label_handler(**_): + secret_name = _get_keycloak_robots_secret_name_if_set(spec) + if secret_name: + _set_keycloak_secret_anno_and_label(name, secret_name, namespace, logger) + + +@kopf.on.update('unified-platform.cs.hse.ru', 'repositories', + when=kopf.all_([not_dev_namespace, in_pu_namespace]), + field='spec.userRegistry.keycloak', + value=kopf.PRESENT) +def update_keycloak_user_registry(name, namespace, old, new, status, patch, logger, **_): + old_spec = old['spec'] + new_spec = new['spec'] + + secret_name = _get_keycloak_robots_secret_name_if_set(new_spec) + old_secret_name = _get_keycloak_robots_secret_name_if_set(old_spec) + + update_secrets = False + set_group = False + + if secret_name != old_secret_name: + update_secrets = True + set_group = True + + # set_group, update_secrets - отдельные subhandlers, потому что могут выполняться независимо друг от друга + if set_group: + @kopf.subhandler(id=f'set-keycloak-group-and-accounts-{namespace}.{name}') + def _set_keycloak_group_and_accounts_handler(**_): + _set_keycloak_group_and_accounts(name, namespace, new_spec, logger) + + if update_secrets: + @kopf.subhandler(id=f'update-keycloak-secrets-{namespace}.{name}') + def _update_keycloak_secrets_anno_and_label_handler(**_): + if old_secret_name is not None: + _unset_keycloak_secret_anno_and_label(name, old_secret_name, namespace, logger) + if secret_name: + _set_keycloak_secret_anno_and_label(name, secret_name, namespace, logger) + + +@kopf.on.delete('unified-platform.cs.hse.ru', 'repositories', + when=kopf.all_([not_dev_namespace, in_pu_namespace]), + field='spec.userRegistry.keycloak', + value=kopf.PRESENT) +def delete_keycloak_user_registry(name, namespace, spec, status, logger, **_): + group_path = _get_user_registry_keycloak_group_path(namespace, name) + + _unset_keycloak_accounts(name, namespace, logger) + delete_group_in_robots_realm_by_path(group_path, logger, OIDC_MODIFY) + + secret_name = _get_keycloak_robots_secret_name_if_set(spec) + if secret_name: + _unset_keycloak_secret_anno_and_label(name, secret_name, namespace, logger) + + +def get_repositories_given_predicate(api_client: ApiClient, namespace, predicate): + # вместо прохода по списку начиная с версии 1.31 можно использовать CRD selectable fields: + # https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/#crd-selectable-fields + # на примере секрета ссылок: + # co_api = CustomObjectsApi(api_client) + # field_selector = f'spec.target.credentials={secret_name}' + # links_list, _, _ = co_api.list_namespaced_custom_object_with_http_info( + # "unified-platform.cs.hse.ru", "v1", secret_namespace, + # "componentlinks", field_selector=field_selector) + # return links_list['items'] + + co_api = CustomObjectsApi(api_client) + repositories_list, _, _ = co_api.list_namespaced_custom_object_with_http_info( + "unified-platform.cs.hse.ru", "v1", namespace, + "repositories") + if not repositories_list['items']: + return [] + + filtered_list = [] + for repo in repositories_list['items']: + if predicate(repo): + filtered_list.append(repo) + + return filtered_list + + +def _get_keycloak_user_registries_given_secret(secret_name, secret_namespace): + def predicate(repository): + repository_spec = repository['spec'] + robots_secret = _get_keycloak_robots_secret_name_if_set(repository_spec) + return secret_name == robots_secret + + filtered_list = get_repositories_given_predicate(api_client, secret_namespace, predicate) + return filtered_list + + +@kopf.on.create('', 'secrets', + when=kopf.all_([not_dev_namespace, in_pu_namespace])) +def create_keycloak_registry_secret(spec, name, namespace, body, logger, **_): + keycloak_registries = _get_keycloak_user_registries_given_secret(name, namespace) + if not keycloak_registries: + return + + for kr in keycloak_registries: + kr_spec = kr['spec'] + kr_name = kr['metadata']['name'] + + @kopf.subhandler(id=f'set-keycloak-group-and-accounts-{namespace}.{kr_name}') + def _set_keycloak_group_and_accounts_handler(**_): + _set_keycloak_group_and_accounts(kr_name, namespace, kr_spec, logger) + + @kopf.subhandler(id=f'update-keycloak-secret-{namespace}.{kr_name}') + def _set_keycloak_secret_anno_and_label_handler(**_): + _set_keycloak_secret_anno_and_label(kr_name, name, namespace, logger) + + +def get_repositories_if_exist(api_client_: ApiClient, names, namespace, logger): + co_api = CustomObjectsApi(api_client_) + result = [] + for name in names: + try: + repo_res = co_api.get_namespaced_custom_object( + "unified-platform.cs.hse.ru", "v1", namespace, + "repositories", name) + result.append(repo_res) + except ApiException as exc: + if exc.status == 404: + logger.warning(f'Keycloak userRegistry Repository "{namespace}.{name}" does not exist') + else: + raise exc + return result + + +def _get_keycloak_user_registries_given_secret_metadata(metadata, namespace, logger): + if 'annotations' not in metadata: + return None + annotations = metadata.get('annotations') + keycloak_registries_names = [a[len(_KEYCLOAK_USER_REGISTRY_ANNO_PREFIX) + 1:] + for a in annotations + if a.startswith(_KEYCLOAK_USER_REGISTRY_ANNO_PREFIX)] + keycloak_registries = get_repositories_if_exist(api_client, keycloak_registries_names, namespace, logger) + filtered = [] + for kr in keycloak_registries: + kr_spec = kr['spec'] + kr_name = kr['metadata']['name'] + user_registry = kr_spec.get('userRegistry') + if not user_registry: + logger.warning(f'Repository "{namespace}.{kr_name}" is not a userRegistry, but expected') + continue + if 'keycloak' not in user_registry: + logger.warning(f'Repository "{namespace}.{kr_name}" is not a keycloak userRegistry, but expected') + continue + filtered.append(kr) + return filtered + + +@kopf.on.update('', 'secrets', + when=kopf.all_([not_dev_namespace, in_pu_namespace]), + labels={_KEYCLOAK_USER_REGISTRY_LABEL: 'true'}, + field='data') +def update_keycloak_registry_secret(spec, name, namespace, body, logger, **_): + metadata = body['metadata'] + keycloak_registries = _get_keycloak_user_registries_given_secret_metadata(metadata, namespace, logger) + if not keycloak_registries: + return + + for kr in keycloak_registries: + kr_spec = kr['spec'] + kr_name = kr['metadata']['name'] + + @kopf.subhandler(id=f'set-keycloak-group-and-accounts-{namespace}.{kr_name}') + def _set_keycloak_group_and_accounts_handler(**_): + _set_keycloak_group_and_accounts(kr_name, namespace, kr_spec, logger) + + +@kopf.on.delete('', 'secrets', + when=kopf.all_([not_dev_namespace, in_pu_namespace]), + labels={_KEYCLOAK_USER_REGISTRY_LABEL: 'true'}) +def delete_keycloak_registry_secret(spec, name, namespace, body, logger, **_): + metadata = body['metadata'] + keycloak_registries = _get_keycloak_user_registries_given_secret_metadata(metadata, namespace, logger) + if not keycloak_registries: + return + + for kr in keycloak_registries: + kr_name = kr['metadata']['name'] + + @kopf.subhandler(id=f'unset-keycloak-accounts-{namespace}.{kr_name}') + def _unset_keycloak_accounts_handler(**_): + _unset_keycloak_accounts(kr_name, namespace, logger) + + +def _wait_robot_tokens_secret_deleted(secret_name, secret_namespace, secret_uid): + # нужно дождаться удаления, чтобы пересоздать секрет, + # но поскольку этот обработчик не блокирующий удаление (on.event), то не можем воспользоваться + # TemporaryError + retry - нужен цикл и sleep + while True: + existing_secret = read_secret_if_exists(api_client, secret_name, secret_namespace) + if existing_secret: + existing_secret = existing_secret.to_dict() + existing_metadata = existing_secret['metadata'] + existing_uid = existing_metadata['uid'] + if secret_uid != existing_uid: + # другой процесс уже обновил Secret, ничего не делаем; + return False + # иначе ждем пока Secret удалится - это может занять время, + # если другие обработчики также обрабатывают удаление; + sleep(5) + else: + break + return True + + +def _get_user_registry_and_robot_name_from_secret_anno(secret_metadata, secret_name, secret_namespace, logger): + annotations = secret_metadata['annotations'] + user_registry_name = annotations.get(_KEYCLOAK_USER_REGISTRY_ANNO) + if not user_registry_name: + error_msg = f'Keycloak user registry not set in annotation {_KEYCLOAK_USER_REGISTRY_ANNO} ' \ + f'in secret {secret_namespace}.{secret_name}, cannot process further.' + logger.error(error_msg) + robot_name = annotations.get(_KEYCLOAK_USER_REGISTRY_ROBOT_ANNO) + if not robot_name: + error_msg = f'Keycloak robot account not set in annotation {_KEYCLOAK_USER_REGISTRY_ROBOT_ANNO} ' \ + f'in secret {secret_namespace}.{secret_name}, cannot process further.' + logger.error(error_msg) + return user_registry_name, robot_name + + +def _deleted_filter(event, **_): return event['type'] == 'DELETED' + + +@kopf.on.event('', 'secrets', + when=kopf.all_([_deleted_filter, + in_pu_namespace, + not_dev_namespace]), + labels={_KEYCLOAK_USER_REGISTRY_ROBOT_TOKENS_LABEL: 'true'}) +def set_keycloak_robot_tokens_secret_on_secret_delete(name, namespace, body, logger, **_): + metadata = body['metadata'] + uid = metadata['uid'] + + proceed = _wait_robot_tokens_secret_deleted(name, namespace, uid) + if not proceed: + return + + user_registry_name, robot_name = \ + _get_user_registry_and_robot_name_from_secret_anno(metadata, name, namespace, logger) + + if not user_registry_name or not robot_name: + return + + robot_password = _get_robot_password_if_exists(robot_name, user_registry_name, namespace, logger) + if not robot_password: + logger.info(f'Not found password for robot {robot_name}, Secret will not be re-created') + return + _set_robot_tokens_secret_if_not_set(user_registry_name, namespace, robot_name, robot_password, logger) diff --git a/controller/src/repository/jinja.py b/controller/src/repository/jinja.py new file mode 100644 index 0000000..11af92f --- /dev/null +++ b/controller/src/repository/jinja.py @@ -0,0 +1,13 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Repository +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2025 г. +# ============================================================ +from jinja2 import FileSystemLoader, Environment + +jinja_env = Environment( + loader=FileSystemLoader('templates/repository'), + lstrip_blocks=True, + trim_blocks=True +) diff --git a/controller/templates/api-component/oauth2-proxy-deployment.yaml b/controller/templates/api-component/oauth2-proxy-deployment.yaml new file mode 100644 index 0000000..1bfb9fd --- /dev/null +++ b/controller/templates/api-component/oauth2-proxy-deployment.yaml @@ -0,0 +1,88 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: APIComponent +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2025 г. +# ============================================================ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ deployment_name }} + namespace: {{ namespace }} +spec: + replicas: 1 + selector: + matchLabels: + app: {{ selector_label }} + template: + metadata: + labels: + app: {{ selector_label }} + spec: + initContainers: + - name: init + image: busybox:1.37.0 + volumeMounts: + - name: groups-secret-volume + mountPath: /unip/groups-secret + readOnly: true + - name: prepared-groups-var-volume + mountPath: /unip/prepared-groups-var + command: [ 'sh', '-c', 'echo -n "OIDC_GROUPS=" > /unip/prepared-groups-var/groups-var && cat /unip/groups-secret/groups | paste -sd "," - >> /unip/prepared-groups-var/groups-var' ] + resources: + limits: + memory: 64M + cpu: 100m + containers: + - command: ["/bin/sh", "-c"] + args: + - -c + - >- + source <(grep "=" /unip/prepared-groups-var/groups-var) && + /bin/oauth2-proxy + --provider=keycloak-oidc + --client-id={{ client_id }} + --client-secret={{ client_secret }} + --cookie-secret={{ cookie_secret }} + --redirect-url={{ redirect_url }} + --oidc-issuer-url={{ oidc_issuer_url }} + --skip-jwt-bearer-tokens=true + {% if oidc_extra_audience %} + --oidc-extra-audience={{ oidc_extra_audience }} + {% endif %} + {% if extra_jwt_issuers %} + --extra-jwt-issuers={{ extra_jwt_issuers }} + {% endif %} + --email-domain=* + --cookie-httponly=false + --set-xauthrequest=true + --set-basic-auth=true + --basic-auth-password=default + --allowed-group=$OIDC_GROUPS + {% if roles %} + --allowed-role={{ roles }} + {% endif %} + --code-challenge-method=S256 + --proxy-prefix={{ proxy_prefix }} + --upstream=file:///dev/null + --http-address=0.0.0.0:{{ container_port }} + image: quay.io/oauth2-proxy/oauth2-proxy:v7.5.1 + imagePullPolicy: IfNotPresent + name: oauth2-proxy + ports: + - containerPort: {{ container_port }} + protocol: TCP + resources: + limits: + memory: 64M + cpu: 100m + volumeMounts: + - name: prepared-groups-var-volume + mountPath: /unip/prepared-groups-var + volumes: + - name: groups-secret-volume + secret: + secretName: {{ groups_secret_name }} + - name: prepared-groups-var-volume + emptyDir: + sizeLimit: 10Mi diff --git a/controller/templates/api-component/oauth2-proxy-ingress.yaml b/controller/templates/api-component/oauth2-proxy-ingress.yaml new file mode 100644 index 0000000..fb6de5a --- /dev/null +++ b/controller/templates/api-component/oauth2-proxy-ingress.yaml @@ -0,0 +1,46 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: APIComponent +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2025 г. +# ============================================================ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ name }} + namespace: {{ namespace }} + {% if cors %} + annotations: + nginx.ingress.kubernetes.io/enable-cors: "true" + {% if cors.allow_methods %} + nginx.ingress.kubernetes.io/cors-allow-methods: {{ cors.allow_methods }} + {% endif %} + {% if cors.allow_headers %} + nginx.ingress.kubernetes.io/cors-allow-headers: {{ cors.allow_headers }} + {% endif %} + {% if cors.expose_headers %} + nginx.ingress.kubernetes.io/cors-expose-headers: {{ cors.expose_headers }} + {% endif %} + {% if cors.allow_origin %} + nginx.ingress.kubernetes.io/cors-allow-origin: {{ cors.allow_origin }} + {% endif %} + {% if cors.max_age %} + nginx.ingress.kubernetes.io/cors-max-age: "{{ cors.max_age }}" + {% endif %} + {% endif %} +spec: + ingressClassName: nginx + tls: + - hosts: + - {{ domain }} + rules: + - host: {{ domain }} + http: + paths: + - path: {{ path }} + pathType: ImplementationSpecific + backend: + service: + name: {{ service_name }} + port: + number: {{ service_port }} diff --git a/controller/templates/api-component/oauth2-proxy-svc.yaml b/controller/templates/api-component/oauth2-proxy-svc.yaml new file mode 100644 index 0000000..be09a35 --- /dev/null +++ b/controller/templates/api-component/oauth2-proxy-svc.yaml @@ -0,0 +1,19 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: APIComponent +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2025 г. +# ============================================================ +apiVersion: v1 +kind: Service +metadata: + name: {{ service_name }} + namespace: {{ namespace }} +spec: + ports: + - name: http + port: {{ service_port }} + protocol: TCP + targetPort: {{ container_port }} + selector: + app: {{ selector_label }} diff --git a/controller/templates/basic-resources/allow-ingress-traffic-np.yaml b/controller/templates/basic-resources/allow-ingress-traffic-np.yaml new file mode 100644 index 0000000..e5d21ad --- /dev/null +++ b/controller/templates/basic-resources/allow-ingress-traffic-np.yaml @@ -0,0 +1,19 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Управления базовыми объектами Kubernetes +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2025 г. +# ============================================================ +kind: NetworkPolicy +apiVersion: networking.k8s.io/v1 +metadata: + name: {{ np_name }} + namespace: {{ namespace }} +spec: + policyTypes: + - Ingress + podSelector: + matchLabels: + app: {{ selector_label }} + ingress: + - {} \ No newline at end of file diff --git a/controller/templates/basic-resources/another-namespace-rb.yaml b/controller/templates/basic-resources/another-namespace-rb.yaml new file mode 100644 index 0000000..9ec85bc --- /dev/null +++ b/controller/templates/basic-resources/another-namespace-rb.yaml @@ -0,0 +1,19 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Управления базовыми объектами Kubernetes +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ name }} + namespace: {{ namespace }} +subjects: +- kind: ServiceAccount + name: {{ subject_name }} + namespace: {{ subject_namespace }} +roleRef: + kind: Role + name: {{ role_name }} + apiGroup: "rbac.authorization.k8s.io" \ No newline at end of file diff --git a/controller/templates/basic-resources/cm.yaml b/controller/templates/basic-resources/cm.yaml new file mode 100644 index 0000000..2617de0 --- /dev/null +++ b/controller/templates/basic-resources/cm.yaml @@ -0,0 +1,15 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Управления базовыми объектами Kubernetes +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ namespace }} + name: {{ name }} +data: + {% for item in data %} + {{ item['key'] }}: {{ item['value'] }} + {% endfor %} \ No newline at end of file diff --git a/controller/templates/basic-resources/external-name-svc.yaml b/controller/templates/basic-resources/external-name-svc.yaml new file mode 100644 index 0000000..e81eeb2 --- /dev/null +++ b/controller/templates/basic-resources/external-name-svc.yaml @@ -0,0 +1,14 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Управления базовыми объектами Kubernetes +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: v1 +kind: Service +metadata: + name: {{ service_name }} + namespace: {{ namespace }} +spec: + type: ExternalName + externalName: {{ external_service_name }} diff --git a/controller/templates/basic-resources/ingress-multi-auth.yaml b/controller/templates/basic-resources/ingress-multi-auth.yaml new file mode 100644 index 0000000..c85aa35 --- /dev/null +++ b/controller/templates/basic-resources/ingress-multi-auth.yaml @@ -0,0 +1,73 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Управления базовыми объектами Kubernetes +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ name }} + namespace: {{ namespace }} + annotations: + {% if basic %} + nginx.ingress.kubernetes.io/auth-type: basic + nginx.ingress.kubernetes.io/auth-secret: {{ basic.secret_name }} + {% endif %} + nginx.ingress.kubernetes.io/auth-realm: "Authentication Required - {{ auth_realm }}" + nginx.ingress.kubernetes.io/use-regex: "true" + nginx.ingress.kubernetes.io/proxy-connect-timeout: "600" + nginx.ingress.kubernetes.io/proxy-read-timeout: "600" + nginx.ingress.kubernetes.io/proxy-send-timeout: "600" + {% if rewrite_target %} + nginx.ingress.kubernetes.io/rewrite-target: {{ rewrite_target }} + {% endif %} + nginx.ingress.kubernetes.io/configuration-snippet: | + {% if identity_pass_through %} + proxy_set_header Authorization $http_authorization; + proxy_pass_header Authorization; + {% endif %} + proxy_pass_header Content-Type; + {% if oidc %} + nginx.ingress.kubernetes.io/auth-response-headers: + x-auth-request-user, x-auth-request-groups, x-auth-request-email, x-auth-request-preferred-username, authorization + nginx.ingress.kubernetes.io/auth-url: {{ oidc.auth_url }} # "https://$host/multi-auth/proxy/oauth2/auth" + nginx.ingress.kubernetes.io/auth-signin: {{ oidc.auth_signin }} # "https://$host/multi-auth/proxy/oauth2/start?rd=$escaped_request_uri" + nginx.ingress.kubernetes.io/satisfy: "any" + {% endif %} + {% if cors %} + nginx.ingress.kubernetes.io/enable-cors: "true" + {% if cors.allow_methods %} + nginx.ingress.kubernetes.io/cors-allow-methods: {{ cors.allow_methods }} + {% endif %} + {% if cors.allow_headers %} + nginx.ingress.kubernetes.io/cors-allow-headers: {{ cors.allow_headers }} + {% endif %} + {% if cors.expose_headers %} + nginx.ingress.kubernetes.io/cors-expose-headers: {{ cors.expose_headers }} + {% endif %} + {% if cors.allow_origin %} + nginx.ingress.kubernetes.io/cors-allow-origin: {{ cors.allow_origin }} + {% endif %} + {% if cors.max_age %} + nginx.ingress.kubernetes.io/cors-max-age: "{{ cors.max_age }}" + {% endif %} + {% endif %} +spec: + ingressClassName: nginx + tls: + - hosts: + - {{ domain }} + rules: + - host: {{ domain }} + http: + paths: + {% for path in paths %} + - path: {{ path }} + pathType: ImplementationSpecific + backend: + service: + name: {{ service_name }} + port: + number: {{ service_port }} + {% endfor %} diff --git a/controller/templates/basic-resources/namespace.yaml b/controller/templates/basic-resources/namespace.yaml new file mode 100644 index 0000000..403c83e --- /dev/null +++ b/controller/templates/basic-resources/namespace.yaml @@ -0,0 +1,10 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Управления базовыми объектами Kubernetes +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: v1 +kind: Namespace +metadata: + name: {{ name }} \ No newline at end of file diff --git a/controller/templates/basic-resources/rb.yaml b/controller/templates/basic-resources/rb.yaml new file mode 100644 index 0000000..a552a67 --- /dev/null +++ b/controller/templates/basic-resources/rb.yaml @@ -0,0 +1,18 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Управления базовыми объектами Kubernetes +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ name }} + namespace: {{ namespace }} +subjects: +- kind: ServiceAccount + name: {{ subject_name }} +roleRef: + kind: Role + name: {{ role_name }} + apiGroup: "rbac.authorization.k8s.io" \ No newline at end of file diff --git a/controller/templates/basic-resources/sa.yaml b/controller/templates/basic-resources/sa.yaml new file mode 100644 index 0000000..0e2acbf --- /dev/null +++ b/controller/templates/basic-resources/sa.yaml @@ -0,0 +1,11 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Управления базовыми объектами Kubernetes +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ name }} + namespace: {{ namespace }} diff --git a/controller/templates/basic-resources/secret.yaml b/controller/templates/basic-resources/secret.yaml new file mode 100644 index 0000000..2029ad1 --- /dev/null +++ b/controller/templates/basic-resources/secret.yaml @@ -0,0 +1,33 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Управления базовыми объектами Kubernetes +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: v1 +kind: Secret +metadata: + namespace: {{ namespace }} + name: {{ name }} + {% if labels %} + labels: + {% for label in labels %} + {{ label['key'] }}: "{{ label['value'] }}" + {% endfor %} + {% endif %} + {% if annotations %} + annotations: + {% for anno in annotations %} + {{ anno['key'] }}: "{{ anno['value'] }}" + {% endfor %} + {% endif %} +type: {{ type }} +{% if not data %} +{{ data_attr }}: {} +{% endif %} +{% if data %} +{{ data_attr }}: + {% for item in data %} + {{ item['key'] }}: {{ item['value'] }} + {% endfor %} +{% endif %} \ No newline at end of file diff --git a/controller/templates/box/csi-s3-pv.yaml b/controller/templates/box/csi-s3-pv.yaml new file mode 100644 index 0000000..952705c --- /dev/null +++ b/controller/templates/box/csi-s3-pv.yaml @@ -0,0 +1,41 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: DataBox +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: {{ name }} + {% if labels %} + labels: + {% for label in labels %} + {{ label['key'] }}: {{ label['value'] }} + {% endfor %} + {% endif %} +spec: + storageClassName: {{ storage_class }} + capacity: + storage: {{ capacity }} + accessModes: + - ReadWriteMany + claimRef: + namespace: {{ pvc_namespace }} + name: {{ pvc_name }} + csi: + driver: ru.yandex.s3.csi + controllerPublishSecretRef: + name: csi-s3-secret + namespace: {{ namespace }} + nodePublishSecretRef: + name: csi-s3-secret + namespace: {{ namespace }} + nodeStageSecretRef: + name: csi-s3-secret + namespace: {{ namespace }} + volumeAttributes: + capacity: 500Mi + mounter: geesefs + options: --memory-limit 1000 --dir-mode 0777 --file-mode 0666 + volumeHandle: {{ bucket_name_with_path_inside_bucket }} # bucket_name/path/inside/bucket \ No newline at end of file diff --git a/controller/templates/box/csi-s3-pvc.yaml b/controller/templates/box/csi-s3-pvc.yaml new file mode 100644 index 0000000..82c137c --- /dev/null +++ b/controller/templates/box/csi-s3-pvc.yaml @@ -0,0 +1,20 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: DataBox +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ name }} + namespace: {{ namespace }} +spec: + # Empty storage class disables dynamic provisioning + storageClassName: "" + accessModes: + - ReadWriteMany + resources: + requests: + storage: {{ capacity }} + volumeName: {{ pv_name }} \ No newline at end of file diff --git a/controller/templates/experiment-pipeline/simple-pipeline-trial.yaml b/controller/templates/experiment-pipeline/simple-pipeline-trial.yaml new file mode 100644 index 0000000..84dc8b8 --- /dev/null +++ b/controller/templates/experiment-pipeline/simple-pipeline-trial.yaml @@ -0,0 +1,222 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: ExperimentPipeline +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +piVersion: batch/v1 +kind: Job +metadata: + name: {{ job_name }} + namespace: {{ namespace }} + {% if annotations %} + annotations: + {% for key, value in annotations.items() %} + {{ key }}: "{{ value }}" + {% endfor %} + {% endif %} + {% if labels %} + labels: + {% for key, value in labels.items() %} + {{ key }}: "{{ value }}" + {% endfor %} + {% endif %} +spec: + completions: 1 + backoffLimit: 3 + template: + {% if labels %} + metadata: + labels: + {% for key, value in labels.items() %} + {{ key }}: "{{ value }}" + {% endfor %} + {% endif %} + spec: + restartPolicy: Never + initContainers: + {% for stage in stages %} + - name: {{ stage.name }} + image: {{ stage.image }} + {% if stage.cmd %} + command: + {% for line in stage.cmd %} + - {{ line }} + {% endfor %} + {% endif %} + {% if stage.volume_mounts %} + volumeMounts: + {% for volume_mount in stage.volume_mounts %} + - name: {{ volume_mount['volume_name'] }} + mountPath: {{ volume_mount['mount_path'] }} + {% if volume_mount['read_only'] %} + readOnly: True + {% endif %} + {% if volume_mount['sub_path'] %} + subPath: {{ volume_mount['sub_path'] }} + {% endif %} + {% endfor %} + {% endif %} + {% if stage.resource_limits or stage.resource_requests %} + resources: + {% if stage.resource_limits %} + limits: + {% if stage.resource_limits.memory %} + memory: {{ stage.resource_limits.memory }} + {% endif %} + {% if stage.resource_limits.cpu %} + cpu: {{ stage.resource_limits.cpu }} + {% endif %} + {% if stage.resource_limits.gpu %} + nvidia.com/gpu: {{ stage.resource_limits.gpu }} + {% endif %} + {% endif %} + {% if stage.resource_requests %} + requests: + {% if stage.resource_requests.memory %} + memory: {{ stage.resource_requests.memory }} + {% endif %} + {% if stage.resource_requests.cpu %} + cpu: {{ stage.resource_requests.cpu }} + {% endif %} + {% if stage.resource_requests.gpu %} + nvidia.com/gpu: {{ stage.resource_requests.gpu }} + {% endif %} + {% endif %} + {% endif %} + {% if stage.env %} + env: + {% for env_var in stage.env %} + - name: {{ env_var['name'] }} + value: "{{ env_var['value'] }}" + {% endfor %} + {% endif %} + {% if stage.env_from %} + envFrom: + {% for env_from_elem in stage.env_from %} + - {{ env_from_elem['key'] }}: + {{ env_from_elem['body'] }} + {% endfor %} + {% endif %} + {% endfor %} + containers: + - name: validate-trial-results + image: {{ validation.image_name }} + {% if validation %} + command: ["python3", "-m"] + args: + - exp_pipeline.results.main + {% if validation.volume_mounts %} + volumeMounts: + {% for volume_mount in validation.volume_mounts %} + - name: {{ volume_mount['volume_name'] }} + mountPath: {{ volume_mount['mount_path'] }} + {% if volume_mount['read_only'] %} + readOnly: True + {% endif %} + {% if volume_mount['sub_path'] %} + subPath: {{ volume_mount['sub_path'] }} + {% endif %} + {% endfor %} + {% endif %} + {% if validation.resource_limits %} + resources: + limits: + {% if validation.resource_limits.memory %} + memory: {{ validation.resource_limits.memory }} + {% endif %} + {% if validation.resource_limits.cpu %} + cpu: {{ validation.resource_limits.cpu }} + {% endif %} + {% if validation.resource_limits.gpu %} + nvidia.com/gpu: {{ validation.resource_limits.gpu }} + {% endif %} + {% endif %} + {% if validation.env %} + env: + {% for env_var in validation.env %} + - name: {{ env_var[ 'name' ] }} + value: "{{ env_var['value'] }}" + {% endfor %} + {% endif %} + {% if validation.env_from %} + envFrom: + {% for env_from_elem in validation.env_from %} + - {{ env_from_elem['key'] }}: + {{ env_from_elem['body'] }} + {% endfor %} + {% endif %} + {% else %} + command: [ "python3", "-c" ] + args: + - print('Results validation disabled') + {% endif %} + {% if volumes %} + volumes: + {% for volume in volumes %} + - name: {{ volume['volume_name'] }} + {% if volume['pvc_name'] %} + persistentVolumeClaim: + claimName: {{ volume['pvc_name'] }} + {% endif %} + {% if volume['secret_name'] %} + secret: + secretName: {{ volume['secret_name'] }} + {% if volume['volume_items'] %} + items: + {% for vi in volume['volume_items'] %} + - key: "{{ vi.key }}" + path: "{{ vi.path }}" + {% endfor %} + {% endif %} + {% endif %} + {% if volume['configmap_name'] %} + configMap: + name: {{ volume['configmap_name'] }} + {% if volume['volume_items'] %} + items: + {% for vi in volume['volume_items'] %} + - key: "{{ vi.key }}" + path: "{{ vi.path }}" + {% endfor %} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + {% if image_reg_creds %} + imagePullPolicy: Always + imagePullSecrets: + {% for secret_name in image_reg_creds %} + - name: {{ secret_name }} + {% endfor %} + {% endif %} + {% if tolerations %} + tolerations: + {% for tol in tolerations %} + - key: "{{ tol.key }}" + operator: "{{ tol.operator }}" + value: "{{ tol.value }}" + effect: "{{ tol.effect }}" + {% endfor %} + {% endif %} + {% if node_selector %} + nodeSelector: + {% for key, value in node_selector.items() %} + {{ key }}: "{{ value }}" + {% endfor %} + {% endif %} + {% if node_affinity %} + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + {% for e in node_affinity.expressions %} + - key: {{ e.key }} + operator: {{ e.operator }} + values: + {% for v in e.vals %} + - "{{ v }}" + {% endfor %} + {% endfor %} + {% endif %} diff --git a/controller/templates/ml-component/allow-ml-cmp-ingress-traffic-np.yaml b/controller/templates/ml-component/allow-ml-cmp-ingress-traffic-np.yaml new file mode 100644 index 0000000..33588bd --- /dev/null +++ b/controller/templates/ml-component/allow-ml-cmp-ingress-traffic-np.yaml @@ -0,0 +1,19 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: MLComponent +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +kind: NetworkPolicy +apiVersion: networking.k8s.io/v1 +metadata: + name: {{ name }} + namespace: {{ namespace }} +spec: + policyTypes: + - Ingress + podSelector: + matchLabels: + app: ml-cmp-{{ ml_component_name }} + ingress: + - {} \ No newline at end of file diff --git a/controller/templates/ml-component/ml-component-deployment.yaml b/controller/templates/ml-component/ml-component-deployment.yaml new file mode 100644 index 0000000..9651276 --- /dev/null +++ b/controller/templates/ml-component/ml-component-deployment.yaml @@ -0,0 +1,137 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: MLComponent +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ deployment_name }} + namespace: {{ namespace }} +spec: + replicas: 1 + selector: + matchLabels: + app: ml-cmp-{{ name }} + template: + metadata: + labels: + app: ml-cmp-{{ name }} + spec: + containers: + - name: ml-cmp-{{ name }} + image: {{ image_name }} + imagePullPolicy: Always + command: ["/bin/bash"] + args: + - -c + - >- + {% if python_package_version %} + pip3 install "unip-mlcmp {{ python_package_version }}" + {% else %} + pip3 install unip-mlcmp + {% endif %} + {% if python_package_registry_credentials %} + --extra-index-url {{ python_package_registry_credentials }} + --trusted-host {{ python_package_registry_host }} + {% endif %} + && + {% if file_exchange_copy %} + mkdir -p $(FILES_S3_COPY_INFERENCE_FILES_DIR) && + {% endif %} + export PYTHONPATH=$PYTHONPATH:$(PYTHONPATH_EXTENSION) && + export PATH=/home/user/.local/bin:$PATH && + {% if download_model %} + python3 -m unip.mlcmp.download_model_s3 && + {% endif %} + hypercorn $(MLCMP_PACKAGE_APP_NAME) -k trio -b 0.0.0.0:{{ container_port }} + {% if env %} + env: + {% for env_var in env %} + - name: {{ env_var['name'] }} + value: "{{ env_var['value'] }}" + {% endfor %} + {% endif %} + {% if env_from %} + envFrom: + {% for env_from_elem in env_from %} + - {{ env_from_elem['key'] }}: + {{ env_from_elem['body'] }} + {% endfor %} + {% endif %} + ports: + - containerPort: {{ container_port }} + {% if volume_mounts %} + volumeMounts: + {% for volume_mount in volume_mounts %} + - name: {{ volume_mount['volume_name'] }} + mountPath: {{ volume_mount['mount_path'] }} + {% if volume_mount['sub_path'] %} + subPath: {{ volume_mount['sub_path'] }} + {% endif %} + {% endfor %} + {% endif %} + {% if resource_limits or resource_requests %} + resources: + {% if resource_limits %} + limits: + {% if resource_limits.memory %} + memory: {{ resource_limits.memory }} + {% endif %} + {% if resource_limits.cpu %} + cpu: {{ resource_limits.cpu }} + {% endif %} + {% if resource_limits.gpu %} + nvidia.com/gpu: {{ resource_limits.gpu }} + {% endif %} + {% endif %} + {% if resource_requests %} + requests: + {% if resource_requests.memory is not none %} + memory: {{ resource_requests.memory }} + {% endif %} + {% if resource_requests.cpu is not none %} + cpu: {{ resource_requests.cpu }} + {% endif %} + {% if resource_requests.gpu %} + nvidia.com/gpu: {{ resource_requests.gpu }} + {% endif %} + {% endif %} + {% endif %} + {% if volumes %} + volumes: + {% for volume in volumes %} + - name: {{ volume['volume_name'] }} + persistentVolumeClaim: + claimName: {{ volume['pvc_name'] }} + {% endfor %} + {% endif %} + {% if image_registry_credentials_secret_name %} + imagePullSecrets: + - name: {{ image_registry_credentials_secret_name }} + {% endif %} + {% if tolerations %} + tolerations: + {% for tol in tolerations %} + - key: "{{ tol.key }}" + operator: "{{ tol.operator }}" + value: "{{ tol.value }}" + effect: "{{ tol.effect }}" + {% endfor %} + {% endif %} + {% if node_affinity %} + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + {% for e in node_affinity.expressions %} + - key: {{ e.key }} + operator: {{ e.operator }} + values: + {% for v in e.vals %} + - "{{ v }}" + {% endfor %} + {% endfor %} + {% endif %} diff --git a/controller/templates/ml-component/ml-component-svc.yaml b/controller/templates/ml-component/ml-component-svc.yaml new file mode 100644 index 0000000..39027ba --- /dev/null +++ b/controller/templates/ml-component/ml-component-svc.yaml @@ -0,0 +1,19 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: MLComponent +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: v1 +kind: Service +metadata: + name: {{ service_name }} + namespace: {{ namespace }} +spec: + type: ClusterIP + selector: + app: ml-cmp-{{ name }} + ports: + - protocol: TCP + port: {{ service_port }} + targetPort: {{ container_port }} diff --git a/controller/templates/platform-app/allow-dns-traffic-np.yaml b/controller/templates/platform-app/allow-dns-traffic-np.yaml new file mode 100644 index 0000000..71ae63a --- /dev/null +++ b/controller/templates/platform-app/allow-dns-traffic-np.yaml @@ -0,0 +1,23 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: PlatformApp +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +kind: NetworkPolicy +apiVersion: networking.k8s.io/v1 +metadata: + name: allow-dns-traffic + namespace: {{ namespace }} +spec: + podSelector: {} + policyTypes: + - Egress + egress: + - to: + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: "kube-system" + - podSelector: + matchLabels: + k8s-app: "kube-dns" \ No newline at end of file diff --git a/controller/templates/platform-app/allow-ns-traffic-np.yaml b/controller/templates/platform-app/allow-ns-traffic-np.yaml new file mode 100644 index 0000000..495963a --- /dev/null +++ b/controller/templates/platform-app/allow-ns-traffic-np.yaml @@ -0,0 +1,26 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: PlatformApp +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +kind: NetworkPolicy +apiVersion: networking.k8s.io/v1 +metadata: + name: allow-inner-namespace-traffic + namespace: {{ namespace }} +spec: + policyTypes: + - Ingress + - Egress + podSelector: {} + ingress: + - from: + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: {{ namespace }} + egress: + - to: + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: {{ namespace }} \ No newline at end of file diff --git a/controller/templates/platform-app/default-allow-egress-traffic-np.yaml b/controller/templates/platform-app/default-allow-egress-traffic-np.yaml new file mode 100644 index 0000000..b65c2ed --- /dev/null +++ b/controller/templates/platform-app/default-allow-egress-traffic-np.yaml @@ -0,0 +1,17 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: PlatformApp +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +kind: NetworkPolicy +apiVersion: networking.k8s.io/v1 +metadata: + name: default-allow-egress-traffic + namespace: {{ namespace }} +spec: + policyTypes: + - Egress + podSelector: {} + egress: + - {} \ No newline at end of file diff --git a/controller/templates/platform-app/default-deny-ingress-traffic-np.yaml b/controller/templates/platform-app/default-deny-ingress-traffic-np.yaml new file mode 100644 index 0000000..de0f141 --- /dev/null +++ b/controller/templates/platform-app/default-deny-ingress-traffic-np.yaml @@ -0,0 +1,15 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: PlatformApp +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +kind: NetworkPolicy +apiVersion: networking.k8s.io/v1 +metadata: + name: default-deny-ingress-traffic + namespace: {{ namespace }} +spec: + policyTypes: + - Ingress + podSelector: {} \ No newline at end of file diff --git a/controller/templates/platform-app/role.yaml b/controller/templates/platform-app/role.yaml new file mode 100644 index 0000000..003257c --- /dev/null +++ b/controller/templates/platform-app/role.yaml @@ -0,0 +1,34 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: PlatformApp +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + namespace: {{ namespace }} + name: {{ name }} +rules: +- apiGroups: ["unified-platform.cs.hse.ru"] + resources: ["mlcomponents", "databoxes", "apicomponents", "experimentpipelines", + "mlcomponents/status", "databoxes/status", "apicomponents/status", "experimentpipelines/status"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] +- apiGroups: [""] + resources: ["secrets", "configmaps", "pods/exec"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] +#- apiGroups: ["batch"] +# resources: ["jobs"] +# verbs: ["get", "list"] +- apiGroups: [""] + resources: ["pods", "pods/log"] + verbs: ["get", "list"] +#- apiGroups: [""] +# resources: ["pods", "services", "persistentvolumeclaims", "pods/log"] +# verbs: ["get", "list"] +#- apiGroups: ["apps"] +# resources: ["deployments"] +# verbs: ["get", "list"] +#- apiGroups: ["networking.k8s.io", "networking", "extensions"] +# resources: ["ingresses"] +# verbs: ["get", "list"] \ No newline at end of file diff --git a/controller/templates/platform-user/role.yaml b/controller/templates/platform-user/role.yaml new file mode 100644 index 0000000..8b95e30 --- /dev/null +++ b/controller/templates/platform-user/role.yaml @@ -0,0 +1,21 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: PlatformUser +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + namespace: {{ namespace }} + name: default +rules: +- apiGroups: ["unified-platform.cs.hse.ru"] + resources: ["platformapps", "repositories", "componentlinks"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] +- apiGroups: [""] + resources: ["secrets", "configmaps"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] +- apiGroups: [""] + resources: ["serviceaccounts/token"] + verbs: ["create"] \ No newline at end of file diff --git a/controller/templates/repository/delete-robots-tokens-secrets-job.yaml b/controller/templates/repository/delete-robots-tokens-secrets-job.yaml new file mode 100644 index 0000000..8bd4568 --- /dev/null +++ b/controller/templates/repository/delete-robots-tokens-secrets-job.yaml @@ -0,0 +1,50 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Repository +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2025 г. +# ============================================================ +apiVersion: batch/v1 +kind: CronJob +metadata: + name: {{ job_name }} + namespace: {{ namespace }} +spec: + schedule: "{{ schedule }}" + jobTemplate: + spec: + template: + spec: + containers: + - name: delete-robots-token-secret + image: bitnami/kubectl:1.32.3 + imagePullPolicy: IfNotPresent + env: + - name: NAMESPACE + value: {{ secrets_namespace }} + - name: LABEL + value: {{ secrets_label }} + command: + - /bin/sh + - -c + - |- + secrets=$(kubectl get secret -o jsonpath='{.items[*].metadata.name}' -n $NAMESPACE -l $LABEL) + if [ -z "${secrets}" ]; then + echo "No secrets with label '$LABEL' found" + exit + fi + + for secret in $secrets; do + result=$(kubectl delete secret $secret -n $NAMESPACE 2>&1) + result_code=$? + if [ $result_code -eq "0" ]; then + echo "Secret $NAMESPACE.$secret deleted"; + else + echo "Secret $NAMESPACE.$secret not deleted. $result"; + fi + done + resources: + limits: + memory: 64M + cpu: 100m + restartPolicy: OnFailure diff --git a/controller/templates/repository/robots_secrets.sh b/controller/templates/repository/robots_secrets.sh new file mode 100755 index 0000000..037be29 --- /dev/null +++ b/controller/templates/repository/robots_secrets.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +# script for dev purposes +NAMESPACE=pu-user1 +LABEL='keycloak.userregistry.repository.unified-platform.cs.hse.ru/robot-tokens-of=test-keycloak-user-registry' + + +secrets=$(kubectl get secret -o jsonpath='{.items[*].metadata.name}' -n $NAMESPACE -l $LABEL) +if [ -z "${secrets}" ]; then + echo "No secrets with label '$LABEL' found" + exit +fi + +for secret in $secrets; do + result=$(kubectl delete secret $secret -n $NAMESPACE 2>&1) + result_code=$? + if [ $result_code -eq "0" ]; then + echo "Secret $NAMESPACE.$secret deleted"; + else + echo "Secret $NAMESPACE.$secret not deleted. $result"; + fi +done \ No newline at end of file diff --git a/deploy/README.md b/deploy/README.md new file mode 100644 index 0000000..597e597 --- /dev/null +++ b/deploy/README.md @@ -0,0 +1,65 @@ +# Инструкция по установке Единого MLOps фреймворка Центра ИИ НИУ ВШЭ (Unified Platform) + +Этот документ описывает основные шаги и особенности установки +Единого MLOps фреймворка Центра ИИ НИУ ВШЭ (Unified Platform). + +## Предусловия + +См. [документ](prerequisites.md) с описанием предусловий. + +## Установка фреймворка + +Установка состоит из следующих этапов: +1. Развертывание на платформе Kubernetes контроллеров и сервисов фреймворка; +2. Загрузка образов и Python пакетов фреймворка в реестры образов и Python пакетов фреймворка; + +Компоненты фреймворка: +1. Контроллер публикации API (apicmp); +2. Сервис управления данными (files); +3. Контроллер развертывания моделей (mlcmp); +4. Сервис отслеживания экспериментов, конвейеров (pipelines); +5. Контроллер репозиториев (repo); +6. Контроллер приложений (papp); +7. Контроллер модулей данных (datasets); +8. Контроллер ссылок (links); +9. Сервис развертывания (gitops); +10. Каталог приложений (app-catalog); +11. Библиотека адаптеров сложного конвейера (mldev-pipeline); +12. Библиотека подключения вычислительного кластера (slurm); + +Библиотеки загружаются в реестр Python пакетов. +Установка остальных компонентов осуществляется путем создания ресурсов Kubernetes из манифестов, +входящих в поставку фреймворка. + +При развертывании компонентов фреймворка из манифестов следует внести следующие корректировки в манифесты: +1. Изменить `storageClassName` в манифестах PersistentVolume и PersistentVolumeClaim на имя StorageClass, +который поддерживается платформой Kubernetes. Из-за особенностей системы хранения используемой платформой, +могут потребоваться и другие корректировки спецификации объектов PersistentVolume и PersistentVolumeClaim; +2. Изменить используемые доменные имена в соответствующих местах в ресурсах видов: Secret, ConfigMap, Ingress; + +### Развертывание контроллеров и сервисов фреймворка + +#### Развертывание контроллеров, сервисов управления данными и отслеживания экспериментов + +Развертывание контроллеров, сервисов управления данными и отслеживания экспериментов описано +в [документе](./controller.md). + +#### Развертывание сервиса развертывания + +В качестве сервиса развертывания используется ArgoCD, +установка и настройка описывается в [официальной документации](https://argo-cd.readthedocs.io/en/stable/getting_started/). + +### Загрузка образов и Python пакетов фреймворка в реестры образов и Python пакетов фреймворка + +Библиотеки фреймворка: +1. Библиотека развертывания моделей (mlcmp), является Python пакетом unip-mlcmp версии 0.2.10.1; + +Образы фреймворка: +1. Образ, используемый сервисом конвейеров (pipelines), +является Docker образом unip-pipeline-validate-results:0.3.7-9c53a08; + +После выполнения установки компонентов фреймворка, необходимо загрузить Python пакеты компонентов фреймворка +в реестр Python пакетов фреймворка и загрузить образы фреймворка в реестр образов фреймворка. + +Загруженные образы и Python пакеты должны быть закрыты для внешнего неавторизованного доступа, +должны быть доступны для разработчиков размещаемых приложений. \ No newline at end of file diff --git a/deploy/apicmps/cors-cm.yaml b/deploy/apicmps/cors-cm.yaml new file mode 100644 index 0000000..ba565de --- /dev/null +++ b/deploy/apicmps/cors-cm.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: unip-system-controller + name: cors-cm +data: +# UNIP_API_CMP_CORS_ENABLED: True +# UNIP_API_CMP_APPS_CORS_ENABLED: True +# UNIP_API_CMP_CORS_ALLOW_METHODS: GET,POST,PUT,PATCH,DELETE +# UNIP_API_CMP_CORS_ALLOW_HEADERS: Authorization,Content-Type +# UNIP_API_CMP_CORS_EXPOSE_HEADERS: Authorization,Content-Type +# UNIP_API_CMP_CORS_ALLOW_ORIGIN: https://platform-forgejo.stratpro.hse.ru/ +# UNIP_API_CMP_CORS_MAX_AGE: 86400 diff --git a/deploy/argo-cd/argo-cd-cm.yaml b/deploy/argo-cd/argo-cd-cm.yaml new file mode 100644 index 0000000..0d2211d --- /dev/null +++ b/deploy/argo-cd/argo-cd-cm.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: unip-system-controller + name: argo-cd-cm +data: + ARGO_CD_ENABLED: "True" diff --git a/deploy/argo-cd/argo-cd-credentials-secret.yaml.sample b/deploy/argo-cd/argo-cd-credentials-secret.yaml.sample new file mode 100644 index 0000000..3e02fe5 --- /dev/null +++ b/deploy/argo-cd/argo-cd-credentials-secret.yaml.sample @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: Secret +metadata: + name: argo-cd-credentials + namespace: unip-system-controller +type: Opaque +stringData: + ARGO_CD_USER: user + ARGO_CD_PASSWORD: password + ARGO_CD_API: https:///api/v1 diff --git a/deploy/cluster-rb.yaml b/deploy/cluster-rb.yaml new file mode 100644 index 0000000..446ba4a --- /dev/null +++ b/deploy/cluster-rb.yaml @@ -0,0 +1,12 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: unip-controller-controller-sa-rb +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: unip-controller-cluster-role +subjects: + - kind: ServiceAccount + name: controller-sa + namespace: unip-system-controller \ No newline at end of file diff --git a/deploy/cluster-role-read.yaml b/deploy/cluster-role-read.yaml new file mode 100644 index 0000000..25047df --- /dev/null +++ b/deploy/cluster-role-read.yaml @@ -0,0 +1,46 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: unip-controller-cluster-role +rules: + - apiGroups: ["kopf.dev"] + resources: ["clusterkopfpeerings", "kopfpeerings"] + verbs: ["list", "watch", "get"] + - apiGroups: ["apiextensions.k8s.io"] + resources: ["customresourcedefinitions"] + verbs: ["list", "watch", "get"] + - apiGroups: ["rbac.authorization.k8s.io"] + resources: ["rolebindings", "roles", "clusterroles", "clusterrolebindings"] + verbs: ["get", "list", "watch"] + - apiGroups: [""] + resources: ["pods", "endpointslices", "services", "replicationcontrollers", "secrets", "configmaps", "endpoints", + "nodes", "namespaces", "events", "persistentvolumeclaims", "persistentvolumes", "serviceaccounts", + "pods/log", "pods/exec"] + verbs: ["get", "list", "watch"] + - apiGroups: [""] + resources: ["pods/exec"] + verbs: ["create"] + - apiGroups: ["admissionregistration.k8s.io/v1", "admissionregistration.k8s.io/v1beta1"] + resources: ["validatingwebhookconfigurations", "mutatingwebhookconfigurations"] + verbs: ["get", "list", "watch"] + - apiGroups: ["unified-platform.cs.hse.ru"] + resources: ["mlcomponents", "platformusers", "platformapps", "databoxes", "repositories", + "experimentpipelines", + "mlcomponents/status", "platformusers/status", "platformapps/status", + "databoxes/status", "repositories/status", + "experimentpipelines/status", + "apicomponents", "apicomponents/status", + "componentlinks", "componentlinks/status"] + verbs: ["get", "list", "watch"] + - apiGroups: ["unified-platform.cs.hse.ru"] + resources: ["datasetcomponents", "datasetcomponents/status"] + verbs: ["get", "list", "watch"] + - apiGroups: ["apps"] + resources: ["deployments", "replicasets", "daemonsets", "statefulsets"] + verbs: ["get", "list", "watch"] + - apiGroups: ["networking.k8s.io", "networking", "extensions"] + resources: ["ingresses", "ingressclasses", "networkpolicies"] + verbs: ["get", "list", "watch"] + - apiGroups: ["batch"] + resources: ["jobs"] + verbs: ["get", "list", "watch"] \ No newline at end of file diff --git a/deploy/cluster-role.yaml b/deploy/cluster-role.yaml new file mode 100644 index 0000000..409b313 --- /dev/null +++ b/deploy/cluster-role.yaml @@ -0,0 +1,45 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: unip-controller-cluster-role +rules: + # Framework: knowing which other operators are running (i.e. peering). + - apiGroups: ["kopf.dev"] + resources: ["clusterkopfpeerings", "kopfpeerings"] + verbs: ["list", "watch", "patch", "get"] + # Framework: runtime observation of namespaces & CRDs (addition/deletion). + - apiGroups: ["apiextensions.k8s.io"] + resources: ["customresourcedefinitions"] + verbs: ["list", "watch"] + - apiGroups: ["rbac.authorization.k8s.io"] + resources: ["rolebindings", "roles", "clusterroles", "clusterrolebindings"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] + - apiGroups: [""] + resources: ["pods", "endpointslices", "services", "replicationcontrollers", "secrets", "configmaps", "endpoints", + "nodes", "namespaces", "events", "persistentvolumeclaims", "persistentvolumes", "serviceaccounts", + "pods/log", "pods/exec", "serviceaccounts/token"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] + # Framework: admission webhook configuration management. + - apiGroups: ["admissionregistration.k8s.io/v1", "admissionregistration.k8s.io/v1beta1"] + resources: ["validatingwebhookconfigurations", "mutatingwebhookconfigurations"] + verbs: ["create", "patch"] + # Application: read-only access for watching cluster-wide. + - apiGroups: ["unified-platform.cs.hse.ru"] + resources: ["mlcomponents", "platformusers", "platformapps", "databoxes", "repositories", + "experimentpipelines", + "mlcomponents/status", "platformusers/status", "platformapps/status", + "databoxes/status", "repositories/status", + "experimentpipelines/status", + "apicomponents", "apicomponents/status", + "componentlinks", "componentlinks/status", + "datasetcomponents", "datasetcomponents/status"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] + - apiGroups: ["apps"] + resources: ["deployments", "replicasets", "daemonsets", "statefulsets"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] + - apiGroups: ["networking.k8s.io", "networking", "extensions"] + resources: ["ingresses", "ingressclasses", "networkpolicies"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] + - apiGroups: ["batch"] + resources: ["jobs", "cronjobs"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] \ No newline at end of file diff --git a/deploy/common/controller-cm.yaml b/deploy/common/controller-cm.yaml new file mode 100644 index 0000000..2b48d2b --- /dev/null +++ b/deploy/common/controller-cm.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: unip-system-controller + name: controller-cm +data: + UNIP_DOMAIN: platform-test.stratpro.hse.ru diff --git a/deploy/common/registry-credentials-secret.yaml.sample b/deploy/common/registry-credentials-secret.yaml.sample new file mode 100644 index 0000000..9863a54 --- /dev/null +++ b/deploy/common/registry-credentials-secret.yaml.sample @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: Secret +metadata: + name: registry-credentials + namespace: unip-system-controller +type: kubernetes.io/dockerconfigjson +data: + .dockerconfigjson: encoded_docker_config_json \ No newline at end of file diff --git a/deploy/config.md b/deploy/config.md new file mode 100644 index 0000000..72c0c4e --- /dev/null +++ b/deploy/config.md @@ -0,0 +1,122 @@ +# Параметры конфигурации контроллеров и сервисов управления данными и отслеживания экспериментов + +## Конфигурация сервиса управления данными + +### Конфигурация подключения объектного хранилища + +| Имя параметра | Обязательный | Назначение | +|----------------------------------------|--------------|-----------------------------------------------------------------------------| +| UNIP_BOXES_S3_DEFAULT_USER_DATA_BUCKET | Да | Имя бакета, используемого для хранения данных DataBox типа s3DefaultStorage | +| UNIP_BOXES_S3_SECRET_NAME | Да | Secret с реквизитами доступа к объектному хранилищу | +| UNIP_BOXES_S3_DEFAULT_HOST | Да | Адрес объектного хранилища, используемого по умолчанию | +| UNIP_BOXES_S3_DEFAULT_REGION | Да | Регион в объектном хранилище, используемый по умолчанию | + +## Конфигурация сервиса отслеживания экспериментов + +### Общие параметры конфигурации + +| Имя параметра | Обязательный | Назначение | +|--------------------------------|--------------|---------------------------------------------------------------------| +| UNIP_DOMAIN | Да | Имя основного домена | +| UNIP_FILES_API | Да | Внутренний адрес API сервиса управления данными | +| UNIP_PIPELINES_API | Да | Внешний адрес API сервиса отслеживания экспериментов | +| UNIP_PIPELINE_VALIDATION_IMAGE | Да | Имя валидационного образа конвейера эксперимента | +| UNIP_PIPELINE_RUN_MODE | Нет | Если Debug, то этап валидации результатов не добавляется в конвейер | +| UNIP_DATETIME_FORMAT | Нет | Формат для хранения временных данных | + +### Конфигурация подключения к системной СУБД + +| Имя параметра | Обязательный | Назначение | +|----------------------------------|--------------|---------------------------------------------------| +| UNIP_DATABASE_PIPELINES_USER | Да | Имя пользователя СУБД | +| UNIP_DATABASE_PIPELINES_PASSWORD | Да | Пароль пользователя СУБД | +| UNIP_DATABASE_PIPELINES_HOST | Да | Адрес хоста СУБД | +| UNIP_DATABASE_PIPELINES_PORT | Да | Порт сервиса СУБД | +| UNIP_DATABASE_PIPELINES_DB | Нет | Имя базы данных сервиса отслежвания экспериментов | + +## Конфигурация контроллеров + +### Общие параметры конфигурации + +| Имя параметра | Обязательный | Назначение | +|--------------------------------|--------------|---------------------------------------------------------------------| +| UNIP_DOMAIN | Да | Имя основного домена | +| UNIP_FILES_API | Да | Внутренний адрес API сервиса управления данными | +| UNIP_PIPELINES_API | Да | Внешний адрес API сервиса отслеживания экспериментов | + +### Конфигурация подключения объектного хранилища + +| Имя параметра | Обязательный | Назначение | +|----------------------------------------|--------------|-----------------------------------------------------------------------------| +| UNIP_BOXES_S3_DEFAULT_USER_DATA_BUCKET | Да | Имя бакета, используемого для хранения данных DataBox типа s3DefaultStorage | +| UNIP_BOXES_CSI_S3_SECRET_NAME | Да | Secret с реквизитами доступа к объетному хранилищу | +| UNIP_BOXES_CSI_S3_STORAGE_CLASS | Да | Внешний адрес API сервиса отслеживания экспериментов | + +### Конфигурация подключения сервиса развертывания + +| Имя параметра | Обязательный | Назначение | +|------------------|--------------------|--------------------------------------------------------------------------------------------------------------------------------| +| ARGO_CD_ENABLED | Да (кроме отладки) | Если True, то сервис развертывания подключен, иначе не подключен. Отключение сервиса развертывания возможно только для отладки | +| ARGO_CD_USER | Да (кроме отладки) | Имя пользователя администратора сервиса развертывания | +| ARGO_CD_PASSWORD | Да (кроме отладки) | Пароль пользователя администратора сервиса развертывания | +| ARGO_CD_API | Да (кроме отладки) | Адрес API сервиса развертывания вида https:///api/v1 | + +### Конфигурация подключения внешнего поставщика реквизитов (OIDC провайдера) + +| Имя параметра | Обязательный | Назначение | +|-----------------------------------------------------------|--------------|----------------------------------------------------------------------------------------------| +| OIDC_END_USERS_ISSUER_URL | Да | URL эмитента для реалма конечных пользователей | +| OIDC_END_USERS_REALM | Да | Реалм конечных пользователей | +| OIDC_END_USERS_CLIENT_ID | Да | Идентификатор публичного клиента в реалме конечных пользователей | +| OIDC_END_USERS_CLIENT_SECRET | Да | Значение-заглушка секрета публичного клиента в реалме конечных пользователей | +| OIDC_END_USERS_ADMIN_CLIENT_ID | Да | Идентификатор административного клиента в реалме конечных пользователей | +| OIDC_END_USERS_ADMIN_CLIENT_SECRET | Да | Секрет административного клиента в реалме конечных пользователей | +| OIDC_END_USERS_AUD | Да | aud реалма конечных пользователей | +| OIDC_END_USERS_COOKIE_SECRET | Да | Значение-заглушка секрета cookie для реалма конечных пользователей | +| OIDC_ROBOTS_ISSUER_URL | Да | URL эмитента для реалма робот аккаунтов | +| OIDC_ROBOTS_REALM | Да | Реалм робот аккаунтов | +| OIDC_ROBOTS_CLIENT_ID | Да | Идентификатор публичного клиента в реалме робот аккаунтов | +| OIDC_ROBOTS_CLIENT_SECRET | Да | Значение-заглушка секрета публичного клиента в реалме робот аккаунтов | +| OIDC_ROBOTS_ADMIN_CLIENT_ID | Да | Идентификатор административного клиента в реалме робот аккаунтов | +| OIDC_ROBOTS_ADMIN_CLIENT_SECRET | Да | Секрет административного клиента в реалме робот аккаунтов | +| OIDC_ROBOTS_AUD | Да | aud реалма робот аккаунтов | +| OIDC_KEYCLOAK_HOST | Да | Адрес хоста Keycloak | +| OIDC_MANAGED_GROUPS_ROOT | Нет | Имя корневой группы для групп, управляемых контроллером | +| OIDC_CLUSTER_GROUP_NAME | Нет | Имя группы кластера, которая включает в себя группы, управляемые контроллером | +| OIDC_MODIFY | Нет | Если True, то создает и удаляет необходимые ресурсы Keycloak, иначе только проверяет наличие | +| UNIP_REPOSITORY_KEYCLOAK_ROBOTS_CREDS_NAMESPACE | Нет | Пространство имен для хранения реквизитов робот аккаунтов | +| UNIP_REPOSITORY_KEYCLOAK_ROBOTS_TOKENS_RENEWAL_PERIOD_MIN | Нет | Время обновления токенов робот аккаунтов | + + +### Конфигурация контроллера модулей данных + +| Имя параметра | Обязательный | Назначение | +|-----------------------------------------------|--------------|------------------------------------------------------------------------------------| +| FILES_API_BASE_URL | Да | Внешений адрес API сервиса управления данными | +| INGRESS_RULE_HOST | Да | Хост правила Ingress | +| INGRESS_BACKEND_SERVICE_NAME | Да | Service для правила Ingress | +| INGRESS_BACKEND_SERVICE_PORT | Да | Порт Service для правила Ingress | +| UNIP_DATASET_CMP_CHECK_CONTROLLER_PERMISSIONS | Нет | Включает или выключает (True \ False) проверку прав контроллера, по умолчанию True | +| UNIP_DATASET_CMP_VALIDATE | Нет | Включает или выключает (True \ False) валидацию датасета, по умолчанию True | + + +### Конфигурация контроллера публикации API + +#### Конфигурация CORS (опционально) + +| Имя параметра | Обязательный | Назначение | +|---------------------------------|--------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| UNIP_API_CMP_CORS_ENABLED | Нет | Добавляет настройку CORS в Ingress, создаваемые для APIComponent | +| UNIP_API_CMP_APPS_CORS_ENABLED | Нет | Добавляет поддержку настройки CORS в спецификции APIComponent; если не задано, то наследует значение UNIP_API_CMP_CORS_ENABLED | +| UNIP_API_CMP_CORS_ALLOW_METHODS | Нет | разрешенные CORS HTTP методы, перечисленные через запятую; если не задано, то все HTTP методы | +| UNIP_API_CMP_CORS_ALLOW_HEADERS | Нет | разрешенные CORS HTTP заголовки, перечисленные через запятую; если не задано - `DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization` | +| UNIP_API_CMP_CORS_ALLOW_ORIGIN | Нет | разрешенные CORS Origin, переичлснные через запятую; если не задано - `*` | +| UNIP_API_CMP_CORS_MAX_AGE | Нет | время кэширования preflight запросов; если не задано - `1728000` | + +При определении конечного значения конкретного параметра для конкретного APIComponent применяется следующая логика: +1. Если `UNIP_API_CMP_CORS_ENABLED: True`, то значения определяются на основе конфигурации контроллера. +2. Если `UNIP_API_CMP_APPS_CORS_ENABLED: True`, то значения, определенные на предыдущем шаге, дополняются значениями +для конкретного APIComponent. + 1. Если значение параметра задано в спецификации APIComponent, то используется оно. + 2. Если значение параметра не задано в спецификации APIComponent, то используется значение + из конфигурации контроллера. \ No newline at end of file diff --git a/deploy/controller.md b/deploy/controller.md new file mode 100644 index 0000000..91e5f03 --- /dev/null +++ b/deploy/controller.md @@ -0,0 +1,211 @@ +# Развертывание контроллеров, сервисов управления данными и отслеживания экспериментов + +Для развертывания необходимо создать ресурсы Kubernetes, +применив манифесты из папки unip-controller из проекта развертывания unip-components из поставки фреймворка. + +Применение манифестов осуществляется командой `kubectl apply -f <имя файла манифеста>`. + +Развертывание включает следующие шаги: + +1. Создание пространства имен; +2. Создание ресурсов kopf; +3. Создание определений ресурсов фреймворка; +4. Подключение системной СУБД и настройка БД; +5. Подключение объектного хранилища; +6. Подключение сервиса развертывания; +7. Подключение внешнего поставщика реквизитов (OIDC провайдера); +8. Конфигурация сервиса отслеживания экспериментов; +9. Конфигурация сервиса управления данными; +10. Конфигурация контроллера модулей данных; +11. Конфигурация контроллера публикации API; +12. Создание ресурса размещения Kubernetes; + +## Создание пространства имен + +Применить манифест командой `kubectl apply -f ns.yaml`. + +## Создание ресурсов kopf + +Применить манифест командой `kubectl apply -f kopf/peering.yaml`. + +## Создание определений ресурсов фреймворка + +Применить манифесты из папки crd командой `kubectl apply -f <имя файла манифеста>`. + +## Подключение системной СУБД и настройка БД + +### Подготовка среды для настройки + +Установить psql клиент PostgreSQL. Для Ubuntu: +`apt-get install -y postgresql-client` + +Подключиться к системной СУБД. +Команды для подключения, если системная СУБД развернута в кластере Kubernetes в пространстве unip-system-database: +`kubectl port-forward service/postgres 5432:5432 -n unip-system-database` + +`psql -h 127.0.0.1 -p 5432 -U postgres -W` + +### Создание БД + +Выполнить команды psql: + +``` +postgres=# +CREATE USER unip_system_pipelines WITH PASSWORD ''; +CREATE DATABASE unip_system_pipelines; +GRANT ALL PRIVILEGES ON DATABASE unip_system_pipelines TO unip_system_pipelines; +ALTER DATABASE unip_system_pipelines OWNER TO unip_system_pipelines; +``` + +Установить привилегии, выполнив команды psql +(важно выполнять при подключении к БД, для которой устанавливаются привилегии): + +``` +unip_system_pipelines=# +GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO unip_system_pipelines; +GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public to unip_system_pipelines; +GRANT ALL PRIVILEGES ON ALL FUNCTIONS IN SCHEMA public to unip_system_pipelines; +``` + +### Подключение БД к сервису отслеживания экспериментов + +Создать ресурс Secret `unip_system_pipelines` с реквизитами доступа к БД +по образцу pipelines/pipelines-db-credentials-secret.yaml. + +Значение параметров в Secret `unip_system_pipelines` см. в описании +[конфигурации](config.md) сервиса отслеживания экспериментов. + +## Подключение объектного хранилища + +### Создание StorageClass + +1. Создать ресурс Secret `csi-s3-secret` по образцу s3/csi-s3-credentials-secret.yaml.sample. +Secret должен содержать реквизиты доступа к объектному хранилищу с правами получения списка бакетов; +2. Создать ресурс StorageClass из манифеста s3/sc.yaml; + +### Создание бакета для хранения пользовательских данных + +1. В объектном хранилище создать бакет `platform-default-user-bucket`. +Его имя может быть любым, но если оно отличается от `platform-default-user-bucket`, +то необходимо изменить значение параметра `UNIP_BOXES_S3_DEFAULT_USER_DATA_BUCKET` +в ресурсах конфигурации (ниже); +2. Создать ресурс Secret `aws-vars-s3-credentials` по образцу s3/csi-s3-credentials-secret.yaml.sample. +Secret должен содержать реквизиты доступа к объектному хранилищу с правами чтения и записи +в бакет хранения пользовательских данных; + +### Подключение объектного хранилища + +Уточнить конфигурацию доступа к объектному хранилищу в манифесте files/files-cm.yaml и применить манифест. + +Уточнить конфигурацию доступа к объектному хранилищу в манифесте databoxes/databoxes-cm.yaml и применить манифест. + +Значение параметров в манифестах см. в описании +[конфигурации](config.md) фреймворка. + +## Подключение сервиса развертывания + +Создать ресурс Secret `argo-cd-credentials` по образцу argo-cd/argo-cd-credentials-secret.yaml.sample. + +Уточнить конфигурацию сервиса развертывания в манифесете argo-cd/argo-cd-cm.yaml. + +Значение параметров в манифестах см. в описании +[конфигурации](config.md) сервиса развертывания. + + +## Подключение внешнего поставщика реквизитов (OIDC провайдера) + +### Настройка внешнего поставщика реквизитов Keycloak + +Для настройки OIDC провайдера Keycloak выполнить следующие шаги: +1. Создать реалм для конечных пользователей и реалм для робот аккаунтов (может использоваться один реалм, +но более безопасно использовать два реалма, например, `end-users` и `robots`); +2. Создать публичный (Client authentication - Off; Standard flow - Enabled; Direct access grants - Enabled) +и конфиденциальный клиенты (Client authentication - On) +в каждом из реалмов (конфиденциальный клиент также называется административным клиентом). +3. Конфиденциальный клиент в реалме конечных пользователей должен иметь права: + 1. Управлять группами (просматривать, создавать, удалять, перемещать между родителями). + 2. Добавлять в группы и удалять из групп пользователей. + 3. Выполнять поиск и просмотр пользователей. +4. Конфиденциальный клиент в реалме робот аккаунтов должен иметь те же права, плюс: + 1. Управлять пользователями (просматривать, создавать, удалять, перемещать между родителями). + +Опционально в расширенных (advanced) настройках клиента Keycloak можно указать время жизни токена: +Access Token Lifespan. + +### Подключение внешнего поставщика к контроллеру ссылок + +Проверить и уточнить конфигурацию OIDC в манифесете oidc/oidc-cm.yaml. Применить манифест oidc/oidc-cm.yaml. + +Создать ресурс Secret `oidc-credentials` по образцу oidc-credentials-secret.yaml.sample в папке ./oidc. +Значения атрибутов `OIDC_END_USERS_CLIENT_SECRET`, `OIDC_ROBOTS_CLIENT_SECRET`, `OIDC_END_USERS_COOKIE_SECRET` +могут быть взяты из образца без изменений. + +Значение параметров манифестах см. в описании +[конфигурации](config.md) внешнего поставщика реквизитов. + +Создать пространство имен для хранения реквизитов робот аккаунтов из манифеста keycloak-robots-creds-ns.yaml. +При изменении имени пространства имен изменить значение атрибута `UNIP_REPOSITORY_KEYCLOAK_ROBOTS_CREDS_NAMESPACE` +в ConfigMap oidc-cm.yaml. + +После настройки OIDC провайдера Keycloak выполнить: +1. Уточнить настройки OIDC в манифесте ConfigMap oidc-cm.yaml в папке ./oidc и создать ресурс из манифеста. +2. Создать ресурс Secret `oidc-credentials` по образцу oidc-credentials-secret.yaml.sample в папке ./oidc. + 1. Значения атрибутов `OIDC_END_USERS_CLIENT_SECRET`, `OIDC_ROBOTS_CLIENT_SECRET`, `OIDC_END_USERS_COOKIE_SECRET` + могут быть взяты из образца без изменений. +3. Создать пространство имен для хранения реквизитов робот аккаунтов из манифеста keycloak-robots-creds-ns.yaml. +При изменении имени пространства имен изменить значение атрибута `UNIP_REPOSITORY_KEYCLOAK_ROBOTS_CREDS_NAMESPACE` +в ConfigMap oidc-cm.yaml. + +## Конфигурация сервиса отслеживания экспериментов + +Проверить и уточнить конфигурацию сервиса отслеживания экспериментов в манифесете pipelines/pipelines-cm.yaml. +Применить манифест ./pipelines/pipelines-cm.yaml. + +Значение параметров манифеста см. в описании +[конфигурации](config.md) сервиса отслеживания экспериментов. + +## Конфигурация сервиса управления данными + +Проверить и уточнить конфигурацию сервиса управления данными в манифесете files/files-cm.yaml. +Применить манифест ./files/files-cm.yaml. + +Значение параметров манифеста см. в описании +[конфигурации](config.md) сервиса управления данными. + +## Конфигурация контроллера модулей данных + +Проверить и уточнить конфигурацию сервиса управления данными в манифесете ./datasets/datasets-cm.yaml. +Применить манифест ./datasets/datasets-cm.yaml. + +Значение параметров манифеста см. в описании +[конфигурации](config.md) контроллера модулей данных. + +## Конфигурация контроллера публикации API + +### Настройка CORS (опционально) + +Проверить и уточнить конфигурацию CORS в манифесете ./apicmps/cors.yaml. +Применить манифест ./apicmps/cors.yaml. + +Значение параметров манифеста см. в описании +[конфигурации](config.md) конфигурации CORS. + +## Создание ресурса размещения Kubernetes + +1. Уточнить имя основного домена - значение ключа `UNIP_DOMAIN` в манифесте ./common/controller-cm.yaml и применить манифест; +2. Создать ресурс Secret `registry-credentials` с реквизитами доступа к реестру образов +с образом unip-controller по образцу ./common/registry-credentials-secret.yaml.sample; +3. Создать ресурсы Kubernetes из манифестов: + 1. files/files-svc.yaml; + 2. pipelines/pipelines-svc.yaml; + 3. sa.yaml; + 4. cluster-role.yaml; + 5. cluster-rb.yaml; + 6. deployment.yam; + +## Проверка установки + +В пространстве имен `unip-system-deployment` должен быть запущен Pod с тремя контейнерами. +В логах контейнеров не должно быть ошибок. + + diff --git a/deploy/crd/api-component.yaml b/deploy/crd/api-component.yaml new file mode 100644 index 0000000..debc0c0 --- /dev/null +++ b/deploy/crd/api-component.yaml @@ -0,0 +1,328 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + # имя, должно соответствовать спецификации ниже, и быть в формате . + name: apicomponents.unified-platform.cs.hse.ru +spec: + # имя группы, используемое в REST API: /apis// + group: unified-platform.cs.hse.ru + # Список версий, поддерживаемых этим определением CustomResourceDefinition + versions: + - name: v1 + # Каждая версия может быть влкючена или выключена при помощи served флага. + served: true + # Только одна версия может быть отмечена как storage версия. + storage: true + schema: + openAPIV3Schema: + type: object + description: APIComponent является определением ресурса APIComponent. + APIComponent - компонент, предоставляющий интерфейс для внешнего доступа к приложению. + properties: + spec: + type: object + description: APIComponent определяет желаемое состояние API компонента. + Содержит спецификацию внешних интерфейсов. + properties: + published: + type: boolean + default: true + description: Published определяет, открыт или закрыт доступ + к интерфейсу APIComponent. + mlComponent: + type: object + description: MLComponent определяет параметры интерфейса к сервису + MLComponent. + properties: + name: + type: string + description: Имя ресурса MLComponent. + required: ["name"] + experimentPipeline: + type: object + description: ExperimentPipeline определяет параметры интерфейса к сервису пайплайна. + properties: + name: + type: string + description: Имя ресурса ExperimentPipeline. + required: ["name"] + files: + type: object + description: Files определяет параметры интерфейса к сервису Files. + properties: + enabled: + type: boolean + default: false + description: Enabled определяет, открыт или закрыт доступ к интерфейсу Files. + required: ["enabled"] + pipelines: + type: object + description: Pipelines определяет параметры интерфейса к сервису Pipelines. + properties: + enabled: + type: boolean + default: false + description: Enabled определяет, открыт или закрыт доступ к интерфейсу Pipelines. + required: ["enabled"] + restfulApi: + type: object + description: RESTfulAPI определяет параметры REST API к предоставляемым сервисам. + properties: + path: + type: string + description: Путь, определяющий часть адреса предоставляемого интерфейса. + auth: + type: object + description: Auth определяет параметры аутентификции. + properties: + basic: + type: object + description: Basic определяет параметры базовой аутентификации. + properties: + enabled: + type: boolean + description: Определяет, включена ли базовая аутентификация. + Считается, что если атрибут не задан, то базовая аутентификация включена. + credentials: + type: string + description: Имя секрета с реквизитами базовой аутентификации + в формате файла htpasswd. + oidc: + type: object + description: OIDC определяет параметры OIDC аутентификации. + properties: + enabled: + type: boolean + description: Определяет, включена ли OIDC аутентификация. + Считается, что если атрибут не задан, то OIDC аутентификация включена. + groups: + type: array + description: Определяет разрешенные группы. + items: + maxItems: 32 + type: string + maxLength: 255 + roles: + type: array + description: Определяет разрешенные роли. + items: + maxItems: 32 + type: string + maxLength: 255 + identityPassThrough: + type: boolean + default: true + description: Определяет, передавать ли идентичность аутентифицированного пользователя + в нижестоящий сервис. + required: ["identityPassThrough"] + anyOf: + - properties: + basic: {} + required: ["basic"] + - properties: + oidc: {} + required: ["oidc"] + cors: + type: object + properties: + enabled: + type: boolean + description: Определяет, применяются ли настройки, заданные в спецификации ресурса. + allowMethods: + type: array + description: Определяет настройку CORS Allow Methods. + items: + maxItems: 32 + type: string + maxLength: 255 + allowHeaders: + type: array + description: Определяет настройку CORS Allow Headers. + items: + maxItems: 32 + type: string + maxLength: 255 + exposeHeaders: + type: array + description: Определяет настройку CORS Expose Headers. + items: + maxItems: 32 + type: string + maxLength: 255 + allowOrigin: + type: array + description: Определяет настройку CORS Allow Origin. + items: + maxItems: 32 + type: string + maxLength: 255 + maxAge: + type: integer + required: ["auth"] + apiSpec: + type: object + description: Спецификация API для компонента, к которому APIComponent предоставляет интерфейс. + properties: + inputs: + type: array + description: Список входных переменных. + items: + maxItems: 32 + type: object + description: Определение входной переменной. + properties: + name: + type: string + description: Имя входной переменной. + description: + type: string + maxLength: 1000 + description: Описание входной переменной. + type: + type: object + description: Определение типа входной переменной. + Тип определяется только для входных переменных, значения которых + передаются через API. + properties: + datatypes: + type: array + description: Список допустимых типов значений входной переменной. + Тип значения используется при передаче значений входных переменных + через API. + Включает файловые типы 'FILE', 'WEBSITE' + и объектные типы, такие как 'FP32', 'str', 'dict'. + + В качестве значения файлового типа могут быть переданы локации файла или + файловой группы. + + Если передано значение объектного типа, то оно может быть сохранено в файл, + (поведение зависит от типа компонента, который реализует интерфейс). + + Тип содержимого файла (contentType) предопределен для типа 'WEBSITE' и всех + объектных типов значения входной переменной. + + Тип значения 'FILE' является допустимым, даже если он не задан в спецификации API. + + Если атрибут datatypes не определен в спецификации API, + то допустимыми являются все типы datatypes. + items: + type: string + maxItems: 16 + contentTypes: + type: array + description: Список допустимых типов содержимого файла (или файлов), + в котором содержится значение входной переменной. + Типами содержимого могут быть любые MIME типы. + + Тип содержимого используется при передаче значений входных переменных + через API. + + Если при запуске передано значение объектного типа, + то оно может быть сохранено в файл, + (поведение зависит от типа компонента, который реализует интерфейс). + + Тип содержимого файла (contentType) предопределен для типа 'WEBSITE' и всех + объектных типов значения входной переменной, поэтому может не передаваться при вызове. + + Если при вызове передано значение файлового типа (datatype == 'FILE'), + то тип содержимого файла может или должен быть передан, + (поведение зависит от типа компонента, который реализует интерфейс). + + Если атрибут contentTypes не определен в спецификации API, + то допустимыми являются любые типы содержимого. + items: + type: string + maxItems: 32 + required: + type: boolean + default: true + description: Является ли входная переменная обязательной. + required: [ "name" ] + outputs: + type: array + description: Список выходных переменных. + items: + maxItems: 32 + type: object + description: Определение выходной переменной. + properties: + name: + type: string + description: Имя выходной переменной. + description: + type: string + maxLength: 1000 + description: Описание выходной переменной. + type: + type: object + description: Определение типа выходной переменной. + properties: + datatypes: + type: array + description: Список допустимых типов значений выходной переменной. + Тип значения используется для указания через API ожидаемого типа + значений выходной переменной. + + Включает файловые типы 'FILE', 'WEBSITE'. + + Тип значения 'FILE' является допустимым, даже если он не задан в спецификации API. + + Если атрибут datatypes не определен в спецификации API, + то допустимыми являются все выходные типы datatypes. + items: + type: string + maxItems: 16 + contentTypes: + type: array + description: Список допустимых типов содержимого файлов, + в которых содержится значение выходной переменной. + Типами содержимого могут быть любые MIME типы. + + Тип содержимого используется для указания через API ожидаемого типа содержимого + выходной переменной. + + Если атрибут contentTypes не определен в спецификации API, + то допустимыми являются любые типы содержимого. + items: + type: string + maxItems: 32 + required: ["name"] + allOf: + - oneOf: + - properties: + mlComponent: {} + required: ["mlComponent"] + - properties: + files: {} + required: ["files"] + - properties: + pipelines: {} + required: ["pipelines"] + - properties: + experimentPipeline: {} + required: ["experimentPipeline"] + - oneOf: + - properties: + restfulApi: {} + required: ["restfulApi"] + required: ["published"] + status: + x-kubernetes-preserve-unknown-fields: true + type: object + subresources: + status: {} + # Namespaced or Cluster + scope: Namespaced + names: + # имя во множественном числе, используемое в URL: /apis/// + plural: apicomponents + # имя в единственном числе, используемое в CLI и для отображения + singular: apicomponent + # вид, обычно CamelCased в единственном числе, указывается в манифестах ресурсов + kind: APIComponent + # короткие имена для использования в операциях с ресурсами в CLI + shortNames: + - apicmp + - apicmps + categories: + - all \ No newline at end of file diff --git a/deploy/crd/component-link.yaml b/deploy/crd/component-link.yaml new file mode 100644 index 0000000..75c4b49 --- /dev/null +++ b/deploy/crd/component-link.yaml @@ -0,0 +1,195 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + # имя, должно соответствовать спецификации ниже, и быть в формате . + name: componentlinks.unified-platform.cs.hse.ru +spec: + # имя группы, используемое в REST API: /apis// + group: unified-platform.cs.hse.ru + # Список версий, поддерживаемых этим определением CustomResourceDefinition + versions: + - name: v1 + # Каждая версия может быть влкючена или выключена при помощи served флага. + served: true + # Только одна версия может быть отмечена как storage версия. + storage: true + schema: + openAPIV3Schema: + description: ComponentLink является определением ресурса ComponentLink. + ComponentLink - ссылка для доступа между компонентами. + type: object + properties: + spec: + type: object + description: ComponentLinkSpec определяет желаемое состояние ящика. + Содержит спецификацию ссылки, что включает определение концов ссылки, + реквизитов и параметров доступа. + properties: + platformAppName: + type: string + description: Имя приложения, к которому применяется ссылка. + handle: + type: object + description: Handle определяет часть ссылки обработчика. + properties: {} + targets: + type: array + description: Targets определяют часть ссылки цель. + items: + type: object + properties: + name: + type: string + description: Ресурс, на который указывает ссылка. + platformAppName: + type: string + description: Имя приложения цели. Если не задано, + используется имя приложения из атрибута spec.platformAppName. + kind: + type: string + description: Вид ресурса, на который указывает ссылка. + Если не задано, то считается, что ссылка указывает на APIComponent. + required: ["name"] + config: + type: object + description: Config определяет вид ссылки конфигурация. + properties: {} + secretRef: + type: object + description: Secret, ассоциированный со ссылкой. + properties: + name: + type: string + description: Имя Secret. + configMapRef: + type: object + properties: + name: + type: string + description: Имя конфигурации ConfigMap с настройками. + required: ["name"] + keycloakGroup: + type: object + description: Keycloak группа. + properties: + userRegistryRef: + type: object + description: Ссылка на объект вида Repository типа реестр пользователей. + properties: + name: + type: string + description: Имя реестра пользователей. + required: ["name"] + x-kubernetes-validations: + - rule: "oldSelf.name == self.name" + message: "userRegistryRef.name should not change" + x-kubernetes-validations: + - rule: "(has(oldSelf.userRegistryRef) && has(self.userRegistryRef)) || + (!has(oldSelf.userRegistryRef) && !has(self.userRegistryRef))" + message: "userRegistryRef should not change" + basicAuth: + type: object + description: Basic аутентификация. + properties: {} + allOf: + - properties: + platformAppName: {} + required: ["platformAppName"] + - oneOf: + - properties: + handle: {} + required: ["handle"] + - anyOf: + - properties: + targets: {} + required: ["targets"] + - properties: + targets: {} + keycloakGroup: {} + required: ["targets", "keycloakGroup"] + - properties: + targets: {} + basicAuth: {} + required: ["targets", "basicAuth"] + - allOf: + - properties: + config: {} + required: ["config"] + - anyOf: + - properties: + secretRef: {} + required: ["secretRef"] + - properties: + configMapRef: {} + required: ["configMapRef"] + x-kubernetes-validations: + - rule: "(has(oldSelf.config) && has(self.config)) || + (!has(oldSelf.config) && !has(self.config))" + message: "ComponentLink type (config) should not change" + - rule: "(has(oldSelf.keycloakGroup) && has(self.keycloakGroup)) || + (!has(oldSelf.keycloakGroup) && !has(self.keycloakGroup))" + message: "ComponentLink type (keycloakGroup) should not change" + - rule: "(has(oldSelf.basicAuth) && has(self.basicAuth)) || + (!has(oldSelf.basicAuth) && !has(self.basicAuth))" + message: "ComponentLink type (basicAuth) should not change" + status: + x-kubernetes-preserve-unknown-fields: true + type: object + description: ComponentLinkStatus хранит фактическое состояние ссылки. + properties: + keycloakGroup: + type: object + description: Статус для ComponentLink типа KeycloakGroup. + properties: + groupIds: + type: object + description: Идентификаторы группы Keycloak в различных реалмах. + additionalProperties: + type: string + conditions: + type: array + default: [] + description: Список наблюдаемых в настоящий момент условий. + items: + maxItems: 32 + type: object + properties: + type: + type: string + description: Тип условия. + conditionStatus: + type: string + description: Статус условия "True", "False" или "Unknown". + observedGeneration: + type: integer + description: Содержит .metadata.generation, при котором условие + было установлено. + lastTransitionTime: + type: string + description: Время последнего изменения статуса условия + в формате ISO. + reason: + type: string + description: Содержит программный идентификатор, являющийся + индикатором причины последнего изменения статуса условия. + message: + type: string + description: Подробное описание условия, понятное человеку. + required: ["type", "conditionStatus", "lastTransitionTime", "reason", "message"] + subresources: + status: {} + # Namespaced или Cluster + scope: Namespaced + names: + # имя во множественном числе, используемое в URL: /apis/// + plural: componentlinks + # имя в единственном числе, используемое в CLI и для отображения + singular: componentlink + # вид, обычно CamelCased в единственном числе, указывается в манифестах ресурсов + kind: ComponentLink + # короткие имена для использования в операциях с ресурсами в CLI + shortNames: + - cmplnk + - cmplnks + categories: + - all \ No newline at end of file diff --git a/deploy/crd/data-box.yaml b/deploy/crd/data-box.yaml new file mode 100644 index 0000000..2c2b993 --- /dev/null +++ b/deploy/crd/data-box.yaml @@ -0,0 +1,180 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + # имя, должно соответствовать спецификации ниже, и быть в формате . + name: databoxes.unified-platform.cs.hse.ru +spec: + # имя группы, используемое в REST API: /apis// + group: unified-platform.cs.hse.ru + # Список версий, поддерживаемых этим определением CustomResourceDefinition + versions: + - name: v1 + # Каждая версия может быть влкючена или выключена при помощи served флага. + served: true + # Только одна версия может быть отмечена как storage версия. + storage: true + schema: + openAPIV3Schema: + description: DataBox является определением ресурса DataBox. + DataBox - ящик для хранения данных. + type: object + properties: + spec: + type: object + description: DataBoxSpec определяет желаемое состояние ящика. + Содержит спецификацию ящика, что включает определение нижестоящей + системы хранения. + properties: + s3Storage: + type: object + description: S3Storage определяет параметры S3 ящика. + В S3 ящике данные хранятся по заданному пути внутри S3 бакета. + properties: + host: + type: string + description: Хост S3 хранилища. + bucket: + type: object + description: Параметры используемого S3 бакета. + properties: + name: + type: string + description: Имя S3 бакета. + subPath: + type: string + description: Путь внутри S3 бакета, с которым ассоциирован ящик. + Данные ящика сохранятся в бакет относительно указанного subPath. + required: ["name"] + capacity: + type: string + description: Размер ящика в формате + <численное значение><единица измерения>. + Поддерживаются все единицы измерения объема памяти Kubernetes. + default: 1G + awsVarsS3Credentials: + type: string + description: Имя секрета с реквизитами для доступа к S3 бакету + в формате AWS_S3_VARS. + required: ["host", "bucket"] + oneOf: + - properties: + awsVarsS3Credentials: {} + required: ["awsVarsS3Credentials"] + s3DefaultStorage: + type: object + description: S3DefaultStorage определяет параметры S3 ящика по умолчанию. + В S3 ящике по умолчанию данные хранятся в специальном S3 бакете, + указание параметров которого не требуется. + properties: + capacity: + type: string + description: Размер ящика в формате + <численное значение><единица измерения>. + Поддерживаются все единицы измерения объема памяти Kubernetes. + default: 1G + datasetReference: + type: object + description: DatasetReference определяет параметры ящика-ссылки на датасет. + properties: + datasetComponentRef: + type: object + description: Ссылка на объект вида DatasetComponent + properties: + name: + type: string + description: Имя DatasetComponent. + namespace: + type: string + description: Пространство имен DatasetComponent. + credentials: + type: object + description: Реквизиты доступа к датасету. + properties: + secretRef: + type: object + description: Ссылка на Secret с реквизитами. + properties: + name: + type: string + description: Имя Secret. + required: ["name"] + required: ["secretRef"] + required: ["datasetComponentRef"] + oneOf: + - properties: + s3Storage: {} + required: ["s3Storage"] + - properties: + s3DefaultStorage: {} + required: ["s3DefaultStorage"] + - properties: + datasetReference: {} + required: ["datasetReference"] + status: + x-kubernetes-preserve-unknown-fields: true + type: object + description: DataBoxStatus хранит фактическое состояние ящика. + properties: + conditions: + type: array + default: [] + description: Список наблюдаемых в настоящий момент условий. + items: + maxItems: 32 + type: object + properties: + type: + type: string + description: Тип условия. + conditionStatus: + type: string + description: Статус условия "True", "False" или "Unknown". + observedGeneration: + type: integer + description: Содержит .metadata.generation, при котором условие + было установлено. + lastTransitionTime: + type: string + description: Время последнего изменения статуса условия + в формате ISO. + reason: + type: string + description: Содержит программный идентификатор, являющийся + индикатором причины последнего изменения статуса условия. + message: + type: string + description: Подробное описание условия, понятное человеку. + required: ["type", "conditionStatus", "lastTransitionTime", "reason", "message"] + s3Storage: + type: object + description: S3Storage хранит фактическое состояние S3 ящика. + properties: + csiS3PersistentVolumeClaimUID: + type: string + description: UID ассоциированного с S3 ящиком PVC. + csiS3PersistentVolumeClaimName: + type: string + description: Имя ассоциированного с S3 ящиком PVC. + csiS3PersistentVolumeUID: + type: string + description: UID ассоциированного с S3 ящиком PV. + csiS3PersistentVolumeName: + type: string + description: Имя ассоциированного с S3 ящиком PV. + subresources: + status: {} + # Namespaced или Cluster + scope: Namespaced + names: + # имя во множественном числе, используемое в URL: /apis/// + plural: databoxes + # имя в единственном числе, используемое в CLI и для отображения + singular: databox + # вид, обычно CamelCased в единственном числе, указывается в манифестах ресурсов + kind: DataBox + # короткие имена для использования в операциях с ресурсами в CLI + shortNames: + - dtbx + - dtbxs + categories: + - all \ No newline at end of file diff --git a/deploy/crd/dataset-component.yaml b/deploy/crd/dataset-component.yaml new file mode 100644 index 0000000..4c8dcc1 --- /dev/null +++ b/deploy/crd/dataset-component.yaml @@ -0,0 +1,139 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: datasetcomponents.unified-platform.cs.hse.ru +spec: + scope: Namespaced + group: unified-platform.cs.hse.ru + names: + kind: DatasetComponent + plural: datasetcomponents + singular: datasetcomponent + shortNames: + - datacmps + - datacmp + - datasetcmps + - datasetcmp + versions: + - name: v1 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + properties: + spec: + description: Определяет желаемое состояние датасета. Содержит спецификацию датасета, что включает ящик и версии. + type: object + properties: + box: + description: Название ящика + type: string + pattern: ^[a-zA-Z0-9_-]{1,50}$ + restfulApi: + type: object + description: Определяет параметры REST API к предоставляемым данным. + required: ["auth"] + properties: + auth: + type: object + description: Auth определяет параметры аутентификции. + properties: + basic: + type: object + description: Basic определяет параметры базовой аутентификации. + properties: + enabled: + type: boolean + description: Определяет, включена ли базовая аутентификация. + Считается, что если атрибут не задан, то базовая аутентификация включена. + credentials: + type: string + description: Имя секрета с реквизитами базовой аутентификации в формате файла htpasswd. + oidc: + type: object + description: OIDC определяет параметры OIDC аутентификации. + properties: + enabled: + type: boolean + description: Определяет, включена ли OIDC аутентификация. + Считается, что если атрибут не задан, то OIDC аутентификация включена. + groups: + type: array + description: Определяет разрешенные группы. + items: + maxItems: 32 + type: string + maxLength: 255 + roles: + type: array + description: Определяет разрешенные роли. + items: + maxItems: 32 + type: string + maxLength: 255 + anyOf: + - properties: + basic: {} + required: ["basic"] + - properties: + oidc: {} + required: ["oidc"] + filesApiSecret: + description: Секреты доступа к Files API с правами на чтение + type: string + pattern: ^[a-zA-Z0-9-]{1,60}$ + default: basic-auth-credentials-not-hashed + versions: + type: array + items: + description: Определяет желаемое состояние версии. Содержит спецификацию версии, что включает название и путь к данным. + type: object + properties: + name: + description: Название версии датасета. + type: string + pattern: ^[a-zA-Z0-9_-]{1,50}$ + contents: + description: Информация о данных версии внутри ящика + type: object + properties: + readme: + description: Информация о текстовых метаданных для пользователя (в формате Markdown). + type: object + properties: + path: + description: Путь в ящике. + type: string + default: README.md + sha256: + description: Хэш сумма SHA-256. + type: string + pattern: ^[a-fA-F0-9]{64}$ + metadata: + description: Информация о файле с метaданными (в формате JSON). + type: object + properties: + path: + description: Путь в ящике. + type: string + default: metadata.json + sha256: + description: Хэш сумма SHA-256. + type: string + pattern: ^[a-fA-F0-9]{64}$ + files: + description: Информация о файле с перечнем файлов данных (в формате JSON). + type: object + properties: + path: + description: Путь в ящике. + type: string + default: files.json + sha256: + description: Хэш сумма SHA-256. + type: string + pattern: ^[a-fA-F0-9]{64}$ + status: + type: object + x-kubernetes-preserve-unknown-fields: true \ No newline at end of file diff --git a/deploy/crd/experiment-pipeline.yaml b/deploy/crd/experiment-pipeline.yaml new file mode 100644 index 0000000..5c641cf --- /dev/null +++ b/deploy/crd/experiment-pipeline.yaml @@ -0,0 +1,392 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + # имя, должно соответствовать спецификации ниже, и быть в формате . + name: experimentpipelines.unified-platform.cs.hse.ru +spec: + # имя группы, используемое в REST API: /apis// + group: unified-platform.cs.hse.ru + # Список версий, поддерживаемых этим определением CustomResourceDefinition + versions: + - name: v1 + # Каждая версия может быть влкючена или выключена при помощи served флага. + served: true + # Только одна версия может быть отмечена как storage версия. + storage: true + schema: + openAPIV3Schema: + type: object + description: ExperimentPipeline является определением ресурса ExperimentPipeline. + ExperimentPipeline - пайплайн, этапы которого выполняются как контейнеры. + properties: + spec: + type: object + description: ExperimentPipelineSpec определяет пайплайн. + Содержит спецификацию этапов с входными и выходными переменными, подсоединенных ящиков. + properties: + vars: + type: array + description: Список всех переменных пайплайна. + items: + maxItems: 32 + type: object + description: Определение переменной. + properties: + name: + type: string + description: имя переменной + path: + type: string + maxLength: 255 + description: Путь внутри контейнера, куда монтируется значение + переменной как файл или директория с файлами. + + Может быть не задано, тогда используется путь, + заданный в конфигурации присоединенного ящика по умолчанию. + mountFrom: + type: object + description: Определение конфигурации монтирования файлов входной переменной. + Если не задано, то используется конфигурация присоединенного ящика по умолчанию. + properties: + box: + type: object + description: Настройки монтирования файлов входной переменной с помощью + присоединенных ящиков. + properties: + name: + type: string + description: Имя присоединенного ящика. + boxPath: + type: string + description: Путь внутри присоединенного ящика. + Если атрибут задан, то переменная ассоциирована с данными в ящике, + ее значение нельзя задать при запуске пайплайна. + required: [ "name" ] + required: [ "name" ] + stages: + type: array + description: Список этапов пайплайна. + items: + maxItems: 32 + type: object + description: Определение этапа пайплайна. + properties: + name: + type: string + description: Имя этапа пайплайна. + image: + type: object + description: Определяет используемый образ для этапа. + properties: + existingImageName: + description: Имя существующего образа. + type: string + oneOf: + - properties: + existingImageName: {} + required: ["existingImageName"] # may be newImage + inputs: + type: array + description: Список входных переменных этапа. + items: + maxItems: 32 + type: object + description: Определение входной переменной этапа. + properties: + name: + type: string + description: Имя входной переменной. + path: + type: string + maxLength: 255 + description: Префикс пути внутри контейнера, куда монтируется значение + входной переменной как файл или директория с файлами. + + Может быть не задано, тогда используется путь, + заданный в конфигурации присоединенного ящика по умолчанию. + mountFrom: + type: object + description: Определение конфигурации монтирования файлов входной переменной. + Если не задано, то используется конфигурация присоединенного ящика по умолчанию. + properties: + box: + type: object + description: Настройки монтирования файлов входной переменной с помощью + присоединенных ящиков. + properties: + name: + type: string + description: Имя присоединенного ящика. + boxPath: + type: string + description: Путь внутри присоединенного ящика. + Если атрибут задан, то переменная ассоциирована с данными в ящике, + ее значение нельзя задать при запуске пайплайна. + required: ["name"] + required: ["name"] + outputs: + type: array + description: Список выходных переменных этапа. + items: + maxItems: 32 + type: object + description: Определение выходной переменной этапа. + properties: + name: + type: string + description: Имя выходной переменной. + path: + type: string + maxLength: 255 + description: Префикс пути внутри контейнера, куда монтируется значение + выходной переменной как директория с файлами. + + Может быть не задано, тогда используется путь, + заданный в конфигурации присоединенного ящика по умолчанию. + mountFrom: + type: object + description: Определение конфигурации монтирования файлов выходной переменной. + Если не задано, то используется конфигурация присоединенного ящика по умолчанию. + properties: + box: + type: object + description: Настройки монтирования файлов выходной переменной с помощью + присоединенных ящиков. + properties: + name: + type: string + description: Имя присоединенного ящика. + required: ["name"] + required: ["name"] + entryPoint: + type: object + description: Определяет параметры точки входа для старта этапа. + properties: + cmd: + type: array + description: Команда запуска этапа. + items: + maxItems: 32 + type: string + required: ["cmd"] + envFrom: + type: array + description: Определяет список ссылок на Secret и ConfigMap, + из которых добавляются переменные окружения. + items: + maxItems: 32 + type: object + properties: + configMapRef: + type: object + properties: + name: + type: string + required: ["name"] + secretRef: + type: object + properties: + name: + type: string + required: ["name"] + oneOf: + - properties: + configMapRef: {} + required: ["configMapRef"] + - properties: + secretRef: {} + required: ["secretRef"] + configFrom: + type: array + description: Определяет список подключаемых как файлов Secret и ConfigMap + items: + maxItems: 32 + type: object + properties: + path: + type: string + configMap: + type: object + properties: + name: + type: string + items: + type: array + items: + maxItems: 32 + type: object + properties: + key: + type: string + path: + type: string + required: ["key", "path"] + required: ["name"] + secret: + type: object + properties: + name: + type: string + items: + type: array + items: + maxItems: 32 + type: object + properties: + key: + type: string + path: + type: string + required: ["key", "path"] + required: ["name"] + oneOf: + - properties: + path: {} + configMap: {} + required: ["path", "configMap"] + - properties: + path: {} + secret: {} + required: ["path", "secret"] + env: + type: array + description: Определяет список переменных окружения. + items: + maxItems: 32 + type: object + properties: + name: + type: string + value: + type: string + required: ["name", "value"] + resourceLimits: + type: object + description: Определяет ограничения по CPU и оперативной памяти для этапа пайплайна. + properties: + cpu: + type: string + description: Ограничение по использованию CPU в формате + <числовое значение><единица измерения>. + Поддерживаются все единицы измерения ресурсов Kubernetes. + memory: + type: string + description: Ограничение по использованию оперативной памяти в формате + <числовое значение><единица измерения>. + Поддерживаются все единицы измерения ресурсов Kubernetes. + gpu: + type: string + description: Ограничение по использованию ресурсов графических ускорителей. + Поддерживается формат <числовое значение> для задания числа используемых + графических ускорителей узла. + required: ["image", "inputs", "outputs"] + connectedBoxes: + type: array + description: Определяет присоединенные ящики данных - ресурсы вида DataBox. + items: + maxItems: 32 + type: object + properties: + name: + type: string + maxLength: 255 + description: Имя присоединенного ящика. + path: + type: string + maxLength: 255 + description: Путь внутри контейнера. Смысл зависит от типа присоединения ящика. + Для MountS3Box - директория, используемая для монтирования S3 ящика. + default: + type: boolean + default: false + mountS3Box: + type: object + description: Определение присоединения S3 ящика типа "монтирование". + properties: + s3BoxName: + type: string + description: Имя ящика. + required: ["s3BoxName"] + mountDataset: + type: object + description: Определение присоединения ящика датасета типа "монтирование". + properties: + datasetReferenceName: + type: string + description: Имя ящика-ссылки на датасет. + required: ["datasetReferenceName"] + required: ["name"] + oneOf: + - properties: + mountS3Box: {} + required: ["mountS3Box"] + - properties: + mountDataset: {} + required: ["mountDataset"] + continueWith: + type: object + description: Определяет пайплайн, который должен быть запущен после выполнения текущего + папйлайна. + properties: + name: + type: string + description: Имя пайплайна. + maxLength: 255 + required: ["name"] +# oneOf: +# - properties: +# simplePipeline: {} +# required: ["simplePipeline"] +# - properties: +# mldevPipeline: {} +# required: ["mldevPipeline"] + required: ["stages", "connectedBoxes"] + status: + x-kubernetes-preserve-unknown-fields: true + type: object + properties: + conditions: + type: array + items: + maxItems: 32 + type: object + properties: + type: + type: string + conditionStatus: + type: string + observedGeneration: + type: integer + lastTransitionTime: + type: string + reason: + type: string + message: + type: string + required: [ "type", "conditionStatus", "lastTransitionTime", "reason", "message"] + validation: + type: object + properties: + validationPodName: + type: string + nullable: true + default: {} + subresources: + status: {} + # Namespaced or Cluster + scope: Namespaced + names: + # имя во множественном числе, используемое в URL: /apis/// + plural: experimentpipelines + # имя в единственном числе, используемое в CLI и для отображения + singular: experimentpipeline + # вид, обычно CamelCased в единственном числе, указывается в манифестах ресурсов + kind: ExperimentPipeline + # короткие имена для использования в операциях с ресурсами в CLI + shortNames: + - exppipeline + - exppipelines + - exppln + - expplns + categories: + - all \ No newline at end of file diff --git a/deploy/crd/ml-component.yaml b/deploy/crd/ml-component.yaml new file mode 100644 index 0000000..f8af15b --- /dev/null +++ b/deploy/crd/ml-component.yaml @@ -0,0 +1,270 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + # имя, должно соответствовать спецификации ниже, и быть в формате . + name: mlcomponents.unified-platform.cs.hse.ru +spec: + # имя группы, используемое в REST API: /apis// + group: unified-platform.cs.hse.ru + # Список версий, поддерживаемых этим определением CustomResourceDefinition + versions: + - name: v1 + # Каждая версия может быть влкючена или выключена при помощи served флага. + served: true + # Только одна версия может быть отмечена как storage версия. + storage: true + schema: + openAPIV3Schema: + type: object + description: MLComponent является определением ресурса MLComponent. + MLComponent - сервис с функцией инференса, который выполняется + внутри контейнера. + properties: + spec: + type: object + description: MLComponentSpec определяет желаемое состояние сервиса. + Содержит спецификацию подсоединенных ящиков, образа сервиса, используемой модели. + properties: + image: + type: object + description: Определяет используемый образ для сервиса. + properties: + existingImageName: + description: Имя существующего образа. + type: string + oneOf: + - properties: + existingImageName: {} + required: ["existingImageName"] # may be newImage + servicePort: + type: integer + minimum: 1 + maximum: 65535 + default: 8002 + description: Определяет порт сервиса внутри контейнера. + envFrom: + type: array + description: Определяет список ссылок на Secret и ConfigMap, + из которых добавляются переменные окружения. + items: + maxItems: 32 + type: object + properties: + configMapRef: + type: object + description: Ссылка на ConfigMap. + properties: + name: + type: string + description: Имя ConfigMap. + required: ["name"] + secretRef: + type: object + description: Ссылка на Secret. + properties: + name: + type: string + description: Имя Secret. + required: ["name"] + oneOf: + - properties: + configMapRef: {} + required: ["configMapRef"] + - properties: + secretRef: {} + required: ["secretRef"] + env: + type: array + description: Определяет список переменных окружения. + items: + maxItems: 32 + type: object + properties: + name: + type: string + description: Имя переменной окружения. + value: + type: string + description: Значение переменной окружения. + required: ["name", "value"] + resourceLimits: + type: object + description: Определяет ограничения по CPU и оперативной памяти для сервиса. + properties: + cpu: + type: string + description: Ограничение по использованию CPU в формате + <численное значение><единица измерения>. + Поддерживаются все единицы измерения ресурсов Kubernetes. + memory: + type: string + description: Ограничение по использованию оперативной памяти в формате + <численное значение><единица измерения>. + Поддерживаются все единицы измерения ресурсов Kubernetes. + gpu: + type: string + description: Ограничение по использованию ресурсов графических ускорителей. + Поддерживается формат <числовое значение> для задания числа используемых + графических ускорителей узла. + mlService: + type: object + description: Определяет параметры сервиса. + properties: + packageRegistryName: + type: string + description: Имя секрета с реквизитами доступа к реестру пакетов Python, + в котором содержится библиотека unip-mlcmp, используемая для запуска + сервиса. + packageVersionSpec: + type: string + description: Спецификация версии Python библиотеки unip-mlcmp, например ">=2, <3" + inference: + type: object + description: Определяет параметры инференса. + properties: + fileExchange: + type: object + description: Определяет параметры обмена файлами + для использования файлового API. + properties: + fileBox: + type: string + description: Имя присоединенного ящика из элемента списка connectedBoxes. + inferenceFilesPath: + type: string + description: Путь к директории внутри контейнера, которая будет использоваться + для хранения временных файлов. + required: ["fileBox", "inferenceFilesPath"] + model: + type: object + description: Определяет параметры используемой для инференса модели. + properties: + modelBox: + type: string + description: Имя присоединенного ящика из элемента списка connectedBoxes. + modelKind: + type: string + description: Вид модели, передается в контейнер в переменной окружения + INFERENCE_MODEL_KIND. + modelPath: + type: string + description: Путь к модели внутри контейнера. + required: ["modelBox", "modelPath"] + entryPoint: + type: object + description: Определяет параметры точки входа для выполнения инференса. + properties: + pythonPath: + type: string + description: Должен указывать на директорию с исходным кодом инференс функции + и исходным кодом всех необходимых для инференса зависимостей + (не включая зависимости, установленные как пакеты). + Добавляется к PYTHONPATH внутри контейнера. + pythonFunction: + type: string + description: Полное имя функции, которая выполняет инференс. + required: ["pythonFunction"] + required: ["fileExchange", "model", "entryPoint"] + license: + type: object + description: Определяет параметры используемого файла лицензии + properties: + licenseLocalPath: + type: string + description: Путь к файлу лицензии внутри контейнера. + Используется если другой способ получения лицензии не указан, + или по нему не получается получить лицензию. + licenseBox: + type: string + description: Имя присоединенного ящика из элемента списка connectedBoxes. + licensePath: + type: string + description: Путь к файлу лицензии внутри контейнера. + anyOf: + - properties: + required: ["licenseLocalPath"] + - properties: + required: ["licenseBox", "licensePath"] + api: + type: object + description: Определяет настройки API + properties: + prefix: + type: string + description: Префикс, который используется самим сервисом + при формировании путей к точкам доступа API сервиса. + Формируемые пути будут иметь вид /// + required: ["packageRegistryName", "inference"] + connectedBoxes: + type: array + description: Определяет присоединенные ящики данных - ресурсы вида DataBox. + items: + maxItems: 32 + type: object + properties: + name: + type: string + maxLength: 255 + description: Имя присоединенного ящика. + path: + type: string + maxLength: 255 + description: Путь внутри контейнера. Смысл зависит от типа присоединения ящика. + Для CopyS3Box - директория, используемая для хранения копируемых из и в S3 ящик + данных. + Для MountS3Box - директория, используемая для монтирования S3 ящика. + copyS3Box: + type: object + description: Определение присоединения S3 ящика типа "копирование". + properties: + subPath: + type: string + description: Путь внутри ящика. + s3BoxName: + type: string + description: Имя ящика. + required: ["s3BoxName"] + mountS3Box: + type: object + description: Определение присоединения S3 ящика типа "монтирование". + properties: + subPath: + type: string + description: Путь внутри ящика. + s3BoxName: + type: string + description: Имя ящика. + required: ["s3BoxName"] + required: ["name"] + oneOf: + - properties: + copyS3Box: {} + required: ["copyS3Box"] + - properties: + mountS3Box: {} + required: [ "mountS3Box" ] + oneOf: + - properties: + mlService: {} + required: ["mlService"] + required: ["image", "connectedBoxes"] + status: + x-kubernetes-preserve-unknown-fields: true + type: object + subresources: + status: {} + # Namespaced or Cluster + scope: Namespaced + names: + # имя во множественном числе, используемое в URL: /apis/// + plural: mlcomponents + # имя в единственном числе, используемое в CLI и для отображения + singular: mlcomponent + # вид, обычно CamelCased в единственном числе, указывается в манифестах ресурсов + kind: MLComponent + # короткие имена для использования в операциях с ресурсами в CLI + shortNames: + - mlcmp + - mlcmps + categories: + - all \ No newline at end of file diff --git a/deploy/crd/platform-app.yaml b/deploy/crd/platform-app.yaml new file mode 100644 index 0000000..cacdc03 --- /dev/null +++ b/deploy/crd/platform-app.yaml @@ -0,0 +1,195 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + # имя, должно соответствовать спецификации ниже, и быть в формате . + name: platformapps.unified-platform.cs.hse.ru +spec: + # имя группы, используемое в REST API: /apis// + group: unified-platform.cs.hse.ru + # Список версий, поддерживаемых этим определением CustomResourceDefinition + versions: + - name: v1 + # Каждая версия может быть влкючена или выключена при помощи served флага. + served: true + # Только одна версия может быть отмечена как storage версия. + storage: true + schema: + openAPIV3Schema: + type: object + description: PlatformApp является определением ресурса PlatformApp. + PlatformApp - приложение платформы. + properties: + spec: + type: object + description: PlatformAppSpec определяет желаемое состояние приложения. + Содержит спецификацию приложения, что включает определение репозитория со спецификацией приложения, + список используемых репозиториев и реквизитов приложения. + properties: + appSourceCode: + type: object + description: AppSourceCode определяет исходный код спецификации приложения. + properties: + sourceRepositoryRef: + type: object + description: Является ссылкой на репозиторий с исходным кодом. + properties: + name: + type: string + description: Имя репозитория. + sourceRepositoryKind: + type: string + description: | + Вид репозитория. Поддерживаемые виды: "git". + credentialsKind: + type: string + description: | + Вид реквизитов. Поддерживаемые виды: "HTTPBasedURLCredentials". + required: ["name", "sourceRepositoryKind", "credentialsKind"] + revision: + type: string + description: Используемая ревизия исходного кода. + repositoryPath: + type: string + default: app + description: Путь внутри репозитория к директории со спецификацией приложения. + required: ["repositoryPath", "sourceRepositoryRef"] + repositories: + type: array + description: Список репозиториев приложения. + items: + maxItems: 32 + type: object + properties: + name: + type: string + maxLength: 255 + description: Имя репозитория. + imageRegistryRef: + type: object + description: ImageRegistryRef определяет ссылку на реестр образов. + Реквизиты и конфигурация копируются в пространство имен приложения как Secret и ConfigMap + с суффиксами -cred и -cfg соответственно. + properties: + name: + type: string + description: Имя реестра. + imageKind: + type: string + description: | + Вид образов, который поддерживает реестр. Поддерживаемые виды: "docker". + credentialsKind: + type: string + description: | + Вид реквизитов. Поддерживаемые виды: "DockerConfigJsonCredentials". + required: ["name", "imageKind", "credentialsKind"] + packageRegistryRef: + type: object + description: PackageRegistryRef определяет ссылку на реестр пакетов. + Реквизиты и конфигурация копируются в пространство имен приложения как Secret и ConfigMap + с суффиксами -cred и -cfg соответственно. + properties: + name: + type: string + description: Имя реестра. + packageKind: + type: string + description: | + Вид пакетов, который поддерживает реестр. Поддерживаемые виды: "python". + credentialsKind: + type: string + description: | + Вид реквизитов. Поддерживаемые виды: "HTTPBasedURLCredentials". + required: ["name", "packageKind", "credentialsKind"] + sourceRepositoryRef: + type: object + description: SourceRepositoryRef определяет ссылку на репозиторий с исходным кодом. + Реквизиты и конфигурация копируются в пространство имен приложения как Secret и ConfigMap + с суффиксами -cred и -cfg соответственно. + properties: + name: + type: string + description: Имя репозитория. + sourceRepositoryKind: + type: string + description: | + Вид репозитория. Поддерживаемые виды: "git". + credentialsKind: + type: string + description: | + Вид реквизитов. Поддерживаемые виды: "HTTPBasedURLCredentials". + required: ["name", "sourceRepositoryKind", "credentialsKind"] + oneOf: + - properties: + imageRegistryRef: {} + required: ["imageRegistryRef"] + - properties: + packageRegistryRef: {} + required: ["packageRegistryRef"] + - properties: + sourceRepositoryRef: {} + required: ["sourceRepositoryRef"] + boxesCredentials: + type: array + description: Список S3 реквизитов приложения. + Реквизиты копируются в пространство имен приложения как Secret + с именем <имя реквизитов в этом списке>-cred. + items: + maxItems: 32 + type: object + properties: + name: + type: string + maxLength: 255 + description: Имя реквизитов. + secretRef: + type: object + description: Ссылка на Secret с реквизитами в формате AWS_S3_VARS. + properties: + name: + type: string + description: Имя Secret. + required: ["name"] + required: ["name", "secretRef"] + apisCredentials: + type: array + description: Список реквизитов приложения для доступа к интерфейсам APIComponent. + Реквизиты копируются в пространство имен приложения как Secret + с именем <имя реквизитов в этом списке>-cred. + items: + maxItems: 32 + type: object + properties: + name: + type: string + maxLength: 255 + description: Имя реквизитов. + secretRef: + type: object + description: Ссылка на Secret с реквизитами в формате htpasswd. + properties: + name: + type: string + description: Имя Secret. + required: ["name"] + required: ["name", "secretRef"] + required: ["appSourceCode"] + status: + x-kubernetes-preserve-unknown-fields: true + type: object + subresources: + status: {} + # Namespaced or Cluster + scope: Namespaced + names: + # имя во множественном числе, используемое в URL: /apis/// + plural: platformapps + # имя в единственном числе, используемое в CLI и для отображения + singular: platformapp + # вид, обычно CamelCased в единственном числе, указывается в манифестах ресурсов + kind: PlatformApp + # короткие имена для использования в операциях с ресурсами в CLI + shortNames: + - papp + - papps + categories: + - all \ No newline at end of file diff --git a/deploy/crd/platform-user.yaml b/deploy/crd/platform-user.yaml new file mode 100644 index 0000000..ee46b32 --- /dev/null +++ b/deploy/crd/platform-user.yaml @@ -0,0 +1,42 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + # имя, должно соответствовать спецификации ниже, и быть в формате . + name: platformusers.unified-platform.cs.hse.ru +spec: + # имя группы, используемое в REST API: /apis// + group: unified-platform.cs.hse.ru + # Список версий, поддерживаемых этим определением CustomResourceDefinition + versions: + - name: v1 + # Каждая версия может быть влкючена или выключена при помощи served флага. + served: true + # Только одна версия может быть отмечена как storage версия. + storage: true + schema: + openAPIV3Schema: + type: object + description: PlatformUser является определением ресурса PlatformUser. + PlatformUser - пользователь платформы. + properties: + status: + x-kubernetes-preserve-unknown-fields: true + type: object + properties: {} + subresources: + status: {} + # Namespaced or Cluster + scope: Namespaced + names: + # имя во множественном числе, используемое в URL: /apis/// + plural: platformusers + # имя в единственном числе, используемое в CLI и для отображения + singular: platformuser + # вид, обычно CamelCased в единственном числе, указывается в манифестах ресурсов + kind: PlatformUser + # короткие имена для использования в операциях с ресурсами в CLI + shortNames: + - puser + - pusers + categories: + - all \ No newline at end of file diff --git a/deploy/crd/repository.yaml b/deploy/crd/repository.yaml new file mode 100644 index 0000000..5e2fd02 --- /dev/null +++ b/deploy/crd/repository.yaml @@ -0,0 +1,148 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + # имя, должно соответствовать спецификации ниже, и быть в формате . + name: repositories.unified-platform.cs.hse.ru +spec: + # имя группы, используемое в REST API: /apis// + group: unified-platform.cs.hse.ru + # Список версий, поддерживаемых этим определением CustomResourceDefinition + versions: + - name: v1 + # Каждая версия может быть влкючена или выключена при помощи served флага. + served: true + # Только одна версия может быть отмечена как storage версия. + storage: true + schema: + openAPIV3Schema: + type: object + description: Repository является определением ресурса Repository. + Repository - репозиторий платформы. + properties: + spec: + type: object + description: RepositorySpec определяет желаемое состояние репозитория. + Содержит спецификацию репозитория одного из поддерживаемых типов. + properties: + imageRegistry: + type: object + description: ImageRegistry определяет параметры репозитория типа реестр образов. + properties: + host: + type: string + description: Хост репозитория. + dockerDockerConfigJsonCredentials: + type: string + description: Имя секрета с реквизитами доступа в формате DockerConfigJsonCredentials + к реестру образов Docker. + required: ["host"] + oneOf: + - properties: + dockerDockerConfigJsonCredentials: {} + required: ["dockerDockerConfigJsonCredentials"] + packageRegistry: + type: object + description: PackageRegistry определяет параметры репозитория типа реестр пакетов. + properties: + host: + type: string + description: Хост репозитория. + pythonHTTPBasedURLCredentials: + type: string + description: Имя секрета с реквизитами доступа в формате HTTPBasedURLCredentials + к реестру Python пакетов. + required: ["host"] + oneOf: + - properties: + pythonHTTPBasedURLCredentials: {} + required: ["pythonHTTPBasedURLCredentials"] + sourceRepository: + type: object + description: SourceRepository определяет параметры репозитория типа репозиторий + исходного кода. + properties: + host: + type: string + description: Хост репозитория. + gitHTTPBasedURLCredentials: + type: string + description: Имя секрета с реквизитами доступа в формате HTTPBasedURLCredentials + к Git репозиторию исходного кода. + required: ["host"] + oneOf: + - properties: + gitHTTPBasedURLCredentials: {} + required: ["gitHTTPBasedURLCredentials"] + userRegistry: + type: object + description: UserRegistry определяет параметры репозитория типа реестр пользователей. + properties: + host: + type: string + description: Хост реестра пользователей. + keycloak: + type: object + description: Реестр пользователей, реализуемый keycloak + properties: + robots: + type: object + description: Робот аккаунты реестра пользователей. + properties: + secretRef: + type: object + description: Secret с именами робот аккаунтов. + properties: + name: + type: string + description: Имя Secret + required: ["name"] + x-kubernetes-validations: + - rule: "(has(oldSelf.keycloak) && has(self.keycloak)) || + (!has(oldSelf.keycloak) && !has(self.keycloak))" + message: "repository type (userRegistry.keycloak) should not change" + oneOf: + - properties: + imageRegistry: {} + required: ["imageRegistry"] + - properties: + packageRegistry: {} + required: ["packageRegistry"] + - properties: + sourceRepository: {} + required: ["sourceRepository"] + - properties: + sourceRepository: {} + required: ["userRegistry"] + x-kubernetes-validations: + - rule: "(has(oldSelf.userRegistry) && has(self.userRegistry)) || + (!has(oldSelf.userRegistry) && !has(self.userRegistry))" + message: "repository type (userRegistry) should not change" + status: + x-kubernetes-preserve-unknown-fields: true + type: object + properties: + userRegistry: + type: object + properties: + keycloak: + type: object + properties: + masterGroupId: + type: string + subresources: + status: {} + # Namespaced or Cluster + scope: Namespaced + names: + # имя во множественном числе, используемое в URL: /apis/// + plural: repositories + # имя в единственном числе, используемое в CLI и для отображения + singular: repository + # вид, обычно CamelCased в единственном числе, указывается в манифестах ресурсов + kind: Repository + # короткие имена для использования в операциях с ресурсами в CLI + shortNames: + - uniprep + - unipreps + categories: + - all \ No newline at end of file diff --git a/deploy/databoxes/databoxes-cm.yaml b/deploy/databoxes/databoxes-cm.yaml new file mode 100644 index 0000000..21cd179 --- /dev/null +++ b/deploy/databoxes/databoxes-cm.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: unip-system-controller + name: databoxes-cm +data: + UNIP_BOXES_S3_DEFAULT_USER_DATA_BUCKET: unip-test + UNIP_BOXES_CSI_S3_SECRET_NAME: csi-s3-secret + UNIP_BOXES_CSI_S3_STORAGE_CLASS: unip-system-controller-csi-s3-sc + UNIP_BOXES_S3_DEFAULT_HOST: https://storage.yandexcloud.net diff --git a/deploy/datasets/datasets-cm.yaml b/deploy/datasets/datasets-cm.yaml new file mode 100644 index 0000000..2963934 --- /dev/null +++ b/deploy/datasets/datasets-cm.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: unip-system-controller + name: datasets-cm +data: + FILES_API_BASE_URL: https://platform-test.stratpro.hse.ru + INGRESS_RULE_HOST: platform-test.stratpro.hse.ru + INGRESS_BACKEND_SERVICE_NAME: files-svc + INGRESS_BACKEND_SERVICE_PORT: "80" + UNIP_DATASET_CMP_CHECK_CONTROLLER_PERMISSIONS: "False" + UNIP_DATASET_CMP_VALIDATE: "False" diff --git a/deploy/deployment.yaml b/deploy/deployment.yaml new file mode 100644 index 0000000..7490c1e --- /dev/null +++ b/deploy/deployment.yaml @@ -0,0 +1,75 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: unip-controller + namespace: unip-system-controller +spec: + replicas: 1 + strategy: + type: Recreate + selector: + matchLabels: + app: controller + template: + metadata: + labels: + app: controller + spec: + serviceAccountName: controller-sa + containers: + - name: controller + image: platform-reg.stratpro.hse.ru/unified-platform/unip-controller:0.3.7-9c53a08 + imagePullPolicy: Always + envFrom: + - secretRef: + name: argo-cd-credentials + optional: true + - secretRef: + name: pipelines-db-credentials + - secretRef: + name: oidc-credentials + - configMapRef: + name: controller-cm + - configMapRef: + name: databoxes-cm + - configMapRef: + name: argo-cd-cm + optional: true + - configMapRef: + name: oidc-cm + - configMapRef: + name: datasets-cm + - configMapRef: + name: cors-cm + optional: true + - name: pipelines + image: platform-reg.stratpro.hse.ru/unified-platform/unip-controller:0.3.7-9c53a08 + imagePullPolicy: Always + command: ["/bin/bash"] + args: + - -c + - hypercorn exp_pipeline.api:app -b 0.0.0.0:8001 + envFrom: + - secretRef: + name: pipelines-db-credentials + - configMapRef: + name: pipelines-cm + ports: + - containerPort: 8001 + - name: files + image: platform-reg.stratpro.hse.ru/unified-platform/unip-controller:0.3.7-9c53a08 + imagePullPolicy: Always + command: ["/bin/bash"] + args: + - -c + - hypercorn files.api:app -b 0.0.0.0:8000 + envFrom: + - configMapRef: + name: files-cm + ports: + - containerPort: 8000 + imagePullSecrets: + #- name: registry-credentials + - name: registry-credentials-stratpro + + diff --git a/deploy/files/files-cm.yaml b/deploy/files/files-cm.yaml new file mode 100644 index 0000000..dfd787f --- /dev/null +++ b/deploy/files/files-cm.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: unip-system-controller + name: files-cm +data: + UNIP_BOXES_S3_DEFAULT_USER_DATA_BUCKET: unip-test + UNIP_BOXES_S3_SECRET_NAME: aws-vars-s3-credentials + UNIP_BOXES_S3_DEFAULT_HOST: https://storage.yandexcloud.net + UNIP_BOXES_S3_DEFAULT_REGION: ru-central1 diff --git a/deploy/files/files-svc.yaml b/deploy/files/files-svc.yaml new file mode 100644 index 0000000..15bceea --- /dev/null +++ b/deploy/files/files-svc.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: files-svc + namespace: unip-system-controller + labels: + app: controller +spec: + type: ClusterIP + ports: + - protocol: TCP + port: 80 + targetPort: 8000 + selector: + app: controller diff --git a/deploy/kopf/peering.yaml b/deploy/kopf/peering.yaml new file mode 100644 index 0000000..aaac9ee --- /dev/null +++ b/deploy/kopf/peering.yaml @@ -0,0 +1,59 @@ +# https://raw.githubusercontent.com/nolar/kopf/main/peering.yaml +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: clusterkopfpeerings.kopf.dev +spec: + scope: Cluster + group: kopf.dev + names: + kind: ClusterKopfPeering + plural: clusterkopfpeerings + singular: clusterkopfpeering + versions: + - name: v1 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + properties: + status: + type: object + x-kubernetes-preserve-unknown-fields: true +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: kopfpeerings.kopf.dev +spec: + scope: Namespaced + group: kopf.dev + names: + kind: KopfPeering + plural: kopfpeerings + singular: kopfpeering + versions: + - name: v1 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + properties: + status: + type: object + x-kubernetes-preserve-unknown-fields: true +--- +apiVersion: kopf.dev/v1 +kind: ClusterKopfPeering +metadata: + name: default +--- +apiVersion: kopf.dev/v1 +kind: KopfPeering +metadata: + namespace: default + name: default +--- \ No newline at end of file diff --git a/deploy/ns.yaml b/deploy/ns.yaml new file mode 100644 index 0000000..96646fa --- /dev/null +++ b/deploy/ns.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: unip-system-controller \ No newline at end of file diff --git a/deploy/oidc/keycloak-robots-creds-ns.yaml b/deploy/oidc/keycloak-robots-creds-ns.yaml new file mode 100644 index 0000000..f42f704 --- /dev/null +++ b/deploy/oidc/keycloak-robots-creds-ns.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: unip-app-keycloak-robots-creds \ No newline at end of file diff --git a/deploy/oidc/oidc-cm.yaml b/deploy/oidc/oidc-cm.yaml new file mode 100644 index 0000000..bd3ad00 --- /dev/null +++ b/deploy/oidc/oidc-cm.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: unip-system-controller + name: oidc-cm +data: + OIDC_END_USERS_ISSUER_URL: https://sso.platform-test.stratpro.hse.ru/realms/end-users + OIDC_END_USERS_REALM: end-users + OIDC_END_USERS_AUD: end-users + OIDC_ROBOTS_ISSUER_URL: https://sso.platform-test.stratpro.hse.ru/realms/robots + OIDC_ROBOTS_REALM: robots + OIDC_ROBOTS_AUD: robots + OIDC_KEYCLOAK_HOST: https://sso.platform-test.stratpro.hse.ru + OIDC_MANAGED_GROUPS_ROOT: unip + OIDC_CLUSTER_GROUP_NAME: default + OIDC_MODIFY: "True" + UNIP_REPOSITORY_KEYCLOAK_ROBOTS_CREDS_NAMESPACE: "unip-app-keycloak-robots-creds" + UNIP_REPOSITORY_KEYCLOAK_ROBOTS_TOKENS_RENEWAL_PERIOD_MIN: "1440" diff --git a/deploy/oidc/oidc-credentials-secret.yaml.sample b/deploy/oidc/oidc-credentials-secret.yaml.sample new file mode 100644 index 0000000..7d966a1 --- /dev/null +++ b/deploy/oidc/oidc-credentials-secret.yaml.sample @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Secret +metadata: + name: oidc-credentials + namespace: unip-system-controller +type: Opaque +stringData: + OIDC_END_USERS_CLIENT_ID: end-users + OIDC_END_USERS_CLIENT_SECRET: canbeanything + OIDC_END_USERS_ADMIN_CLIENT_ID: end-users-admin + OIDC_END_USERS_ADMIN_CLIENT_SECRET: required + OIDC_END_USERS_COOKIE_SECRET: "00000000000000000000000000000000" + OIDC_ROBOTS_CLIENT_ID: robots + OIDC_ROBOTS_CLIENT_SECRET: canbeanything + OIDC_ROBOTS_ADMIN_CLIENT_ID: robots-admin + OIDC_ROBOTS_ADMIN_CLIENT_SECRET: required \ No newline at end of file diff --git a/deploy/pipelines/pipelines-cm.yaml b/deploy/pipelines/pipelines-cm.yaml new file mode 100644 index 0000000..6589bf9 --- /dev/null +++ b/deploy/pipelines/pipelines-cm.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: unip-system-controller + name: pipelines-cm +data: + UNIP_FILES_API: http://files-svc.unip-system-controller + UNIP_PIPELINES_API: https://platform-test.stratpro.hse.ru + UNIP_DOMAIN: platform-test.stratpro.hse.ru + UNIP_PIPELINE_VALIDATION_IMAGE: platform-reg.stratpro.hse.ru/unified-platform-resources/unip-pipeline-validate-results:latest \ No newline at end of file diff --git a/deploy/pipelines/pipelines-db-credentials-secret.yaml.sample b/deploy/pipelines/pipelines-db-credentials-secret.yaml.sample new file mode 100644 index 0000000..a329831 --- /dev/null +++ b/deploy/pipelines/pipelines-db-credentials-secret.yaml.sample @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Secret +metadata: + name: pipelines-db-credentials + namespace: unip-system-controller +type: Opaque +stringData: + UNIP_DATABASE_PIPELINES_USER: sample + UNIP_DATABASE_PIPELINES_PASSWORD: sample + UNIP_DATABASE_PIPELINES_HOST: sample + UNIP_DATABASE_PIPELINES_PORT: sample + UNIP_DATABASE_PIPELINES_DB: sample diff --git a/deploy/pipelines/pipelines-svc.yaml b/deploy/pipelines/pipelines-svc.yaml new file mode 100644 index 0000000..6755e47 --- /dev/null +++ b/deploy/pipelines/pipelines-svc.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: pipelines-svc + namespace: unip-system-controller + labels: + app: controller +spec: + type: ClusterIP + ports: + - protocol: TCP + port: 80 + targetPort: 8001 + selector: + app: controller diff --git a/deploy/prerequisites.md b/deploy/prerequisites.md new file mode 100644 index 0000000..cb189ec --- /dev/null +++ b/deploy/prerequisites.md @@ -0,0 +1,112 @@ +# Предусловия + +1. Настроенная платформа Kubernetes; +2. Доступны подключаемые системы; +3. Зарегистрированы и настроены на работу с платформой Kubernetes два доменных имени; +4. Доступны реестры образов или кэш образов с необходимыми для развертывания компонентов фреймворка образами; + +## Платформа Kubernetes + +Платформа Kubernetes включает в себя кластер аппаратных или виртуальных узлов +и развернутые на нем системные сервисы. + +Требования к ПО Kubernetes: +1. Версия не ниже 1.24; + +Требования к аппаратному обеспечению: +1. Мастер-узел: 1 узел, 2-core CPU, 4 Гб RAM, 50 Гб Storage; +2. Рабочие узлы: 2 узла, каждый узел 2-core CPU, 6 Гб RAM, 50 Гб Storage; + +Для сервиса managed Kubernetes мастер-узел может быть создан и управляться автоматически провайдером сервиса. + +Требования к системным сервисам платформы Kubernetes: +1. Драйвер S3 CSI от Yandex; +2. Сервис DNS CoreDNS; +3. Контроллер сетевых политик Cilium для обеспечения сетевой связности; +4. Балансировщик нагрузки, через который осуществляются внешние соединени; +с развернутыми на платформе сервисами фреймворка и приложениями; +5. Контроллер менеджер сертификатов cert-manager; +6. Контроллер Ingress Ingress-Nginx; + + +> Работоспособность драйвера S3 CSI от Yandex на установках Kubernetes вне Yandex Cloud не проверена. +> Существуют проблемы с работоспособностью при использовании microk8s. + +> При использовании managed кластера Kubernetes рекомендуется при настройке сразу выбрать Cilium +> в качестве контроллера сетевых политик. Последующее изменение может потребовать пересоздание кластера +> (это верно по крайней мере для managed Kubernetes в Yandex Cloud). + +Требования к пользовательскому интерфейсу: +1. Настроен доступ через kubectl (файл KUBECONFIG); + +## Подключаемые системы + +Подключаемые системы должны быть доступны через программные интерфейсы со стороны сервисов фреймворка. + +### Система управления версиями + +Хранит копии репозиториев, используемых для развертывания приложений в фреймворке. + +Требования: +1. git программный интерфейс; + +### Реестр образов и пакетов + +Реализует внутреннее хранилище образов контейнеров, кэш образов, пакетов Python, кэш пакетов. + +Требования: +1. Docker Registry HTTP API V2 программный интерфейс; +2. PyPI программный интерфейс; + +### Системная СУБД + +РСУБД на базе PostgreSQL, используемая другими компонентами фреймворка для хранения данных. + +Требования: +1. Версия PostgreSQL 16 или выше; + +### Объектное хранилище + +Хранит данные приложений. + +Требования: +1. S3 API Version 2006-03-01 программный интерфейс; + +### Вычислительный кластер + +Используется для запуска вычислительных задач, предоставляет метрики о работе задач. + +Требования: +1. Планировщик задач Slurm; + + +### Внешний поставщик реквизитов (OIDC провайдера) + +Требования: +1. OIDC провайдер Keycloak; + +## Доменные имена + +Должны быть зарегистрированы и настроены на работу с платформой Kubernetes два доменных имени, +первое - для сервисов фреймворка и размещаемых на фреймворке приложений, +второе - для реестра образов (пояснение приведено ниже). + +Доменное имя для сервисов фреймворка и размещаемых на фреймворке приложений называется **основным**. + +Компоненты фреймворка, и размещаемые на фреймворке приложения доступны по адресам вида +`https://{domain}/{component}` (например, `https://domain.ru/forgejo`) или +`https://{domain}/{app}` (например, `https://domain.ru/app1`). + +Реестр образов не может быть доступен по адресу такого вида, поскольку docker cli распознает +префикс в адресе вида `https://{domain}/{prefix}` частью имени образа. + +По этой причине рекомендуется зарегистрировать два доменных имени, основное и для реестра образов. + +Если основное доменное имя имеет вид `domain.ru`, то для реестра образов могут быть использованы имена +`registry-domain.ru` или `registry.domain.ru`. + +## Доступ к реестру образов с образами компонентов фреймворка + +1. unip-controller:0.3.7-9c53a08 - образ контроллеров, сервисов управления данными и отслеживания экспериментов; +2. quay.io/argoproj/argocd:v2.9.0 - образ сервиса развертывания; + diff --git a/deploy/s3/aws-vars-s3-credentials-secret.yaml.sample b/deploy/s3/aws-vars-s3-credentials-secret.yaml.sample new file mode 100755 index 0000000..6de3750 --- /dev/null +++ b/deploy/s3/aws-vars-s3-credentials-secret.yaml.sample @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: Secret +metadata: + name: aws-vars-s3-credentials + namespace: unip-system-controller +type: Opaque +stringData: + AWS_ACCESS_KEY_ID: sample + AWS_SECRET_ACCESS_KEY: sample \ No newline at end of file diff --git a/deploy/s3/csi-s3-credentials-secret.yaml.sample b/deploy/s3/csi-s3-credentials-secret.yaml.sample new file mode 100644 index 0000000..3220e81 --- /dev/null +++ b/deploy/s3/csi-s3-credentials-secret.yaml.sample @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Secret +metadata: + namespace: unip-system-controller + name: csi-s3-secret +stringData: + accessKeyID: sample + secretAccessKey: sample + # For AWS set it to "https://s3..amazonaws.com", for example https://s3.eu-central-1.amazonaws.com + endpoint: https://host + # For AWS set it to AWS region + # region: "" diff --git a/deploy/s3/sc.yaml b/deploy/s3/sc.yaml new file mode 100644 index 0000000..a9932d9 --- /dev/null +++ b/deploy/s3/sc.yaml @@ -0,0 +1,19 @@ +kind: StorageClass +apiVersion: storage.k8s.io/v1 +metadata: + name: unip-system-controller-csi-s3-sc +provisioner: ru.yandex.s3.csi +parameters: + mounter: geesefs + # you can set mount options here, for example limit memory cache size (recommended) + # options: "--memory-limit 1000 --dir-mode 0777 --file-mode 0666" + # to use an existing bucket, specify it here: + # bucket: cloud-platform-dev-gc6d85hf + csi.storage.k8s.io/provisioner-secret-name: csi-s3-secret + csi.storage.k8s.io/provisioner-secret-namespace: unip-system-controller + csi.storage.k8s.io/controller-publish-secret-name: csi-s3-secret + csi.storage.k8s.io/controller-publish-secret-namespace: unip-system-controller + csi.storage.k8s.io/node-stage-secret-name: csi-s3-secret + csi.storage.k8s.io/node-stage-secret-namespace: unip-system-controller + csi.storage.k8s.io/node-publish-secret-name: csi-s3-secret + csi.storage.k8s.io/node-publish-secret-namespace: unip-system-controller \ No newline at end of file diff --git a/deploy/sa.yaml b/deploy/sa.yaml new file mode 100644 index 0000000..da33723 --- /dev/null +++ b/deploy/sa.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + namespace: unip-system-controller + name: controller-sa diff --git a/docs/building.md b/docs/building.md new file mode 100644 index 0000000..df9aa8b --- /dev/null +++ b/docs/building.md @@ -0,0 +1,50 @@ +# Сборка образа Docker + +В документе приводятся команды для сборки Docker образа на хосте под управлением ОС Ubuntu. + +## Предусловия + +1. Наличие и доступность на хосте клиента системы управления версиями Git. +2. Наличие и доступность на хосте сервиса docker. +3. Авторизация клиента docker в реестре образов, который будет использован для размещения образов фреймворка. + +## Сборка + +### Получение исходного кода + +Клонировать репозиторий с исходным кодом: +``` +https://platform-forgejo.stratpro.hse.ru/mlops_platform/unip-controller.git +``` + +### Сборка образов + +Установить пременные окружения с адресами реестров образов: +```shell +export REG_NAME="my-org" +export RES_REG_NAME="my-org-resources" +``` + +Первый реестр образов используется для размещения образа контроллеров и сервисов фреймворка. +Второй реестр образов используется для размещения образов, необходимых для работы приложений. + +Перейти в директорию с репозиторием +и собрать образ контроллеров и сервисов фреймворка: + +```shell +export CONTROLLER_VERSION="0.3.$VERSION-$(git rev-parse --short HEAD)" +export NAME="unip-controller:$CONTROLLER_VERSION" +docker build . -f build/Dockerfile -t $NAME +docker image tag $NAME $REG_NAME/$NAME +docker push $REG_NAME/$NAME +``` + +Собрать образ, используемый сервисом конвейеров (pipelines) фреймворка: + +```shell +export PIPELINE_VALIDATE_RESULTS_VERSION="0.3.$VERSION-$(git rev-parse --short HEAD)" +export NAME="unip-pipeline-validate-results:$PIPELINE_VALIDATE_RESULTS_VERSION" +docker build . -f build/pipeline_validate_results.Dockerfile -t $NAME +docker image tag $NAME $RES_REG_NAME/$NAME +docker push $RES_REG_NAME/$NAME +``` \ No newline at end of file diff --git a/docs/img/hse-logo.png b/docs/img/hse-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..516dbfe713b3933fd779d007518dc432e7640608 GIT binary patch literal 19353 zcmX6^WmH>T)2(0)UaSueEgIaN;!vzm+$qH!iUcig#T^0^EA9~7T|;qqNO4GjK#_jw z`(>^C$vSs3H#zsr-h1{$eN!CZ{>CTHa}ckTpsVJiJIxl8iTRUsDYyn*Xd|VkPH~VI(XZdMA&F#USMEbGe@j z({PPyS6O>ux3&|`99_!H(L%?HMNTMZZsZbEANhkBt6xp!`zG>9-D^|$TC$|w{t?LKHBk0WsEdm63q$`n@T#)RO!QoKBILrMbty?CAJOXX_Z6=p)vq z50_i-H#JfhDROIhQ55?LQ+I|-aH;IQK4tch-PLcooSU&j=a+}LiXKkQ!-9|)9f zNiZ7E^@rRLdhNiGa5!sev8Pu|BW*4x$3em#D@O7i&I0?kgZE9jc`@nfx+3dR zZIbwSqDS7g><>(Vzr;S#M|ZPGvbK}10+HL82mAYS2F-`RANOM1ji?p_L2o=-AC@{= zJbK{gaQ7>Cmc6;K)SI$+G^%Uheavnd?+n8u=l0&>SGMV->HYgv!X8s z)6(H$0UFl0T2_AN`V1sbn8NExEm{WO1VtsB@e=<;=80WoWf@>ngTDDisWqESWXe%N zEfchpre1lr$!X~Jom0%<3wWJZb;ipc`K?yd$sP?1+6)`FoOE=sYHY3!MlHk$9m^h3 z8Ic;?v)355dkjD6vD7@)$sN_T8IpVCg+Wzke-L%geQ0Km%ajqP>-WT!X5CxeHd*ss zyDnF|Xs>x0Qo4GF4#wQl9A?844?n0?Ca8MQ-T{~1^Ns&}!<2D|A38Q~zA99EYv9eg znU}6h*R*meiQb7Nzo0DW$Q7_?R}q*R$XWOz(e#GNPFF?`nex3w3(JT}gYmbU=*eqX zng}=}bVyDwz8N#kux)tPoww~yu3lskE8gQ*V`5@~ z?lrN(&)cmvi|zzzb~TyBl9Hx8EXLr76;g$mZ<#Qe(|DXi1waWM9iu8_Ga9)#+bez> zY_!O0|CB-yDnNhJ;RWeh??nus|D2pX{ztFf6Dy5c%e$b~_Nke$-K!yw0d0(DY+&LO9C_iM#mhOefYKG!I=)(@$U7cBW<%QnsG`rvWz06%J z4@Q^?u3$;S(skuuV+RBNz91=hn0Lryp9)Q5DQeSPi-I=?J(2juFGM3wk+~(+sk_n8 zkhGN}nk5NbFdjz5@{la+BJUj~WHi|5+yk8J=h?d@Wbo~PyOU%*ajG(C*#gnkd7xMN zW>5K2JV5Cv*#lSHv|78sK(?Hb``TzlPv&W z#u&Gv?y1Jh61vRNV0Su{U_+{G?kTmn;Q2b`EHhGR-euTc&lrM&Ed|kVIuLiZZAX51 zZ9NXWfYu@W%Ibqix2-{lrtM#_!+;#kphun^NOhKEBP50s|4>XoG4&qqID0<*cQ zB}4nPh(#Pl>a#A*e6YFXMY)C`?U4Zd8#nF!EmpzpyJ7z&&;JrkPjkSGL&i%}=xyG9 z9B1*TZ#<(y9%~(VDVrnkwFZ`0XpMi7edv+^LYi@>5=ob1R94&Klhs0*15))FO>omp zO8C)rm*8^kJvh=7pKFTyozR9eks3qf9A&f{X^QT2#=r`wZ4?nw(yFR|C>Rr=(c2J< z{ndIBF{IR{i=QxdGOZ)}B#J;xNWS9*41Mo3EC|QWF1+hi1K1vQizTLiKVB<}K^h?Z zA|31LLEe%jQD5`clB+^2uDAl;XH~;&K z+A;jENs7vQELH*X?7<#87m{fZ_qSm=NmEh{iHhm3_<1t)%VyRK311! z|MV>#(4{sCE;bgDI~p*XIE!lQsm|%JV+Gx94&ytMXY7(F8_u6!Uh<)xzCHW0vASZj zkH5r-eF3rm$&`9fxD=kq`Mbn8HSA&LZ-%4skJkdwS*Lm`&zD>WwktKlAFGBPs8(Aw z$js@3+O<)S_O8R~j^dp^I&`3eG;|aIse1chv8&DGxb|PDM-;1UE(_|B=48(%Zd|#< z_P;ldthRYp_oiz#7EYAiZc=`TpxAoSNdPhwGRBNKTYeCkb(LxtUZY_{zC zEsMv?-I4+wq9+)Os@^61VF(`3yQsN{3HSRADN4_qKGUy>?CpHAmy_T$zkp0j-De!? z$`?0;gMx672b!b<*uRG5mFkn3bddjK=CH=%-m)xPx>!*to>V4lgi1g%=Qf zu5(f7j5sBNjgiHZL8OE5q8(Px#W|nUwOAuhaJd#1Xui?3CqOt{yr|B4mKiy14f!;! zYGCfiv44W&`S=;~k6#xV?VA9Id$E$B>J2Aop0#?7$Amq&Py$o9{pz@vvm8+2M_*zz zOr;V)cF%-+{5rph^k98!;~l+60cdk2kaBfzK$v*zqfE20@kp|U2?_SoZp>E&H#Zj8 z%T#$AhxY%>s^g&brf$TVO8#pdp49o8c(8n)<12$qY>Kr0fyZ?3^J4+3&b&+k;Av8Z zNHATnD-x!iRMdlifXT(;okzQ8&|~j3f+w=xeXt9XDn5XlWXr$#yL)x;ywRX;ME|L? z#)Xsy8sm4UzRx2-Vs*u;DZ@drFotARQqDP(kyePY(KKU=T^EyiPJfAWQsiq(?XK-D z_g;`91XkT-&O!IxIQ%h-S9M`Y8K9WW)}h9C^r`jYkqPxPa(9v z{gEzRr!QN-sj~_>V`~3~LZ&~eo)pie+=*}b%;NDx;uC$ET~2CyeHA%bW3|{kVXj%! z>VT;}oa>`_GExVHOGKSTuel-pks&BTq(iYYEQ8;WgJ4jSqs@<5*N0i{JE59+Y0YOD|yODWL(Ku0hnn{M@`XP+=Q%s=uWQ`x39e||A~$J$~P z{VD!2(oYrYMrBCS^91C z=9E*IJj)3?|JGMA_wNrQohlnOWFwo#@Q}Z2IwkjJ0nQlZcE=>}o<%r$J`Zx8yOdd@ z?8n{Iu-i5kencJK_|*Gq|5rv6KYV*&)pjVtQiwG45fiVC)MKrYxg!a#Z45mffA2#T zanaO4*;j){W)cPF|NW;|P*0C5`gMgMEAvD`6NoDj1Y zXo!M*F#*^u$p3n{Iqwfm20W?N=W7cmG}QQG z3OS~DxA|v}NLt#~I4a$G^+F!jdln<2oiqTH)Nl3>Axl%cEO8>MPY#^V3)W^Agg{8i zA}yi+ezel<0sL+D(yq;~y2gN{@=A*@F7%fqi7csKjG ze2tb=6q|1{53Ub%G~W!nZmYboO_NMSyy!K3!zvC@4|xEXSXBKyi=9p7Ej-Fps)aTS z7FJCS;Rw-~GDJ%{cNw^Rwq3@VNukl46{y>6p|7PH?>Ja18&mqmhax+#r-`L3+QIt^3g7Zeef* z?~)j6^vVhG?>)FwI>Yt6*0eIPWJ|6+1ikFZ;=0!Z6x=E-;XpxQePX+QkDXv@s2=^b z9l~Gcf@VBi4~6`>ph0OX>wiUs;@$ub>de=d%D-j5Mf~9f9wPpVZ~AFW6AM1_lSIP2 z-x_FJ1z-YzxeV|LPWV$m;$|}+kb?2bD~DhVa1?1ueb_e<8MoxFN`w?Y8XL2oTguZRhcMIYhZ9ffobCzD+Z z2MqtHg_S>gt_ECptXr|^eKK#_u-7c$*zw~xNd3wmK{!~mbBs@XV2Xc3sfIn{6yRVO z&m_nJWhV&G+P>54QXW>WIQ_K5|81Y}jgI+h&=xX&HjnhVH0M;X4}Nb~FY7PkLAqb* zdve|ktMSq^KI|pWwGTsQcsDN!mc)+KqxW-r03Tc`QfZ@|odWngE3sqdnieKi!?DQ< zsl2w?q-@hYexMJbFl?qj*ik%JGit~AGd6X%udP;5Hp}@9Cq^=k`Q7eDiK_`ku^s8O z6>W52N8^5}01O*|syTQH55dB~hMTe1FJ3iN4S%9Ka$JfSttn8}O90|V)-2l=9q`3< zv!t$CQ+l>0a=_nCTv5Djf$e9r$WJYSvGiVh&`jNh>>=(&4HGmTJjZn~*)H)Y#8GMk zG-#Z5plpy$bVDgrY2eHIQYPFTP6JpG8uskvOX#^+Xz8KQ6pVOl#=KvuDNT!b({)Y7 zsWz~Rq-+=tv;9xtWpo*QuO9DO3i69$Ub%}VzJwITqr-5=>ADdw(KV2^=A&xw!a=QN zRkay$&IMQpR*Poi@Rz@!*4bLJm%vFsym!MlgY|e5)R)|qG6;5F=t+Jx`GR{8R{)vT zn-4sWf<8xm?;jFcQd$$D4={D!QP|qSOxY?VL>fnx7lUdAB4;nWv%dS4Y@Do6^C$SB zcs?v8)+A~gO)2bBZOV`EEBfBYQbX;#AzUsOkqP4jmamd`M)4)RMgkL$VxioYAQ-17 zSoc-6_)?Rmp2kN4EhB7{q~zBb7Ls<(ygq{8;Ll3$G05d5^>LY`VVIYF&-f{IBfG;D z=8W*IW)LT$T=a}XR7iI%N*etWR=_zcrQdrx`xCPNRyQqH)l|k<>PGEQ82j=Uqc@M& zUwe~dvBqk&zxvV9FIY@42;F^{lTPBcw1j-wBin=J_oH*C&;#Pa_&~ZsIknpXP=e9| zCB@ukIy*7XFFm5Q4;e-YzB9wgw5JaA5QfWEqCLo;Q(C=l|5)O&P$Sg}!@8=FhG)II z@++@i-OYd}V2ifrh9QGV|F`8T}{ej$e&y4HWpU(wdm&L^>pz?&6F zV};B36TS)=bIFPph9kK@)@_)+iOCV^4Py|mKIAcGkakR z`b=Hnyh5)oT!cjbk#{dD5yQ8p;Z48BXx^#)#*NkycoI~4jpXl_#*zh{cR`VoHD(~9 zwXd$ixQ%li-SZ2*j@ zUlyb?)s{W1bU^Fvnf;s_IMx|*mRuBaG@3C^Q)7)J#4!n-y8R0m3W~Kiia&Au-29OJ z`S^Q_%TgPU!|9tPrR}`F;a@49MT>g3PY2S5_=YL4TQ`oFySImmgwLbGwQp|g1Rd!r z?}$y_ZYJmS71k~1IO^&B8L%bWLQ@MYkUo)A`1v!0uOveJnF{WBf7k0O$N((o)(n^v zZn3f1@hV83tE=CV$Fy{}4rIJ>H+yQ~E9LcztsMnN-axo#Iy7hQJ6trU<4oT)wnvz; zjQk*^yY2y=xWlE-{R#`gxzCa^xG7)-0sho7xSFf|s<> zaFn*NpPd862tTF1z%daWvx<8|;gU^Oj(?mM#}Ms2M6Pj+0HdThZUjHK((IMZl#21U zbfYQG3PCx?yw$I_5;4q_M7^S98V??oABJi9O>0y#rM$#tizNE?Ne*J;be{K9Ht3Xz z&UJc(EIhaN`Jtqcm`m&i?cVccr&sxL!9OMo_hs*Ej?Kye(s%CB*3fh=TNxIBSB?nr zvdies2gfHKv^iuQ4pim{VLSSV$laI$NW+UwXTmV;#_4cc=$;l^^R^f<$&mK-n}ppg z_o%Ogt;d{sd1lM1>EctV*xD>$H*hx_TE^tE&(e922PTfgo^7zi}IH)dFF56N8o@UH1D^Jef^Jy09u zh#^rCoTp0|mh7B=ih?nwLw)L>mTGK_t*2_!Im&jIe+meZ_NJF_c!%!x<*xKVD3#KD`{oC#4+uy1m{sTEe@gVJ=$Js;A(h=`$AG_x2DddUs;vQH1 z)%z)2B+>?GFFsTdNy_E^>Mrr9%|fqK+wvoOE$|4J6T1%0GbRkvq$GeSgQLfJB6+Qm6HzYz-n{_x0GEfbg8Y`8=u%8PNJDB z^~1tV|MFOi8#-RsEbv=VdxUs8ZX8PJJ^8o#`*F_f{E6>q7p%=;XXd?)<}1G?Z`DTn zXXkcaGyn@kJcKbv(of{T(2lvc|4jL_|y1U6i4g`~-e!y@r5-pXMs6tl2Ul?Bn=fMA=)K6}Cu@ z$(IwHPVj{ejgl6YDTFTp!p{x4r|}o1lu@GIamPhX-2Z~6k!0mw`fh-XuYeLOERsk5Z-2WAsKidxj1q|EokH^N4(G| z9U{p;Wp8r#s^(qkR_k{H!B6C*u!d8t%8^fzokz9fvfEBD&60ZpwMIZu?Z&{OTB)Er zPsDL}eZQQpthp+X4@AbX-9ehzNF6Y-n4vzGY9z2yCR5a9y&5+JPkWBPh%TP1xO)^4 z#n)h`xjyM(IOl)2!bXGkmdeOU4h@O}4lq{i{7xGdY(i^sOpb^U$sL!MkQ|374?2p; z7z|aq{YwwaUrp7582nT#qLRPk;yY~xZp63#u}?btqh zV2fb}*O0EPfi}#9ZX5hO$ydMZvGIzRR{C$hLGCq1d}zmUeYaC4`Tq+6j%S88eXdrS z#IaZm*CT}!S7VeFDJFZ^lZ_F8YPs7l>h4=Gec5e4ZJP!E35p<#m);vfkfa4Bp(-AT zB<{CQ&($_r%IrxJt@O{5Q|}+SeDMlN)$;)Wb0-qHP7UID%wYAbI?@Y zlf!UkgaVoJ@VDI|>;TSJu7KHQzk(9s3j|w1?GTB<$ItIdi*5E@!B1i#;^{{6dPBcZ zIDmY?AQ^C+Y%V$Vtm6FF9;rkLvxQg8NXYsG6DSK^a+V%oZ=6r^mBB(WV8C?f5GtzI zHn`76uu%57lFFC&Ip-u-)6FxFX7f}tjlEX?w3_q;K480FQi=WrFZ;i*C0}553qX{A zpFidu6X2*|GgzslSK8H7XtQ+1Hsz(OT<`+#*%Cac#4!IYdVk$0GLDH_&RY3Hln=P) z_)59?dc=%}@Cbj$zNWlV&N=t67upyJKijV)Uz9)UFj$-Me^YX(0ia4NGYKsH5~}j zo&K7R{>^)5d;<$#(&pmXc+am0ywD2xY2cDEJd|rihmTBuFp5z;FY_?6UO_Y5#dI}6 zuwGQJQ^abOZth!`hq-7uoY+#M)|AE>tJzZd3zFEVciJkYYW6F-#9e)3R3@7%+K8-*e^z3%z!Ik(VT2S2G z-G-FJgEJ~fj6RLbtW>G8rrsKVT#3ZHj!-r;)%gCA+4ryUAwT-aJ%qX6_1%qE{38y+ z{_5^^V!omLKCa?}iegK_n-}8V`kgFP(-t8^4RizPmKTX005?r+Trl5sygIg~KH`U2)Z)`-r}n+lM2?ypIzX zt_;6c&NAy%sXZX|tQ!8;u^oJGdGhhYJ7%%~Q3~%YrJY_?K0t|4 zzIn+D7)$ewp$V)oV!yD7e`8=!|L1h{uDuoGk%S+AZ|!%gOBDRNitUtaI{e(h6h@*} zCv7ixR zqWMQB{Fy^Va3F(smF%X$Qy1OuQshWCl(>tHbCn@KzU>nr%KGESZDLlw2U>{8I;Oix zwBkl*;O?cncjK;Wts9>XoF|<>Sr;jI*F8LjdE~rMEWUU1*Er=} zGf%+v0In-LHQ|XJc})urzb{z3DlF#0J029izz&@4*+(5KML<5={ayb(KVm|RpH-+Y z2pYoN;V_ev5GYb6yJRWd+iSo3$)!n?7<~lnj6EKu1^&ixGtjO(>eXw%cX{*Wc`yD1 zMVWMG)_NC&=~cQRp{m>Rke=6=FtO}<$)$(bd=m5Dn=yF_6B5nL+|6zq!xAfQSm$$d&iKf^1{td>wX219iq9>*brPGp3QtT?+ddL$6*jAIMa!KN>>H0A*r%8Vhcb zvlH2G))ap{QXgh_$geuA{Z~s>(XBE6_s>D-cthmT+J5MQ!-}i=#CMAl0IZjn>cUts zkFdk7R#p4=srrMtNiBb0MvBG(<#@0|U0Nt(n4Pgz zO)AgLUGz9B&jy@vP!<{~Q3-$=AWfhG%i^bB6;IJ3Q2z1|OauMGo%hNU@4{7nBR(&k z(2?rg(3XTe0nIB@koSWd5e@%Trvr<@@`M2VPO8t*j|vqY=YQo^IYjI0X80lrjw)ND zZrbgN+`B`X?{b|e9sbMv7|;dVw0pAk6=C((If|O= zV@mAc!3m>A%koA3rkZSO56~kkpSi0t(maY{@W3h}XLyLMxd2dNkdOP(x*x#;V~_Vy z78CMUH&}2q=>n$PlJ{medE!OYO?o0n^_rv4?0z6YI)=C$?U>rkwq_o_&V5bk2n4VKPd4&|4ItiwFRkh&i1S1+)fa1 z%NN|*sTJDU>E|n}QL-skD|p=*12t6uXVUmG3rVJioFJn}?>=>pjl z+1I8D&?{{ahJxnoDkSS>Z}@O+^ZoHjR=n)0~c^fTnTWxF0&;NvCiYZgmhAnv-sYu~-^@q5VaPwoNj zc^~?39q=IL&yYVxpSN@Agafi1&s}>hQQYUW9W1_85Q)fD_y@DV5GD%EGNS^S#l!1D zk)o}Ev@momZ;t~rZ^Yh$K>p*D#8F-9!}3EDd6oV;svhT6EI^R*vGiEP7#}p?*t! zS@Qr*|K=u-$5Du=0B-)w^b9STMWCdcRTcc7f zpMF1mM%{-@P>4BAy?0s3rC#D0+D}!eQbYEd-))qp*OihEcaiugP{ka8zBy4|+C;iwwa}EAVX3bLTE`rX`75FZjNj_an592>=^hMV))la|aZ5mmCb z-_X2z=soi}%~FHEP8wU;je8E^X6Tb%TGt{?^a1;X%0Unyw6w?f&;Rvob-!3pDIZzC zj2YASYfja?Grr@>=TisYCrMirpa!QgiCgKDYV!j5uIbd6Y6!A^eF)^x&^54}jWTsu zjb-{>8rVF;YWv!XU+PY~JrVyv9+{JVZn@{BtydtmeSEc)Wjh-Wb}Bhm3e!)MBRQay zNd}yvI3G1#5h-;WA1g^Xs0xqJ@kCUa(X#hLa`W)(2Y^CQ7o)eoSjb z5qg{&n)2E3yPxK178?8O;JEoM)D3PcB+aV59O@FP>NvV)JF%Z2ih8kJO9{UOJ8&iA zVz*%>`y5zSMA3c5ruZUfHN_>-(2+q2dai9FMPq@?Iwql!rJPahmGw6C-lCGO!vt>Vlf3zU0{|}5fCg&8} zSh~}%t341wMn`%pqIxq6`e}i_7vpUF`sBfarMh{Jch}uMlRlg@YL63?iwF`{%T{43X|#Cf^@dw ztOd2BB;*}!DMkPEccGcQw{uP$$sKC!M!Z|_U4#c@TzYGTj}tSuKOEI+*ns0*8woA# zc4SHep{`ve`02WY{2t5llK6SsSJ7D5!*}Eev?1PBmHO(qgtW6^Azbe*^Y#f@)`PEP zTnm=}sbPaadk2zXKY#x-?eQX7=b~urmVI@&$IDBz#8_z0p-ACQ`YbOmX}7`|{r$_Rf(g7AddQ)G3WV!7ujtNn#?xLK-Rpl z9ejkLRulQI6MtnfLp0oTHw5B?mUet~7oBAS{tnrW24NalePz`@ynTLhN(tG=!J9ff3B3& zDzG%IsRkGIwG*ZE)Wx@~QAy7N`3wjQWCM8Yur&NcKEM2KSNBiBzoNef40S1-W9fJM zffwnZc=1|s?VwiCVbD(qczeSjB#5m&CM5`GeA_VAi^oH zcU=D!-1h&^?3Noo>f5Z^xBp32)j8kXnG1Ebo2l;VVg|#UoFDY%X#8A^!~J295Hol< zKM8QEr}o3{UC4R=6$fmPxWf|O#V(nXJHVD*VCNU6Q-DpUcy=6t(vc%wQwRRF3x=h2 zB%H~6D)?c}rPG4@Xyxw#7rL77&(GwRoZc&<-^?To zacsE_@L{{jyXMMGxUrPiZa086^Tp$5+31B{H&$~Ono;bvqP$rkj(j%98QV>~}6tFoWqx>b8s zW4!d$J7)Yd?MeEe(9Juh*BTKn57~ZhVk<;Yqubose7pwyjKS zNPv0n418ApG4Wc=&j<=D?m1EzC%Z6;SU2jm)RfJqkx^C*aOpNPw!ljS9PeWFOzbzX zcBb(Myv)-DB>urN%i-rv9F<(Uo-tW z>lffudcpw%M4zs3BnzbenQzizdM$k1@!4VbxG3!^=KM&Ji}%gu%&P)=8QK&@<6(i; z$Q}12;RXBO9CarLSRC>6c5W&`)cYKjxYnHVCzeqZM&15250PfEWJ4X-D%M#|UK$VO z8vP&sh?Dd5rbjV%3A zQI-w6n_wo1nGV7xu#HINi2ra{OY_d}f8U|Gd?fibGnC^sG@axpm^UyywjxkWr9`TI z+*243L6l2<^w}Y8U##8$WlEOtlGv(eE|}J}c{QmS7CtIciL>QfDQzw+3c7J=Yc0-B zzd>ijNDJtxB81te^j+4yuzt-EK@T^cDzd5?XF(z?@ZJ?ZJ}Jk15Rz{z3KSb_@+3E( z%(Vi znnb@Sm!j2&`_Dt?S$F77yxnyo8CeiaAQ6#A?(LodQdkrB=Rtwzc-KEl|`3!s&Bw37_ z=Uewx<84#_sy0GL@3GThVQ}o(<0wOqdB2zYO301y+k+Y&r-N-*^)f=Up3Oe3##MEWzYsshT~C3^2zR5k0wayT={8gGUCbxOqpzU08QbuTBrcPx!T zvQ;PUIanoG610+szw9dLx0kka&cxTZC_yqSG-nXK?vIh zaq_DX0kf8!NVo4f{`ZU7Ii%0($;PmM@X-&qz*&*);*1w?>hy9_=nOqAmxX(?!}7n5 zs&*!Gf-y%=7KKiAitso!6Ek}rHRv5XH5MS*{1d($<^Q%4f0Hx?B)nlh?k@}FcK^h_ zmrCww_Hs4rmge^w(>8*UP)=}m>Ag!4%j8(e$Y0K;II?FA^5E@8DqZ+#~{#S=#+5=1By>}Morddk?VbDDO+b&cZg(xj!4j1l!CwPa%=#otT z<4VPmg5WT9|6$-voeV{?`?KgO2&ze#nOM`0QM@l?`_oNr(W%>~UAvSs1cS2r{WaOQ z6<}@bL|e*CcGE{QLiP+kqV#os$#VrGi4oh3gZ%aGajoi~%LGI{%|&W6-}YDoaN;#f;JvD8x$TJ*>Px%SR_ z(Uy7O>sa1>HX%~NVRnZF105v+U<6Y(g#V+UGlMF2nX85J?0th0+72Y!?qa!ZyiUGE z9bG8rxVhc&)KJ;n^FBp?+;#P*4rY!;X*M?c6yMe?=(YC|pzYfObwllNCNx{1Sl*r0 z5T!%lS+_VT%7Iv6s|+W`*l#_E^3E^kQivvyUP~s515F-aQHD9($op|nWonTn0z-5c z)y;oTGH+Y`A3YXt+07lb`eRR9-9S6VU_4$~5=ANOmEQW8tqS%0e#g8zYJTr9Qx=H0 zW<)gzS|I_7F=rkQ$Cq;ns}o34Jhf|B;-7@OyZ3GcqDB zp#~Ig1IjmWw=YwqYFmBJ2Yf{%izxED3OCChaIO-)JoXdWG;q@^nQ(y%z=o90@GYvtrZWdTRq20ypEc-u0SCsGJz`4f~ zNKCt4VVE&?t~JhrR5Qqb&Cfb#oUh<^SjyM3(6(gWL|=MwuAcKh9EHo`?6)ceDrVwj zF9Jol$Fz<>8qXz^i=X5`G{%@a zO;thHuiGV-q@+ttttiM{!nDp6;4Y6h_99{xpxnYJxEX`ldF?%u52U==?*75Fx-kZs zC?CeP`D?KNztpDpnB{U7aC<--??Nj|tj(;MS41bdXOZc6hVYq@_T^aJ+iLlebt#2M z5nuB4WB%x7$OO{)hih*@y2yIOyVKqChS;d_d)}dCR=tw6TM2#xdx6uIl3k4PLYhr? zT3Z20)N`eXvS;+Ge4>UwE)DIL;m8`;)jWjV;o*fks-^kU;B;p|%%i=@FVZY>Km9>_ z-qtr`z*qCjTS-cCz3o?0f@zh-Zv*u&*_E|GGZ1sUH7XIiTJ2Fkd`xokB4$mdEKj(x zcfRGW*~QDasvy5g=6=?Lp^ExyCh>uQ9<5al@w7meGCtG2T7);NwceJ)mCD{N`_C#9 zXDh7TaqtEgs~fk3sIjUJbQ2VK?Up%xf`>-7k!Jj1kKvX{t>((AWjHw&b|L!8oW?D1 zLUk2gT=2x}4W$B`s)7NL^r`$B;oJ6xlBb{g!;@r%^M?{k9cqE*=Z+47)ELBIGjDqdh{VKl!@HR z5anp~T>I)qy%$71ls?0aWdrU-_vF85{rJCj1XXy^uZk%Cl=ALAt5gkhkw!c@i6eJDtCJQ z5@~h_ugc68MJK6Lm(i`8*HM5s4ZTtp==7(K^9Y4eeXN{)r8SJqJ2!r*yS%5YEP72yx@J08Y+I`+;N2?wJIyE z+Ht^^o5OMK8Q4@2F4;?d&F30d(!;J$oR^zE4;wwJY^(dv8tyRNR}wm$ON36ww=~n4 zjB3Kfj)#7Z5*8SZQ&sxXd&FlKLl?k!;mpD+Cg9l6N0;`$>0@W~+^+m~uZ z5ud6RT5+uAtM~90Em@yo69BF!peVI`#9BO8e9YF`N5RaovcG_2fSn z2vHuqB7s<6@!-9-g6$(#mj%c)Dif@Lnw-sXsSyqQzvaq1+wBz+FjaK%1OJ+l8)=nEawQWm;#9iw z<&hiCj$1%+(tVpFMIl@?#}TtH<#FWN<+%C$?f!)oP!&qt8-DB%JS$g*rVa_bI04`S zFbp&707E~7p(YkZ;_iDH9+l+Cosn((LnCb5UynFMt95gO@IJ|?Qw)IbhTG$wl&Tq1 zblJZFQfc}Ex8$z^7u!KwL76rBWJSoYjIc#uF~Nuwz!jhDsL>@hjFJXoiwh3w?73RqCc>w`u$4B*{o z<3$ripAK`0_3-078(h@zE4=Uw&D&KFQdtUgn9Q(fF~7QI0<`riQ+RC%Co0tVNegmT zddIE^8Fl3Z$NAu|GW_^9*t>8ml@|NbTY(EY3-jDbug@uwojxk~P;3KKVhze0Yw*Lp z(abu`dYxTjX9!9^vA9eYnza44FZ*v?&h@DSfc3IsJB5{hk+eKtVqMinfSBl6TI}R? z$4A21J3LYKsFsKC*TzPM5Kuz&@#}3%__;skp#^TbZOF%{q5Y=57rE)mJ3RK*A-ck> z2z2F`j?la#WQbLqXD^;DS2}zx;znsT3KoK0z9gTf51*Q}FG%QApDK)f-xv1@r8`DQ zS3v5VwOB`K^gPLZm7eLOta{=V@kd6dK^JE%yw)SeJxs~sjL7)&6bJvhbJPco#CtC3DGL`B_|`e<{$Btn3fJ{D>dIk$0=-HW23+xS*bkvxX8 zjboV0WK8p;o1tx@_!K^##-r(|FJl^oJ-5w=p(04vjjks_Tm7SXUsC3Wvdu6?4cbFt zPFL9$G^Q%g?vs{HM_0_&Fh}2&yk%QDk@|+8&76`@!AxRm8{<(u7ccR5`B+-yB|T$d z>tTz050D%?7F|*EGrUx3zDO=VSb9&Oe8DB%U8t=1_%Okq({Bp;8JW^9scbt3i5RRd z53oT=!FQ!q{>((WBjRcxp60*~lLeB8;p^f`Lf-E$Io*1DO-_2ybTT^%-0O}qfbQec zmZREy4=zcU>1}*IgY@`3=_aqRoo;#cx?+co`t=PPyc+>a3;2HY1c}3z&UXmuF_y#bYkDi+ZQCZn+swig!9ftL$2{nt(VUMvZGuC6dYhs5@D>-;Q4@y&_!I`P4l%@mOD%p1*odDThl zx39r~DnGQk67bfj1>HhOy*gZ8#&4VFW{B{9y?GuaU7Qa(?3%`fd|#t{%fVHTX&V~* zY|%as=!cu;C^+VlYt#Q*a6*K#mPk3!eIc{XRfNt^( zrwK0v9W_(T;SMpwH#o*)YZ)dPhH-+KoLuYG4x5RAA5JqrUNu)`Zih=EXva_IJclFP z5DkU8O%TTDEIR{!nK6sTHcf?t)(qP=hL)RY*AIMcq@%uL9*2VQyF7*xQ1D+#>tk#) z5ioN;WLJb&&4oRf)&s2pn6Br%%I6!{E-m9x)@@PuHS^)sFu_^gB-Zd` zfv4}GBEQ&}a(AVMn$SBL==CM*LXq5v$G3W zBCa0|vx|pqQHf){P5V|lfOl}@DX(4+L0!e4S56e)D3$wT&HQ`KnDBu0z$icb34kv$ zug1o97`96T4>CjAdqXdH@#^*D|F1+O_hDOF#O4f6yEy7rwEXy5t6IN(pRnT1*6b?U zoFw8cXrqQCIDP;sIJT)L>RT?Sq+T;94E9#tN*Ip1a`3CESLf%eTyNou5qmcsb_rTh z_gUsSJ-6PrT~Vxkl@1jdU{6J~@&xmGh}D44rDA)Z`FYQCi{t#&bmDVNdnib`@OfJ3 z^^NjuIp1D0uAt{Z)OsN%L7*1^=UmL{n#t>^k6LzwZmF5)MDe59rVJ2p*SwBP85RNO z zd(D$J?hNFGIE7!5x*`?PPx%($8JF!6IJ!>QvuN3s0eR_l2|mcI^Gar1Yo*ocK8DY6 zA@9b=`CPR2*lt?DLkQ>3%S*e73E=hA@zT@{ms3IvUUjMg?c3St3%oKGD3MsR_n~ur}eZO1j?;`=LmAema~|)G-%9Cw?*Cl9$&| z=~=k?Z`eML^KB}Gd+m1j5LZjZT;5R?_+c<7B0_BMN-+puCc^^$W^vJ7C$OGwF^aeH z{djqemEPE#CBoAb2oPmmxHr@c}LEgpZ%`(`lIk_6p+VRjRPdAoqgUDS&;VQpvp; z72IH*lKlT#wwq}%UKqva44VP29laL!i~MSTuZam>F6!dJBMb7SzJx#X)CXymy@CDJ zd3jAth@Th~h}Y@y0C|T_UbAV(J^B6e@|uS3&|d~nsRs$q>>(}YPq>0bdwES?2QA;R z@Af)tpcBuW5%fYX9>lMZmskC?|1oQOtM%hw@Qdu3ZvyS3Zso7|mGSbbzc%jtZ3Jow zX3S^5CmTUW{VI&&54X0&f5xwfmscZ&UuEfLoGF#tula@d%qUTOqf}ojv6eAb1U2q?7+SFR$5E&)dVY9#e6ADLl;ri*}_2{$514;z#Y}HCKX% z*WR|O@!nHCbwhnip50Rs_=TUVm)Cqt&yK3Y3hrmt7uVAxioc0C3s@`0!DGCoy&|9|G`7<+e-sM9_(UVpReSL@KQR4m)bM zjw%I@Cx~0Rap!OI{d;+N&A9Xuk+ymSDgvn#jz^$i`Fl~=i`HaS9@9l#uGi`5iYtCT z;(x+>FyE7xmzS5VjXQ&NThx7}CHE-A_!L%9kqEDnitogJe1)?D9oSgy?tAaO6fM6% zN1;zd%etlKQb}Ej{f_eY;y`cxQeWte`^BeVa9+-RX{!@I1B;B8qLs%jb>fG5Z?0Zx a^#1|ia(CNDHB@5&0000 -o custom-columns=:.metadata.name` -n +``` + +Удаление "зависших" ресурсов: + +``` +kubectl patch box -n -p '{"metadata": {"finalizers": []}}' --type merge +``` diff --git a/tests/data/resources/pu-user1/apps/app1/api-cmp1.yaml b/tests/data/resources/pu-user1/apps/app1/api-cmp1.yaml new file mode 100644 index 0000000..97fef5a --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app1/api-cmp1.yaml @@ -0,0 +1,21 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: APIComponent +metadata: + name: test-api1 + namespace: pu-user1-pa-app1 +spec: + published: true + mlComponent: + name: test-mlcmp1 + restfulApi: + path: mlcmp1 + auth: + basic: + credentials: app1-apis-cred + identityPassThrough: true \ No newline at end of file diff --git a/tests/data/resources/pu-user1/apps/app1/api-cmp2.yaml b/tests/data/resources/pu-user1/apps/app1/api-cmp2.yaml new file mode 100644 index 0000000..69c3c89 --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app1/api-cmp2.yaml @@ -0,0 +1,21 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: APIComponent +metadata: + name: test-api2 + namespace: pu-user1-pa-app1 +spec: + published: true + mlComponent: + name: test-mlcmp2 + restfulApi: + path: mlcmp2 + auth: + basic: + credentials: app1-apis-cred + identityPassThrough: true \ No newline at end of file diff --git a/tests/data/resources/pu-user1/apps/app1/api-cmp3.yaml b/tests/data/resources/pu-user1/apps/app1/api-cmp3.yaml new file mode 100644 index 0000000..fa8884f --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app1/api-cmp3.yaml @@ -0,0 +1,21 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: APIComponent +metadata: + name: test-api3 + namespace: pu-user1-pa-app1 +spec: + published: true + mlComponent: + name: test-mlcmp3 + restfulApi: + path: mlcmp3 + auth: + basic: + credentials: app1-apis-cred + identityPassThrough: true \ No newline at end of file diff --git a/tests/data/resources/pu-user1/apps/app1/api-files.yaml b/tests/data/resources/pu-user1/apps/app1/api-files.yaml new file mode 100644 index 0000000..a7307e2 --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app1/api-files.yaml @@ -0,0 +1,20 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: APIComponent +metadata: + name: api-files + namespace: pu-user1-pa-app1 +spec: + published: true + files: + enabled: true + restfulApi: + auth: + basic: + credentials: app1-apis-cred + identityPassThrough: true \ No newline at end of file diff --git a/tests/data/resources/pu-user1/apps/app1/api-pipelines.yaml b/tests/data/resources/pu-user1/apps/app1/api-pipelines.yaml new file mode 100644 index 0000000..dbe6e0d --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app1/api-pipelines.yaml @@ -0,0 +1,20 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: APIComponent +metadata: + name: api-pipelines + namespace: pu-user1-pa-app1 +spec: + published: true + pipelines: + enabled: true + restfulApi: + auth: + basic: + credentials: app1-apis-cred + identityPassThrough: true \ No newline at end of file diff --git a/tests/data/resources/pu-user1/apps/app1/ml-cmp1.yaml b/tests/data/resources/pu-user1/apps/app1/ml-cmp1.yaml new file mode 100755 index 0000000..f526c49 --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app1/ml-cmp1.yaml @@ -0,0 +1,44 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: MLComponent +metadata: + name: test-mlcmp1 + namespace: pu-user1-pa-app1 +spec: + image: + existingImageName: platform-reg.stratpro.hse.ru/pu-user1/test-model1:1.0.0-c25bfce + resourceLimits: + cpu: 500m + memory: 256M + mlService: + packageRegistryName: app1-python-package-registry + inference: + fileExchange: + fileBox: s3_files_box + inferenceFilesPath: /tmp/inference_files + model: + modelBox: s3_model_box + modelPath: inference/model + entryPoint: + pythonPath: inference + pythonFunction: inference.run_inference_v2 + license: + licenseLocalPath: ./license.txt + api: + prefix: mlcmp1 + connectedBoxes: + - name: s3_model_box + path: inference + copyS3Box: + subPath: inference + s3BoxName: test-app1-models + - name: s3_files_box + copyS3Box: + s3BoxName: test-app1-user-data + + diff --git a/tests/data/resources/pu-user1/apps/app1/ml-cmp2.yaml b/tests/data/resources/pu-user1/apps/app1/ml-cmp2.yaml new file mode 100755 index 0000000..f50b6fc --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app1/ml-cmp2.yaml @@ -0,0 +1,39 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: MLComponent +metadata: + name: test-mlcmp2 + namespace: pu-user1-pa-app1 +spec: + image: + existingImageName: platform-reg.stratpro.hse.ru/pu-user1/test-model1:1.0.0-c25bfce + resourceLimits: + cpu: 500m + memory: 256M + mlService: + packageRegistryName: app1-python-package-registry + inference: + fileExchange: + fileBox: s3_files_box + inferenceFilesPath: /tmp/inference_files + model: + modelBox: s3_model_box + modelPath: /app_data/model + entryPoint: + pythonPath: inference + pythonFunction: inference.run_inference_v2 + connectedBoxes: + - name: s3_model_box + path: /app_data + mountS3Box: + subPath: inference + s3BoxName: test-app1-models + - name: s3_files_box + copyS3Box: + s3BoxName: test-app1-user-data + diff --git a/tests/data/resources/pu-user1/apps/app1/ml-cmp3.yaml b/tests/data/resources/pu-user1/apps/app1/ml-cmp3.yaml new file mode 100755 index 0000000..602cab4 --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app1/ml-cmp3.yaml @@ -0,0 +1,40 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: MLComponent +metadata: + name: test-mlcmp3 + namespace: pu-user1-pa-app1 +spec: + image: + existingImageName: platform-reg.stratpro.hse.ru/pu-user1/test-model1:1.0.0-c25bfce + resourceLimits: + cpu: 500m + memory: 256M + gpu: "1" + mlService: + packageRegistryName: app1-python-package-registry + inference: + fileExchange: + fileBox: s3_files_box + inferenceFilesPath: /tmp/inference_files + model: + modelBox: s3_model_box + modelPath: /app_data/model + entryPoint: + pythonPath: inference + pythonFunction: inference.run_inference_v2 + connectedBoxes: + - name: s3_model_box + path: /app_data + mountS3Box: + subPath: inference + s3BoxName: test-app1-models + - name: s3_files_box + copyS3Box: + s3BoxName: test-app1-user-data + diff --git a/tests/data/resources/pu-user1/apps/app1/model-s3-box.yaml b/tests/data/resources/pu-user1/apps/app1/model-s3-box.yaml new file mode 100755 index 0000000..465e167 --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app1/model-s3-box.yaml @@ -0,0 +1,18 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: DataBox +metadata: + name: test-app1-models + namespace: pu-user1-pa-app1 +spec: + s3Storage: + host: storage.yandexcloud.net + bucket: + name: test-app1-user-data + subPath: models + awsVarsS3Credentials: app1-all-s3-boxes-cred \ No newline at end of file diff --git a/tests/data/resources/pu-user1/apps/app1/user-data-s3-box.yaml b/tests/data/resources/pu-user1/apps/app1/user-data-s3-box.yaml new file mode 100755 index 0000000..4f49226 --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app1/user-data-s3-box.yaml @@ -0,0 +1,18 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: DataBox +metadata: + name: test-app1-user-data + namespace: pu-user1-pa-app1 +spec: + s3Storage: + host: storage.yandexcloud.net + bucket: + name: test-app1-user-data + #subPath: test + awsVarsS3Credentials: app1-all-s3-boxes-cred \ No newline at end of file diff --git a/tests/data/resources/pu-user1/apps/app2/api-cmp10.yaml b/tests/data/resources/pu-user1/apps/app2/api-cmp10.yaml new file mode 100644 index 0000000..aa2a462 --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app2/api-cmp10.yaml @@ -0,0 +1,54 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: APIComponent +metadata: + name: test-api10 + namespace: pu-user1-pa-app2 +spec: + published: true + experimentPipeline: + name: test-ep10 + restfulApi: + auth: + basic: + credentials: app2-apis-ba-cred + identityPassThrough: true + apiSpec: + inputs: + - name: input1 + description: "Входная переменная 1" + type: + datatypes: ["FP32", "FILE", "WEBSITE"] + # * если будет передан datatype == 'FILE', content-type должен быть передан обязательно + # * если будет передан datatype != 'FILE', то content-type игнорируется, + # для каждого datatype есть предопределенный content_type; + contentTypes: [ "text/csv", "application/json", "image/png" ] + required: true + - name: input2 + type: + # если в списке datatypes нет 'FILE', то он все равно будет разрешен (добавлен в спецификацию API) + datatypes: ["FP32"] + contentTypes: ["BED"] + # По умолчанию все входные переменные обязательные, + # но входную переменную можно сделать опциональной + required: false + - name: input3 + # Если type не указан, то это эквивалентно: + # type: + # Полному переченю поддерживаемых типов + # datatypes: ["FP32", "FP64", "INT32", "dict", 'str', "FILE", "WEBSITE"] + # Пустому contentTypes, что означает допустимость любого content_type + # contentTypes: [] + outputs: + - name: output1 + description: "Выходная переменная 1" + type: + # Для выходных переменных атрибутов datatypes и required нет, + # поскольку выходные переменные всегда имеют неявный datatype == 'FILE' + # contentTypes может быть указан + contentTypes: [ "PDB" ] diff --git a/tests/data/resources/pu-user1/apps/app2/api-cmp11.yaml b/tests/data/resources/pu-user1/apps/app2/api-cmp11.yaml new file mode 100644 index 0000000..18f089f --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app2/api-cmp11.yaml @@ -0,0 +1,28 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: APIComponent +metadata: + name: test-api11 + namespace: pu-user1-pa-app2 +spec: + published: true + experimentPipeline: + name: test-ep11 + restfulApi: + auth: + basic: + credentials: app2-apis-ba-cred + identityPassThrough: true + apiSpec: + inputs: + - name: input1 + - name: input2 + - name: input3 + outputs: + - name: output1 + - name: output2 diff --git a/tests/data/resources/pu-user1/apps/app2/api-cmp12.yaml b/tests/data/resources/pu-user1/apps/app2/api-cmp12.yaml new file mode 100644 index 0000000..93828cd --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app2/api-cmp12.yaml @@ -0,0 +1,27 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: APIComponent +metadata: + name: test-api12 + namespace: pu-user1-pa-app2 +spec: + published: true + experimentPipeline: + name: test-ep12 + restfulApi: + auth: + basic: + credentials: app2-apis-ba-cred + identityPassThrough: true + apiSpec: + inputs: + - name: input1 + - name: input2 + outputs: + - name: output1 + - name: output2 diff --git a/tests/data/resources/pu-user1/apps/app2/api-cmp6-cors-oidc.yaml b/tests/data/resources/pu-user1/apps/app2/api-cmp6-cors-oidc.yaml new file mode 100644 index 0000000..638d155 --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app2/api-cmp6-cors-oidc.yaml @@ -0,0 +1,30 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2025 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: APIComponent +metadata: + name: test-api1 + namespace: pu-user1-pa-app2 +spec: + published: true + experimentPipeline: + name: test-ep6 + restfulApi: + auth: + identityPassThrough: true + oidc: {} + cors: + enabled: true + allowOrigin: + - http://localhost:63342 + apiSpec: + inputs: + - name: input1 + - name: input2 + outputs: + - name: output1 + - name: output2 diff --git a/tests/data/resources/pu-user1/apps/app2/api-cmp6-cors.yaml b/tests/data/resources/pu-user1/apps/app2/api-cmp6-cors.yaml new file mode 100644 index 0000000..24be7bf --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app2/api-cmp6-cors.yaml @@ -0,0 +1,42 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: APIComponent +metadata: + name: test-api1 + namespace: pu-user1-pa-app2 +spec: + published: true + experimentPipeline: + name: test-ep6 + restfulApi: + auth: + basic: + credentials: app2-apis-ba-cred + identityPassThrough: true + cors: + enabled: true + allowMethods: + - GET + - POST + - PATCH + allowOrigin: + - http://localhost:63342 + exposeHeaders: + - X-Test + allowHeaders: + - X-Test2 + - Authorization + - Content-Type + maxAge: 1001 + apiSpec: + inputs: + - name: input1 + - name: input2 + outputs: + - name: output1 + - name: output2 diff --git a/tests/data/resources/pu-user1/apps/app2/api-cmp6-oidc-ba.yaml b/tests/data/resources/pu-user1/apps/app2/api-cmp6-oidc-ba.yaml new file mode 100644 index 0000000..64a3f4b --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app2/api-cmp6-oidc-ba.yaml @@ -0,0 +1,28 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2025 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: APIComponent +metadata: + name: test-api1 + namespace: pu-user1-pa-app2 +spec: + published: true + experimentPipeline: + name: test-ep6 + restfulApi: + auth: + basic: + credentials: app2-apis-ba-cred + identityPassThrough: true + oidc: {} + apiSpec: + inputs: + - name: input1 + - name: input2 + outputs: + - name: output1 + - name: output2 diff --git a/tests/data/resources/pu-user1/apps/app2/api-cmp6-oidc.yaml b/tests/data/resources/pu-user1/apps/app2/api-cmp6-oidc.yaml new file mode 100644 index 0000000..3f9b5c4 --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app2/api-cmp6-oidc.yaml @@ -0,0 +1,29 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2025 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: APIComponent +metadata: + name: test-api1 + namespace: pu-user1-pa-app2 +spec: + published: true + experimentPipeline: + name: test-ep6 + restfulApi: + auth: + identityPassThrough: true + oidc: {} + # groups: ["/dev-multi-auth"] + # enabled: false # default - true + # roles: ["/test"] + apiSpec: + inputs: + - name: input1 + - name: input2 + outputs: + - name: output1 + - name: output2 diff --git a/tests/data/resources/pu-user1/apps/app2/api-cmp6.yaml b/tests/data/resources/pu-user1/apps/app2/api-cmp6.yaml new file mode 100644 index 0000000..0a12e0f --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app2/api-cmp6.yaml @@ -0,0 +1,27 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: APIComponent +metadata: + name: test-api1 + namespace: pu-user1-pa-app2 +spec: + published: true + experimentPipeline: + name: test-ep6 + restfulApi: + auth: + basic: + credentials: app2-apis-ba-cred + identityPassThrough: true + apiSpec: + inputs: + - name: input1 + - name: input2 + outputs: + - name: output1 + - name: output2 diff --git a/tests/data/resources/pu-user1/apps/app2/api-cmp61.yaml b/tests/data/resources/pu-user1/apps/app2/api-cmp61.yaml new file mode 100644 index 0000000..5824298 --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app2/api-cmp61.yaml @@ -0,0 +1,27 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: APIComponent +metadata: + name: test-api1 + namespace: pu-user1-pa-app2 +spec: + published: true + experimentPipeline: + name: test-ep61 + restfulApi: + auth: + basic: + credentials: app2-apis-ba-cred + identityPassThrough: true + apiSpec: + inputs: + - name: input1 + - name: input2 + outputs: + - name: output1 + - name: output2 diff --git a/tests/data/resources/pu-user1/apps/app2/api-cmp7-oidc-ba.yaml b/tests/data/resources/pu-user1/apps/app2/api-cmp7-oidc-ba.yaml new file mode 100644 index 0000000..78100e9 --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app2/api-cmp7-oidc-ba.yaml @@ -0,0 +1,29 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: APIComponent +metadata: + name: test-api7 + namespace: pu-user1-pa-app2 +spec: + published: true + experimentPipeline: + name: test-ep7 + restfulApi: + auth: + basic: + credentials: app2-apis-ba-cred + oidc: {} + # groups: [/test1, another2] # another2 -> /unip/default/pu-user1/another2 + identityPassThrough: true + apiSpec: + inputs: + - name: input1 + - name: input2 + outputs: + - name: output1 + - name: output2 diff --git a/tests/data/resources/pu-user1/apps/app2/api-cmp7-oidc.yaml b/tests/data/resources/pu-user1/apps/app2/api-cmp7-oidc.yaml new file mode 100644 index 0000000..28c4112 --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app2/api-cmp7-oidc.yaml @@ -0,0 +1,28 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: APIComponent +metadata: + name: test-api7 + namespace: pu-user1-pa-app2 +spec: + published: true + experimentPipeline: + name: test-ep7 + restfulApi: + auth: + basic: {} + oidc: + groups: [/test1, another2] # another2 -> /unip/default/pu-user1/another2 + identityPassThrough: true + apiSpec: + inputs: + - name: input1 + - name: input2 + outputs: + - name: output1 + - name: output2 diff --git a/tests/data/resources/pu-user1/apps/app2/api-cmp7.yaml b/tests/data/resources/pu-user1/apps/app2/api-cmp7.yaml new file mode 100644 index 0000000..04eb390 --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app2/api-cmp7.yaml @@ -0,0 +1,27 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: APIComponent +metadata: + name: test-api7 + namespace: pu-user1-pa-app2 +spec: + published: true + experimentPipeline: + name: test-ep7 + restfulApi: + auth: + basic: + credentials: app2-apis-ba-cred + identityPassThrough: true + apiSpec: + inputs: + - name: input1 + - name: input2 + outputs: + - name: output1 + - name: output2 diff --git a/tests/data/resources/pu-user1/apps/app2/api-cmp8.yaml b/tests/data/resources/pu-user1/apps/app2/api-cmp8.yaml new file mode 100644 index 0000000..9c66ee2 --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app2/api-cmp8.yaml @@ -0,0 +1,25 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: APIComponent +metadata: + name: test-api8 + namespace: pu-user1-pa-app2 +spec: + published: true + experimentPipeline: + name: test-ep8 + restfulApi: + auth: + basic: + credentials: app2-apis-ba-cred + identityPassThrough: true + apiSpec: + inputs: + - name: input1 + outputs: + - name: output1 diff --git a/tests/data/resources/pu-user1/apps/app2/api-cmp9.yaml b/tests/data/resources/pu-user1/apps/app2/api-cmp9.yaml new file mode 100644 index 0000000..5e31df9 --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app2/api-cmp9.yaml @@ -0,0 +1,25 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: APIComponent +metadata: + name: test-api9 + namespace: pu-user1-pa-app2 +spec: + published: true + experimentPipeline: + name: test-ep9 + restfulApi: + auth: + basic: + credentials: app2-apis-ba-cred + identityPassThrough: true + apiSpec: + inputs: + - name: input2 + outputs: + - name: output2 diff --git a/tests/data/resources/pu-user1/apps/app2/api-files.yaml b/tests/data/resources/pu-user1/apps/app2/api-files.yaml new file mode 100644 index 0000000..1e8ae6f --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app2/api-files.yaml @@ -0,0 +1,20 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: APIComponent +metadata: + name: api-files + namespace: pu-user1-pa-app2 +spec: + published: true + files: + enabled: true + restfulApi: + auth: + basic: + credentials: app2-apis-ba-cred + identityPassThrough: true \ No newline at end of file diff --git a/tests/data/resources/pu-user1/apps/app2/api-pipelines.yaml b/tests/data/resources/pu-user1/apps/app2/api-pipelines.yaml new file mode 100644 index 0000000..625089f --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app2/api-pipelines.yaml @@ -0,0 +1,20 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: APIComponent +metadata: + name: api-pipelines + namespace: pu-user1-pa-app2 +spec: + published: true + pipelines: + enabled: true + restfulApi: + auth: + basic: + credentials: app2-apis-ba-cred + identityPassThrough: true \ No newline at end of file diff --git a/tests/data/resources/pu-user1/apps/app2/cors-test-env.js.sample b/tests/data/resources/pu-user1/apps/app2/cors-test-env.js.sample new file mode 100644 index 0000000..287b704 --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app2/cors-test-env.js.sample @@ -0,0 +1,7 @@ +function basicCredentials() { + return "base64 encoded user:password"; +} + +function accessToken() { + return "access token" +} \ No newline at end of file diff --git a/tests/data/resources/pu-user1/apps/app2/cors-test.html b/tests/data/resources/pu-user1/apps/app2/cors-test.html new file mode 100644 index 0000000..66b43d7 --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app2/cors-test.html @@ -0,0 +1,16 @@ + + + + + Cors Test + + + + +
+ +

+ +
+ + \ No newline at end of file diff --git a/tests/data/resources/pu-user1/apps/app2/cors-test.js b/tests/data/resources/pu-user1/apps/app2/cors-test.js new file mode 100644 index 0000000..bc5242d --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app2/cors-test.js @@ -0,0 +1,35 @@ +async function check(authorization) { + const url = "https://platform-test.stratpro.hse.ru/pu-user1-pa-app2/pipelines/test-ep6"; + const headers = { + "Authorization": authorization, + "Content-Type": "application/json" + } + try { + const response = await fetch(url, { + headers: headers + }); + if (!response.ok) { + throw new Error(`Response status: ${response.status}`); + } + const json = await response.json(); + console.log(json); + } catch (error) { + console.error(error.message); + } + } + +async function check_basic() { + const authorization = `Basic ${basicCredentials()}` + await check(authorization) +} + +async function check_oidc() { + const authorization = `Bearer ${accessToken()}` + await check(authorization) +} + +const checkBasicButton = document.querySelector("#check-basic"); +checkBasicButton.addEventListener("click", check_basic) + +const checkOidcButton = document.querySelector("#check-oidc"); +checkOidcButton.addEventListener("click", check_oidc) \ No newline at end of file diff --git a/tests/data/resources/pu-user1/apps/app2/dataset-ref.yaml b/tests/data/resources/pu-user1/apps/app2/dataset-ref.yaml new file mode 100755 index 0000000..af1b637 --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app2/dataset-ref.yaml @@ -0,0 +1,19 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: DataBox +metadata: + name: test-app2-user-data + namespace: pu-user1-pa-app2 +spec: + datasetReference: + datasetComponentRef: + name: samokat-lite-dataset + namespace: test-dataset-controller + credentials: + secretRef: + name: test-secret \ No newline at end of file diff --git a/tests/data/resources/pu-user1/apps/app2/dataset1.yaml b/tests/data/resources/pu-user1/apps/app2/dataset1.yaml new file mode 100644 index 0000000..a4bce68 --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app2/dataset1.yaml @@ -0,0 +1,28 @@ +apiVersion: unified-platform.cs.hse.ru/v1 +kind: DatasetComponent +metadata: + name: dataset1 + namespace: pu-user1-pa-app2 +spec: + box: dataset1 + filesApiSecret: app2-apis-ba-cred + restfulApi: + auth: + basic: #{} + #enabled: false + credentials: app2-apis-ba-cred + oidc: + #enabled: false + groups: [/test1, test2] + versions: + - contents: + files: + path: files.json + sha256: 0004c84b66f954f2e7cc24afabf35d15350bd7e4040b9469d83e28dd45cbc1b5 + metadata: + path: metadata.json + sha256: d36b066987771d33ef70cced58d5c5187b2ec302df96a8156259f30444521704 + readme: + path: README.md + sha256: e8ac53b3a72d60b03055d12814a3325ae8982d525d0de35f09547b25388dbd82 + name: v1 diff --git a/tests/data/resources/pu-user1/apps/app2/datasetcmp/samokat-lite/dataset.yaml b/tests/data/resources/pu-user1/apps/app2/datasetcmp/samokat-lite/dataset.yaml new file mode 100644 index 0000000..06f233a --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app2/datasetcmp/samokat-lite/dataset.yaml @@ -0,0 +1,20 @@ +apiVersion: unified-platform.cs.hse.ru/v1 +kind: DatasetComponent +metadata: + name: samokat-lite + namespace: example-namespace +spec: + box: samokat-lite + filesApiSecret: basic-auth-credentials-not-hashed + versions: + - contents: + files: + path: files.json + sha256: 0004c84b66f954f2e7cc24afabf35d15350bd7e4040b9469d83e28dd45cbc1b5 + metadata: + path: metadata.json + sha256: d36b066987771d33ef70cced58d5c5187b2ec302df96a8156259f30444521704 + readme: + path: README.md + sha256: e8ac53b3a72d60b03055d12814a3325ae8982d525d0de35f09547b25388dbd82 + name: v1 diff --git a/tests/data/resources/pu-user1/apps/app2/datasetcmp/samokat-lite/v1/README.md b/tests/data/resources/pu-user1/apps/app2/datasetcmp/samokat-lite/v1/README.md new file mode 100644 index 0000000..142f661 --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app2/datasetcmp/samokat-lite/v1/README.md @@ -0,0 +1,5 @@ +# HSE-Skooter Dataset (Lite) + +Авторы: Грошев М.С., Сластников С.А., Чертова Э.В. + +Датасет содержит изображения с комплексов видеонаблюдения на проезжих частях и дорогах общего пользования, включая зоны пешеходных переходов. Облегченная версия, состоящая из 10% датасета HSE-Skooter Dataset. \ No newline at end of file diff --git a/tests/data/resources/pu-user1/apps/app2/datasetcmp/samokat-lite/v1/files.json b/tests/data/resources/pu-user1/apps/app2/datasetcmp/samokat-lite/v1/files.json new file mode 100644 index 0000000..0b9d234 --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app2/datasetcmp/samokat-lite/v1/files.json @@ -0,0 +1,24733 @@ +{ + "kind": "directory", + "path": "data", + "files": [ + { + "kind": "directory", + "path": "test", + "files": [ + { + "kind": "file", + "path": "img_3284.jpg", + "sha256": "03d4995239a480ab76b7f859ad63e28b26e1d3bb692b591651026de76e2a5825" + }, + { + "kind": "file", + "path": "img_1493.jpg", + "sha256": "b947e3ee84f134694d35b16ea354288c0c4638bfb5192fbb6a557b80e4e9f403" + }, + { + "kind": "file", + "path": "img_2824.jpg", + "sha256": "12a736e7e492a233a188102058a87a784944860e40165308fc52a8a465520f6b" + }, + { + "kind": "file", + "path": "img_301.jpg", + "sha256": "1fd909b3022b0781b632ae27eb9e979e219ddb8240be5ce783206bef674baeac" + }, + { + "kind": "file", + "path": "img_1487.jpg", + "sha256": "5507051466cedca2bf607f4388c911d932348b1bbb017d192e467940332b814c" + }, + { + "kind": "file", + "path": "img_1478.jpg", + "sha256": "4da100514d93557e278a5d1b18dcd33c87194bbd588ca7d2957a1ac895392c4e" + }, + { + "kind": "file", + "path": "img_4528.jpg", + "sha256": "aec479d8913b1a781a10765bbbdd48a508f7e6fbbe252aa98ea8ca5852190161" + }, + { + "kind": "file", + "path": "img_3253.jpg", + "sha256": "cc4b095d42a4ff058f2b5f223695904990caf6063db2e961f88274be2d40c244" + }, + { + "kind": "file", + "path": "img_3904.jpg", + "sha256": "bd26f0010ae0b35dc5b78c1b999b1135022625e33666cd13fbcf61442ba1a310" + }, + { + "kind": "file", + "path": "img_3910.jpg", + "sha256": "f5ec19d25c44d9280424da202ca4fcddb7fbe0de199fd9737eadc148cbff394a" + }, + { + "kind": "file", + "path": "img_1691.jpg", + "sha256": "55e5076f0e7959d9359942069f7e1f0afbb7403a16237f2f43e7e191fc66bc2f" + }, + { + "kind": "file", + "path": "img_3086.jpg", + "sha256": "d9335129c673675c0687310119e3b43a580d6be37655677e3967625d1bed1096" + }, + { + "kind": "file", + "path": "img_1685.jpg", + "sha256": "556ce3e95fa570616af276b943f999e32d1d89b76687668c0364c39570bae423" + }, + { + "kind": "file", + "path": "img_103.jpg", + "sha256": "87f11881ef6a8d9091d8b530bba6d7a82b095c6fde8a2dcfa8be9d8c70c34e69" + }, + { + "kind": "file", + "path": "img_4070.jpg", + "sha256": "3ea96eebdf7e2ebd3e7e20e20434c4cbb56d7233e57f68fad017cac61d2185e5" + }, + { + "kind": "file", + "path": "img_856.jpg", + "sha256": "a28205ea4a7404c1319203c611b41c32581eaa9aa2a34a0da2bc5a73ea6c1dfe" + }, + { + "kind": "file", + "path": "img_3079.jpg", + "sha256": "7686a02345d8d8cdff09f210fce8c81d50e7b60ac10d04f59e1097318fbc16b2" + }, + { + "kind": "file", + "path": "img_1652.jpg", + "sha256": "ffc3ef9e1c699514534182845f00fbd761a84cf2f08e7c2594d7e0d59cbb844b" + }, + { + "kind": "file", + "path": "img_4058.jpg", + "sha256": "7b714ea9ca969af4a7a9bae0e662f70056a3d9fc0fef48c3a68079b3b57d56f7" + }, + { + "kind": "file", + "path": "img_3737.jpg", + "sha256": "4750cbd58c52152eeeb124e56e418368b641dc340d23b02f4b8f78665df0b55a" + }, + { + "kind": "file", + "path": "img_4689.jpg", + "sha256": "80dac8fedd751b9e2b2ff4d3093f850d851de9f7c89fcc7d5c25b80778bc2014" + }, + { + "kind": "file", + "path": "img_1097.jpg", + "sha256": "501951278aac37d8dcc0e2e64d8628e5e289656c7689560dea545fe681bad78d" + }, + { + "kind": "file", + "path": "img_3119.jpg", + "sha256": "6fb3a975d6156d80b0d2af589e7ada4a1a38224579807830929e9317b2c677c9" + }, + { + "kind": "file", + "path": "img_1.jpg", + "sha256": "6dd7946deb14cd2a81641db85099a930d067d0b6f1e1b452869311a6785f2782" + }, + { + "kind": "file", + "path": "img_2950.jpg", + "sha256": "7db459c8b0db87c08a827180c78bf221cc3d25032e1b52ae9e4e048ccd40fc02" + }, + { + "kind": "file", + "path": "img_1518.jpg", + "sha256": "cf839b5027338c313b65841c6a167208cba715f71dc8afd334c58ac00db8cbbb" + }, + { + "kind": "file", + "path": "img_4306.jpg", + "sha256": "07f00646bcc9a8f9a7b4305d9ca605c082bc27d2a5d653757c12c41bd5ee07a3" + }, + { + "kind": "file", + "path": "img_2763.jpg", + "sha256": "1b7587e2646a8a4bce58ae1ba4bc7d70f733049faee4902e074104bffeed2aeb" + }, + { + "kind": "file", + "path": "img_2005.jpg", + "sha256": "b593510f0b41d18dff82cc236c2d99a8e9a1c521670d1b29ab6d202cd7114700" + }, + { + "kind": "file", + "path": "img_3333.jpg", + "sha256": "e899f88dbd66fe31f328423b0d46a3b36f37d45a9ecd2aa5e7a8bc72da7e9abf" + }, + { + "kind": "file", + "path": "img_2993.jpg", + "sha256": "55aba1f94f5fe2affa14e21a79db3f3eb1e998c3e62ef3159792d04af30a5d1d" + }, + { + "kind": "file", + "path": "img_1242.jpg", + "sha256": "8e7280c3085cfe1c98de155729db68feeac094a0e51de01126341e63b771dd17" + }, + { + "kind": "file", + "path": "img_1256.jpg", + "sha256": "562aa7c706b63314c5b6dcde7210a0f44315a1903ff6108aa5850fd423102288" + }, + { + "kind": "file", + "path": "img_3441.jpg", + "sha256": "644844d5b1468b3517d7144fe9dc231faa0a4ff2ba603f3c074c9947fc483478" + }, + { + "kind": "file", + "path": "img_3327.jpg", + "sha256": "3ca77db1d8da1c9e5138eb95b2817035c0635e4e770ce748de26050979b2ce84" + }, + { + "kind": "file", + "path": "img_1530.jpg", + "sha256": "052a177b32ed9a45fe774c4c0436693f957a1fb160df6ef8a1f264e6e5d64a79" + }, + { + "kind": "file", + "path": "img_2986.jpg", + "sha256": "02cba3d25ed1f2487b45ce3c969282dafc5c1c4c64b2b770806d663050c863f2" + }, + { + "kind": "file", + "path": "img_1257.jpg", + "sha256": "75d94836cd8f7a1e40d8eb00768f14efcbe9361fcc5f067a95c051b635e4baad" + }, + { + "kind": "file", + "path": "img_2762.jpg", + "sha256": "13835bef6b5486e90bcfacb10acd13b8264f77349a1b29b63f9e3608496cf65d" + }, + { + "kind": "file", + "path": "img_4475.jpg", + "sha256": "7f6ed38744cabe3f8eebdd5138dd290324ef6a24bf6680ba2ee287bde7c96bee" + }, + { + "kind": "file", + "path": "img_2004.jpg", + "sha256": "9075cfea1010dd654840e20e0175f0cac2a50910e803e45929f0833b38ee9c54" + }, + { + "kind": "file", + "path": "img_4307.jpg", + "sha256": "c77cd52e8355402db56d68acddc71a1de5ab1284c540273659b8a0556234194e" + }, + { + "kind": "file", + "path": "img_1294.jpg", + "sha256": "663963eb670ceca50a9b6c5fb12f94c9604dc8f66e05f4f1be8c93907019f393" + }, + { + "kind": "file", + "path": "img_1280.jpg", + "sha256": "5ae22426b46d00c5a28e7fef4343763b58d0eccabb210d7422829f1705fa4911" + }, + { + "kind": "file", + "path": "img_4893.jpg", + "sha256": "39b39f4c081d903ea52976c06219e9c7dce5a7f6a54b825d951b513f030e7b89" + }, + { + "kind": "file", + "path": "img_3642.jpg", + "sha256": "569ae852cb26070a28daf37adc829b06cc798e9c78ba60a3ca6992d1605134c9" + }, + { + "kind": "file", + "path": "img_2548.jpg", + "sha256": "c07ca1023bd94815f06367312d20681eb2292ad9b93097dec7288c3487da987d" + }, + { + "kind": "file", + "path": "img_1041.jpg", + "sha256": "1af5afbf4cd1916d6f439b5da504bd374e616072e3adf387db170cbbb7a6ba84" + }, + { + "kind": "file", + "path": "img_4887.jpg", + "sha256": "1cf7bdad12919ebe2755af44f594db0768833013b080c889cfa59cf8cecb2bf1" + }, + { + "kind": "file", + "path": "img_2206.jpg", + "sha256": "bf9ccfc2596bc8c7de5a81b7bf1285b695ac13f63504f24224a4be15ca87bf70" + }, + { + "kind": "file", + "path": "img_1069.jpg", + "sha256": "bc4c73b7fd66517047acb4e848cca154ffc19d566dd037bf4a11616d9533bb3a" + }, + { + "kind": "file", + "path": "img_2212.jpg", + "sha256": "484b09b568a1ca08e96b82518f1d6301fbfb773e28493c9bc4cc73f4d49d7058" + }, + { + "kind": "file", + "path": "img_4663.jpg", + "sha256": "1b1c109bdde8150c7d4307f583bb234ab8fcf14f34f4562bfef3745590667849" + }, + { + "kind": "file", + "path": "img_704.jpg", + "sha256": "23fdf0d8dae75d389e5ed1a02dbce4ba78d90e7f03c5c8ed8e6d634bd73662f8" + }, + { + "kind": "file", + "path": "img_1914.jpg", + "sha256": "40db64bd9cf3c44df389770b39a9d18df9f86cf6f18a3c628754737caff44ee9" + }, + { + "kind": "file", + "path": "img_4878.jpg", + "sha256": "a95f1a8f885bbd7ec3b34d9093ee9b102f746f256f2763c477eaf296cfa9a0bb" + }, + { + "kind": "file", + "path": "img_1647.jpg", + "sha256": "a55f2e3bec545492bffcf35a80b8119da60522488343633a34ff8f60e9742369" + }, + { + "kind": "file", + "path": "img_1121.jpg", + "sha256": "264d0308d1a0e1c8cdfa0f5aace2a9898c4ba733fda6c8cb8a0c81f8e1ea1c39" + }, + { + "kind": "file", + "path": "img_4703.jpg", + "sha256": "07c7fc7036188b72c887ec23b0b173aef196d94ac617525e55258058fc850f95" + }, + { + "kind": "file", + "path": "img_2400.jpg", + "sha256": "f540ded9e71d7155db1216a12f2dcac56c8d0c34f63a53c8ba30c8b2bee49686" + }, + { + "kind": "file", + "path": "img_4071.jpg", + "sha256": "033b0d45831fdcb0523a1a4a34f63a7ce5381a5c98d71f20c61971a4ee4f4b29" + }, + { + "kind": "file", + "path": "img_116.jpg", + "sha256": "56f3eb7c29d9ee1a06ba71d9f9bce0ad9d211470c129831b4e8e3d2e75e4695d" + }, + { + "kind": "file", + "path": "img_3939.jpg", + "sha256": "3a5ff4bb664a1ac3d0624d07c7d106786a1e44d9764a7c07ea2b23ee72911eb6" + }, + { + "kind": "file", + "path": "img_3911.jpg", + "sha256": "00324e743c02d5cddd12fda228329014ca2c99da651f6641453ae6750786e6a8" + }, + { + "kind": "file", + "path": "img_3905.jpg", + "sha256": "3236c9a291f07e7b5d8d8262aad1278e302adf4a320d290c0b60a243f041a56a" + }, + { + "kind": "file", + "path": "img_3534.jpg", + "sha256": "40ab4689a14d9c14c4dd6d6a9719202f6b1a5ea67de81d41472b9c1f62d5784c" + }, + { + "kind": "file", + "path": "img_1323.jpg", + "sha256": "106e66f17596aa51d634d310b70d37f289d431d9a56d03db5f37b9e05b925ba5" + }, + { + "kind": "file", + "path": "img_1445.jpg", + "sha256": "0105693326221bd76c7418e22eed05b43340804f61da82f63205e8aaa169bc18" + }, + { + "kind": "file", + "path": "img_1337.jpg", + "sha256": "7ce515bb79d13c630095fd5646e6359bac29c012f2af6efeede019a11865cf65" + }, + { + "kind": "file", + "path": "img_3520.jpg", + "sha256": "abf71e4205eb41369b7cb672addcfc989bbf15982217afbab7fcb8be8a6f92fb" + }, + { + "kind": "file", + "path": "img_3508.jpg", + "sha256": "f4e21d170cc9d6750b47ec947a087840d909ee0505247da0ba07d7fc5a890966" + }, + { + "kind": "file", + "path": "img_11.jpg", + "sha256": "a79b29364b9ab7aa8abf1d3ddc7c3cccfc645ed7f7a41b89489b96d2efff22a6" + }, + { + "kind": "file", + "path": "img_3291.jpg", + "sha256": "1a80e8a0efa51fdc6fb9060e8fa39e43a1e0203f206890938b8b0182e53dec2d" + }, + { + "kind": "file", + "path": "img_464.jpg", + "sha256": "8d68a288082569449b3c9df53d821a3040e5c0351cedd4115ef1b08e1e4d42a5" + }, + { + "kind": "file", + "path": "img_3293.jpg", + "sha256": "f0df6745e26d4e9320c2fbb6152eb21dca589267e7363fb22322fd3f3cdd9ee8" + }, + { + "kind": "file", + "path": "img_2833.jpg", + "sha256": "544aace00dfa09bcb517c73aa5fd52a7b3eeb616a2a383c69b38e82379f9f455" + }, + { + "kind": "file", + "path": "img_316.jpg", + "sha256": "f61cf622bf1a9dd12e79a9f8f83b189b7e2092ea8bf7038a16267241e5987f98" + }, + { + "kind": "file", + "path": "img_3287.jpg", + "sha256": "1bc41690e383153a9a2ae1a8b5e7880c759a485bb380ed99f967d3c820bb30bb" + }, + { + "kind": "file", + "path": "img_1490.jpg", + "sha256": "299c33d3df1ce43d2ddb4d60e77f304ae8d9a0df1b9f279f378f90c81f796a1d" + }, + { + "kind": "file", + "path": "img_2172.jpg", + "sha256": "a82383a3110bcc373624967a880141a85a34a72384f8eb7e0415010f70d36308" + }, + { + "kind": "file", + "path": "img_3278.jpg", + "sha256": "f3ab6248f4aec28e4be5d8316b5436a15855a43e4af334865ca0162bb71bc056" + }, + { + "kind": "file", + "path": "img_1447.jpg", + "sha256": "99c4c681cb4c2335e231484d12397875bdd532859df48437ab9058571b787a0c" + }, + { + "kind": "file", + "path": "img_4259.jpg", + "sha256": "e2a6f6830aaa6493c0c52d2ab91ced23f74a50b2f91b70703cc6a513e7f94299" + }, + { + "kind": "file", + "path": "img_1335.jpg", + "sha256": "007f4082c757e4e46b065aaf8005336ee6fa2a692736ee1efd0697491b7d31c5" + }, + { + "kind": "file", + "path": "img_896.jpg", + "sha256": "15771a25085dbbfda8e44178a706f89a4ad0a85d1cb88d1b565164d019dfd240" + }, + { + "kind": "file", + "path": "img_128.jpg", + "sha256": "f466b18aa8e24347254be8699f510995579cf0430d67268e21a6b66b5d1d1b02" + }, + { + "kind": "file", + "path": "img_4098.jpg", + "sha256": "b0cb7831b009cf73f8b2a9fd2caf425dafbe59afef8d371bc4234e0af1faf0ee" + }, + { + "kind": "file", + "path": "img_1679.jpg", + "sha256": "ce3ba88d373c8b7e7e29d2db1ecdb770647d46d6a9f97f102be5bc31a49358aa" + }, + { + "kind": "file", + "path": "img_2402.jpg", + "sha256": "cdac4b9a830194ca6946fa2769a6504750c13b7be2fabcf44956b6f77e3df259" + }, + { + "kind": "file", + "path": "img_1651.jpg", + "sha256": "e639048dc66b298baee4e3946512e404be41e75ec9dbb1fb97aacc3e1f082a14" + }, + { + "kind": "file", + "path": "img_1094.jpg", + "sha256": "678aa202f2e8e309078d03d2d7651e7f0e0bfa9223ad9f21be4a246bf40fb059" + }, + { + "kind": "file", + "path": "img_3683.jpg", + "sha256": "349e046c111ccc0b854f342b7d764371344eef8656e237b6d41cdab6ce4e3e94" + }, + { + "kind": "file", + "path": "img_712.jpg", + "sha256": "cb2d22b870eae7506faa556588f191386cef5e14457c389f53bea598b82d4ffd" + }, + { + "kind": "file", + "path": "img_3697.jpg", + "sha256": "c4a9717ab3d1872bd46d4dd91ea9a7602f2b29581220668e7b46fe3b907a7aa8" + }, + { + "kind": "file", + "path": "img_2562.jpg", + "sha256": "8566d887e63c91c99ea8993771769afcd3eed38ff8643618a12c4221b5a15b92" + }, + { + "kind": "file", + "path": "img_2204.jpg", + "sha256": "a93df1b066b43555d3d8b8657af988f6c2826e25180c6fbb8108524c05de1e4a" + }, + { + "kind": "file", + "path": "img_921.jpg", + "sha256": "07affc0693ed9244e02e910538b0582776c10f5a622d192792d8b439d35aeacc" + }, + { + "kind": "file", + "path": "img_1057.jpg", + "sha256": "f08b3147dadf7ab83f0109b01251e2db1f7217f4e9939c616ff1b0396a1578a4" + }, + { + "kind": "file", + "path": "img_4891.jpg", + "sha256": "8b444f4b0d21176ee9cb08c97e85bcc1a95d82a88925def8cbf70acad159d94e" + }, + { + "kind": "file", + "path": "img_2947.jpg", + "sha256": "e301eb6f395f869a4f162eadcb3ee41be5f7630717ca8886c2c3f0b7c2fb47ec" + }, + { + "kind": "file", + "path": "img_2760.jpg", + "sha256": "3141e147cc61ffa3a8ca7d4a3cff578122dadb3b52afe1433d53dbb717acd09f" + }, + { + "kind": "file", + "path": "img_2774.jpg", + "sha256": "b3c277fadef9824a80e4eb21497ee6193948c123a2ca760aa4c3af2dac94d3dc" + }, + { + "kind": "file", + "path": "img_1533.jpg", + "sha256": "2884a30cf9bd23ceebe62221d773a8247477435d355a6a6d76b1edf343551b81" + }, + { + "kind": "file", + "path": "img_1255.jpg", + "sha256": "d3661d48e209a6778161258a2a3ac96216d58f0fc77dc8d5b783b54beede49cc" + }, + { + "kind": "file", + "path": "img_2748.jpg", + "sha256": "5622014f98996917ded2d964e27e8d39d5c79e419a288dcf9fa7ba186787ee5a" + }, + { + "kind": "file", + "path": "img_3325.jpg", + "sha256": "a697aaacbf62eb9ac10be139a902351207d7988cbeb7085eef2eb3d5f0fb22aa" + }, + { + "kind": "file", + "path": "img_3443.jpg", + "sha256": "51b0c9b60c9e215dae170c575ab440c2d6f1b35d6d50d4c0590bd3748d77eeb3" + }, + { + "kind": "file", + "path": "img_2985.jpg", + "sha256": "3b7f13afcd285bab89a2f6f84206892c3e42244f20f90f672ea324f635ae4667" + }, + { + "kind": "file", + "path": "img_3319.jpg", + "sha256": "7ef084993ae60c45a55c487860fcc2321990f71f1d9d0c79fa16e89a212bfd17" + }, + { + "kind": "file", + "path": "img_1268.jpg", + "sha256": "c9ef8bf091d326632692c3df709317e8b97df3b7638caab950958ab1da80c6c2" + }, + { + "kind": "file", + "path": "img_2952.jpg", + "sha256": "38d27e550d3cfc8490c796cd8b4d2d4fc71c27f2c004679adbb6704790fd6976" + }, + { + "kind": "file", + "path": "img_511.jpg", + "sha256": "012312470e9b9e0cb8b58f333b264a96b2befef8877a653e2062a45833012c5a" + }, + { + "kind": "file", + "path": "img_4884.jpg", + "sha256": "1dd132d41993a0bdcf8f97a605e981bf01c073178a1f8302cb5ec410cd3a75b7" + }, + { + "kind": "file", + "path": "img_3655.jpg", + "sha256": "9fb330561beec52f855c0b959178a757986a8081a59a7af550aaec5d58389337" + }, + { + "kind": "file", + "path": "img_3641.jpg", + "sha256": "4ea9ca173e7d28f838eb8bb31d9f63698dff6476ae4641edef321ba1202a6437" + }, + { + "kind": "file", + "path": "img_3899.jpg", + "sha256": "8689623db134512714f0720ef91cc835ca4d62b579d97cfd1f87592b60fd3fb7" + }, + { + "kind": "file", + "path": "img_908.jpg", + "sha256": "3df3e684a40c63d56d7fe54f8399945c7f8b65dde91b0e0fa49b880d9d02a47d" + }, + { + "kind": "file", + "path": "img_4890.jpg", + "sha256": "208514b524940b394351a6db94fc965ddfbaa226a704c9fc9fe67294c9238bfd" + }, + { + "kind": "file", + "path": "img_1730.jpg", + "sha256": "1c69a2a379a7976c683007ca461c07fbec0850fb2d676b5f0845732dca5bd305" + }, + { + "kind": "file", + "path": "img_1718.jpg", + "sha256": "5a1a6eff17175733c8548d1be1b355e3b58ca4866f582a1568089bf539be6175" + }, + { + "kind": "file", + "path": "img_3669.jpg", + "sha256": "e43e79f997d87fd4d7e55e9a4a37f2d73d5e4b8ab3980f859eefe16883933193" + }, + { + "kind": "file", + "path": "img_4112.jpg", + "sha256": "91c857a4424be08839f59e83a29847ffd2a9d6a95289abc8b55d7d32bc98b2c8" + }, + { + "kind": "file", + "path": "img_2205.jpg", + "sha256": "e2419401b355376982936d682700cd3df96f5a48d16eb1dde2963023709cdd09" + }, + { + "kind": "file", + "path": "img_4674.jpg", + "sha256": "599e33ca432f9e981741dde1825158a2ec0c74dc9b94b55e5fb8c7b5ac8b27ba" + }, + { + "kind": "file", + "path": "img_707.jpg", + "sha256": "6e1c2b69f03600d9742c64563697478f1ba62d2b3dbdcabfdeaa4b81d3aacd5c" + }, + { + "kind": "file", + "path": "img_4847.jpg", + "sha256": "013d6ae586b0cef98a9aafaa28bffa2643105d75af6eca94bab9f2706e478c62" + }, + { + "kind": "file", + "path": "img_3872.jpg", + "sha256": "960d279ea4d6f35c79a1e5c5a5e44302d923c4c0c687e621c4cd55378e0f9a80" + }, + { + "kind": "file", + "path": "img_4728.jpg", + "sha256": "51af88288fdcc255efc7547f894ead6a80920b08fa75e54f2c2c4562393d5863" + }, + { + "kind": "file", + "path": "img_3047.jpg", + "sha256": "8734dd17f6e0a32aa0b63198baf566088006d21b4407c9ae8005c56b07d1b5d7" + }, + { + "kind": "file", + "path": "img_1136.jpg", + "sha256": "8193d8c19699acd41bdb31604185f0c67ddc9a6618308958b952618c7a208410" + }, + { + "kind": "file", + "path": "img_1122.jpg", + "sha256": "43f3d0314b0c689944fd06c3439835ff5089c92d892769bff25cb1a2a5f9a153" + }, + { + "kind": "file", + "path": "img_4714.jpg", + "sha256": "c07b87413c02dc4397d51da2887757cd43e053d1b853910fff4b191c0e8e58eb" + }, + { + "kind": "file", + "path": "img_101.jpg", + "sha256": "a1dadfb6239db1546d511e593ebcf82e2563463ffb6bfb2f994be96d65869b9e" + }, + { + "kind": "file", + "path": "img_4099.jpg", + "sha256": "9157220ca81d008d3ce56385b923bf32dc81e11f3f844a1ca2cdf66465178c37" + }, + { + "kind": "file", + "path": "img_3906.jpg", + "sha256": "1b1db29822a7e790e84ad5e9a3bb04229a06241fa7615d08fe206e67d023d879" + }, + { + "kind": "file", + "path": "img_1334.jpg", + "sha256": "d16744250ceddf824b0b3f5f0277793219397298f091d8ebfe808edd6bc6764f" + }, + { + "kind": "file", + "path": "img_1446.jpg", + "sha256": "93ff954991c8c9e1a02400e3290fec58e9fc27ea1047e53a18df99cfe0929c19" + }, + { + "kind": "file", + "path": "img_2629.jpg", + "sha256": "aa2ad6a7c6a36f80e0a58d2e9c2704dae1d576c5308343bb046c4dcd257089a6" + }, + { + "kind": "file", + "path": "img_1320.jpg", + "sha256": "e7caf505644dda1016a58a2ec4a3b31ffce510ea3cb0dd251b03fe7c4d6f1fdc" + }, + { + "kind": "file", + "path": "img_2601.jpg", + "sha256": "9899245e8ffa481059b3c844b271be3326851da33959b304e1b1a8c81fe75820" + }, + { + "kind": "file", + "path": "img_2167.jpg", + "sha256": "009cec2b07521cf92a7d4d6e28f1e0c0c2b7d6344f6776f3fa9df1280fde7dec" + }, + { + "kind": "file", + "path": "img_4516.jpg", + "sha256": "80c1a7176f71d8843f3f25dec5fad3385f48b162eda04f7ff5c05851ebe435d3" + }, + { + "kind": "file", + "path": "img_3286.jpg", + "sha256": "802c67847466870fcea8511dd2a7ee7de880b04e8931d52d8f3c4c3a8c377dd6" + }, + { + "kind": "file", + "path": "img_2198.jpg", + "sha256": "d17ad0fc6ec51f7687588790e8bd71914343ac80e2d7b0f21d79a835ededdb3e" + }, + { + "kind": "file", + "path": "img_303.jpg", + "sha256": "239054d25291f2d4177d5b40b7912c1abe43cda9a29b4eaf0d8218c9ce877c40" + }, + { + "kind": "file", + "path": "img_307.jpg", + "sha256": "6ff4ec31c4a4abb1b974d1f3e3c7e3d66039fbe0abe5cde32b222729c467cb69" + }, + { + "kind": "file", + "path": "img_3296.jpg", + "sha256": "9f43c22e5be5f2e3afe2ca22c9cc19e7150dc5186cc5aade92e7f4edb60db76d" + }, + { + "kind": "file", + "path": "img_2822.jpg", + "sha256": "1d623407022385386e77cbe5e7b8121359aa9e1875bcdd3a5d8987918f6ec827" + }, + { + "kind": "file", + "path": "img_1324.jpg", + "sha256": "dd03824666c3a9acbcc3fc3507a8832ab9a7fb7386c8096022a804a6d2b2d6f0" + }, + { + "kind": "file", + "path": "img_1442.jpg", + "sha256": "4b6a80fdc3706dc30205cfa278acfba5bc52b7d1d2c74bcf0f73b2bacb28bfe2" + }, + { + "kind": "file", + "path": "img_3241.jpg", + "sha256": "ef801cf503d21abed5224153aff624dee6e6befaa740aeb948b9254c5ff9f353" + }, + { + "kind": "file", + "path": "img_893.jpg", + "sha256": "cbca56e32a4fee88df7727b110bd8267dfe37b9d7167ede7f6b6614463d02831" + }, + { + "kind": "file", + "path": "img_3043.jpg", + "sha256": "c35625e5874cda732f8cae8a5f68d8a58b9f0100150b420ed0a9d4c5ad723fb6" + }, + { + "kind": "file", + "path": "img_4704.jpg", + "sha256": "6be4fac1293ecd73c3b787bf1cd4f214ff833a28da15699688ac512bceb1f473" + }, + { + "kind": "file", + "path": "img_2413.jpg", + "sha256": "995b5c2eaf4029405aeb15384889e7b56e7d446553d69b127d6fef694cc6a5ff" + }, + { + "kind": "file", + "path": "img_4076.jpg", + "sha256": "71276aa84a4fa1e060dd4839ca5e532f0f4b867f3a70ac0f0689a77394a37024" + }, + { + "kind": "file", + "path": "img_1907.jpg", + "sha256": "11456d7c649f21b0464cc7fc207cead675aafaa8cc3a8f0c9dace53ba6ce7532" + }, + { + "kind": "file", + "path": "img_1734.jpg", + "sha256": "e02ff7da29ea7b60342e5ffa7b44846783a66aee656302c09f7494413fbef7e6" + }, + { + "kind": "file", + "path": "img_1052.jpg", + "sha256": "b4b0bd8871d548c6a3a2c8fa5cb611320dc048578b7b76d14cda07ecd41f8942" + }, + { + "kind": "file", + "path": "img_3651.jpg", + "sha256": "e60f910d43f569dcf4f810176c171e8d365b2a32dedbbf5847e99ff21a55c115" + }, + { + "kind": "file", + "path": "img_4880.jpg", + "sha256": "2c69684ad6f5e08a2cc4c517c91080c78eda9963cc423072c4133784150deb33" + }, + { + "kind": "file", + "path": "img_2567.jpg", + "sha256": "ad3b08632efefed21955fb3e4aa52f6cf992572078b48a214665b7c46385042c" + }, + { + "kind": "file", + "path": "img_4116.jpg", + "sha256": "4fecda559aa675d303ae2d642908d7c2bffb09ebb37f46fff2f85e78bc5c0083" + }, + { + "kind": "file", + "path": "img_3679.jpg", + "sha256": "d73003d11473f42bf78f3c5142b1da0c9b646622000777083e92e437dc91219a" + }, + { + "kind": "file", + "path": "img_4102.jpg", + "sha256": "4066b2d379f2a3d04f0ac5e52920448483cb2fd3a732a2e24eff43f126be67c4" + }, + { + "kind": "file", + "path": "img_1536.jpg", + "sha256": "5313ac80ebbade276dd141e3e07693db27676cda9f2c5fbf7ae2658602a69898" + }, + { + "kind": "file", + "path": "img_1244.jpg", + "sha256": "911d4aed8233a8c240d4a26ae7c8e135280107e4a64db5bc488d7e24ee0ddc7c" + }, + { + "kind": "file", + "path": "img_2017.jpg", + "sha256": "64c5a80711e83103f70e4392c7947e93ca0bb0f384691e002f7b17bbcb363776" + }, + { + "kind": "file", + "path": "img_1278.jpg", + "sha256": "02ce456ee87e23acc482043175fadf30414d1292de1bf5c1c9a5fb7af78b9ebd" + }, + { + "kind": "file", + "path": "img_4473.jpg", + "sha256": "6729184f0c329b43f1438c55d8ab6f514ad91afcda7f72ed18192357cc2eca4f" + }, + { + "kind": "file", + "path": "img_1251.jpg", + "sha256": "eab02b50a30e101bc22a1928c583605227eb0423f9c0df13c6701c13ff0d6497" + }, + { + "kind": "file", + "path": "img_3320.jpg", + "sha256": "c7714e023d03b66e1a43c03761f32e528b6957906454b855c412b8898a4080cd" + }, + { + "kind": "file", + "path": "img_2943.jpg", + "sha256": "71cdd864b90a7c63c5cfef2a15da0416c8658d5cb8cd734ad2f4d9636ce53109" + }, + { + "kind": "file", + "path": "img_272.jpg", + "sha256": "1e5605c990e0b3f6c23ad15e8be1c006723167a98c3ed59c7d2fd5af794a7d37" + }, + { + "kind": "file", + "path": "img_2200.jpg", + "sha256": "beb0972c1af9255d6493f232648e4f58fa681b03bd8db672de57134b2858d6e9" + }, + { + "kind": "file", + "path": "img_4895.jpg", + "sha256": "d78f49f85618039e14fa77473d210f4ff756d5ce198aa1a5ca56d9d6e45ce9f9" + }, + { + "kind": "file", + "path": "img_3693.jpg", + "sha256": "bf373efe5d3e8713855ba124f221c5ad534059670e8046f27d662ab71008863b" + }, + { + "kind": "file", + "path": "img_4842.jpg", + "sha256": "64bff6a492f6aadbc1fa129334c3696f2186f8c8741d305af37d2b38f94ccf05" + }, + { + "kind": "file", + "path": "img_716.jpg", + "sha256": "6c1cb5280848198a9a1cee1c1eb8c6ec1915ac8dda5cdf5cc7ad753db546bd54" + }, + { + "kind": "file", + "path": "img_3718.jpg", + "sha256": "019c7a4d8dbe2d48cd35c1eca91fb57af137092e10e837dce3d6384dbed85c9a" + }, + { + "kind": "file", + "path": "img_2412.jpg", + "sha256": "e29316b5c44f82ba4c10d2208c0e41a4edd9e95e217534aaa44a429bb0dd5ed1" + }, + { + "kind": "file", + "path": "img_2348.jpg", + "sha256": "32e8f5bfe4be9b7406ddf68aa8c68e4c18b55b9a303f03edd58a8c8fcdad6141" + }, + { + "kind": "file", + "path": "img_1127.jpg", + "sha256": "5f79904080ec75a7cd9f4aec25b4eb389809386a6e299386864351ad25d17b47" + }, + { + "kind": "file", + "path": "img_3903.jpg", + "sha256": "6ac947c0d7259f3b8077394308f027d6f597f9ab162e4d18d5da1365e613bed2" + }, + { + "kind": "file", + "path": "img_886.jpg", + "sha256": "fe2298a187a22f35153ac7e23b03549b58539a20314a12d7c1de9dc9bfeed380" + }, + { + "kind": "file", + "path": "img_110.jpg", + "sha256": "18e6f5f809595d70c5ed63a657d4bddf472029049578fe9619c13fe1504523b2" + }, + { + "kind": "file", + "path": "img_4922.jpg", + "sha256": "0fc4e6b1854ba89ca9e8b2ca51815b564f8874f1287eef79e3845c019e278f25" + }, + { + "kind": "file", + "path": "img_4275.jpg", + "sha256": "713758812ec92ea017af5ffdf8912659104bcaec5378cd8491145869167c1a69" + }, + { + "kind": "file", + "path": "img_2176.jpg", + "sha256": "818aff324c5bfc33de515c974f80a0cfa95a7297e47bed8958ca4e650921f793" + }, + { + "kind": "file", + "path": "img_1457.jpg", + "sha256": "575648865d28d5348d68cabe0e3e95a37421c71ab3cd1a90c53e078dff76da62" + }, + { + "kind": "file", + "path": "img_4249.jpg", + "sha256": "5b9b9f53bbb2ffa43e6a6a2be4f59264fa53c1bdeb54393d3c1d783b6ad73d67" + }, + { + "kind": "file", + "path": "img_3283.jpg", + "sha256": "f374faa80a3212c8c49be26b713c463e8f2d86e389bf4dc2bb9e89b06b54988c" + }, + { + "kind": "file", + "path": "img_3297.jpg", + "sha256": "645724363c7c73fee5d317e0415c3a6fe9abcf29740a5c0d5bcb5bfb48d63190" + }, + { + "kind": "file", + "path": "img_1480.jpg", + "sha256": "4778a487c35e837d9d4b7cc42e377f1671bfd152d76431fb0a9b12469a616a4e" + }, + { + "kind": "file", + "path": "img_476.jpg", + "sha256": "48eeee9e47505aa87a73b0ad2e443b3452f9030d92e6084541088f652259a0da" + }, + { + "kind": "file", + "path": "img_1496.jpg", + "sha256": "24f55018073fab2d3caa17d9f197adffd85eaec395bfcf9d507470a6a6d0f2e2" + }, + { + "kind": "file", + "path": "img_2835.jpg", + "sha256": "423e21bde6b2864006bc936b5801d23e408676864e6a42f93b6a7d3acc58147d" + }, + { + "kind": "file", + "path": "img_3524.jpg", + "sha256": "7358ec9ba3dd95a045682f85957d605bc8927ee006b6272bf36869c1cdf93f86" + }, + { + "kind": "file", + "path": "img_1333.jpg", + "sha256": "6203e2e964274ae68f5538c1aafa8d4611c8eacdec4b77c7b947274d355888d9" + }, + { + "kind": "file", + "path": "img_3242.jpg", + "sha256": "186aaca105937e3e0b7f682fa88718c52db9309c52438d56e8a49d297219939a" + }, + { + "kind": "file", + "path": "img_2606.jpg", + "sha256": "6e19afe244b5a16a39ef61f714557cd2662226b39917dcd68b4998eacd7259b0" + }, + { + "kind": "file", + "path": "img_4511.jpg", + "sha256": "02d54a54e8a45cbd6c946f436c717caf0c1c3533c6baaf64ca2503b2ed6ee534" + }, + { + "kind": "file", + "path": "img_112.jpg", + "sha256": "2f424db962cf7b0f3ed05609fefa596af9c22c1598768f2238eebb664b159729" + }, + { + "kind": "file", + "path": "img_106.jpg", + "sha256": "26a9a391d28c0ef7c3049c912873917f2f1e98de98a3070c7daf717a554791f4" + }, + { + "kind": "file", + "path": "img_3097.jpg", + "sha256": "0cf4ee0117c3fb6f1f36d4457ebc69094886478c80fb24824c3734799b6d4125" + }, + { + "kind": "file", + "path": "img_1680.jpg", + "sha256": "5f09057d4d1f0bea9fbc9534d770563af55f8dda353f5474d8e0297e8c85e89b" + }, + { + "kind": "file", + "path": "img_890.jpg", + "sha256": "d6747804031c20848200d26051a2fcfe0e72d93466e0837e072b012142ab976d" + }, + { + "kind": "file", + "path": "img_3901.jpg", + "sha256": "844c4c7ae2a312a9aa32cf34b4320ccb5f6dbd168f2c7658bd5c57b3d6803281" + }, + { + "kind": "file", + "path": "img_4061.jpg", + "sha256": "6f2c290426819d857abea03e8c7455af72defc983b4b4add41b99052b04edd02" + }, + { + "kind": "file", + "path": "img_2410.jpg", + "sha256": "57c22bf04e7cd8cf6c1dbd1456466a031e9581c2c733af278022daf5abc2aafe" + }, + { + "kind": "file", + "path": "img_2376.jpg", + "sha256": "6dd1ea3a084a3255323392e1b839489ebc9683bb52ec6d6a9e97993161b847ae" + }, + { + "kind": "file", + "path": "img_4707.jpg", + "sha256": "a22930cb8bbac18e6d3aedf1db92d3e744d6d8bcfd37fb9dfadd96f0a10e87ba" + }, + { + "kind": "file", + "path": "img_3068.jpg", + "sha256": "a9e1d74d83e467a185ba15ebc45cdb0a5f56d18facf31b421e937ecbb5ae6851" + }, + { + "kind": "file", + "path": "img_4840.jpg", + "sha256": "55f8d83ebddbcf0415efb1ef2b35767b9cceb8d6ab2daeae1b118fd9d41d9bc6" + }, + { + "kind": "file", + "path": "img_700.jpg", + "sha256": "bcdb2133fb981f008f441c261218121b033cefa946d6cf309dbd4ba384a05ccd" + }, + { + "kind": "file", + "path": "img_3875.jpg", + "sha256": "2cf328a2e05cb03b6525bdb6698dcdb5574505518e238b2143dcf53f46f28b4c" + }, + { + "kind": "file", + "path": "img_1045.jpg", + "sha256": "6768870d8290dac8d59ff83e70e762aad0e6b071fb1655332cfe65fa4730a458" + }, + { + "kind": "file", + "path": "img_1051.jpg", + "sha256": "88fa9fb792e414cb8e63333533ed41a8666a3a8cee572ca7fc8948ada132103d" + }, + { + "kind": "file", + "path": "img_1737.jpg", + "sha256": "513820ac18e83eea5b2527df9acfd9c0f9e98cff1cdf265835dfe9356551f044" + }, + { + "kind": "file", + "path": "img_1284.jpg", + "sha256": "f1eaedd1c0a86a14955c79c944c5e1f43cc3f8525c1958e12b9fe2bd65fef7b5" + }, + { + "kind": "file", + "path": "img_2799.jpg", + "sha256": "850c047aa4194d56f1fe0169bb8dcbe5974a0828db6781925843530809681da4" + }, + { + "kind": "file", + "path": "img_2941.jpg", + "sha256": "c0e05176862d450f92b399a4969055a2aa7cc7afc7d47cdf2365c927f6031b4b" + }, + { + "kind": "file", + "path": "img_2969.jpg", + "sha256": "7254622f86a13fef93e0a9ac0f22edddafea688854f15e4ef1d5ab5a06054f45" + }, + { + "kind": "file", + "path": "img_2996.jpg", + "sha256": "36382d5b1784f26bb19f430afb4d7ad7c2268adf9d50b4783fc99fd72d771a23" + }, + { + "kind": "file", + "path": "img_4459.jpg", + "sha256": "5043996eb23289f92e1fcf5f6b9c38d7d79030425b65fdccf8964590f72f2ee1" + }, + { + "kind": "file", + "path": "img_4303.jpg", + "sha256": "7faa7fe5d8153642febfe2553c86cc93daeb1d906b506bf9cfb0d88cad7a6430" + }, + { + "kind": "file", + "path": "img_3478.jpg", + "sha256": "90b25649992344e621e03dccf3dfa672c397b6ad8123dc663cafb8237a133f61" + }, + { + "kind": "file", + "path": "img_1508.jpg", + "sha256": "49066442fbf4c96c4af10086c50c432bc8e1177d47759e387b37349597b83bf9" + }, + { + "kind": "file", + "path": "img_2767.jpg", + "sha256": "bc5b54126620af73270b1781971a73fc860dcf53839a1212554c51f6a72d7618" + }, + { + "kind": "file", + "path": "img_3479.jpg", + "sha256": "07798c789cef10b3b241bcc7d007ad851e8820c238537cd83509ffeeb8166a06" + }, + { + "kind": "file", + "path": "img_4464.jpg", + "sha256": "47ac223c71ca13288fef45ad8384111c8db138676f8257a00db841f037e483cc" + }, + { + "kind": "file", + "path": "img_2029.jpg", + "sha256": "2c24cba27c007ea90a19f1c337d33516c3eab2e7b5928a80f8512eb54e3f6bdb" + }, + { + "kind": "file", + "path": "img_1520.jpg", + "sha256": "58fa4a5b0360eb23c312c0f5550bc9ddcccda9551808e4c1228967a56c725632" + }, + { + "kind": "file", + "path": "img_1291.jpg", + "sha256": "5dcb644e4d0eaa89a94c02736dcd666e10135639c30b8959a18e0618a4de0ab7" + }, + { + "kind": "file", + "path": "img_503.jpg", + "sha256": "21d56381e337dbac89bf2b2df79b275fed676fa8988caa0362b7789a28e5662b" + }, + { + "kind": "file", + "path": "img_926.jpg", + "sha256": "0f2bc8d14b177de3ea66876659b736bd82a0b6b9076f5d56b1da4abcde6264de" + }, + { + "kind": "file", + "path": "img_3121.jpg", + "sha256": "e97ae23ea2898b97654f7e36e0902d69e690717c3b32cd70039c563c839f6e65" + }, + { + "kind": "file", + "path": "img_3860.jpg", + "sha256": "0820beda28b525b67a740d2de28aae607a12ea9b518093146b65a778870052e4" + }, + { + "kind": "file", + "path": "img_3874.jpg", + "sha256": "ad6624eb7079c786e435f7780ccf49a82766c422ab4b806952e6e28386db4b64" + }, + { + "kind": "file", + "path": "img_3684.jpg", + "sha256": "16cef993673c9f141214ab8481ef507006d183acafd9ffcacdc0caf8279750f5" + }, + { + "kind": "file", + "path": "img_4712.jpg", + "sha256": "e30617592cb60b11a960b1c7ff750e05462cf76a909facb5fb987dc1e0885bba" + }, + { + "kind": "file", + "path": "img_1124.jpg", + "sha256": "3867be435b954f1eec02364fad3511ba0b6bdd0d8bc4ce0714ce739e3435b8d1" + }, + { + "kind": "file", + "path": "img_3733.jpg", + "sha256": "a2cb04edbb6a2e8eae8aa0b7999f902b39679d22d6257bcc0dc4e616d058715a" + }, + { + "kind": "file", + "path": "img_1642.jpg", + "sha256": "4f7a027a95c73e9bdb1483a5c3c045cc04ade3693a7660cf9acfcd6bcae3c835" + }, + { + "kind": "file", + "path": "img_4048.jpg", + "sha256": "d2348959682097f83e4e9fbdf04c6c096fe120d1b6197c35d6e8530ec096f44c" + }, + { + "kind": "file", + "path": "img_3727.jpg", + "sha256": "dcbe51cb641849040567ea699afd797f9bc09387921d0ebcb180590ec244e4ad" + }, + { + "kind": "file", + "path": "img_1871.jpg", + "sha256": "11c65bc1c50cb953ba9885e367291d2bb93391ab7151d92105e1446835d4d357" + }, + { + "kind": "file", + "path": "img_2613.jpg", + "sha256": "b530e6bcd7cfb82d0729123ea6f06c7c7b3bb0baaa9bd3d854cc4782eebaa3d6" + }, + { + "kind": "file", + "path": "img_1326.jpg", + "sha256": "b472b87b609145f4ce3ca40ac5457aadfc16cf23c5b20312bd415d3f388e24e2" + }, + { + "kind": "file", + "path": "img_463.jpg", + "sha256": "9a6d146c46b350becbfadd280d7677b8858b2c2bacef05ad0650375b16f7270f" + }, + { + "kind": "file", + "path": "img_3294.jpg", + "sha256": "ba2711dd3609e7721d6cbb529a4659ba737f4cdc3668852a3ba23b7cd2164843" + }, + { + "kind": "file", + "path": "img_2820.jpg", + "sha256": "d49cee787d7cfc2b44e228294219d5c037760e6a2ff306fddd8133a11e5d29ea" + }, + { + "kind": "file", + "path": "img_98.jpg", + "sha256": "6f12977674954326ea3e7498be264f7b277c079a72ad06359ae84dbf78fc4fd3" + }, + { + "kind": "file", + "path": "img_2853.jpg", + "sha256": "041ce149e3f72eed6da0922b9536b8e593f9bdc3bf40f3bab04cc6907b1ba0c2" + }, + { + "kind": "file", + "path": "img_2106.jpg", + "sha256": "f1b38900629792fb0abe2613d2182be9fad94ac4b9712a1fd605f33c08ca39fb" + }, + { + "kind": "file", + "path": "img_2112.jpg", + "sha256": "32cfec6c243af7e1700211050cd3c772a18f8583d32c5cc6341b574b4cda0094" + }, + { + "kind": "file", + "path": "img_4239.jpg", + "sha256": "050af89ba53dd2ab43cf258d3e82ac00dbb6284bcc9415302464cd11af5f103c" + }, + { + "kind": "file", + "path": "img_3967.jpg", + "sha256": "fd9b4d9907b041dd3d7fab52d11f4126508cbc1b041d033805a0fe357b742219" + }, + { + "kind": "file", + "path": "img_3973.jpg", + "sha256": "d2e95f04a170565bf8f977a284221713f3a3f023f8e6d80a6a5bb562592f1c1b" + }, + { + "kind": "file", + "path": "img_1194.jpg", + "sha256": "7de6e3e691e5fc2ca1c5e6af222110dc959dd807c967340d5b494619196dcb99" + }, + { + "kind": "file", + "path": "img_160.jpg", + "sha256": "0cd63b76544af443032288a44917b55819a307081a973a17b36c3506ccefc703" + }, + { + "kind": "file", + "path": "img_1619.jpg", + "sha256": "c1449fdf2282443e69432ee04adbfff78e51edccdc655413d26d8f54e65f6bb1" + }, + { + "kind": "file", + "path": "img_821.jpg", + "sha256": "06045feccde31055aaf7a015c62d6a80905d1b6917e5884ed707ea2a7491d7a6" + }, + { + "kind": "file", + "path": "img_809.jpg", + "sha256": "1335467970fe5b29672504ffa9fec086a53e4514e11e3a5627b9032d69ec1e84" + }, + { + "kind": "file", + "path": "img_3026.jpg", + "sha256": "4f5bc075c98b66b22e47d466c22b526992832e8cee24e2ea8d4a398ed4d81754" + }, + { + "kind": "file", + "path": "img_4749.jpg", + "sha256": "6479563e2dc6aaec3cdba585fdb7ca511df8c821e5c68838142448a9d5c958a4" + }, + { + "kind": "file", + "path": "img_4826.jpg", + "sha256": "8b5d863eb3fc9f7e3bff1a7f092e2fb24e87c64b5cc195f15376d0cbc87889f4" + }, + { + "kind": "file", + "path": "img_766.jpg", + "sha256": "6f87727d5a398537452bf657009e8d165f703864cb489ad857e722a63b925a6b" + }, + { + "kind": "file", + "path": "img_4198.jpg", + "sha256": "7e0704c167e933c512b2f3137014ab242747637adb3d0f56363ba3b87f88b411" + }, + { + "kind": "file", + "path": "img_2516.jpg", + "sha256": "3c8c4dcb29a0ee6600b1306e33a148b009841f621c577db7759705588d531560" + }, + { + "kind": "file", + "path": "img_4167.jpg", + "sha256": "287d8f3666180433c8457f3d5cd38c6916611403599e15886ff65ffe62597a70" + }, + { + "kind": "file", + "path": "img_4173.jpg", + "sha256": "9a0cac57e3b7d34bf752960567afdadd0323db961f7cda97e112377480713e25" + }, + { + "kind": "file", + "path": "img_1023.jpg", + "sha256": "0412b9f7460847850cc9b0b7f73ee7e3d7e08a379dc9f7fecf61248daf89fa63" + }, + { + "kind": "file", + "path": "img_2258.jpg", + "sha256": "7c62e1dc1f1484486d15d53c6b750a67dac868a1baed88f558e18cd3e38ac2f5" + }, + { + "kind": "file", + "path": "img_969.jpg", + "sha256": "b2ef234d5b99da3c21ddc853b7e90f2f7dd357d7448744b8463e9486a61b7788" + }, + { + "kind": "file", + "path": "img_1584.jpg", + "sha256": "6116904e37bfa9543665860475a52db13cf40b541e806aebfcfa72527b9ee830" + }, + { + "kind": "file", + "path": "img_570.jpg", + "sha256": "f6bcf0d3128e00ceb0ec3944045d5678d58d31b8de5f86f4035315403ecae74e" + }, + { + "kind": "file", + "path": "img_2099.jpg", + "sha256": "45d3370275630421cceae5800b12d99eb18967b7b08023d10abc1094ae3e1cf2" + }, + { + "kind": "file", + "path": "img_2072.jpg", + "sha256": "f6e76598a3b697e33a26cf2ff5afac3c531b673a91c2feb9d1b4f3a911d56d5c" + }, + { + "kind": "file", + "path": "img_2066.jpg", + "sha256": "2bfbd8e5de90b1a8bec3798920a04b93112914e29273c489c351f15ff682f0b6" + }, + { + "kind": "file", + "path": "img_4417.jpg", + "sha256": "28f777b4f688710269849027e05a784ae8000b889c5ea8501fc3244a3c5c008f" + }, + { + "kind": "file", + "path": "img_1234.jpg", + "sha256": "d0302c19097b32a4a7fca71405748af5c87a56bb235a17222feaefa8372fd996" + }, + { + "kind": "file", + "path": "img_3423.jpg", + "sha256": "2af7d808ca4a1f50f44b7875feb7176a83b674bcd3734df6c6b727d4deb6fe4f" + }, + { + "kind": "file", + "path": "img_4370.jpg", + "sha256": "9ca732ebf5c994035b705414d04ca0c2f22b35121262d9fd4f8adf6f93481482" + }, + { + "kind": "file", + "path": "img_1591.jpg", + "sha256": "826f5bf28070a6a08e443a1ba6eccd61b3231dc821d8d17c98952fe455120104" + }, + { + "kind": "file", + "path": "img_2098.jpg", + "sha256": "308592dd9dcfd34893513e610cdf22fd2b981accacce471a6803d8bfa22562a9" + }, + { + "kind": "file", + "path": "img_1988.jpg", + "sha256": "6e3c8fe5592b4ad652a8b7198b218372421c9eb9ecbbdc9aebe341b4570b41f9" + }, + { + "kind": "file", + "path": "img_3147.jpg", + "sha256": "6ad98ba5cc1e157ad10aca99685d7bfe97f70822bdd0203ac135a3d2a91081c3" + }, + { + "kind": "file", + "path": "img_954.jpg", + "sha256": "ae5e64478e14ebafc18ac2af12a10317e48d4f9b291523df58182e98ae17c621" + }, + { + "kind": "file", + "path": "img_1778.jpg", + "sha256": "02e800e77f3590289b5d1304678d917508da047b709964d3af63f83ed5c6b427" + }, + { + "kind": "file", + "path": "img_773.jpg", + "sha256": "276299517f4c7381e5ff16fb0f904f0dba4d879db253669a1d7ef0b18d87d03b" + }, + { + "kind": "file", + "path": "img_3184.jpg", + "sha256": "8b54dc4f7cb743e95d5d684fb9347c9ea577a060207b0987768d8661e9002dbf" + }, + { + "kind": "file", + "path": "img_767.jpg", + "sha256": "489fe8d949583c6d56ef2da64de74f5b5556ed058dc32de5409b470de1d84f27" + }, + { + "kind": "file", + "path": "img_3806.jpg", + "sha256": "5bbe4367d656911df5ac89da178393ffacb5c01606bc70ce193e7cc38aec83eb" + }, + { + "kind": "file", + "path": "img_1977.jpg", + "sha256": "f31f6bfc5474e05bcdff6f836e84d936db143c4c44179248985317ce7b4fde6e" + }, + { + "kind": "file", + "path": "img_2339.jpg", + "sha256": "ae581b4ac785fd4a77d980295ad90a395c51d51a43efa3854e766d16ad90ee1b" + }, + { + "kind": "file", + "path": "img_3999.jpg", + "sha256": "614cfa16d1d6314b814e9535ee001422a9ccf0897463b094dd7a4f664705242b" + }, + { + "kind": "file", + "path": "img_4760.jpg", + "sha256": "27172290d7b7c013be347f5d4b06c260c17c59b8dddfb76d60be28c4dd0911b3" + }, + { + "kind": "file", + "path": "img_2311.jpg", + "sha256": "0a1917b4009443235651ac7c9e41f99edccecf1f981b7b4d899888bec00d6992" + }, + { + "kind": "file", + "path": "img_1618.jpg", + "sha256": "d6bf034144a860689058dfbc024ec5a8fd977525733e738853c1adf329dc471e" + }, + { + "kind": "file", + "path": "img_4774.jpg", + "sha256": "8c9af16c1e8def46412f118d9fdb5a217d86be4f9af0bfe6622df4d6b5d27bed" + }, + { + "kind": "file", + "path": "img_834.jpg", + "sha256": "4ac4b5b13aa6301a5d8129f26d214d464311d55fef113938528c598a106dfbd5" + }, + { + "kind": "file", + "path": "img_1181.jpg", + "sha256": "4e9bb33f578d12dd091c2c85a999c66ad0978102e0344a9f5e5ecb0fe098feaa" + }, + { + "kind": "file", + "path": "img_613.jpg", + "sha256": "91e9400a095d3487c38fe11eb60404fe5b26390acf177999cd1faac1c5e4fe6b" + }, + { + "kind": "file", + "path": "img_149.jpg", + "sha256": "740ec3eca16cea632681dbd447d237193b6004f800f72e1678d153dd3e2d5625" + }, + { + "kind": "file", + "path": "img_1368.jpg", + "sha256": "18258341c17be9650251935fab3d270c63bac172ee1d5f2ecda27f3f445a5181" + }, + { + "kind": "file", + "path": "img_363.jpg", + "sha256": "363f58c4664c9efe5dd0d03910b9d28e4dd5064b1230540b3f34fc71d0bc5046" + }, + { + "kind": "file", + "path": "img_1397.jpg", + "sha256": "e7b03f41c99bb3af91c2cdf1fff94de722d6e9ba8aafcca6b772db0bc1a235b6" + }, + { + "kind": "file", + "path": "img_411.jpg", + "sha256": "058b6d207daea05862eba1851c2c78162bfca53510cfdbe34793a0d57f824b81" + }, + { + "kind": "file", + "path": "img_4589.jpg", + "sha256": "7f07f5b583a7cc3572900a6f7db53836707f35dc252463432dc5f3270b61831c" + }, + { + "kind": "file", + "path": "img_349.jpg", + "sha256": "8276cf164afcbcb4e0416cb94310475ffd2d1d9652e4ba161173508939454dbc" + }, + { + "kind": "file", + "path": "img_2878.jpg", + "sha256": "8e183ba53a6e059fc56f2477370217caf818de541ddd8757e6813ed7be8e59d6" + }, + { + "kind": "file", + "path": "img_361.jpg", + "sha256": "ef8e7e2b58d114a9aa3a0d58ee133251bae337273c05f75b4c2048d91169d5b3" + }, + { + "kind": "file", + "path": "img_2677.jpg", + "sha256": "90c5fd08d4633150a2a18921b4192b45c06a59a59bdd26d33edb8e5afc2beeb5" + }, + { + "kind": "file", + "path": "img_1418.jpg", + "sha256": "97593b060c4096f7db96cbda0a43608ab27f17a3d93bff47642a6e7af9710c10" + }, + { + "kind": "file", + "path": "img_3227.jpg", + "sha256": "461b6b56fca3d1087d7cfcad9d8a9c3485861cc6be3d67255253b8409d7a67cd" + }, + { + "kind": "file", + "path": "img_1815.jpg", + "sha256": "a03375399bd850ddb373b1f77a36cbe5ecbf310d3ca08c9d755a31fd77906b05" + }, + { + "kind": "file", + "path": "img_3780.jpg", + "sha256": "953ddb5ea0c51527fec71ca2ed786e5b8fc622d19d4d4ae64cfcf5314c283faa" + }, + { + "kind": "file", + "path": "img_611.jpg", + "sha256": "64bf9c3ef215bc955b61c3cc2de789f8517d15db12e5532d0e5ee54ce39807b5" + }, + { + "kind": "file", + "path": "img_4004.jpg", + "sha256": "eec19289eec6f39cc2a81e1ec549be6065b51b72dee7ea6adca8c296d0510417" + }, + { + "kind": "file", + "path": "img_2475.jpg", + "sha256": "2cc5d04bb10578490ccafce5f937430a8ca78d7444d5c7c38d211fbd96b09b28" + }, + { + "kind": "file", + "path": "img_1168.jpg", + "sha256": "96552032448edd8a03a1db4497baa91f6d910ce69f545d4e45de4a15f37a2bab" + }, + { + "kind": "file", + "path": "img_2461.jpg", + "sha256": "84a8cd27d3cbbc7ea90d9cf2c2466f221cfae2d955df2ce7530e9d20f6fa8765" + }, + { + "kind": "file", + "path": "img_3019.jpg", + "sha256": "39438f6a7501223977f1d40c91d1c0ea312e6a6a4d34790be26ef1cefc293f09" + }, + { + "kind": "file", + "path": "img_1626.jpg", + "sha256": "1c984580e964ccf83b7097cbda16ceadaf97a1cd6102be4bb936928b0663efe4" + }, + { + "kind": "file", + "path": "img_1975.jpg", + "sha256": "90eae66598d691285ef42030f1a8d4d60d0d7073b701ff53b808ac8ba7277462" + }, + { + "kind": "file", + "path": "img_3810.jpg", + "sha256": "af44f0824f1583e33443dc19d9dcf26f59a1172f4a225ce437b8cdb7aecbc8b4" + }, + { + "kind": "file", + "path": "img_1949.jpg", + "sha256": "e8c84528ffda90346159e76052e53bd030b6a9f479c56204a68eb7c8b936a8d1" + }, + { + "kind": "file", + "path": "img_4831.jpg", + "sha256": "876cb0fc40273b72b665a5d327c5e4e4982faeb3f0e32761fe750e820c834dc9" + }, + { + "kind": "file", + "path": "img_3838.jpg", + "sha256": "72e6d63a9a939e8893eb578a9d292b41ad7f8053bb3d0214143217e17434101c" + }, + { + "kind": "file", + "path": "img_2273.jpg", + "sha256": "fe64fd763b4b73ccd0e8ba989d41922775516c8db53ec1a5cb6212f3047c293e" + }, + { + "kind": "file", + "path": "img_942.jpg", + "sha256": "d46f841af9184ec6209f9baff73236d7f8deea302c9495383561e92fb8f6503a" + }, + { + "kind": "file", + "path": "img_3145.jpg", + "sha256": "1fd7032e310c8e3bf7e06a2fca6be3db8f594e5f991279a3d0e88ae507d77b46" + }, + { + "kind": "file", + "path": "img_1034.jpg", + "sha256": "5671b7694f8971a762b6691273773d2317d4da9328280f9ead8ea8e0313271d8" + }, + { + "kind": "file", + "path": "img_2529.jpg", + "sha256": "c72a1915233a68ed26b68d3c09016be715830b9d25ed91c64011356c1025ca6b" + }, + { + "kind": "file", + "path": "img_2924.jpg", + "sha256": "73b660191b88c87bcf22b8b11473924fa7f561262171b08ebb1f0455efe68979" + }, + { + "kind": "file", + "path": "img_4414.jpg", + "sha256": "20ce49711b02d1cf0cc20b08de84088a57dd0f1a800f1cb0689a96d8a3568411" + }, + { + "kind": "file", + "path": "img_2059.jpg", + "sha256": "44f3f5f039e0a5fb36886eeaaf79dd8a578ffed9df44479a27116c1a46f8a06e" + }, + { + "kind": "file", + "path": "img_3347.jpg", + "sha256": "b389c9b043d4ee876ae92f87185ece0accd3bb9e8e95fa13e5ae5849afccc07e" + }, + { + "kind": "file", + "path": "img_3353.jpg", + "sha256": "a6f1dcaa946932c1e7c1c414806466fe12e7eca26429c26e94ab63148d4c3028" + }, + { + "kind": "file", + "path": "img_1544.jpg", + "sha256": "f8e50febf107b5eb0e87c7044adb20581ba9bef8e5c26e0815498891480e4386" + }, + { + "kind": "file", + "path": "img_599.jpg", + "sha256": "23ad0540c093108f05a6387fc3d4f2d68a101844fa54004b803f3fc6dff4f4b5" + }, + { + "kind": "file", + "path": "img_4415.jpg", + "sha256": "25e3e71728b9a5c56468d6f0a52918eb41a885f76adfc9f82760f51df64436d1" + }, + { + "kind": "file", + "path": "img_2064.jpg", + "sha256": "e1ff0cd77e13d448286d458ff648d59c251c272b431f8381e0877d92946ed231" + }, + { + "kind": "file", + "path": "img_214.jpg", + "sha256": "a43d95279b6736e135d1b0b63a18c2e555f2062f1ca2a1ab648d36e0d270cf7f" + }, + { + "kind": "file", + "path": "img_3385.jpg", + "sha256": "f23a0197aac2543b4157d0cf1bb21ee31160d0fec34e32661d4745170b3583d8" + }, + { + "kind": "file", + "path": "img_1021.jpg", + "sha256": "bde60bbbe241356cae55ca742d982e2742c81256e82554b1bfed7739d618bdf2" + }, + { + "kind": "file", + "path": "img_2528.jpg", + "sha256": "a49ba2bc0acbf5b673678d514fd8c3f689b58dd184c9b17f5b2f15edd722a94a" + }, + { + "kind": "file", + "path": "img_3144.jpg", + "sha256": "e42f23c78e8276ee31d76ddd31a21e2adf1c44088f0e8037281457dcc3daba64" + }, + { + "kind": "file", + "path": "img_3622.jpg", + "sha256": "f808245c75bd4a74a368517dd363205998c680adba13a33fc568158f70e11063" + }, + { + "kind": "file", + "path": "img_1035.jpg", + "sha256": "3d3d935cb61b8f7699a6a2ac38f29cb4511b10b7943ca9b668e9e1cf6f11dca1" + }, + { + "kind": "file", + "path": "img_2514.jpg", + "sha256": "9d5432974edec7d170db6ae675f6bc262fb2e80708ec069d9b76314f26e99bbf" + }, + { + "kind": "file", + "path": "img_3178.jpg", + "sha256": "a1bf99ac8498642d119473dfa35f26ec0340f02a954820a651360d7aeff0e403" + }, + { + "kind": "file", + "path": "img_4617.jpg", + "sha256": "8cf8c17c1e7b7a0614d859bcf94d3adddf851a881b47e1be5b60108b5c706dc1" + }, + { + "kind": "file", + "path": "img_4171.jpg", + "sha256": "5b7b55ee9a7c3d19f0b78ddaaefcdda2dc1d543fc037c22613637cff87eff5b3" + }, + { + "kind": "file", + "path": "img_2500.jpg", + "sha256": "4e8b6de4f94d3c0a547bda7da0b731e02441f79278e14703c038a0b71f85120b" + }, + { + "kind": "file", + "path": "img_4824.jpg", + "sha256": "b848bb3515fb4c31912f93e83d5f4e94d143b3c464f2a21de1668faf4b1b5962" + }, + { + "kind": "file", + "path": "img_758.jpg", + "sha256": "0990b524205b429b14b70bddf38a1a46c1306beaeacd8adfe62f13faea5f9223" + }, + { + "kind": "file", + "path": "img_4818.jpg", + "sha256": "784312353c32b2e2f1b925c15d1bcb214a21e46b92bdb87a1a90dd8c05af4035" + }, + { + "kind": "file", + "path": "img_3756.jpg", + "sha256": "b2a0c1d486138db8b2178e94cad15d652defb30fd39f62de92a06c3df54b9eb3" + }, + { + "kind": "file", + "path": "img_1169.jpg", + "sha256": "2fa6a0299d5acfe84980713073f6f20164e415f68b25f3df9fca223099c31e35" + }, + { + "kind": "file", + "path": "img_837.jpg", + "sha256": "506cc011af97d7f8dc84708efdd3ef8d38c3f89ab425a88686f665f970ea75eb" + }, + { + "kind": "file", + "path": "img_1828.jpg", + "sha256": "63892d97ecb2a50797ec52e5d2d8bee7375375cdb37cffc7f8fab0eb11ad9af4" + }, + { + "kind": "file", + "path": "img_604.jpg", + "sha256": "2132a3d278b2c7e9714a7a261fe0e7416fb9c04ff1f02491761fe779cd7e56a6" + }, + { + "kind": "file", + "path": "img_1182.jpg", + "sha256": "a4b15af797051c3c46d0c98e40b794d5425e9503f804ec60b0b2f37b25cf0047" + }, + { + "kind": "file", + "path": "img_3795.jpg", + "sha256": "f209175e4c8e950df185f12033c061015489f1c098e03542af38802fa4b819fe" + }, + { + "kind": "file", + "path": "img_2138.jpg", + "sha256": "871520b560d0c43b2bc5dc158a3a29a34fb7e110b8b248794c70048a60d6e4c6" + }, + { + "kind": "file", + "path": "img_2886.jpg", + "sha256": "cb19176dbd7466e25a41e2ab32c07029edd0ca72ea98a603a7b39fc67a302796" + }, + { + "kind": "file", + "path": "img_1343.jpg", + "sha256": "3df685ca3cc9584e059a5e4f94d417f764e1d3f8e27d1dda029610bc1d1ab703" + }, + { + "kind": "file", + "path": "img_3554.jpg", + "sha256": "99248d0f2e5cf6acf5ca79e8ebb1d0ed346ba4c57829ccfd710795e8cdc70200" + }, + { + "kind": "file", + "path": "img_59.jpg", + "sha256": "bfe1198135477fd849a3a011b04e05b09a713fa3908caec24fff98fd05ad37ff" + }, + { + "kind": "file", + "path": "img_2104.jpg", + "sha256": "a79a82cc3b338c4788fb27cd5e61ea778b57e5446293c89e180a6cf2c1c9e4ac" + }, + { + "kind": "file", + "path": "img_2662.jpg", + "sha256": "668cdbc49a4781ff0ab1427773e653986a0349aeed39c46e4caaaf8c132f132d" + }, + { + "kind": "file", + "path": "img_3568.jpg", + "sha256": "d52c4aaf10c32133aad5c9d47571d48aeb262c82f09ed38fc945e4dc5d38be4d" + }, + { + "kind": "file", + "path": "img_1419.jpg", + "sha256": "47dd70c1b537139f174ccdc4e656085f10fe97b427c111e4c4b287a4745f6861" + }, + { + "kind": "file", + "path": "img_412.jpg", + "sha256": "fe67c95856edc646eb161c7a9d77596155165242beabc51a9f4e8a09abaa19a5" + }, + { + "kind": "file", + "path": "img_348.jpg", + "sha256": "59c86b2f675a5a0544bf283e281136b9cae4acb2005c3176b8e034d9af834e25" + }, + { + "kind": "file", + "path": "img_364.jpg", + "sha256": "0da88514eb0bcf38b19496f12710d0697c2faa38f750c7a2ae50c1dce033fd60" + }, + { + "kind": "file", + "path": "img_2841.jpg", + "sha256": "aeced89cbca477958e9b95f126625fd1b70ece67479bd514bd2851edeb07715c" + }, + { + "kind": "file", + "path": "img_1421.jpg", + "sha256": "dcb86163c759511110d08c93867a2ba5aaa5b9a6f46aca0bc1790020d420228f" + }, + { + "kind": "file", + "path": "img_3544.jpg", + "sha256": "816b2c220230a859361ceb6699fc69634dccb76419447cd057b28a49d061f76c" + }, + { + "kind": "file", + "path": "img_2672.jpg", + "sha256": "4687921ffbd80ac028061be66e77ea82a995820fcd336ebdffe8f21f3e0fca10" + }, + { + "kind": "file", + "path": "img_1838.jpg", + "sha256": "40cf3d4caaf6379bf329ad585c4499d64194bb43325e1f268bf55babd2913554" + }, + { + "kind": "file", + "path": "img_4940.jpg", + "sha256": "f01397993b13de3c8673ab3af80b05eab892f32edec8d19405332d7d0eea8029" + }, + { + "kind": "file", + "path": "img_3746.jpg", + "sha256": "345a01bd9e9803a8317272b311e06d4ee2cb9200697ae3112f4bbbf480043b58" + }, + { + "kind": "file", + "path": "img_1151.jpg", + "sha256": "32ce359d8e22798d23017f95867587970dc53969fb8b780d76afac892b156fe8" + }, + { + "kind": "file", + "path": "img_2470.jpg", + "sha256": "71a189160940a4ca3b0b386a413b6b290815fbe8377685c2715e9bb7146217eb" + }, + { + "kind": "file", + "path": "img_2316.jpg", + "sha256": "ab6b7656cffe93139292ba30a7425725375f8b6ddcb35e36ce466be243b1b75b" + }, + { + "kind": "file", + "path": "img_2464.jpg", + "sha256": "57511f25274976f157de8ef6c474efeea3abbe1e5d95393af8e07c0c72d37e47" + }, + { + "kind": "file", + "path": "img_774.jpg", + "sha256": "825f88c960db3b152c3f7949c12c2c9f3aad60bc2adb7ded6ef072b5329f6fa9" + }, + { + "kind": "file", + "path": "img_1958.jpg", + "sha256": "c484a067ee056e68a917c4c0144173d84e5a113d070e4ad7726f09f184af2a83" + }, + { + "kind": "file", + "path": "img_990.jpg", + "sha256": "1b4b7ecd5790659ea9fe9529d3589309427e8ab70a558d08960f3a52912b94ff" + }, + { + "kind": "file", + "path": "img_748.jpg", + "sha256": "2fe761248031730cf8e78ce0a1ba0b27992280f1c11c798ea580f26335dc6666" + }, + { + "kind": "file", + "path": "img_1031.jpg", + "sha256": "48b441b5eb357093c67a22121e6f0a85c9c888d757905663bdb113940c78ff30" + }, + { + "kind": "file", + "path": "img_3140.jpg", + "sha256": "0ed7f1f0c6c38ff3f473d303051e9bfd30aa39133b7691ae86e0c7e4fd18f667" + }, + { + "kind": "file", + "path": "img_1743.jpg", + "sha256": "4ba9e6618402e2da13a5db95cff8fe307a5cec0b77dcb5a6df028398ec7cf91b" + }, + { + "kind": "file", + "path": "img_2262.jpg", + "sha256": "917eaf0ed1f01a69a0cddc28b6cce7b451d428a999e45da1f81f645313a528fd" + }, + { + "kind": "file", + "path": "img_947.jpg", + "sha256": "7f7783234a9567cefe30c7a8edf1ee0e12e53b42e38d5a291ec889d0dfdc5d37" + }, + { + "kind": "file", + "path": "img_3381.jpg", + "sha256": "365bc5cd89c73ea510576d62bc3fd0c79d18854a1e410512d519478a954820fa" + }, + { + "kind": "file", + "path": "img_576.jpg", + "sha256": "fb6b3f289729272b8847b731725a98dd8bb439976bfbb144e80162d9aa3ca568" + }, + { + "kind": "file", + "path": "img_210.jpg", + "sha256": "d7ae71cf534c6693db8e9d026a2d7098772441014dac54a7bd4a99073602e402" + }, + { + "kind": "file", + "path": "img_4388.jpg", + "sha256": "a73372ffdc0134595d3450cb35860dcd78f9e648fef9a6e76237681ea5892796" + }, + { + "kind": "file", + "path": "img_2935.jpg", + "sha256": "9d66b08bced92670e91bf663fbdb1299d929cc90aaba67e5bf5919f6a7540ea4" + }, + { + "kind": "file", + "path": "img_1582.jpg", + "sha256": "6d956ee697d5c61bc9c441007f945271b19aa67f89846fc7a360a19bf542acc3" + }, + { + "kind": "file", + "path": "img_3395.jpg", + "sha256": "2ecf6eda9413b2a8435efae15575fbd538916f9a00759e511548dbff7099f641" + }, + { + "kind": "file", + "path": "img_1233.jpg", + "sha256": "58cc227861cd904730ad67e2a4fa5d3a6492f40dcccfca8dd8a512071879599c" + }, + { + "kind": "file", + "path": "img_589.jpg", + "sha256": "14e6ab09fe6aa1cdbe0d09f4227763395f35b8bf01836407fee7dd1d77cdf220" + }, + { + "kind": "file", + "path": "img_4362.jpg", + "sha256": "b03e79a38cda0346048a70b39df48283d8524e22bca61826899ca16454e10250" + }, + { + "kind": "file", + "path": "img_4410.jpg", + "sha256": "0e746535ff601ec5e4203b31d84efe4055b7f85e419395a4a2d284fe47866ad7" + }, + { + "kind": "file", + "path": "img_2061.jpg", + "sha256": "b002cdd93380cabeeb0ca7f6fc2b70c23e7238554f4bc47d69575a8403a54efa" + }, + { + "kind": "file", + "path": "img_3419.jpg", + "sha256": "7e02c7d911caaeebe0cc52b4b9da58d342eee42d837ab09d0ffdcb8dd51c8090" + }, + { + "kind": "file", + "path": "img_1226.jpg", + "sha256": "12c11f994dc665d1eb8a727849ce173ba10c145b179be86c3337eef7f0aefa1e" + }, + { + "kind": "file", + "path": "img_239.jpg", + "sha256": "8fcb611c46ac6bc76430e2bb518ae9f0760d291e7c42372e6f981b834249d4b2" + }, + { + "kind": "file", + "path": "img_1597.jpg", + "sha256": "b2e700a77ad7ee810a08fb94bc88089ce8c5107e669bb6e472b6a59a52c3eac9" + }, + { + "kind": "file", + "path": "img_2920.jpg", + "sha256": "5e2aa2f909d92f861ef96d5cca5d753aace006dda88946382e7b9f5a9fb2ef64" + }, + { + "kind": "file", + "path": "img_2277.jpg", + "sha256": "a8837d4aa0b3975867333310bd7d73d781359f2f99089d78574008849845e6cf" + }, + { + "kind": "file", + "path": "img_3169.jpg", + "sha256": "143978355e8df245f1c360f47f1f3a72a571acf7b828d023dee0453eaa89c402" + }, + { + "kind": "file", + "path": "img_4160.jpg", + "sha256": "9a5f2450e76330f7b3881920fcee35af5426c502b17bac8c063d2b5fc3fff7a0" + }, + { + "kind": "file", + "path": "img_2511.jpg", + "sha256": "8502a1964ac776e92c85f5c44ad96fec1599a10a5dc882cb75db40c93edaf2f9" + }, + { + "kind": "file", + "path": "img_952.jpg", + "sha256": "aa503018914c580430326b58f5880945888e59bee8da50ca96c02860cdb5fdc5" + }, + { + "kind": "file", + "path": "img_4148.jpg", + "sha256": "1bac6bc137ebc73fd16b9b2c61c808ed3b5db68d594d00c236d4672a01f10cb9" + }, + { + "kind": "file", + "path": "img_1756.jpg", + "sha256": "8c1b56ca3db3c409dbd3c88643a6d67f89e8a8c185b3a50777f14547f07b38b7" + }, + { + "kind": "file", + "path": "img_1959.jpg", + "sha256": "46323f67e0a4d90e76a7076247dd8048d99b3acd724745a007dede12e6239731" + }, + { + "kind": "file", + "path": "img_4821.jpg", + "sha256": "3d5def5f734a7c1183139d70ce5ed71496c99b34542fe198c24c635a16fedef7" + }, + { + "kind": "file", + "path": "img_3828.jpg", + "sha256": "7806c8bb334392833bc82b98cfff60c32d361243873930e1e0d393aff1c43c09" + }, + { + "kind": "file", + "path": "img_3182.jpg", + "sha256": "59ff8c9e7a272b2871ced839dcbf7d68e25ca3438d61b9addfa257abaf987b0e" + }, + { + "kind": "file", + "path": "img_2465.jpg", + "sha256": "e7e370e0d587108f1e746dc3346d7a1ea3776f47bb20c2791963038ccd1bde49" + }, + { + "kind": "file", + "path": "img_4000.jpg", + "sha256": "17abfcc285fa4f645f9cec3d962b06a184173a495c32eb8a0b34723b44d9d5cb" + }, + { + "kind": "file", + "path": "img_198.jpg", + "sha256": "2c12fde6bf3f94d1b0efd70586253707cd16775774a7c9d7fcde23e9fb010fe4" + }, + { + "kind": "file", + "path": "img_1150.jpg", + "sha256": "923f3c5c6071e448025ce667cd9bbfe8a502dfbb0e65ac09dc2bf47cf3a538d2" + }, + { + "kind": "file", + "path": "img_4028.jpg", + "sha256": "975c68032545efe2f877847c2d61fbef56b927c4a50f5be2abe314ac1fa448ac" + }, + { + "kind": "file", + "path": "img_167.jpg", + "sha256": "74d0536631251e81a7fd27497b8310d63452c0f93f8f93c38b4c582df0582969" + }, + { + "kind": "file", + "path": "img_4941.jpg", + "sha256": "a1af05b9c5a43d9204670793bf56492ad76d4b012833bd0b0f905b24abb4fccb" + }, + { + "kind": "file", + "path": "img_1839.jpg", + "sha256": "106a41f11ba0a3f2309e6e793d4211b7ced9dd9ba72da907f8e2b886c659282a" + }, + { + "kind": "file", + "path": "img_3579.jpg", + "sha256": "be181dc63d66fe38e2c2564328b295c8fa78611040bb146cd68afd8133b27cee" + }, + { + "kind": "file", + "path": "img_74.jpg", + "sha256": "7352abb3a1e5077136d4d64222045075a20b0128766232e116350306db2e516f" + }, + { + "kind": "file", + "path": "img_2115.jpg", + "sha256": "42eaeaa480ea8bb00c28cc79f0f0cb85c6df7625a9b4e9dc167a76eaffdaf1ad" + }, + { + "kind": "file", + "path": "img_3545.jpg", + "sha256": "1eb05a320ba64b13723bb59b8564eab3da87f27844212e264caa5197fb05fcae" + }, + { + "kind": "file", + "path": "img_1352.jpg", + "sha256": "42580e3fb1b8311273b9ecebfbbdafbdb716e31ee2cefb7777cdddf59a892e65" + }, + { + "kind": "file", + "path": "img_1434.jpg", + "sha256": "53944485445c2fa494e8ce7e5f7cf4f78f3ede74b37eb37e78890452df4c699b" + }, + { + "kind": "file", + "path": "img_3223.jpg", + "sha256": "18f7235a482782edbc57b34a653119234bb2433bab5bfbaa1567de0acd3d4675" + }, + { + "kind": "file", + "path": "img_415.jpg", + "sha256": "ecdbfec9d2ca8a903a8f742e8a4c16a033f58f942ae9fcf8e9ce9fcbd2fb2a71" + }, + { + "kind": "file", + "path": "img_2842.jpg", + "sha256": "6b5900ab1c55846db2eef57b6b986d72a5a70413b26ea0abf5f55c0978fdb9b0" + }, + { + "kind": "file", + "path": "img_1387.jpg", + "sha256": "7b136e04f620714e42045ca7719479dd4b6fc0c8766eb17c6864f7c706fc5e50" + }, + { + "kind": "file", + "path": "img_2895.jpg", + "sha256": "a0d855ff100369da3c745ea4c2e470c8fecb47b3ecb8033e4fa14acbbb5bb553" + }, + { + "kind": "file", + "path": "img_3553.jpg", + "sha256": "99c1b8902cda23911a7bf9b6909ffcb926b84534582b11624fa858a488e24e84" + }, + { + "kind": "file", + "path": "img_1344.jpg", + "sha256": "e20d82191cdcb82150921091412f757cce2b9e83175f82393edbf96e1cc969e4" + }, + { + "kind": "file", + "path": "img_1378.jpg", + "sha256": "55c248bd5efe73a1847dfcb71b5d3c9cc85bcd4a5e2483deba1c8b40aebc4235" + }, + { + "kind": "file", + "path": "img_4566.jpg", + "sha256": "9633515e23c8f6736dd06eff0a385105d619584b93e3bfb95410db0952e04377" + }, + { + "kind": "file", + "path": "img_62.jpg", + "sha256": "79afca05c6290fd374ebb3e125968e0beaa6704b8ac8d52f44d88698a98f9f91" + }, + { + "kind": "file", + "path": "img_171.jpg", + "sha256": "ee7239c922924aae56983b3cfb9859dfd239871a3c48a1b8fc9cae7554dda663" + }, + { + "kind": "file", + "path": "img_603.jpg", + "sha256": "efb047c0ffdafc60db9d5bf4825022ab705ae52ce108d03bc9f0dd698bfbaaf5" + }, + { + "kind": "file", + "path": "img_1620.jpg", + "sha256": "c116f5bc8ca489ca74e022c913ea51fc64f86538e5a12ae82c55373c160a2296" + }, + { + "kind": "file", + "path": "img_4016.jpg", + "sha256": "34aeed8543f3250e47e9ba29df24bd8e860f9c2f7ebd3fb8df68ea36442584bc" + }, + { + "kind": "file", + "path": "img_1026.jpg", + "sha256": "689925a8784972781b7fe5dc56957a143854fea22e58ae42441a39a1572efc7a" + }, + { + "kind": "file", + "path": "img_1998.jpg", + "sha256": "cc8f206d43a37ec8c056f9580afabbf55a45dd87de59d476969fc9bfe95a9dd1" + }, + { + "kind": "file", + "path": "img_4162.jpg", + "sha256": "82af86c422855010d62eddd26f01b94989adafdd2911b484c1f869a99cadcc35" + }, + { + "kind": "file", + "path": "img_2261.jpg", + "sha256": "11f82d14304ec181121c9050b9b5f1a19c775648476b8c6a1414e29de50624f8" + }, + { + "kind": "file", + "path": "img_4176.jpg", + "sha256": "072874a3aa7b0b6c97c463c4a89149f945e55203a0e1b01a6ad2d7d233c572cb" + }, + { + "kind": "file", + "path": "img_2088.jpg", + "sha256": "81f23604e436b19037e9ed10cc8f1a5f5842f268bcd52e783c7aa071451574d6" + }, + { + "kind": "file", + "path": "img_1230.jpg", + "sha256": "b7f50f1284b3ea703eb9ee8c2bf0d78b2cba8df912669be9b0bfab23c3a520f1" + }, + { + "kind": "file", + "path": "img_1218.jpg", + "sha256": "3b404bf629398a5d4657c28c8df4aa05cebdc6720e23154ab1a76ed0b0468e2b" + }, + { + "kind": "file", + "path": "img_4374.jpg", + "sha256": "9d5680bfc6306ef20d6efc4f513b6ce1b7d0807b00eddcaa305ecaed983f3514" + }, + { + "kind": "file", + "path": "img_2705.jpg", + "sha256": "d467cb189207824da5302ad6322c19e86f7c3ad822a0c2d3424ed4b68a091453" + }, + { + "kind": "file", + "path": "img_2076.jpg", + "sha256": "728fe895526bbbe9c4dfe40a572d108a34e0d4ae0db02bb8d3e3c80b2c8b5c13" + }, + { + "kind": "file", + "path": "img_1219.jpg", + "sha256": "2639a16f9270b44043a34971575a7ea4ac0f2358d13152529de98ca405d33638" + }, + { + "kind": "file", + "path": "img_1557.jpg", + "sha256": "9259b2725e77ac2809fc022a95a6d1d883e4e3d741e522ac943a0fda0bd95b1c" + }, + { + "kind": "file", + "path": "img_1543.jpg", + "sha256": "792853f82d75834b3644bd30c783f253d32a36b63f694c77510561e4d4190975" + }, + { + "kind": "file", + "path": "img_212.jpg", + "sha256": "7ab522397ff763845ed7ad01f5139461965dfdfd0c8f5c06386f8a1359429358" + }, + { + "kind": "file", + "path": "img_1580.jpg", + "sha256": "136591b40c2539e7726ed1b0634f1335df6eb39aaf8dc2a7a0c7f357a43ccdca" + }, + { + "kind": "file", + "path": "img_2937.jpg", + "sha256": "1b72bf8065e4b50b227090f23649aaf1bae00887301390c131571469c73694a9" + }, + { + "kind": "file", + "path": "img_4611.jpg", + "sha256": "edd9c6b704a6b7dc0c68164b0c174b51a261648f086dfa0a21be11db1e9abc70" + }, + { + "kind": "file", + "path": "img_3618.jpg", + "sha256": "8ba1c85703af90fecb4e99988f25dc0342af623d65ff65b139b4891bcdde084f" + }, + { + "kind": "file", + "path": "img_4177.jpg", + "sha256": "84f36022ad131f47838a45032f20b89d23f222f2811202b264da7c71611983e7" + }, + { + "kind": "file", + "path": "img_2506.jpg", + "sha256": "3f7a7d126bbe6acae8773bb09e859881b5aea7530d995045478680ad53af1e02" + }, + { + "kind": "file", + "path": "img_4163.jpg", + "sha256": "473922267b04345ec5f416b21ec296107af38cf6d08e709804cf5af6ad1d01c8" + }, + { + "kind": "file", + "path": "img_4605.jpg", + "sha256": "3f49e31f638a38f68da4679c77a0ea7fffb56082a12537301bbee4d57d9ade4a" + }, + { + "kind": "file", + "path": "img_1755.jpg", + "sha256": "8760ad024b88c0bd3106b07545a076e5081dd1248866f0b6858b60580aafc807" + }, + { + "kind": "file", + "path": "img_1033.jpg", + "sha256": "b7a18323f9adaf1eb41d21e24177046de6c7aeb8caa447dbfde63899e8fc2c17" + }, + { + "kind": "file", + "path": "img_979.jpg", + "sha256": "01e239cfa5af55a8b322c2f83f023c043f724a1bf1c037e8f3330fe574d50e48" + }, + { + "kind": "file", + "path": "img_1999.jpg", + "sha256": "6f105ed6c90a3013b72c0402d12cf4c702b165e002cd3b3ad96c0fd097598c1d" + }, + { + "kind": "file", + "path": "img_1741.jpg", + "sha256": "46416030f7a40ab8f646c6064cac5f67fe4a5867ab0e89406c06c0612eb594ed" + }, + { + "kind": "file", + "path": "img_3817.jpg", + "sha256": "9ad1090c717b3dbe8a42fff373038d898caa95c344db0032858cbef93965344e" + }, + { + "kind": "file", + "path": "img_776.jpg", + "sha256": "b40b3363ba965579675d9f22fcdf00624470dd73cb521231a0929c38f1667161" + }, + { + "kind": "file", + "path": "img_3181.jpg", + "sha256": "6421cc55c5aa39b7cd61dd0c65d2890769377a9cc744c702ce591d56eaa9ac42" + }, + { + "kind": "file", + "path": "img_1796.jpg", + "sha256": "17c59af5480ccb3f1c8bf54b5a44b173dfaad400537e4de485ef4630f8e0f6df" + }, + { + "kind": "file", + "path": "img_1782.jpg", + "sha256": "8f3eb318ced243c2976b783dae144a69c1343111d7852f8f8a4c83458c5137e9" + }, + { + "kind": "file", + "path": "img_4003.jpg", + "sha256": "ccee9048034973b051c910bb3ff5e214277e1b43615cafb9c6cedc40f0ba1dc4" + }, + { + "kind": "file", + "path": "img_4771.jpg", + "sha256": "6846fc23767aaa0d7bf9519602762dd8ae972ea1e4fc6c3fb6177346b2a18ca3" + }, + { + "kind": "file", + "path": "img_831.jpg", + "sha256": "3c25b8b4b2f25be3b0da376203d19ea7d56cabb030fecc4b96f51d4d0ac147b2" + }, + { + "kind": "file", + "path": "img_1621.jpg", + "sha256": "f6b4763f6e2001c4673ad0aa5303f36eb759309f5fa4c105ae0dc3bfadfb0c0b" + }, + { + "kind": "file", + "path": "img_3022.jpg", + "sha256": "cf5c1bd5dd093d9fb23d1bdd93de6828e8625262795711da51602d604ee67dfe" + }, + { + "kind": "file", + "path": "img_3977.jpg", + "sha256": "d16e30828ac8a32e92742d7363c3244d47cdc6f9c248f22bb2e8d148fff15e56" + }, + { + "kind": "file", + "path": "img_399.jpg", + "sha256": "b7310873dd72498e43e39844c9d9341be5150d03b7e9b2f3daf777c760ee030b" + }, + { + "kind": "file", + "path": "img_63.jpg", + "sha256": "9f06bc6632b86d9d027b89a77f69b89883b453c9f007c8ca1d50fc35dc6d2e60" + }, + { + "kind": "file", + "path": "img_77.jpg", + "sha256": "5f40eccaf6f8d3fed49223fb546efd79b430cef6985f6e9bd949295c52b04aca" + }, + { + "kind": "file", + "path": "img_2857.jpg", + "sha256": "b49207933b1f66d1802d0848f3acf1d2ae362d920d8f330bf32faf9f636e12a7" + }, + { + "kind": "file", + "path": "img_4595.jpg", + "sha256": "2d4171f55cd2ed416eeb678d78c1cc52340ec0a1d70d32abb3877c99da38076f" + }, + { + "kind": "file", + "path": "img_2696.jpg", + "sha256": "15be178e45f12e36dde213546d159eac5e2d8d4fa9028f893293b5d06c08ee72" + }, + { + "kind": "file", + "path": "img_357.jpg", + "sha256": "c5b86e319e0313e24b2b42824437b229737509178e860b1c7ef23c96306f0c90" + }, + { + "kind": "file", + "path": "img_2866.jpg", + "sha256": "527eed4b9c8d782657090ee7edad49555ab2cfc08400e53bc24396472b031d78" + }, + { + "kind": "file", + "path": "img_431.jpg", + "sha256": "2e417d64dca2b02c4792b9a6038d235d07944d0dade189e727352e0b8738bc82" + }, + { + "kind": "file", + "path": "img_2872.jpg", + "sha256": "002d3c977e36cb271878e9e3fe576d12f594f224940143f1eea012db028da591" + }, + { + "kind": "file", + "path": "img_4230.jpg", + "sha256": "3a1faff6bd2420bd5db32559bbb31beadf574ab868229852835e076ac8611fac" + }, + { + "kind": "file", + "path": "img_3239.jpg", + "sha256": "75fe6472fe3e574df449d2057268577e55b060ae91fb95396d4487f983b46ce0" + }, + { + "kind": "file", + "path": "img_52.jpg", + "sha256": "a5b66f0fb9e159cbed7e9459d545c855ef8acd7b60015ebadf463fb7d7211603" + }, + { + "kind": "file", + "path": "img_2133.jpg", + "sha256": "2e0fdaa95fff269b9bf1b5299996fba1682310f80e675eab11cb78f9381d27c2" + }, + { + "kind": "file", + "path": "img_1412.jpg", + "sha256": "4e7664493fad39c2906b7668a7b131b26e573afef56ba2dfe522c6d056773892" + }, + { + "kind": "file", + "path": "img_4797.jpg", + "sha256": "9ca6880e2dcc6b8aa66f52cfcb158bfd563ac47c6c83622d154658f1fd7ef404" + }, + { + "kind": "file", + "path": "img_1189.jpg", + "sha256": "20953fe682c04757b7f2d483447287fc45f25d2b74f8d71fb20b1d6ad7bb7639" + }, + { + "kind": "file", + "path": "img_1823.jpg", + "sha256": "299e4025fcd89d67380dce4e3044a23d4848db8afba8ebcc90f4b8382474bf52" + }, + { + "kind": "file", + "path": "img_627.jpg", + "sha256": "3f6723434d88cfe8efa404f6b5f798e552426218868f20df0fe7847b4e33de71" + }, + { + "kind": "file", + "path": "img_2325.jpg", + "sha256": "a4d59880791dfce58a58c1a079ed199de373e67f2b57fa53f196ce3b9978336e" + }, + { + "kind": "file", + "path": "img_4754.jpg", + "sha256": "b5d523c09c7fe2c156405e347dad29ee2619f0c37cb3f78ffb24305110d447aa" + }, + { + "kind": "file", + "path": "img_4032.jpg", + "sha256": "44c77c679ecac6b3a113d474ef3546864cea6edd953ada9c91454372e71f21e0" + }, + { + "kind": "file", + "path": "img_3991.jpg", + "sha256": "b0c2f03bc675951f520558b6469822b86dd2d88e2842db750d1078891d787fb4" + }, + { + "kind": "file", + "path": "img_4768.jpg", + "sha256": "df00ec7690b21850ca8b45a9c8982e29d04f771c6bcf26d1ce6dddb1528eb7b3" + }, + { + "kind": "file", + "path": "img_1176.jpg", + "sha256": "c603313bb383f918a747ae6e2083187035da8e0a354f05a10b373f21375afbe8" + }, + { + "kind": "file", + "path": "img_196.jpg", + "sha256": "789c5a2b6ca29f9b68c203b7145f667146672d3051149e24e61f257ead4950c7" + }, + { + "kind": "file", + "path": "img_1604.jpg", + "sha256": "3c0898ccd307af22d92865176e9defa881367e1bfa41c07fdec006e7447279e3" + }, + { + "kind": "file", + "path": "img_3013.jpg", + "sha256": "d047645a5314ade12cd901d7406e961603798f8af7b35c9427777befd8556248" + }, + { + "kind": "file", + "path": "img_1943.jpg", + "sha256": "e576c39203c3a59f077c36a30ba42efd52d4c4c23abf9564042f97536e444230" + }, + { + "kind": "file", + "path": "img_4191.jpg", + "sha256": "8c2c85d8b0d06c086cea10fe9f700630922ed709e6b4bf9e9451fe6a74113271" + }, + { + "kind": "file", + "path": "img_2251.jpg", + "sha256": "0e9dd83da757b8e0a4169ec41b457c8443c3306832f414f12b174d0d0c75bb4a" + }, + { + "kind": "file", + "path": "img_2523.jpg", + "sha256": "d08bd6d09e7b17cb29e05ae80d0667b06406205c0340dbd4e08aa806750c89b0" + }, + { + "kind": "file", + "path": "img_4152.jpg", + "sha256": "81dff826da1114154079e2171a6b13f13be2f2c21def4135fc397c4b014e002a" + }, + { + "kind": "file", + "path": "img_4634.jpg", + "sha256": "d5855b17e0fd82be9ed5396c70036c7245dd897e77e8fd4d2288c0a021ae66fa" + }, + { + "kind": "file", + "path": "img_2245.jpg", + "sha256": "5f67ed68d428bab50e8e890001f5f03b4896a2d451659f7fbd5be7c28f13aa9d" + }, + { + "kind": "file", + "path": "img_1994.jpg", + "sha256": "4f2def17c0adc77298634fbc0d779c4c3ae1f4e54f40e2bc3535823b0cfdb9db" + }, + { + "kind": "file", + "path": "img_3615.jpg", + "sha256": "a67f0d98be5ac904a117815557ab26f89aae4a4647d0a9e8ebf199ef1cadb4d4" + }, + { + "kind": "file", + "path": "img_4393.jpg", + "sha256": "898a5aead48943f85ffa1c64d3a664d659682cdf31f698153cc154c4ae23c045" + }, + { + "kind": "file", + "path": "img_2735.jpg", + "sha256": "320ac39f96d08b1aaf6a063e0ff73346fd5a1c1bccf7df14f30e0fd96d532cdc" + }, + { + "kind": "file", + "path": "img_3359.jpg", + "sha256": "0b98d8f604ff5a945f70283a518e25e8481e9f922a9c2e84d00bd628009daee4" + }, + { + "kind": "file", + "path": "img_4436.jpg", + "sha256": "681087b44af2c18ef17eb2977637d55f8ca300a4a3d35a15f16864327e40f582" + }, + { + "kind": "file", + "path": "img_4378.jpg", + "sha256": "e6750f5fd6b62d882f2fd38ae88c21c6fc9f03ec7323ff5fbde1e97552755950" + }, + { + "kind": "file", + "path": "img_1200.jpg", + "sha256": "a9dde123d1f3fac6830a3de7a0eda57ef39ce6dbf69f406d9fdc43566f730635" + }, + { + "kind": "file", + "path": "img_586.jpg", + "sha256": "8d5a7751574ad362650a2c9d02a7941f198259f09584e1b80ca457d9cf63e4b9" + }, + { + "kind": "file", + "path": "img_592.jpg", + "sha256": "2286974e579bf9a5446f447be491d48846ab3b85ea0fcff5c7b58355c67ddf52" + }, + { + "kind": "file", + "path": "img_3364.jpg", + "sha256": "24244c68e1d105be80044c34b38b9d9b9cb75937b486151f987e93ce3664c411" + }, + { + "kind": "file", + "path": "img_1201.jpg", + "sha256": "2581ec8ca870a2802c7d2492c01816bb1027978d5379787db24ee10e1e68deb9" + }, + { + "kind": "file", + "path": "img_4437.jpg", + "sha256": "e41d4079003c747532b189c3277aeff28c7648ece34a162085e2f4514b01f4fc" + }, + { + "kind": "file", + "path": "img_2046.jpg", + "sha256": "a3496b3319bb47df5dde9b949f9312df94d6e8dfa0b78a1dc9ffeaed06d7ed30" + }, + { + "kind": "file", + "path": "img_550.jpg", + "sha256": "087a721cba4744c3ff26d1f359d860c1c9f36476e83b17ab56839701b21a9873" + }, + { + "kind": "file", + "path": "img_4392.jpg", + "sha256": "1aa62fde5dea243077d96b6cbaaaf951445a591018aefdada44e93d960406820" + }, + { + "kind": "file", + "path": "img_4386.jpg", + "sha256": "7f35cae7308ee5f29dbfeebe9a30d9e5f172b4d48952f1d25b7290d8c5e64435" + }, + { + "kind": "file", + "path": "img_4609.jpg", + "sha256": "8ad6da5cce6188ae0e9df5fdbdeaf6ee3ca492686f3e0f6a4a1e15219e6fbec4" + }, + { + "kind": "file", + "path": "img_1771.jpg", + "sha256": "4c3b5cf91a6b4b84ec0b93242a61f90d4aa3bccf84b51d4af720faf5344b85d3" + }, + { + "kind": "file", + "path": "img_4153.jpg", + "sha256": "b4e472b2d847972d332f99e4f4d9a7a3609f59114bbb235a0463f7e0a8760378" + }, + { + "kind": "file", + "path": "img_752.jpg", + "sha256": "cdece0ad4802f9f7907e605f07dcec1461e5334e8ce1474ad342ff0b73e753b3" + }, + { + "kind": "file", + "path": "img_3012.jpg", + "sha256": "84aebfbee169f9a966f83b865e916cffc8c2ac9aee1cbf2104576eb6792a51cc" + }, + { + "kind": "file", + "path": "img_1611.jpg", + "sha256": "025218ea5228e33649e1a6ead7dffe1c8d409a5a840c4ab13f96c99dc3ae3ec6" + }, + { + "kind": "file", + "path": "img_197.jpg", + "sha256": "e98b8a0eff77d1f2ae6851ffc26c0ea9436d12b810f2aa28fd3b72f41f5c60e1" + }, + { + "kind": "file", + "path": "img_1177.jpg", + "sha256": "6cded5090b0e8167d6712c1f711700755598ba7fe7582cf492d7833df06dd881" + }, + { + "kind": "file", + "path": "img_1639.jpg", + "sha256": "94db7d70c0374b791735e42a0b9dfd530302c1f5a7d32075aca1219e08a2f35c" + }, + { + "kind": "file", + "path": "img_801.jpg", + "sha256": "9a167ef0de384d12cd6baa399d9ff90fc651978fb37235c47c6044da70947aa0" + }, + { + "kind": "file", + "path": "img_4755.jpg", + "sha256": "17e927cba5feb14a571ff8707c8c0dc3bcf5fcbeb15c8e5513c3ad42ddb97aa0" + }, + { + "kind": "file", + "path": "img_815.jpg", + "sha256": "f3539d62ad9b37a0c7924844a9d26254642b06e7fc84e8568ae5e2dd2b63465c" + }, + { + "kind": "file", + "path": "img_140.jpg", + "sha256": "001d4ab5e8ea86d5608bbf01b3a2a680f8ddfec5967be63b35613eb1edddfec4" + }, + { + "kind": "file", + "path": "img_626.jpg", + "sha256": "31e09da1e7bc4a88ca6c2c35c215cc91bb4aa2671e892d325e1a342fdd1118eb" + }, + { + "kind": "file", + "path": "img_1836.jpg", + "sha256": "dff4c68533e65da27b781b61b14de4a38410e7dc52adc259f9e1568f9ee9fca3" + }, + { + "kind": "file", + "path": "img_3947.jpg", + "sha256": "f35908581f9a63478db1f3e1c6e989ed4fd28f3c47d156e1d3c29495104d903c" + }, + { + "kind": "file", + "path": "img_1407.jpg", + "sha256": "df8c7d858ab16828ad720ee30de32421e7247f6b9747b55cb49171fce675fbe0" + }, + { + "kind": "file", + "path": "img_3576.jpg", + "sha256": "c9e1ffb62f1c1fbe5cecec69b9823c06f54f7e099cbb3e2217aaee6c2590cbc2" + }, + { + "kind": "file", + "path": "img_1375.jpg", + "sha256": "d63294f202f8e8959775ecf5afc410fdc25dc86aa61097e0ca940175d94f5cfd" + }, + { + "kind": "file", + "path": "img_3562.jpg", + "sha256": "53fd9ec3da53e9c1321541a97acee912d14565e3926c2299d25e2a2f08391f4a" + }, + { + "kind": "file", + "path": "img_2640.jpg", + "sha256": "6604ee7d253529563c2fd276ff8d268f727a8f6b7ad28c97d6c1f6fb060f2920" + }, + { + "kind": "file", + "path": "img_1349.jpg", + "sha256": "7b5f433ace91b826c4de4d208409770fa2ff218b6f8cda2123f193607dc495ac" + }, + { + "kind": "file", + "path": "img_2126.jpg", + "sha256": "d3073888c548571e62c20893bb9a1b70faed999d031593a2f5588cdde4d838f0" + }, + { + "kind": "file", + "path": "img_424.jpg", + "sha256": "54919e7573b1c07b485df9379fbdf63b59b1e580dbbf938895a7a54de6406fe2" + }, + { + "kind": "file", + "path": "img_2873.jpg", + "sha256": "d4754f34c5d50b165a0296ada7a5b11d657ad8989414330ff991d6eaab6a981a" + }, + { + "kind": "file", + "path": "img_4580.jpg", + "sha256": "3216e6dd0437cec240b55f0dfb467b2670b19a61b0d65a54ba3a847928ebd824" + }, + { + "kind": "file", + "path": "img_4594.jpg", + "sha256": "49ccba220c7a219488270fb2da77d2e9c9cfd0265361bfbf5d71dda90bca6385" + }, + { + "kind": "file", + "path": "img_354.jpg", + "sha256": "f8dd504c7aed4c708803e9a03dca3b7debc3bc147ccee5567813a6571ea891ba" + }, + { + "kind": "file", + "path": "img_2865.jpg", + "sha256": "fda4c4172c3982d23c12d2354bebe1c437447d9b35e7e793d772b0c04f8e446e" + }, + { + "kind": "file", + "path": "img_2656.jpg", + "sha256": "7edc4a6963b3e5c09e486960d368f6c4789cced4920128bbd0c42b08c5941da2" + }, + { + "kind": "file", + "path": "img_1439.jpg", + "sha256": "8ad2fa4e4f32693d5ec50d42bf89c56222fed27fad0ef346883778744d458b03" + }, + { + "kind": "file", + "path": "img_2130.jpg", + "sha256": "6e5629c378fae6e8e1cfc1c5cfc0f0a4d1d15187f5c8d42c183165c401b88b73" + }, + { + "kind": "file", + "path": "img_45.jpg", + "sha256": "3a2165275115fb39905827b8f33911ed26fd44173b937982bf6b35e06a245310" + }, + { + "kind": "file", + "path": "img_4555.jpg", + "sha256": "a8a4fc5834c0cfef4f84e3f0f10d82b5dc6ff94413a5987d3c88c406752c28de" + }, + { + "kind": "file", + "path": "img_397.jpg", + "sha256": "23c01e3dc9b801cc405b3f526b2271a792cea98622a85b4ceb99e40282a52cbe" + }, + { + "kind": "file", + "path": "img_2483.jpg", + "sha256": "783d1474f9e8b3e9b18b0c199064babb78373bcd17413c5a860f3b18ff6ddf97" + }, + { + "kind": "file", + "path": "img_156.jpg", + "sha256": "4c68ba615204e2494a6099f4168428aa127c18b4bdc18822c014af5db0395209" + }, + { + "kind": "file", + "path": "img_4743.jpg", + "sha256": "4fd661b0e57ab91f904908f87c40d9baf52b9d34bee84b4509239e544806d0ea" + }, + { + "kind": "file", + "path": "img_2326.jpg", + "sha256": "c1bf8899bbea476c918b15b0a42b78add9a7eb2b434510f0979f3a8ae4aef707" + }, + { + "kind": "file", + "path": "img_2468.jpg", + "sha256": "1eea9bb2b49540d1816284fafab6d4ae6a3af7d9320244224e76eee584e87b07" + }, + { + "kind": "file", + "path": "img_3825.jpg", + "sha256": "f9568d4ea7e12e4d4ef0a65d9005563431f3f3f233cb6dc9d222106f73f01808" + }, + { + "kind": "file", + "path": "img_2291.jpg", + "sha256": "ffae49c1316784a7093b71b568703387d18c353ed7265b915b4755a70a605e63" + }, + { + "kind": "file", + "path": "img_1940.jpg", + "sha256": "c01047422964f9f0add5ef2fd3d6a159271ebae8a140c1b1ba4fa875f72dbf75" + }, + { + "kind": "file", + "path": "img_2246.jpg", + "sha256": "0c6b191cd62e51f528c2d36c99142f4e0698eb4facd5cf32f94c77a5161eb2a6" + }, + { + "kind": "file", + "path": "img_977.jpg", + "sha256": "5735e4f3273329a9c1f9665820ffcdca0c95f4b33f51c937d868aa509940d84c" + }, + { + "kind": "file", + "path": "img_1029.jpg", + "sha256": "85afe3010d6da882278a27c57c27252ddde5ec6a8bf58dea31379d4ba7a560aa" + }, + { + "kind": "file", + "path": "img_4151.jpg", + "sha256": "ef60f8bbca37c485bc458f5fb0d0d166687737607bb6123a3b715fe5ab038359" + }, + { + "kind": "file", + "path": "img_2534.jpg", + "sha256": "5dcede3378e080e2825bfe634afca0455b47dd1e265a8a62d973a6ed6f91967c" + }, + { + "kind": "file", + "path": "img_4623.jpg", + "sha256": "fd127840251b58a3b81366e642c1cdf75424e26fdbf386936a4745f55219e72a" + }, + { + "kind": "file", + "path": "img_1015.jpg", + "sha256": "3e70b197d441b9d5d404a802d04d8da006b09988620ee50fe0d197cb44de266b" + }, + { + "kind": "file", + "path": "img_1767.jpg", + "sha256": "864725780685e4d95a74a9c84874578490b915f4a1db161016e0aa2f1947db23" + }, + { + "kind": "file", + "path": "img_4390.jpg", + "sha256": "12477c9518ce8656891bdae84bd7a27517b920383d243187212fc353deb78a29" + }, + { + "kind": "file", + "path": "img_2093.jpg", + "sha256": "0801fa21ffe8ecd183e0e0f49a7ce35cfc41472fe857cfa1f0a11596939f325c" + }, + { + "kind": "file", + "path": "img_2905.jpg", + "sha256": "7df7292ddd63287ca8e2cfeafa8af8080c6a07e4cb9948847e343efcba953763" + }, + { + "kind": "file", + "path": "img_220.jpg", + "sha256": "ef530ab73ad9d81aea9b397614ebfdd466c11301504a86fa869100fc3dc9de8a" + }, + { + "kind": "file", + "path": "img_4353.jpg", + "sha256": "35f75739d3897b2685f62e62c76fe9bb6fad163eb50952edeefecd59b90097a1" + }, + { + "kind": "file", + "path": "img_4421.jpg", + "sha256": "4cc2b1d2cfbebaf18a535f22cbd5f87038f3ddf97ca0ef46c374cfba702e0d45" + }, + { + "kind": "file", + "path": "img_2736.jpg", + "sha256": "1dbc3c67feed687cf318cba9a51f9ff8ac13add80e4c8052a7ddf8add2404323" + }, + { + "kind": "file", + "path": "img_1564.jpg", + "sha256": "085ce354b708c0038a2ab6ce929053753b6572ec2796f17d1780778e8763f3ca" + }, + { + "kind": "file", + "path": "img_1202.jpg", + "sha256": "41b7a43bb1d456b94160334cd0f1ab0b8042bcc72814dadc5517d2072657f338" + }, + { + "kind": "file", + "path": "img_2737.jpg", + "sha256": "68e6df2f34d6807e3c32b624e11a326d922488c3fdd63ec5615235c602bd6e81" + }, + { + "kind": "file", + "path": "img_4346.jpg", + "sha256": "4f117e20eb5ca4a1b9f2083744dea2c085c1bce18fa83e22ce882397adb9c2f8" + }, + { + "kind": "file", + "path": "img_547.jpg", + "sha256": "1d013aafb6986d5f8d8226f16fd25d32edd06bec20be3b19a8ea1915767ea59b" + }, + { + "kind": "file", + "path": "img_2910.jpg", + "sha256": "a3601ea440291d87dbd97c5050c0dda632a85d17e04b27125b48e4d5552904b3" + }, + { + "kind": "file", + "path": "img_4385.jpg", + "sha256": "90d7df03a297031054c63e301ee6b41ff41a13c3fc9ee686df87c30cf1c1e803" + }, + { + "kind": "file", + "path": "img_4391.jpg", + "sha256": "22125c40ab2984ad8da05e1bbf22e8bf50ff47e783954fc9a592b34fce7d647d" + }, + { + "kind": "file", + "path": "img_3617.jpg", + "sha256": "00f60328453ba556a6d7023ab7921df221be58ecf6560b6b0cff808abc00159a" + }, + { + "kind": "file", + "path": "img_2509.jpg", + "sha256": "5a5d85cde730a6854c3527f9f80ae28dbe18c911eefb92fb2051a8c3383e2e1c" + }, + { + "kind": "file", + "path": "img_1000.jpg", + "sha256": "ed004a30d9cab949d5585646d1a368922817ecb177a7fab402ea1e9467ccb4c0" + }, + { + "kind": "file", + "path": "img_792.jpg", + "sha256": "63c978e77378d5cf1fa95384dc13a69c9f3eae11c5cc5204879620fdede7f6ca" + }, + { + "kind": "file", + "path": "img_1028.jpg", + "sha256": "122b5e4a123da280a63be1eab44dcc37eb24dc1abce604ba5e494d286d6c55e0" + }, + { + "kind": "file", + "path": "img_2284.jpg", + "sha256": "7d49e91b73ab811afe2418fddd38cdea7d7cc9683dd22f8c3ec6ea8e69820282" + }, + { + "kind": "file", + "path": "img_194.jpg", + "sha256": "bd658ee3b328bd1adade3d060486427e7c32eb3c73cf4f7d9f350df0dae87dbd" + }, + { + "kind": "file", + "path": "img_1174.jpg", + "sha256": "1e4710059b62febbb1292659b345daf76f423288153d1be42e649e92f435e550" + }, + { + "kind": "file", + "path": "img_1612.jpg", + "sha256": "6e5ddb18e50bb58377629a01f0e94ae80855dccf37b63271d1fbccc422ee94e0" + }, + { + "kind": "file", + "path": "img_3011.jpg", + "sha256": "74230014530c28aa2b26ce0568335c69f2db3e598f14702b41d5a69419c0e98d" + }, + { + "kind": "file", + "path": "img_1606.jpg", + "sha256": "8c08cef95089dda197aab431610f51a49782e7b4bb2a4da3b1d92f536db74867" + }, + { + "kind": "file", + "path": "img_3987.jpg", + "sha256": "8e33a3d57602ac183a4be56d348017ad63e2cfdff7164617788478907d7dc0f4" + }, + { + "kind": "file", + "path": "img_2441.jpg", + "sha256": "f931f6fe75c6f61be5f674b3864a6d374a73b67bc79ce5eb363163ccad3d8cbe" + }, + { + "kind": "file", + "path": "img_4030.jpg", + "sha256": "089c95c9285b55967eda61658be8380a3b832d4ae7170b102a9603782508e445" + }, + { + "kind": "file", + "path": "img_2327.jpg", + "sha256": "a6bd64886c50767e9b86f491764d3ca842db71203b370f669bce247b6ea028b6" + }, + { + "kind": "file", + "path": "img_802.jpg", + "sha256": "e59468062f8db8f488666b205ca54b77fd8e918c928960044eee7bef8b4f584e" + }, + { + "kind": "file", + "path": "img_3978.jpg", + "sha256": "84c055206ba5ea7a8e90bc3c6c74c26e37f0b7454b37c15f7e343b935b7f3195" + }, + { + "kind": "file", + "path": "img_396.jpg", + "sha256": "1f4ba50c9ba6ef0c4c2db74c6c933bfd51c3b824f0aa4e82ca88eeaf952acb98" + }, + { + "kind": "file", + "path": "img_2125.jpg", + "sha256": "53a85a8ace99437924b8a65643cf9d0f3295452b5784730054f03f292ec5e317" + }, + { + "kind": "file", + "path": "img_2643.jpg", + "sha256": "d99af16d5e744f921df339a285a68c70c40bfbc444c6718be8617cd67846dcb1" + }, + { + "kind": "file", + "path": "img_1389.jpg", + "sha256": "1bba6cc8236f0cb3c420e51ea0983f585fd93c32bdc6cc8eb9859bb48f4ddabb" + }, + { + "kind": "file", + "path": "img_87.jpg", + "sha256": "52f7a24aba32bd6c06d66b0c8009bbed9526ebf07cf1db2495c3ba0c55a64c17" + }, + { + "kind": "file", + "path": "img_423.jpg", + "sha256": "e122dada4d3026aa9c965f457bbab037215f8ad8907f86705cc5bb228d90dce2" + }, + { + "kind": "file", + "path": "img_351.jpg", + "sha256": "e3a026eba2bb3ef31d1eee1fb48433d27634f56f6c287c58204a49f770de933a" + }, + { + "kind": "file", + "path": "img_1399.jpg", + "sha256": "812905119bafbc290656297c02d89ccd6ea57773414984c1ed1f8da325721272" + }, + { + "kind": "file", + "path": "img_2690.jpg", + "sha256": "db66095db03f4991bf3bb2ebc21a0ad8fded73395d0509241d2e1a9668cc2da0" + }, + { + "kind": "file", + "path": "img_2684.jpg", + "sha256": "a6320f314cd5bc6f389df718ceebbe3769d962c9a9e99fe877be6fcd7b7b701a" + }, + { + "kind": "file", + "path": "img_4578.jpg", + "sha256": "0e4f74206c04ecedbece6dd007a3e15c92e60d24bc98dbf293d1c36ca1817347" + }, + { + "kind": "file", + "path": "img_2109.jpg", + "sha256": "e1880fd538771def5ec11d6948433c90b8b79f6dc43e95ab0d55331dce370384" + }, + { + "kind": "file", + "path": "img_1366.jpg", + "sha256": "95b83fe7a7ba884b1d23ce400e424e5a478dbda595c300fdd807009705bd98b3" + }, + { + "kind": "file", + "path": "img_4785.jpg", + "sha256": "4cd6df98b29ac1d53ead8efe3c226591cf80ce9e9acf695512273b09d1e51d7b" + }, + { + "kind": "file", + "path": "img_3773.jpg", + "sha256": "bc8de538bdb83f08ed7c681be9396346e80825c96999e0ed063b7be63e1d8e6f" + }, + { + "kind": "file", + "path": "img_3001.jpg", + "sha256": "269d1984a7b38b592ac1e116b54d3f62e2498ea49685e2ac6f6e67fd710b329a" + }, + { + "kind": "file", + "path": "img_2479.jpg", + "sha256": "816f7627d27c4384a2d6e445eccc74ef147af315eb2e6758a7ff9e2fca48643d" + }, + { + "kind": "file", + "path": "img_4020.jpg", + "sha256": "13bfc8d75e04b27c6a8effe45ca84f52b5c8cf488f736458fcbb7c40599b2bf0" + }, + { + "kind": "file", + "path": "img_806.jpg", + "sha256": "153b537475760c37c1f8f4856ca11d6308719d2c418ba374d7bbd553d4f376ca" + }, + { + "kind": "file", + "path": "img_4746.jpg", + "sha256": "0087f36d5c8e29e0d4b5fe0229f80fb530d8f6c2a46dd86bb46f2b894fddefb9" + }, + { + "kind": "file", + "path": "img_2323.jpg", + "sha256": "4b79bee836a39ae3baadce64ee76bfb181c5a70016281dc415b564132f693169" + }, + { + "kind": "file", + "path": "img_3983.jpg", + "sha256": "3f7cf8182886742017a4aceb5f5a699b65ca1c19a2672ff41304e64bd54c3132" + }, + { + "kind": "file", + "path": "img_4815.jpg", + "sha256": "37c608e33debad5ad72d4d72e5e1bb479f715c9e201e59ba3d7eb8268555b3a3" + }, + { + "kind": "file", + "path": "img_999.jpg", + "sha256": "2bae10a72123830129132378ce5c209d0f4d8bb0d3bbbb8cd373b8601823c923" + }, + { + "kind": "file", + "path": "img_3820.jpg", + "sha256": "bc084b792a15faca2ea306c487000217f3e7855b045b13abe9e36d6240b12ba7" + }, + { + "kind": "file", + "path": "img_2280.jpg", + "sha256": "a50052cef5dd8c825c81bc6c7b13a8493596924afb735598fd8d7a428d88591d" + }, + { + "kind": "file", + "path": "img_4829.jpg", + "sha256": "5af3228c6011a66596ebb49a945472efe63c1d44d1ff52b2d0cdcdfab98d063c" + }, + { + "kind": "file", + "path": "img_4183.jpg", + "sha256": "068d565446f93c02e963e0f3dbe09894a5df531a9d5f4418295f44372e7949af" + }, + { + "kind": "file", + "path": "img_796.jpg", + "sha256": "62ea8748717d62b0dab64aeccf35ecc52724b9647fac7780ec45733f896476b3" + }, + { + "kind": "file", + "path": "img_1762.jpg", + "sha256": "4d2584da5f6d30dbf60d8f84e5407bbe4a4064671bd9c56ebba881eb7a350712" + }, + { + "kind": "file", + "path": "img_2525.jpg", + "sha256": "dd4509a7606455f4b188dba2bd2c9a40ba2fcc46d914f7cbaf7e11a372714ea2" + }, + { + "kind": "file", + "path": "img_1038.jpg", + "sha256": "51f168866cc32c6e8398c8506a0c547701bb9e686594286c4f996cc9974a6839" + }, + { + "kind": "file", + "path": "img_4381.jpg", + "sha256": "7f70f789a1254775bfda2d4a66463db533949942053ca585118a0dd7acbf6434" + }, + { + "kind": "file", + "path": "img_2928.jpg", + "sha256": "2d8698634f25a58a72f3fb89fbfc588546d6b036772224465494d93da9e86695" + }, + { + "kind": "file", + "path": "img_3405.jpg", + "sha256": "5e14bcca20023d65300d86a217e61b5a61b524f4d80701177cbc5c7caf46053a" + }, + { + "kind": "file", + "path": "img_2041.jpg", + "sha256": "53a8103ee517c52b9e81ea80cebe5b40f35a82c2bfb338eb3062c50e071c13eb" + }, + { + "kind": "file", + "path": "img_4425.jpg", + "sha256": "7d84345ef8966941c9b51152b8211063c57b58e90069b78ec24f60eb0e3f1fa4" + }, + { + "kind": "file", + "path": "img_1549.jpg", + "sha256": "c7cdedadb9bfc50bd4ffc743c6969a4bff28259b5a6d0769dccd6f213eebdc7f" + }, + { + "kind": "file", + "path": "img_3362.jpg", + "sha256": "670e4efaa627ceaa052eb8bbd0e48cf32b059a6480410ff727dc1f5305df9d7f" + }, + { + "kind": "file", + "path": "img_4380.jpg", + "sha256": "7a78ccf664369257a79ca4325da6784d68c1a7ea7041cd8ec932eb21f372473c" + }, + { + "kind": "file", + "path": "img_2901.jpg", + "sha256": "1c0ba1a19cb34a7e044e9ff4b7b317684a50787472864b7c1fcaeedbd73ca546" + }, + { + "kind": "file", + "path": "img_967.jpg", + "sha256": "0f48edd75456e6ebb7903c684ed8250752fafd800b88e72de935db05d92c10c5" + }, + { + "kind": "file", + "path": "img_1987.jpg", + "sha256": "53ae76718386b89d7c1c4d612e254a59b46a7205adf4bacf02a2c2deb95c2070" + }, + { + "kind": "file", + "path": "img_2524.jpg", + "sha256": "015c4f57a81cc66127292307510e74b660a3b4443cec4bcb3a7b86e30e3920f9" + }, + { + "kind": "file", + "path": "img_1993.jpg", + "sha256": "401938289506de8bfa16e9ea8b866ccd80af2d6e8a297535584570fc7c699015" + }, + { + "kind": "file", + "path": "img_2518.jpg", + "sha256": "3f206f2501fb9fd052aa73bf56c51c6d46caff9ba75106c1269fee70453bf6e6" + }, + { + "kind": "file", + "path": "img_3835.jpg", + "sha256": "7ef3a7553818992c4c3c09a68a769ba931b1fc0b052bd085fb9e708fc5305454" + }, + { + "kind": "file", + "path": "img_2281.jpg", + "sha256": "9cb94e211ae861cd844f4393a3965c1f3e0d77a0eefd6bd174a40a1d984252de" + }, + { + "kind": "file", + "path": "img_740.jpg", + "sha256": "8b8ba6adf45dd36a5ce83c39de3bea561dfcea9d30d82813667952b5b2b5662a" + }, + { + "kind": "file", + "path": "img_4800.jpg", + "sha256": "27486245d8a28de69edb4ffc16fc66fdd03255b486cfcf9db2c8ad0be9ef031e" + }, + { + "kind": "file", + "path": "img_4753.jpg", + "sha256": "5dcb2f7f522ca12c9b03784b249fb087018fa454d31fbc9995cbaee0be3be97b" + }, + { + "kind": "file", + "path": "img_2322.jpg", + "sha256": "d221ddea84d3ff9001599e9ceff2ee8da9ebda63e5fc731d6c385c0004795aa6" + }, + { + "kind": "file", + "path": "img_4035.jpg", + "sha256": "dab9379e1a91bc23ced2843044191427d638561e053fb7c71d5b0244fd9e407e" + }, + { + "kind": "file", + "path": "img_2336.jpg", + "sha256": "afe214954f8606e181c4243e9df04f7b65e1111c8a7be334800d5e3206df6e29" + }, + { + "kind": "file", + "path": "img_1617.jpg", + "sha256": "52ece3473f64dac94649f906e158e4eb184e21ee357a117de8d1499d83e1c1aa" + }, + { + "kind": "file", + "path": "img_4784.jpg", + "sha256": "796197dd15804deb19113f4d87a56fa8231fceabddc46232e132d4ca56fa4b39" + }, + { + "kind": "file", + "path": "img_1824.jpg", + "sha256": "54b693092cf60c32d8d85833c00e7b8c2d6b2d94bab077a525b50d57cf70d25c" + }, + { + "kind": "file", + "path": "img_1818.jpg", + "sha256": "a77a62687a60077598b63452efae61422b3ee24473f2b717982028ef66abe18b" + }, + { + "kind": "file", + "path": "img_3558.jpg", + "sha256": "c7810e97cd65ff1a5e25ac54abcd9bd11513b340ee6546278f664826c2a027d6" + }, + { + "kind": "file", + "path": "img_4237.jpg", + "sha256": "c5c4845f487f631b81621f20513b86464cfc5da81f57c646d561eef73208b14e" + }, + { + "kind": "file", + "path": "img_1429.jpg", + "sha256": "b72ea33f9b2ace713ed671203fbbd1650d739de1053e6d8f80cb6a7f4e7266cc" + }, + { + "kind": "file", + "path": "img_2120.jpg", + "sha256": "e5539e75f68987b39092c5e9d6da4b8694212a186eb5ee100e8bd4ed38ad9af2" + }, + { + "kind": "file", + "path": "img_41.jpg", + "sha256": "409513655bee7d79e9502d78893a1a0317a87f76532a1fb356e2b0836abd3eab" + }, + { + "kind": "file", + "path": "img_1401.jpg", + "sha256": "a61f0c6ca9d02288ed7d217bcaf06d0104f61ec70f42f5ffcc3ba6387d4fc529" + }, + { + "kind": "file", + "path": "img_2685.jpg", + "sha256": "af450181d046ac5da0aec9dd6e4dfadbbce2f6006c5a269fbb0eadb9905c5db3" + }, + { + "kind": "file", + "path": "img_2861.jpg", + "sha256": "6f653173325c2a2b3a2fbd2563f392ddef364a0e4761ecf26bd387b83c3a6df9" + }, + { + "kind": "file", + "path": "img_436.jpg", + "sha256": "78ac6eb4d437ccd1a6847ece3859ed2d5f3094542b9d47b13c4d393b47a6b17e" + }, + { + "kind": "file", + "path": "img_3599.jpg", + "sha256": "edc71cba15c2b3222b2a41ed89d01dfc98fed2151d629d6d4680345756510056" + }, + { + "kind": "file", + "path": "img_2693.jpg", + "sha256": "8f0a0c44d69f0ef75c4cf301dbd17e31080f71dc13a68b5ed37687ab97416e7e" + }, + { + "kind": "file", + "path": "img_4209.jpg", + "sha256": "0e63f530f4641bcc25573865ee07752845b6c7e15d26a705c96efd119aa43fe2" + }, + { + "kind": "file", + "path": "img_3572.jpg", + "sha256": "0e1587178953b050d5ea3dadfa617ca9881ca041d3d6747db40a7ba3a65a6cd1" + }, + { + "kind": "file", + "path": "img_2644.jpg", + "sha256": "953e2def562a5da5f80309ae1a8d7aa88eec3d1597a91ea98ee8f8b64b7f44fc" + }, + { + "kind": "file", + "path": "img_2650.jpg", + "sha256": "bffecb19bf9bf6c0fb066002fcae8ecb0cbf89fe154d09c27e45f375a86736d4" + }, + { + "kind": "file", + "path": "img_4221.jpg", + "sha256": "4553ccfa718cde946fa055e8b9a94ac40589ff314bab2db4f2d16ba1d590b791" + }, + { + "kind": "file", + "path": "img_3943.jpg", + "sha256": "09dd67ab523e42c21fe39a78dd8569704bec5d5a0eee5f12d511ac8a785ef5b3" + }, + { + "kind": "file", + "path": "img_2308.jpg", + "sha256": "37daf389b3133792fd4992146a6d91bf826e08e5d893865ac22c42fcb6a08cb9" + }, + { + "kind": "file", + "path": "img_3016.jpg", + "sha256": "e8e52468b0287dee9cbbef49b400c7a4ff63f3196c4890d3cff2803187be907f" + }, + { + "kind": "file", + "path": "img_1629.jpg", + "sha256": "2d14525254c12f66df35b34f165cf05b604ab17a643d680add748ac4420b0d59" + }, + { + "kind": "file", + "path": "img_4816.jpg", + "sha256": "021616a42d163e824b60f00c60788bde7b7d9463adff3eb016e91eb3127978d4" + }, + { + "kind": "file", + "path": "img_3189.jpg", + "sha256": "681f003c9c848281be32fcf80d62d50624aec9d14d4f53df7414c0f3e1262e29" + }, + { + "kind": "file", + "path": "img_4194.jpg", + "sha256": "f4e01fa1837314f508dbd37435ea1a13d407bd2d11a901624cf7e6073415c2b6" + }, + { + "kind": "file", + "path": "img_1007.jpg", + "sha256": "bb454bfcee80c5d9b87efc2c16587f82eae52be74f55f3a4ae286cff70e11c3f" + }, + { + "kind": "file", + "path": "img_4619.jpg", + "sha256": "089a269ac7994b2da633eeab8fa2df4363aa79c0e6f49011ff3b77788cb05683" + }, + { + "kind": "file", + "path": "img_1761.jpg", + "sha256": "e9efc044395bdc8a930c5de8f9a6175f638b910f598c51ebf7417ed5486eee27" + }, + { + "kind": "file", + "path": "img_1013.jpg", + "sha256": "96c33d8878cfef64d96af0583def110dd56471fd875dcf821f6c5e1be751804e" + }, + { + "kind": "file", + "path": "img_4157.jpg", + "sha256": "08af2db21920a26654b0aa68372e0b8aa66d191f60c1bc78a458da066b4d2d79" + }, + { + "kind": "file", + "path": "img_2917.jpg", + "sha256": "61708b8b9afd448116d23ee269a7aa852f62b5c1221483c99e910340e50c468d" + }, + { + "kind": "file", + "path": "img_2903.jpg", + "sha256": "d1b239fc5b0ec2d0f7d2887252cb3cfe49f9ae2e3eb801573a23b9068507eaa0" + }, + { + "kind": "file", + "path": "img_1211.jpg", + "sha256": "3a0ce2b8d2c4636bc526e03d00d8980cf05bfaf2bd2cf1104e7fbe283a36cbde" + }, + { + "kind": "file", + "path": "img_4369.jpg", + "sha256": "c91582bc4a89eef2a8934a1ff27f0728bbacea1cd9bfa56b90a9d4efdf9ca83e" + }, + { + "kind": "file", + "path": "img_2718.jpg", + "sha256": "aa3d9451594dcdf8189200d0cf7fbaa6f9f32eeeb12b5e6d56f2871d74557b2f" + }, + { + "kind": "file", + "path": "img_1577.jpg", + "sha256": "ac9deb443f031f13b09f4a65ba0dc6127859a35f80adf709fa9b1b10c059d74c" + }, + { + "kind": "file", + "path": "img_4355.jpg", + "sha256": "b504a7c275348d8933791d622f409a688048990246db7a0a17c62569358613aa" + }, + { + "kind": "file", + "path": "img_2724.jpg", + "sha256": "408f052a0d2e20f981b5b5e81086dab86cdbd754329882e0a003d652618b984b" + }, + { + "kind": "file", + "path": "img_2042.jpg", + "sha256": "174d3407d15b83aa3cda4523a51dfff39c3e242adedc0820b2461f8626816bd1" + }, + { + "kind": "file", + "path": "img_3407.jpg", + "sha256": "9ae3c0ff6eacc7904fc7551e49cc243cfc89041eecece84eed5c009fa0b25407" + }, + { + "kind": "file", + "path": "img_1210.jpg", + "sha256": "40ac12a50d8e7a4ffa9007ba60228cfbf4fea16cc520a253ecd2f699a08198bc" + }, + { + "kind": "file", + "path": "img_2094.jpg", + "sha256": "f30f337146802dd87c423565c0f1eccc6242395836883b4832ed6947a0da15a0" + }, + { + "kind": "file", + "path": "img_4383.jpg", + "sha256": "7d3030b4686c629c1e5730486fd4deefaf47021195e44effd9a9bc3ef7a80b0e" + }, + { + "kind": "file", + "path": "img_233.jpg", + "sha256": "e574b28373a09c8b1d405a515604803cb50162ce4ce05ed78e981e15fbbd216d" + }, + { + "kind": "file", + "path": "img_555.jpg", + "sha256": "683ca4911773dc4feb7e6fac8158b8776fde0175816dfabf1f86ba85aec715c0" + }, + { + "kind": "file", + "path": "img_1748.jpg", + "sha256": "a4e92eb64504d4c0c9b9468fad12858018649685c71e45719cecb96d00aeab56" + }, + { + "kind": "file", + "path": "img_2241.jpg", + "sha256": "9b252b1013af7a9654f72d74a56268e70c7e0ad2e3473e2757db11c0a81ff816" + }, + { + "kind": "file", + "path": "img_964.jpg", + "sha256": "e449c16589bf8a4dd10f484768e9d68075e51e40bf25c440377a3b4326b39408" + }, + { + "kind": "file", + "path": "img_1760.jpg", + "sha256": "802c0415d71ba886c9fe311e5c193b920c654410ea96a910b0bd5e0178b4a49a" + }, + { + "kind": "file", + "path": "img_1947.jpg", + "sha256": "2e278acec9b8463b095f394c48abbb29f7d311f733fa1fde6a7a0fe10b2bbeb8" + }, + { + "kind": "file", + "path": "img_3188.jpg", + "sha256": "f20c4ac68332d9a25a34e0b0ee2eaf9083d19df57d6ecbdc5f71987bc8fe18a6" + }, + { + "kind": "file", + "path": "img_4036.jpg", + "sha256": "bafa89c1e629f01505216f8ac1eff0cd34a250f70fb4e3569cb0af0d02ea62ce" + }, + { + "kind": "file", + "path": "img_1614.jpg", + "sha256": "953f95380e3844493ee65f97c86e60a0932d90e4367aa2d0d4e235a9d211147a" + }, + { + "kind": "file", + "path": "img_179.jpg", + "sha256": "15e0e5f027bcd2699dfc88e7afe39076ee77036096ca98db7130783e1e8f749d" + }, + { + "kind": "file", + "path": "img_2490.jpg", + "sha256": "209458b2362f89fa870c3445581062d9cce7f682df13bb1fc7b17c5533c1f150" + }, + { + "kind": "file", + "path": "img_3956.jpg", + "sha256": "6fb901b7868cff44d85df2c7c22c8e4d0199de0a5dfa4b6af3de9d4d2b7c7158" + }, + { + "kind": "file", + "path": "img_56.jpg", + "sha256": "c53189fe22e92f3863798c22e67a21ff1ea79f4ae0aa6ee6249c6d10a215298a" + }, + { + "kind": "file", + "path": "img_384.jpg", + "sha256": "87b8ae9464052d3828a5ad9ef81e653848a522f632e8e9ec8bea539dbf9a6aa8" + }, + { + "kind": "file", + "path": "img_1370.jpg", + "sha256": "8810346c21902f00e1e7b78a0d91f5604e7cab2ebbdd689326513b4b57061604" + }, + { + "kind": "file", + "path": "img_2692.jpg", + "sha256": "c09cc74249d14316d17ef548ea382350b9d0061e9f54e2ff7fe93ba62f480c8a" + }, + { + "kind": "file", + "path": "img_347.jpg", + "sha256": "594454d9ad7e86d82bed20b3fcfd7304d5f32eb461e21d6cb198ed7adf28e8df" + }, + { + "kind": "file", + "path": "img_353.jpg", + "sha256": "500f5c4419bfa8020af57b4cd06ae61c74d4d38dbabd5a12bb3370e304d8fa0c" + }, + { + "kind": "file", + "path": "img_2187.jpg", + "sha256": "bf796fe2e3bc5395d9cc1ac29698c3b84a0758b0a94edaf4db92f6f44dddb175" + }, + { + "kind": "file", + "path": "img_452.jpg", + "sha256": "b8b592c0faa7fb78c8c3fb7ec7edfad16a8ca52648634d24d1a521ac60d598f6" + }, + { + "kind": "file", + "path": "img_4535.jpg", + "sha256": "75fb17ee703d9e0d85e3583736aed9d770007d10b3564355ff6c48562fb90914" + }, + { + "kind": "file", + "path": "img_31.jpg", + "sha256": "2940c096279b52a247c90c17df56d7b59e7ee295a2719cf3c43cf08b4f95e596" + }, + { + "kind": "file", + "path": "img_4253.jpg", + "sha256": "6695800701639ce7a93c14a0c144f928ff5524ad0bf2339d4d4387869e835349" + }, + { + "kind": "file", + "path": "img_4247.jpg", + "sha256": "de53ec0ecfbaa15c80420d38ba2397b68a9272f8520f8a44a76b3172726e500a" + }, + { + "kind": "file", + "path": "img_1471.jpg", + "sha256": "eba95dfb294601b6f5d87d28a1369b677688b75159276db7c099ad82e9a43f4e" + }, + { + "kind": "file", + "path": "img_1465.jpg", + "sha256": "35a680022b081375ff2b271f9ac4cc11a1315fd814bfa556c24ba47752b5bc2d" + }, + { + "kind": "file", + "path": "img_2385.jpg", + "sha256": "a251516b1c261fd0f42c26e3ef2f61430531579d5a56d27581f14152dd7ca03b" + }, + { + "kind": "file", + "path": "img_678.jpg", + "sha256": "06eab15bbb1dd2b4fd34edbae3f0c3bf486607eebbf042204e86ad5d48dc5274" + }, + { + "kind": "file", + "path": "img_4086.jpg", + "sha256": "f596587c83429e8fe244ae13b06ea5a229e82147f162e68f846deb40ce33c710" + }, + { + "kind": "file", + "path": "img_888.jpg", + "sha256": "f742bb11d185565e3d617c61ce2f4102cdb53a15e063e8b297b1d008a7eeebe7" + }, + { + "kind": "file", + "path": "img_644.jpg", + "sha256": "9ec9a49be23243d7bbf7343b04757ceb4b3c5f927a9920e375b14a0f530cd6bd" + }, + { + "kind": "file", + "path": "img_2420.jpg", + "sha256": "9aac7b957a66c13780476d5360f25420801901eeabe58f46c70f28e8bf3a17f8" + }, + { + "kind": "file", + "path": "img_863.jpg", + "sha256": "758680af9458b31c527cc47e3a726524809bca4c387248cdc2557e4af2e27306" + }, + { + "kind": "file", + "path": "img_3702.jpg", + "sha256": "9cfe1874d041c5427e4f30bd17d0c310097e1bdd8d809429274a5065e684005e" + }, + { + "kind": "file", + "path": "img_1115.jpg", + "sha256": "36144f3be3307d1bcfab3b712e28474caa05967f9e0a720966573bffb3f8146d" + }, + { + "kind": "file", + "path": "img_687.jpg", + "sha256": "32b07a9393fb6da8e2c78ae60f5d2b5529b16af698fc299c9af0b65ab6f8994a" + }, + { + "kind": "file", + "path": "img_1101.jpg", + "sha256": "45b47e59972399123234262b7b71a71986d541f70d0d73692d92f796e3d2a6d3" + }, + { + "kind": "file", + "path": "img_1920.jpg", + "sha256": "37c4e814ab04e0a1226eda209d067a4ea7a9ef1ae1aaebdb12c92e451e0ad2c5" + }, + { + "kind": "file", + "path": "img_2583.jpg", + "sha256": "9c4b81c7cd6134194034c5fa457ad2c595d7b0232549fba63848c8b81c0508dc" + }, + { + "kind": "file", + "path": "img_4864.jpg", + "sha256": "266cd832f7f125e586a16168c46d682972f43ba24c282db3597e1e8735032f77" + }, + { + "kind": "file", + "path": "img_2232.jpg", + "sha256": "561e43fb815ce7a2749e76274e0335acca8757745b8b516801dc009ad539b427" + }, + { + "kind": "file", + "path": "img_3138.jpg", + "sha256": "326c74dac3c20a4da62d324c9cdf1e2dc1b6cfeb8587122270548f5170917f28" + }, + { + "kind": "file", + "path": "img_2540.jpg", + "sha256": "649ecfc0532481861b46c62728579c7506097572dd8dfc906e35f479c981e13c" + }, + { + "kind": "file", + "path": "img_1707.jpg", + "sha256": "d79c2fc701cd3875c4ee1c06793ee5d1a98dce27eec76eaec09b704b367d8b17" + }, + { + "kind": "file", + "path": "img_3110.jpg", + "sha256": "d34fefe796122e6f45be02f8f75442d6820f96f93666e4576ac35e8afd895b6b" + }, + { + "kind": "file", + "path": "img_3104.jpg", + "sha256": "99fda2d5b2fa5d25a68c622a072d9889565ba411bfa65ad2ff1085c9383bbe90" + }, + { + "kind": "file", + "path": "img_4482.jpg", + "sha256": "0cf4540852323ad617d3a10a5f4e0ed495b258f1f3aabea27533e59224bdce38" + }, + { + "kind": "file", + "path": "img_4496.jpg", + "sha256": "f7c0a75f4e8d25b418c70545e6e85e89ba94605b9c3a6fd7902be390731671fd" + }, + { + "kind": "file", + "path": "img_526.jpg", + "sha256": "d4b5f5623904f917d3856852094ab8432a7f681b109a15a1a2a6e2de659d0fc9" + }, + { + "kind": "file", + "path": "img_2965.jpg", + "sha256": "f7847fef946cf2539ec569e81478d26302ff398d2b5108555d089a9ce4874b12" + }, + { + "kind": "file", + "path": "img_2030.jpg", + "sha256": "ae7ee6be52e32b02a87111753e77c87673076642a8a18262ee7e246c3527cbdd" + }, + { + "kind": "file", + "path": "img_4327.jpg", + "sha256": "3f01c76144e564229a62ca73257149ccebb0e5d56db52088287eb0bd30a56844" + }, + { + "kind": "file", + "path": "img_4455.jpg", + "sha256": "d6089d11fca7f1af22f3874e287f6072ef9ea585f4173e50539ec2a6c34e12cc" + }, + { + "kind": "file", + "path": "img_1505.jpg", + "sha256": "bb1da369584da032ed7424b0d11e40b2dad5f50296e2d9d0770bc6b7e1ca55db" + }, + { + "kind": "file", + "path": "img_3460.jpg", + "sha256": "d0050bea77e5a78e16815260a31017de337c7eec0f10a870efc6a70b6acc2766" + }, + { + "kind": "file", + "path": "img_2743.jpg", + "sha256": "1ef748439bf4c1bf896a868b39c18cc472f3c253c8a7d3d02f1c43c2c7029deb" + }, + { + "kind": "file", + "path": "img_4332.jpg", + "sha256": "e91f2bf3762fc35734a6033693197c43551db13e9d222898ccd1d85169e41ae8" + }, + { + "kind": "file", + "path": "img_255.jpg", + "sha256": "42fa5745a68abb63bf23c7105df2d0e9fdd5a89e74d37a70d4c46da5215085b7" + }, + { + "kind": "file", + "path": "img_2964.jpg", + "sha256": "39aa72907ca654e777a27efb158ac430c0b43d14f83fa1320cb2926ee19f057f" + }, + { + "kind": "file", + "path": "img_2958.jpg", + "sha256": "cff248ddd2e68929fad1fa27cea59534115e11d4a06ccd2167bf856d83ac8a2c" + }, + { + "kind": "file", + "path": "img_9.jpg", + "sha256": "856dacc973e484b3c73a3678d77bdbf41df828d010d76aedbfb50f618c3c9546" + }, + { + "kind": "file", + "path": "img_1712.jpg", + "sha256": "bffda89556722d3de4ba769a788762869d99c8683d12732ac91c77ed86b5c4a2" + }, + { + "kind": "file", + "path": "img_3677.jpg", + "sha256": "e4ef08bafc877c84e218f165e0790be3ae1e308342fef7181bbd4aad36846ea4" + }, + { + "kind": "file", + "path": "img_916.jpg", + "sha256": "3f5243751cef5cc2947ab4dbac2ce83bb3e70cdcf599b9a86761f72c85dd9e64" + }, + { + "kind": "file", + "path": "img_4130.jpg", + "sha256": "42c622f27cad66a82ce7c9b8abb5848291b6e10dc790dc725a00a34ce550adfa" + }, + { + "kind": "file", + "path": "img_731.jpg", + "sha256": "bd78451914d1fb21fdbd48adff8cfc60b1746ce9660e1369bb132906c629d6dd" + }, + { + "kind": "file", + "path": "img_4871.jpg", + "sha256": "1d3b526a6e6b7420a909f810a4043e61fe07a9c6af03210c056e8ea937e396d0" + }, + { + "kind": "file", + "path": "img_725.jpg", + "sha256": "593a1570b8a7e95d397601ca894684cb87fe908858dd7c6f37875cc1ab69759d" + }, + { + "kind": "file", + "path": "img_4695.jpg", + "sha256": "afc6788c1d332e0d2905cfe938cc021353e1073d0f22ebca989c1cf29819ade7" + }, + { + "kind": "file", + "path": "img_2582.jpg", + "sha256": "256f41a53e044256e4c739dc20927c8ff035aba782e5833bbae6b53426d9c333" + }, + { + "kind": "file", + "path": "img_3844.jpg", + "sha256": "9f0a05399a090397c0f84b6607adb7affda36ff4f4595ec1a9e1bdaa8533a4fa" + }, + { + "kind": "file", + "path": "img_686.jpg", + "sha256": "6174901560fd9f5c4d8259ce7ee5354f63f84209ce0e367c0c0afcfda1f0bd3e" + }, + { + "kind": "file", + "path": "img_4078.jpg", + "sha256": "5d7aa420a11090d36c1dd40072fcb83b5a28bdc07747309a64fe9133ec50b655" + }, + { + "kind": "file", + "path": "img_2421.jpg", + "sha256": "26da86a914499ae026eb1d15e62606cc96dfa17dd3469e9061913f0c6cea046e" + }, + { + "kind": "file", + "path": "img_1896.jpg", + "sha256": "2442e0d495c19f38415a447942ea0dbda236d606f5e52fe43d6802bd84bd180f" + }, + { + "kind": "file", + "path": "img_2347.jpg", + "sha256": "3192cf98b24523bf75df9cb67a9bcf286d2bec7efd44b5bad2ac9e2e5fe41599" + }, + { + "kind": "file", + "path": "img_4905.jpg", + "sha256": "567945226a3c2adb55c56fa0000e429a411f33b8091a92168333f85b967a309f" + }, + { + "kind": "file", + "path": "img_123.jpg", + "sha256": "6b9c122313ac94155d9030688d62b3cf90db5fcefc79d0abcf1ca3149fd409fe" + }, + { + "kind": "file", + "path": "img_3918.jpg", + "sha256": "b935be407291673e8d762229f10441a30869360390ad3d16ea75314391351e8d" + }, + { + "kind": "file", + "path": "img_1869.jpg", + "sha256": "6c29bbef7354e522f571ca54cf47b88dc25860b4b78a3a4f0579f38ef0c23886" + }, + { + "kind": "file", + "path": "img_3515.jpg", + "sha256": "1001ac9ab2148865c8983106ccabba1abc9d574803ced5f0fb1ac49f0f74300d" + }, + { + "kind": "file", + "path": "img_2179.jpg", + "sha256": "63f8b797e46833d0c550d22c1986f3b3132b61ddacb2dd3c474791382abf0ae9" + }, + { + "kind": "file", + "path": "img_1316.jpg", + "sha256": "2d26c3e7f686011f75d3ba340541b8f8631fac8d78935c801eda3920191dbe08" + }, + { + "kind": "file", + "path": "img_4520.jpg", + "sha256": "4eb0b491201c94aa8768be2da01392186ac248f8d6b801426e4502043eaeaf4b" + }, + { + "kind": "file", + "path": "img_2145.jpg", + "sha256": "9d615f03f69746779b615f5458cb14ba81b5e0102ccbd245759de52713876c9c" + }, + { + "kind": "file", + "path": "img_321.jpg", + "sha256": "81c5bc6415effd89f182e18095f93932054ecbc622f93a90c1ffe9c9fc88a5d0" + }, + { + "kind": "file", + "path": "img_2804.jpg", + "sha256": "0cfd87d75d5bfe5d1637d4a7b45662b0bb834dbf6f87ddf8c0483861ca1b86a4" + }, + { + "kind": "file", + "path": "img_2192.jpg", + "sha256": "e64ff23761c327d4873f5fdba26365d49a68d09f42d08074aedda517dc397c95" + }, + { + "kind": "file", + "path": "img_4293.jpg", + "sha256": "fb855aa8ea67f908e81f7693271a2490cad45f063aa57e701d5cdf6d76586b37" + }, + { + "kind": "file", + "path": "img_2184.jpg", + "sha256": "0ce7dca09aed207b58ad0773f594da588d393b2721dbeff6574187b7e59b296d" + }, + { + "kind": "file", + "path": "img_323.jpg", + "sha256": "1b035b39e14a56b96c9e4c00a884443d2e441d6c85ae901687af15cd53524357" + }, + { + "kind": "file", + "path": "img_3517.jpg", + "sha256": "096adf5c7dcb9ed94f56f494e0b86dde3f7ceb6d03405d5b7864435a7ecc0481" + }, + { + "kind": "file", + "path": "img_3265.jpg", + "sha256": "bf00745a96d41fe930e19cfbfe4dd6a41dd48796c547b3e1471644b2439ac634" + }, + { + "kind": "file", + "path": "img_3932.jpg", + "sha256": "0f36f41df788ed8dc755d58efcdb3f68c6dda8aeadce28ea455f6422dce38adf" + }, + { + "kind": "file", + "path": "img_4091.jpg", + "sha256": "e77295380233a00fb13c49652ec07098e81c86a6dc25a1b700dec904c787a5dc" + }, + { + "kind": "file", + "path": "img_121.jpg", + "sha256": "57c7e585f431fa370965addc8b4985043f979e685e64c41788251db3b3111f5e" + }, + { + "kind": "file", + "path": "img_4913.jpg", + "sha256": "2535986e749bed64d7cbdd0710051017fa8dc68d59ee75c4ab0bbd3725350b37" + }, + { + "kind": "file", + "path": "img_3729.jpg", + "sha256": "927c8df1d7abf11db06f0e3ee0fb64a2b75b5b1ce90efc0cb97dc1875fd1d44d" + }, + { + "kind": "file", + "path": "img_2437.jpg", + "sha256": "152badf68a18d2c32836aec11191a7c02a279118ae5ee8df52986b1a4cfb2ab1" + }, + { + "kind": "file", + "path": "img_860.jpg", + "sha256": "77c733eabdb4af18542e76fc8cd23b56b4f7d0905d7e626ee783766c694def26" + }, + { + "kind": "file", + "path": "img_4720.jpg", + "sha256": "ae950a4a842a83b33a84475430036110b58a08ec5ab33990f4b52142ad557896" + }, + { + "kind": "file", + "path": "img_4052.jpg", + "sha256": "a033493477559f5447114c564a7cf67b573e93a8139670c7aaf5c4f26ac23f1e" + }, + { + "kind": "file", + "path": "img_3715.jpg", + "sha256": "e9e127fbbeda5aad426714cb38cc76422a7f5c40274c176c88870b95a120b3c9" + }, + { + "kind": "file", + "path": "img_684.jpg", + "sha256": "2198ab04b6ae1e73cd17b4c888f279e428200031ca33e2f6d73ac39d692a5210" + }, + { + "kind": "file", + "path": "img_1670.jpg", + "sha256": "3ce9d248f71b14b01b3da03e3624d904e8050605c46fb0c1ddc4ecb4e6687ef8" + }, + { + "kind": "file", + "path": "img_4708.jpg", + "sha256": "09b64507150072d8c3bd0e317e2a4bb092ac08614c31d58e3cdc242b2faabc21" + }, + { + "kind": "file", + "path": "img_1116.jpg", + "sha256": "a76c05343d74edc151cc7ea0fd04b808f9c1fd5a065eca0400455c4615ff4696" + }, + { + "kind": "file", + "path": "img_4697.jpg", + "sha256": "7fb843e4d5c73a14782cf34660d404dd2e12023be2835ea55dd9f7ed513fd673" + }, + { + "kind": "file", + "path": "img_1923.jpg", + "sha256": "de0bffbae894906f3413532b2a3b7b3abcd60c242e1ef0281d9471c5386ffadb" + }, + { + "kind": "file", + "path": "img_3852.jpg", + "sha256": "e7baf45d0fdb3047a9205d727511ba468c84afd17dfed203e5df852744290426" + }, + { + "kind": "file", + "path": "img_4867.jpg", + "sha256": "096208bc89f42427c05007ca22b98f206751affa21f73bfb47d0ff4f472f966b" + }, + { + "kind": "file", + "path": "img_914.jpg", + "sha256": "3357175e449aa9070b535e64fd52915df63e82448c1a2bc47e30a5f88ae9afa3" + }, + { + "kind": "file", + "path": "img_2231.jpg", + "sha256": "0cda9382aebfcc2535c8f33c0ea37a459e74cefc101d71e3677a05506be0c04e" + }, + { + "kind": "file", + "path": "img_3113.jpg", + "sha256": "79e3b0c75a79e188999124648e5096680982ea133a198880e8cc5ea7014c291f" + }, + { + "kind": "file", + "path": "img_3675.jpg", + "sha256": "5fb9917a461491d131d6996267d81d3e15c83b13a80a1cd46957b9368fc95ff2" + }, + { + "kind": "file", + "path": "img_1062.jpg", + "sha256": "5bb433ddcd1e690bdd268e675ec5e207eadb841cc67a1e5830f64dde7715f46f" + }, + { + "kind": "file", + "path": "img_2782.jpg", + "sha256": "2f52120420e584c3ab54be1dbc8ca06f6d6152200e1a4846972e12052aad4135" + }, + { + "kind": "file", + "path": "img_2972.jpg", + "sha256": "9bf7952cd4b42d5df0a8fc9441aa27b3658f045e774d35fe972c23d2b725278f" + }, + { + "kind": "file", + "path": "img_4330.jpg", + "sha256": "d3781e9dfbb92a4013ccedef1dc7e17df7c34cb821a9b6cf0d7c29bbd9f79501" + }, + { + "kind": "file", + "path": "img_3305.jpg", + "sha256": "3845c504258c0a016e05562402aa5d60437266334ccd27cb1d5645e0fc28823b" + }, + { + "kind": "file", + "path": "img_281.jpg", + "sha256": "33250274cc31ceec47518b2a52cda5679f71997e96764e05bbe5c2e185f2ba8c" + }, + { + "kind": "file", + "path": "img_1261.jpg", + "sha256": "94507bbf421704156b41910a68322e07346730f7ed4fd2b1f28e5f9b86eaea12" + }, + { + "kind": "file", + "path": "img_242.jpg", + "sha256": "3e921c41915591f29b7a6665a1d77939182413b30489449e40bac41c0cd3a9e0" + }, + { + "kind": "file", + "path": "img_524.jpg", + "sha256": "0d8baeb547548b4de3bbcf79cb3cb091fc2322455f00ec780a8ff415a1c7c3bb" + }, + { + "kind": "file", + "path": "img_530.jpg", + "sha256": "e135c59b146bba0e64118c9a549063915f035ee19266483fc628504cc88dca81" + }, + { + "kind": "file", + "path": "img_4480.jpg", + "sha256": "88fa02ed163a07030400a29eddbb5d64df2281f918d746619e47863589afbc12" + }, + { + "kind": "file", + "path": "img_3112.jpg", + "sha256": "cb4f65044a1416f6879d1e3ef80d3c9564d77ef1b697d7b29f44db1335ec1058" + }, + { + "kind": "file", + "path": "img_4899.jpg", + "sha256": "41bcf42faf5dceac225a2bb00f14aca940adb3b922b1d488119e91cddbe24639" + }, + { + "kind": "file", + "path": "img_4133.jpg", + "sha256": "8742ccfe0f7a799138cd9f97d808b5833da1fb198afb563cd955b40113845ab7" + }, + { + "kind": "file", + "path": "img_4655.jpg", + "sha256": "ef9a73191aca7ee2a58b6dd488f92ff3abefa8bfd7aba95b92b195b37401d025" + }, + { + "kind": "file", + "path": "img_4872.jpg", + "sha256": "ef060f47f7fea5d6ab86039ac6778e167740e34a7e6183c8d6e88e65536f51cf" + }, + { + "kind": "file", + "path": "img_1117.jpg", + "sha256": "b5b00fd0437d41cc188f7b94dca7c509b3d6c5bdf89cb1d51ff0d44ea9b4abca" + }, + { + "kind": "file", + "path": "img_875.jpg", + "sha256": "156f709b229fa1fe3c1c087160f202359388cb59b2dcca4fcf2523277614acec" + }, + { + "kind": "file", + "path": "img_3099.jpg", + "sha256": "e446ffdf05e60c12269543e776db0d9bdc32b7ca2ce8635cb63176b42d5617eb" + }, + { + "kind": "file", + "path": "img_4084.jpg", + "sha256": "40620bfaa01510f2273ca5f18d63d3eefa1f9b24aa6d848a7afb1d17aefed43d" + }, + { + "kind": "file", + "path": "img_487.jpg", + "sha256": "82a650c0096b2b7d2d624f0febba3892c7adef6a236f1b4a4bfda1e085d05d7b" + }, + { + "kind": "file", + "path": "img_1301.jpg", + "sha256": "c4da95b8a88368700e8cacc5c4a888cc1ec2c1059663bf3dfa1087a80a12f7fe" + }, + { + "kind": "file", + "path": "img_4523.jpg", + "sha256": "2120b956f609984bc26a91c205a120115a0de33ba5b1f5d38d4f9bfb28e302b8" + }, + { + "kind": "file", + "path": "img_336.jpg", + "sha256": "e49aa28d1b9403f53213102839cf9744db174d7a0e714bd1b93980fa4e772173" + }, + { + "kind": "file", + "path": "img_1498.jpg", + "sha256": "12df76a0dc9a4020aae2a349956ad136a2a011e535e6a4a538b19f2119ef4991" + }, + { + "kind": "file", + "path": "img_4286.jpg", + "sha256": "5bcc4937cb61955ad8e62ffd81c90c34ca49458f48207e5273e9ca654877b0fe" + }, + { + "kind": "file", + "path": "img_440.jpg", + "sha256": "4248a144533b3bba54c9491517e447eb7c074c9808adafff65ce3c1936ac1f81" + }, + { + "kind": "file", + "path": "img_2803.jpg", + "sha256": "e0dd65e55ddc2f4f78ef6b7c097098dcb3f2da1fef7d8db7b194950196f2fb58" + }, + { + "kind": "file", + "path": "img_2195.jpg", + "sha256": "facfb69a47396639cd8e29cf79e4c9ec8b389921c616ff724e4b5ce9a79eddb8" + }, + { + "kind": "file", + "path": "img_468.jpg", + "sha256": "b1dae6c24aa6f711684ce1d5cdda572b47155707d9803c31eb91cb67522589d9" + }, + { + "kind": "file", + "path": "img_1311.jpg", + "sha256": "3c3b8c1d3313f4a913749d9e044fa5b97fc6c689ee0cef1ba3c0e1b5bf3189bf" + }, + { + "kind": "file", + "path": "img_23.jpg", + "sha256": "84a4c20f5e7a27bceaeaafcb49666f32d7a113a94c9fd8066d7f6aef24aa0dcd" + }, + { + "kind": "file", + "path": "img_4533.jpg", + "sha256": "08fad876427b0a7d88ee6f74d7a27b025a80cf6c269261d8f94e9f86ebbe175f" + }, + { + "kind": "file", + "path": "img_3937.jpg", + "sha256": "351d4ea26546cf9a28c72592b6176f2d3752a7cd73892a235d68ee0f3895e9a8" + }, + { + "kind": "file", + "path": "img_1661.jpg", + "sha256": "6eaff44f528e45a0dbb967ba23595d986c1715b643b9cbf425584b13b54292c2" + }, + { + "kind": "file", + "path": "img_3062.jpg", + "sha256": "affabe5501f9d6b30f388c9619c729bf9a8d72e9615e6eabaff1187e24da5780" + }, + { + "kind": "file", + "path": "img_1885.jpg", + "sha256": "dce1a90707fc3399c25e97160bc473625d268c9acdf5157af1f5ada2560dd1b1" + }, + { + "kind": "file", + "path": "img_4725.jpg", + "sha256": "e96f67b907bf2bfd078735712056dcca2a1204e4cebc6c6f70ecff13037ab03d" + }, + { + "kind": "file", + "path": "img_2340.jpg", + "sha256": "becb66506bb901475e4ec0848622a7e90c76bda94c7ca94cfd7b2141aa3b6972" + }, + { + "kind": "file", + "path": "img_1891.jpg", + "sha256": "d6dcaaaf7cbfc0b15eae621612437cdeefd45ed071b9c2a5e4f6e56ce752dff9" + }, + { + "kind": "file", + "path": "img_1649.jpg", + "sha256": "a24ca42be85e4e6307c5c737f2979390306e16a8ac13ea891ee785089dab2990" + }, + { + "kind": "file", + "path": "img_4876.jpg", + "sha256": "08d40056e155adaa22d0e7e843b3d67ef305d531af6147c53b0fdfd2618387ae" + }, + { + "kind": "file", + "path": "img_4692.jpg", + "sha256": "44f250c8311ef409cf5ae916cac61aaf36dd625131e3ee2d0a09ff060d3f1469" + }, + { + "kind": "file", + "path": "img_2591.jpg", + "sha256": "6eb67488c8c0d532e4a3be5662db8dabc5303a060f1f2595f32efc529a42cc5b" + }, + { + "kind": "file", + "path": "img_1926.jpg", + "sha256": "704bba139316c19153aa8ee4e6707631afac901b0b8777f600d64997b6e47a49" + }, + { + "kind": "file", + "path": "img_1073.jpg", + "sha256": "990e9c0620b0f9124393ff73aa946ea4cc253fab859f5bf5f477194392aa2156" + }, + { + "kind": "file", + "path": "img_3670.jpg", + "sha256": "9d141cfa2a9e2be3c0eb3be604d9a9faef4ffcaa22c1268d0386b223f27d108e" + }, + { + "kind": "file", + "path": "img_1067.jpg", + "sha256": "0109ac6ab549c67a3123f74262739329109b430cd6d0d2b19cae8833d8cd19eb" + }, + { + "kind": "file", + "path": "img_2208.jpg", + "sha256": "cc27a57eeac0e7234dc2f9bd67eaffe4835fee0201f34143e7892bc71aaf999b" + }, + { + "kind": "file", + "path": "img_911.jpg", + "sha256": "dac38d3ad149b88a3cd092bd777cdb5b011bf6b04c91e51a35894031cc639c3f" + }, + { + "kind": "file", + "path": "img_2546.jpg", + "sha256": "8c61ea01a8908e09e1f8e408b6d814d5423a1f0397558b4409568a26e735b71f" + }, + { + "kind": "file", + "path": "img_534.jpg", + "sha256": "1d0126467ff2ac00026336682ffa32e72ac07c7319c96bafd65dfe3c71c1b365" + }, + { + "kind": "file", + "path": "img_246.jpg", + "sha256": "69159b00a0fa172b0022543f6499105ee177d896572fa7ebbb4365c1ab60d0e6" + }, + { + "kind": "file", + "path": "img_2787.jpg", + "sha256": "d4e58f1236c91f064e84922951e44181991e54da36ab9e179c1396fb7fcc5e37" + }, + { + "kind": "file", + "path": "img_3499.jpg", + "sha256": "a39d549e1ba90edad1a1300c0c541b4ae8030cb798d70bd9cacd334918a64daa" + }, + { + "kind": "file", + "path": "img_3300.jpg", + "sha256": "7b064fa8ee1f350e138e83a328b111a2d9f7d95e91edb9d350cf86d54c7ae3b4" + }, + { + "kind": "file", + "path": "img_2037.jpg", + "sha256": "5053867ffd2ddfd2baa6e8bdfea023cea1724ee5a36cf230971ff96bb5c9838b" + }, + { + "kind": "file", + "path": "img_3473.jpg", + "sha256": "b7f0d130d69cf455ae249eb1852ccee1cb7bc05c0f6fe0dd58b23c72f92740d0" + }, + { + "kind": "file", + "path": "img_1516.jpg", + "sha256": "742917778ee276bbb16e1c7ad9984a7e50afa41c1eec1bc0a583af3a69d11785" + }, + { + "kind": "file", + "path": "img_3498.jpg", + "sha256": "e1096e5447ba67d21720c16c9eba7a6b84d64f129878432b95acbbd1e0958414" + }, + { + "kind": "file", + "path": "img_4491.jpg", + "sha256": "b0a43d41aadaa5c917c53f12a330d9bad03b088e7dcfc3a9519f36951f1332fb" + }, + { + "kind": "file", + "path": "img_521.jpg", + "sha256": "cded6b0a84fd083ca3892d36be2de4da594dc3bcf29064adda5f85b1ec8b80ff" + }, + { + "kind": "file", + "path": "img_2976.jpg", + "sha256": "1320f818caadf3077db657b5fff69dd9e039f6cfdae6d85b151ea256a52e22eb" + }, + { + "kind": "file", + "path": "img_247.jpg", + "sha256": "467e909fa5ffd113a296392f7efd6df40a789143acc954ac18c848bf6a38a3b8" + }, + { + "kind": "file", + "path": "img_2962.jpg", + "sha256": "76fa769dd1221f76ef130ef830090824d6af6fd8af81e4f89661fa547f2df312" + }, + { + "kind": "file", + "path": "img_904.jpg", + "sha256": "290b34b8635d96b0e853aa0a86a773333b5270b3d8e629bab81676e844bf395b" + }, + { + "kind": "file", + "path": "img_3881.jpg", + "sha256": "bd02a1efd3ddcf7bf03c0292d1c5227c03bf9a8b4ec63009ad4c15fa7c294f31" + }, + { + "kind": "file", + "path": "img_4678.jpg", + "sha256": "6e9b5f0e5cac8b7ccc2c3f3b59152fd51ff04fa99316d8a15e3ca9557d09e4f8" + }, + { + "kind": "file", + "path": "img_1700.jpg", + "sha256": "6fcc03f54b2a20b1ef2971d76aeca6264041ad0d6b06da721d49bef9a94a46de" + }, + { + "kind": "file", + "path": "img_3103.jpg", + "sha256": "25d1dddd2ea55fb48743671f485dca1928bb76dead2e91e27de5dad535cde7a9" + }, + { + "kind": "file", + "path": "img_3665.jpg", + "sha256": "a067553a5b0c5b6086f7f86db407c9e56941aee85c8a346db02dba28c9bdf05e" + }, + { + "kind": "file", + "path": "img_2590.jpg", + "sha256": "c5e643b11372522f461b46f7ab81c5c2f75a0a611d347f60fb7c4f3963a29266" + }, + { + "kind": "file", + "path": "img_4056.jpg", + "sha256": "11e8e8176aacc973f680f3d73ff7b0d3bafaae0d7320e9675ad028bc9c4d6430" + }, + { + "kind": "file", + "path": "img_3739.jpg", + "sha256": "5e916f5a5c2e6c0a1494276536bb1ea3f7b98574d771f2c94a9f3f9f97f5547d" + }, + { + "kind": "file", + "path": "img_1648.jpg", + "sha256": "54407b3bbfa1ed328fd5d081acd56647ba157fc94ee144a841478e4778ec94d3" + }, + { + "kind": "file", + "path": "img_694.jpg", + "sha256": "9a11a4c0dcea276dcfef923a7dd2e61c4216292b0a68d63a4e9452a9e6c9adb4" + }, + { + "kind": "file", + "path": "img_3063.jpg", + "sha256": "15d7cca994d6815863c984bf778e68e416a23a12c04372e725a4cc3574b0badd" + }, + { + "kind": "file", + "path": "img_2369.jpg", + "sha256": "9e0ad15e0d61093d58e57abf4f1b468e7d01676f067d9621a97e3dcc14752f44" + }, + { + "kind": "file", + "path": "img_1106.jpg", + "sha256": "945745d5b31fa901ca1e8f32ddb0f8e4c46b8663d0e655066f3a0e388b9dd9b1" + }, + { + "kind": "file", + "path": "img_1853.jpg", + "sha256": "a2f4ecc6e7566471736928ee8dc471c75031f75667fdc53334031b1e7fc2b0ed" + }, + { + "kind": "file", + "path": "img_2396.jpg", + "sha256": "5bd5cffb2bb0d89bdcba4ff98e362f2981a821b2c8cf551cf4d6ca5fb3abcc5c" + }, + { + "kind": "file", + "path": "img_4081.jpg", + "sha256": "9dfba2925573e7e2af20032a7e4feba0a086f4b54a9c63a869bd5a00edac7cef" + }, + { + "kind": "file", + "path": "img_4917.jpg", + "sha256": "cb4e467286e24acba7a844ed5bef030dc763749ab08834efeadf024574df8251" + }, + { + "kind": "file", + "path": "img_4903.jpg", + "sha256": "dd3078d378ac1cca40a5e4f7dece71bf41f4053f1b6645fa184a6c003c13823a" + }, + { + "kind": "file", + "path": "img_3507.jpg", + "sha256": "a38ba7e7d4c9a838d2cae68ddaa5fdf5b30e0d7bef6ecc2cfb7393678c84d13e" + }, + { + "kind": "file", + "path": "img_1304.jpg", + "sha256": "c559a2dab2c0c84c3616637868ed0f0ea538d745365cbaccb0260e1769be9139" + }, + { + "kind": "file", + "path": "img_469.jpg", + "sha256": "1aaa1a062f145f00c105ff680fbc423546092eca2794a9f701045a7c19b38290" + }, + { + "kind": "file", + "path": "img_2180.jpg", + "sha256": "b8650c6f403e0f4d05524fab425defc20dc96ef33a8b1f05efc7b61230b985f5" + }, + { + "kind": "file", + "path": "img_4283.jpg", + "sha256": "0ee74a4ca9e3afc1b46e0af6e4ffbf2a64542469830c0925f45123f85347e5ee" + }, + { + "kind": "file", + "path": "img_2194.jpg", + "sha256": "1edcf7438f828024af551e2690c4760ba341de70cfb60d5a48615ea585622b9a" + }, + { + "kind": "file", + "path": "img_443.jpg", + "sha256": "27aa13cbe6b948b61acd0c7fb639ee52a12706d3c9a426911795751da6b37597" + }, + { + "kind": "file", + "path": "img_325.jpg", + "sha256": "0c084ace7d462e9aee84ba72e291b034d21bd69865b36d225c0267bc16abbf26" + }, + { + "kind": "file", + "path": "img_2196.jpg", + "sha256": "d798222a7c00e41a84b4f41dcc01f5e4d7ad8bdc38cd2c3a57600a4d5d9e8284" + }, + { + "kind": "file", + "path": "img_4281.jpg", + "sha256": "60ff33db5e12aa79afdc5f86c48b38aad83ab3701e5d452399d5d09a3c5ba81d" + }, + { + "kind": "file", + "path": "img_480.jpg", + "sha256": "e86c675e1dc091d034402349cbf7ec0e2e6b222cd82dc16007fe5062eb51191c" + }, + { + "kind": "file", + "path": "img_20.jpg", + "sha256": "ee7492feccfd842f310105abf08d72616505d7195a3aad506ef3affa61988fb5" + }, + { + "kind": "file", + "path": "img_899.jpg", + "sha256": "23133bc88a6238af3412062c4ab3a51fc92762205d0a384dff4f5b63ccb041d1" + }, + { + "kind": "file", + "path": "img_1851.jpg", + "sha256": "1d77c406de4c6c50fd19df8c1a51bc9d7ac91a00aee6727b7ec56eabb4a48bb9" + }, + { + "kind": "file", + "path": "img_3934.jpg", + "sha256": "7d97ef3092c177d6f48782fa0087b391c354a656ee6c476ba87b028ac2a26675" + }, + { + "kind": "file", + "path": "img_1845.jpg", + "sha256": "b7f02efe2c56589e348c3a894397286cc9b23753401e2719c24d4dede4c72c49" + }, + { + "kind": "file", + "path": "img_2425.jpg", + "sha256": "36507550574f37181c4579bdaea8b94d06519a9c2983331569329849bd5898b9" + }, + { + "kind": "file", + "path": "img_866.jpg", + "sha256": "7a6759f9b06bf9a04b4042e1fc4b658775dd7de38f10154fd19016f26caf54d3" + }, + { + "kind": "file", + "path": "img_4861.jpg", + "sha256": "cc6e0fc01afa9cd13be92a6d05e2dbf65f3fd8ee065dffc2fd9cbdab7ed1e014" + }, + { + "kind": "file", + "path": "img_3868.jpg", + "sha256": "fd544bfdafeb41de8d78c08919c4dde8776bf8060162aaf249d1bc86dc057b1c" + }, + { + "kind": "file", + "path": "img_1925.jpg", + "sha256": "62a68a7b2db478bd300dc7da7ce1636c87f07b841627025fad3d8d3492dc8132" + }, + { + "kind": "file", + "path": "img_3854.jpg", + "sha256": "c8a4eb7eeb0200be0651265a6495046c1def858be7d856dd2d6e99575c627e93" + }, + { + "kind": "file", + "path": "img_4691.jpg", + "sha256": "0b7c449d0b4d54c19d70f769264ec63a65a45efd8057f519b09101e516227c18" + }, + { + "kind": "file", + "path": "img_1702.jpg", + "sha256": "07d995b94bb10898b644f13c7ce2b3ed21f70e800c2009bf01bf4391ec4138c2" + }, + { + "kind": "file", + "path": "img_3673.jpg", + "sha256": "625ac2df8553c7c3b1bec9c5e62d47e474c0381c5f2c5b9b19b7156d28560755" + }, + { + "kind": "file", + "path": "img_1064.jpg", + "sha256": "7e08867f9a90d3494158db876deb9f72604ea42c7f1819f602948a82cbd361b3" + }, + { + "kind": "file", + "path": "img_3667.jpg", + "sha256": "9eac3068be721556f0436a9f6cd2e28a344e4f7bd0fa0bed4c9ebc48bb8481bd" + }, + { + "kind": "file", + "path": "img_3101.jpg", + "sha256": "f398c80065ebfef7c899270017988755e6f37a3252d984df02dd3bff77b097c7" + }, + { + "kind": "file", + "path": "img_4646.jpg", + "sha256": "32f14358fd93f9ebcdd82790f02a68615e5a6eaa3b0cec1b3ec2ba93d3a1311a" + }, + { + "kind": "file", + "path": "img_2551.jpg", + "sha256": "870ac7231b8a7680c61721b6d288fe209bf2a891a4f75bfef3f6e3c6a602eab1" + }, + { + "kind": "file", + "path": "img_3883.jpg", + "sha256": "daf9d1093d76229421b6f240f6c0e43cf3ba61520b04fd9c0d461280a96ede9b" + }, + { + "kind": "file", + "path": "img_4487.jpg", + "sha256": "877d6fc2d2958cdc30df8a885ac424494d3520e8bf10ff073e8e707c916579f5" + }, + { + "kind": "file", + "path": "img_1500.jpg", + "sha256": "d2d1563213615f8bbb851cddc32d35ac42c8a95acb51bc7cc07918954dc5ca9c" + }, + { + "kind": "file", + "path": "img_1272.jpg", + "sha256": "8c32c35e9db3211ea48f9f20cabc27372e0d05b4cd2da54dc03840dfd1b076c5" + }, + { + "kind": "file", + "path": "img_4322.jpg", + "sha256": "8a243a65a97f1af1ff9d318cc93226ab98bbfb8ed5328690cdf6f569fec9094a" + }, + { + "kind": "file", + "path": "img_1529.jpg", + "sha256": "9740fc3865030b8043d88c871b8b438cf75d94ff6bc669b5b70ce089011e75ff" + }, + { + "kind": "file", + "path": "img_2020.jpg", + "sha256": "6e4b49f89a7ea226ebf73694249bc93d24f97464bf3932fbc44d27509dd004c6" + }, + { + "kind": "file", + "path": "img_4337.jpg", + "sha256": "dd0c9047a5e441b552a5a8e12ef760c188ba30a3ecb38ab6c9d9320233fec4e9" + }, + { + "kind": "file", + "path": "img_2008.jpg", + "sha256": "86a38f7ba54ef20e2fe639fdcb974363d55733cba088173f9c231d177bfaaab8" + }, + { + "kind": "file", + "path": "img_250.jpg", + "sha256": "68ddc94c26c9bc4d9d73322ee8ab7d4167147e5085dd67be130ea2adf33ed1bf" + }, + { + "kind": "file", + "path": "img_244.jpg", + "sha256": "482c8f1afbbad0199ef84cdbb540a83c135f95b36a094be12f81e232359e1c20" + }, + { + "kind": "file", + "path": "img_522.jpg", + "sha256": "30c5c0a8a967e764d827c898663e6273ef58f25756f62ba8962c0da38342c636" + }, + { + "kind": "file", + "path": "img_4135.jpg", + "sha256": "aa8d0ae3093b59b5685e571b1037334875c56363d455e60c61e6c2b5dfbae6a7" + }, + { + "kind": "file", + "path": "img_913.jpg", + "sha256": "7df2867b547feca015137bd2ddddfeedc58669ab1af5eee176f8db5f4b3290dc" + }, + { + "kind": "file", + "path": "img_4653.jpg", + "sha256": "d21b571003d7d4d4264e8044da1a95d44f00ba047b4c4d11eb9d599e8696ac1b" + }, + { + "kind": "file", + "path": "img_907.jpg", + "sha256": "f8f21f103de3b9b8c7808dd6cb430e27b5d158b0525824482fe1d8cff4985931" + }, + { + "kind": "file", + "path": "img_3100.jpg", + "sha256": "06b8f6380c492e56d48a46f066e64b85c21692d3344614073d269de1c79b2eb7" + }, + { + "kind": "file", + "path": "img_4874.jpg", + "sha256": "babbb05578086b8fb23c05cd08ee6c8d44e01d05519497f869604f46badd6bbb" + }, + { + "kind": "file", + "path": "img_4733.jpg", + "sha256": "ceea55de182fa34515b8f615bdf9dcb54b264097062b0d7d5ce8b5918e28f484" + }, + { + "kind": "file", + "path": "img_2342.jpg", + "sha256": "c2004fa99aecb2d9798a7ed6c7ef3c6ea9e258ce2dc9291abe789713c024fa75" + }, + { + "kind": "file", + "path": "img_4055.jpg", + "sha256": "62beacea482b33062389cedce2bb0fa1d194f87a05890c24457aef93a2e5c852" + }, + { + "kind": "file", + "path": "img_1663.jpg", + "sha256": "9d1258a9c6699f35094c4fefdb5f984bde5b69f7302e8eaaa67e9f0ba25005c8" + }, + { + "kind": "file", + "path": "img_3074.jpg", + "sha256": "bdb02298099231ab4c36aeee3c4f5740e93660e028bfd0c38cf2298f793a22f4" + }, + { + "kind": "file", + "path": "img_3706.jpg", + "sha256": "91c3e92c41d0d6be7241a836e34b0f6d387bbb60f747a1e67e3f068a4d1a0081" + }, + { + "kind": "file", + "path": "img_3935.jpg", + "sha256": "7803a774cfdc36a50a26ed234bbc52f27d7efe4c5930756d2454691e62395408" + }, + { + "kind": "file", + "path": "img_2395.jpg", + "sha256": "1e0c5c5825272f356d58158600e6bd54727b522add1022fbe22c2741f810754c" + }, + { + "kind": "file", + "path": "img_3909.jpg", + "sha256": "838cfd52997a75940c90ebb61befec6c8f1e91ead9dba34b4f883d17bb1388b4" + }, + { + "kind": "file", + "path": "img_898.jpg", + "sha256": "a46722bceccb8561eca47f3057892ba4e7c09255447f0cad40249eea3b75819f" + }, + { + "kind": "file", + "path": "img_2632.jpg", + "sha256": "f1a799773fcb0d317fa98c9b5e98d6a689c515cd72593f427567bfa42963ae31" + }, + { + "kind": "file", + "path": "img_2626.jpg", + "sha256": "c9953157887a8a8df57a31fe6a91ecb8581b0f775cf7e335bd6dfb56a4a40f10" + }, + { + "kind": "file", + "path": "img_1449.jpg", + "sha256": "032f408c985c0490757f51c113237f2c54b0a3f8c7e33275494abdf5a6d0f97f" + }, + { + "kind": "file", + "path": "img_4519.jpg", + "sha256": "ab309b06f5849b636aafffde9c42a50d16db82cd07f2d577b57dc99af94abeda" + }, + { + "kind": "file", + "path": "img_456.jpg", + "sha256": "aadb30a739ccfffba49b99c5027da441ad135d3de938f5b0937c44a6c061220d" + } + ] + }, + { + "kind": "file", + "path": "test.json", + "sha256": "7c16a2f3051c43e7a447b35610dc74468110954cf8b9b9539b08d281f437dc79" + }, + { + "kind": "file", + "path": "train.json", + "sha256": "a7a0d8d88001918774412fbc71f35e57bc86de99754486730a6eac407ac2dfff" + }, + { + "kind": "directory", + "path": "train", + "files": [ + { + "kind": "file", + "path": "img_329.jpg", + "sha256": "faf2677f3ca705e774e8be35fad06c715c748f9b6c0ecc2ab1d008a2be27f6ea" + }, + { + "kind": "file", + "path": "img_2818.jpg", + "sha256": "147de0cc73bda02652f384120dd7b03fffba53c5bdf8c2eb453fa373ba45abd4" + }, + { + "kind": "file", + "path": "img_473.jpg", + "sha256": "8f5d790ddfc77724119ce7deebcf2fbe0234ac677fca5bd0876ee3cd3e67a8f3" + }, + { + "kind": "file", + "path": "img_315.jpg", + "sha256": "833a5b99daa3783af4e22f934be65476621069129a685a28a727360f2bdccf26" + }, + { + "kind": "file", + "path": "img_2830.jpg", + "sha256": "c43dd9ffc2ec3d929923590884eac2670c6261468402fd43134b4c9b9966418c" + }, + { + "kind": "file", + "path": "img_4299.jpg", + "sha256": "8235f77d8ad5957c1d4e281441c6dc51152c07e66f6cd6ca292f28d0c97322b1" + }, + { + "kind": "file", + "path": "img_3290.jpg", + "sha256": "5183f3cf8f79f497d8034b54bd06377cd22e1fb99666ffaa2df0ef7903386b5a" + }, + { + "kind": "file", + "path": "img_467.jpg", + "sha256": "648db9e75c5b66561a4d3a0a381a3bfcc514bdeb7c31ec14bb10ee4971141630" + }, + { + "kind": "file", + "path": "img_4514.jpg", + "sha256": "5fdd25c2134efcc725276b4cf3a2253762c76b8960499bed63ae5c2392de835e" + }, + { + "kind": "file", + "path": "img_2165.jpg", + "sha256": "7fd1aa10326bbacf85b4f7944ec00a5357753906d4689489ca3211dd5f2f6462" + }, + { + "kind": "file", + "path": "img_10.jpg", + "sha256": "37753610e7de2b2f94804d2d7c3bdf9857b5d27808b1115d03c6cf2bbb12ec76" + }, + { + "kind": "file", + "path": "img_2603.jpg", + "sha256": "ae576a2e5783ac5b30aabd54c83fe39322ac6dba1487a86f174337ad73f53e86" + }, + { + "kind": "file", + "path": "img_4272.jpg", + "sha256": "3662d5e3ccce138585b18daef2c465026aeaf3304c95ba5d1971b047cdb0bbe9" + }, + { + "kind": "file", + "path": "img_2617.jpg", + "sha256": "ff4023348d1d786678d27e4a346cf08649be6f02cde92d811d61de05de33589f" + }, + { + "kind": "file", + "path": "img_3509.jpg", + "sha256": "dda7f0c92e80a8cacb494c82c74b5571b9b8f70228d378b3f6660ed7f69c9a0d" + }, + { + "kind": "file", + "path": "img_4266.jpg", + "sha256": "b6a3ad708c16aca606c62aeb1fa516e4e52eb927dce487ca8a9e0f8eeb4398df" + }, + { + "kind": "file", + "path": "img_4500.jpg", + "sha256": "fa88a93e77a75a2d48fe5bdcdcae774353a2b49f5a6644847b54b1a5d1fb2add" + }, + { + "kind": "file", + "path": "img_498.jpg", + "sha256": "31865cf24d1364700e04d691b6f0e7eb6f89f97525a4c73fcb2f2a810f48928f" + }, + { + "kind": "file", + "path": "img_2171.jpg", + "sha256": "38df83d28e64d4cedf6fed01287cc96da36987b7c5d6d52439b707bb0fe41466" + }, + { + "kind": "file", + "path": "img_1450.jpg", + "sha256": "0cf6efe3bc573728432e75df9dc112aa8fd4b360edfeb7eb17d8ae9da5e39102" + }, + { + "kind": "file", + "path": "img_3247.jpg", + "sha256": "58aefc984bdc53118b4964525a94383a9451f9096e173d0dcfe4b08cfccbc45c" + }, + { + "kind": "file", + "path": "img_2159.jpg", + "sha256": "5866768337aaf0710cee68af0e7be0595fb4b03e63d24de12ba51dcda6867abb" + }, + { + "kind": "file", + "path": "img_3521.jpg", + "sha256": "799b8065e022f598b23bd109bf1d527075dae2701c65c058745bae934fc7477f" + }, + { + "kind": "file", + "path": "img_1336.jpg", + "sha256": "fdbd397abb325d488b51ffda974441d4077d6012a0859cd9b9cd3f4ff86625c9" + }, + { + "kind": "file", + "path": "img_1322.jpg", + "sha256": "1c20a5183dac804f115bd6b9bcf1d2e912520c8de6d53b572fc83a35b2e00c64" + }, + { + "kind": "file", + "path": "img_3535.jpg", + "sha256": "60d02cba1bbf39082db1df86afb2177c912337b59f18d804b85ead182345834e" + }, + { + "kind": "file", + "path": "img_38.jpg", + "sha256": "94c2caef6eccc76bacf9482ea4419b2be8e5d6fdcbaafe5fdab72bdae17253f5" + }, + { + "kind": "file", + "path": "img_1444.jpg", + "sha256": "06b7fb209a45d05e2fd1c8787ca852e69291db31a1be7f0d3d307acc99d03999" + }, + { + "kind": "file", + "path": "img_895.jpg", + "sha256": "502b5c7d9487a07085e42f26e633ec6c27703c8e37f49a2b25ef00be250880bb" + }, + { + "kind": "file", + "path": "img_1875.jpg", + "sha256": "f0f365475e28d9b40049384afe9cc70943e267d4310932b12bd3ad97ea9d64c0" + }, + { + "kind": "file", + "path": "img_1861.jpg", + "sha256": "031aef53dc87411225157370ce5cc56439513fa5a267eb50340a47aa798fc8a2" + }, + { + "kind": "file", + "path": "img_659.jpg", + "sha256": "bcec276b5dbe336659ec5153fc6fce47823ff02ba29a7e6a81b1f67a286224b8" + }, + { + "kind": "file", + "path": "img_881.jpg", + "sha256": "e2118cd781a5e5f1bccad7274a82d551178fa2bdc26c4c1c3ffec2f56289ecad" + }, + { + "kind": "file", + "path": "img_4919.jpg", + "sha256": "61d931a4f6f62f28564a901e23443cd71f0e73c8ce92f3df33623c8051fc28a7" + }, + { + "kind": "file", + "path": "img_3938.jpg", + "sha256": "215244ec3edea11447df2e60768b0639e210ef985bea119424318f6da26d739f" + }, + { + "kind": "file", + "path": "img_117.jpg", + "sha256": "e6a8da41fd6d052c7088dbfc2f2e449930c6ec9bfb76459e0e38ed67602c22a4" + }, + { + "kind": "file", + "path": "img_1849.jpg", + "sha256": "3833f2cef2cf004282a268219fd45681783ab79d106c26a010badae23bf84c82" + }, + { + "kind": "file", + "path": "img_671.jpg", + "sha256": "b9bb2882c696fd055808c627cf487562e4fb389224f76ecd38a799761f898489" + }, + { + "kind": "file", + "path": "img_4931.jpg", + "sha256": "6b42880a7ae0e2d572feed1391031552c26553e85c2a696faf0f38c8820dab8c" + }, + { + "kind": "file", + "path": "img_2398.jpg", + "sha256": "b37bb30ce50350b5e3b0367b764440787ed0e2c6ee54c3dfdc847d2ae17bf611" + }, + { + "kind": "file", + "path": "img_665.jpg", + "sha256": "3cef877bbfae0b3bc48f9a7a5f71964e358855b1133c5f7ef7ff74aae738d2f4" + }, + { + "kind": "file", + "path": "img_3092.jpg", + "sha256": "fc9a13e1f7acc2ecc8d8c1f29b2fb45adedb77246b4a29cae68d9b13185b065d" + }, + { + "kind": "file", + "path": "img_4925.jpg", + "sha256": "f05095c5a3db98c9eacbde006c41766f315978b9df4f85bf494747e22ac02142" + }, + { + "kind": "file", + "path": "img_2401.jpg", + "sha256": "9f5bfd1078e4e562f8d96591d3b113dc5de90aeddbecb009f0b1dd7b9e52305b" + }, + { + "kind": "file", + "path": "img_1108.jpg", + "sha256": "54e8b4bc45b93cce37ced8af5054af1db9299300e3f7ff88071101d91d525efb" + }, + { + "kind": "file", + "path": "img_2367.jpg", + "sha256": "efe025c8929e5159feb0ac348346d8cb3261fd588c5450536bba5cfd4eec8aa6" + }, + { + "kind": "file", + "path": "img_4716.jpg", + "sha256": "e38d69a41f25f01591d49f766bf3cd3693fcc567539af226655716bd8b8dadc7" + }, + { + "kind": "file", + "path": "img_842.jpg", + "sha256": "6f81be0b8b63dc529e732f24e082f63004f3d57690778311ac15921a0d579235" + }, + { + "kind": "file", + "path": "img_2373.jpg", + "sha256": "5ebfcb354b6cdbf0b1995d556e3e9c022cea2d456db37df39b55df575deb030b" + }, + { + "kind": "file", + "path": "img_4702.jpg", + "sha256": "ca83d63a40c710603abe20065c187f9d1c500e185b10039358c8875326f4784c" + }, + { + "kind": "file", + "path": "img_4064.jpg", + "sha256": "b69b6579f8996b8eb037dd9f061c421ccaac2f5fcc2196fb0732271a5b22ba79" + }, + { + "kind": "file", + "path": "img_2415.jpg", + "sha256": "99c2537df205455a64c5ac97c680127f269f746c7b91b080062dbdb7c0626b17" + }, + { + "kind": "file", + "path": "img_1134.jpg", + "sha256": "7cae3a375e63d400a0432deb19e8d3321f7185b9bb53764ffdf14f8e88e82554" + }, + { + "kind": "file", + "path": "img_3723.jpg", + "sha256": "ed263943cb07cfdf73a60253c6445229de7c2d3e1bc004321b2e0a5f5307ebcf" + }, + { + "kind": "file", + "path": "img_3045.jpg", + "sha256": "717884dd471f52e0bef5daef2af3c454939863250e317018b2e96dbc82ac0986" + }, + { + "kind": "file", + "path": "img_1646.jpg", + "sha256": "b34f3184b761aec50448606a4deb32100de0844e0489a3c43f379ccccd4f54c2" + }, + { + "kind": "file", + "path": "img_3051.jpg", + "sha256": "0dae6d3b35bfecc5b06c970ba7a0dffde1850e9a29f30a3cfe2a74b8de141db1" + }, + { + "kind": "file", + "path": "img_2429.jpg", + "sha256": "48cf8d0e941dca31e71445b6728f6f43500a6305b1b7254bf0f060d3354c072d" + }, + { + "kind": "file", + "path": "img_1120.jpg", + "sha256": "e9628f076c05916077148c6b3fc117cc664d139bde92b329251ba45e892ea485" + }, + { + "kind": "file", + "path": "img_3870.jpg", + "sha256": "0101c3ceb83afbc614e871a9450e8e53db31ac65a01c55a1335e1ca300315e35" + }, + { + "kind": "file", + "path": "img_4879.jpg", + "sha256": "0ff38a10e89118c52704ed0bedb6ac485381af3e6db9ee68e260b5f0e3e9d347" + }, + { + "kind": "file", + "path": "img_739.jpg", + "sha256": "cb5211aeeba8a0facb8d7f6b3169c0bc8dec0ac1c095c07bf1654e4686d26bbb" + }, + { + "kind": "file", + "path": "img_1901.jpg", + "sha256": "fe57bba6d9b6481bae473163cb6e0c70dc34f104b3d2233770ab140de474478d" + }, + { + "kind": "file", + "path": "img_1915.jpg", + "sha256": "c36d7d84aa724698ba30c3aaccce6e33ee547ca323131fbf2c983949ac1462a5" + }, + { + "kind": "file", + "path": "img_3864.jpg", + "sha256": "289264fd7dc4665a59eb6f0cde7f3219e5a19db709f1bb67ecd525c64d701763" + }, + { + "kind": "file", + "path": "img_3694.jpg", + "sha256": "f9f66ae698c45c5459bb55d81e2d186cdc024b4eb1151d723ec4c12bbd4508e1" + }, + { + "kind": "file", + "path": "img_1083.jpg", + "sha256": "42cc563056a06033649caa65f96cdb6a5f5cdd2e67de13e42412e3de026f2d43" + }, + { + "kind": "file", + "path": "img_4845.jpg", + "sha256": "d7322d83f5296908284e3a76886962d301a2ab02d0789c31a766d2602c657d6e" + }, + { + "kind": "file", + "path": "img_705.jpg", + "sha256": "2ce6c4dd6864fb43c71f4dc567919f6553740bce5c4b44bf9f7d306147e1d1e1" + }, + { + "kind": "file", + "path": "img_4851.jpg", + "sha256": "6025b29f814c0d366751734ff13b76e981c76270e4236cd36ac2ae27215c2fe9" + }, + { + "kind": "file", + "path": "img_711.jpg", + "sha256": "b73c4281fbc6b2fbaf3e3b02cae485b276eb9c12e452f66520affa249859cce4" + }, + { + "kind": "file", + "path": "img_1929.jpg", + "sha256": "a83e943d21721a14956ed735e34f5b62cfc651a4b600e8f28f6d4e1740a61e0b" + }, + { + "kind": "file", + "path": "img_3680.jpg", + "sha256": "dc4c109f0bd924ad0a26b41f3d9c4c6b8af39f90a955373c88316f93b9266527" + }, + { + "kind": "file", + "path": "img_3858.jpg", + "sha256": "74eadfc00113e020d6f3a88091dfb8a6a6311e36effe515e36bb1db2e94e4972" + }, + { + "kind": "file", + "path": "img_2575.jpg", + "sha256": "4e1c815efb824b86c6bdd9d82e138ff27d1c21099d0ad9feb6d85808410396ae" + }, + { + "kind": "file", + "path": "img_4104.jpg", + "sha256": "5402f7744eb473af6896ab03fa470b3cca449d9fa074a0e461e31dab0157433e" + }, + { + "kind": "file", + "path": "img_4662.jpg", + "sha256": "9f2dd407d3ca096cd993c00f0dcc20bfdda106c857d0fc964cdd5850df8139f3" + }, + { + "kind": "file", + "path": "img_2213.jpg", + "sha256": "20a8bed36861982b1c6d8cd8b440a361269a253af7bdf0a3ff063d23615a0031" + }, + { + "kind": "file", + "path": "img_922.jpg", + "sha256": "a7d8f2db5ae23ee0e5cf4ada04aa6b2a433f858a52a1909a1fde66965a39a490" + }, + { + "kind": "file", + "path": "img_4676.jpg", + "sha256": "1633bd5afa0871cf044b2817337a926faf9d49b29987c48a4ff96502bbd7bf51" + }, + { + "kind": "file", + "path": "img_2207.jpg", + "sha256": "9ecaa8fc28989d1c13738dd190503e673cab2f6f8da830dcfd8bbb240d675590" + }, + { + "kind": "file", + "path": "img_936.jpg", + "sha256": "ce89ceb2149270cc58517655a98a0dcdd52e12cff298aaaff13ad2437ccc9f55" + }, + { + "kind": "file", + "path": "img_1068.jpg", + "sha256": "764ba2aa359c5b33e5c56b233e107693f209483994d24cf9a59752ef59fa65d9" + }, + { + "kind": "file", + "path": "img_2561.jpg", + "sha256": "3379fefd6e0c35c9dfcd1a38dde91193df41a4a48335a6d1657060c325d6c1b6" + }, + { + "kind": "file", + "path": "img_4110.jpg", + "sha256": "bc2e5f4d064928d327d5f08cfc6120c52c2f3986d933aaf35ce3d2700622860a" + }, + { + "kind": "file", + "path": "img_1040.jpg", + "sha256": "452cfab645fe3bed073a887c699bcb140b8a7e075df5d56f034c12bb7747684e" + }, + { + "kind": "file", + "path": "img_2549.jpg", + "sha256": "6e3ab91a90bdc11060c945f18c1ec9b481d7e7578cb361366675baa724f7eb08" + }, + { + "kind": "file", + "path": "img_3657.jpg", + "sha256": "311ba44b0a5d04ae9505c6d3c402fb010106068a289db8f4af82b74fcb0a53a1" + }, + { + "kind": "file", + "path": "img_4138.jpg", + "sha256": "1e6255266488178b53d15c7f51b14b0b8e3c67fb8dc8c69954774133748c9df4" + }, + { + "kind": "file", + "path": "img_3131.jpg", + "sha256": "4a1b4061a58f6d2a0d6e3cdb947dc4752090edad47da0b8ce14ae86835bde4c0" + }, + { + "kind": "file", + "path": "img_4886.jpg", + "sha256": "7873067f650aa2c70afb42d2c74b1a483187c7597645e8abb539e11b3ca95ad3" + }, + { + "kind": "file", + "path": "img_1726.jpg", + "sha256": "e69a57f1651af30686947db372bb9e02a60e53db3e65c1bab4a6e8d74e5d600f" + }, + { + "kind": "file", + "path": "img_1732.jpg", + "sha256": "2a556c0803e0f5bff9d590c2725062ab879dc457e26b1da25d1a8394d3f0009a" + }, + { + "kind": "file", + "path": "img_3125.jpg", + "sha256": "950035c4fba0cd968fe0b219d2403c5866876df9eee18387b4a0061ea85b9a81" + }, + { + "kind": "file", + "path": "img_4892.jpg", + "sha256": "b9a8f279b3d2941c44c3e876a5151af8914e55dfcd59f25e3725d9d9d821b455" + }, + { + "kind": "file", + "path": "img_3643.jpg", + "sha256": "07be77915cc0e9edb68c0aa74eeec2fe351d2a7002cfcb99b7a071274758990c" + }, + { + "kind": "file", + "path": "img_1054.jpg", + "sha256": "bb113a362d7fd5c426daae6f97185cc8f358f582d0b4363179ba2f0e9d90cda5" + }, + { + "kind": "file", + "path": "img_2978.jpg", + "sha256": "392392581a82eee1581fd2e44663123c2e2e52d5a8eb4b3716f2fffb96e9b87b" + }, + { + "kind": "file", + "path": "img_249.jpg", + "sha256": "f97683a401349d266ccffe0a97b58792d1b914e07003556ba6a33325161f8bbf" + }, + { + "kind": "file", + "path": "img_507.jpg", + "sha256": "4278d774368c7489e0d00d1577f3623f1acfc9fe120b1cf3adeb97438b6523aa" + }, + { + "kind": "file", + "path": "img_1281.jpg", + "sha256": "06f5a228fb366495e2a94551452ac455ce8ffcf7479a65adccc52bebadf594e5" + }, + { + "kind": "file", + "path": "img_2788.jpg", + "sha256": "1280e0252f6b3b5dfeb7d6d987b6c4ee62f6547f41769c9118447928c214a802" + }, + { + "kind": "file", + "path": "img_3496.jpg", + "sha256": "4af35a9254bc0081e16239a044c475effc3ed6e95ce46d4e3d4806e7e8a916ca" + }, + { + "kind": "file", + "path": "img_261.jpg", + "sha256": "6c3e1024fd6d10a036f195b3f3e6ad687f41614bb7631438dbd9c749716e2cb0" + }, + { + "kind": "file", + "path": "img_2944.jpg", + "sha256": "6268ec316ba18309457d431511e3ab442ae22ef463b2fff57eb61cd0feda2236" + }, + { + "kind": "file", + "path": "img_3482.jpg", + "sha256": "d325b846b0abdef08942ba91505f354fc468d8ec445547caf7532ba2c792672e" + }, + { + "kind": "file", + "path": "img_275.jpg", + "sha256": "8378b2e2ba305fd62f4c05a8fcf177535207d97f766e9d87f3bc15f0d1616ac6" + }, + { + "kind": "file", + "path": "img_1295.jpg", + "sha256": "17983dafddb179e1221cdad559aeb7e5a1358d6ea6264ac3e479c2c3bcf378ff" + }, + { + "kind": "file", + "path": "img_513.jpg", + "sha256": "69a99b115da8f380b9cd70ab059eb642a963a42cd1008c89676683ae34eeee54" + }, + { + "kind": "file", + "path": "img_2011.jpg", + "sha256": "7a221220a66da14db41fba0c97a4ab44c6c7cd11190a8be5bc69fdcc910b18d5" + }, + { + "kind": "file", + "path": "img_4460.jpg", + "sha256": "06956496968db302950fce6fcab844e8cdc362654e557f997878cc817322d7a1" + }, + { + "kind": "file", + "path": "img_3469.jpg", + "sha256": "27666677b2bd25ff926c64b5d0fd39d09c45c678f212c6851c9eeee10b4a8b59" + }, + { + "kind": "file", + "path": "img_2777.jpg", + "sha256": "d0bc8d31957319a455e349d9321ece033734f3f69169e68c6b95b8929d5db80a" + }, + { + "kind": "file", + "path": "img_4312.jpg", + "sha256": "4aa68461d8265f0c119ff5d15dbd4b2d849d8acb78665f2c51d8093d4686c152" + }, + { + "kind": "file", + "path": "img_4474.jpg", + "sha256": "3997d5c76291a4c67077c68e87ee504ea8a1ac8618aa6f19ea1412967479a089" + }, + { + "kind": "file", + "path": "img_1524.jpg", + "sha256": "74230bdc5ed0d036d2cf96d0932cae53eb5a5eb3abd43fbff4a1eb165de77c0a" + }, + { + "kind": "file", + "path": "img_3455.jpg", + "sha256": "b4ab7cbe8338f5d86e0c60b25826151a80fc952c51c5ad3b9db83f7741b4fb41" + }, + { + "kind": "file", + "path": "img_2987.jpg", + "sha256": "8bc89a8b3e864be63079bc2239de154d67d107771779caba00ab9c3004eb3e76" + }, + { + "kind": "file", + "path": "img_2039.jpg", + "sha256": "81efc07ff89de7f86bc3d3e61906c81900c61951d36a499ef8bb3ab4821ade69" + }, + { + "kind": "file", + "path": "img_4448.jpg", + "sha256": "78674cee7af3836a2f57e1001b4fe208f31956e3ab0895781b73796da111c5a3" + }, + { + "kind": "file", + "path": "img_3440.jpg", + "sha256": "f9d54b384a7c6e95b71a44b08808cbe3ae0d6c08ff676deb321d2819091f3df6" + }, + { + "kind": "file", + "path": "img_1531.jpg", + "sha256": "222833d8a764848211c7d0c265a4ee3f3d33c08cbc25f500f27cfa7d07118549" + }, + { + "kind": "file", + "path": "img_4449.jpg", + "sha256": "a3f4de77b281467a865106a00d10c21975e9cc62d80f5c37f0d378c1bb8da4d0" + }, + { + "kind": "file", + "path": "img_3326.jpg", + "sha256": "d0a5239663a9d62909073360cd094e5a944a0e1239f7ff826b1ae46573a505f5" + }, + { + "kind": "file", + "path": "img_2038.jpg", + "sha256": "2d3aa36d009c53c11980aa1c69f0d27a1516f983ae5521794de116f870de674b" + }, + { + "kind": "file", + "path": "img_3332.jpg", + "sha256": "bfb1237547a47095cde3a345ae3ff99edbce93d2581de5b80096ac6f9137a6b4" + }, + { + "kind": "file", + "path": "img_1525.jpg", + "sha256": "77c6fd5142c882098a6e85e2c39d07bebb5c0c995a59e77369167cecb14b9d33" + }, + { + "kind": "file", + "path": "img_1243.jpg", + "sha256": "a2072df95c9d7b2bf2513d4921d810de685d19640288bf57876795775bba13c3" + }, + { + "kind": "file", + "path": "img_3454.jpg", + "sha256": "1071556ed77c93222a6b99147e6df1b690f40042c2bc8d3df8232487770d324b" + }, + { + "kind": "file", + "path": "img_2992.jpg", + "sha256": "1bfce4e017bb9d60236edb125623286b7629bc7d066033131d23ab9cf1e526a9" + }, + { + "kind": "file", + "path": "img_4313.jpg", + "sha256": "546c3214882cf3887c074b413d7a0d5b6f6b532582bd554bae3983eea1db890a" + }, + { + "kind": "file", + "path": "img_1519.jpg", + "sha256": "ba2daea1670d6e1b2e311b0cbce0a85a45abf05f4f7ccf1003ab1ad86c15237a" + }, + { + "kind": "file", + "path": "img_4461.jpg", + "sha256": "d8de46e2b815256f83e168e3beb358044f9ceaafa828f9d9233b97a81fdce2fe" + }, + { + "kind": "file", + "path": "img_2010.jpg", + "sha256": "047911d691889dfb91496f12cc03f28e478edcaf6bfaa4636eb490abdfd98513" + }, + { + "kind": "file", + "path": "img_2776.jpg", + "sha256": "2eff8afebbdad55599408b69798288e6abe8ad41b38d3397f136de0ffd0cec9a" + }, + { + "kind": "file", + "path": "img_3468.jpg", + "sha256": "621d0e7b7b9813245f731b1d8b47e13cbd2512ed98bf2ffd07c3a77aadbbff4b" + }, + { + "kind": "file", + "path": "img_274.jpg", + "sha256": "525a43bf806a823d311b211b09a6d94159dd0b49b2227d0d79ec4803fb1ef2fc" + }, + { + "kind": "file", + "path": "img_3483.jpg", + "sha256": "35b2e46703fd1741d7e7cbc7671a6056e3849b569f1a0da06ade3557e66eecc7" + }, + { + "kind": "file", + "path": "img_2945.jpg", + "sha256": "d9302cfcd8098888d7653be4fa3c8a4aaa82d2336150ba6ba4ccf44a3d5cec00" + }, + { + "kind": "file", + "path": "img_512.jpg", + "sha256": "f8ef54d87f0fc8cb7b81afea7c0adf6c6425833414a52010c853b072c3922b56" + }, + { + "kind": "file", + "path": "img_506.jpg", + "sha256": "f4b76a0f5e9851fa13e098bfcea88cf956d788f353c7e5ca1d9c21b4b6876b82" + }, + { + "kind": "file", + "path": "img_260.jpg", + "sha256": "95ab9003076ca633d0328013bdffe68b9b1d6f435556a5b1c72b60402f295b0f" + }, + { + "kind": "file", + "path": "img_3497.jpg", + "sha256": "6fc3dd3aa6b071016118f4301b6039a94583c5d2514d672825fa8af7db93a312" + }, + { + "kind": "file", + "path": "img_2951.jpg", + "sha256": "d57b2a50059544432580e79eb7907fb66e5de13112c57762d891774c1d9c92bb" + }, + { + "kind": "file", + "path": "img_2789.jpg", + "sha256": "230dad027ef96d422bd8bcf27a137512de433d93e0c86b0ff216bf7ddcb1d62a" + }, + { + "kind": "file", + "path": "img_248.jpg", + "sha256": "689a32ef6aab5106cbe4a5890dfec2988fac6c2df5f623c1d724707bd38cb18f" + }, + { + "kind": "file", + "path": "img_2979.jpg", + "sha256": "73d15d8a0ec26eceea7c402dff19558a3ebcc082c98c771cd21e61b7f7b81d9b" + }, + { + "kind": "file", + "path": "img_3124.jpg", + "sha256": "d7e4f384299e7d7fe2a675f3153b8c03fcedd07d85daba18dddc35c3f2b645e3" + }, + { + "kind": "file", + "path": "img_1733.jpg", + "sha256": "355f52944dfa4c5c5cc0d0e78ba81d45fed880ef0e2c7d670e4adc811503e467" + }, + { + "kind": "file", + "path": "img_1055.jpg", + "sha256": "e5e7c76bffe49068f7ca2f405dbfbe36a61d41269acebb9a278495b58e252715" + }, + { + "kind": "file", + "path": "img_4139.jpg", + "sha256": "c282313ee573659796e5d61246a375be9416b2490cd585628a81369bf1e4c733" + }, + { + "kind": "file", + "path": "img_3656.jpg", + "sha256": "90675f0935b192258552433ae92f130ec36f7564b7551a82c7f90c737fe4e0ae" + }, + { + "kind": "file", + "path": "img_1727.jpg", + "sha256": "47df8c43f0e223b1a7fc2a2ab6f1b54aa3e85b5ef32ed5986a7e03dc16c63cdd" + }, + { + "kind": "file", + "path": "img_3130.jpg", + "sha256": "c43d6b15b536a0dbb1418cefbb353f538e8622ce8bd44deed8f4dddaa4783186" + }, + { + "kind": "file", + "path": "img_937.jpg", + "sha256": "7b0d3bf58b5509b8f82f7d0d7a013816aa9807e574e9d4203efea8a5f4e0b7c7" + }, + { + "kind": "file", + "path": "img_3118.jpg", + "sha256": "d6721f65fade4f42f11802fbfeca0a03ce684391ee97e95d79127fd978937964" + }, + { + "kind": "file", + "path": "img_4677.jpg", + "sha256": "449f6baa2800105530c404e90296813613f9bf578b531d50d5b88f8726b4d0a6" + }, + { + "kind": "file", + "path": "img_4111.jpg", + "sha256": "ff5c9e390c8368bdb8f08a7c9248d593eca42a78ef58294f6522d895fadbe2e8" + }, + { + "kind": "file", + "path": "img_2560.jpg", + "sha256": "eda3cc019ada44d7790db90c8346d277c1dc66bb6bdd7e95df7e1cc7437f556a" + }, + { + "kind": "file", + "path": "img_4105.jpg", + "sha256": "5fbbc5afe85361be31cbb818ed6cf04ee661b7df83e53ac0e32a0f126c32f683" + }, + { + "kind": "file", + "path": "img_2574.jpg", + "sha256": "be96cca71bfa9453d7795e79f52de6020f4d05f78f74bb2e21a52852cc00353b" + }, + { + "kind": "file", + "path": "img_923.jpg", + "sha256": "49fe087a9c392b18c9c40837d799a56f1e7b067fc681d91974b8778889c3000a" + }, + { + "kind": "file", + "path": "img_1928.jpg", + "sha256": "2c941296d67f5d5ff9c47cb44af30ec47a774f1d7a66e1455a77b2430daee7b0" + }, + { + "kind": "file", + "path": "img_710.jpg", + "sha256": "2f5c9303ecbbfeb81d345524c35b1bdb91e2307faa12abea20ca309497a0e18e" + }, + { + "kind": "file", + "path": "img_4688.jpg", + "sha256": "04f54a1dd464ced30b5e5bd4c61608e2f0427009abf08dbd9f2821108cc9dad3" + }, + { + "kind": "file", + "path": "img_4850.jpg", + "sha256": "589e154566c1ab5794fddce693a9ea3719017d269fb4bff76bb979df33c6a9ef" + }, + { + "kind": "file", + "path": "img_3859.jpg", + "sha256": "9bec6da6f9d3791908d5c8d370c10b927d00b07bfb4489821bcb510c490000d1" + }, + { + "kind": "file", + "path": "img_3681.jpg", + "sha256": "4cb0476474dfce8837c0193d06d389dc82d16433a08689cf3a3cafbebc14ed4a" + }, + { + "kind": "file", + "path": "img_1096.jpg", + "sha256": "433846e0352e7bb391a3fc078d33a5dc6e99b3780f1457768e0a97143bb5f70f" + }, + { + "kind": "file", + "path": "img_1082.jpg", + "sha256": "95c5a1b5d965bc90f91c55a184fa45684f8b4416cd502f7360f3c9e91026c63f" + }, + { + "kind": "file", + "path": "img_3695.jpg", + "sha256": "48430b89685cf85cdf493ea5ad07af55b06e6f437ab2da9fe33a8f7e8b89f653" + }, + { + "kind": "file", + "path": "img_4844.jpg", + "sha256": "1fc44e500b160a7ede767227a9ba94809c022fa811edb603f9ca18266926d317" + }, + { + "kind": "file", + "path": "img_3865.jpg", + "sha256": "fa43f6aaaaae6c8ad8a990f34706ce2fd03f7ca71fefea975c826840ac4a52bd" + }, + { + "kind": "file", + "path": "img_3871.jpg", + "sha256": "468c0ed2df65e3b759563b3a5ab77ee8edfc0253cf52846c074ceca108ae7acf" + }, + { + "kind": "file", + "path": "img_1900.jpg", + "sha256": "197e9d8440a0b0e1f25911fbaf049c84022ad6d2d74f9779982945be47d8a4e4" + }, + { + "kind": "file", + "path": "img_738.jpg", + "sha256": "b673a349c865768ec41c0f11a5d951097bdf6e970f74856f96ebdec5a433f46a" + }, + { + "kind": "file", + "path": "img_3050.jpg", + "sha256": "fd4a3f90a8fd3d79f2a0b571f6dbc6e49eb2f5e1bbfcd5990bb6e2e7144b2f27" + }, + { + "kind": "file", + "path": "img_2428.jpg", + "sha256": "d44eead1487ba92951ab8796d0ab2a9026b81b5a13998090527f5027093fecd0" + }, + { + "kind": "file", + "path": "img_3736.jpg", + "sha256": "df20c5ef8318257d5695055f07e3ccf67074759dbebf95f8e7a974e64ca3bb9d" + }, + { + "kind": "file", + "path": "img_4059.jpg", + "sha256": "1d2e33d8041975ed9edd11ac82c8f699e01f2cbaa87966339b292c55d8913ad9" + }, + { + "kind": "file", + "path": "img_3722.jpg", + "sha256": "9b709bc6b3262a1cb1c02671d1bc5ab09caf00dd1374fd8bf0dcb7170df76045" + }, + { + "kind": "file", + "path": "img_1135.jpg", + "sha256": "5952913f90bf528e76de65b067d2fa60e59e0dc432c5708eee3a4914b9d009b5" + }, + { + "kind": "file", + "path": "img_1653.jpg", + "sha256": "ab530177f3959848595ad6a4303c4e0d91deb4d5aae43fcb6d9c7a8446bb78a0" + }, + { + "kind": "file", + "path": "img_3044.jpg", + "sha256": "eefc69bf62614dd5016a4f0d8db64b94f642ab22b7a987388385207c617a40b3" + }, + { + "kind": "file", + "path": "img_2372.jpg", + "sha256": "ad45663775b742c2d9d85c2190ed8e0da24446df3b36ee31e009b1638ae9c7dc" + }, + { + "kind": "file", + "path": "img_843.jpg", + "sha256": "ec0094d58e80494c74764049bc313037d1eb64422da99599e66c58014128b618" + }, + { + "kind": "file", + "path": "img_2414.jpg", + "sha256": "f297c0a27803d4d37ecca2ee028d10da0bd125b22d15ebd71188a18e31540d3f" + }, + { + "kind": "file", + "path": "img_4065.jpg", + "sha256": "868ccb6b07ca8e2d70b6d72c6453da687b23fa2dc5d771605ffd1ba4113f9873" + }, + { + "kind": "file", + "path": "img_1109.jpg", + "sha256": "78082d2e4042e7ea80396f1328329ddd57324f39c3119e775b21a0b4021ec1a9" + }, + { + "kind": "file", + "path": "img_4717.jpg", + "sha256": "26b3dbe011d76f09d5a1aff6327d72ff89a59c5041bde274639085d3ce95f651" + }, + { + "kind": "file", + "path": "img_3078.jpg", + "sha256": "5763426f058927134dc7eef92b01d2993dd0194714e060d2f9316bcf62af7375" + }, + { + "kind": "file", + "path": "img_2366.jpg", + "sha256": "e049160030446937d034e2f1337da8e0ed01b0e6f4e7c3e79cd18acbd90e1ce0" + }, + { + "kind": "file", + "path": "img_857.jpg", + "sha256": "f91ac3aa852483655f316d51df92ecfff7602cb6eb5160bf719e7847c68607cc" + }, + { + "kind": "file", + "path": "img_1684.jpg", + "sha256": "42fd4d7a0617e31133ad360298b1b90f32b8162d126a7816e58c5220ebfec69b" + }, + { + "kind": "file", + "path": "img_4924.jpg", + "sha256": "0067186fae286e70a5e9d75c101ec229fa74e640001b9e5f1cb63b33e3385b5b" + }, + { + "kind": "file", + "path": "img_3093.jpg", + "sha256": "82ef57e8258ac5f60585910383ecfd6da92d10973c54898bb561a388da24828d" + }, + { + "kind": "file", + "path": "img_664.jpg", + "sha256": "d5517aab5a4c5d2ec62255b16dd66254ec9ab10328442be484f4bbe74882b335" + }, + { + "kind": "file", + "path": "img_102.jpg", + "sha256": "82c0ae8e64f87d6663c40565f7a1cebffc886c037839d8dc370f6373c36893b2" + }, + { + "kind": "file", + "path": "img_2399.jpg", + "sha256": "379956f5a1a708bd952df431e980de66aff58ab4c25c7ed5e5c10ed2a45394c2" + }, + { + "kind": "file", + "path": "img_4930.jpg", + "sha256": "14821637e4509e044594732583050b52fa8799285b1bf17340de222ebeaee851" + }, + { + "kind": "file", + "path": "img_3087.jpg", + "sha256": "e960a1cc48caa405db6f6df0a48ca25209df1efb316727c9baf47920f965ecb4" + }, + { + "kind": "file", + "path": "img_670.jpg", + "sha256": "fde568c7b5fa2c3223b8588865d3e831f97d3cedbf118df4c4863c74b31cb600" + }, + { + "kind": "file", + "path": "img_1848.jpg", + "sha256": "37b603a9316b94e560736f4658dc5d89c3b7fcbfd1b1086bafcdd68bec8081d2" + }, + { + "kind": "file", + "path": "img_1690.jpg", + "sha256": "8330083cd58d2f8a7c1fd6c4865c95d506f9b891924ec853ba87e75c164808fa" + }, + { + "kind": "file", + "path": "img_4918.jpg", + "sha256": "e2e670c65dda89491c30edbc1b78517282b74d65923a59356bf13d9ce3e2bfab" + }, + { + "kind": "file", + "path": "img_880.jpg", + "sha256": "7ac47de71d0ec067484489beaab733f9d8191ca5338fafcd845ed2a39e3c566a" + }, + { + "kind": "file", + "path": "img_658.jpg", + "sha256": "ed499f59c5b61836b2cf49bf652acef74e0fe63b65fe2bab768b0635671a3ff1" + }, + { + "kind": "file", + "path": "img_1860.jpg", + "sha256": "035411db5d846946a460cd200ea1f7d8d57cf44b39e532403780437469b8c9be" + }, + { + "kind": "file", + "path": "img_1874.jpg", + "sha256": "e30a8b7992b4f3f760f3ffab1f256e6096b7dd09143dcaa466ee15d5cf97319c" + }, + { + "kind": "file", + "path": "img_894.jpg", + "sha256": "ee147298471179f304a6d4cd7977d2138b9cf331854cda826751171f1ac52d1c" + }, + { + "kind": "file", + "path": "img_39.jpg", + "sha256": "12be95f29388e4d0f12247c0ceced60d4b2e3b8974dae440f8bc042a8af1d951" + }, + { + "kind": "file", + "path": "img_3252.jpg", + "sha256": "f4349f11923793540f0d77665d25727d9d7e4f95f430151590e58cf807170f6b" + }, + { + "kind": "file", + "path": "img_2158.jpg", + "sha256": "5babd758bde7b1038c1ebee7f253feea7a18697392be30450e9d5e2e260e1876" + }, + { + "kind": "file", + "path": "img_3246.jpg", + "sha256": "a4804ab8eefa53fdd3c502e3b5dbf3d9d6d2a54bbea9cbe0fbe717b65a34fdcf" + }, + { + "kind": "file", + "path": "img_4529.jpg", + "sha256": "0e31bcc79fe078bff03f3cb47675e5ab831ac6f161dee8bf597ab267005a707e" + }, + { + "kind": "file", + "path": "img_1451.jpg", + "sha256": "1ed6eac9e35f22c06bf455ce637bda99e3c9b2223ec661f1a55bbb887bb8f2c1" + }, + { + "kind": "file", + "path": "img_4267.jpg", + "sha256": "36c42e23c111ccd544e04dc846b3e325559a32a813aaf0fa00a17147ba3b3a6d" + }, + { + "kind": "file", + "path": "img_2616.jpg", + "sha256": "4d043a2b670a90d345ba78c812e25d7a55a2fd6024dd334fc7b74ea7f86afd10" + }, + { + "kind": "file", + "path": "img_2170.jpg", + "sha256": "0781c83baa004dde2d22283e54abd85cb63936bd99e917c1a5cfe044323c96b6" + }, + { + "kind": "file", + "path": "img_499.jpg", + "sha256": "0c54a8ca1d715906ec0b4808abaea6b4505aa42ed4be34d5313863ac6465f124" + }, + { + "kind": "file", + "path": "img_4501.jpg", + "sha256": "d481538a42034c603ca2c3d731f9e0932d4c9e06fc821666596279019e6ec3b5" + }, + { + "kind": "file", + "path": "img_1479.jpg", + "sha256": "5dae28c63cbb5c49f049bff583dcbcabe56ca3ac6d3d31f71ffaec9ca812910f" + }, + { + "kind": "file", + "path": "img_2164.jpg", + "sha256": "c3ca75b48b6af3cb88746851c4e25a831b2f1a61b89da6b94a57b9a436ec91c1" + }, + { + "kind": "file", + "path": "img_4515.jpg", + "sha256": "8d35ac81c9042c67ef7be389a8fe20fdb83445f9ab53e844af47b9d0cc0f8c26" + }, + { + "kind": "file", + "path": "img_4273.jpg", + "sha256": "ac947d3026bb85ac1f1dfa3677f9d310b86ecda4cbf4d2ecde5db652443b4f94" + }, + { + "kind": "file", + "path": "img_2602.jpg", + "sha256": "633902bf959e969525e8220082d0a1d1282298fec12af137de8041c2e25de7d0" + }, + { + "kind": "file", + "path": "img_4298.jpg", + "sha256": "fe51dc76455a2c1acb574643208c274c5585d23852af920d87bd0665bd4b63ae" + }, + { + "kind": "file", + "path": "img_2831.jpg", + "sha256": "616850fe9e065a39d76454f844d44f1cf252e75b16b16213b6e92cd35dd7baad" + }, + { + "kind": "file", + "path": "img_300.jpg", + "sha256": "383ec8e2608be227e841728178696e413bad2009170c94d20005fd6ccbda7710" + }, + { + "kind": "file", + "path": "img_466.jpg", + "sha256": "e81a72c4238ad425dea10e38814c06bdc80fdb6e78391ca9be2fb0c7c642fa36" + }, + { + "kind": "file", + "path": "img_1486.jpg", + "sha256": "edb3ff733f317ef0019a51da8e2e5da8488a86e6380c8c32e0b15a3f9003f7d2" + }, + { + "kind": "file", + "path": "img_1492.jpg", + "sha256": "9ee42d136cea733bb0762340ed545fb166cc107bc94f42091c6e2bb1998e58a6" + }, + { + "kind": "file", + "path": "img_472.jpg", + "sha256": "9a87f9cd8ef2ae6963e65b4859ca0dbc41c183217acd7b98c533cf180069edba" + }, + { + "kind": "file", + "path": "img_3285.jpg", + "sha256": "f7ef0d210a723a1bafe4e21b299aad39ee9e707990f28c1ff28a2ac92911092f" + }, + { + "kind": "file", + "path": "img_2825.jpg", + "sha256": "92402af6e7ebbfa4b4256921e2a060dde842e506fe583482cb3257885d27e61d" + }, + { + "kind": "file", + "path": "img_314.jpg", + "sha256": "63a700c7f189efc7a82c9908e279507275da9e30c09cd78a4a5b208a31167ac1" + }, + { + "kind": "file", + "path": "img_2819.jpg", + "sha256": "f29876ca772a894926e45b96b04577297257f7afa3559d17e14fea34279109ae" + }, + { + "kind": "file", + "path": "img_328.jpg", + "sha256": "20ed6dd7130c84683555acc1738b67552e8317189ed6064eb4d586fc1298f1a2" + }, + { + "kind": "file", + "path": "img_458.jpg", + "sha256": "7d36901c81b3c497f6cf7af69170ad13fede4d9c65da7e58f1c40fd99d9005b9" + }, + { + "kind": "file", + "path": "img_1484.jpg", + "sha256": "162a92466fada22384c0403ba0a83792caf307f5abcba9973c6e161ef3b42133" + }, + { + "kind": "file", + "path": "img_302.jpg", + "sha256": "35d214fb6845fb77e0e8372b3f16ff9fc700039834e7e971129a303f170255d6" + }, + { + "kind": "file", + "path": "img_2827.jpg", + "sha256": "3d3040ac2197bb33415a138e5acf63bc940bef62da3026929fefac631702ec72" + }, + { + "kind": "file", + "path": "img_2199.jpg", + "sha256": "eddc17dfd839c1027cf18a68dad652461631a62470983ec3693308ea23788fb4" + }, + { + "kind": "file", + "path": "img_470.jpg", + "sha256": "bcd1383f1f0198cbb056a58bf9c03fb61ce9f0a87846cd089ffcdfded129122b" + }, + { + "kind": "file", + "path": "img_4503.jpg", + "sha256": "a2f45eb30b8895899c8eb71c114f49ac766fc735a569f5e2df0303fe24ffd338" + }, + { + "kind": "file", + "path": "img_2614.jpg", + "sha256": "3629791992f0986dd2558da2b6a04e94f173c953f37e32942ff96e16daeafbba" + }, + { + "kind": "file", + "path": "img_4265.jpg", + "sha256": "04311ed3df9f4ec297a77ea832dc176b64347be248ce322969975eba1a0e0ba7" + }, + { + "kind": "file", + "path": "img_1309.jpg", + "sha256": "5946859bcd84182e68649e34667443127a538a04b83150d859138c13fa5cfb6c" + }, + { + "kind": "file", + "path": "img_2600.jpg", + "sha256": "aa5757e811dc18e0a1677522f272e1f4bd1cc88cf236dd961042707e1814b134" + }, + { + "kind": "file", + "path": "img_4271.jpg", + "sha256": "3c199163bb13bcd7f1071539c30786db497f59bceaa146e481be6e22cf1c7912" + }, + { + "kind": "file", + "path": "img_4517.jpg", + "sha256": "e2e7abd81988352737a97d50799873a97880f340bdca97c10158a0961edee1e8" + }, + { + "kind": "file", + "path": "img_2166.jpg", + "sha256": "f958e80dea89be69ab5a2ccd1ebb4fa420572f5ae4532d75347da3dba1910d62" + }, + { + "kind": "file", + "path": "img_13.jpg", + "sha256": "ff741f1fb94c50e1311d192bdbaef95d97a2725b4b4c6ac82f3842659f7d824a" + }, + { + "kind": "file", + "path": "img_3250.jpg", + "sha256": "653a9b8d612a4816616ceb49e0980137efe5874062d74e11a315eef7401a18af" + }, + { + "kind": "file", + "path": "img_1321.jpg", + "sha256": "f441ddd94c42d19374398aa23160983750b3307484316d2ea23f14a85c15a33d" + }, + { + "kind": "file", + "path": "img_2628.jpg", + "sha256": "cd1436fd1cf92e75418ecfb0f50f31bbe3f84ebceb419a671fc6b957a781dc54" + }, + { + "kind": "file", + "path": "img_3536.jpg", + "sha256": "233b2fc1422677e8fa4045c4ccd1d9caa3b859471b9551043280b8c4e0e16301" + }, + { + "kind": "file", + "path": "img_3522.jpg", + "sha256": "0793d3338d673c4fbb6651cef86e9686297a992d888a1146a146a5fed06fbb27" + }, + { + "kind": "file", + "path": "img_1453.jpg", + "sha256": "6126f80122cce78bfbfe425510e923ae26d96ddcf7e4d4f42b9e5686d2da8ad9" + }, + { + "kind": "file", + "path": "img_3244.jpg", + "sha256": "e22f0c59149ea3768f910d05b883f25d093023e182fc5cdf94d47ad7208e7fef" + }, + { + "kind": "file", + "path": "img_3913.jpg", + "sha256": "e456b4eb70723d0d1a64a7eb5b601eb169d0cb4ca7d9754ff736738b4d35e7ec" + }, + { + "kind": "file", + "path": "img_1862.jpg", + "sha256": "b9c5ff6e468d5aa6037d00faaf716359accfec3b9185490dc16047a5a5df7520" + }, + { + "kind": "file", + "path": "img_882.jpg", + "sha256": "e70d1e7f2c07816c7294dcfe11a43f43f096ea74eb360113f8831fc7a2def526" + }, + { + "kind": "file", + "path": "img_1876.jpg", + "sha256": "2c58336c180506efaf538eef9a4b6bef06ce46cba10328c52a240ef5cbb420cc" + }, + { + "kind": "file", + "path": "img_3907.jpg", + "sha256": "fcaf3b33c2a85232fa68661ca72772b9fad62b85f0b99aff64d943604dcffb77" + }, + { + "kind": "file", + "path": "img_100.jpg", + "sha256": "5f2bb4af9be2522b048521ec9767412241179997c7bfa1b10c171cbced6fe236" + }, + { + "kind": "file", + "path": "img_3091.jpg", + "sha256": "e47de452a6f70e94a98f6cd69036ad0880f881673677415058277a5d758fe784" + }, + { + "kind": "file", + "path": "img_666.jpg", + "sha256": "e9cd3f576adc4c987582c09977d8a38e3fa7aee52f319617caa491af3a4dae19" + }, + { + "kind": "file", + "path": "img_4926.jpg", + "sha256": "469027ff5bb57a1a90520e52cb5a0e031c1bae82a823dc961e3106d206b55c8f" + }, + { + "kind": "file", + "path": "img_1686.jpg", + "sha256": "b3925804a6b9bf2f2af85565e2c1af7b3e02ac0c86579780de889cbd4ad4cf73" + }, + { + "kind": "file", + "path": "img_1692.jpg", + "sha256": "f6e4623a5b44e5696dbddf5651ac9c841699b1a7cbd1b0b4bbb0014178268447" + }, + { + "kind": "file", + "path": "img_3085.jpg", + "sha256": "c601667c149495b7fb5182df0f2c8e646128c592b1a2a5cd2d7e93c0e51d2d31" + }, + { + "kind": "file", + "path": "img_672.jpg", + "sha256": "6741e970bbcd8bcfe3f4942e10e17c1e89d2f93e688a0448b385a6403d46bd99" + }, + { + "kind": "file", + "path": "img_4932.jpg", + "sha256": "153621cc2bfa27dd7ec4e0c9bad25d935c6a64a70cb6d719f4793c7a0d96e1e3" + }, + { + "kind": "file", + "path": "img_114.jpg", + "sha256": "f50709957cdfc76b8268784491c0334c1250cd1482a91a3ae583e5e00dbef827" + }, + { + "kind": "file", + "path": "img_4067.jpg", + "sha256": "c9bf671d832dae408931d872ebda8f14e4fe18a2e8ab73e9b1b66f7b31c69930" + }, + { + "kind": "file", + "path": "img_3708.jpg", + "sha256": "6b336a8b83800a07404d6953b41fba5582764caa36a2d5acd54a4e602fb18038" + }, + { + "kind": "file", + "path": "img_2416.jpg", + "sha256": "1d67e13974f19c1a15cd6c79927a7c569124211b2f80f1ba1913020746115b76" + }, + { + "kind": "file", + "path": "img_841.jpg", + "sha256": "94d7f467135ed01457c30d5fddad99eef9d1e1024101d0e6370a00cbfc198ece" + }, + { + "kind": "file", + "path": "img_2370.jpg", + "sha256": "6ed5b27f46c2ff22a578f440bad549ff0f3ab59f34cb6c5171e2b51644cc41ac" + }, + { + "kind": "file", + "path": "img_699.jpg", + "sha256": "ee1b76f08c30285e0f9ffb5b354b1b7dd8cde860f3cd13efd052c78f468e2acc" + }, + { + "kind": "file", + "path": "img_4701.jpg", + "sha256": "ac343a6a9a2f296fda23e124fb3cacd835dc1b223790ea6ebf9ecefa8c5b604d" + }, + { + "kind": "file", + "path": "img_855.jpg", + "sha256": "c979fe171a3ac04fb1834d670d5ce65b999dc17bb11e2cef7db3d4be32d8275c" + }, + { + "kind": "file", + "path": "img_2364.jpg", + "sha256": "9adf8002df0762d16e0aa3161a38334954aff29fa88cbafbcf00676699af5c11" + }, + { + "kind": "file", + "path": "img_4715.jpg", + "sha256": "a56d06c33550c4d2f7ec85ec73e5dd15f9720071805d2d55e82e639a3e9d1ab5" + }, + { + "kind": "file", + "path": "img_4073.jpg", + "sha256": "671e56da154b63969125bbe2e1fa727f40a1ad13d686efc9b4b233edce8ff87e" + }, + { + "kind": "file", + "path": "img_3734.jpg", + "sha256": "2327a912d183ba269519739ba286498665dcf5146472dfd345f3174c4d3402d6" + }, + { + "kind": "file", + "path": "img_1123.jpg", + "sha256": "35ac1203f807ddd0f14779cd4f6ab4c4af9b2cacc1df07756bcb907125b83a2d" + }, + { + "kind": "file", + "path": "img_1645.jpg", + "sha256": "733bf76c306f83b89a99993f791b18da2a2500149c5014af6b1c435ab6fb559d" + }, + { + "kind": "file", + "path": "img_3052.jpg", + "sha256": "fe4f9133b42c5e891b76197a19f10d4f9eb6758b7a87ac8fd6746c690f21d3b9" + }, + { + "kind": "file", + "path": "img_869.jpg", + "sha256": "0b3aff62a1c6f2ac0cbb1d752daed2cd9328246a5475661183b6ee0d1c01ba0a" + }, + { + "kind": "file", + "path": "img_2358.jpg", + "sha256": "0c2c185276546b85f2eba9209a1c5eb1c16854a1b0caca1d1f5d34dd86e31150" + }, + { + "kind": "file", + "path": "img_3046.jpg", + "sha256": "86f76194bfb7eb6ea55d8a387a9f4b1572359e3cd979d096b0cfd7c69c57262f" + }, + { + "kind": "file", + "path": "img_4729.jpg", + "sha256": "a58cec6253f41cb51c7311d8be6d5d11242a31a0809f6f70e110f37577374e1a" + }, + { + "kind": "file", + "path": "img_1889.jpg", + "sha256": "c58a6785c70034a4b0a032f309244c8136299ea6785c89f19b0546634f509ef3" + }, + { + "kind": "file", + "path": "img_1137.jpg", + "sha256": "7e279787170c5ff1352f867dea6fd801ad87f4591d5fcf2f962c3b01d68d6953" + }, + { + "kind": "file", + "path": "img_3720.jpg", + "sha256": "693db3317d2b7afa4e261de5d3c4c0747eb68e3305ea64939bedf19acedca029" + }, + { + "kind": "file", + "path": "img_3867.jpg", + "sha256": "867ee1a9e81610ac6374231987632cba8106f6de4450dd8527e0396ad23d5e19" + }, + { + "kind": "file", + "path": "img_1916.jpg", + "sha256": "cdcf658348c1f7108dada8b1498533c9a01b0f0b2357c4ca98ea4e2f94d5337c" + }, + { + "kind": "file", + "path": "img_1902.jpg", + "sha256": "eb8394d9b8896c10c365587021786758a43c875b21d2a2f382c2eddf79b83a43" + }, + { + "kind": "file", + "path": "img_3873.jpg", + "sha256": "28ec509acb06492a7aa54d09542363e8cb7c979917a7b7fc931fce604dabdf7d" + }, + { + "kind": "file", + "path": "img_4852.jpg", + "sha256": "77643057ad508c953aa39123235845f85807c5d3d92fede99ce93a23e514bf92" + }, + { + "kind": "file", + "path": "img_4846.jpg", + "sha256": "d0b0f9d09ffd91434ce3f9de7d08ed17c1ae75e0251fde607d53fc3ed30e09a5" + }, + { + "kind": "file", + "path": "img_706.jpg", + "sha256": "402191eb5a647773ebdf1847fe0ce559d96fe74cd8ad6af22a96284c2a8ea258" + }, + { + "kind": "file", + "path": "img_2589.jpg", + "sha256": "4ad9e350028fbe53943eb2f4c203d2d8589a3e13525e70bba8bceaa3011fdc6d" + }, + { + "kind": "file", + "path": "img_1080.jpg", + "sha256": "62135caa9e11c93c58bf84752b0c09e4752a72070aa1b96127075b62671e4d45" + }, + { + "kind": "file", + "path": "img_4113.jpg", + "sha256": "8227f138109ed094338ec9915ce205b92b402522c5beb025d5bc7d9938bf2503" + }, + { + "kind": "file", + "path": "img_4675.jpg", + "sha256": "9ecdc7cbd983275d4a6ad17545351b9c0c3898db21f1e8242cc092ead991b059" + }, + { + "kind": "file", + "path": "img_935.jpg", + "sha256": "d5880e6ea9b34ebb78030aa67debc69ed85cf5ff5552d74687f3e152f5a08020" + }, + { + "kind": "file", + "path": "img_1719.jpg", + "sha256": "85053aeb8d23fbffc249987f7094f528548de1f8791757b56b1bfacdc0ec0d00" + }, + { + "kind": "file", + "path": "img_4661.jpg", + "sha256": "9d1bf54807d39ffa60aaa97a3d875d855f16316739056bfa0600276c63eaf918" + }, + { + "kind": "file", + "path": "img_2210.jpg", + "sha256": "59e63c0c9afdabf1288c4a6658042112c1fc6c1c60396f69f492cc74228fbc04" + }, + { + "kind": "file", + "path": "img_2576.jpg", + "sha256": "a94f4ec46abf29e5d54dd55885665dd84a1722ec7d7a62e8e89c50db810e231c" + }, + { + "kind": "file", + "path": "img_3668.jpg", + "sha256": "c1118f3f380751772bcb0c7a65cfe24e91ced57f777c848ee421138496ec68e7" + }, + { + "kind": "file", + "path": "img_4107.jpg", + "sha256": "7610fb4c56650621522c31ec2a3b508c0eec5d2dbdbe3bd6f2530f38ae6bd9f9" + }, + { + "kind": "file", + "path": "img_3898.jpg", + "sha256": "e374bb1589c3ad348fc32d9cfc778173685e5dcfb88278f0ca91ae3a8367a201" + }, + { + "kind": "file", + "path": "img_3640.jpg", + "sha256": "8ba3393016c0aecb8b90f805428b29afbc2bb15368a2919b5faafba8043e5335" + }, + { + "kind": "file", + "path": "img_1731.jpg", + "sha256": "91521020fe6150973b03c9b48ebef217ec40cf0116e1481be999246158337a73" + }, + { + "kind": "file", + "path": "img_4649.jpg", + "sha256": "4cbbb9871bd7bb0fcb52c21adda991aea44ff9884d3615fb1e89a86d0d3b073f" + }, + { + "kind": "file", + "path": "img_3126.jpg", + "sha256": "7a66c7ea77c2e34e3277fd26ac62c716778168aadb2e0c8b4ad4408e6567e779" + }, + { + "kind": "file", + "path": "img_2238.jpg", + "sha256": "5aa4ec0b0022bc2770386455c047fff565ab1ca8d89ea243228f6951c586ca17" + }, + { + "kind": "file", + "path": "img_909.jpg", + "sha256": "7be9cd64e2a1c4c993c0c5f31ea15f74b5a5bbd4109e54fd176d34b09ece7779" + }, + { + "kind": "file", + "path": "img_3132.jpg", + "sha256": "fcc2896a5e3722295003f45d12e435293ede4dc6a7a61b45ef8de55f29411cc8" + }, + { + "kind": "file", + "path": "img_4885.jpg", + "sha256": "e9d92b029b7546bca86f2dbd16fc22c58d5604792d2375b04d5e01d8436f1bab" + }, + { + "kind": "file", + "path": "img_1725.jpg", + "sha256": "9797e7a0988a6bbb107c848c892b85d19444eb3ee12b791e52af9b08768bc6d2" + }, + { + "kind": "file", + "path": "img_1043.jpg", + "sha256": "264ed34dba7517b2fb68534a09d160091c4179b2ecccae97c9dea641ef4dc762" + }, + { + "kind": "file", + "path": "img_3654.jpg", + "sha256": "94d84890ea48d8dadb587a4f16f48f3e71fa24d9af70ffb730b4e3362a4e80ab" + }, + { + "kind": "file", + "path": "img_538.jpg", + "sha256": "5014e658d5724207b16ef28f37c10d18b04b3cff989395c347f45e2ad1e26d98" + }, + { + "kind": "file", + "path": "img_510.jpg", + "sha256": "99ab442928f1140dd02d589afda91af8804a533da50d6862e0860b576239dbdf" + }, + { + "kind": "file", + "path": "img_4488.jpg", + "sha256": "0e50e3a1688913c6e6dc4eb6d514de55adb2e89fd5f6b9c0723aea06ce00ceba" + }, + { + "kind": "file", + "path": "img_276.jpg", + "sha256": "8021f82eefc61da3a91d96ab3b3cb65bcc50bb163583221d5ae1eef7839641be" + }, + { + "kind": "file", + "path": "img_3481.jpg", + "sha256": "1741116b66308cb39f502619000144848090333151b33e9cd0769814e5b0793d" + }, + { + "kind": "file", + "path": "img_1296.jpg", + "sha256": "eb8b5d8c6dc1fdb91189752a439a65e12654149fc187ef0e59d8753939ada2fc" + }, + { + "kind": "file", + "path": "img_1282.jpg", + "sha256": "19deb04a94980152262c4ce67bec6592c9bd917348900f6f3823ab6e7c5a252b" + }, + { + "kind": "file", + "path": "img_2.jpg", + "sha256": "ce364fcc28f23e387862c94d4c515e954e94048c4a18cdbba28084800a6cb3c2" + }, + { + "kind": "file", + "path": "img_2953.jpg", + "sha256": "8e1ec52bb6773dd37fa34b864a834d716fa6e1ab558a68e455045853a01c5a2c" + }, + { + "kind": "file", + "path": "img_262.jpg", + "sha256": "321e99a06eb36debcd58df10768ce3a4122dc4927c8f5f4b296de5e0ffd60b07" + }, + { + "kind": "file", + "path": "img_3495.jpg", + "sha256": "97b2fe4b2b41e7539a0969c488ff00404d01283549d5df4e02198f99af697362" + }, + { + "kind": "file", + "path": "img_504.jpg", + "sha256": "c1ffc93c7a5968357fff1a0cd7bd7c0c0eca3536726adab3e6586eac64109570" + }, + { + "kind": "file", + "path": "img_2006.jpg", + "sha256": "5135d0167661b1e5a11eeae6a99d9f5bc463ca6f2d59fe33432a62cf6797c95f" + }, + { + "kind": "file", + "path": "img_3318.jpg", + "sha256": "6576ae2157e534b90cbe73e8157f032a63c543c0d5309807fee4a8c6fabf6ac4" + }, + { + "kind": "file", + "path": "img_4477.jpg", + "sha256": "e8665e8daab95f4acac9c5b8d895f0307ce6e926c975466adaab7f9d467a9d96" + }, + { + "kind": "file", + "path": "img_4311.jpg", + "sha256": "2b7da090a9b5e9a8cdc3cb378d29e2f27afe54917480d355fb95770a8847756c" + }, + { + "kind": "file", + "path": "img_289.jpg", + "sha256": "89e9634d5756c923377403e84a32476804fdecd04a20c4c9888511a7fd78f8db" + }, + { + "kind": "file", + "path": "img_1269.jpg", + "sha256": "70b91fe6432daef5077cbe40d7ddb6a5aadbd61d22dea247f5df24cb7f841e94" + }, + { + "kind": "file", + "path": "img_4305.jpg", + "sha256": "1d2b46ede0ff0c62722da78aece23e830ae151e77326223fc0b97e4f098db118" + }, + { + "kind": "file", + "path": "img_2012.jpg", + "sha256": "291f8f29afbe308fda17ede9c4d1a87e8500fc06eb6b1b566b26e8d71e2d732c" + }, + { + "kind": "file", + "path": "img_4463.jpg", + "sha256": "6f4166102d807393b5b07c1ee289f8e5bfe77f1756b0c66811d6f35b55eaa3ef" + }, + { + "kind": "file", + "path": "img_3324.jpg", + "sha256": "4d474aab5a58d92a0dab5c1dd8ef4be61ed3524cce838d753c9b4f44ab179770" + }, + { + "kind": "file", + "path": "img_2984.jpg", + "sha256": "07ee53d8b7ee228a00b5b6d8788d2a67f122b6be46f97d6979cf0ee1233a1f28" + }, + { + "kind": "file", + "path": "img_3442.jpg", + "sha256": "d873a3da127a83246da4d64bad0ede66a3b17ae1493b4611328f53942b2a776f" + }, + { + "kind": "file", + "path": "img_4339.jpg", + "sha256": "37191bf58e28b8d987d6882b7ef28f5465825ed22d844bd3cd9309b688c617c0" + }, + { + "kind": "file", + "path": "img_2990.jpg", + "sha256": "220df9094e2b461aa38e175ede1250a7bd827de4866c02f05246095784d80256" + }, + { + "kind": "file", + "path": "img_3456.jpg", + "sha256": "6534aff8353fd1a929e5aab2f8c3b2908db2742527b1c3343da54fa58e058a6e" + }, + { + "kind": "file", + "path": "img_1241.jpg", + "sha256": "141c24900bc06bbc3544b4f55cb69fcb7e735cc42edb46e5f6f5ab4acc0c2676" + }, + { + "kind": "file", + "path": "img_1527.jpg", + "sha256": "d8a0a344a5b2448983940e50172310e8ba571c8bf8b8d2e51f632aecf4db5cb3" + }, + { + "kind": "file", + "path": "img_3330.jpg", + "sha256": "4cd72aef6e1ee7e144399f9895e04a3d9f77c237c7957c0fbe54a2adddf707d6" + }, + { + "kind": "file", + "path": "img_1240.jpg", + "sha256": "f8654818553fa9213b3ec212b88a0a0e7c5d406ee6730eff8a5d0ddb6e1b8619" + }, + { + "kind": "file", + "path": "img_2749.jpg", + "sha256": "eff2a517f19c36552a13d6b616441be04a4ab2cfdf3f14a8db359b7b2da57884" + }, + { + "kind": "file", + "path": "img_3457.jpg", + "sha256": "7a50214295353dbd0623d4f552520b332ab6ed21a4996add462e2824abeb088f" + }, + { + "kind": "file", + "path": "img_2991.jpg", + "sha256": "e4b34eb175667926546236bcd5dc2b520e9b58cb8a4e5b975438bc5dc74cf6f3" + }, + { + "kind": "file", + "path": "img_4338.jpg", + "sha256": "754a403a4bc1f17136584f18f16c0c598d0ede684294292757d28a45abe9cbbd" + }, + { + "kind": "file", + "path": "img_3331.jpg", + "sha256": "eb52fc84db47cc91b2e4250fc28f4eb4d7bd10bfd7d7ba8f6bb9f8c2e647a1e3" + }, + { + "kind": "file", + "path": "img_1526.jpg", + "sha256": "810c8d01d39fc4728aab6ece8cb8e2083c65faec8564965caff020723d45d0e5" + }, + { + "kind": "file", + "path": "img_1532.jpg", + "sha256": "4b2bcf74cdc0833014ed072d1381807090f775b18407783573c21acf35d10869" + }, + { + "kind": "file", + "path": "img_1254.jpg", + "sha256": "833528cf37663d7fa9ea6d38c2a829f74edf88da60d0d192845610b7f026a4ec" + }, + { + "kind": "file", + "path": "img_2775.jpg", + "sha256": "e93c42737e84cca0e4a246a59853fc5529e8713a484f024a376b97543aa9025a" + }, + { + "kind": "file", + "path": "img_4304.jpg", + "sha256": "c610352da5e4c4804dcf3edadf64dc7cc95f13c6d2a925aa2f3b17526406b07e" + }, + { + "kind": "file", + "path": "img_4462.jpg", + "sha256": "a65a7411d79a27117b6f288955b746f2a0d33b2ad518a8c54b294282dc435bf2" + }, + { + "kind": "file", + "path": "img_2013.jpg", + "sha256": "96ddc123adcd4f8cf5dbc819324384736c005b5f8f7d6f280f4bdbf47635e8ac" + }, + { + "kind": "file", + "path": "img_4476.jpg", + "sha256": "e3f35393a2074d8163fcf66f8b57f5a6547708329f2f4937b898be23ba8ecaf0" + }, + { + "kind": "file", + "path": "img_2007.jpg", + "sha256": "11df3d76f5adbf83b4d8ca5eead7d007ab57a1c6478a438cc07beccf1480e1cc" + }, + { + "kind": "file", + "path": "img_2761.jpg", + "sha256": "857cc87e02beaf0d473de99d6a25f4a81ce051c6d256b90319c3ff17c6316564" + }, + { + "kind": "file", + "path": "img_288.jpg", + "sha256": "34613a89801b9d6ed3b2eedb42a8a5c018ef64aaf3a32e735a72c454d4ccb97a" + }, + { + "kind": "file", + "path": "img_4310.jpg", + "sha256": "06331663623464dc94eab02a0b6b1bbd2ca6ad84413a61d2c2ebf535ead1df1a" + }, + { + "kind": "file", + "path": "img_3494.jpg", + "sha256": "83574748647509154eb1466923e23e1c918fcdbae428304a4861deb5c48b664a" + }, + { + "kind": "file", + "path": "img_263.jpg", + "sha256": "8f8ba747c89f0b5741b07bff7edd28ec7ab28eeb7f6d6c9c25914959646b53a8" + }, + { + "kind": "file", + "path": "img_3.jpg", + "sha256": "5376b428a34f988a9516212a95721ed44d78c970e129a15eb219a5e4539078ab" + }, + { + "kind": "file", + "path": "img_1283.jpg", + "sha256": "cdf4113a2ef29da6e2878c09e07e9f02cd02ef510749b79dcf450724fb1c0e47" + }, + { + "kind": "file", + "path": "img_505.jpg", + "sha256": "213509f275084121cfaab15c3665c95883881814f72553043074364d889eca1f" + }, + { + "kind": "file", + "path": "img_4489.jpg", + "sha256": "a719494e1a58d48e85ea26c5cf742402a4fe2512d4412d664cf59e1f4be4715d" + }, + { + "kind": "file", + "path": "img_1297.jpg", + "sha256": "057e2d52bcaa3765799eb81bf8468165c0e478a7a958448773bad1dfa322b504" + }, + { + "kind": "file", + "path": "img_3480.jpg", + "sha256": "78ed65a17e7332b4dd3522a7b24994fcb66e84d2b29df99e4fbf3d8078b5de4b" + }, + { + "kind": "file", + "path": "img_277.jpg", + "sha256": "2a4e50b1db9b911febeb1db349d20ac1721bba2a791e26906d478059820737c2" + }, + { + "kind": "file", + "path": "img_2946.jpg", + "sha256": "45769c469a86b56fd96b12a9b1b065ade6bbcbe9f3728b02f3ed0ad3331ce029" + }, + { + "kind": "file", + "path": "img_539.jpg", + "sha256": "1d10c0ab2c5c762c000134cf59cffae68e278a33173347c5a5c19ff23dd0c517" + }, + { + "kind": "file", + "path": "img_1724.jpg", + "sha256": "8929e9d6dc3e9d7fb88408296e653d268b38f4902704d138949116bd765f6eb3" + }, + { + "kind": "file", + "path": "img_3133.jpg", + "sha256": "785150c945a30199db1a0bb842e693dd00d3446c64515d7bde9be72ce70283ab" + }, + { + "kind": "file", + "path": "img_1042.jpg", + "sha256": "ddab9a66291fe3ee908b1af9ad1081cd5fc8212f2e8690faf3e755f8d0fea2ea" + }, + { + "kind": "file", + "path": "img_1056.jpg", + "sha256": "0133cafa849604891fb325df7a64259dc4abd93106fe47316ce6e22a20edf96f" + }, + { + "kind": "file", + "path": "img_2239.jpg", + "sha256": "f42bb8fbe9e4513320b655822fee53c8c65f322b3d20de083f96439c0817c415" + }, + { + "kind": "file", + "path": "img_3127.jpg", + "sha256": "834d5451ced9b322b28d8040e68a1afb984b5783344b4188a6c60a497a96e67b" + }, + { + "kind": "file", + "path": "img_4648.jpg", + "sha256": "008f8f3a6d991ea7a2f2699801f73bbf97d56edcd2dbf3a9cfcaecbf9094ccd3" + }, + { + "kind": "file", + "path": "img_920.jpg", + "sha256": "f94e1f2d7d04dc130bac90d9abb912c78980d83abcd3c7d0d863d2d973c2b958" + }, + { + "kind": "file", + "path": "img_2211.jpg", + "sha256": "43bcb213c01f7ebbd8abb91e81dd4f313bed8e14dbec362993380b4d6a8c4658" + }, + { + "kind": "file", + "path": "img_4660.jpg", + "sha256": "1b41ecd7ae9e76931016367ad22e9fc0207c50dcc908f6caab646d60b1112bdb" + }, + { + "kind": "file", + "path": "img_4106.jpg", + "sha256": "e86f8e37e785225f68bc32794b6b8239e6399a924e6d38cae5bf7ecdbad4d448" + }, + { + "kind": "file", + "path": "img_2577.jpg", + "sha256": "7c8f6f47493f629a9e9394af1935e8d6a08b47858ee64dee3b87108f1af44868" + }, + { + "kind": "file", + "path": "img_2563.jpg", + "sha256": "3715ee2b347e068181e15c1a171a9d2b37da428f6ab1d0f364cb5af4d981ab62" + }, + { + "kind": "file", + "path": "img_934.jpg", + "sha256": "51f503d19b4d67933cc82f45df156a5cb1398210d29f0b986dd326895e4101fa" + }, + { + "kind": "file", + "path": "img_1081.jpg", + "sha256": "0f93548c9aeb8a1d32b87d6e6822bfb318cbc70b54cb94d88e08fb40d78938b5" + }, + { + "kind": "file", + "path": "img_2588.jpg", + "sha256": "70b95d66ea603c836652138d585516bef2f6a8ca4b0d676aaed4029ba8e78d28" + }, + { + "kind": "file", + "path": "img_3696.jpg", + "sha256": "fce4b3aaa5de180c647617b2b2c693beec56679b74b263bc1ec39a8950674c91" + }, + { + "kind": "file", + "path": "img_3682.jpg", + "sha256": "145759e576ab5e69bcd30ddeb823ea6b17cd5043c811bf6e13e38f76976c4f20" + }, + { + "kind": "file", + "path": "img_1095.jpg", + "sha256": "41487ac64a4c639072d662be51b6122bc58497c052a1291bc1a3c4ddd203e39e" + }, + { + "kind": "file", + "path": "img_713.jpg", + "sha256": "a2ba01f9d6e9facc391ea6ee791844a2d30a39cdec8a8f1e5fe74f93c21a8dc8" + }, + { + "kind": "file", + "path": "img_4853.jpg", + "sha256": "c2e2d2fa91a515e07445cdb7d0e90e2140aa3c82adb6f2ffd845990f9d4c90a0" + }, + { + "kind": "file", + "path": "img_1903.jpg", + "sha256": "0b99843a66d61aa82ad97bb8fa8e8b1910d2a51fc0f30dbdb11e233a0b3951b0" + }, + { + "kind": "file", + "path": "img_3866.jpg", + "sha256": "9b48a90b63c379b2aad68fc638dd9ac26ac80e94a817846098f6d759845bcb88" + }, + { + "kind": "file", + "path": "img_1917.jpg", + "sha256": "7ac30c6468c585f1cf30d7d9c951363b44d9e73cfe64d0a299275da05e500f3f" + }, + { + "kind": "file", + "path": "img_1650.jpg", + "sha256": "3c15200d7935cc41778cff98e31d48993b97e4e74038ffd12e06511bdd6d9296" + }, + { + "kind": "file", + "path": "img_1888.jpg", + "sha256": "5ea09d6a886a3e03b43aacd9661aaba5111d7b4fe3c0c2f7cd115d9929d7d101" + }, + { + "kind": "file", + "path": "img_2359.jpg", + "sha256": "dd1e95cbe6e5f35e014276108a67793d93824a7f989c58608c2224256e3ff04b" + }, + { + "kind": "file", + "path": "img_868.jpg", + "sha256": "e7f161cba1c5fc67b691b0efcf829f2b4a4467636c4d35fccf85fefbfa8eae0e" + }, + { + "kind": "file", + "path": "img_3721.jpg", + "sha256": "b160a83cebeadbf03326bbe79a62c1c0ecbb0b5e2533e26163d9465c69e293f7" + }, + { + "kind": "file", + "path": "img_3735.jpg", + "sha256": "df432d4456a1643abfe48e05784f63810c99864331aaaac72a1092c09aa33611" + }, + { + "kind": "file", + "path": "img_3053.jpg", + "sha256": "1179aacd0cadc0f1f180ba0929c6cb6e990bb7d4cb435dc7771aa7e4a5c65cea" + }, + { + "kind": "file", + "path": "img_1644.jpg", + "sha256": "74845a08c06b85cde58f39e94020b27a03012fa64a99c564cd9751f41d60836a" + }, + { + "kind": "file", + "path": "img_2365.jpg", + "sha256": "8dba7d81098c6758780e21efd6a2167f1960fbc5ce21d6f80c9330b6f2cdd39e" + }, + { + "kind": "file", + "path": "img_854.jpg", + "sha256": "056735193bef649accec68f07849264b8cf631c298ed459fe62694268ee8ba98" + }, + { + "kind": "file", + "path": "img_2403.jpg", + "sha256": "5223a4b1a2b55d2cade90fc863bbc2b188d33f29c550a219c41340bb252354c8" + }, + { + "kind": "file", + "path": "img_4072.jpg", + "sha256": "76dc77b7689672d2b5a7c3550cfd3e9a7c9f7e1acf2023d0aa23ef1164c758fd" + }, + { + "kind": "file", + "path": "img_2417.jpg", + "sha256": "4f84838d10b3d8f9cc86f893f3e18f6a8449e53dde7de70a398c6745c19eef31" + }, + { + "kind": "file", + "path": "img_3709.jpg", + "sha256": "846aff4dd9ed5b44d9e68172449df3c096835fb7786958e99ac7521701e1dc17" + }, + { + "kind": "file", + "path": "img_4066.jpg", + "sha256": "64cbd904e169c672845bbd5fe2530bb9f80710951a07b85aadec2776a85a38b2" + }, + { + "kind": "file", + "path": "img_1678.jpg", + "sha256": "430d5971cb0ce09c679c502eefacd0d3de6b72fbeefbad590383191113ba129b" + }, + { + "kind": "file", + "path": "img_4700.jpg", + "sha256": "4de35e475785cb9fc2303d3c89d9a051f4a76cfa8d5d216e83143ce9e7442b4a" + }, + { + "kind": "file", + "path": "img_698.jpg", + "sha256": "c52b1da9d26e6ff97fdf3a349a2f4732f504e69765a2b752cc819e4910ebc962" + }, + { + "kind": "file", + "path": "img_2371.jpg", + "sha256": "c3eee71e866eb7ebfeb92b5b06bb0900f43901eea5f4a560c97ea2d2c4598ee6" + }, + { + "kind": "file", + "path": "img_840.jpg", + "sha256": "cd62d86df0e4925a52802b92e8f98860cf52d4e9ed9a19ed9574370d5259d204" + }, + { + "kind": "file", + "path": "img_4933.jpg", + "sha256": "3bc8e3b53b7a2e4f15b0d9b347b4623197f6a8c819b2bebdf1ba57e7f3288a71" + }, + { + "kind": "file", + "path": "img_673.jpg", + "sha256": "e2137f233a0a4b1a3e3df37aa8f4cb34442d5134a5a5cc0202ec02096628194e" + }, + { + "kind": "file", + "path": "img_3084.jpg", + "sha256": "170d142eb5aadfdda2041e7192bc680397fd1ea80c4186ebac77bf15b1ceb4d9" + }, + { + "kind": "file", + "path": "img_1693.jpg", + "sha256": "c30d175aad2e580f19cecb675c7a19660f4e945b54f51ab741aaa8d01372041b" + }, + { + "kind": "file", + "path": "img_115.jpg", + "sha256": "5470f777c5bfc1a537460ca5c09692d82f0c0f06b596828f41b811b09ee8ff00" + }, + { + "kind": "file", + "path": "img_1687.jpg", + "sha256": "17655e924212364e2ee25f08091bbaa70b9eb7357b4ab1ea9c9408f64edab05a" + }, + { + "kind": "file", + "path": "img_4927.jpg", + "sha256": "fef7e20e2082773aadcc5a894f530c1998b43b36bf937de7f46052111f729c6d" + }, + { + "kind": "file", + "path": "img_667.jpg", + "sha256": "4492dbc03726689ab9e18bf95a39eb2144e96b3b9a9912a3915965d9e6871efb" + }, + { + "kind": "file", + "path": "img_3090.jpg", + "sha256": "bab8c9dc06f5443cc9053af17faf9cc4126569d04e274c5634c0dfa7890d98de" + }, + { + "kind": "file", + "path": "img_1877.jpg", + "sha256": "6b7e791bfc331a6a88430a3f41bbe7c22d5e2316a568e9dce3d1245165a6d51c" + }, + { + "kind": "file", + "path": "img_897.jpg", + "sha256": "49db6edda50cd910a8dd53c991185472ee2b14bdd8b99aaadf7a89324145b13f" + }, + { + "kind": "file", + "path": "img_129.jpg", + "sha256": "2803e8481bc264e3a56b1fd45543d2eb956f36d7607e1e0f128d8f1270669f28" + }, + { + "kind": "file", + "path": "img_3912.jpg", + "sha256": "70a22e99e532aade76adda70dedbd8c1d42503925fcc9f6d0748cf635e5e91cf" + }, + { + "kind": "file", + "path": "img_883.jpg", + "sha256": "0bab91742c7c3a2af32401c4f49cceba990d78eb70899c0d60317bdd4b2ece98" + }, + { + "kind": "file", + "path": "img_1863.jpg", + "sha256": "391a666e1dc8c169deaad8cb28f6f65d7664877154252b3a92a4800b014d240a" + }, + { + "kind": "file", + "path": "img_3523.jpg", + "sha256": "8302b036e01b1a1c93b38a67fca594581f707456d47a8c5f1f8395f47e908f49" + }, + { + "kind": "file", + "path": "img_3245.jpg", + "sha256": "a3c77a70029415f85be76388bec2d4d3291b4d6be630170d74ffcdda2fd0d50d" + }, + { + "kind": "file", + "path": "img_1452.jpg", + "sha256": "bd5255f731aea618d575f996f2dafe47c26fb59f4fb153248fb249f3b190c8d2" + }, + { + "kind": "file", + "path": "img_3251.jpg", + "sha256": "27c8a396dc19b44731c17a7b6090cbeb1e02438120a7084f927a642cb3bdbc16" + }, + { + "kind": "file", + "path": "img_4258.jpg", + "sha256": "a5d538d9717c5c3ba43afd3402ef30770f8e56dfd46c8b7455fe1ff6daf86b03" + }, + { + "kind": "file", + "path": "img_3537.jpg", + "sha256": "0bdd1ab74e752bf113f26ffd227a1964eeebc2a66641a556145e6e9f37963fb3" + }, + { + "kind": "file", + "path": "img_4270.jpg", + "sha256": "d44af8c254ecd77f8ca7992e7eb94e09bbdc21d9a865f61650a0869b1f88e7db" + }, + { + "kind": "file", + "path": "img_1308.jpg", + "sha256": "cbb2770a31ccdbfe842460e69c99045c63fb386f35ec2a195aaeded00c5e4639" + }, + { + "kind": "file", + "path": "img_12.jpg", + "sha256": "374d33ebf4bfa641553827db233f4dea63d96c40dabe572f23bc9a8d38f008c0" + }, + { + "kind": "file", + "path": "img_3279.jpg", + "sha256": "a51b7ee9dc9ea23593449529465e57988fb1bf7759692990f781977400b6adf0" + }, + { + "kind": "file", + "path": "img_2173.jpg", + "sha256": "65f2387d869a400c0dfc3e5137866a3ebc2dcaaed4447bd5ed1cee9c2d0d06a3" + }, + { + "kind": "file", + "path": "img_4502.jpg", + "sha256": "d9d5ca9cb9f53826b01105a76c0e7f39d31ef3fda0a740db929fd771437eb7f9" + }, + { + "kind": "file", + "path": "img_4264.jpg", + "sha256": "c2915ef3538c36e944922a9fd2dbca7afd9c7b95019b37c91c6787a37633d5bb" + }, + { + "kind": "file", + "path": "img_2615.jpg", + "sha256": "44ce67dc9e35ea2931f5ad652891ec7a93e55ebae67a495f5de080f1a841ebec" + }, + { + "kind": "file", + "path": "img_2826.jpg", + "sha256": "912e03f5bc2e48c5e3bc719738d890a58026a57ff1912b89f544f9f12a5b23d7" + }, + { + "kind": "file", + "path": "img_317.jpg", + "sha256": "46309f766c29e3d8895d4c2cffb42080093409bdd04c922f5425d2c408e305c0" + }, + { + "kind": "file", + "path": "img_1491.jpg", + "sha256": "6c64a21b626d3f8064cf12846b7cfbb3a375dee08c0e09da6cb17c588ce57e71" + }, + { + "kind": "file", + "path": "img_471.jpg", + "sha256": "c821758962a776a94701bdffb332bcc78093d48e2d3dc637214d7b3e5e05a302" + }, + { + "kind": "file", + "path": "img_3292.jpg", + "sha256": "7acd35cae762d81adf9b2e6e5c46617569dac92f1e246fde2818663a1171720f" + }, + { + "kind": "file", + "path": "img_465.jpg", + "sha256": "520ef94a096da000a93903b4ec29c7c44a143a7a47f9983cc50bfc2c4f92f3ca" + }, + { + "kind": "file", + "path": "img_1485.jpg", + "sha256": "fc7390a39e67f795ac04f791b27e58bbff5cc9a1126aea1cc6a9f6473fbda230" + }, + { + "kind": "file", + "path": "img_2832.jpg", + "sha256": "ca46877c00c8124885dd738154abdfc8c07dd53ca0580cab49b901103b616416" + }, + { + "kind": "file", + "path": "img_459.jpg", + "sha256": "29ed02897d567f680c8c3819080159d3aeedf38475f37ec690c7406aaa8ea21d" + }, + { + "kind": "file", + "path": "img_2836.jpg", + "sha256": "e231f3cab865a2d414ff78a48519a56f9004f26e1e4a3dbe92f3297c78e3462f" + }, + { + "kind": "file", + "path": "img_1481.jpg", + "sha256": "b4eee136de8dca5a1d50d1dcff475bc8a410e430c1356cf89aacd2a8ac07bb6d" + }, + { + "kind": "file", + "path": "img_2188.jpg", + "sha256": "662172e5025157f2bb226682831a38bda4807165278c18a04b4ae0b2501bdbb7" + }, + { + "kind": "file", + "path": "img_461.jpg", + "sha256": "9118a4ec82e9fab7965d6e3d4a45e1e76abc9f129e7d67b1759fa08e6cdfa999" + }, + { + "kind": "file", + "path": "img_475.jpg", + "sha256": "8ce085c2d4a947d525621b64ee229956130fffae9b871b961f4d236cd5d892db" + }, + { + "kind": "file", + "path": "img_3282.jpg", + "sha256": "047c67c2291cd5dd071e43d09b5ea827dd91516fc8190c27a7610b98f38b210c" + }, + { + "kind": "file", + "path": "img_1495.jpg", + "sha256": "f239294f841dc10800407bb8d466132f7b0681301ae83a04c3814e884dd1d793" + }, + { + "kind": "file", + "path": "img_313.jpg", + "sha256": "3be44f1ba16ee269a25e9db35361a748b6bc8528fe58fe2625bad9e8cdc07c3f" + }, + { + "kind": "file", + "path": "img_449.jpg", + "sha256": "2689b07563e3b9bb37a9a5224eec2c92d8fc30fdcd0cf45d263bb292f2297e36" + }, + { + "kind": "file", + "path": "img_3533.jpg", + "sha256": "2f443c01c9fb45979005810a8f2a7f8e6762191f03cddbba360e3fd4ecd27e31" + }, + { + "kind": "file", + "path": "img_3255.jpg", + "sha256": "aac462c268fa3012454109212a61fae68ab1e14f5b61489b379160670817a610" + }, + { + "kind": "file", + "path": "img_1456.jpg", + "sha256": "375af7965786fb208bc38f3618c8b8ac07e83182035e0f9c4f5cbd38b0e69165" + }, + { + "kind": "file", + "path": "img_2639.jpg", + "sha256": "7ea576130527db836e4d28e13a9b68cc5dbda5e068bd6d70eca0706b8c26dfd3" + }, + { + "kind": "file", + "path": "img_4248.jpg", + "sha256": "9de904a1b2ad76bb3c25391607cec591e843dbf1447fda408029b30280caa031" + }, + { + "kind": "file", + "path": "img_3527.jpg", + "sha256": "e73a6511f959c93a529493027abd0ded7d7716e11b04f0716cc1b0004888f63f" + }, + { + "kind": "file", + "path": "img_1330.jpg", + "sha256": "5d03744aa8b5e3eaabfebd720990ae1fe306492cb9ed12d6d0d1b536ab75e8c9" + }, + { + "kind": "file", + "path": "img_2611.jpg", + "sha256": "6ff9c71762326559d6916bf595d13bc39952b31bfd5a10f537e596ee23d93d7a" + }, + { + "kind": "file", + "path": "img_4260.jpg", + "sha256": "06d12a3e7e09703e45902fa8e518054818211c72c69f6029513ea701b417abc5" + }, + { + "kind": "file", + "path": "img_1318.jpg", + "sha256": "5ae6cfacd9fd57d50ed6c4834f26b440cbbdc5311c5d30e040a5adeff20ae7ef" + }, + { + "kind": "file", + "path": "img_3269.jpg", + "sha256": "9ef825b7963ba23ecdb2fc59483dc5a115fe14c9b62b39b80b423999c51438a4" + }, + { + "kind": "file", + "path": "img_4506.jpg", + "sha256": "0f75690f22740c334d0769e25a4296b15cde150ef48a7715a2b35b4e7f311115" + }, + { + "kind": "file", + "path": "img_2177.jpg", + "sha256": "183bcb9f174ea5f699ead64fc306fd1062a65f809cb6b6526fb7d6b591a70b54" + }, + { + "kind": "file", + "path": "img_4512.jpg", + "sha256": "7e917f4903ba939f86f18d757397ad1614a15a73209a88574a007e34ba5cc8b3" + }, + { + "kind": "file", + "path": "img_16.jpg", + "sha256": "4c621ea232203baf3855e1ecef9adc1e82a5f46aa67792f78478023ad6a2eba7" + }, + { + "kind": "file", + "path": "img_2163.jpg", + "sha256": "52ef78775ade15533d0f4dc969e08a3c0a0e4f7f82ac04be82484222962a0032" + }, + { + "kind": "file", + "path": "img_2605.jpg", + "sha256": "91103750577ed6a34178cd707ab442978b11667dbef48b0af82119b9f25086e5" + }, + { + "kind": "file", + "path": "img_4274.jpg", + "sha256": "375c8ed900273beab45dcf00b1a5eeb57c06f6227df5942f865e7530cad2b848" + }, + { + "kind": "file", + "path": "img_3094.jpg", + "sha256": "4de0d1fc2f1a1a0ef62a25454efa911b99afa75c42a028477e9f7714518daa17" + }, + { + "kind": "file", + "path": "img_663.jpg", + "sha256": "f4fdd717f0769788dc63b5b20bd2801221794f58fd1d5c458f59088288c7bfb4" + }, + { + "kind": "file", + "path": "img_4923.jpg", + "sha256": "6fcd0a1d38a772ea4754f6e6a8c93f91307f65195d6127073feb99c457c63c69" + }, + { + "kind": "file", + "path": "img_1683.jpg", + "sha256": "a8a4974ee637d34adecc6fb92f564e3193697ad10d306bd998b9d98b6a4f7403" + }, + { + "kind": "file", + "path": "img_105.jpg", + "sha256": "7bf7681bc14e71f65ee0569b6982bd70aa2716c594b918d1b8dc5b3cafc6814c" + }, + { + "kind": "file", + "path": "img_111.jpg", + "sha256": "46e2abbd8e930c871318858c40bb1496adaa6d1ab3fff5e9cc6db6bd828d605d" + }, + { + "kind": "file", + "path": "img_4089.jpg", + "sha256": "83bde88553d52bf5c1dd730569dced772310fadcdaa484c9bb622ab7ac6723c3" + }, + { + "kind": "file", + "path": "img_1697.jpg", + "sha256": "3172b4d0ca9da5c86f5de1afcbac2d2455fb0883a131015fe41359a82f39ad7e" + }, + { + "kind": "file", + "path": "img_3080.jpg", + "sha256": "551c0d3f1c748cbc8bedf0e3495cbfbb4b353a4cd302873fee9bfdfb42e8c182" + }, + { + "kind": "file", + "path": "img_677.jpg", + "sha256": "ddab0c2be3adb0a011079802f17eb85f10615eff2c88576f1d50531238122867" + }, + { + "kind": "file", + "path": "img_4937.jpg", + "sha256": "b999460a3821dd281384df4c404bd6b82a992058b1f87e3435fc38d5a97ab641" + }, + { + "kind": "file", + "path": "img_1867.jpg", + "sha256": "a60cef2924d2eb28ef3aab6cd9ec3a019cf5a6be32a6283d0e7584c56dc8b963" + }, + { + "kind": "file", + "path": "img_887.jpg", + "sha256": "1004be0e26e6fd65020a60a350a991f4ea7d600c9e207a8be5e82177a4174033" + }, + { + "kind": "file", + "path": "img_3916.jpg", + "sha256": "ab9918cf30193ee4c8398eafcb7d76ef74f4ca8728558960040c3b74ddb8cde4" + }, + { + "kind": "file", + "path": "img_139.jpg", + "sha256": "5a314c1e5c0f3c219807004069c3c682fb05eea7524d174b82d7b0948d220ff3" + }, + { + "kind": "file", + "path": "img_3902.jpg", + "sha256": "85d6daf24eae12d8102f5cb00828241757ba6a984872394974bc0155e1b0977c" + }, + { + "kind": "file", + "path": "img_1873.jpg", + "sha256": "480068f28c518bc1e2c4c187450d3376817787c2b96aa96b785fa5c95525744a" + }, + { + "kind": "file", + "path": "img_1898.jpg", + "sha256": "d4c02b1f5cd6e837f7073b06393987cb98238b0e095742b80ffb3bd0675f3bd1" + }, + { + "kind": "file", + "path": "img_1640.jpg", + "sha256": "70ad36bb0d1f358e0ca9de292d8498945d7057d33cf5882983b85666e4a0f463" + }, + { + "kind": "file", + "path": "img_2349.jpg", + "sha256": "d54ac1eb6adbb43aa9c646ab6f90ce4f6c65c9df515ede9e229c7b001fef31b4" + }, + { + "kind": "file", + "path": "img_878.jpg", + "sha256": "321f7db3dc75fa42c2acf478598050d24ed2f36f1b2fb902a02cdee044edd2ba" + }, + { + "kind": "file", + "path": "img_4738.jpg", + "sha256": "77e8380487a64f96c344d2b6d42cf17c082181b4c0f8afa58325486965e4729e" + }, + { + "kind": "file", + "path": "img_3057.jpg", + "sha256": "9d2f571092847df37c353d7687f0bdf3b63bdbbf31b04e58aac4766db8e7859f" + }, + { + "kind": "file", + "path": "img_3731.jpg", + "sha256": "86b8cb08547a7019d32c6349c334d0a9d893e3470ca6ed31a7d3897046e7c464" + }, + { + "kind": "file", + "path": "img_1126.jpg", + "sha256": "d644b67ca0212d3ccb373a1b6045ffcb0c9ff796ad238e2b72cc234c697f1f24" + }, + { + "kind": "file", + "path": "img_1132.jpg", + "sha256": "d5817becf264ddc3e7bafc23eca053e4c7798b5ad73cf4423671530a2d4de338" + }, + { + "kind": "file", + "path": "img_3725.jpg", + "sha256": "6f6cdadecdd0a5d1f5b53ae29c1675e0eed6b1271c17f3e396c5236f9ddefc59" + }, + { + "kind": "file", + "path": "img_1654.jpg", + "sha256": "9eee731e6bd86b0928ad64d000c8329521566a876ea048192ed2a76215921a8f" + }, + { + "kind": "file", + "path": "img_2375.jpg", + "sha256": "b9faf9b16376515a53464b79be16f0e31ae8387c2aa1ba278640759fa29c9131" + }, + { + "kind": "file", + "path": "img_844.jpg", + "sha256": "b1e0711d500077b96ea5682c7bb3076c79f1a004c1c27ecdb8180d84d8e6fbc3" + }, + { + "kind": "file", + "path": "img_4062.jpg", + "sha256": "9e45a6c5601e00f0c50b26260d0d410fccfc8f7e5d8e85f6980464f4145559de" + }, + { + "kind": "file", + "path": "img_3719.jpg", + "sha256": "2f2b6c463a7dc29afd0016c6643ac962a22cfe65dbdabc0966738fd9ec7789f2" + }, + { + "kind": "file", + "path": "img_2407.jpg", + "sha256": "c482e17746b7170eee9b891b66722dc3361f6bbcd221b08f53410c72bf6a54aa" + }, + { + "kind": "file", + "path": "img_1668.jpg", + "sha256": "716b4928ba3676100134eae6c4fc00c612863e44787f0349c23dcee2a98f7a98" + }, + { + "kind": "file", + "path": "img_2361.jpg", + "sha256": "21b9141004cb6c5c3838562110e0f92822b5b73e332d1a52d0836ebd1da70c4a" + }, + { + "kind": "file", + "path": "img_850.jpg", + "sha256": "72bf383332836eb9b797d6e40e1ab9e04ce8d65f8e221c12ea2488a64a47bb96" + }, + { + "kind": "file", + "path": "img_4710.jpg", + "sha256": "a4bbc0925a22d362f6d3f99053bd9bcbeafbfa359c9fd0c7dad8ffe2d9b694ef" + }, + { + "kind": "file", + "path": "img_688.jpg", + "sha256": "63102a714cc1d4562c7f7fbe190a5da2eff2eaf4e59522949eb9a50bb26f7210" + }, + { + "kind": "file", + "path": "img_4857.jpg", + "sha256": "de5a2d8c3a172fff18fcd35d76fc51d52297239685a41133bf0f647c15ef5397" + }, + { + "kind": "file", + "path": "img_717.jpg", + "sha256": "eb5ccd5035fef095b2054755e4a29b95a83195f0cdb38afc854e27d4d23d7d1c" + }, + { + "kind": "file", + "path": "img_1091.jpg", + "sha256": "b684d59896f21dc899e0c1ab70016d38c19c8ced4f9c596bfd9ddf20dfdb3e43" + }, + { + "kind": "file", + "path": "img_3686.jpg", + "sha256": "9635a5ad34ba5d13f6a386088049eadc77ea5267b6ace0aa1ba5cb77068fe07f" + }, + { + "kind": "file", + "path": "img_2598.jpg", + "sha256": "06df7d77989eb72c1b52fb4da3050b841288388c5cfc36ef2523081bb134161c" + }, + { + "kind": "file", + "path": "img_3692.jpg", + "sha256": "331baa214760ac6972fa691553e0c9ab971e22bd0219e088a5916c1c9d2f1aaf" + }, + { + "kind": "file", + "path": "img_1085.jpg", + "sha256": "8c2a0b1dd4df353ebfbad4ccfd3adc06a847d20b05be6e8a5cb80353e225f0e3" + }, + { + "kind": "file", + "path": "img_4843.jpg", + "sha256": "a14c9cf19a512bb84f2ead64f064b03a6fa6ec5dd0ce0ccadfa07e8685a30783" + }, + { + "kind": "file", + "path": "img_703.jpg", + "sha256": "d78271310e3a716ab2e3907bfdf68d64f986c34c106530c057e866a6839540b5" + }, + { + "kind": "file", + "path": "img_1913.jpg", + "sha256": "bfd1ffbe421406ac688aba130b145a86fc6b132f9cc2eb8b4164c37edb99924d" + }, + { + "kind": "file", + "path": "img_3862.jpg", + "sha256": "fb7898a7c4fd4f8796e44334307c0f47da140625a25a482fce750f7116b7cbd2" + }, + { + "kind": "file", + "path": "img_3876.jpg", + "sha256": "513b29ea5703779db0d15feff3cb55f162535fcac286a0d3d4492e9b6e3ef376" + }, + { + "kind": "file", + "path": "img_3123.jpg", + "sha256": "8f157c2b4a31c2744bd4d10bbd88f37456afa8634f404f4d8b35f8cea7f6af59" + }, + { + "kind": "file", + "path": "img_4894.jpg", + "sha256": "fbd5154fcd56c182e8b9cc73d3e348ba9f3de07259cb44a47c7ff0584751194d" + }, + { + "kind": "file", + "path": "img_3645.jpg", + "sha256": "ffd248db273cbd759e452470e9e1fe61ef87c07ffd5936917261ab8fe7696feb" + }, + { + "kind": "file", + "path": "img_1046.jpg", + "sha256": "f30aab3415a4ac291bf4fd2fd0dbe2dbd7865190fc27b4d8b94a857c5915e581" + }, + { + "kind": "file", + "path": "img_3889.jpg", + "sha256": "2629a27b67594c195ba97f3bb8a4d456f6ec2a7927c45e03497741f1212a280f" + }, + { + "kind": "file", + "path": "img_3137.jpg", + "sha256": "7ed39ea17eb4d5d44bf74250461d5d13b82075aa862f11e7871f1170a661500f" + }, + { + "kind": "file", + "path": "img_4658.jpg", + "sha256": "3b97984d0d1bb69e775b1a1085a8bc6ddc04cb05bbd09ee337cf9e0930103054" + }, + { + "kind": "file", + "path": "img_918.jpg", + "sha256": "e2e7b8ccc5af4c10a9e6abb6b0b80805832af2277f9316fee6172376ae3fb24d" + }, + { + "kind": "file", + "path": "img_2229.jpg", + "sha256": "1b30e786e4491cd50bc345d4122f2edbbdea3062a91f29f6913a04f75ed666a4" + }, + { + "kind": "file", + "path": "img_1720.jpg", + "sha256": "b40ad0a2e882225b53ab7e25671c053e0976edc0b15d4d739a07fc8741bff551" + }, + { + "kind": "file", + "path": "img_4670.jpg", + "sha256": "57c21ca3807a0a81a95d2ef395dfe6f494f9f0b3885da8717ef394045381967a" + }, + { + "kind": "file", + "path": "img_930.jpg", + "sha256": "92d5e2035eee379d0bfa108907a06294495dede74a6dd5ee4daf4014e9d1e25c" + }, + { + "kind": "file", + "path": "img_2201.jpg", + "sha256": "84d6890441e069fef9a5771203a1690748474ad0d93df60a946cb00f18a28a8e" + }, + { + "kind": "file", + "path": "img_1708.jpg", + "sha256": "fe39bc54eaf98bc26b47ef2a0e5fd812bb2a58166989efeef6d1696a52ced164" + }, + { + "kind": "file", + "path": "img_2573.jpg", + "sha256": "c9c674c29f876e080786b53808d61585b31f8db8191d302bc11454720f126cec" + }, + { + "kind": "file", + "path": "img_4664.jpg", + "sha256": "5f3a2833abe3776a314991273e5d1e7f5b061feb5b2a68fc446ea6f1a008d2fd" + }, + { + "kind": "file", + "path": "img_924.jpg", + "sha256": "1fbf1c7f57551a262c3ce1b0944a23ece171def7e90f397fe642467f33fa61c0" + }, + { + "kind": "file", + "path": "img_2215.jpg", + "sha256": "74138d01640821dc232b22aaf2e18c74ac5ccb23368ae8fb5784649241d633f8" + }, + { + "kind": "file", + "path": "img_273.jpg", + "sha256": "a2381880111a2ebe0db1535f4e18b60da303cff98e8f7bad97b4497f750dbbaf" + }, + { + "kind": "file", + "path": "img_3484.jpg", + "sha256": "761ca647fc472aa247d6fd0444a3d9dfef022bee2b3be2d462c2a2f2d2fd6de7" + }, + { + "kind": "file", + "path": "img_2942.jpg", + "sha256": "14c7713ce08881800fa3786dabc53a56e1fb319d10fb4ba36384ddce56587c35" + }, + { + "kind": "file", + "path": "img_1293.jpg", + "sha256": "082d46f57b3060b2cf2ebaa5c6d42e2d359446f3521bae9c80c79820078a0560" + }, + { + "kind": "file", + "path": "img_515.jpg", + "sha256": "fe3b0e557bd44ceaf15405989fdb8e18f78e871a2a27a3f74f81b89842c5a995" + }, + { + "kind": "file", + "path": "img_4499.jpg", + "sha256": "2099a6da47b276ab2516f74849895055dc65054041b05afd443602ee6397464b" + }, + { + "kind": "file", + "path": "img_501.jpg", + "sha256": "d789228456c1ce03e5298cafdf510a3b40c4806bf25f89017955cb28ba21153e" + }, + { + "kind": "file", + "path": "img_1287.jpg", + "sha256": "1c8cecfafa143ad8931cd28086dbee72c346aa6657d9e3763cb9b6622f6d4d15" + }, + { + "kind": "file", + "path": "img_7.jpg", + "sha256": "277c5a5f48a15da859693f5d014295f40fe4e3750c259028d7a74db9cfc03f0f" + }, + { + "kind": "file", + "path": "img_267.jpg", + "sha256": "78decee8b978e616b24d67fb4654efca5ba7c30b228072dea044a736ec196e40" + }, + { + "kind": "file", + "path": "img_3490.jpg", + "sha256": "67f63bccd0e3a951ffa318bd2bfc22ce73ac15832e948a39e80e92835b65f1cb" + }, + { + "kind": "file", + "path": "img_2956.jpg", + "sha256": "5f37e84098219f01f5918bddaab00f073ad9fdea0f8eee924822966770bfe925" + }, + { + "kind": "file", + "path": "img_529.jpg", + "sha256": "64385744fa6fccd5031c94f6d018d34095ec63f515fd096e41677d3b537f2101" + }, + { + "kind": "file", + "path": "img_1250.jpg", + "sha256": "6b8a2c454c53e81a4484eba729de3cb579a20abbfbbb9292f11335af9df5904f" + }, + { + "kind": "file", + "path": "img_3447.jpg", + "sha256": "5e8d8810c26358e153ccdec8833b680e1577f78ac8c806bb687ff9c1a0198d7d" + }, + { + "kind": "file", + "path": "img_4328.jpg", + "sha256": "7f43df585797a132b8cc250ffe5af073ad66dce631a4f0c061210c5cbb792d79" + }, + { + "kind": "file", + "path": "img_2981.jpg", + "sha256": "6b80ca1ef5cf0c202416c9894bec19a79cad4f9d0869c1c615733ce5d5aa3ede" + }, + { + "kind": "file", + "path": "img_2759.jpg", + "sha256": "ccec7fa778a8b575f47bcb66073e80f5b624686a72983c6c1b7ebd3f31170e0b" + }, + { + "kind": "file", + "path": "img_3321.jpg", + "sha256": "b38b6a2adaa3b7dfa5e1ce6156d1e2324b6348dc6c81be6e938d0e4b68a3cde7" + }, + { + "kind": "file", + "path": "img_1522.jpg", + "sha256": "8f63e14db83bc1d516b20051aa53214c36fc157663ec4d3cf112780406dfa7c0" + }, + { + "kind": "file", + "path": "img_3335.jpg", + "sha256": "09f923de73190ace4635656114151d0e4c28fb12fc35bda880758e8df87f3a91" + }, + { + "kind": "file", + "path": "img_3453.jpg", + "sha256": "3c5200eaf9c2632655b2425939256aa261005ba8acebbb0f752738f974fbafad" + }, + { + "kind": "file", + "path": "img_2995.jpg", + "sha256": "88f3be64968b85fbf07204006da21904a8acb72658f16eea2e3220ff09399735" + }, + { + "kind": "file", + "path": "img_4314.jpg", + "sha256": "d1bcf3edec008a5610c8cf60908728ced6f847cde317d4694b5f87302f58893c" + }, + { + "kind": "file", + "path": "img_2765.jpg", + "sha256": "729325b7b7b1d26c7e0de9971357d7b1ea7429a6d13e940ee70aad3c42054ab1" + }, + { + "kind": "file", + "path": "img_2003.jpg", + "sha256": "05be7fdbb124a4265e020c105e0df1a9673522829020694ecbc36c6f5259e0d5" + }, + { + "kind": "file", + "path": "img_4472.jpg", + "sha256": "b97f8746ca6181b5f6c0bf455b0ecbfaf96d14ec79269be22e0eca5089621eab" + }, + { + "kind": "file", + "path": "img_4466.jpg", + "sha256": "8bfe94189d680fe8dfb1e1d2a087af82b0dfd7009c905504d0d2655198c762af" + }, + { + "kind": "file", + "path": "img_3309.jpg", + "sha256": "d0174ae263a6a159f3106bd621722625a252f8673bbda9459958aab6342edb18" + }, + { + "kind": "file", + "path": "img_298.jpg", + "sha256": "5624ce92124eeb1d074482579e7c89515203b9eee77a73378c85e1afff3ce029" + }, + { + "kind": "file", + "path": "img_4300.jpg", + "sha256": "11bb523fd56e84ee53d029ad146facfa58d1c3e0490d80917168c5070fc54ebf" + }, + { + "kind": "file", + "path": "img_2771.jpg", + "sha256": "1d7cf238f3955cc3b1bef9f4bbedbb7833e5fc6cb7c9d9835db467635cfb28ca" + }, + { + "kind": "file", + "path": "img_3308.jpg", + "sha256": "3811292b460307fb963f014815326a321c55946f1e5990c91eebdb3d4d73196a" + }, + { + "kind": "file", + "path": "img_4467.jpg", + "sha256": "6eae13eca4167bcedb1f16f78152d656a4d3f863ceb1ec460e2c8ce4f90b4312" + }, + { + "kind": "file", + "path": "img_2016.jpg", + "sha256": "c37371932bebb27cd57313f66fda33c2c0fb16dc870f8d0ae5a089eda52c2a61" + }, + { + "kind": "file", + "path": "img_2770.jpg", + "sha256": "8758cca57dc5e24735b457b68dec35237c222f3d382b8053dfa070ec6370a928" + }, + { + "kind": "file", + "path": "img_4301.jpg", + "sha256": "e39ac7cc2e45d8c7d3f5ee824e2060ef496118a1ab332a450504b9ccd0caf8a7" + }, + { + "kind": "file", + "path": "img_299.jpg", + "sha256": "cca3376d8075e937092af645c409d013316a63cbabba0c51a5538e1cb143d192" + }, + { + "kind": "file", + "path": "img_1279.jpg", + "sha256": "014122c98d84466386f3e85aae840c41c201cd1bec9306cec001823776716d63" + }, + { + "kind": "file", + "path": "img_2764.jpg", + "sha256": "6c9bf314aee076acaf7af759b21edca9facd0f40bc1b99df83f71b3d3b9b4163" + }, + { + "kind": "file", + "path": "img_4315.jpg", + "sha256": "08e738d0eca93ecb33451cb4eacbe97c0ca9c53da7b370af4d8c1983f31f8030" + }, + { + "kind": "file", + "path": "img_2002.jpg", + "sha256": "360553a8d462c67340fbced6b7c800b446e6e0a7ef51cd84433b50469839ea39" + }, + { + "kind": "file", + "path": "img_3334.jpg", + "sha256": "2ff90c3bcbc996ab7cb48b8d3ff7dd08a900c4ea75ea9db6f2482c0aa566b568" + }, + { + "kind": "file", + "path": "img_1523.jpg", + "sha256": "b5b7efe0b2b7b4d9eb9d4cc6f40fc14109b02a932c79519e013b2cf1c3352a94" + }, + { + "kind": "file", + "path": "img_1245.jpg", + "sha256": "ea3c372f430cfb78f5283ad52ecad7ad3fb18a7a6c5695d8149b82ca54875f2c" + }, + { + "kind": "file", + "path": "img_2994.jpg", + "sha256": "13fd7b684f7729e8e1a3677c05207aeb61bf87f87138ac82863a2d8b4b27a30a" + }, + { + "kind": "file", + "path": "img_3452.jpg", + "sha256": "b3e7cb1c949ad61eb11cb462cd0977a9358ad5ab81eafbe0bc62f5da84bd6bdf" + }, + { + "kind": "file", + "path": "img_2758.jpg", + "sha256": "47fb99bc2bc592260412665d0395079ee5d68101d0707677324dd71a890e8807" + }, + { + "kind": "file", + "path": "img_2980.jpg", + "sha256": "e6d77225611baf70c4c8d1ca7e4d04a475da1f85958f91ee938644d61baeec9b" + }, + { + "kind": "file", + "path": "img_4329.jpg", + "sha256": "6ef18bb04febad84369f4b17e27f6866b36ec5ccccd17464f3753c664cfe2755" + }, + { + "kind": "file", + "path": "img_3446.jpg", + "sha256": "9b9fca4806a3ffef140de4f1ab0ef6d835ec39576a63ed16e42d61c9b9a77d9f" + }, + { + "kind": "file", + "path": "img_1537.jpg", + "sha256": "da9e0b5f890de16f1e42793163f0d6d3dccb709c0476fc349f984f44dc5c76ed" + }, + { + "kind": "file", + "path": "img_528.jpg", + "sha256": "5b87af3bb3465154c9f99d6165a83c17ab61bef90783a92154b13514d965a365" + }, + { + "kind": "file", + "path": "img_500.jpg", + "sha256": "cae4d51a9da67dbda3078242c82563d5aab1a1b7a4037a33454d21dc1decfc0e" + }, + { + "kind": "file", + "path": "img_4498.jpg", + "sha256": "f6b8a54f32524cf37984ae2a04895b1c776ad4ada1a26f99fcd4bf1759fc1657" + }, + { + "kind": "file", + "path": "img_2957.jpg", + "sha256": "57ab8d0ec2148d83ed91c51adab619920cfc624dfe047f2e6344480a2f99cdd2" + }, + { + "kind": "file", + "path": "img_3491.jpg", + "sha256": "490bff6ea0cb814e3c25ea7c237d86dae6ae2ff1d3a9afc5554dee9599bd1a05" + }, + { + "kind": "file", + "path": "img_266.jpg", + "sha256": "51d9e59ad9c51c215e6b9afb2db5eecdadd33fe4ec5df3086cc8c2dfd8bb959c" + }, + { + "kind": "file", + "path": "img_6.jpg", + "sha256": "4e0bc00f2c2b105f853a7ab45bbbd45d92eec46466fb740c0d94159982e04a46" + }, + { + "kind": "file", + "path": "img_1286.jpg", + "sha256": "5ed0b18994bb90138a93e7df60078de6e0459fde7f7567096f230fd013741608" + }, + { + "kind": "file", + "path": "img_1292.jpg", + "sha256": "31932a32b4a5d48b36819bb971dd141a0bc99a47d91b0df30b4dd5b994ad42d5" + }, + { + "kind": "file", + "path": "img_3485.jpg", + "sha256": "93416dca47f6aa462ec0714c0f23c28d173e06dffcb508d694e9b7908c645493" + }, + { + "kind": "file", + "path": "img_514.jpg", + "sha256": "00010bbc1d23e41eb6364945d83f5a5f3009f4986207cc52f0827d7bf248253e" + }, + { + "kind": "file", + "path": "img_4103.jpg", + "sha256": "06fa4d2e956c65f9aac21cf4e4eba817892d38233097eac8d7effc4ca28c27a4" + }, + { + "kind": "file", + "path": "img_2572.jpg", + "sha256": "d6dcfe40e07ff2b31c055242edb7c0b2fcac1f409aa491d0fe3e90a1ee0824d1" + }, + { + "kind": "file", + "path": "img_2214.jpg", + "sha256": "41c5677f478ded3a176157cd35d2a5ec6534321c5fd70888a010328800f9b101" + }, + { + "kind": "file", + "path": "img_925.jpg", + "sha256": "7d729883c2ce79aabd3673cd45eed668cf97f4c52c1cd666f1ee7454804862d4" + }, + { + "kind": "file", + "path": "img_4665.jpg", + "sha256": "25fa5e4668e1df1c8e513b48fb9f0ca456197419d28d3caec9f234902abe47c6" + }, + { + "kind": "file", + "path": "img_1709.jpg", + "sha256": "23c1f6f049ba215ebfa346de8bdceb7dede613b7d397db99c02eefc1823e0408" + }, + { + "kind": "file", + "path": "img_931.jpg", + "sha256": "971bdbbb210a00b5bb1b5e77288772f74bc88a84aa56030d2fffa56403c26168" + }, + { + "kind": "file", + "path": "img_4671.jpg", + "sha256": "75de93f7a2eef260b0d784e9910177199f0ed072eb22088e73b7d9bf04775eb1" + }, + { + "kind": "file", + "path": "img_3678.jpg", + "sha256": "172c26f5828b1f0f3eb39c182e8344e6743a315577c8b1cf35d0871815847f25" + }, + { + "kind": "file", + "path": "img_4117.jpg", + "sha256": "d580ef7d2bee49dedab2c6f2dd40991d5e690ae5b918dbd66c2326e101f1af91" + }, + { + "kind": "file", + "path": "img_2566.jpg", + "sha256": "08cffdc56ab486fdd0129a3e1ecc00d13630b8872cbd8eda2176c17ae6f73a2c" + }, + { + "kind": "file", + "path": "img_3650.jpg", + "sha256": "0c8bbedafed699a12dc7bb45f6f4b4958ef74fa65d2ae7fe5aa646233963795b" + }, + { + "kind": "file", + "path": "img_3888.jpg", + "sha256": "53aabd1d20b036a7bcfff220ce73bddc6db1a391cfd5418d0ae96f5c1fc874f6" + }, + { + "kind": "file", + "path": "img_1047.jpg", + "sha256": "02135bbd54e5b669ab053a7480374507090fbbc30e1256a7d52b6758156b954c" + }, + { + "kind": "file", + "path": "img_1721.jpg", + "sha256": "bcae6b80a0e7fd10044fa6ffc66ceb350316722085ca5255368c37aa29d11b69" + }, + { + "kind": "file", + "path": "img_4881.jpg", + "sha256": "ee7b4844224acaace8e183d5f9f63e418aa3d43d8a4cac68c1f7daeb13d4e385" + }, + { + "kind": "file", + "path": "img_2228.jpg", + "sha256": "b90eedc489e5287a743f334e038135aa5c6b87b93fd19fb731209326f2640048" + }, + { + "kind": "file", + "path": "img_919.jpg", + "sha256": "e6f3c0d276712f855e60eb5d78757abeb91b5119a5473e8474c5c2ba424a8238" + }, + { + "kind": "file", + "path": "img_4659.jpg", + "sha256": "14532e3dd976ec6ab80e1e99c1f845a5c2d46685c0abd8c1a16f6db3fea0d201" + }, + { + "kind": "file", + "path": "img_3136.jpg", + "sha256": "7f85ae73b99a05442127540de452e4e173a227dc7ce9a36c1bcdac7ea39c1ae1" + }, + { + "kind": "file", + "path": "img_3122.jpg", + "sha256": "5446aa2271b16d58ffbd22790cb23c9ebc219ff27dc66e96010de651b80942d4" + }, + { + "kind": "file", + "path": "img_1735.jpg", + "sha256": "a47d86c048291bbf75d4aa8446318a4f681721123481405e80a9993102439858" + }, + { + "kind": "file", + "path": "img_1053.jpg", + "sha256": "7b15ee941f14ba4b2b2e28a64d3c2dda3cac0fb4678942b587d64749efe1bd35" + }, + { + "kind": "file", + "path": "img_3644.jpg", + "sha256": "1243f30748cc4a66bc1f4d975def0baf57406d4f03c2bb74668ba664238d4013" + }, + { + "kind": "file", + "path": "img_3877.jpg", + "sha256": "dc963a3a42d665110ec2df841696f09f5b08001875a1ed3d065c3a6a500471dc" + }, + { + "kind": "file", + "path": "img_1906.jpg", + "sha256": "c256ca24895d46d7fe611f5d5f5b3845a3da5ef16bd0d7d6724de9710898895e" + }, + { + "kind": "file", + "path": "img_1912.jpg", + "sha256": "ee9ee89df5756edf99a4b32ba0b2cebe279adc710154de3688b2506b0348a5ea" + }, + { + "kind": "file", + "path": "img_3863.jpg", + "sha256": "564620f283f03f7a02f7c885046cadc3edacffb06b86fa3c92d7e9877e361076" + }, + { + "kind": "file", + "path": "img_1084.jpg", + "sha256": "8b59ff7144a3b4b306ef6ea4ea01aa773509e8e1e575da70dae6d2d328b83fcf" + }, + { + "kind": "file", + "path": "img_702.jpg", + "sha256": "d4c1033f71c9d7f1541f2a28f7bc499335e8aeeafe49883c0ccd0df6b4f78e6a" + }, + { + "kind": "file", + "path": "img_4856.jpg", + "sha256": "8df17ac09fc53db52f60f5e2f38c85b186f2371ff792be1c81b7baea72057a3d" + }, + { + "kind": "file", + "path": "img_2599.jpg", + "sha256": "8349591a9b45eede9c32aac08dbcf66eebcbff7e09e69083c11e3f884f57236f" + }, + { + "kind": "file", + "path": "img_3687.jpg", + "sha256": "5e3ccb6a3531fc398cf0b556f3859fd43d1cd9cc67610d2941a165fa60107894" + }, + { + "kind": "file", + "path": "img_1090.jpg", + "sha256": "0c22974fc72837154751544eff9fedb1095119e08591250f58c05ad351839ef2" + }, + { + "kind": "file", + "path": "img_2406.jpg", + "sha256": "52ed9c47225fa7a936888436fc7ad5bbd3f382e21bfe976f822144f94bcee607" + }, + { + "kind": "file", + "path": "img_4077.jpg", + "sha256": "94dc218c223822bcfb66278bcd312af68395fb4905d5d0e5fa3b24daf2981fb7" + }, + { + "kind": "file", + "path": "img_689.jpg", + "sha256": "9ce1e0bfe6739876670f69e70709a1d51f01b17e9dbaed676b2a60ad68648def" + }, + { + "kind": "file", + "path": "img_4711.jpg", + "sha256": "5e02a627c7cc055aa1ff5573c560f9b823f82cdded3d6364e14d66cfcdbb4065" + }, + { + "kind": "file", + "path": "img_851.jpg", + "sha256": "473eb85b96d115354dbc03b9417cb34ec696c13b19d9f58db75cbc7cbbf6ce9a" + }, + { + "kind": "file", + "path": "img_2360.jpg", + "sha256": "384e3cbc671e0c0d2be92b9f3cd5f98c6f11c9403ef8ba4c07e2d6a4b2c4a8ae" + }, + { + "kind": "file", + "path": "img_1669.jpg", + "sha256": "c6a6ecb5932f7da3f526beb747c1caa61b73e411d18b038ed51017f47cfb22d3" + }, + { + "kind": "file", + "path": "img_4705.jpg", + "sha256": "a5e13fe0dc6e9c76e34839d80302a6a3dc7fd9822bd1eea8c63adaf2fb3d4814" + }, + { + "kind": "file", + "path": "img_845.jpg", + "sha256": "fd8a698d476e78592f50b40f245a8bccd27c2d32c765576699f49ffd67d556bc" + }, + { + "kind": "file", + "path": "img_2374.jpg", + "sha256": "a021ac067ac94a0f3cd65cde02539d0ee03c4f953251e0f506c316a110cba71d" + }, + { + "kind": "file", + "path": "img_4063.jpg", + "sha256": "f19c0ad2fa0fa8971cb03f91fba8fc672404c73808b4577bb849e37c1eeacb3d" + }, + { + "kind": "file", + "path": "img_3724.jpg", + "sha256": "e3e8f0a51cc9934b7f64e86c3989af0d24583f972d608c2d7913d3a0aee5da9f" + }, + { + "kind": "file", + "path": "img_1133.jpg", + "sha256": "ee82fa67571ef4733811b21a4545cce5c861f72824dfa3a26d2eb95ae224a893" + }, + { + "kind": "file", + "path": "img_1655.jpg", + "sha256": "4625c0006973aacc0763c49c5dee0508d2182d0fc6f9feccfea2df3d347cbebe" + }, + { + "kind": "file", + "path": "img_3042.jpg", + "sha256": "43d4b7bda974936fa9a88faf445e9afa88628a89fffbf8094312172656ed20c3" + }, + { + "kind": "file", + "path": "img_3056.jpg", + "sha256": "cbffcd387dbbeeccb9e0bcceaaa61d2195707b90b75b63ce23ef4254ed8cb4bc" + }, + { + "kind": "file", + "path": "img_4739.jpg", + "sha256": "2a8389e1ae86f9e3a46781daf72f78189ba45b2525183d80ebff23bfeb7898b9" + }, + { + "kind": "file", + "path": "img_879.jpg", + "sha256": "58b6f52cb155275543d8e43997aaa31f60aeaac5fa1d53a8e314abc3fd0dd868" + }, + { + "kind": "file", + "path": "img_1641.jpg", + "sha256": "c3ccbeb396b726b32ccbccccbbe14c79f8a3f0ed049116a55b72bc8d930d2781" + }, + { + "kind": "file", + "path": "img_1899.jpg", + "sha256": "fdbe94f50c8875ef4b48ccaffb03e26e4736c7e3312fa61dc1db525b69a48b42" + }, + { + "kind": "file", + "path": "img_3730.jpg", + "sha256": "fb62fbd4d56dd41be268f12eae02ac7fd60fd8ed4e2bb9825bed83f565ac222b" + }, + { + "kind": "file", + "path": "img_1872.jpg", + "sha256": "a1eaf01acc0002053153a8fbb291a6e894c80335e90169f07f1486e0d9de8e2f" + }, + { + "kind": "file", + "path": "img_892.jpg", + "sha256": "25fa96992188f77415cdaac50714188e054d0daee0b36815ea07d1f3d39ae9f2" + }, + { + "kind": "file", + "path": "img_1866.jpg", + "sha256": "bc7e364615c7ed43b9e2d54d7ef0f9679526ceb50f0003c036d05d363123f839" + }, + { + "kind": "file", + "path": "img_138.jpg", + "sha256": "860406d808663972c2b782927005625e301f243756fed7ec9eb05837a63f8d1b" + }, + { + "kind": "file", + "path": "img_3917.jpg", + "sha256": "230a916b322b6d68cb76ed224f340e4481a8ab8af5c7326ba54958c92f8e70e3" + }, + { + "kind": "file", + "path": "img_4088.jpg", + "sha256": "13e06a89e3c3cc45b547fde88d2aa173e94ac9c6ed7caa7dcec711a0e70c5d5a" + }, + { + "kind": "file", + "path": "img_4936.jpg", + "sha256": "4933502548798f81a88c82020b6beb67c4feb111e3c0e63fcb4464a0c34c74ed" + }, + { + "kind": "file", + "path": "img_676.jpg", + "sha256": "2d7d336228ec0cbe8a1b24d4c9ea81646af9e5f696ab17cb10a31d9cb83e0437" + }, + { + "kind": "file", + "path": "img_3081.jpg", + "sha256": "953b2fe97aa0a45ba017cf10de2583334beaa145471d714870957a23ecb079ff" + }, + { + "kind": "file", + "path": "img_1696.jpg", + "sha256": "d306b78d6225beca127eba7bc88b81cc8b03760330b096f01bccd02ac0a919dc" + }, + { + "kind": "file", + "path": "img_1682.jpg", + "sha256": "d6327995fecadaa5b07fc67e97f8197407e9e98b1eeed154812406b6e2da566a" + }, + { + "kind": "file", + "path": "img_662.jpg", + "sha256": "7ab866f506eca8dffd80aa09e28d45552327ec5db1adbd61319e40fb995ee685" + }, + { + "kind": "file", + "path": "img_3095.jpg", + "sha256": "d493fbf12cc2c6aa493e715000948939364e69e99345dc0521f57de1ee80c53e" + }, + { + "kind": "file", + "path": "img_104.jpg", + "sha256": "0181353325ad6276a9d520dbbd4d6c05cef4930ee76c541daf433fb5404788eb" + }, + { + "kind": "file", + "path": "img_2162.jpg", + "sha256": "82148cd3da72f635aaed4f32e06d311d55503b4b78c5931c0be6a9471f363ce1" + }, + { + "kind": "file", + "path": "img_17.jpg", + "sha256": "6447331bf5b53542d50ffcc392fa441718fd9984ce632695f0398fb99509f1b6" + }, + { + "kind": "file", + "path": "img_4513.jpg", + "sha256": "c159314bc34b0228d5f1e3aaf20c0b09d91212a4234a8585bcb32835075f6448" + }, + { + "kind": "file", + "path": "img_2604.jpg", + "sha256": "c163435088fa3982ec9b7c40a4572a570beb6dd2f5c96e23743c5091f21b78e1" + }, + { + "kind": "file", + "path": "img_1319.jpg", + "sha256": "49b77dc406f85f8cc2e72eb1cf383efdf07b6ef79adfb936e1bfee51bd5f7ed0" + }, + { + "kind": "file", + "path": "img_4261.jpg", + "sha256": "2e878793991d92493024a883bbbcb65af99c619161952f7eb3acfc18c1cb20f0" + }, + { + "kind": "file", + "path": "img_2610.jpg", + "sha256": "493e79816cb9885f6898ab9f4ce0afd30a24fe4da9a4d3bf21e4cf67ba5a993a" + }, + { + "kind": "file", + "path": "img_4507.jpg", + "sha256": "1b0c6e500783439dd46b40cc7caef6802707faa30124ba201891c7a5d2b497d1" + }, + { + "kind": "file", + "path": "img_3268.jpg", + "sha256": "0c7f910986adf97d9d9cab1b8c22384e99e21abee7a0813bf0e6747d9d42f136" + }, + { + "kind": "file", + "path": "img_3240.jpg", + "sha256": "f31774273adb15d0925e61742a24f29d7d93dd5fce6e1e8df11b76fa652c6225" + }, + { + "kind": "file", + "path": "img_1331.jpg", + "sha256": "30bd10fc78da8410aa9181f4bed5259a1afd4b52ee881d18d9d55a4e5e352920" + }, + { + "kind": "file", + "path": "img_3526.jpg", + "sha256": "83df3ee563568dc3cf516e637b2b81980d52afbc9db11524598b18f5bb6e3105" + }, + { + "kind": "file", + "path": "img_2638.jpg", + "sha256": "e0604b4efad5194fef25eff9165998a2190c5fc74cc1df6f3a4b1f66172d9c97" + }, + { + "kind": "file", + "path": "img_3532.jpg", + "sha256": "aba9d4db7eea61c49e2525f367fbd0a844a0269af73eeef2c720aa670c3c6eb9" + }, + { + "kind": "file", + "path": "img_1325.jpg", + "sha256": "0d7db137ff77ed70af0ca2835217c35917225e6321f6bec03b7db71d6a9f5c80" + }, + { + "kind": "file", + "path": "img_1443.jpg", + "sha256": "4ba1b5aae03d1fd6fa2de4040d3d33065c443ed5876c2f5d808b760f4b81aa7b" + }, + { + "kind": "file", + "path": "img_3254.jpg", + "sha256": "65d969ffe6e45fac2e02c4f965beef724baf2f70f2a30c25ee97cb79b292ea3b" + }, + { + "kind": "file", + "path": "img_448.jpg", + "sha256": "c5b87ec278bcf45c360ffb7d2366bf7bc48a2b04c0b11842bceca5f1fc399b8f" + }, + { + "kind": "file", + "path": "img_1494.jpg", + "sha256": "165412f8c7854124641bc8746f8c42016955a7c7be819b06cf2c20126479b16e" + }, + { + "kind": "file", + "path": "img_474.jpg", + "sha256": "97d766cbd17311837085740cf7dd8b8979c62484513a23113305499020493f36" + }, + { + "kind": "file", + "path": "img_312.jpg", + "sha256": "9c103f1c8da1a5472925bb98efe5d55d302fd553f8ff9b269345c80441fa815e" + }, + { + "kind": "file", + "path": "img_2823.jpg", + "sha256": "9c3c59d96b84fa8f9399a906a1957b8abcbec53052a2276bd039114c013c6713" + }, + { + "kind": "file", + "path": "img_306.jpg", + "sha256": "b3f76fbc4b64db6308617fca8920c77acbaaeb7e9aa582bdd5c2cab2d46cfd4a" + }, + { + "kind": "file", + "path": "img_2837.jpg", + "sha256": "475fa0a13a83dbc7633bcb82bc128cc1ef22dcfd9525a3f44572e0139309a0e0" + }, + { + "kind": "file", + "path": "img_460.jpg", + "sha256": "d730c4c0a38163f8f2de8f26686ee1393287a50b602ff012e8a0e11196a3cf3e" + }, + { + "kind": "file", + "path": "img_2189.jpg", + "sha256": "8944b3f441461407e2c19e9734c6229d700397f104f6c9f0d4a5c1afd76b013b" + }, + { + "kind": "file", + "path": "img_2821.jpg", + "sha256": "82ccc5770f2479ec8ed281b34a0a17ab71d94109ba1e0e282931b69c9ca8d889" + }, + { + "kind": "file", + "path": "img_4288.jpg", + "sha256": "81688ede2e983e105679df00066056709fbe361c0e4959564d8eb4ff6bec1052" + }, + { + "kind": "file", + "path": "img_310.jpg", + "sha256": "bf5d66d9f1d3179689a816c8302ebc1075c1678c9c3f66638075fa4cd2da1771" + }, + { + "kind": "file", + "path": "img_3281.jpg", + "sha256": "66615777051d6ce6b26f76d164784ada9b687010cfbda3488a74384f6468f1e2" + }, + { + "kind": "file", + "path": "img_1482.jpg", + "sha256": "2eea3a44530899f2de6968dcca4ebf9f1efbbdec17ff1b5bc026b0d2e875be84" + }, + { + "kind": "file", + "path": "img_3295.jpg", + "sha256": "af9b0f6a304b682fb89f3b29b39d86f0f60d144d63e31bc202cea4b482f92c90" + }, + { + "kind": "file", + "path": "img_462.jpg", + "sha256": "413bc6c0e2cda149a003bc5b439a6d792cf5661f612e72697dcc121da0060d2e" + }, + { + "kind": "file", + "path": "img_304.jpg", + "sha256": "ae27cc0a92584df00ede85abe2853299c051fd08ba4ee9ae3f2ee54b49b290a4" + }, + { + "kind": "file", + "path": "img_2809.jpg", + "sha256": "5cac769ada6b92a5fa3531d73e996b74d4cc50a023e7a98ddc8fb074c7ef3c47" + }, + { + "kind": "file", + "path": "img_338.jpg", + "sha256": "27383c55c5bf9b3e196141c12ffbd2eae85f303e34ba2f7b39eb272a7fe3be95" + }, + { + "kind": "file", + "path": "img_1455.jpg", + "sha256": "c59e648e9330fc903e4d135cee1f07af55664f2436b1072fd464d7301eeedc83" + }, + { + "kind": "file", + "path": "img_29.jpg", + "sha256": "1eb03a0aba12c960bf562da3b0723f5c6180aae3de1e463999d9e35c6b64f89d" + }, + { + "kind": "file", + "path": "img_3256.jpg", + "sha256": "f9472d065c6a9a99e57376815a0aa38239096a6eddfe5a141f8efe54e7273175" + }, + { + "kind": "file", + "path": "img_4539.jpg", + "sha256": "5af56df9e282146facf61110736d54a74ed39c974aad191c955e2f2efcb6ff50" + }, + { + "kind": "file", + "path": "img_2148.jpg", + "sha256": "86ff852e8099c3104868afac6239dc913201e2d057c2baaca6968f50beeda813" + }, + { + "kind": "file", + "path": "img_1441.jpg", + "sha256": "e1ab120f45a66ba7ee6f5bd21268f7cac056cc2b482a02951992486747f425c8" + }, + { + "kind": "file", + "path": "img_1327.jpg", + "sha256": "41373b32ab0955315bcfaad754654047204f3f910733a940849d6a94b61cfec0" + }, + { + "kind": "file", + "path": "img_3530.jpg", + "sha256": "6924edb1adc0d981e25a836752b35a3859b64ad30d5168f65da0449ff9e511cd" + }, + { + "kind": "file", + "path": "img_4277.jpg", + "sha256": "7af6f6d4450b3922d3e230ecebbcd1f2f8812fe5a7839274a0f75ca4c3374f82" + }, + { + "kind": "file", + "path": "img_3518.jpg", + "sha256": "1fce2255819b6b562a6d64eaac2307767a36d564cab2e21684208a6afb4410b2" + }, + { + "kind": "file", + "path": "img_489.jpg", + "sha256": "8b5d87aea1c078f3c02a431937e643586a9f46f25b05c4113e64bceea05f3e2a" + }, + { + "kind": "file", + "path": "img_15.jpg", + "sha256": "eb5c9168c69cc79e766dba0bc5809287555f87d4532fc5e5af248c13901649a2" + }, + { + "kind": "file", + "path": "img_2160.jpg", + "sha256": "d73787ce3b83f70ff304020d5a14a47f1a40f853b2c27704cd70e9aa70b7f9b7" + }, + { + "kind": "file", + "path": "img_1469.jpg", + "sha256": "82ff62be6c4697222e37339dc3590d926d4b62d6761b7625131ecc7e243318b6" + }, + { + "kind": "file", + "path": "img_4505.jpg", + "sha256": "cf4427136907743c22fbd860a3c785bcf443f38ece534fbac1b0a21aeaca202d" + }, + { + "kind": "file", + "path": "img_2174.jpg", + "sha256": "55a06745f53bf85577bb6e799c1eca2c2b6f10f7967507e9be439e0474af1c92" + }, + { + "kind": "file", + "path": "img_2612.jpg", + "sha256": "3dadb52a377b9c0003d54254aad5ec817483c2326e2525d0c1bc562c907b4860" + }, + { + "kind": "file", + "path": "img_4263.jpg", + "sha256": "00122cdd36b7c7dee515e62e8af2a34ba68ee0262f42a130209fd069fb610c50" + }, + { + "kind": "file", + "path": "img_1694.jpg", + "sha256": "ee9c39876aabff0aa94174b5539c6d0defab70e26867c0f385b2b125ab2d2de3" + }, + { + "kind": "file", + "path": "img_674.jpg", + "sha256": "912299d222b5ba879cb814fd2b5c348dd170404530fb45b3b03a1cabc109d4b0" + }, + { + "kind": "file", + "path": "img_3083.jpg", + "sha256": "bfb42eba8a22dfcfa89ba03d4f93aeb2f4429596cb5b01f0f0b416c7c1282864" + }, + { + "kind": "file", + "path": "img_4934.jpg", + "sha256": "7c9dd162765aca86a424c071749838f25fa9ce0f0878509da2d3e32175d0ecc3" + }, + { + "kind": "file", + "path": "img_3929.jpg", + "sha256": "07405cca6820a2c0c7a31ae75a2c79e81289becdf4cebcd7541c70c85bcabb3a" + }, + { + "kind": "file", + "path": "img_660.jpg", + "sha256": "cf5b832aaa458e8e986cb9e68e1869d4f7f88c5af243482d49784987aa76a273" + }, + { + "kind": "file", + "path": "img_4920.jpg", + "sha256": "a763d83a0efabaa2108e9d92b3cd90f6bed752f2325308e12d03075733c4dd76" + }, + { + "kind": "file", + "path": "img_2389.jpg", + "sha256": "a28870bd2275482f74cd3016df23556520a0287ef38a78425d8b6eebcc52534f" + }, + { + "kind": "file", + "path": "img_1858.jpg", + "sha256": "b6ef240381badd88e3b13978305b335b5a8acbd6617cb0d204c62e5dda26f472" + }, + { + "kind": "file", + "path": "img_648.jpg", + "sha256": "70ff4797f1ee38788f1dab4a20e99c6a8f02cc38072cc5ac7c9aa1b982d93ba9" + }, + { + "kind": "file", + "path": "img_4908.jpg", + "sha256": "82cf76c5fe95487e9f93f2cd56785830564fbdb1ef8a441392bd0a63e0eeec3f" + }, + { + "kind": "file", + "path": "img_1870.jpg", + "sha256": "2f2727607a60368faa2dac9866f14d071ce222bbc45ede4879b2dd6d033a65f3" + }, + { + "kind": "file", + "path": "img_3915.jpg", + "sha256": "cbba3dd9e0990c033e404f9826f08eb833be7cdbb4891b7f0eaac62a50d3bb58" + }, + { + "kind": "file", + "path": "img_1864.jpg", + "sha256": "12d5e1226d5ee4b52576517d43596ba9f1c7e199a751646c0c7931777235c5a6" + }, + { + "kind": "file", + "path": "img_884.jpg", + "sha256": "e30bb90070536feb31c006a045912eb97562af7a16d5bb582b60d9eec0abca9c" + }, + { + "kind": "file", + "path": "img_3040.jpg", + "sha256": "8c8796164c795c946017a2a5f42a00cf4bf20c96fbc1a74330e048a52eeff784" + }, + { + "kind": "file", + "path": "img_1657.jpg", + "sha256": "a92da1d451734ed2f4a605bdce932572b1d95a9df22775850bb7706f7394b6ff" + }, + { + "kind": "file", + "path": "img_1131.jpg", + "sha256": "43eacadd3b58c845c60dba30ece24b2c414e52cb0590d011bf82993145d0e1d0" + }, + { + "kind": "file", + "path": "img_3726.jpg", + "sha256": "a156fd1f70ed07c3b71cd91e40d94042de3c5921d309b98834e5c7170a3f4eab" + }, + { + "kind": "file", + "path": "img_4049.jpg", + "sha256": "6f61939b5e027d72329bfd162e7b9953e61969ec3a37d8c64eac42192618de1d" + }, + { + "kind": "file", + "path": "img_2438.jpg", + "sha256": "7a4a84f871819409671cae18c7618cec6f04f17799aa3f519f8346b5ba40f7b7" + }, + { + "kind": "file", + "path": "img_3732.jpg", + "sha256": "a9a32da8aca94e442498ff3e5da7f6024857bbacdd51c0f5f4f13372de1bc5f7" + }, + { + "kind": "file", + "path": "img_1125.jpg", + "sha256": "54bed68a64365fb99028e491b21c77e93e8e4c360b2b8ac27e287a60480cfd0a" + }, + { + "kind": "file", + "path": "img_1643.jpg", + "sha256": "d33a06c0644d8658b1a0079b1d4102f977f6cdc5be352d287e5ae230709eef47" + }, + { + "kind": "file", + "path": "img_3054.jpg", + "sha256": "75443588baf69989b0e770a909efcbb7431c2386348d083f2542a89a5d6e87f3" + }, + { + "kind": "file", + "path": "img_2362.jpg", + "sha256": "0a7e6135f8b551ce9aec921c509e4c9f52802b0f95b5868220702bc8b56d4442" + }, + { + "kind": "file", + "path": "img_853.jpg", + "sha256": "42ee87f429953488ed35c37f3ddac0fb494c9334cf688439a63d8980cff160d5" + }, + { + "kind": "file", + "path": "img_4713.jpg", + "sha256": "02f1454f3c5e7eb616eafa082bc0d7a19b9607dd69f50464a3863ebe55390d17" + }, + { + "kind": "file", + "path": "img_4075.jpg", + "sha256": "0f92b96747de084f700c5d2cc1b7c9597ad8a63c878fe59d2a8e92bb9ca5e178" + }, + { + "kind": "file", + "path": "img_2404.jpg", + "sha256": "03cc9111d6d48d574257b5b3ae0e9a17fe96f9279b7d99e5c7841183294b88f1" + }, + { + "kind": "file", + "path": "img_1119.jpg", + "sha256": "bbbf5499d79f2ac2c30256ff4ef10700e33e15bed8819b24825b44b283f9b531" + }, + { + "kind": "file", + "path": "img_847.jpg", + "sha256": "c30593ef4c08a24357e6b9aa58d0cd8d97d3824409299f8da149cd7f9ee43035" + }, + { + "kind": "file", + "path": "img_1938.jpg", + "sha256": "7310657d0c85e1fbba2d5188f5a6b94cc51d8d82c4b388cc8e4987222d479969" + }, + { + "kind": "file", + "path": "img_4698.jpg", + "sha256": "9f891542d74623d3e362d7293920e0e3cb4793cbbec82debe62802cde21cb077" + }, + { + "kind": "file", + "path": "img_3691.jpg", + "sha256": "ed46976b646a9616cecb819b3b4724405286da069a0cb5c38c0d76fedcd44ef1" + }, + { + "kind": "file", + "path": "img_3849.jpg", + "sha256": "8adb9c87ef116609ac9574ceea1c8fd7e2d7e50dd8cddb7ac3cee3b34df1c60d" + }, + { + "kind": "file", + "path": "img_1086.jpg", + "sha256": "c4cd0a05d1a99337dbfbce4b94ce7502dbbe792916db16efa3cf2626683b69e1" + }, + { + "kind": "file", + "path": "img_1092.jpg", + "sha256": "61a7a789238c33a14b46327345a55b5da872ffa22830bd59788c0096b65a10f5" + }, + { + "kind": "file", + "path": "img_3685.jpg", + "sha256": "f0f8f62d654b9c9daeed47257c6ede57ce117155a38c76a30478aefe7714f7b4" + }, + { + "kind": "file", + "path": "img_4854.jpg", + "sha256": "34134c7ef95670d9f56301995c0937f575da0f29b2d088a1b046e1609369c859" + }, + { + "kind": "file", + "path": "img_714.jpg", + "sha256": "0defead6ca07d028b0e7c9e90ddbe76cb96a0406d242f69eee3dade85331c9a8" + }, + { + "kind": "file", + "path": "img_1904.jpg", + "sha256": "3ea5702f3381735f5126f56aab53e3bad5e6929cc42cae9eed902e0ad5a2a276" + }, + { + "kind": "file", + "path": "img_3861.jpg", + "sha256": "93ffcc5edb159df0f790ddc0abb06fab12a45481cfb5f522dc7f2e27fa1d10c0" + }, + { + "kind": "file", + "path": "img_1910.jpg", + "sha256": "3e269292cf4ddedd9373941abcf83d6e633c66446592868d9cf4bfefbba7130e" + }, + { + "kind": "file", + "path": "img_4868.jpg", + "sha256": "34f0912b55577b46872b6880232a40983b8d264f03ae528a011ec2fa27ddacab" + }, + { + "kind": "file", + "path": "img_728.jpg", + "sha256": "467434cf2407be0a1789f099c29f781131127cc915039ca33ff50aa0adbe0963" + }, + { + "kind": "file", + "path": "img_3134.jpg", + "sha256": "c9050ef9155c04ba687bffbcfe8c5f04ee630c4b1cb8542890128c5772ad8e31" + }, + { + "kind": "file", + "path": "img_4883.jpg", + "sha256": "df6fc00b5ff9ae30b529a34c9cee71e79318b7ca61db16d2c4ccb962705c9eb5" + }, + { + "kind": "file", + "path": "img_1723.jpg", + "sha256": "18a00b8f243bc4d88695724b5f7002e7dd3733e637605ba5fee01ae1ba3f4df1" + }, + { + "kind": "file", + "path": "img_3652.jpg", + "sha256": "0b24db9da03d9455fc268b0b506a1f806a1cf2d5c46dea6f8c440970765481b9" + }, + { + "kind": "file", + "path": "img_2558.jpg", + "sha256": "ef5de2fdd8eef526809c8a4d875f32eead50e69bda63ca5498dcc969abce7f9c" + }, + { + "kind": "file", + "path": "img_4129.jpg", + "sha256": "632901a63c70fcf3f9015bcaf7d488ed70ce82ccbe9c4bfd8d0c4d62783a4f61" + }, + { + "kind": "file", + "path": "img_3646.jpg", + "sha256": "9f58a8fd17ab877fff7a6a575b26c14d94153d20e84ca7ae709fdd734b530e92" + }, + { + "kind": "file", + "path": "img_3120.jpg", + "sha256": "aa8b59995948ced6a0acf9f3fc72036c6f4a649bc66824730a33701ef7fd942d" + }, + { + "kind": "file", + "path": "img_4897.jpg", + "sha256": "4044dc1bfdb1dc0e2c8c3f5766850fa02de55dfc0765aa4a13f1ee501d348591" + }, + { + "kind": "file", + "path": "img_3108.jpg", + "sha256": "a4933d4614d1dc17e5bd614afe398060813334286db0e6d42a91eb941507b02a" + }, + { + "kind": "file", + "path": "img_4667.jpg", + "sha256": "f2d337a16f75f4e57deb3a0fcf2202a68a4b40255d55359601ffc411b2616bf5" + }, + { + "kind": "file", + "path": "img_927.jpg", + "sha256": "c64bc0d506df6d7e61540439927928ba9402a1108cbb25dbc2bed4b4aa0d8470" + }, + { + "kind": "file", + "path": "img_2216.jpg", + "sha256": "66666eaba0674d6f9f5f495f82e61ca7bea4f1d83c8d63d3b1c4bee6fd6b4f1b" + }, + { + "kind": "file", + "path": "img_2570.jpg", + "sha256": "cf793286db889cef35226d4120da6b04849d3b0827d89e5433f28a61e7253b0b" + }, + { + "kind": "file", + "path": "img_4101.jpg", + "sha256": "8e0d6787558fd0de8aba84b4b5583e3b018212e6f9c7be83abf1b10c1401ade8" + }, + { + "kind": "file", + "path": "img_1079.jpg", + "sha256": "c984d822546616eca7b501fcbb9dfd6c7f0c30aa8fba84e3a3822d7849663eb2" + }, + { + "kind": "file", + "path": "img_2564.jpg", + "sha256": "ee2f359d9babe58d8e64fac6a56879a034970885bd14787fe6046c6da0d3b43e" + }, + { + "kind": "file", + "path": "img_4115.jpg", + "sha256": "95c103bbb32adecb938d7815679bdca8475a65ca10ee3e5431e644333910fc94" + }, + { + "kind": "file", + "path": "img_4673.jpg", + "sha256": "bd778a08b07f74d005d8f4f637691a0540d28681a1427e6681f407d36fee1d7c" + }, + { + "kind": "file", + "path": "img_933.jpg", + "sha256": "fa3de50c3737c652597338171ddd9e32b6d726efca7f47902ff2ab54e0306dc8" + }, + { + "kind": "file", + "path": "img_2202.jpg", + "sha256": "87660bcd1a1141fd3bfb37fd8879852fc65a96ce60091933258187d40befb571" + }, + { + "kind": "file", + "path": "img_4.jpg", + "sha256": "def287c0827c6c84d75bdb69c0fc435463cd00de2680465639d88bb6df854acc" + }, + { + "kind": "file", + "path": "img_3493.jpg", + "sha256": "9335f26f737e1f14162d79a2fb0679686e8d5fa71d777a901a304cd5fc4d15b6" + }, + { + "kind": "file", + "path": "img_264.jpg", + "sha256": "9845695b765e6869de8fa43da9274aaac9455501015f72ba5e75402559a0fa44" + }, + { + "kind": "file", + "path": "img_2955.jpg", + "sha256": "b4331764b2497dec02e8497f9baebf4c1c8687e7f69ff669815d740a012f756c" + }, + { + "kind": "file", + "path": "img_502.jpg", + "sha256": "a29a3376e67288416e1f71818840c75a5eaa5712bf8aaa25420ffa39ef4acc1a" + }, + { + "kind": "file", + "path": "img_516.jpg", + "sha256": "5595eff570ab93f80e270c5541fc11cc8bfff9475410fdc1fae520643b4c897a" + }, + { + "kind": "file", + "path": "img_3487.jpg", + "sha256": "b3918c01878557a0328bcfdb1a467702c677f7b572e43779767eab6fe1418526" + }, + { + "kind": "file", + "path": "img_270.jpg", + "sha256": "f6f48595140e368a26c7272c5347ae927e62d9761c02b65f3c643c68fca4fb95" + }, + { + "kind": "file", + "path": "img_1290.jpg", + "sha256": "acc86e8ee25a790416b3656b4b938c56ea9ccf733f4035d96f8fb52f09a6fa6e" + }, + { + "kind": "file", + "path": "img_258.jpg", + "sha256": "007ae4fe8b830a1c79dd7c8414d2e4c4a99e68c3b1abb2e9e177eab449b29e7a" + }, + { + "kind": "file", + "path": "img_3450.jpg", + "sha256": "a708940cc0f8395231f86d61d4b7c3f78d86337a06ae0b5c7b8d69e3c940fb0a" + }, + { + "kind": "file", + "path": "img_1247.jpg", + "sha256": "750165e322de6d6c622ee2a7c59ea90d5261a3c4541fd1f9ca10971dc62358e2" + }, + { + "kind": "file", + "path": "img_1521.jpg", + "sha256": "049f2d4551c56c7d6687dbf925b4be273c48c26ab0fa27cf91232e5b172377f4" + }, + { + "kind": "file", + "path": "img_2028.jpg", + "sha256": "05f0436acaac25651239d946da9e458ab2505cf88dd0dcdd615fb416bd965dbb" + }, + { + "kind": "file", + "path": "img_3336.jpg", + "sha256": "da84c4719d0f74a96c3b523932aa5c7425925420a96c21174d3915719782c68e" + }, + { + "kind": "file", + "path": "img_3322.jpg", + "sha256": "4f73f30f67e0db7ef700929b0555b8944edef5b3627e85573b00a65fc0c73585" + }, + { + "kind": "file", + "path": "img_1535.jpg", + "sha256": "bfcfdeb8a78ce457a2199b2a8badedee7e7793c67b32f9a2d8d9d6fd3d139ef8" + }, + { + "kind": "file", + "path": "img_1253.jpg", + "sha256": "6722ffca29e3871cf3ed8d0191a5ca83dadb4b5934b1f5edcf3a9ba2113c9a58" + }, + { + "kind": "file", + "path": "img_3444.jpg", + "sha256": "7eaa54a87db5c78a28e206bfbf96b7739dad5ae9f2520843450fa22e5531c18e" + }, + { + "kind": "file", + "path": "img_2982.jpg", + "sha256": "055dddcfe5956f970dd84abe1b38779c435edf73c0e63e154a12f5a9a96cbe15" + }, + { + "kind": "file", + "path": "img_2772.jpg", + "sha256": "4095f53fbdae498b7c3b552b4d3667d07d7f7322e1be6aafcdc4ab904fc7e8bc" + }, + { + "kind": "file", + "path": "img_2014.jpg", + "sha256": "27d291fc92132b5bb57bafcfea86ea34cdc2a5a7be948a8982092df9450d5964" + }, + { + "kind": "file", + "path": "img_4465.jpg", + "sha256": "e6e24f6602150205b7bf5e545b5becafd133fe20e360ed4216dafd3019c2f4b9" + }, + { + "kind": "file", + "path": "img_1509.jpg", + "sha256": "13673364a7f614a39c908de8a8de90da2167c9b570b8a902c867675747fa2123" + }, + { + "kind": "file", + "path": "img_2000.jpg", + "sha256": "e5a1defa66b8aa115c0ec796327b08786a705dd6c2d3da057d8eaad90be97ecf" + }, + { + "kind": "file", + "path": "img_4471.jpg", + "sha256": "8bffb6b70d27bf947a2ed129b8e992a29403288b2ea1313e33e9ccb704c938ba" + }, + { + "kind": "file", + "path": "img_4317.jpg", + "sha256": "dd2fbf5fa6c192dc49d152750ccef1f67b8391cfb7b1d04a48e6ea54b15e06f8" + }, + { + "kind": "file", + "path": "img_2766.jpg", + "sha256": "7c96a35632d774d78d4ae867c14291f55a18c1662234dd58b3d48d9f48f81f59" + }, + { + "kind": "file", + "path": "img_4470.jpg", + "sha256": "09609d760637914307426c4c4b81bf52b6245d90a54fb8ae176983d655491a0b" + }, + { + "kind": "file", + "path": "img_2001.jpg", + "sha256": "26c3f4bdc477013ea1384850d8acd3276992509c51c31ed831fcd61d94de74ce" + }, + { + "kind": "file", + "path": "img_4316.jpg", + "sha256": "a29bbdfe7817c4f0c6411e15042826e5758d65e7e4c8f48a1a6cece571ce7996" + }, + { + "kind": "file", + "path": "img_2773.jpg", + "sha256": "ee4cba530a4d2e040777c65e9f588923e50904db0feb1778ebe598d6ae0f5e35" + }, + { + "kind": "file", + "path": "img_4302.jpg", + "sha256": "9b50cbede73fe58f3f7e0352f3b8ebc914f5a4e2a475a5b8668109c7f68bd89a" + }, + { + "kind": "file", + "path": "img_2015.jpg", + "sha256": "8623aa372005a2f00f3d49d5981579cd0da38c5b5483034873d82e73e09ecc6f" + }, + { + "kind": "file", + "path": "img_1534.jpg", + "sha256": "9dc6fc0c19b4564eb75dfbf42aa98be7af4513f26505db37dc9e252e412ead4a" + }, + { + "kind": "file", + "path": "img_3323.jpg", + "sha256": "d4157258334b263e4ff68417bff678adf37dd69f19e95de68ff9af73b0a8d33e" + }, + { + "kind": "file", + "path": "img_2983.jpg", + "sha256": "fc3e975b1ab9971bc93b879bcfd6df1b935dc4a6e39e243f4290765275c21934" + }, + { + "kind": "file", + "path": "img_3445.jpg", + "sha256": "33931e1f66bcf5c36b735245dcd053ea503aca71554c96862061b8fc09eb452d" + }, + { + "kind": "file", + "path": "img_1252.jpg", + "sha256": "78549426909ee2911a73f044d99231beb09df36b7501355eca70b55627d53942" + }, + { + "kind": "file", + "path": "img_1246.jpg", + "sha256": "7d1fea7abd1b06b5d2eb35ac480ef01ead608cded23eb5494fb97c9254e29bd1" + }, + { + "kind": "file", + "path": "img_2997.jpg", + "sha256": "6c382d21a4e95e615980ec36c725128fdb28989e7d0b31f9b3692e5d58b853c8" + }, + { + "kind": "file", + "path": "img_3451.jpg", + "sha256": "7b5534743d668206735f64a3c7b928e9e4e402ac1ca1cdaece33aee288ee1307" + }, + { + "kind": "file", + "path": "img_3337.jpg", + "sha256": "1630a2691f1e5521118c743fdcd641e812104f29cc83e1d08f15def14c2ea86c" + }, + { + "kind": "file", + "path": "img_4458.jpg", + "sha256": "82193860efdb446015a3693f4b779d09a7cd170acedec3219b6cdbf8fb356d9f" + }, + { + "kind": "file", + "path": "img_2968.jpg", + "sha256": "8e9de9f12dbd3d8e6372d40503f0cbc4176e2b8d8be87791cc1593c82074469b" + }, + { + "kind": "file", + "path": "img_259.jpg", + "sha256": "bd11f17179b905ca48327a1a509c40065302f58e8350f1ed86c8ac8bff57ca62" + }, + { + "kind": "file", + "path": "img_517.jpg", + "sha256": "eebd72134ffc3c56ba5f294d4c322134f6300d28e481a079f51e135667ec52ad" + }, + { + "kind": "file", + "path": "img_2940.jpg", + "sha256": "c7c962c638587e31e323ca85c53b0f06ccb100d63d550dd0ca3059fb839e9d7d" + }, + { + "kind": "file", + "path": "img_271.jpg", + "sha256": "203e8628e3205494fa217d4aad21069bdf665abc9869a884e04bccfbc2a5ceca" + }, + { + "kind": "file", + "path": "img_3486.jpg", + "sha256": "5c5e1a229c5b00cc5611a2feac2eb96427559e6c07305ab58738d3b203617a6b" + }, + { + "kind": "file", + "path": "img_2798.jpg", + "sha256": "a79fc654e4ed8e3536f40eb5d8b018bb79d2e94e36645669494168b99dc5bd74" + }, + { + "kind": "file", + "path": "img_2954.jpg", + "sha256": "a2563de4ae0e7e2b626e5b9d7b94a4fd9ba67494549a35c7ffddd0a70c353167" + }, + { + "kind": "file", + "path": "img_265.jpg", + "sha256": "42371c50d08bae90d925bbc75e6343262f354965100a96c61f40b3ed6d6b9652" + }, + { + "kind": "file", + "path": "img_3492.jpg", + "sha256": "4b43fe3eb05de2f7f2e248cb02a3ba6087d7b4fa6a7123cb5bb227f96230a9c6" + }, + { + "kind": "file", + "path": "img_5.jpg", + "sha256": "498a3fbbbb56a7f50cb9f1d7be7f485a6a8a3aa003cca74df556ea20ef13cdbc" + }, + { + "kind": "file", + "path": "img_1285.jpg", + "sha256": "c237003475ed3c5c7ba9f85f30a7aaf9009c0204dde3bd7678622cfe00fa2a75" + }, + { + "kind": "file", + "path": "img_4114.jpg", + "sha256": "5239574d27a7d0532aab5bead34419827217b4c3015bd7413f0bbc3539e6dcf6" + }, + { + "kind": "file", + "path": "img_2565.jpg", + "sha256": "b2e6bbc14c03593f13c6c15ad4e68a5c52ecc5e6fa3c865ffe650e159dbe7d03" + }, + { + "kind": "file", + "path": "img_2203.jpg", + "sha256": "e4b2e0063ded5f9fef4b85f857219722ec8a81003066dc8a1ccc28aa74ff9100" + }, + { + "kind": "file", + "path": "img_932.jpg", + "sha256": "e2e49259fb7295470e76374d435437fe7031d78cef224947534ce6a329ada01d" + }, + { + "kind": "file", + "path": "img_4672.jpg", + "sha256": "d2a7b0e34210d54d93215aa885bd38f41c5a7a90470a05ed6985a26cfbe96f65" + }, + { + "kind": "file", + "path": "img_2217.jpg", + "sha256": "67ff8b48b68d454feb9400aabfc0aa78fe8970059cdb900c4e563bfc7de9ea70" + }, + { + "kind": "file", + "path": "img_4666.jpg", + "sha256": "35f94f7aa46e01a543676522697d53decbd0c90308701b6fcb64c58b4ba623b3" + }, + { + "kind": "file", + "path": "img_3109.jpg", + "sha256": "6e23e11e60fb8dcb176548693fec3d7b37c295afffa38d0bb79b3fb3f0541f87" + }, + { + "kind": "file", + "path": "img_1078.jpg", + "sha256": "eba4a056f538f916cc3ca058358a27d68a096838bf7009986e7729132fdae100" + }, + { + "kind": "file", + "path": "img_4100.jpg", + "sha256": "307839c0a6a12e631f0c61c8b054b8d869844017cefb1624591c1e3f3977fc8b" + }, + { + "kind": "file", + "path": "img_2571.jpg", + "sha256": "577b6a3732a7d2fc047a3b435fb7a66b1ce29bbe8e1dfeb7e9fa2691d18b4d34" + }, + { + "kind": "file", + "path": "img_1050.jpg", + "sha256": "43e278daa875633d9c43b1e51971bd4d7d5f4117efee4795cbccce114eff475f" + }, + { + "kind": "file", + "path": "img_3647.jpg", + "sha256": "484bd06e1ccdcd03d2107caed968888a6fb85fda7ecabb517c50d660d075e01e" + }, + { + "kind": "file", + "path": "img_4128.jpg", + "sha256": "3307e2edbfd945eb137eae1f57e7cb8858b6feb425bdc4d3bb2c894bcf033e7c" + }, + { + "kind": "file", + "path": "img_2559.jpg", + "sha256": "922b2ceff13b6a205fc7fab1418af4210acb33152e1d927a92b2c703e410c864" + }, + { + "kind": "file", + "path": "img_4896.jpg", + "sha256": "2bdfe9fc0239ce0bd44811b4bc14a31bde17f003e291d86dd86113939a37218a" + }, + { + "kind": "file", + "path": "img_1736.jpg", + "sha256": "d6ad86678624de7e3970b622ad6e084222e84c1966763118411e8533679269d5" + }, + { + "kind": "file", + "path": "img_1722.jpg", + "sha256": "17b90084aa82e1d61dc66f75848bcf04ebad51ea52bd632d35060a8fbe7c8281" + }, + { + "kind": "file", + "path": "img_4882.jpg", + "sha256": "369ff2b6faf351404d4cb61c0872ec540c460f2de0bccc5593dd6113db7142b4" + }, + { + "kind": "file", + "path": "img_3135.jpg", + "sha256": "923040ce4af219c4b9ca1a08a0837568cbabb153c530e03f36b9c7d269ab3d53" + }, + { + "kind": "file", + "path": "img_3653.jpg", + "sha256": "511c964f2d532795e5e0a01c5dcd7fca789d7379124ca0c2ea95302973f043ea" + }, + { + "kind": "file", + "path": "img_1044.jpg", + "sha256": "4b783117a79e7022a1f0acbc424634502d30b45cd0addd9c4a08519a145202db" + }, + { + "kind": "file", + "path": "img_729.jpg", + "sha256": "9dc633ea7a2d0986b16f1c8faa0873eaed81e942c4fea06f5f0f84730b4c5eae" + }, + { + "kind": "file", + "path": "img_4869.jpg", + "sha256": "c0558ae48a02b81dbe61539b3178a679b2115aff38e054f3a69be402cfaec46e" + }, + { + "kind": "file", + "path": "img_1911.jpg", + "sha256": "7632d2cfbb67256541549f344ba21d3bd6079b277840a3e657f8d88dba569ccc" + }, + { + "kind": "file", + "path": "img_1905.jpg", + "sha256": "5cba17de87bae500dd4f6da6ec5c960fd34fd94fed77853744b25ff68a2a451d" + }, + { + "kind": "file", + "path": "img_1093.jpg", + "sha256": "3b673ead127f054ee57a90d99c97172c2548092c7eafab6c408f004c6438b68f" + }, + { + "kind": "file", + "path": "img_715.jpg", + "sha256": "40fab5a31f91e49c7a38f20d441938a1e5a20b5b6f3de7740e64f2dffc9edc06" + }, + { + "kind": "file", + "path": "img_4855.jpg", + "sha256": "4f95bc9808749da11e63e222acc295d7d6e1b6c79caaeac48ced07df5901697e" + }, + { + "kind": "file", + "path": "img_4699.jpg", + "sha256": "3803da43fcddb0fec55b3915d026e2d672a0a4d867d32deb3481e228bb66711b" + }, + { + "kind": "file", + "path": "img_701.jpg", + "sha256": "4081dafe6efb7bf8028c7702e665466e7b3db7fdc0cc5fcd8c337006152cd8a3" + }, + { + "kind": "file", + "path": "img_4841.jpg", + "sha256": "0df3180c4183fdfb04a53788cb8aa510cf81a42338ea6d3df7d6bd7693ff18cb" + }, + { + "kind": "file", + "path": "img_1939.jpg", + "sha256": "2da9c64887ceec3235b2f764771aff1f66749fa8b93758a1da7668bcca8862f1" + }, + { + "kind": "file", + "path": "img_1087.jpg", + "sha256": "6646e2bd10a9f3ebd3ad72b165e34bcf3a962d19769ad0c0ffb0e8d637843306" + }, + { + "kind": "file", + "path": "img_3848.jpg", + "sha256": "ee1483ed92313006c7e19403a4406b3084ff767bc6a651f62bb9b399b1dcd1ed" + }, + { + "kind": "file", + "path": "img_3690.jpg", + "sha256": "3fb39d5646867633ded7767bf23abdff202533e721d485d27c9da22cac68ac68" + }, + { + "kind": "file", + "path": "img_2411.jpg", + "sha256": "41162ac9d129e6a9ad9efd1e80d429db56f05fa744f75d8b1fa1e3f9ca0884b5" + }, + { + "kind": "file", + "path": "img_4060.jpg", + "sha256": "b033cfc86acc1ef24e8c7fccb3b703f90498436ed6faf914b84db0f6705cb9c5" + }, + { + "kind": "file", + "path": "img_1118.jpg", + "sha256": "ce2f9725aea5e784bb58b263a914188963911af1f0d8fbe24db889279c097dbc" + }, + { + "kind": "file", + "path": "img_3069.jpg", + "sha256": "f4a653207977e3dad71598ab411012c75122299b0bae87c0afe24bdba6c7a96b" + }, + { + "kind": "file", + "path": "img_4706.jpg", + "sha256": "b1e1b254a8cb9e21d86cabf339a1458f1ec7e40e1acc25365dfee94dbd03ad26" + }, + { + "kind": "file", + "path": "img_846.jpg", + "sha256": "fae7ce0c7604432163dbf1f2022993c8991c093c00cd3564cae0e1b5b0165d38" + }, + { + "kind": "file", + "path": "img_2377.jpg", + "sha256": "6cad6cd70cce40bd3b63d4c9b9db70b5fe749d226bd49d17520b12bc63da4467" + }, + { + "kind": "file", + "path": "img_852.jpg", + "sha256": "bf2d845e27e97200d88019f4bd428725ba48a72c92b2637f32df360afc02c0ba" + }, + { + "kind": "file", + "path": "img_2363.jpg", + "sha256": "8300fbcffd54658fb91ef46e49beb7ba1fc0c7bfc345b312d73bee7bbd1b50ba" + }, + { + "kind": "file", + "path": "img_2405.jpg", + "sha256": "c8de890a30023aa2703b56d134d47cc6704dc0666382e17141fb32f138d01c95" + }, + { + "kind": "file", + "path": "img_4074.jpg", + "sha256": "9a8d83f46eb3c9c0d8708c128f130478d25d5264466e2a38e446b2404254f488" + }, + { + "kind": "file", + "path": "img_3055.jpg", + "sha256": "68db2a34cbc8f5dbb645f108aac7462da6b1f90289be3292646d8b20f1ba1a81" + }, + { + "kind": "file", + "path": "img_1656.jpg", + "sha256": "911b2b639c79c40e162560b554f0d250ece53c406a4c3feca0659785d30f0b5c" + }, + { + "kind": "file", + "path": "img_3041.jpg", + "sha256": "f80fd247ae9f36c63f959bb347fd1b03a69fc9032bb47d96ecd1890f52755aef" + }, + { + "kind": "file", + "path": "img_2439.jpg", + "sha256": "99903040134046e350784bd8bb5a7b64de3c2d7bb7bf773355918e6b220cc8cb" + }, + { + "kind": "file", + "path": "img_1130.jpg", + "sha256": "8699a6f4ed8f3e9d1f50dd5b24959b6c249015e8704cdc5f00a8c756b39ec7f2" + }, + { + "kind": "file", + "path": "img_3914.jpg", + "sha256": "f291c0bf1cf5e0bb5a33720add731e2d82c228889ee6ef780e0f22463c477174" + }, + { + "kind": "file", + "path": "img_885.jpg", + "sha256": "8150354de2e968c23cd3709d96f5a9ef8b328ff7d86310098e5e5e3a17876aaa" + }, + { + "kind": "file", + "path": "img_1865.jpg", + "sha256": "9c243de7ade36f96832a66fcc45f5faa098a733bd6cf3cd0d17580c2ae1324fb" + }, + { + "kind": "file", + "path": "img_891.jpg", + "sha256": "8bc1240e37428b439b5e84d5be496ccc4414ef2783d4efb86b6f00681755ab14" + }, + { + "kind": "file", + "path": "img_4909.jpg", + "sha256": "16114f840306876028d3e7cacd3908441715d93f651e42b48ae9e0ae7d978eed" + }, + { + "kind": "file", + "path": "img_649.jpg", + "sha256": "5738c61f5e881668cbf66df64eea2b4a84be61fe414bc45d8de0c9cb00e1eaa1" + }, + { + "kind": "file", + "path": "img_3900.jpg", + "sha256": "c31cad7d2537fefd5c1b3750d08b57ff2304b2e48afcc80fa08340fe8bb909c2" + }, + { + "kind": "file", + "path": "img_107.jpg", + "sha256": "8db49fd9feca27aacafe225277b314c51843da4b8c35ae53e94d8e1023559e17" + }, + { + "kind": "file", + "path": "img_3928.jpg", + "sha256": "2817b8cbfafc963e34debaae603aa92202a0051c0213eb5032d64573caedba15" + }, + { + "kind": "file", + "path": "img_1859.jpg", + "sha256": "ad1e7994d2f53f8caf565461ed6dca6f02e8331e8e0481f6664b7531b682a019" + }, + { + "kind": "file", + "path": "img_1681.jpg", + "sha256": "2c3fc2a5e1c0a7feb909d996bc66292f0f848c2feeff5cc6489eec4970b334ec" + }, + { + "kind": "file", + "path": "img_2388.jpg", + "sha256": "5bca21b5a958438dd857bbbc8bf6e0dafec6be9052c4d3d84e030c874d5b07cd" + }, + { + "kind": "file", + "path": "img_4921.jpg", + "sha256": "a93c1a4e5e0715b8eb8444f1c16696c6cac2f3d3493c8378018acaa2cad339f5" + }, + { + "kind": "file", + "path": "img_3096.jpg", + "sha256": "58ea226321ce279ae6ed749a5e62374641dbef04889e1fbe70b2e466031b8345" + }, + { + "kind": "file", + "path": "img_661.jpg", + "sha256": "386e3a8194523c663fe1f31dfbba5e24db5cd5dea5fd5b411a18d2a4631ac34e" + }, + { + "kind": "file", + "path": "img_4935.jpg", + "sha256": "dd72ce016c85b75867b14e87997ad3243ce3a60383201bbfba6c7ec377d1f25f" + }, + { + "kind": "file", + "path": "img_3082.jpg", + "sha256": "fb3a42cbecc2710a07ec29f924df56af3c9792d17eb06f7ac4c10cf179fb454a" + }, + { + "kind": "file", + "path": "img_675.jpg", + "sha256": "311d078d29c3904d721a0419aa7aa62d9537726c8775337906d6b43c797681ef" + }, + { + "kind": "file", + "path": "img_1695.jpg", + "sha256": "cf508ec560ba23feae61b51048b89e7be1e0bbe10a0c3b78bb8332b637138584" + }, + { + "kind": "file", + "path": "img_113.jpg", + "sha256": "c88b5367573131ba04e255d06a3a2a13ba938e4afdf857a4a506f2db44a8c7da" + }, + { + "kind": "file", + "path": "img_2175.jpg", + "sha256": "4df163345a85516beca7a51c1fc7363a1cee460ec0111219bc1885a6d226ffe6" + }, + { + "kind": "file", + "path": "img_4504.jpg", + "sha256": "bd406383b1bd70620a965f1f8e25331afccd7e845c83c86d8e1752e912e08b3d" + }, + { + "kind": "file", + "path": "img_4262.jpg", + "sha256": "8cec2d8f175858f684783a481d5d329dd3697db6a1d4d116b76594e4ab098116" + }, + { + "kind": "file", + "path": "img_3519.jpg", + "sha256": "8c02c42fc8cd69b4861df045f2d61e71b4f83f3854971922534bac7c5873ab9d" + }, + { + "kind": "file", + "path": "img_4276.jpg", + "sha256": "bfcae89bcc02a01768e486d60a28ccd1d692d370a968f3d879b60274571cc426" + }, + { + "kind": "file", + "path": "img_2607.jpg", + "sha256": "af8e97c0655ed92515ed64b13aa9900e67c0dc2a048d3defe31bfa8ed1fc970a" + }, + { + "kind": "file", + "path": "img_1468.jpg", + "sha256": "ddf6816aec0a9569a4d0ea60f3a0186dd44ce213c7d616da38163ef2e9cc28b5" + }, + { + "kind": "file", + "path": "img_2161.jpg", + "sha256": "3a064d976e4f4bd72d33b61ed4737b2710eced8eb9cc123f5276c67d75cedd7c" + }, + { + "kind": "file", + "path": "img_14.jpg", + "sha256": "b8e53c45ecda2b4c9b80102d00e57acb3f5540bdcf24304232bfef9e72cab135" + }, + { + "kind": "file", + "path": "img_4510.jpg", + "sha256": "dba1ac2be48757923d129c6f53e57b7e779fb8c7b9085a97e747752284d9212b" + }, + { + "kind": "file", + "path": "img_488.jpg", + "sha256": "50fdf1883a26948bb39e7f99fdb47a79b20a7f4e6a9a8036ec38cc6406545981" + }, + { + "kind": "file", + "path": "img_1440.jpg", + "sha256": "88f75256e92487f7b726c8221492a666d16195a2190f21a95f22954f68ac967d" + }, + { + "kind": "file", + "path": "img_2149.jpg", + "sha256": "bd5a16c6c4050c632d646bd1671b88928812f80c699deb3c15fcd127b8bdbabc" + }, + { + "kind": "file", + "path": "img_4538.jpg", + "sha256": "c9f98957674ca208d6e6bb2770ec9efb1f3bed39679bfec53b314f5932f67e71" + }, + { + "kind": "file", + "path": "img_3257.jpg", + "sha256": "226c0f347497b9f1f93dc37530b2ff35c00fddaa5441880b060bf8f620c6a100" + }, + { + "kind": "file", + "path": "img_3531.jpg", + "sha256": "67bf66dbc6aeb768c163a845dfa45917812782aaddd3d830438cbc34fbb27257" + }, + { + "kind": "file", + "path": "img_1332.jpg", + "sha256": "6c33c74d85160da79bf82e3ce25f72e9fd9bf80dbb0857638a4b5caa4b4ca97d" + }, + { + "kind": "file", + "path": "img_3525.jpg", + "sha256": "60aede01a05742a1389be958d1a115f7bb2f27b60ff3c0cff3ed33aefe16ae67" + }, + { + "kind": "file", + "path": "img_28.jpg", + "sha256": "aa00de832ab3c059f8ab0ffc301075aad4959ffad5326d278ad910643bcfa4bb" + }, + { + "kind": "file", + "path": "img_3243.jpg", + "sha256": "e27e9b55a4643c52121f53d673568e9bb0df1c882f3cc0648352b174f5730033" + }, + { + "kind": "file", + "path": "img_1454.jpg", + "sha256": "28caacd5579d9be53f086f954c30a537ac0a2543c10bddfc65830a760e497c88" + }, + { + "kind": "file", + "path": "img_339.jpg", + "sha256": "3125f0d41c608aa50d8f4b17ea51f408b5f003dcfc6a9a183529db3e04df9467" + }, + { + "kind": "file", + "path": "img_2808.jpg", + "sha256": "a6d42b1cc62bb07c7ba62cbb6ca31d579853ceeb8a43c56ed2118f36054e76a6" + }, + { + "kind": "file", + "path": "img_1483.jpg", + "sha256": "ad6d725e45e33bacbd3b429995c262d34cbd0e9e32a6d2d9176e93fbec1c3f7c" + }, + { + "kind": "file", + "path": "img_305.jpg", + "sha256": "bd2b2ab4dda0baac98899e0a31e03f8d1eb488fb5a39c8b067066de4b0ccc955" + }, + { + "kind": "file", + "path": "img_2834.jpg", + "sha256": "ee0f08af8e189ab4641e0c5e3d5c8035802b35323a26e03b15aa7358e7df4db2" + }, + { + "kind": "file", + "path": "img_311.jpg", + "sha256": "33d9cd346bb5f10967e4999a16bb4145cf5afccdb6a30ce70f3526ba7ddc73c6" + }, + { + "kind": "file", + "path": "img_4289.jpg", + "sha256": "62e879ccfe920dc224661011c1b10bfad2220f5b108ac8d4c2dbbdd7fc2a6f96" + }, + { + "kind": "file", + "path": "img_1497.jpg", + "sha256": "c3f1d3fd6d6e214bcf1ee2915412b793f685cd2da9745e24239fa192eaaee886" + }, + { + "kind": "file", + "path": "img_477.jpg", + "sha256": "a750d973f4f948222e26beed1395b28d13ecfe68c36a96e1236bf1047afc67f5" + }, + { + "kind": "file", + "path": "img_3280.jpg", + "sha256": "e9e5a57eb521ff8fab9641564326e84bf0f9d53979cb816a3a035801cce6ac50" + }, + { + "kind": "file", + "path": "img_438.jpg", + "sha256": "aaff7417ad59caab888dfa15deb1be72292b8fcbdfd7040c4b30bad1ac14a1b1" + }, + { + "kind": "file", + "path": "img_376.jpg", + "sha256": "ef2321c91874c24017d6950217ad8d98aae9f63a40f837b3caffc937c6f8d52a" + }, + { + "kind": "file", + "path": "img_3581.jpg", + "sha256": "0e7881d8c36a079bc7b24fe4b7c1251d99d49fe203c3ed18cdd5f333567493a4" + }, + { + "kind": "file", + "path": "img_2847.jpg", + "sha256": "9a8afe0e28b823677e9d839dcb21a5063bb90a06500d806ea974977e7638b366" + }, + { + "kind": "file", + "path": "img_1396.jpg", + "sha256": "f191aadd4c2a9a5b21fde912e5d1e25c5ffc60a4957da67a67ccc471928065f0" + }, + { + "kind": "file", + "path": "img_4588.jpg", + "sha256": "55f159640f79926fa149104ed47cac2768869dd83f8b22bdd2ed0b4678d7b111" + }, + { + "kind": "file", + "path": "img_410.jpg", + "sha256": "ded43298e52ab76e26a2c17b06786d0a072e0009da9feb7fee2fca5b313fe597" + }, + { + "kind": "file", + "path": "img_404.jpg", + "sha256": "b1785409f4aea7cfb41873dbec517e8100a4dfb1de120cf89ba432cf5b236011" + }, + { + "kind": "file", + "path": "img_1382.jpg", + "sha256": "a17aff4f30c5463b92f5236235be67a0a54ff8c13d38da840df8e037c8828269" + }, + { + "kind": "file", + "path": "img_362.jpg", + "sha256": "1cc803668d675113d251028d1cc7ac3428bb177026f9b720a444ecd3d9553174" + }, + { + "kind": "file", + "path": "img_3595.jpg", + "sha256": "5ecc4a3219264cb6d30f4465d2cb9dfc0b52b571c7f259622170cd99b28a8552" + }, + { + "kind": "file", + "path": "img_2660.jpg", + "sha256": "d849b62607dd0cc64023456f8d84deac53009a4fa89f904bb5a649dac385ed1c" + }, + { + "kind": "file", + "path": "img_389.jpg", + "sha256": "1635b6f517faf7a9d2f9a2a473162572027939c92c004ac137b59dc513512242" + }, + { + "kind": "file", + "path": "img_4211.jpg", + "sha256": "e4859b7cad7760c91ac4ae2469f7d375ad47e39326b067ec3c738fe09fec5f85" + }, + { + "kind": "file", + "path": "img_1369.jpg", + "sha256": "78218b5bffcbaedfe76b6fa9cf4629f400e46beca77b0b43a365e5ffd0ac12ee" + }, + { + "kind": "file", + "path": "img_4577.jpg", + "sha256": "d7b8799cbd5068e3ea4798c9f98e1be051cd4f3bdb11288b46651b0fcac70bf6" + }, + { + "kind": "file", + "path": "img_3218.jpg", + "sha256": "ed97642532e5d307ed70a5926fc2ff1b2ee276a730def99c9e95b3c010f4fe82" + }, + { + "kind": "file", + "path": "img_73.jpg", + "sha256": "029628b4dbbd68d798bc5b73b9819b5cc4a0a3fc20c9b736a704b4398e58d784" + }, + { + "kind": "file", + "path": "img_4563.jpg", + "sha256": "9b81d4af13461abb4330aa903d50783b339806f921d3892ad7f0cb0e679a426b" + }, + { + "kind": "file", + "path": "img_67.jpg", + "sha256": "ba9f4e348800084fc6617a2f8b3a438f31605936a019e6acb9ac3d9176a51bd9" + }, + { + "kind": "file", + "path": "img_2674.jpg", + "sha256": "d56190b4fc4b9181d4cf12ec699a10119017108bd35e203574a4f10d0bd2ea55" + }, + { + "kind": "file", + "path": "img_4205.jpg", + "sha256": "745a8f22a871c67fedd6799562a01e70e6e6f5af3a987192fcf79a0ff73337b5" + }, + { + "kind": "file", + "path": "img_1355.jpg", + "sha256": "8f227b34869900cac49bc8d64fa70dfa0d0fc75afd573229cb2abfc655bea1b9" + }, + { + "kind": "file", + "path": "img_3542.jpg", + "sha256": "e9790035d17cf1ed9c21f6b19487ceb97cc86d10bb0fd9a7df9d35af97662218" + }, + { + "kind": "file", + "path": "img_2884.jpg", + "sha256": "39f2911ddc304b13ebe8c6a802dac34622dcc9749a15183e8fdcf4808ee9103b" + }, + { + "kind": "file", + "path": "img_3224.jpg", + "sha256": "81afe069aa5f3ecb309bc824d8912a930341c6e97b5f80edb1335153865aab2b" + }, + { + "kind": "file", + "path": "img_1433.jpg", + "sha256": "166be0a0bbe711c180c6a1482d59184ec52f25af692901c0f9c695a94c39fd36" + }, + { + "kind": "file", + "path": "img_1427.jpg", + "sha256": "f42c3f14a9c488c253515ad65b06325baadacf586c623e43187ce8e742f0f9bd" + }, + { + "kind": "file", + "path": "img_3230.jpg", + "sha256": "5546bbadb5a1620fb52566988e498626310d1f03db7036d31c2cda7478eec135" + }, + { + "kind": "file", + "path": "img_2648.jpg", + "sha256": "31895c52f41b7db1c18e165cf7a5f8e956c30a72d7f31dc78330b0ea94f4ca65" + }, + { + "kind": "file", + "path": "img_3556.jpg", + "sha256": "2291cebd6eac8760a2511fdaf2ddf3ac9482187c6986fd8cadfe07448cb20b70" + }, + { + "kind": "file", + "path": "img_2890.jpg", + "sha256": "4f564a05d185e7ba9cbe774a301fd3af9441e2e3d58a411e1090dbec752338fc" + }, + { + "kind": "file", + "path": "img_1341.jpg", + "sha256": "2949e06c368523a59d9cc773876b7a68d92093541404ff011583d204d735d0b7" + }, + { + "kind": "file", + "path": "img_1816.jpg", + "sha256": "3264a0a180cead9dff684c459675fd45b06ceb392e61dff8e92d88d0fb557379" + }, + { + "kind": "file", + "path": "img_148.jpg", + "sha256": "0e8d66bbd29319fc7248a31a16e0322aaa6f67bf9f66e123dcb012986411dced" + }, + { + "kind": "file", + "path": "img_1802.jpg", + "sha256": "f6fc8201e7e98b675a237f6438e4863b44d4d495a195e091b6e051c645d9a262" + }, + { + "kind": "file", + "path": "img_612.jpg", + "sha256": "1d67c718ac2f9ef2c20325d2efddbcd336e0f8b6cde4b76e77eb40aebad212cb" + }, + { + "kind": "file", + "path": "img_3783.jpg", + "sha256": "f69d8886cde77c8e8a5104e5485cf02bfd56ddaaa0853573c5af42c03aea200c" + }, + { + "kind": "file", + "path": "img_174.jpg", + "sha256": "65b94cf349bfdad010dbecbf482200add86a957b3b60f47f359a2d7ad2558196" + }, + { + "kind": "file", + "path": "img_2489.jpg", + "sha256": "558f895712a9dd44b83b87c8a96dda60a675165fb0702dec08c65ef5496ed786" + }, + { + "kind": "file", + "path": "img_3797.jpg", + "sha256": "af97daea9e180b6e51101a197b6433eea092deae76a1669ad8b949f39689bc63" + }, + { + "kind": "file", + "path": "img_1180.jpg", + "sha256": "94dfc6055dd54f5222ce1037f757e6731bbf7ae4553eca80c843b4abda19ca55" + }, + { + "kind": "file", + "path": "img_606.jpg", + "sha256": "50ab00c1c3faf835b484904bf5f28873264ca604b3ba65e6f56f8442258b9287" + }, + { + "kind": "file", + "path": "img_835.jpg", + "sha256": "6b5c52814063bc10ce64a2eaf2405d5e699670c5d68c02ffeeae35567ab7cb5c" + }, + { + "kind": "file", + "path": "img_2304.jpg", + "sha256": "f4192ca3ca5ae7c0575cfd4b2456235899688abe202dffe30f634da9a4387d1a" + }, + { + "kind": "file", + "path": "img_4775.jpg", + "sha256": "61edefc429666fd9ce107f769302f125ce0302e2bada83e91d6cc8f8ed1037db" + }, + { + "kind": "file", + "path": "img_4013.jpg", + "sha256": "31915b8d91b74e671d75aa25b25884a33897d25dc272cc06f44ae556e71d1de2" + }, + { + "kind": "file", + "path": "img_2462.jpg", + "sha256": "68063deb4783777ea30f0fe0d4e1ff76233c5ee9804cb51fccf6ee56ad37d38a" + }, + { + "kind": "file", + "path": "img_4007.jpg", + "sha256": "b528e1e9bfec26347ef508d3ed2bebdf7fd9de02e4f0011c02c8c9d49e185d1f" + }, + { + "kind": "file", + "path": "img_3768.jpg", + "sha256": "4811739428bfcfa63126d1659067e39a00bd3b33340931a7ff68b538c91aaf50" + }, + { + "kind": "file", + "path": "img_2476.jpg", + "sha256": "1fa1c9990b3bd9d8c785f35895ee3e7aabbf29f5004236ac5e1e78860e748470" + }, + { + "kind": "file", + "path": "img_2310.jpg", + "sha256": "b0137847a0aa586a1f48e511b25718ddc484cff3a1f32f732b6e95394628ce24" + }, + { + "kind": "file", + "path": "img_4761.jpg", + "sha256": "b5b11d71861e3187c80a26f0232492aa533b52ae12badeda66f4a9cbefbef102" + }, + { + "kind": "file", + "path": "img_1631.jpg", + "sha256": "c693ffe7a85df701a60cd6db890ef01de4c6dd6a1f9d52699ea0a63da714dabe" + }, + { + "kind": "file", + "path": "img_2338.jpg", + "sha256": "628b0fa44e57f3cf88d23ebaa9aff4208b7f685fb9c51abf44025bb2ea9c40d1" + }, + { + "kind": "file", + "path": "img_3740.jpg", + "sha256": "b973cba7902ff7a6f8227d200c0419ac5bf7c7bb0d188eadead888a5c350b05d" + }, + { + "kind": "file", + "path": "img_3998.jpg", + "sha256": "4bf1fd3cbd21f4bcb7c56550abb0e2bd7a2b040ab3ef3331e191e968ac61ec6d" + }, + { + "kind": "file", + "path": "img_1157.jpg", + "sha256": "d1ddd983b82d3ad979c5ceba93369bc1039d77ffd076e97d6237db58a8f8a32c" + }, + { + "kind": "file", + "path": "img_1143.jpg", + "sha256": "d13406da9a388c690432bce2da3bb354e033629be488cc8ccc980635432badfe" + }, + { + "kind": "file", + "path": "img_3754.jpg", + "sha256": "882704f9a87e982beabe606e3a827da07eb4c38a8c55cb9dbe6f021a99bdcaa5" + }, + { + "kind": "file", + "path": "img_3032.jpg", + "sha256": "2939214e650213e6ce1a20cb5a65ce506b30da3008cc742548198643dc0665ce" + }, + { + "kind": "file", + "path": "img_1625.jpg", + "sha256": "5fe27da57193fd9fe09d8d7a4061ae69eaf6828d65c94d0da97f853f281c007b" + }, + { + "kind": "file", + "path": "img_1962.jpg", + "sha256": "5e1b6bb1ae853f0dbae31daea91d40e2cfdde4d8910f2f076685dd34d6afe179" + }, + { + "kind": "file", + "path": "img_982.jpg", + "sha256": "2ee8af2f107c1c08bb51b16370223caf3f130e2f4f46c8c87f058c08ab6551e8" + }, + { + "kind": "file", + "path": "img_3813.jpg", + "sha256": "f8ef9fdf393d065e177fae7ba2bba56d77dda1ca21fb9e769262ef0a8ebb611a" + }, + { + "kind": "file", + "path": "img_3807.jpg", + "sha256": "02237879634e869fc6e5b41d3bfe434cd6ccc2bbd1154bfba2fa40dd4c6a1f10" + }, + { + "kind": "file", + "path": "img_996.jpg", + "sha256": "97fa6b76ea6ddafd560908565597a1141bf3140cfe8ab755de703c23d9b0ecff" + }, + { + "kind": "file", + "path": "img_1976.jpg", + "sha256": "5dd8faaf5786221be166249734fe490037c7cd6442d9141ef410dcaa692a75a7" + }, + { + "kind": "file", + "path": "img_3191.jpg", + "sha256": "4f79be2fdcc4fed605779d08394124279ad3743b1c35d0e36c691d5f4f6ee6ec" + }, + { + "kind": "file", + "path": "img_1786.jpg", + "sha256": "372d584356d281605e1ce9a73f58c0e03959b733470c4e5facfb7509159ec545" + }, + { + "kind": "file", + "path": "img_1792.jpg", + "sha256": "02984c6373da7fab2a9ccc14b4c9b5166a00ba54410d57e3c2057a3c84ed09d0" + }, + { + "kind": "file", + "path": "img_4832.jpg", + "sha256": "837563ad51dea33c0b428e5cdda2ede20e2e4f922d3c350d3c9cc9e77ec6cb23" + }, + { + "kind": "file", + "path": "img_3185.jpg", + "sha256": "7a67b4ba7feb2a5a3eddf47719048863451a0ae2f08c87accc808ee77c81c4c9" + }, + { + "kind": "file", + "path": "img_772.jpg", + "sha256": "a2fcedfd17833f1d8635da906e5df0c65438dddd13ab61135811ebcb1a420122" + }, + { + "kind": "file", + "path": "img_4601.jpg", + "sha256": "9b3e384ff801b21b9e65e80ece2ec6f3b5ce447c75748d118bcbd584e41f78de" + }, + { + "kind": "file", + "path": "img_799.jpg", + "sha256": "6720e730aeee67fe13b1a49d4acf83c9b14ce1498c7f1d292124ca931b03bdcd" + }, + { + "kind": "file", + "path": "img_2270.jpg", + "sha256": "a25cb5a7bda1af53778e4f4965917b010088b94b5456f4e531cf506d66078344" + }, + { + "kind": "file", + "path": "img_941.jpg", + "sha256": "a4831585c038debdaef87007c54b5f056e9fdafe23f423535844127c7bcea02c" + }, + { + "kind": "file", + "path": "img_1779.jpg", + "sha256": "d09499a66eb23b6787a50b7ac3cc95df569ba24b96ac51d991263241e0f8a413" + }, + { + "kind": "file", + "path": "img_3608.jpg", + "sha256": "6464fb425d732382b7b7550d226e56b6c1bd42b0d1272d0d91ec7bad0cd0baac" + }, + { + "kind": "file", + "path": "img_2502.jpg", + "sha256": "d98c27db31eff96f23722ddb2247cea9bf1c0ab61f67635c57d28d391a83b240" + }, + { + "kind": "file", + "path": "img_4615.jpg", + "sha256": "b339729ed5b0f99da4da44d036124317623a0b13637cc8d11760599ff1ea7fac" + }, + { + "kind": "file", + "path": "img_2264.jpg", + "sha256": "8ca1af71567ad86ad888b610f20a74e7dbbb58defac3dd44368c33c6e81845dc" + }, + { + "kind": "file", + "path": "img_955.jpg", + "sha256": "6e7342b6d2825074f62809d37901ae03a1e575e79c3ad8b58f4575a8a5362ce2" + }, + { + "kind": "file", + "path": "img_1745.jpg", + "sha256": "6c06b28fe6d5525a716652053902fb25df6dcf2b5f83b0b32e73a4ecba31eb5b" + }, + { + "kind": "file", + "path": "img_3152.jpg", + "sha256": "b48eb68ebec63451e04bcc2c7096898491d4fbf385cd5bcb126d0ccce770f5e0" + }, + { + "kind": "file", + "path": "img_3634.jpg", + "sha256": "52bce1a5d6c2158bf455f930b3d3fc1c066aaeafc346440dd2bb5295852b9d76" + }, + { + "kind": "file", + "path": "img_1037.jpg", + "sha256": "f3cf6c6176baebc94fa484d74699c3ba5916e760bb7b608dbf4fd1a623774556" + }, + { + "kind": "file", + "path": "img_3620.jpg", + "sha256": "4b751e8bbc360fb2aacbc3fd47bee95ff4c64889cbfb3ee7e99cdb639ca64b2a" + }, + { + "kind": "file", + "path": "img_4629.jpg", + "sha256": "f8445fbb176ca040349580f039bc8a0e4a33a5a5aaa605f36bf6f03c24e559b4" + }, + { + "kind": "file", + "path": "img_3146.jpg", + "sha256": "50f3c579fff7b374f56c2eb77f198f8b52549924dc33ddef22573b2d289130ba" + }, + { + "kind": "file", + "path": "img_1751.jpg", + "sha256": "beace40853f4fae4eaa9f0ae9fea55571453eeecfe2fafc7df829777bc2f19e5" + }, + { + "kind": "file", + "path": "img_1989.jpg", + "sha256": "128d64c0dd16b14708a37c394d58e9cb13b421dd33029a2a393c2ee51d441505" + }, + { + "kind": "file", + "path": "img_558.jpg", + "sha256": "1011c2dc88cb044945e06c994408a56a353f71261acd9edc670adee027954d44" + }, + { + "kind": "file", + "path": "img_2933.jpg", + "sha256": "967a1deb9c80e802edf1514f5afc2e26bb2307ebb882a1537514691d752d4f23" + }, + { + "kind": "file", + "path": "img_202.jpg", + "sha256": "fd67047e85c3d962eb423f69aa5846d6e76ee7f7c72d8eac6d2ee37050a9e10c" + }, + { + "kind": "file", + "path": "img_564.jpg", + "sha256": "086cf36386f3b33e1feabed3ac91afd3a89e77d743d05cb0131fa9f1eec6d0fd" + }, + { + "kind": "file", + "path": "img_3393.jpg", + "sha256": "2ceabc2b8a668e12955f73eefa16659ee6e8c5ef6831ed8ad9e8726678ca240b" + }, + { + "kind": "file", + "path": "img_3387.jpg", + "sha256": "28fc500c72fe421b41aec622d6c3acca63d0b4f19bf7839fb2c880f45726529c" + }, + { + "kind": "file", + "path": "img_1590.jpg", + "sha256": "55ca4fb0dca58a927fbfa81b963c0a7c2556608cf37b97b0ae496e4d156c5f4e" + }, + { + "kind": "file", + "path": "img_2927.jpg", + "sha256": "adc4cbe5f676b6dbd4546e92a2989b48b44e552b87ac54cf0fae61b5938aef39" + }, + { + "kind": "file", + "path": "img_216.jpg", + "sha256": "d4b35c2c05e769798ded4b8b79fc63d145347841cd39f5c5052d2f98b8a50d8f" + }, + { + "kind": "file", + "path": "img_4365.jpg", + "sha256": "f94e78873eb2809b13f55021fca991a55643dcff0a6b034df91fbbc25eb5690a" + }, + { + "kind": "file", + "path": "img_2714.jpg", + "sha256": "5362edbf59af71014da83814004773435c1403413c83c48441f457591352156b" + }, + { + "kind": "file", + "path": "img_4403.jpg", + "sha256": "5302f5794e53be89406f48f711ca69e394ff3326664b5a3650eeee6ed79fab08" + }, + { + "kind": "file", + "path": "img_3378.jpg", + "sha256": "99b1388bd73279fb6a944cc6c18c28ab6e30dd99ed16f57132099055a4c99822" + }, + { + "kind": "file", + "path": "img_1209.jpg", + "sha256": "d1e28a0f4ba0d0366347b4bfb5289a854d05f8ff953bba325ee67a0ff0b2faa5" + }, + { + "kind": "file", + "path": "img_4371.jpg", + "sha256": "d87f443c67666f3da31c7409b412482a7c41ff4a89ef2b987a1644a93f41759f" + }, + { + "kind": "file", + "path": "img_2700.jpg", + "sha256": "23ac41958168e459e3082ef6c329c70f3c0156e1b6970cfd045677d8bdbe3b12" + }, + { + "kind": "file", + "path": "img_1221.jpg", + "sha256": "209907224b206777166e498a476b8173a8552d853769c4c9d87da63252dac3f5" + }, + { + "kind": "file", + "path": "img_4359.jpg", + "sha256": "652481739cecdf23f7bf61afb2077a0202ccb966a9d9a963c0ad081214c42810" + }, + { + "kind": "file", + "path": "img_3436.jpg", + "sha256": "48376a7829b39e91b358b7bd6b891d6670e54e1c034521f4e6c5a6dc78f7ee4c" + }, + { + "kind": "file", + "path": "img_2728.jpg", + "sha256": "9b86dda29c93fdbe311fe8a5b509897660f64c56a9828de5e552a663bd237db8" + }, + { + "kind": "file", + "path": "img_3350.jpg", + "sha256": "b04d66bfafad87d19dd2aa90acd57f4668c7f43343bdaa6bf0500727e56f6b00" + }, + { + "kind": "file", + "path": "img_1547.jpg", + "sha256": "15ca0a6d4f63f992fb772687505a45c8e12f6e57926fafd368870b22965a3e53" + }, + { + "kind": "file", + "path": "img_1553.jpg", + "sha256": "e25a360e0809725298f8f0a31a3fa65bf94483cb006cf3a8eef740cd4e34ff91" + }, + { + "kind": "file", + "path": "img_3344.jpg", + "sha256": "a03829290eb8f0bf6bdd6e31cc6397b11537aa2030fedf65e8a8cec973934267" + }, + { + "kind": "file", + "path": "img_3422.jpg", + "sha256": "d250a7432e47ab409d0cdede0504d2d81f67702dee5054293683ddc2e72df748" + }, + { + "kind": "file", + "path": "img_1235.jpg", + "sha256": "cfa7aba8871566a3c74c9a7a8bf67ae81a1507302bf0d9d64bc6d67c9d59468d" + }, + { + "kind": "file", + "path": "img_3345.jpg", + "sha256": "7c711f3724f6c92aab5dede79eba2b32616e1100c75eaacbf192bc9990ea2ede" + }, + { + "kind": "file", + "path": "img_1552.jpg", + "sha256": "8243427406c504025f67926ab580201132f633d7d378ecea31d7a6635144562f" + }, + { + "kind": "file", + "path": "img_2729.jpg", + "sha256": "535f4b7f7ab55a8629bc0c07e4312d5d181e31ec395c55cbc45fdf590d168425" + }, + { + "kind": "file", + "path": "img_3437.jpg", + "sha256": "26b7347d823f60b68721503aef8c73f50a2fb0b85fb4effe37b8205bae23a909" + }, + { + "kind": "file", + "path": "img_4358.jpg", + "sha256": "db2f78889660019571711ae5a4b91b75a9e5712043ceefb47e269de7d3156f95" + }, + { + "kind": "file", + "path": "img_1220.jpg", + "sha256": "33f7d08d91abb9df11e467146f2ad975ab0e77c4f96000a0132da1effe395745" + }, + { + "kind": "file", + "path": "img_1546.jpg", + "sha256": "d4c4d9888ace6adede7163b377ccdc56b278bda0c1fdd6d78d0095ddbf37481f" + }, + { + "kind": "file", + "path": "img_3351.jpg", + "sha256": "0db4d0f97a3bb4b0b6ba5d89b072d6d4c0949962b8253c6665af94d59ad796a1" + }, + { + "kind": "file", + "path": "img_4416.jpg", + "sha256": "0c38ac875f314a895d695aefde05276b4db84d33af78d1cd1615810a22b244c9" + }, + { + "kind": "file", + "path": "img_3379.jpg", + "sha256": "d34cbbac77ff64372589405e150ff6e641a2654baf1f54d5146752ed1715338d" + }, + { + "kind": "file", + "path": "img_2067.jpg", + "sha256": "d31f62fdd6af8561756be2f6358b21e372e23b9866bc92a67927aa73b558c530" + }, + { + "kind": "file", + "path": "img_2701.jpg", + "sha256": "1bf55b7f91b9644895016692d6d181a06b576ed3374b0928fc7e6ee8a7465017" + }, + { + "kind": "file", + "path": "img_1208.jpg", + "sha256": "a1b5faef4716552d9878a31da86c59d323a8053b9a0d489ec2b0642fa9e57e40" + }, + { + "kind": "file", + "path": "img_2715.jpg", + "sha256": "de6a72d8c1e2a39d113c97ba7ffe09de6b8af459e7b7d76378e578f5994b5abb" + }, + { + "kind": "file", + "path": "img_4364.jpg", + "sha256": "56328c182df8fe3df71e976ea7dc66e9fb58b90d1bf89ee80e2975892115632c" + }, + { + "kind": "file", + "path": "img_4402.jpg", + "sha256": "244c94a4732960160048685d0af24227658615361520d3deea80c37fe4fc145b" + }, + { + "kind": "file", + "path": "img_2073.jpg", + "sha256": "729893b2870d6b9f3af07e18bcbb36da4bdd06f1b56b91b0d327137fb7adb5d4" + }, + { + "kind": "file", + "path": "img_3386.jpg", + "sha256": "99e65c239912d8b40730dc662bcee92afb29d9b09b8890eb744513570ca00b59" + }, + { + "kind": "file", + "path": "img_571.jpg", + "sha256": "6f3a652d4e1dbc075557053a068de111a4289f5c3eab764b45ee10e966e8f4b8" + }, + { + "kind": "file", + "path": "img_217.jpg", + "sha256": "dfebcecfaed9bf2721e3dc173332bb71a726b30985df84ec178dc417c7e51801" + }, + { + "kind": "file", + "path": "img_2926.jpg", + "sha256": "15a46fcae677bcc686551c5e1a7ab90198da6164cf092e08dad46fd289bbbfae" + }, + { + "kind": "file", + "path": "img_203.jpg", + "sha256": "9c19f1895cb0b186860016fe2b215cf4ccfb38db1daf0836ca4af7a035ffc235" + }, + { + "kind": "file", + "path": "img_2932.jpg", + "sha256": "ba0ed88429ec31ecc5a6b4910543d2531a783c7d7d3aa68ba904cd206efe3c68" + }, + { + "kind": "file", + "path": "img_3392.jpg", + "sha256": "2bf3f7eecea8b54a66d6c82ac26234bf89b6a408ba25631946d9b5dd5cd3cc57" + }, + { + "kind": "file", + "path": "img_565.jpg", + "sha256": "df6214b01d0342dbbda264333ce4e0579b893d39943adb1f74daec200f2a2216" + }, + { + "kind": "file", + "path": "img_1585.jpg", + "sha256": "5c99acb8d325d225f79781daee2ad20d87ecb590397f2e935cd14725c75d041b" + }, + { + "kind": "file", + "path": "img_559.jpg", + "sha256": "29159aab385f9878ec6635d1b1957c0a8c30791896474752c0a58b91590dc525" + }, + { + "kind": "file", + "path": "img_3621.jpg", + "sha256": "427f198df438fad318fa98805afbb2d42810462f54da78fc0409bd59b6262fc9" + }, + { + "kind": "file", + "path": "img_1036.jpg", + "sha256": "b7cf3d9a56ba259057a3304a659d0e307153bca50689fcd00acc4b87b212693b" + }, + { + "kind": "file", + "path": "img_1750.jpg", + "sha256": "7de6d692bc2a7fb00b6cd751762fb1cd5412e8afa696965f6ed93947c74eca55" + }, + { + "kind": "file", + "path": "img_968.jpg", + "sha256": "c6ab825fcb50b37a341c3881fc6bb142970c6bdafff3ca83741d3499af7e44e9" + }, + { + "kind": "file", + "path": "img_2259.jpg", + "sha256": "2e7ffc1cf7c9171770cbf0d29653b1da39f6e1038a8dddd355b7ac7e3a418478" + }, + { + "kind": "file", + "path": "img_4628.jpg", + "sha256": "7aa0b4c38ea0b96a780e86e473af69f3ef72d6cbe6f01928144cfd52f00704a5" + }, + { + "kind": "file", + "path": "img_3153.jpg", + "sha256": "99517aa15011c2adc4ea5f68cd4095a3e37816e3dfc1b348a858672596e882b9" + }, + { + "kind": "file", + "path": "img_1744.jpg", + "sha256": "01f19abba01de339026f24efe0f2a1ce2556f4c5be5300edf6bb3c1825657b04" + }, + { + "kind": "file", + "path": "img_1022.jpg", + "sha256": "12dcf83e5f6c997c521a0753cf2e89c7ae273d41416e84010f83905434668a24" + }, + { + "kind": "file", + "path": "img_3635.jpg", + "sha256": "dc6adfccdbfab42301c435a6d7ecd41e21fd784bbf7a57172a482a97a466d50a" + }, + { + "kind": "file", + "path": "img_4172.jpg", + "sha256": "d9f8ce210b6e77db8d546bc70fa08ee0f22b3d4392d006d501d773affff5d945" + }, + { + "kind": "file", + "path": "img_2503.jpg", + "sha256": "2f2c5bee3b7238c0bda0f0e1b0eca045cd3d3e18c7ad071d766bc79ac1a879b6" + }, + { + "kind": "file", + "path": "img_2265.jpg", + "sha256": "207e3ff4dbb9c158719157e55acaa3ce9424a17e3116f256a636bca79b7d52d1" + }, + { + "kind": "file", + "path": "img_4614.jpg", + "sha256": "ed776e7d66a84efa3ac38feb95321b6778380b348e465169c8b87c33bffddea8" + }, + { + "kind": "file", + "path": "img_940.jpg", + "sha256": "8ad7a5e9017e0ab1026e7b182ba195d693e182af49d949c58dc3915442aaf5a8" + }, + { + "kind": "file", + "path": "img_2271.jpg", + "sha256": "f38e3052dfd2c384ac65bdfed44f81af5b8e56326c359a9838b548b2b1dfb9dd" + }, + { + "kind": "file", + "path": "img_798.jpg", + "sha256": "60a647aaea2160d10e7326376035cc34a0f1e49635f082fd1af146744cc40fad" + }, + { + "kind": "file", + "path": "img_4600.jpg", + "sha256": "38bd8b94bb277598d94f4af3faa28df7bf9c00f8dba2c0db93efc41b7e077382" + }, + { + "kind": "file", + "path": "img_4166.jpg", + "sha256": "308f7ca78c9b744df590b3ec4bda22590583e29f0760d18189ccb65403ab1fcd" + }, + { + "kind": "file", + "path": "img_3609.jpg", + "sha256": "5ed80bc53f9efeacab76f7295682c8d7840cb2aec9103a428ba14fac9db1100c" + }, + { + "kind": "file", + "path": "img_2517.jpg", + "sha256": "04c79bfcfcd4de24c3575882b2bfc99b1b7ae515a65468e60a123bf0782a7c3b" + }, + { + "kind": "file", + "path": "img_4833.jpg", + "sha256": "4b9d8161cbd1bbb5a0771a38daafe2f4f4175ab17a198a6ca6a9260acbe88057" + }, + { + "kind": "file", + "path": "img_1793.jpg", + "sha256": "b13da581b80ccdfac276e4d04cb26f5a61559a24eea4504a707385017b63835a" + }, + { + "kind": "file", + "path": "img_1787.jpg", + "sha256": "15c08ab55112d6868fd3b6b0cb87eb699a923a41ce622294aa1aa7173dd587ac" + }, + { + "kind": "file", + "path": "img_3190.jpg", + "sha256": "8a340ef2ba4f1ed424f217bd501505b196c7921da4034c1472e81398e495e758" + }, + { + "kind": "file", + "path": "img_4827.jpg", + "sha256": "3c6b4f1342e3a5be5c0a843b773b6abbb14e7f1562e58a37d0ab64797f5ce08b" + }, + { + "kind": "file", + "path": "img_4199.jpg", + "sha256": "2a49cfb1c569f88b72cd7dc76a95b7b7f16dc12e62b53f47302f9d0bf7687db3" + }, + { + "kind": "file", + "path": "img_997.jpg", + "sha256": "233e5221a50ae83d436073d1b672497aaf85c728cb20efaf73098c8676695127" + }, + { + "kind": "file", + "path": "img_983.jpg", + "sha256": "af96bd81ea615c2f58107521b5a53725773a7d56519eb0b7c4e640e35b9593b7" + }, + { + "kind": "file", + "path": "img_1963.jpg", + "sha256": "0d40e21310fd9b4113227e2ee297ef6ec9a877b98ed9c771e50b1533ef484528" + }, + { + "kind": "file", + "path": "img_3812.jpg", + "sha256": "6d208e8578710b3209cb4885d8ce0b8a48823cc189482e61b0ef08ccbf89b594" + }, + { + "kind": "file", + "path": "img_3755.jpg", + "sha256": "9334feb0336352ec7561f52f29791d58807aa13280e87ef9d4e3cacc0f8d6ea0" + }, + { + "kind": "file", + "path": "img_1142.jpg", + "sha256": "13eba7c1dc8793fe4f8cc110614671e8a430dbf89b24e4d80d8c19a316a88dd3" + }, + { + "kind": "file", + "path": "img_1624.jpg", + "sha256": "08371c9fb235913b2845583b04b96ded074d691ffaea8618228a294339aa4c05" + }, + { + "kind": "file", + "path": "img_3033.jpg", + "sha256": "376e9346c4e567f4149bfafd92d3e2b1443a8b2d341d5de35574860cf4bb4211" + }, + { + "kind": "file", + "path": "img_4748.jpg", + "sha256": "cbe80721f37976063024fb2ef70561af5386ab11715bf4ba9ab68d36e121e4ba" + }, + { + "kind": "file", + "path": "img_3027.jpg", + "sha256": "e851cb21b57de0e5191ac4b8f74737894d5ba0f2f690ae164ed83504f0ea7b48" + }, + { + "kind": "file", + "path": "img_808.jpg", + "sha256": "6a72725f628fbf964c034177d77a8a4e06ecf37eda7e6af43d5302e715b5511d" + }, + { + "kind": "file", + "path": "img_1630.jpg", + "sha256": "5d01d028a4d4ac315dba11c3fd6b1a443bf2872b514eaaa795ef16ef95187efb" + }, + { + "kind": "file", + "path": "img_1156.jpg", + "sha256": "10a0300a3abcc19ce9f60a5da19e602333bf052782791b33c8475d106f57efd9" + }, + { + "kind": "file", + "path": "img_3741.jpg", + "sha256": "596f7db9559ee0ba1ed82d19308c7291fa833de0ef10dd0e08d35cd31e839d67" + }, + { + "kind": "file", + "path": "img_2477.jpg", + "sha256": "01894857d8130a3dceba262b016ecd10bae19b39bed7c51023cc29b0b12ad26f" + }, + { + "kind": "file", + "path": "img_3769.jpg", + "sha256": "c0ac2b910b0b819fa00d2453cf2b9269d6ab63f69e9e0b9d40d96c531a2766af" + }, + { + "kind": "file", + "path": "img_4006.jpg", + "sha256": "c71e1921c0b8c1691ed9bef95db3ed03a8a0ed4ddb824c5f222c8258bde8884b" + }, + { + "kind": "file", + "path": "img_820.jpg", + "sha256": "996dc1df972a68e3eb1ab9dc2cb387c165ff700f635ddb97a8ae1b5324ef093f" + }, + { + "kind": "file", + "path": "img_2305.jpg", + "sha256": "773c003625b8dcec50a932cca702d4a301a3062718dc4ecec81c8d750c550599" + }, + { + "kind": "file", + "path": "img_2463.jpg", + "sha256": "79e248700f275445ae7470caa8d2664faa728e04842a72b77d293c7160654813" + }, + { + "kind": "file", + "path": "img_4012.jpg", + "sha256": "b72ed8ee4a5541b73ca13043d5a91068b7e427127f8f3d33efad10af564feae0" + }, + { + "kind": "file", + "path": "img_161.jpg", + "sha256": "525d93071b0e9df0b9622b54ab76ef8b5d5f1caf5a8780894fe4722e0a33aefa" + }, + { + "kind": "file", + "path": "img_3796.jpg", + "sha256": "ed5e8f565017af90ab8394083caef4515db1ef2a1487e37bbd4f361f315a3f7f" + }, + { + "kind": "file", + "path": "img_2488.jpg", + "sha256": "fe64587ea133d27bd329db93f74a68a3c7372999f16466b599000ad7b578292c" + }, + { + "kind": "file", + "path": "img_607.jpg", + "sha256": "33d90cbbb78edb82e69f6ef64346c8462fb4062b18094359f66f4eb4fed24cad" + }, + { + "kind": "file", + "path": "img_175.jpg", + "sha256": "0242120b6dbf311d51853ca5a3b2e1cc86d25dc87d1ac95fbd8fdc567e8514dc" + }, + { + "kind": "file", + "path": "img_3782.jpg", + "sha256": "2229107123ed4c534cb8cf445d98e30b048a87e9a7ee6d792778fa1059e07d23" + }, + { + "kind": "file", + "path": "img_1195.jpg", + "sha256": "9bd71de3f871be69e4b73b4199f636bfe70f198ad8703d7506f108b831a8a5a8" + }, + { + "kind": "file", + "path": "img_3972.jpg", + "sha256": "7b6f911f46cb81f88fa7b60bcd0877588cce5536c016eb04e4a2b89dfcc81a05" + }, + { + "kind": "file", + "path": "img_1803.jpg", + "sha256": "5145338c3d1145b91ff27ccf8a3bfe955798c7d90fa93575f6af8ca550750caf" + }, + { + "kind": "file", + "path": "img_1817.jpg", + "sha256": "9ae7fea0453c219b584eee9a189d6523254c134b7ccf561de28e5ccbeb4b7dae" + }, + { + "kind": "file", + "path": "img_3966.jpg", + "sha256": "e8b47cdfa23126defa1c865dacd05830f45ef49b3f89c2e43e0ca380549b9eb6" + }, + { + "kind": "file", + "path": "img_3231.jpg", + "sha256": "d7cbbbf5705aad5618d63dcd63a788188a3bc5a680ea09ea7b6518560d30b01b" + }, + { + "kind": "file", + "path": "img_1426.jpg", + "sha256": "9e1764677796aabbdd2b9435d66faf64343da327ec21574b8bdcb90e2348ba8c" + }, + { + "kind": "file", + "path": "img_1340.jpg", + "sha256": "7784286cdf0bfaba887aceaa549a2122dab69e5d9636238c6be80baa4760d54a" + }, + { + "kind": "file", + "path": "img_2891.jpg", + "sha256": "8c4c3b8ae78628bd60fe02681984ae64c7dd1e36a359d2a01b63013c661163dc" + }, + { + "kind": "file", + "path": "img_4238.jpg", + "sha256": "6af4ad3ccfc573bb940e53f8b9b14df70da2a62cd53edbb03868e6dde0d24994" + }, + { + "kind": "file", + "path": "img_3557.jpg", + "sha256": "852dfb669fd21b4a68c789199288f9bffae0e726ee6497ddbec31ae9ba8ef26b" + }, + { + "kind": "file", + "path": "img_2649.jpg", + "sha256": "5d7e1b6e3ac9ad5f7f530abca64c2a913aff47aefd487e733ec00031936e9f8b" + }, + { + "kind": "file", + "path": "img_2885.jpg", + "sha256": "6324d798687d9d160418e0458e25b31b28594b36163aa20eceec1bbfe53be4bb" + }, + { + "kind": "file", + "path": "img_3543.jpg", + "sha256": "e6a6748bb0b22e81d9fdcada3dfae6827f2fb0467ba1b030eba847951f4c7687" + }, + { + "kind": "file", + "path": "img_1354.jpg", + "sha256": "af87beae7d852de4880fc710ae5a36d0b47c58f2b73715f7db0fad281b82f084" + }, + { + "kind": "file", + "path": "img_1432.jpg", + "sha256": "a9d2e499b74b0ac48dadaee5c3969407fc001d4d3d03aff8482b4c2c030cc491" + }, + { + "kind": "file", + "path": "img_3225.jpg", + "sha256": "2a4e70e2fa0b284ecf8bc9b3e9814e4dc24e6674476eaa820460345cd2f7de6b" + }, + { + "kind": "file", + "path": "img_66.jpg", + "sha256": "bbb7a5edec555883ff2ef86656e8f1260fea2f3d5a1afd9add5a11ea83f1ca29" + }, + { + "kind": "file", + "path": "img_2113.jpg", + "sha256": "6e198c1bf0d98753b101672e3e867e9a1effc15c9fc8ab9c5a0cb66ba068b4f8" + }, + { + "kind": "file", + "path": "img_4562.jpg", + "sha256": "ac18ebb942562cd1b28636c9f7e5a2f5b97909558a9aa3ea8d2e5724a8d0ed43" + }, + { + "kind": "file", + "path": "img_4204.jpg", + "sha256": "6d49d10d193ff19b9cca1fad51bd7076c0d56d7b3407b8da74a3aacf9fbf8a58" + }, + { + "kind": "file", + "path": "img_2675.jpg", + "sha256": "63b867a1efa37876416bfa892c670af99b937ea2e8f3bab1150c97f460c4c607" + }, + { + "kind": "file", + "path": "img_4210.jpg", + "sha256": "2715521ebee5e5af6eebe8aa6a7029615842a27dfdc3a09066f70ce3eccb003d" + }, + { + "kind": "file", + "path": "img_388.jpg", + "sha256": "6ee489951fe60494696b81577d74ebb3510b2992d17ac44bd3384760f2c3c239" + }, + { + "kind": "file", + "path": "img_2661.jpg", + "sha256": "c761afd81013057e6f2239c3d06c1569e54407bb8c962fb46e64fc4b406b359a" + }, + { + "kind": "file", + "path": "img_72.jpg", + "sha256": "3dd9b7fd9b33cad787becfbdb0bd0ba38d8b66eb9786aa3ca48bcd131ed409f4" + }, + { + "kind": "file", + "path": "img_2107.jpg", + "sha256": "32be20efae3df56cef39ce0d9f7c03cb8a093f6e249ed93d0d80ed4b3077b6b4" + }, + { + "kind": "file", + "path": "img_3219.jpg", + "sha256": "b3f7adff5866d51c286f7363cc951b4c9a5fe7a072610f9d1b966b9fd54d7c90" + }, + { + "kind": "file", + "path": "img_4576.jpg", + "sha256": "5cc8ca49a8b564e0bc7c0ddc589c738135603cb4a6b0468d91a3594120b15410" + }, + { + "kind": "file", + "path": "img_405.jpg", + "sha256": "61565b3b1e77c40c3bd6466d7344999720ca9d4c6c60a92498e8697ed02405c7" + }, + { + "kind": "file", + "path": "img_99.jpg", + "sha256": "0f52425ddb0fa2f08762eddfce8670595fc02d3d012c5169373dc86981358cd4" + }, + { + "kind": "file", + "path": "img_2852.jpg", + "sha256": "71750b5ecf7b75575169ded58a45b595f5f8c5582ec1d22e6207e86cd473ea07" + }, + { + "kind": "file", + "path": "img_3594.jpg", + "sha256": "ed15a988703ecb2d2f03d5f7b835c882ca3fa5b2e4ccafbfba43e5384bcac45a" + }, + { + "kind": "file", + "path": "img_1383.jpg", + "sha256": "087d03e18fa7eef53f2d7b4b64c0bf1f7cbf7b48ab249c251b227dd523a88cd9" + }, + { + "kind": "file", + "path": "img_2846.jpg", + "sha256": "28c1eabcb2f9de0b2ae039b8ee824456bd656ff50de1557854f825e95f04412d" + }, + { + "kind": "file", + "path": "img_3580.jpg", + "sha256": "e19d4831569e11ac2dfe0e16e03869a3368924f48164d1532d549e021ed046b8" + }, + { + "kind": "file", + "path": "img_377.jpg", + "sha256": "51bf2a68298632f701ec8c75906a8743670000aebd49e0a5be6cfd2cccb1740f" + }, + { + "kind": "file", + "path": "img_439.jpg", + "sha256": "9c26b6919bcb2ebd599456132e4421aa9ffaabf28409a1d4ece6cfa5168d9e31" + }, + { + "kind": "file", + "path": "img_1381.jpg", + "sha256": "768fac316ec6acf8686f2e037da7a1fe2af9114be2b93ef924a20dc7ac2ef25e" + }, + { + "kind": "file", + "path": "img_3596.jpg", + "sha256": "0f56e3ca948ca0ce23851d678c21064f11d57f460647a4bb3cd48cc16e24ba22" + }, + { + "kind": "file", + "path": "img_2850.jpg", + "sha256": "e15a6db899a3955a8b69b42b014274e8ca5636bc1e1e1a265299982e13b40af8" + }, + { + "kind": "file", + "path": "img_2688.jpg", + "sha256": "76ce6f3f9657e7e4da2c59a55ede736fffda24c6dcff4daa8dcba00cc89084ac" + }, + { + "kind": "file", + "path": "img_407.jpg", + "sha256": "69edb2cd98bc81c6cb5d733ad1a6bde627da7cc944957c5b9994b03625950f70" + }, + { + "kind": "file", + "path": "img_413.jpg", + "sha256": "d9823c392a84d1171b061ace21a97fa9853cf8be7b30b31894e4738569903492" + }, + { + "kind": "file", + "path": "img_3582.jpg", + "sha256": "64e7bf366f4ad9737fd9647c2a7e97e5e2e92e9f788b07f144fcaac6dc874a61" + }, + { + "kind": "file", + "path": "img_375.jpg", + "sha256": "b158ba96b8fa1bb934277c85a2ebef830c587d0bd3601a83b51ea53a26ff6139" + }, + { + "kind": "file", + "path": "img_2844.jpg", + "sha256": "131005192022c499d3ed68bf9e73950a9bf9d397a42f435c43e4f1d40daca270" + }, + { + "kind": "file", + "path": "img_1395.jpg", + "sha256": "3439e6daee6d46b8002f9670594b22557754a3803d6b3a2eed4a71011f7fc485" + }, + { + "kind": "file", + "path": "img_3569.jpg", + "sha256": "55f8cd3bad0ebb33dfd65cbca9e4b0a79162f0503ebf851cdeb40feef2cf772a" + }, + { + "kind": "file", + "path": "img_4206.jpg", + "sha256": "9339acef612c019069157565fc9891c5b67e402a39aec15dcdfaab46e4d22068" + }, + { + "kind": "file", + "path": "img_4560.jpg", + "sha256": "43a43d81157b3b1a3015386edde6afa3e1085132a623c2dec4fb703e1855a441" + }, + { + "kind": "file", + "path": "img_2111.jpg", + "sha256": "60208c869289f51df99369e75b36ae6f280125630b7e51cd1f65f1a1cc64f50e" + }, + { + "kind": "file", + "path": "img_64.jpg", + "sha256": "2feb4deac7e69ffc8ad19a1b3de9b778e4f58a81518e5bcfdb1a3af07ae1ea16" + }, + { + "kind": "file", + "path": "img_4574.jpg", + "sha256": "b00354c1fc0e1609fdf222be8e6f26b0cf34fc71b55782a55e6f64e288a2871f" + }, + { + "kind": "file", + "path": "img_2105.jpg", + "sha256": "51d7c9ab38380656ff8ef553ae418c875794f3201d17696abfc1b7a9d84eceb8" + }, + { + "kind": "file", + "path": "img_70.jpg", + "sha256": "7411d754e62d2e49f3adebf1fb8fdd1a0c89cb925c88a021e4694951167aae88" + }, + { + "kind": "file", + "path": "img_2663.jpg", + "sha256": "92188a575f432027a776e701abd0f4c48f9a84d0493d733e09c97078979fd5ac" + }, + { + "kind": "file", + "path": "img_4212.jpg", + "sha256": "79dd080aebbcc03fe6f7eb5b87836367e9b271aa98aa51bda443ada32f2f0f85" + }, + { + "kind": "file", + "path": "img_3555.jpg", + "sha256": "294f9a1f188a4f4df9c97999a7a0a21d0a7679b49ee535cb5e709468a552d59d" + }, + { + "kind": "file", + "path": "img_2893.jpg", + "sha256": "75278d1fb186c775f41fcdcb9aa321e6851c30179a2203e7037cc36de2b67c32" + }, + { + "kind": "file", + "path": "img_1342.jpg", + "sha256": "894850dac66e6365f0863e7b11d774bed0a98c320148a2b92ab811da7947cd0c" + }, + { + "kind": "file", + "path": "img_1424.jpg", + "sha256": "2147c4bf3acd2013f4b6d8a6146951b73dc04f1c779375682108021a320fac2e" + }, + { + "kind": "file", + "path": "img_3233.jpg", + "sha256": "367d3b2a4af0cdf9b7839a143ed76f7cdc82b0595a25da4291d368a6c90e966f" + }, + { + "kind": "file", + "path": "img_58.jpg", + "sha256": "849d7c06e990211c9d3f6175773ad9cac153a8f9fdcaf7f1724c66f2f48307d1" + }, + { + "kind": "file", + "path": "img_4548.jpg", + "sha256": "9ccb4c31d5242f924c70ede09c2c6ed1059201d1b5af85ff33a81bef057d5738" + }, + { + "kind": "file", + "path": "img_2139.jpg", + "sha256": "5d54497a965d6be52b5592d3011dd2348bb682a0394cb04e9d8d5d1526d1af1b" + }, + { + "kind": "file", + "path": "img_1430.jpg", + "sha256": "5286799a0fb412416c964b80f4105f25cb7866f6678d9e0b8f4da29c71540464" + }, + { + "kind": "file", + "path": "img_1356.jpg", + "sha256": "377e95237066753c48441f2fbd97ea44085ecef600b41690173465254ffe3077" + }, + { + "kind": "file", + "path": "img_3541.jpg", + "sha256": "d746df6114d97f11600a07d44ba4f46eba076a44348d7e50da819efb5e8e9368" + }, + { + "kind": "file", + "path": "img_2887.jpg", + "sha256": "bddaa7c93113bb1ec31fbf681316ffc7c2d9eae01eb5937ea541a8c577556301" + }, + { + "kind": "file", + "path": "img_639.jpg", + "sha256": "11afd2bbd7bd0b8efc5748e47a4851c2b00c49526d761da93f73150bcecec194" + }, + { + "kind": "file", + "path": "img_1801.jpg", + "sha256": "889609886ce5a8e1d7b57c075ce79d367a0df5bfb37501bc7d5bbf1f6d115255" + }, + { + "kind": "file", + "path": "img_3970.jpg", + "sha256": "ddbd3ee6c35e36331e5a9826a08761ea4456efbfa08fc1780e95e7c7b266095c" + }, + { + "kind": "file", + "path": "img_3964.jpg", + "sha256": "6ed56e40f7f744616b1b170469bd998eeab44079cf6c04769d2da4a521b6f4a7" + }, + { + "kind": "file", + "path": "img_605.jpg", + "sha256": "ce0010c107b267677081e8426e3a048e584e192070902f95f1e51462eda6818a" + }, + { + "kind": "file", + "path": "img_163.jpg", + "sha256": "1a1332808b0b58fe61d8953c383b6b9883e4c4959e522adbb0e33181aee871d1" + }, + { + "kind": "file", + "path": "img_3794.jpg", + "sha256": "94cf06f49160f715b29bda50bb137e2b4c72a2b1b061b905831123287ccf7e30" + }, + { + "kind": "file", + "path": "img_1183.jpg", + "sha256": "6491bd75f5de19b8eed2141bf695a0fc267910a76b5c3f480adf2a296a7831e6" + }, + { + "kind": "file", + "path": "img_1197.jpg", + "sha256": "d7e6d002925117389f1a37219fae7cd8a15ac4a76ce6ace023027376eef64945" + }, + { + "kind": "file", + "path": "img_3958.jpg", + "sha256": "c5ec955e32bbd7ce15b94dedba2b948d103c75cf3d87eff3f7edf13dc121a256" + }, + { + "kind": "file", + "path": "img_177.jpg", + "sha256": "fab67a58e781cbe2124742c87d91845e0f496728f3edee9e5f6c94203dd53325" + }, + { + "kind": "file", + "path": "img_4789.jpg", + "sha256": "ebacf310ec3ee16e51623588a5b784e31f802769bd14eb0f6876e242842134fe" + }, + { + "kind": "file", + "path": "img_1829.jpg", + "sha256": "52daeb09d15a7c482bf2d8ded13ed77264c841966c4f7fff158cceea8dfcfc1c" + }, + { + "kind": "file", + "path": "img_822.jpg", + "sha256": "93e4b01dab1db80b1f302a5370e0c36ee5d8f6ab55a4df420620be8db73735c8" + }, + { + "kind": "file", + "path": "img_2313.jpg", + "sha256": "ca47795e160fcbebb1eb3c20954c67a7544c90f7d0e147dbd34cab157694ffdf" + }, + { + "kind": "file", + "path": "img_4762.jpg", + "sha256": "ba53e22c60292d314135c89c31d78502cab682be0c0f3083a461fa8848920463" + }, + { + "kind": "file", + "path": "img_4010.jpg", + "sha256": "2e224c3123d3355e3f9ec7f8ec1f8992043d31a8d60c2c697e21a079a0f365f7" + }, + { + "kind": "file", + "path": "img_188.jpg", + "sha256": "e29b101578ec30f6b49366b748ca313aa952afcbefb2510a011aba16f8bff304" + }, + { + "kind": "file", + "path": "img_836.jpg", + "sha256": "ae8b8495167658098085e679b56fa057082d2c86a4dadb212657beb536ff6804" + }, + { + "kind": "file", + "path": "img_2307.jpg", + "sha256": "0c4f7d953ef86775e3fdfd3cd06d2382d872506ef9f65f5bd734ec88a5789373" + }, + { + "kind": "file", + "path": "img_4776.jpg", + "sha256": "2a24efd9ff2b22ac71bef918f95fd3eb86eca908e8ebfaa8e87187ef2bb7699e" + }, + { + "kind": "file", + "path": "img_3031.jpg", + "sha256": "8c336786aaa2a45278a03e26993f519fce06542d0d17a9ec94a57ec7b6845ffc" + }, + { + "kind": "file", + "path": "img_1140.jpg", + "sha256": "5cf2fd396e72c81b2a3dcf4a1be93804906665f6a0cecd8b44588561e46239c1" + }, + { + "kind": "file", + "path": "img_4038.jpg", + "sha256": "36da967d9879602869e53c1b23eb9482545b5517b4aebf68db795621b8cab20f" + }, + { + "kind": "file", + "path": "img_3757.jpg", + "sha256": "9c5d4e80951ee86e044fbe210b3f071aa548d7d708f9be48d5530c3698a13099" + }, + { + "kind": "file", + "path": "img_2449.jpg", + "sha256": "e30bc994c4d9696cbfacfc8bec54a8116b9c4309a5454a848dbeb279562bc944" + }, + { + "kind": "file", + "path": "img_3743.jpg", + "sha256": "d9fa65a242e58defe28d6d1624a16cf00a3dad152a72a4d5df03ce4b3b152cae" + }, + { + "kind": "file", + "path": "img_1154.jpg", + "sha256": "5b0ade4d80dec124770bdb374f2f93587cbced7b86f766ab97e321403377b4f4" + }, + { + "kind": "file", + "path": "img_1632.jpg", + "sha256": "f44c391c53bd6fd6763258f392af24a2ea57c0c72002265a984bb4787529ac2b" + }, + { + "kind": "file", + "path": "img_3025.jpg", + "sha256": "113905631f35510b40ed154b8baa4f7bdf4f5168b2e3db9089fe22531cab4a7d" + }, + { + "kind": "file", + "path": "img_995.jpg", + "sha256": "6e6c4cf2bf051d1e1e7988a413a54213c68781d20a9633a60d3bfbb8ea2eaa5c" + }, + { + "kind": "file", + "path": "img_3804.jpg", + "sha256": "c390d45ab7b26173ef4250fc2039cbbbb40340f1becb52e2ba92ffe3b3073a42" + }, + { + "kind": "file", + "path": "img_1961.jpg", + "sha256": "c48271ff33ecfafc28cc0062250ba3c364c3e6fdf7554cecf8072b34b11b20ef" + }, + { + "kind": "file", + "path": "img_4819.jpg", + "sha256": "5dadb83d8ccc9cbd5ccdbb7d4de91d0e9a2c74b2f83e430a016b6b66f2557eed" + }, + { + "kind": "file", + "path": "img_981.jpg", + "sha256": "23e6d4437375383c15718ac0627954422f98c5c92276d3c631b09a28d57444f9" + }, + { + "kind": "file", + "path": "img_759.jpg", + "sha256": "52e550135a6bf3e930e63f7a1d5fffe8e975ed589d2219e9e3a8f600608a3642" + }, + { + "kind": "file", + "path": "img_1791.jpg", + "sha256": "0b939526dfa152505c63fcd1d35bd069ccdb643c1317b8a85c279823bc7dc269" + }, + { + "kind": "file", + "path": "img_2298.jpg", + "sha256": "7a7cf7701fa2c7ed93fc18ac10c27a0852af4ee953f7a5031055e26c6b89ef72" + }, + { + "kind": "file", + "path": "img_771.jpg", + "sha256": "4f95cae0e2af0bf6eb645afc79d1eb52e8d5b12f8c9e1ff08d2348a9afa86a5a" + }, + { + "kind": "file", + "path": "img_3186.jpg", + "sha256": "d1f11d0d77179ed87b049a9505f5fadf59afb2732e5a3375374613dda16e23f8" + }, + { + "kind": "file", + "path": "img_4825.jpg", + "sha256": "41d91b78c839c7e880067f3f79885295fc104b941037641cd883b5578094f1a6" + }, + { + "kind": "file", + "path": "img_765.jpg", + "sha256": "6399bee9db09d789cfd33b8e6b0caac6daca4ef063bfc18636eb1231ce6c2ca3" + }, + { + "kind": "file", + "path": "img_3192.jpg", + "sha256": "43c728cb86622c96ebc00fe3d6e83b3dab340232fb9eb9ad0fb6d04140bdce40" + }, + { + "kind": "file", + "path": "img_1785.jpg", + "sha256": "efb0c052342f9fd5f134e12c3103f69ea20cd5da4431451934836a0a2899540b" + }, + { + "kind": "file", + "path": "img_4616.jpg", + "sha256": "57fb69f4f03869058171a67402a9ed963e994a83efb9339408389a1760cd879e" + }, + { + "kind": "file", + "path": "img_3179.jpg", + "sha256": "03a26f19a50d78580b3e5f35f6003943b8938c50f097c0cf6a2c9b3dd4c8a790" + }, + { + "kind": "file", + "path": "img_2267.jpg", + "sha256": "7fe60a43aefcf42aedeed04055d4efc6f66602152be43b6709ac8253ce2ca8c8" + }, + { + "kind": "file", + "path": "img_956.jpg", + "sha256": "f3adc9090e3995a47cf2b0410cf6f66c100a614159ddb13320321a4fea8d20cc" + }, + { + "kind": "file", + "path": "img_2501.jpg", + "sha256": "2cfccac9e334eb79cc642bf6d6a46ba35ca4ac780df369bc644ec4fea12d8d57" + }, + { + "kind": "file", + "path": "img_4170.jpg", + "sha256": "fec9854fe7ea45a1358a94e2d18f800de26a25703376828219b8f86d98e31633" + }, + { + "kind": "file", + "path": "img_1008.jpg", + "sha256": "e9da496c2eb45c34506b134e8deaadaae7e3fe3864b86a0d014bdcb40a2a1449" + }, + { + "kind": "file", + "path": "img_2515.jpg", + "sha256": "1929b5d68dc9f230df550d1305faaf985c55f9db9fc0f998d3695d1934f91b52" + }, + { + "kind": "file", + "path": "img_4164.jpg", + "sha256": "e07240ecf5f14d6346d0842734691c1718dc61746283c9b8925445ed62bcf4c2" + }, + { + "kind": "file", + "path": "img_4602.jpg", + "sha256": "bbb7d32f7e374d08504db36f9b2569f0822e159b6d5dc258720ef5e8b7dd9bd0" + }, + { + "kind": "file", + "path": "img_1752.jpg", + "sha256": "011cf0dce97ecc1d418d17ea300ad53ddbfda30d0296e954668ff7e4a8293ef8" + }, + { + "kind": "file", + "path": "img_3623.jpg", + "sha256": "0a1554164c4ac73a05a9035e94aceb17441ee8b056daf3daca81baeb80cdbcda" + }, + { + "kind": "file", + "path": "img_3637.jpg", + "sha256": "8be55234e48947a131e84c570884f384fc2f9c9ca6e8cfb52bb0e62c0b01825e" + }, + { + "kind": "file", + "path": "img_4158.jpg", + "sha256": "de74622993f072b1748e50fdedf7a96c720198fbaf84711fda3fc7c5b192351a" + }, + { + "kind": "file", + "path": "img_1020.jpg", + "sha256": "a65a7a1b026d34b8b10ffc94ce7742d035567e5bc3475c698a95599158c81b8a" + }, + { + "kind": "file", + "path": "img_1746.jpg", + "sha256": "667947b2b10a85fb96ccad68f35d812edf3f1b839696909b81167ea19ba400d5" + }, + { + "kind": "file", + "path": "img_3151.jpg", + "sha256": "d2330fd570926d8d798290640c4458a0281ad184080dd7965abae4051d3a79e8" + }, + { + "kind": "file", + "path": "img_2918.jpg", + "sha256": "65d66ce0fefe2a3844c12854a420b0f246952bb47a16b7d5d8d7ce29c8e81770" + }, + { + "kind": "file", + "path": "img_229.jpg", + "sha256": "bb0af6027ed9d7568549cd8e95b9ecb3eed1964a98da8b77c4809a894eb85da1" + }, + { + "kind": "file", + "path": "img_215.jpg", + "sha256": "791714b984f3388d7a880c3642fa7db2eaed7ea016c55a8ad9f986c7dde19da7" + }, + { + "kind": "file", + "path": "img_3384.jpg", + "sha256": "c2a80c4a061e24d8087dbbf5bf1c5fadcb8ae5f52efccee09b39590ba129df7e" + }, + { + "kind": "file", + "path": "img_573.jpg", + "sha256": "2b2cc9a277c300b60cee68042d06f23d893580b48fb6dae9aa4eb756b6f7e56d" + }, + { + "kind": "file", + "path": "img_1593.jpg", + "sha256": "7cbfa717e29923e3551b4805fbfaa6f4b2c266cb7d5b1f7a931f886417549807" + }, + { + "kind": "file", + "path": "img_1587.jpg", + "sha256": "14bf40e07e0a6603e4351173c533329777d4eb832a3a0c835d930a233390784f" + }, + { + "kind": "file", + "path": "img_3390.jpg", + "sha256": "31caa8f776d5076e0ad37c7032f7d676c736347f688ad65c95a1b591aacfc035" + }, + { + "kind": "file", + "path": "img_567.jpg", + "sha256": "e5a91af48c598f6e7d3588c3e8711341627b1f4d7e7ae939baf054b87c2dc209" + }, + { + "kind": "file", + "path": "img_2930.jpg", + "sha256": "f2b2f72d8be16229e7521f2e0875c09fa92082a86b448bf95f22165563255fb9" + }, + { + "kind": "file", + "path": "img_4399.jpg", + "sha256": "43454ed25e0ee198af2f0e76e117bb74ea3619d196fde37288c177fddae69e02" + }, + { + "kind": "file", + "path": "img_201.jpg", + "sha256": "a58a0345e2c84419bcc758fadec2e075845f9d08ada1fc37ff9bf3e69ecbc654" + }, + { + "kind": "file", + "path": "img_4372.jpg", + "sha256": "4f88d74428d914466820411238e961f91f0705c51ee7bbdd0f8f40e0610eef59" + }, + { + "kind": "file", + "path": "img_2703.jpg", + "sha256": "455cf27e622c35cc2eeb79aaff767ce156b19e98e91aeb4fd7f3f02a405a711a" + }, + { + "kind": "file", + "path": "img_2065.jpg", + "sha256": "91011c1b268a21dad177f3751d7b1db345d4d282c7c455e5cf7c757112c6efbb" + }, + { + "kind": "file", + "path": "img_1578.jpg", + "sha256": "c6f8da5de86cf66dff1289b66ac86b14ee4a6fa26b243c1306a5d686345e0ce9" + }, + { + "kind": "file", + "path": "img_2071.jpg", + "sha256": "b564360a95a69b2e5e0742fe290dd582176b016e50e2efa2284c1f0cf6be9390" + }, + { + "kind": "file", + "path": "img_598.jpg", + "sha256": "c96f33cd3c96bff2c53b5f56102fce4ed8626f0c700e6d2d522ad3eeade2ac00" + }, + { + "kind": "file", + "path": "img_4400.jpg", + "sha256": "d69cc25eca85a14c262ad757f75fe62dbe3096c0d4e269a4e0153a48201aaf7d" + }, + { + "kind": "file", + "path": "img_4366.jpg", + "sha256": "481c95d4cc75a13d8920e8d58a2b2bd70ac1215ead6893ce8fcae78eb1ddf6a1" + }, + { + "kind": "file", + "path": "img_3409.jpg", + "sha256": "2a18dd92649ee4aec3eb77855b13ec400a7665b6ef72ab53a6a5bec605abfa3c" + }, + { + "kind": "file", + "path": "img_2717.jpg", + "sha256": "86cc2f12a224ff7bacfb50502bf78286fb544689170cca7489f32f25ab8758fb" + }, + { + "kind": "file", + "path": "img_3421.jpg", + "sha256": "be0a3176444a328792de921a0ffe43957cbba7ab9f68e7f7f5ab75bb9d79760e" + }, + { + "kind": "file", + "path": "img_1236.jpg", + "sha256": "0e26ccfad6077671064c70390df3486f151164ca79c56810c54a59b487fbf7fb" + }, + { + "kind": "file", + "path": "img_1550.jpg", + "sha256": "b9969192bfe17030edb6eb0c3cfe77432b154aa7f830cc2a563c7502861722d1" + }, + { + "kind": "file", + "path": "img_4428.jpg", + "sha256": "8780c7bb99e7b078c0f45d574cac1de53d9ea61ec5fab9c5d543c6b7d328f4c7" + }, + { + "kind": "file", + "path": "img_1222.jpg", + "sha256": "54c07fb991ba0391eea68ab8fdbb0f2c861882c3c2f8f13c7d4e04836ce840ab" + }, + { + "kind": "file", + "path": "img_3435.jpg", + "sha256": "f2ceb4283c4a5dacfcad8e592c44aabcf59b45e2ce8e851da7d53cb2e7fd6ea8" + }, + { + "kind": "file", + "path": "img_1545.jpg", + "sha256": "74525b4e2ef109c1931d923652bafb1802e968dc17aaaac9880d0fbcd0c57535" + }, + { + "kind": "file", + "path": "img_3352.jpg", + "sha256": "b03e50a9e8531d277df4aee7b13fca21aa40ebc205794e5fc555964df30366e0" + }, + { + "kind": "file", + "path": "img_3434.jpg", + "sha256": "9050bc20695181cbb8e1eadf5dafd0385ad52b16506f64f0559eb1b047428f5f" + }, + { + "kind": "file", + "path": "img_1223.jpg", + "sha256": "fcb63e15b71385ec8166b140bca826e53aae34550b1e1e14a90486561885d974" + }, + { + "kind": "file", + "path": "img_1237.jpg", + "sha256": "bdd053d37d1afb4fbeb1f41a376819af6e434dda9db7e82e40cfb94635abf5af" + }, + { + "kind": "file", + "path": "img_3420.jpg", + "sha256": "b7997a8b34c5ae7629d37c2ea0804c2bb330aed7634fade0ca8b09b2fc23474c" + }, + { + "kind": "file", + "path": "img_4429.jpg", + "sha256": "99a6e519354971f302167e599c333ee7408b4ed936cf2d509225f940bf6fda67" + }, + { + "kind": "file", + "path": "img_3346.jpg", + "sha256": "44e008c5b59dc2fd1fab80bad0f78dc0acce0034a7a95ba20152cfc07da76dff" + }, + { + "kind": "file", + "path": "img_2058.jpg", + "sha256": "e4870e8c965a7a772065e9f83054cb60e5a0b72f14317318fed6abc2dd7db26e" + }, + { + "kind": "file", + "path": "img_1551.jpg", + "sha256": "771f3e5004c93d2cedb56b1ab4197b9dce3e45b3925159869868151cd7c7235c" + }, + { + "kind": "file", + "path": "img_4401.jpg", + "sha256": "1042bf7c39b3ebd2d11306358e1ec9ec977992e774e42c5bbf8f5dfb55b715cb" + }, + { + "kind": "file", + "path": "img_2070.jpg", + "sha256": "e6287ac0a55e64a4c152b6efc6917cdb90b03c86842eefbecee77407ab859110" + }, + { + "kind": "file", + "path": "img_1579.jpg", + "sha256": "853c5ee69bcd51f17aaceef9d520758405543c5cd30eeac9ba4afe8657932b37" + }, + { + "kind": "file", + "path": "img_2716.jpg", + "sha256": "1a15b3c7d5e2f8f13abec2ca114b463ff895a6141d8c3c4d16f11e6f24493187" + }, + { + "kind": "file", + "path": "img_3408.jpg", + "sha256": "2dd4462176ca69a1d21ff999e650b38256ddd22e2a0b6da8cf2315db26ca8585" + }, + { + "kind": "file", + "path": "img_4367.jpg", + "sha256": "9c4bc54c7ec8d9ab6039f0189312875f0a20b2d571bf2fb3aec91a514bb66dfc" + }, + { + "kind": "file", + "path": "img_2702.jpg", + "sha256": "75b1b7c322c8e813afb30eb23c9e0d2d3ae9b8b4869700ed830d5778c31c875c" + }, + { + "kind": "file", + "path": "img_4373.jpg", + "sha256": "1ae503b846a01b02db111fb441f5dc7f6a2997f93d61df13b555f719d775c60c" + }, + { + "kind": "file", + "path": "img_566.jpg", + "sha256": "63d345e6d61d7d10b87588e52a1c94a43f8f9b4f520fecf79e4fbc2e2a73d949" + }, + { + "kind": "file", + "path": "img_3391.jpg", + "sha256": "ff1d9f31e72307ee93672bd43792fd7da8f335c5ee43b99a4b6805dcc4c0363d" + }, + { + "kind": "file", + "path": "img_1586.jpg", + "sha256": "74cd3284f1f03910b83ba15cc281001dc3194559081db8f08f72f885db04a560" + }, + { + "kind": "file", + "path": "img_200.jpg", + "sha256": "9b7a99cf356f3684b5d2a37a3ce142545d9d0baa2da0d78e2c332d62f29a67a7" + }, + { + "kind": "file", + "path": "img_4398.jpg", + "sha256": "2b08d78e09c0514e19ae1edc6cb4409c684b56258bf71d53da2f2988d1905485" + }, + { + "kind": "file", + "path": "img_2931.jpg", + "sha256": "c2ba2f7c8bdd0c79612335cc1b0f25e95c5cdcde91809fb84add777372e1f382" + }, + { + "kind": "file", + "path": "img_2925.jpg", + "sha256": "da1b20ed6e2ea1b01d33a588865dabdb717f61fcbd1276bed8045dda97547b30" + }, + { + "kind": "file", + "path": "img_1592.jpg", + "sha256": "9247181d2a67ab6172d85f7bb4b302f0d8e948116e20989312ca5391e9e16a58" + }, + { + "kind": "file", + "path": "img_572.jpg", + "sha256": "620b565cdef416ee65f0159f9bf6f21176155fb9d88713f0e3963ed2b1d2d538" + }, + { + "kind": "file", + "path": "img_228.jpg", + "sha256": "cff6ca7d70bd5bb95a2d7e149a0db23fd83d841e6ce4ce4ed44dc980edf7d2c9" + }, + { + "kind": "file", + "path": "img_2919.jpg", + "sha256": "78746d003fdde53f464528da99e798086bd44af6bd6d98bf56e205057d53fd05" + }, + { + "kind": "file", + "path": "img_4159.jpg", + "sha256": "e40d193794fc8bb0d3aab633ad7f68f7570dee21d78756ef23f4dc24a11d3ff8" + }, + { + "kind": "file", + "path": "img_3636.jpg", + "sha256": "f806067f95c9b204e420bf0e3077b936f9242df2bd834a1f5f2f673db9540887" + }, + { + "kind": "file", + "path": "img_3150.jpg", + "sha256": "e347d067b9930dbf0167e5d30b075235566f1c0fa8e4f5dee910640ab0dad777" + }, + { + "kind": "file", + "path": "img_1747.jpg", + "sha256": "74c209fc401c10f3c01aa4f1a0e35940cb1282fa3681877ca12e829471aa9408" + }, + { + "kind": "file", + "path": "img_1753.jpg", + "sha256": "1dace5f8307875f689588c7738afd5b6c634ecc4fe9d0c578e9ab76c65811cee" + }, + { + "kind": "file", + "path": "img_4165.jpg", + "sha256": "020329dffe015316298c517851e1ed3dcdb807b27a6949c3dd159c5144750cfc" + }, + { + "kind": "file", + "path": "img_943.jpg", + "sha256": "3420dcab84bd76b6665019f07fcf72fab3e8059beceb00f229c28ab13578a35a" + }, + { + "kind": "file", + "path": "img_2272.jpg", + "sha256": "88405bf712c7a4046c5a8c97b3741c4340386ba498d7c5231b9f791ed4694f5f" + }, + { + "kind": "file", + "path": "img_4603.jpg", + "sha256": "c8ac3a012dbe3473b5ecc40cdce283dd0fdbe2248dd6f0d6b89c6500ae3a3992" + }, + { + "kind": "file", + "path": "img_957.jpg", + "sha256": "943e2c2c2567c8ac6b05bad1232a2a4e6ebe6b9f02d6675e6c0929ba8dd8c8c3" + }, + { + "kind": "file", + "path": "img_2266.jpg", + "sha256": "d7cdf6e4a9bb7058707e090d704b3cf9234779a1130468c944f608154c771127" + }, + { + "kind": "file", + "path": "img_1009.jpg", + "sha256": "8edbe1fe5127924a6971c4523a6e5bfb610fac5003ae7d1f922c0a4e2b38fcef" + }, + { + "kind": "file", + "path": "img_1784.jpg", + "sha256": "2af6f48fa9ea6a244f0ca194ccc51e5050d4726619d6687b6dc696e45760ea75" + }, + { + "kind": "file", + "path": "img_3193.jpg", + "sha256": "8b815d88a148a64a6b2418e9f25a0f39dda26faf70b3db7dfe4eca981db22e76" + }, + { + "kind": "file", + "path": "img_764.jpg", + "sha256": "f44640834c0d40fc0c832506a001dcbcbba237e935c9c2c80428bcb31f1dfc95" + }, + { + "kind": "file", + "path": "img_3187.jpg", + "sha256": "945622e5b763371079d0200fde1d0d220d48638b846aca4e7dec7a2bf981f910" + }, + { + "kind": "file", + "path": "img_770.jpg", + "sha256": "1c997d977166168529c3e59d148e5f2d8c853642f57fec2a69a30a3560536041" + }, + { + "kind": "file", + "path": "img_2299.jpg", + "sha256": "8da3b90c75f520b7dc2f1599884a6b98b89d42ebda728e1919f256ff49bf3f17" + }, + { + "kind": "file", + "path": "img_4830.jpg", + "sha256": "b9fce998cc0f1bf73d70e0574cf319565f443826d93cd9d060cfaf4d7eb8be4e" + }, + { + "kind": "file", + "path": "img_1790.jpg", + "sha256": "360d27406435321f3b191d858e492d479340fe0d090fb39b911cfbe79f087187" + }, + { + "kind": "file", + "path": "img_1948.jpg", + "sha256": "f8b1ab119eafb280742963f2215e52ba2a54040b34e2c7fd3232c160c9d77b6b" + }, + { + "kind": "file", + "path": "img_3839.jpg", + "sha256": "654ac1eb650cd2ed1fc5da617a7269d3df67dc7e60efc5e1c653e45bc04d261d" + }, + { + "kind": "file", + "path": "img_3811.jpg", + "sha256": "60fb50e98a5ff07a521b9cefd8766b1bcef4a91878c8e417b4f7c5c80be6cd28" + }, + { + "kind": "file", + "path": "img_980.jpg", + "sha256": "b184b77fe997329a7288e443eda5d8e7c2974fa104a076d80a1b813c5718a80c" + }, + { + "kind": "file", + "path": "img_1960.jpg", + "sha256": "622b2ab73a43f9b240ef6bbe7d0ef738acf5aa58b68648ffcd43cd3969e42049" + }, + { + "kind": "file", + "path": "img_1974.jpg", + "sha256": "72486294601db985a7819f7ce261084308535b6de773a2502071049f6cef79c4" + }, + { + "kind": "file", + "path": "img_994.jpg", + "sha256": "86b1413e2225a7346433058016933981a1d579dcf483f63271163e5a39a12786" + }, + { + "kind": "file", + "path": "img_3805.jpg", + "sha256": "9c8609939058636724b581fa46a80a47feddd53d9512138a5919449ddc7d60b9" + }, + { + "kind": "file", + "path": "img_1155.jpg", + "sha256": "3651fbb4206b10274daf02c7cd4eda00a852da7aac5acc183ce96087b6c8cd22" + }, + { + "kind": "file", + "path": "img_3742.jpg", + "sha256": "64a8546f545293d1b331cb303c710b77265a94f985c66569600d25a30c48e67c" + }, + { + "kind": "file", + "path": "img_3024.jpg", + "sha256": "fc634d05366ae3f0d6e6173b9ec079953bcf54489e2e51cd0d2d4077f3c29d52" + }, + { + "kind": "file", + "path": "img_1633.jpg", + "sha256": "f5a97a08f68070e91a61fede4e62d400349680a8ea0131e1dc8fb958526a4264" + }, + { + "kind": "file", + "path": "img_1627.jpg", + "sha256": "658153e50d90a657d9878c922c47c53cd7b93366e318dd08f712a670434faa0a" + }, + { + "kind": "file", + "path": "img_3030.jpg", + "sha256": "0d9bed7eb1c36ccaf0075f50cf21288e18386542ac44b500dd0094490184a71f" + }, + { + "kind": "file", + "path": "img_2448.jpg", + "sha256": "dd09b52dccb423f5d88d2954220851f39a6516eb8e0e3aeb67a8b53d4ca8c734" + }, + { + "kind": "file", + "path": "img_4039.jpg", + "sha256": "03dc13b9047dae4eccdc75409b88288a2567f9088f8115f705f4577c17a53831" + }, + { + "kind": "file", + "path": "img_1141.jpg", + "sha256": "ddcf3b283a3cd55f8de472cf37595eab82b696b71781844aa3254bcf3d88edce" + }, + { + "kind": "file", + "path": "img_2460.jpg", + "sha256": "764716d7d03a613b5f2467220ee96b3f849a944cc14c510c51c0de19fdf54cbc" + }, + { + "kind": "file", + "path": "img_189.jpg", + "sha256": "5f828ed65dee1ec3bd6d8a7163beaaa5d5ce2391fddb06044ffcbd4acde41151" + }, + { + "kind": "file", + "path": "img_4011.jpg", + "sha256": "0be804515691612e99eaf759aac06b871796570f9a237388bb05a120a07441ce" + }, + { + "kind": "file", + "path": "img_4777.jpg", + "sha256": "2171be784d493f0ae1ef1a4f9641027abad0b67a86465053b8f336ea6b8c2bc6" + }, + { + "kind": "file", + "path": "img_3018.jpg", + "sha256": "1375771a3c533781fbbe2b6d79cc91daa0c33a7ec794a2da32052f85356cb1e0" + }, + { + "kind": "file", + "path": "img_2306.jpg", + "sha256": "bd713a51992acf94a9c4f88c4c6fe371ef091f6fd07fa00786dff74a9af85883" + }, + { + "kind": "file", + "path": "img_4763.jpg", + "sha256": "7910ec17674cb711097118129a50dadbea53061cc0c99f4562c1729c6eff7fbc" + }, + { + "kind": "file", + "path": "img_2312.jpg", + "sha256": "db9a1e844132613dc143133fd0d6cdf5e940ad5f6fb5627d08c578cbf672b3f9" + }, + { + "kind": "file", + "path": "img_823.jpg", + "sha256": "2f8b1e39d8a0bfe37924c2d8133969430e2b335a9c735433f005aa420801175a" + }, + { + "kind": "file", + "path": "img_2474.jpg", + "sha256": "80252351a2ab7ae2f3ce428f0dcae2cbdc11642e2638821262ac10dd1c14b3d6" + }, + { + "kind": "file", + "path": "img_4005.jpg", + "sha256": "599091042a7c0dc9474df310fb1bbd371427ac3d679aec3db353083dc6bbe152" + }, + { + "kind": "file", + "path": "img_3781.jpg", + "sha256": "3653ee6f42d26dcd300e59f35f4f5e2e97d88bfd0470ee7843953b46260f762f" + }, + { + "kind": "file", + "path": "img_176.jpg", + "sha256": "29c8241a1c55485ee2f044551dbf49ea376f1958f640344ff4c267e4d73db544" + }, + { + "kind": "file", + "path": "img_3959.jpg", + "sha256": "60711320cfe9a910f6c2ceaa8496699bc850c5c4e116a729bd123ade0502ae14" + }, + { + "kind": "file", + "path": "img_1196.jpg", + "sha256": "933f97eb717f171d278c44995733c8f804d0364c2ad83bb432d8d7890df0b767" + }, + { + "kind": "file", + "path": "img_4788.jpg", + "sha256": "92e5a3b7c30faa76679a63e593c0959b8054cec279739784f7ffa4efbc923a46" + }, + { + "kind": "file", + "path": "img_610.jpg", + "sha256": "13b643bd0123343154e05eaac1f3a9265a83a5a75b9b70c044598aa1b2564af0" + }, + { + "kind": "file", + "path": "img_162.jpg", + "sha256": "45bdfa2fea56d46a45d81276e1cc5ef8c92fb4d2ceb28f53d1356dd92e68ada2" + }, + { + "kind": "file", + "path": "img_3965.jpg", + "sha256": "d47cc4118c9df446201e605e868615fcde2f9fa5213ae6b0dac361eafa7ddef4" + }, + { + "kind": "file", + "path": "img_1814.jpg", + "sha256": "f2c81cedf967665dd897ca18f285f9d8b68cb74adae3e30fbad3a686624c9c70" + }, + { + "kind": "file", + "path": "img_1800.jpg", + "sha256": "f006610bcb86181bd657de228732fa1e85e7d2001267713f4ee1bdd1f9aca813" + }, + { + "kind": "file", + "path": "img_638.jpg", + "sha256": "eaaa8c861c73e99786a8b05aad3ab003c84a8c0dd4739652264579157161d74d" + }, + { + "kind": "file", + "path": "img_3971.jpg", + "sha256": "6b20c9fa5e2775638e4a2538ecf7fb659b36db54b761a71e7851e3c80c058bb9" + }, + { + "kind": "file", + "path": "img_1431.jpg", + "sha256": "21867c0178a29fd429d57dba68a1180728493a734c462f8eddc9fd871751b0e0" + }, + { + "kind": "file", + "path": "img_3226.jpg", + "sha256": "11af347e078498e358f8f48758edb3e4a22abe0787fdc20d656a8760fa0ea1bb" + }, + { + "kind": "file", + "path": "img_4549.jpg", + "sha256": "84ba3e494a0bd41cf3e0fcc5394da80b4f5576588d50cf763be2a401b2a7794c" + }, + { + "kind": "file", + "path": "img_3540.jpg", + "sha256": "31e3337d2ac511538e4af9275b4e2d3c464b8025f847cea7383c8b6dc4202612" + }, + { + "kind": "file", + "path": "img_1357.jpg", + "sha256": "4129624da9a3002c30827b65f2b9fcd1724fab259a90047b0324e4f7a8978456" + }, + { + "kind": "file", + "path": "img_2892.jpg", + "sha256": "3d703f32089588041333167c72a78f641c01086d3be67f2c50bc3724c37f62d4" + }, + { + "kind": "file", + "path": "img_3232.jpg", + "sha256": "648386cf1afeb2b3db2d72ceb9d9cceb2b5ea915d189771634def2c848f71654" + }, + { + "kind": "file", + "path": "img_1425.jpg", + "sha256": "eac3cd941b33545e11ed5b50b73d0da064777ad7ec30054b7fa022855fa680d3" + }, + { + "kind": "file", + "path": "img_71.jpg", + "sha256": "a0ab0a870e236c3de9a2e5e900885ff835c2faf9c63b35686cd6fa0b0a4426b0" + }, + { + "kind": "file", + "path": "img_4575.jpg", + "sha256": "151e30a48c874455386ce75e2376c5b16279b2cd637218d069900a008ae86e23" + }, + { + "kind": "file", + "path": "img_4213.jpg", + "sha256": "6ecad3159b96048be21e5053b57d233de2df04adf10c9671e12418b61189f03e" + }, + { + "kind": "file", + "path": "img_4207.jpg", + "sha256": "61cdecc30364713b7d34271fbc43b5504efa384d5610b8637a5491131ece4a77" + }, + { + "kind": "file", + "path": "img_2676.jpg", + "sha256": "0939ef59fe45d475b27f53174637f1217a37c18015c42a9056a39d8d0de43172" + }, + { + "kind": "file", + "path": "img_65.jpg", + "sha256": "705e5e9c29da0fe5121aa63e9ee79b53003b5dd4e7e9e1855eddd43f2f3c9a40" + }, + { + "kind": "file", + "path": "img_2110.jpg", + "sha256": "87b6a8d8b26bf791a5746e8fd433add799113d71f14b438818c216e967909566" + }, + { + "kind": "file", + "path": "img_4561.jpg", + "sha256": "04f5a20bbcc6abb0b2abd60936d002514ab6d4025c1354b57b06de59c83f034f" + }, + { + "kind": "file", + "path": "img_1394.jpg", + "sha256": "3b9e8621d50b22cd095085605feb9b78bee567df9145f73747a381de376d0a4e" + }, + { + "kind": "file", + "path": "img_2845.jpg", + "sha256": "3b7496c4d74861870a8faea21b113aedd26e49bfc8fbbcc5e3bbf2d61afc7a85" + }, + { + "kind": "file", + "path": "img_374.jpg", + "sha256": "78e07669ee30815162ba5c6a4a952cf178d655895c8a00a97f38ed6ddf3591d9" + }, + { + "kind": "file", + "path": "img_3583.jpg", + "sha256": "f690bd8d67c7890ae02eb057326c6a1ad900b5bad6c854e6e6303d85f1ff0625" + }, + { + "kind": "file", + "path": "img_2689.jpg", + "sha256": "aa5771d39298b9d1255abc0849d34ee1d0883fd7bffa916f095d1e97ee8f38f1" + }, + { + "kind": "file", + "path": "img_2851.jpg", + "sha256": "4c5fd4c8be8c3ab1bae2bd3a13e572f1b3bf823b97af380c3e11732528c0eb42" + }, + { + "kind": "file", + "path": "img_360.jpg", + "sha256": "8c7a4305352baa536a42edd0c3c14ee0cbf49dd3fd8ceb5a35bb14a37e713d21" + }, + { + "kind": "file", + "path": "img_3597.jpg", + "sha256": "5862266c273474c788d994164de60e117fc78a78693f47d0eb0dd035c431da01" + }, + { + "kind": "file", + "path": "img_1380.jpg", + "sha256": "f0fc036bfbc16cede40105c3b6b92645e736057df164eedfd6fe5b993eda6bea" + }, + { + "kind": "file", + "path": "img_406.jpg", + "sha256": "4be4fb1cd17de3e3652b694f869f20250c0dcf40d1287cdef207a95358f6615e" + }, + { + "kind": "file", + "path": "img_2879.jpg", + "sha256": "4a0c44e298bc1fae4482dbcbb4a8e5dbddab8dbb4bb4836684e66f198755c57b" + }, + { + "kind": "file", + "path": "img_402.jpg", + "sha256": "429327b7eeb8105540aef222a9996b8f2b83e089c349e449ad0befa21c55e8f8" + }, + { + "kind": "file", + "path": "img_1384.jpg", + "sha256": "edf75808e92ec9c57fb997d16b5c9ec54b5bec323f97b769571973121c4f1f9a" + }, + { + "kind": "file", + "path": "img_2855.jpg", + "sha256": "ce7069493f7e8f9ed136b680a6dd65b35e0953a525ed803526027e1c908bf14d" + }, + { + "kind": "file", + "path": "img_3593.jpg", + "sha256": "6f28d8f6e4c40d812833e5b9fd0e7685fcdb1a8a82c5e9815201838150358f48" + }, + { + "kind": "file", + "path": "img_3587.jpg", + "sha256": "72bc470679cf12101dbfa606c242aa3ffc109e8674489b346204a074a0b09eed" + }, + { + "kind": "file", + "path": "img_370.jpg", + "sha256": "bf665f8b85d7407f668858fc96ecd91c47db6f71d096a026ef69d343e5485f8a" + }, + { + "kind": "file", + "path": "img_2699.jpg", + "sha256": "17603bb6ed50cf6fa6cb33ba87b28594c1fa8dd37237bd43883a207024a70098" + }, + { + "kind": "file", + "path": "img_1390.jpg", + "sha256": "2f0eb4dd6a30af6a2cf37d10fa05a6fd59ae1525287145b17ff90080cc4e9eb4" + }, + { + "kind": "file", + "path": "img_416.jpg", + "sha256": "9e0beb53b3d4fe6c39184c8dcc2f880cea31eeb999362fa335a5440316d0f0ab" + }, + { + "kind": "file", + "path": "img_2869.jpg", + "sha256": "6a91e331dd9881bce8dbe8b7e358fdd3e0e8e8731f2851a81c9f3aeff29bc850" + }, + { + "kind": "file", + "path": "img_358.jpg", + "sha256": "698a55d2de434c7d4803fd4716cfe57ddce545f7aaab4b4898c7a3287b44f684" + }, + { + "kind": "file", + "path": "img_3236.jpg", + "sha256": "24a6f21eb386f08e7f596242d12568459c9289fa9e992a49ecce23779a051f2b" + }, + { + "kind": "file", + "path": "img_4559.jpg", + "sha256": "52478e9e7d22ec14be7dccdd8f181f0d07cdc43abc5109c695db1433b1f70309" + }, + { + "kind": "file", + "path": "img_2128.jpg", + "sha256": "6cc795b20b87e51d1ca4b2d0ced5f21038c3c977ab48310724f9b5bbd22b271f" + }, + { + "kind": "file", + "path": "img_2896.jpg", + "sha256": "d8926188a3fc225f18c0bcb891b5bb5d8c7cc0044e1445fad50f80f66b3d5285" + }, + { + "kind": "file", + "path": "img_3550.jpg", + "sha256": "fbd851b06d9dbd326485a400d2533a11bd9c8d4af742cecaf3db01e92a8262b8" + }, + { + "kind": "file", + "path": "img_1347.jpg", + "sha256": "3beebd18c91789f8ea464ee84cb59a81064cb3e3aa101db0c2f08b956d2f93f3" + }, + { + "kind": "file", + "path": "img_1353.jpg", + "sha256": "362004f11ddd196fee0496c000d705307798cc9608836992c23c52442aeb2fb5" + }, + { + "kind": "file", + "path": "img_2882.jpg", + "sha256": "fed5398773d076c21f1f42a5355ca0cecb5202af6147d327792618430109715d" + }, + { + "kind": "file", + "path": "img_3222.jpg", + "sha256": "4311de230c6e87fc446e965a44e8348e23379ff379540f9576e83cb1a90d98cd" + }, + { + "kind": "file", + "path": "img_49.jpg", + "sha256": "e194b1f9cc17f7b03a7900c506270f687df48ab18fd763874ccc417cb66053d6" + }, + { + "kind": "file", + "path": "img_1435.jpg", + "sha256": "8002ccecbecb6b7a5788e941cb77054628f399041e00445b00bd499bf0183507" + }, + { + "kind": "file", + "path": "img_4565.jpg", + "sha256": "6ba2265b322c315061320d210e51cfb8f223208dec092a2af1358c214c4dd902" + }, + { + "kind": "file", + "path": "img_61.jpg", + "sha256": "5828e6f292875831912672ebaa8305664b9dfd510e436b21d62a5de716ccc518" + }, + { + "kind": "file", + "path": "img_2114.jpg", + "sha256": "a24291d1a06275cd285d9adf892cfe69c862aa91d64d6a98ddbbd1bf10e9f49d" + }, + { + "kind": "file", + "path": "img_4203.jpg", + "sha256": "72dd086297a501e34b4cacd80f6b502bfd81a0bafcb7b720bb95704e8da42e50" + }, + { + "kind": "file", + "path": "img_2666.jpg", + "sha256": "f1a76a77a8d53a2cae19bbc15621e55e682eab8e18cc9b6d42d2c32d6eeca999" + }, + { + "kind": "file", + "path": "img_4217.jpg", + "sha256": "f0e6cb76e67d7157b6baf09f934b19564106bd433b54752564cca6c911bc4a14" + }, + { + "kind": "file", + "path": "img_3578.jpg", + "sha256": "41987bf3d5daea8b65236165214fd67a18169379c20a3064d47d9e32ab317f86" + }, + { + "kind": "file", + "path": "img_1409.jpg", + "sha256": "e96b20cae87f63af1b1ddb0109037a82dff9c0d340eae44002505c2faf50f38c" + }, + { + "kind": "file", + "path": "img_4571.jpg", + "sha256": "37a5fcb41caa220ce4ec143023f4fc8f2e8c0510adc9c739e498ff93d98e9296" + }, + { + "kind": "file", + "path": "img_75.jpg", + "sha256": "d641b136f92c74eec8651bb7e1a2820ee4d8e55297477243ab5edc90f964ec00" + }, + { + "kind": "file", + "path": "img_2100.jpg", + "sha256": "bb6b345374a57e917488c0cac096c8ae1a0f32eda6503b22d7a5fab74d11b8ca" + }, + { + "kind": "file", + "path": "img_3949.jpg", + "sha256": "47fe7eac88f3cb22ebb6bc9f3ad54bdcdba6c7c441127878fe660d9aa8f14a44" + }, + { + "kind": "file", + "path": "img_166.jpg", + "sha256": "d941d8c107c0ce7b5ca224b82a2eef63b3774d2c75298bc56ca8790f73f8982b" + }, + { + "kind": "file", + "path": "img_3791.jpg", + "sha256": "fb6780d953e7db733e2b279d18441d8d19e5982c6bae587affa6f07b1e8da50a" + }, + { + "kind": "file", + "path": "img_1186.jpg", + "sha256": "e55a1eb8a9e071c8b258a54affaf66efc104bb4efe5fa9edfa23ea7f399d1737" + }, + { + "kind": "file", + "path": "img_4798.jpg", + "sha256": "18ce82faec6b7c91c5e74f473a994a582f5428300c5db569a7d4081341a0246c" + }, + { + "kind": "file", + "path": "img_600.jpg", + "sha256": "5034eb2ff2b2e1510b5c72a4f9e627d57703a4a5ea7c0c08d75ae2e653efec2a" + }, + { + "kind": "file", + "path": "img_614.jpg", + "sha256": "a6ce0139cce59085229c3ca01584f8935154b25bfeb4549323e982fe7a4d00e6" + }, + { + "kind": "file", + "path": "img_1192.jpg", + "sha256": "51412e95d0488981c973cfb471b030819125b46b49f84192082836e4d1af5dda" + }, + { + "kind": "file", + "path": "img_172.jpg", + "sha256": "f35e7acd1f4922999411048a177a620548f1f162150b094dfa5f823b38994d02" + }, + { + "kind": "file", + "path": "img_3785.jpg", + "sha256": "3dd02dcda9782d83136026ce9634a907a00bab767be3b856f848d162a6bee08e" + }, + { + "kind": "file", + "path": "img_3975.jpg", + "sha256": "791b3fc05b739e3e1d962e528bf1f070f6fb719c4c78dc04481b923fa4bd1127" + }, + { + "kind": "file", + "path": "img_1804.jpg", + "sha256": "33e7efbd8edaf6696093ddf71356aecb831b382c49eeade0c5fce5121294570f" + }, + { + "kind": "file", + "path": "img_1810.jpg", + "sha256": "351cace63e648c93e5406deebee230f75ae5a97cb2659cb420849604681131fe" + }, + { + "kind": "file", + "path": "img_628.jpg", + "sha256": "36e76adfc09a3672f0bd2bd4010de96ec1fc3b9d9eaa92ae41bb939eacde0e78" + }, + { + "kind": "file", + "path": "img_3961.jpg", + "sha256": "92d9f02943c985ae7bedfa1112f1530d73f8d34b4faf6b58c2773981019d7c9c" + }, + { + "kind": "file", + "path": "img_1145.jpg", + "sha256": "797e17e5ffb7963e950a2507750f54198aca055a5ca949ede3f5f421bba856b4" + }, + { + "kind": "file", + "path": "img_3752.jpg", + "sha256": "d16f928a16d49cf797ce19fd6c72d204bad6ffd56c0fd229b6c229f55d5905ad" + }, + { + "kind": "file", + "path": "img_3034.jpg", + "sha256": "89df02b1292cf68c9d3e3af63508710d01dadae605f001829af3af49a4049a24" + }, + { + "kind": "file", + "path": "img_1623.jpg", + "sha256": "b57ef01e78719871335712993ac55731878a2391f88205717219d395ddc86f58" + }, + { + "kind": "file", + "path": "img_1637.jpg", + "sha256": "de6404068bcd48a5833ce374ebd5ef46f65197a7d7b4cd2b8ea8ed70ba08b9d3" + }, + { + "kind": "file", + "path": "img_3020.jpg", + "sha256": "f8f324306a6f60abdc2cf1fab74b82328596215dc5a712ffed31fa8608b865ec" + }, + { + "kind": "file", + "path": "img_4029.jpg", + "sha256": "2376d8556a7df40262444ebdd1a3d41329d72c8efe1cde8a6a647513e1c93865" + }, + { + "kind": "file", + "path": "img_2458.jpg", + "sha256": "58dbb81a7f3ade15e5bec3873b314c71b3a389df935f562e520307410ad10477" + }, + { + "kind": "file", + "path": "img_199.jpg", + "sha256": "33b85f83a5537f7cd730e59c6e10b6b57b19b6a306fc1e1a7405903877b2a7b6" + }, + { + "kind": "file", + "path": "img_4001.jpg", + "sha256": "e3e92eab3b71026f8bf6778dcdbbcace332b8bf51c1d6d29490022e924a188ae" + }, + { + "kind": "file", + "path": "img_1179.jpg", + "sha256": "85573a003fe6eb1c1aa3e66d18b5e30e7cd8eb21bd372eb079f605e658e49368" + }, + { + "kind": "file", + "path": "img_827.jpg", + "sha256": "88daba0599e4d5b7de854abb5aa69acf2030796796f417c8a19bde25890e6f9e" + }, + { + "kind": "file", + "path": "img_4767.jpg", + "sha256": "8afa0493bc383f0072ca3521172405b68105070f73e0cb211af8928c4b96dc1d" + }, + { + "kind": "file", + "path": "img_3008.jpg", + "sha256": "3df7dd5df4a050eae73c92765adf0e0e24bc3a940ba8ddc5c3c76da92baaa8c5" + }, + { + "kind": "file", + "path": "img_2302.jpg", + "sha256": "1cc854c4d7602ee0af5464745158bcafee3add4b35136983415dcd0a81dbd404" + }, + { + "kind": "file", + "path": "img_833.jpg", + "sha256": "40572be4bb612ccf78da360c347d3f0b37b409e2f32dd0214459bb2a72db4a1e" + }, + { + "kind": "file", + "path": "img_4773.jpg", + "sha256": "4fe19f49e21a309e7487c6115d84fb8d7dd208f3303888c7fdeefdf7d1bade59" + }, + { + "kind": "file", + "path": "img_4015.jpg", + "sha256": "583c51b580f132afbb9ff1e16901b5aa02866bd038b20758f4c22e7defa106ee" + }, + { + "kind": "file", + "path": "img_1794.jpg", + "sha256": "d6b1a547495d6e08e8dfbdf84dda565c004aafd2b519a8a3697d590f93efc907" + }, + { + "kind": "file", + "path": "img_4834.jpg", + "sha256": "cc23fe8ac6dd97822982ddcde173e0fc809e56a571815be6351d13a7c27815dd" + }, + { + "kind": "file", + "path": "img_3183.jpg", + "sha256": "f5a6c3d49b0c74e340d254ea5be785e547978e07e708a8aabfeeaaa93792a4b4" + }, + { + "kind": "file", + "path": "img_4820.jpg", + "sha256": "a5dfd7f2478de2e610f7f69305c4aabe2ce96a7680d4cef905a4ea23535f3e24" + }, + { + "kind": "file", + "path": "img_2289.jpg", + "sha256": "4563b6a2fd4d2433e7173adf99e3b434921726da2f312581fd29a5f74d4a2998" + }, + { + "kind": "file", + "path": "img_760.jpg", + "sha256": "daa09a8a2f3cdf3f2e15f111c1cdd39881bc5104334dcdc9f75ddc39ba355a0e" + }, + { + "kind": "file", + "path": "img_3197.jpg", + "sha256": "7d56e83bbb5df9470ecc1f1637ef2a8fa7ec2484fb93cde08dcb181bb78f499c" + }, + { + "kind": "file", + "path": "img_1780.jpg", + "sha256": "cae6334e90e06a2569af3d5a2f00316cac73a1ec188438681b2209181a6413d3" + }, + { + "kind": "file", + "path": "img_3829.jpg", + "sha256": "1ccf15ec2737c85403ab60c35a280754d2d1696069d276abdbc28c28987ccb3b" + }, + { + "kind": "file", + "path": "img_3801.jpg", + "sha256": "2a28cf671fe4eba62069796f96612d17ea25648d7d9abe54f359bc20d6e6833d" + }, + { + "kind": "file", + "path": "img_4808.jpg", + "sha256": "c0b228a38804a85ba5a80e9d036f39842987149e9577e8391aa60d547463e609" + }, + { + "kind": "file", + "path": "img_1970.jpg", + "sha256": "e2fea4ab503c37fc2bfe85bbff72c726c3be3ba14427b4ef4b84577c6be16a83" + }, + { + "kind": "file", + "path": "img_1964.jpg", + "sha256": "9c33f53df4039721e44cace1c2982f15d510967b1d4735f020dc0917c6a17005" + }, + { + "kind": "file", + "path": "img_984.jpg", + "sha256": "943f7d6b2e1b53c1480da12f8fe242e3b355dd2b8bed99532bf6252fb316d919" + }, + { + "kind": "file", + "path": "img_3815.jpg", + "sha256": "20ca7ba5e66e23f4473c5d54b0e7a1a7bdf74c2ce0ec44634ac9f9f412bfb62b" + }, + { + "kind": "file", + "path": "img_2538.jpg", + "sha256": "33aaa75215c961cde40b6694c63870c6e7c5f3a0db822c471cf9a0da8c220443" + }, + { + "kind": "file", + "path": "img_4149.jpg", + "sha256": "dee7e14fc7a97d7c5abc498ab448725a7423f59508b71c7ef08a8c0948e056e1" + }, + { + "kind": "file", + "path": "img_3626.jpg", + "sha256": "5005b94052ff27bc413d4845ecb653a782bd5b53a0357a9d4a73fc274fbe0952" + }, + { + "kind": "file", + "path": "img_1757.jpg", + "sha256": "36335fd0f4b353c16bca61727c88fc7faa41b7fb8c1430851e6343038756c598" + }, + { + "kind": "file", + "path": "img_3154.jpg", + "sha256": "fa5a2f05598f1dc2903e5d4791c7a3741896d6cc7c73578f6013997872bcb402" + }, + { + "kind": "file", + "path": "img_3632.jpg", + "sha256": "a1840542bbeb4e49b027fa57b881220a32c66a651a17e0d9acb55c69b8895b5b" + }, + { + "kind": "file", + "path": "img_1025.jpg", + "sha256": "e97f18969aa6de78525a522c277527f2cf1de861c5cb13186d973e921833649d" + }, + { + "kind": "file", + "path": "img_2504.jpg", + "sha256": "b244d9208b6aee1e714d40e8b246b49ee202b3ade9908468b97372750b181c32" + }, + { + "kind": "file", + "path": "img_4175.jpg", + "sha256": "1aeb2147760fe9af782cb508e5fb239410fcbc25fb8c70224feb36d64c48c4b6" + }, + { + "kind": "file", + "path": "img_4613.jpg", + "sha256": "e525e0b9b9d33f6e0b88579d6927330baedfe8c011c5e87040765a4e06ca81a2" + }, + { + "kind": "file", + "path": "img_953.jpg", + "sha256": "cb6cb967c0163bb735a038aa6b453abfcba8861c548cff6e0f99cd4b262b5e2e" + }, + { + "kind": "file", + "path": "img_3168.jpg", + "sha256": "45bf1a67cbef3e2456b2021fe86fed5e3980ed6123f897cb1f09fe87561786f1" + }, + { + "kind": "file", + "path": "img_4607.jpg", + "sha256": "70cb87bff240e44ec75fbb16c8c1e4838890b70a856012b0a4381e272a008606" + }, + { + "kind": "file", + "path": "img_2276.jpg", + "sha256": "9427d277f61006bcabd21673e07d26cfe22ba4ca1f46ff2e8281a5791ca02845" + }, + { + "kind": "file", + "path": "img_1019.jpg", + "sha256": "1ce44c31ea192bf388680ce215e022fe0d3dcff8a8c10f79bbc61034f779059a" + }, + { + "kind": "file", + "path": "img_2510.jpg", + "sha256": "4c2304296c5b701811d41ebb2a770f817f54c2cae29b50d59b89faeaec049fcc" + }, + { + "kind": "file", + "path": "img_4161.jpg", + "sha256": "1263bd259331093e117e21efd7fe416d5bb9167275185c795e6c7dd1e2ec956a" + }, + { + "kind": "file", + "path": "img_1596.jpg", + "sha256": "da47f628495a360e394e7cb203fef9106847877239c9f2a454210888a6b24de4" + }, + { + "kind": "file", + "path": "img_2921.jpg", + "sha256": "c14f70e998e15e0aab6cc5472e6684a395b1e86ebf553ceec10f0af638ff5106" + }, + { + "kind": "file", + "path": "img_204.jpg", + "sha256": "3ef6abb3d33ca56030adb361f8c62114d78a7f27345686cb0a4a227615c9a281" + }, + { + "kind": "file", + "path": "img_562.jpg", + "sha256": "c707163d9abe193b9ab68225228b25743429676d333674d806a254164ef84e5f" + }, + { + "kind": "file", + "path": "img_238.jpg", + "sha256": "7f5e8c2fff92cc75a7cad8c263195afed5c3bdfe31ab4d1a1ef89c971fd16f63" + }, + { + "kind": "file", + "path": "img_2909.jpg", + "sha256": "853911293fbcdd7c19c39ca829e66b00f41c8c4f350d9360ef7f7e5dd6e53f92" + }, + { + "kind": "file", + "path": "img_1555.jpg", + "sha256": "18a82756a790a273dbb714a7b77ed1a1a025cdcefbefcb526b4ba9eeb9a0e5e5" + }, + { + "kind": "file", + "path": "img_3342.jpg", + "sha256": "f3763510a427637f50a0be9193a0aa641bc9fd4882196a87f9e6c1e3b6580d58" + }, + { + "kind": "file", + "path": "img_3424.jpg", + "sha256": "697773debe822e198f6cd3053fd9c856f198172d5db4fed788ae2d5dd76ee212" + }, + { + "kind": "file", + "path": "img_1227.jpg", + "sha256": "34ab79dffde2c9c34fc102b05114546cf1b9cab2046d44fef1546d09551223ba" + }, + { + "kind": "file", + "path": "img_3430.jpg", + "sha256": "0a201fbce265696280c936bad1d9e99e7d906720e1887cdd1af5170588760910" + }, + { + "kind": "file", + "path": "img_2048.jpg", + "sha256": "b2e75bbc2866224ab8f540bec5ad96f7911f792cf91637f0fdff767fd1a091d2" + }, + { + "kind": "file", + "path": "img_4439.jpg", + "sha256": "ef3d99234f1c9bab8f19ddea5ce1ce5d90444c706f3f1e3b8621622421abf942" + }, + { + "kind": "file", + "path": "img_3356.jpg", + "sha256": "5117ee3cf0f095f60e40802c4ac95b2e4be9809c7a086878b997684d9581c850" + }, + { + "kind": "file", + "path": "img_1541.jpg", + "sha256": "805a84a4468a67e997e48f6f877081f99a305bcb68a918c64123700048f5b666" + }, + { + "kind": "file", + "path": "img_2060.jpg", + "sha256": "ca2f1d9bcd703f04e3297da09d7e318b55afa63123782e396ab5d9952bc8e2eb" + }, + { + "kind": "file", + "path": "img_4411.jpg", + "sha256": "9cca0fd7853ee9700704792cc7ac72f74198863e7820ec4c3d7ca8f87d4ffbaa" + }, + { + "kind": "file", + "path": "img_1569.jpg", + "sha256": "0c3912ed84cee81483f85f78cca43cb58f771438706fbfec3d3935767e286d40" + }, + { + "kind": "file", + "path": "img_3418.jpg", + "sha256": "c1bef94e607ad607fc5d1bd86c4611f35282020d74b78c40179602cf41bede1f" + }, + { + "kind": "file", + "path": "img_4377.jpg", + "sha256": "9ecdc7d080bee75d59fa4cbd6643187782aa80e570c29155e95e86186724cdbf" + }, + { + "kind": "file", + "path": "img_2706.jpg", + "sha256": "6a368132381e7361de89f5e505ba24722af35749d2afb5aaeb23370f7fb36ce0" + }, + { + "kind": "file", + "path": "img_4363.jpg", + "sha256": "76072d03c8933493830ce271579b6fcc815f47d23468979ccfd74de2a46121e3" + }, + { + "kind": "file", + "path": "img_2712.jpg", + "sha256": "5b330caae8123b1f6034ce46e4c4f74b8740583563ed14cc2ac38e0846803819" + }, + { + "kind": "file", + "path": "img_2074.jpg", + "sha256": "51e5130467d4eca634c29b43b8e33d982aeb7d6b0b56692ef346a34c7bffe22e" + }, + { + "kind": "file", + "path": "img_4405.jpg", + "sha256": "e0e8afe3c183085ac945516630bfa8acfc7854d08b28cae15c5cb74a6e62ba8e" + }, + { + "kind": "file", + "path": "img_2713.jpg", + "sha256": "67ee386c7bb2dc62d2303c8100f5b9d559f66f2d626a86fee6507a41130215af" + }, + { + "kind": "file", + "path": "img_4404.jpg", + "sha256": "e2ca3a68e85bbce6acf04c953b09aca3cd3b09d34b8b7e67bf3fc2b559ff8269" + }, + { + "kind": "file", + "path": "img_2075.jpg", + "sha256": "b12ab81a4ef17cb012e9de168857af1244c376f21864e91d4300e85f25041c16" + }, + { + "kind": "file", + "path": "img_1568.jpg", + "sha256": "ae0f5ee40ffe872f2e99779d6dda0b914b8cf3523cc8faab66000620dcaf9b07" + }, + { + "kind": "file", + "path": "img_588.jpg", + "sha256": "24ac0122c66a0f5e4c0a11033b3c0381f24725d733d77f661b8cbeb7f80170a2" + }, + { + "kind": "file", + "path": "img_2707.jpg", + "sha256": "22264f260290149c647c6adda668b54d251c03f2c23ad90ee9cda62edc8382d0" + }, + { + "kind": "file", + "path": "img_4376.jpg", + "sha256": "676f18762297e585bf8e298617fd761aebd22eeb53c5c912c05d223efaeefd89" + }, + { + "kind": "file", + "path": "img_3431.jpg", + "sha256": "44535301892d9d7e15b3665121e68b66f91a3ad6aa5567078246224ae358ab49" + }, + { + "kind": "file", + "path": "img_1540.jpg", + "sha256": "3861242aaa477e8d8a9b81ce2383e4e4b6330d6af41db24441cfbfab763b2b3b" + }, + { + "kind": "file", + "path": "img_3357.jpg", + "sha256": "cb9ed35b6b3a8351c3c7c93a6b6f3ab65e56af9af1259e010119d51a4418f304" + }, + { + "kind": "file", + "path": "img_4438.jpg", + "sha256": "0a66f5a7a8c14c94cb941fecc26a2bd0ff9f49bd634632195466982a4e4f86f2" + }, + { + "kind": "file", + "path": "img_2049.jpg", + "sha256": "ebbe5d40dfcb91ca43d9a5ab518192c89104e1ba7b6ce95ccd8d342fb434aece" + }, + { + "kind": "file", + "path": "img_3343.jpg", + "sha256": "003ff1b93cbac535b229bccf7a27517b7b802b6b276e65683abe7b1bcb513777" + }, + { + "kind": "file", + "path": "img_1554.jpg", + "sha256": "425bf4ce688f92d619c4800e65c4042ade364f0983ac90cf2c01446058fa8c3c" + }, + { + "kind": "file", + "path": "img_1232.jpg", + "sha256": "0eef2cca20b23c87e2e0a25564223ccca8646c29e49c64f6daa0567d4215d60c" + }, + { + "kind": "file", + "path": "img_3425.jpg", + "sha256": "465ef0a22574e40abd08f1f79854d9b192e3b1a94cdbf2454266344864395f28" + }, + { + "kind": "file", + "path": "img_2908.jpg", + "sha256": "a3ca7d7baa0486b2295157874df9f37210adb4237c5592aa351fd0b50ca692ff" + }, + { + "kind": "file", + "path": "img_2934.jpg", + "sha256": "c0f1e97becb25a75747c293c152d569b8608713135cead5a6d47352fb8dd40cc" + }, + { + "kind": "file", + "path": "img_205.jpg", + "sha256": "b8e8bd1b09ad60fd275bfe4d9088c63a9685bc30cd912987188ebd9f2cc2e51b" + }, + { + "kind": "file", + "path": "img_563.jpg", + "sha256": "8bd9c0c3b12d5f6709567f1b5ae665b126868ea1caf4deb982bffdf7bcbe1b02" + }, + { + "kind": "file", + "path": "img_3394.jpg", + "sha256": "866e76d57ddf36d3206ecc5e22c99c44e1d1bb573f3a7f4b0c18deb40cd46327" + }, + { + "kind": "file", + "path": "img_1583.jpg", + "sha256": "28314f6b538cb2cf00fb50a13d1ce9f75710cb76bf20e1200c2b898f22285ef0" + }, + { + "kind": "file", + "path": "img_577.jpg", + "sha256": "322179106d9d5103114084d4cf6c6d7b892aea1fa07abcb4e2bbddedc5ba9490" + }, + { + "kind": "file", + "path": "img_3380.jpg", + "sha256": "3cb20e867d746d9fea3e5f60686ccaf0c1c55a390b556bff057251bac2de0cea" + }, + { + "kind": "file", + "path": "img_4389.jpg", + "sha256": "cd79842a383601e00a80f6b383dd9a4e91632b183ff26bf638e99dc675fe3ca8" + }, + { + "kind": "file", + "path": "img_211.jpg", + "sha256": "e0382879e65a0b4459774d82b23c9818282eab09f8b198c6e2098cea2cb8b6cc" + }, + { + "kind": "file", + "path": "img_946.jpg", + "sha256": "6cd7cd2b399c8f049eb308ab88377e7100696aab12fdca10c9a8234816cde143" + }, + { + "kind": "file", + "path": "img_4606.jpg", + "sha256": "eed5bdae284de21b7f2ca81ab2e0ba8e5f673c200dd9275776e56a5fed464023" + }, + { + "kind": "file", + "path": "img_1018.jpg", + "sha256": "77310a717cbfe29c0166fcac2b1b34cebb6c41e282fa75bf0a10502fcadf3aba" + }, + { + "kind": "file", + "path": "img_4174.jpg", + "sha256": "b90c506b124dfaae5a4814a160d8bde885fb5c069e50bc9ac229ec266fec8274" + }, + { + "kind": "file", + "path": "img_2505.jpg", + "sha256": "7fb2c6e12386962cf424208385e8e40b292fcc375fe8da3649c471373610769b" + }, + { + "kind": "file", + "path": "img_2263.jpg", + "sha256": "69ad36fcc5356ed11dedfbb17f34b3fde562b8479d8eed77cf17ca9961cd9aa8" + }, + { + "kind": "file", + "path": "img_4612.jpg", + "sha256": "c92f439205cf2780a5530b8763b302b4515dd448d54981d54ca2d2fbf0fc8ce1" + }, + { + "kind": "file", + "path": "img_3155.jpg", + "sha256": "e1dd259fa09088cc3f2a76f212c86ab4b458122f348ab5f5fe91792232d4c41d" + }, + { + "kind": "file", + "path": "img_1742.jpg", + "sha256": "3f9a58bc814b2ddd8db53a845e70108009c0a904752ae226af30d92cd82bfd08" + }, + { + "kind": "file", + "path": "img_1024.jpg", + "sha256": "1df358a76cf774bb688e3d36fc13950eb23a975269113f34f7466e80b77eaa36" + }, + { + "kind": "file", + "path": "img_3633.jpg", + "sha256": "f2507c178f1dd9dd46a95929c6fb1a3c6d67fc6bc290d1b1eec51b96972d51bf" + }, + { + "kind": "file", + "path": "img_3627.jpg", + "sha256": "db52cb1ad827f32c8a12e3738aae642d66d19413709647569fcd5e5c1f8edfd0" + }, + { + "kind": "file", + "path": "img_2539.jpg", + "sha256": "4f147becd82769ab9178eab1f23c8b098a66524829ecf15a0d8215350c942593" + }, + { + "kind": "file", + "path": "img_1030.jpg", + "sha256": "7af2e35b46464400b6860b6f5e49c5dc1c8bcdcfadc855c5dcc6a21ab1969721" + }, + { + "kind": "file", + "path": "img_3141.jpg", + "sha256": "eb7d2bb9e003ed63532988f21e3a590d7be38d8488cc57e39c9df8a5c36824f9" + }, + { + "kind": "file", + "path": "img_985.jpg", + "sha256": "ea19321698e714b838e07680ebe72efb4cf698922f0e571c079878267c639314" + }, + { + "kind": "file", + "path": "img_1965.jpg", + "sha256": "92f5c6c73538ba8072ae93445ebf0690b0acdfa635469872b1a021eb9d772f30" + }, + { + "kind": "file", + "path": "img_3814.jpg", + "sha256": "b83a209c09c74aa8edbece584f8a0e272da5b2f8597d0714014524414adf2b39" + }, + { + "kind": "file", + "path": "img_3800.jpg", + "sha256": "90791d25167239a9adba4ce7d4ae868610aa89c219639b97ad6490d434cfdfd0" + }, + { + "kind": "file", + "path": "img_1971.jpg", + "sha256": "b15719d9591ee098580269c866e858b0f3a2720e879c8474a22f0f9d495885a0" + }, + { + "kind": "file", + "path": "img_749.jpg", + "sha256": "48a983271756e98b162a97824521c7811c5c88a94e6d4c838010d8b2556e5258" + }, + { + "kind": "file", + "path": "img_4809.jpg", + "sha256": "383b0814751b899c5bc0740556d8a5303f71e96ed2a1fbe762a0de9c24392933" + }, + { + "kind": "file", + "path": "img_991.jpg", + "sha256": "190a9c37bf7020dfae16e519daea75c8c1902d713f11580d48b74be6dbcc3bd1" + }, + { + "kind": "file", + "path": "img_1781.jpg", + "sha256": "94eff7241634bd617c579c6fe4d095c327daf37ac8a576a6e47b6a2f85cb9e72" + }, + { + "kind": "file", + "path": "img_3196.jpg", + "sha256": "964c778e492869f80d4ba69b9a0d7eb3d33c5614bb41afaec8f1f7f9baba804c" + }, + { + "kind": "file", + "path": "img_761.jpg", + "sha256": "28ed20de83aec51c6a2f7df8793ddf6cb00e45d589250e07c32ef6b7ab7c7ff5" + }, + { + "kind": "file", + "path": "img_2288.jpg", + "sha256": "63d8fdb533ee18a9b5bf5b6d52abe64b72a1ad5239512204b9b1c49d1e71e6fa" + }, + { + "kind": "file", + "path": "img_775.jpg", + "sha256": "e29e06e66e3a8088ae1aba557679368cdf63c18c5ea57e72777d0ae308e48ff2" + }, + { + "kind": "file", + "path": "img_4835.jpg", + "sha256": "a0c39865d7079216bb939ce92d533336e123ae4fe2ac3de7896b1d53efc421b8" + }, + { + "kind": "file", + "path": "img_1795.jpg", + "sha256": "ae0fade2e8f51492568654a14919915becc3a7b301b94540816510544bfbb0c1" + }, + { + "kind": "file", + "path": "img_4772.jpg", + "sha256": "6fa88f7701b7be0959bb7cdb8714f3e0710c85264d6d4805dfdb24d13661bd18" + }, + { + "kind": "file", + "path": "img_832.jpg", + "sha256": "b3ddbf0d87cabf65757c7e9e46eb7db1e17fb92d358b9f55fa2738150b5368bd" + }, + { + "kind": "file", + "path": "img_2303.jpg", + "sha256": "3616de416ba06dff709638fb99941d21864267ad44967cbe007673dca0e01751" + }, + { + "kind": "file", + "path": "img_4014.jpg", + "sha256": "4cd331cacd13c52146c3f4455fba33d98ab896977de7451a99fa201dfc985e7d" + }, + { + "kind": "file", + "path": "img_1178.jpg", + "sha256": "6d29427f7643f5bc7f70131d05d8e8cdb9634db1de4237577963c742acf7b540" + }, + { + "kind": "file", + "path": "img_2471.jpg", + "sha256": "2887ce68d373d8e51b01b80de431636ec8024f34892b9a4fe179f256809df59b" + }, + { + "kind": "file", + "path": "img_3009.jpg", + "sha256": "8335f5286d694521b2c3447f953ddae945f836357df368c58c358834c878738b" + }, + { + "kind": "file", + "path": "img_4766.jpg", + "sha256": "6978ebb4b71657f64c92c2318c7cc5366048b6bd2b0d5a9a6164fa3982d279cd" + }, + { + "kind": "file", + "path": "img_826.jpg", + "sha256": "a98c31125829efef4ce8fd8a0f5a8c6faa6ecf5b312ee204acf3927ce7bd4273" + }, + { + "kind": "file", + "path": "img_2317.jpg", + "sha256": "108a30bb55bbf0b138662df81a0bf1daca7ca6c140015732ed3635e11687907b" + }, + { + "kind": "file", + "path": "img_3021.jpg", + "sha256": "832e0406d50238261a3390af255436870600cf7984b2889f783ca25fb357f968" + }, + { + "kind": "file", + "path": "img_1636.jpg", + "sha256": "5a2d6a813065a98550c9169ffdfa4be173fef7fcf4180a9def7cffff19cb5db9" + }, + { + "kind": "file", + "path": "img_2459.jpg", + "sha256": "77253ebefadaf0908fe26528ef3367b14659312ba8f26b294aab9a93a62a00c5" + }, + { + "kind": "file", + "path": "img_3747.jpg", + "sha256": "fbfff060127169ebc2b09ecb7300f1be3027eaaa2996b6427fcad479d20e2731" + }, + { + "kind": "file", + "path": "img_3753.jpg", + "sha256": "4cef238873872bf40a4c1b5b3df7408a72445a2fd352b33841d8aeed96ac0d39" + }, + { + "kind": "file", + "path": "img_1144.jpg", + "sha256": "8cef72f65e75a72ebf30fb5811d50d6b91dc8c4751d749b2364c5839e632d02e" + }, + { + "kind": "file", + "path": "img_1622.jpg", + "sha256": "5db65bc41377591e76492f6889d54f570055fba935d11a2c998d2d89add38883" + }, + { + "kind": "file", + "path": "img_3035.jpg", + "sha256": "462c9026ce5e54c9a0a5d2a8a6f859a8ed2470b189eb5e819bfd35b911ff7cce" + }, + { + "kind": "file", + "path": "img_629.jpg", + "sha256": "c4a5d91fc94a12f272560ca9327125f4e269196254aa0f1946e34b051832d269" + }, + { + "kind": "file", + "path": "img_1811.jpg", + "sha256": "5b5abd9cab7164ae5fe0f4c2025ff4f5743aab82f17301adb39a2774df45fbce" + }, + { + "kind": "file", + "path": "img_3960.jpg", + "sha256": "8f57a1890eebde864ca860c1c72e5f4d303aed281e8816878ac994a1b924b054" + }, + { + "kind": "file", + "path": "img_3974.jpg", + "sha256": "2a6263ca00f460063d3682240e76df2696804371eca3b78ba19f65c2c79359f1" + }, + { + "kind": "file", + "path": "img_1805.jpg", + "sha256": "9fa1178875475093367954c9d37b3bf834478fe78b0adf083fd789524f2c790d" + }, + { + "kind": "file", + "path": "img_615.jpg", + "sha256": "4e5fc1a45ba8a7a64993ad1fc3a97602458296da4f3a499bb041990f98315d31" + }, + { + "kind": "file", + "path": "img_3784.jpg", + "sha256": "8566cd91dceb62f4570d2342ffaf19672303a640e003670ec1ee3ec20a49cfac" + }, + { + "kind": "file", + "path": "img_173.jpg", + "sha256": "1f02e922ed6d42e5b5a5c32fe52f80d3e01f2dc2c8aa8895a83e9316f6bf9b65" + }, + { + "kind": "file", + "path": "img_1193.jpg", + "sha256": "e09ba2e55555db78dc31eb0449f53f215c2866a51ee628a74fcc475fe6707d4f" + }, + { + "kind": "file", + "path": "img_1187.jpg", + "sha256": "28a2c82486cd20fa628e716880fe01f4889078394fcedf6f028da07afc6c7b70" + }, + { + "kind": "file", + "path": "img_3790.jpg", + "sha256": "8556283bed83014dc167fc4e1a8dbfd3add136c0afa45e7dc4c141c0dfc07216" + }, + { + "kind": "file", + "path": "img_3948.jpg", + "sha256": "47498fcb5c1b7ec27bf7c767c4e4ae26c16525d871cc5e90bf5d17fb9000a808" + }, + { + "kind": "file", + "path": "img_601.jpg", + "sha256": "8416fbe1de9f7ec27b5ba6a3f466a5d2d75e4a4027b236b335a9f7c3b0ca4b6b" + }, + { + "kind": "file", + "path": "img_4799.jpg", + "sha256": "92d5c86a869c54aadb2a29f037ad8c2f58fbbff8d39e12a3aaf7896bc2328b88" + }, + { + "kind": "file", + "path": "img_4216.jpg", + "sha256": "c7d0c09450ea1587bff4b801716401d0cf88382e3b318d161c23b2591a40c3f1" + }, + { + "kind": "file", + "path": "img_2667.jpg", + "sha256": "f3643bc6b12661c042a30a79204f598fef91643e814b885a7a92c9ba7a51a226" + }, + { + "kind": "file", + "path": "img_2101.jpg", + "sha256": "5ff77046886d403be0f5eefd5d90fd60c0f85a74fac453a3e115c25a235d2d3e" + }, + { + "kind": "file", + "path": "img_4570.jpg", + "sha256": "34eabcbe71627a3e07a5c6df58f5e9e63bbec3cb81c683580a1031cf970a428d" + }, + { + "kind": "file", + "path": "img_1408.jpg", + "sha256": "587fe9fe4aebb402ec7956086f0623ee1353aad03589f53f2549d26bc8b95ee6" + }, + { + "kind": "file", + "path": "img_60.jpg", + "sha256": "1843530ef384a1d62bc94748ff4a3843cbef567fe95e6865f042222f37b33bfe" + }, + { + "kind": "file", + "path": "img_4564.jpg", + "sha256": "607f270b6013c926f27ed1a40792a118e35770850065fc73f6184e448a41a6b0" + }, + { + "kind": "file", + "path": "img_4202.jpg", + "sha256": "6a56b8af20fd1d856e867711f47a9b379db7c163a4746cae4ec7449fdb251174" + }, + { + "kind": "file", + "path": "img_2673.jpg", + "sha256": "c89a35fea108b5064b0a35a81500cb93cc92d22800da9632d7f3bfd98a3f905b" + }, + { + "kind": "file", + "path": "img_2883.jpg", + "sha256": "cc9227fbb29d2ebb018609b2e5d2837bbcd9a3046a5f5c16ca85c3c885869938" + }, + { + "kind": "file", + "path": "img_48.jpg", + "sha256": "73d1315a3d6edf6c719179c64ef2a45577f7774f09d580a11f6f87120ed78de9" + }, + { + "kind": "file", + "path": "img_2129.jpg", + "sha256": "b37cb09a5b1c09ea2cc0325750909f1cf90e64fa360388ec33c0b9b63e31ac8c" + }, + { + "kind": "file", + "path": "img_4558.jpg", + "sha256": "a35672acfffe7074883e0600b85abb3e306e8e3c8684286746ab95e346743748" + }, + { + "kind": "file", + "path": "img_3237.jpg", + "sha256": "3624e6f66df862e4b2d96bcd7139ecde3f1ceca129b6b172dddaf46c2cae2a40" + }, + { + "kind": "file", + "path": "img_1420.jpg", + "sha256": "b175aef0c6312fd6d6a8e85dd453dc2c7b5f249b36b12b1ceb7f2e9f46db4dfc" + }, + { + "kind": "file", + "path": "img_1346.jpg", + "sha256": "48ee2fdce7cdd822d11ffcfacc1d9c575090af22a4325fc2ec32d8f2a534e9d7" + }, + { + "kind": "file", + "path": "img_3551.jpg", + "sha256": "1483f557f48a362f170805e68ff992af47eaa3647da44b9750ef2ddf9ef740ee" + }, + { + "kind": "file", + "path": "img_2897.jpg", + "sha256": "490c86c30d82cc56f3dc280f8706a2bba30a0bbc09c09bc222c8c6e9ea9ebaa2" + }, + { + "kind": "file", + "path": "img_359.jpg", + "sha256": "eca5f398ee6e474d0ae31087ede9d2655c5855b42adf2672757f9408ffc064cc" + }, + { + "kind": "file", + "path": "img_2868.jpg", + "sha256": "f65999338f10e408a4bebf81d6da42d6aa1b76c806a81cd270109f59c9fb42e8" + }, + { + "kind": "file", + "path": "img_1391.jpg", + "sha256": "a60b05122d37cee789542f7b9389f29b5b405eaea17e19ce5b074add15d7ff40" + }, + { + "kind": "file", + "path": "img_2698.jpg", + "sha256": "ec63c8f40a7dae4157495f9dc3ed5d330f000b3ed816867dcb58150b2375b346" + }, + { + "kind": "file", + "path": "img_371.jpg", + "sha256": "043d3642b928d7719c1d9894b3891d9f6d243b289c3e0db7e2f3ce6e07dce3ad" + }, + { + "kind": "file", + "path": "img_3586.jpg", + "sha256": "a6ef563ce609a83ecda502d324b4a3a84c5658ee4c854c510269ae0b182bb8d6" + }, + { + "kind": "file", + "path": "img_2840.jpg", + "sha256": "2bb6170d624dcff2cf8b0b896cf7e95ff2947233267ecb257519f40864fb5b60" + }, + { + "kind": "file", + "path": "img_417.jpg", + "sha256": "f850448256197092cb5c996370b2e0ed09506d075669250abeab6367edc50491" + }, + { + "kind": "file", + "path": "img_403.jpg", + "sha256": "9b62424274d46c932fedd21939659e18fa83005a986498098a48ff6f128f00af" + }, + { + "kind": "file", + "path": "img_365.jpg", + "sha256": "c085bb29ee497504fb7f633957a05623a5c010d4a88fb80ff600f9d5effaf8be" + }, + { + "kind": "file", + "path": "img_3592.jpg", + "sha256": "e2109b249098244e83e357df3996cb1e08d9d9cfe2d9aa9cdabdc01cb6762137" + }, + { + "kind": "file", + "path": "img_2854.jpg", + "sha256": "ac49753a1a06cbdf31dd33de51a7f38a859e73f499c02c1f022a51d011926183" + }, + { + "kind": "file", + "path": "img_1385.jpg", + "sha256": "d5f05672e5cdd20d98ca276c5cf352324fd07c80e6dcf397154f4b7dad8a5808" + }, + { + "kind": "file", + "path": "img_89.jpg", + "sha256": "aa0590a02a65f1979fbd78d606c13fc55bfc74453344575f85799a11ae930ec2" + }, + { + "kind": "file", + "path": "img_373.jpg", + "sha256": "56f3fda57ede0feedf9243638db5f1fe4e6e8b07abad6cb501d54c4bdad1c4e3" + }, + { + "kind": "file", + "path": "img_3584.jpg", + "sha256": "4eb781b67e4eae20155f29072bfcebd68572855f7676f76bed94271966ebc5f2" + }, + { + "kind": "file", + "path": "img_1393.jpg", + "sha256": "daa9f67e8ac9b840d584668f1df3d82683e7c385542ec99d24b17b3291e34a80" + }, + { + "kind": "file", + "path": "img_2856.jpg", + "sha256": "23d731c653e56a2c0160c9982ee2db186ec8e300c9e838b7f24de527fc8c0c35" + }, + { + "kind": "file", + "path": "img_367.jpg", + "sha256": "3fb4d76d559315d35906fb9303dd23631ae860523f0e67aa0d424920ee1c5ad8" + }, + { + "kind": "file", + "path": "img_3590.jpg", + "sha256": "e565f153c27e8d684a74a4ca717abd0775fdcd24594a6e38453f98c5cea39e0e" + }, + { + "kind": "file", + "path": "img_401.jpg", + "sha256": "064480dbf2d5af130fcf7464913d8708ea998b162d1c4b806432289480fb9e95" + }, + { + "kind": "file", + "path": "img_4599.jpg", + "sha256": "72659d43e69823ef55b499687e35bb5c1766d475fe3c4c87dcf1a4ca84469bb9" + }, + { + "kind": "file", + "path": "img_429.jpg", + "sha256": "dc80c8aaa69a632f2acd8aa6a329a369dd1ae109f5a1050425b9e0cb2ef5eea7" + }, + { + "kind": "file", + "path": "img_3221.jpg", + "sha256": "11d530eeff0677ea34e0983aa2fa79eaf6181b85d624c6ff0b06d5e27194362c" + }, + { + "kind": "file", + "path": "img_1436.jpg", + "sha256": "3d18292b2f743803873ea28643f0e7c9e3bf9f71a2caa73bd82303b13994b918" + }, + { + "kind": "file", + "path": "img_1350.jpg", + "sha256": "6121972f631343702532d77372e1b58679ed687da4dd05288a8313662f66c188" + }, + { + "kind": "file", + "path": "img_2659.jpg", + "sha256": "4fe1614d588857c3c73f66b74e3d62daa2dc9fd5247a1a9146a438edac0ecc04" + }, + { + "kind": "file", + "path": "img_4228.jpg", + "sha256": "d2ed0ea6f1c24a0ca8bcc2a311762c8f7e973b0038f5c41b43f0d9303c56c029" + }, + { + "kind": "file", + "path": "img_2881.jpg", + "sha256": "ecf7dd6108dc7382aff79256d7634ae5976ddc17be3df7403e71f9ef96681ec3" + }, + { + "kind": "file", + "path": "img_3547.jpg", + "sha256": "89eb9c7c37545b6d0f0071da7acc37e896900e342a9e51bb12213c8098c3f3fc" + }, + { + "kind": "file", + "path": "img_1422.jpg", + "sha256": "bbc8262d0a2f15a3f78e30d0ec666656a6edfcd0b43cab1017a53352312b97ff" + }, + { + "kind": "file", + "path": "img_3235.jpg", + "sha256": "7719998f0bc452d2fc4d9e293597cd202658a1c3a93dc8a47d5a46837873457d" + }, + { + "kind": "file", + "path": "img_4572.jpg", + "sha256": "fce9f4cac66985273472cc9b84655d8a5019a5403390a9af3ee0903b2c44a0e6" + }, + { + "kind": "file", + "path": "img_76.jpg", + "sha256": "3c0557650e82e4172849291aef27cd6a271454874a9ddbeed5c0666c42df1d05" + }, + { + "kind": "file", + "path": "img_2103.jpg", + "sha256": "624980b55fa0b46364eac9bf0fb1e800d7510c1cb87f4766dac4440707addaf4" + }, + { + "kind": "file", + "path": "img_2665.jpg", + "sha256": "51b8d2892aa6487257c1066ce52ce1a588b14c456fbf93fadf50060465efb704" + }, + { + "kind": "file", + "path": "img_4214.jpg", + "sha256": "88a6252eb2f09882744b32f4114682c714f9d1aaf403b351544506270643b0b6" + }, + { + "kind": "file", + "path": "img_2671.jpg", + "sha256": "e0593186bd383c7fb731dbdbff7984dc7cb64cf826ef833cda30c85bf97a2439" + }, + { + "kind": "file", + "path": "img_4200.jpg", + "sha256": "a2efa57def70435a256779914217ed10eec59042962a5935ea87c069b7cfd792" + }, + { + "kind": "file", + "path": "img_398.jpg", + "sha256": "9c3242285b16f33539a9e9f534f2e3b0bdd492ff14a9565c18ea9b7df3f0a99e" + }, + { + "kind": "file", + "path": "img_3209.jpg", + "sha256": "70453befb84b0e2eba8a828b7507da20231a0fdccbf343de726f6eed4047ee9e" + }, + { + "kind": "file", + "path": "img_2117.jpg", + "sha256": "dcff68bf70bb7e39bef72586a148f8949abf52c1f235cd238ebfe2af6087e674" + }, + { + "kind": "file", + "path": "img_1191.jpg", + "sha256": "f21d2b3c551c5c325276bb23033f28e15ac61b2a95fcf0317b1e19f818434e9f" + }, + { + "kind": "file", + "path": "img_2498.jpg", + "sha256": "3d18a53ffac698a67d236cf166ca2ee46c5de84cbe5f29d614206bc46f638988" + }, + { + "kind": "file", + "path": "img_3786.jpg", + "sha256": "2cb1dc0d977df800c474acfc54c1d396c30c61bb10e7395d45b07069ea22826b" + }, + { + "kind": "file", + "path": "img_617.jpg", + "sha256": "bf731384ba7b6ce646161e328fb490b365b6713c94ede37e77f10f7ecdca0ffd" + }, + { + "kind": "file", + "path": "img_3792.jpg", + "sha256": "c6bace0828629b96d5200217a7c56b1434095302e5971f9b25c174f6c8598aa0" + }, + { + "kind": "file", + "path": "img_165.jpg", + "sha256": "2f852c95d351daa73064ed40900ab2c64a24bc86062252ffec8d909347dc4ff5" + }, + { + "kind": "file", + "path": "img_1185.jpg", + "sha256": "e45e097a6fc68c23fc48333b5a2af74cca2f8c03f6221344ca2790ff356713d7" + }, + { + "kind": "file", + "path": "img_3962.jpg", + "sha256": "095e08b1da2ec307791dac0c039c331ad84226b1948de16f622b1ec7afd08bf0" + }, + { + "kind": "file", + "path": "img_1813.jpg", + "sha256": "ae55daa7724599bc10324ca370487bf6ec1ef95024423fc75f6891ffdeb972ee" + }, + { + "kind": "file", + "path": "img_1807.jpg", + "sha256": "056d0c0a2f0e795e74624cbeecf25b8cc172cb324ac629fd682150c32350474d" + }, + { + "kind": "file", + "path": "img_3976.jpg", + "sha256": "af19eec1b0786c9168679087187f6426876e623018a7d29c83b42acd3ffc7f69" + }, + { + "kind": "file", + "path": "img_159.jpg", + "sha256": "444ce76aa4a854218c9a880f348a3de01717fe2cbbbdf71e2aa0de47d9355bee" + }, + { + "kind": "file", + "path": "img_3745.jpg", + "sha256": "fc57b8e1a3b3d83f7fd4f98ee8f49f1b565e87b59d81a996d847a332a58da9e9" + }, + { + "kind": "file", + "path": "img_1152.jpg", + "sha256": "ead67cac2d2ed9f7dd6e27544901010199166f75e93e0fec954dd434975fa9d9" + }, + { + "kind": "file", + "path": "img_1634.jpg", + "sha256": "5d97d3e10aca5c2fdbe8657feb24a0eb8aa841d6a44edd020e63de3cd435e58e" + }, + { + "kind": "file", + "path": "img_3023.jpg", + "sha256": "b001acec0f7168d29766e3cd09519f23969c443ffcf451c50f539680383b6ea5" + }, + { + "kind": "file", + "path": "img_2329.jpg", + "sha256": "b7f7fef2ca0c220a32a27ad795361c9962adb92fd33ebcb0fdc983b5a2f6e401" + }, + { + "kind": "file", + "path": "img_818.jpg", + "sha256": "c8cf549ea166e0ee0b25be47f80297e21a557f675f63c0ea9f2134f93665b2f4" + }, + { + "kind": "file", + "path": "img_4758.jpg", + "sha256": "ae94f5dff9b7921d5f936fb8886eafa03716b4971965a8f854be564f0c42dc4d" + }, + { + "kind": "file", + "path": "img_3037.jpg", + "sha256": "cd52ce23a2484901e451e370f1849d8e55feda52e4e3ced9b19b365d42a6fc07" + }, + { + "kind": "file", + "path": "img_1146.jpg", + "sha256": "05fa3c6dea4d5e119d89a00e38ca811380f0c61512efa603595170f0e892e422" + }, + { + "kind": "file", + "path": "img_3751.jpg", + "sha256": "27af84fb15064a4f002bc13a1c091ccf3200ce7f08e6f8ef964a185558bd9516" + }, + { + "kind": "file", + "path": "img_3989.jpg", + "sha256": "df37c4bfc21380c0457ecf31cbee2cb929b5bc749c7168e200bd390f089af9fd" + }, + { + "kind": "file", + "path": "img_3779.jpg", + "sha256": "b6ed23c741925254eaba08528410f6a0763120528418ac62355c73edf8928c42" + }, + { + "kind": "file", + "path": "img_2467.jpg", + "sha256": "d3859c62e397ea984e70cd9397524c36e5c67cb1952b8d1b98f2b3fb9f177108" + }, + { + "kind": "file", + "path": "img_2301.jpg", + "sha256": "a728efd0559db0ada562018f092a338948b65f4bf9a32f24d35e58ed0e30a2e3" + }, + { + "kind": "file", + "path": "img_830.jpg", + "sha256": "97d5b8389830add1250bd2c5fc237ee6d165dcbe5fa16d6f4ad55b83516604b1" + }, + { + "kind": "file", + "path": "img_4770.jpg", + "sha256": "2c8102f26e316b61bf7137a9541cd930414f3f76d376bcd78e59ce16a8048ca7" + }, + { + "kind": "file", + "path": "img_1608.jpg", + "sha256": "b103162e9c5cb3563c6fbb941a06f5053f3fcf6f821b9a129dd3b290f27a614b" + }, + { + "kind": "file", + "path": "img_2315.jpg", + "sha256": "b7e175b3b5cc9bdae2405c20c4ad0bbfb683db61dd13fccf3dd2921366d7ab10" + }, + { + "kind": "file", + "path": "img_824.jpg", + "sha256": "99e92a8be8b3c28a85992bc9b891126e4bd9e5e9783c8a0cc1442619cec55425" + }, + { + "kind": "file", + "path": "img_4764.jpg", + "sha256": "f3140702d6f8519e3f48b145f6370c360cc3a49e405f09f700a5dc3524c7144f" + }, + { + "kind": "file", + "path": "img_4002.jpg", + "sha256": "679d6cfff976abf29f12e82674a2ebb3396a4f61b129bb53295fcac8dcce11b5" + }, + { + "kind": "file", + "path": "img_2473.jpg", + "sha256": "c7595ebf0254b223451e1605616d2c4d5320faff73a28bdc7b54b25faea83e32" + }, + { + "kind": "file", + "path": "img_4823.jpg", + "sha256": "d5f03d90816418a4fdf682546517b95e6286961c77df38c71a93232315cfd5e0" + }, + { + "kind": "file", + "path": "img_3194.jpg", + "sha256": "813850aa8734324ad765e0f049aca449018828b2c4f2ee991daca5b750131c1d" + }, + { + "kind": "file", + "path": "img_763.jpg", + "sha256": "a9f550bed02d72e3aaeb50df7ee320e607e7c45d99926bbbcf51e9f2d1c3a693" + }, + { + "kind": "file", + "path": "img_1783.jpg", + "sha256": "16118b1bb8ad48397ec5c2cd457a896e42bdcba2c9b8c550001c9badfa8a648c" + }, + { + "kind": "file", + "path": "img_1797.jpg", + "sha256": "b5e2d6a2af6bd06f436a10a7298776be18f6e6120a8da430ba61a95711cd2ffd" + }, + { + "kind": "file", + "path": "img_4837.jpg", + "sha256": "39c70406253cc88033690ba0c9e5f70727604857346abc12c567144030972070" + }, + { + "kind": "file", + "path": "img_3180.jpg", + "sha256": "c478e1b5c6e0aa11d83b263b94603b4abe2f5be51cd8252c561de598d0c9e3f7" + }, + { + "kind": "file", + "path": "img_777.jpg", + "sha256": "91b3e5751a1a953031a2910f16b5c177fc323a4dc5a8a5a2a8b54d9bd2b852c7" + }, + { + "kind": "file", + "path": "img_4189.jpg", + "sha256": "cea3f782b74b76c10c8d339a192c7717be770fe761adc194d06e83efd9c4180d" + }, + { + "kind": "file", + "path": "img_3816.jpg", + "sha256": "cc96d3afba9a45fea9c38e1f61ab6e87863ccdee1b2a1657302072ae143ba1df" + }, + { + "kind": "file", + "path": "img_1967.jpg", + "sha256": "1967f7a60dd8d6f3dda94b02fa96a05790fe9aa3f30b32893856ab6c9eb22b00" + }, + { + "kind": "file", + "path": "img_987.jpg", + "sha256": "597d61625a3560a14009636a7a26748c21ed21e772e005cbeec6215c6a4c122e" + }, + { + "kind": "file", + "path": "img_993.jpg", + "sha256": "c7b80e84d8549681698d910763564585b61546169c205621911079685b9fdb4b" + }, + { + "kind": "file", + "path": "img_1973.jpg", + "sha256": "86d144236b4491504d6a1c89b03bb088bb3971115c52f5fddc987a937419fd4c" + }, + { + "kind": "file", + "path": "img_3802.jpg", + "sha256": "a9fd5c937caabd7fca9df5c3230ec8f69e4cbca0b413d60b260baa5658bc3e57" + }, + { + "kind": "file", + "path": "img_3631.jpg", + "sha256": "8e8436c4552c2155de5373a5645ffac029696ca85f4616e60ca0eec59c4f090f" + }, + { + "kind": "file", + "path": "img_1740.jpg", + "sha256": "e2ac2790ac4ae755031ab602a2d6631238b84e73c93e6464f7f31a80534dc662" + }, + { + "kind": "file", + "path": "img_3157.jpg", + "sha256": "fb46fcf7a66f48530668de39a0ed6931ef85990fea3aa0d42a49fe8769d222c2" + }, + { + "kind": "file", + "path": "img_4638.jpg", + "sha256": "e6d29f0cd6eb7205a259e73890efe201758e1da7badf16c85b1817d744bbb4a0" + }, + { + "kind": "file", + "path": "img_978.jpg", + "sha256": "fe882a959cb1480722fb894f63c69f7951d46dcd46b1a760f88a98b4577ded91" + }, + { + "kind": "file", + "path": "img_2249.jpg", + "sha256": "119a95a07091ad533d2f1048eb56a25c2a3124c16381360fbd140f5c57eeeaee" + }, + { + "kind": "file", + "path": "img_3143.jpg", + "sha256": "25f8a036293acfaa57071b73d07d174fe9a71612184a2e44b07936050436b10d" + }, + { + "kind": "file", + "path": "img_1754.jpg", + "sha256": "1c3bbe4ac0911f2831f325fa8267ae473a36f01ab7f71fd9f2f0c651cc2bcd96" + }, + { + "kind": "file", + "path": "img_1032.jpg", + "sha256": "4870667d0a29ffa347ada0667c85338c05fd9ea2e5ab7894a0baeba34b4114ca" + }, + { + "kind": "file", + "path": "img_3625.jpg", + "sha256": "432a397aa3b974f579bfb108ae5c241a3dc825c16985480f048ac6b23a01ca11" + }, + { + "kind": "file", + "path": "img_2513.jpg", + "sha256": "ceeb8db6b5d74e2249b959a518a0f3f615462d113f953eb41986a58228b6eba5" + }, + { + "kind": "file", + "path": "img_4604.jpg", + "sha256": "87a36d3022a3652f9798c122eb78fc42c9405fcb5a3e4ceff51f25648be8a293" + }, + { + "kind": "file", + "path": "img_944.jpg", + "sha256": "79b6708d4b4034fda861adc716fc8b6fdfa75971cba7ca44bc0903350e7d80cf" + }, + { + "kind": "file", + "path": "img_2275.jpg", + "sha256": "1d0b6360203b0fef32426b5bfbedd456ef893b9f3816e861ce5437d33185c184" + }, + { + "kind": "file", + "path": "img_1768.jpg", + "sha256": "10b4f37238ed191c2e06e45d355d951b7a6092a631260ceba473171f2c4d8b17" + }, + { + "kind": "file", + "path": "img_788.jpg", + "sha256": "2031b09a2be835a9deca778bbab6e3c45d9eb23b810b08d579899d2d55271338" + }, + { + "kind": "file", + "path": "img_4610.jpg", + "sha256": "e0ef5de170cbb825bcc4dee8da33ebd277873b108edfa194803499bcbaca4ca6" + }, + { + "kind": "file", + "path": "img_950.jpg", + "sha256": "593a122c1904bebeb3f656a5140c4a231b392ce7621176f018eb24a40a320810" + }, + { + "kind": "file", + "path": "img_2507.jpg", + "sha256": "b828094ac5617a189d04ff24ca6df1864234086ad5549d8130dd3bcb5e79311c" + }, + { + "kind": "file", + "path": "img_3619.jpg", + "sha256": "83b8d2f6bab7bc0a7e7e32d1df96d95317ba92b46c9e52602c338b64ca532149" + }, + { + "kind": "file", + "path": "img_1581.jpg", + "sha256": "c1b7099e0c0c486735e34292bc4240d07463331e8072f21bff86a26c3023afba" + }, + { + "kind": "file", + "path": "img_561.jpg", + "sha256": "d56a2c916cb2e91f067909f3e8bb5870b5047fc9a98d4324802649f2b2ab5072" + }, + { + "kind": "file", + "path": "img_3396.jpg", + "sha256": "7d8993ea7d00b54ff37b0dd991fd555085a9cf8dc1ebb959a1c87a991c91be46" + }, + { + "kind": "file", + "path": "img_207.jpg", + "sha256": "1ea7b5b61e1d307b85975a883b9503cf3ea925faa69de3734723c948a66e303b" + }, + { + "kind": "file", + "path": "img_2936.jpg", + "sha256": "342d0be7da25aba8c4eee7618138026f10e3e8c5ab366051980467ba554d8ea2" + }, + { + "kind": "file", + "path": "img_213.jpg", + "sha256": "7f87eee57465637dc65101cce8865ba8348062b395d1ebea5a1debd02bb1c831" + }, + { + "kind": "file", + "path": "img_2922.jpg", + "sha256": "85e333fd6c0d4ae6a90c15b8b1cb1667b4e921cf0b0b1e97a19a5df6219bcf0f" + }, + { + "kind": "file", + "path": "img_575.jpg", + "sha256": "9fc05d0ed99f4fd9802d32a5f7e862fa426e50aabe0f535e0a8162c49fd00e90" + }, + { + "kind": "file", + "path": "img_3382.jpg", + "sha256": "bc3b55fb198fad860316c0a843817da0aca779d82d25284f8fd9eceb64f8546a" + }, + { + "kind": "file", + "path": "img_1595.jpg", + "sha256": "0ed5e0dced2a2a5ae8c0bdbfaa4acd70a670dad25a6932509d5dc7d4d24331b4" + }, + { + "kind": "file", + "path": "img_549.jpg", + "sha256": "ee72d2af6fb310441eb87130f9bae6cbc97f806dede09df124f6b9b6c67e6311" + }, + { + "kind": "file", + "path": "img_3355.jpg", + "sha256": "a58af20d517aef15a63d2b4155b2854904c31fdbd85bf04e8039f93f36994f27" + }, + { + "kind": "file", + "path": "img_1542.jpg", + "sha256": "4dfec7c5055f694395f2daa5ec179601974faa1e5b995e21eae2143a27b86249" + }, + { + "kind": "file", + "path": "img_1224.jpg", + "sha256": "82157333a56b71f56a7633f5d1ecb288083075674af39ddf30395c91ebf9a589" + }, + { + "kind": "file", + "path": "img_3433.jpg", + "sha256": "817ba02daec73e92892b643d41d470e777a9d82133581d597595aeca2be31756" + }, + { + "kind": "file", + "path": "img_3427.jpg", + "sha256": "0f2d661068b3a96c6d10196586f573f87c8912aa14bebffff2c9208e5055821c" + }, + { + "kind": "file", + "path": "img_4348.jpg", + "sha256": "79250703042daa832f68ea85ac5057a81c0241929fa80be1ed4cfa2d1d0d6235" + }, + { + "kind": "file", + "path": "img_2739.jpg", + "sha256": "d9ddd8da5cf25f0fa1fef8ff4dbccdf3b8cf32e5e4d9d7f92932ac94e8af4849" + }, + { + "kind": "file", + "path": "img_1556.jpg", + "sha256": "8b8570174c9d11653e394154a181e36c533195886ec8b14d4ff2cad5411dae66" + }, + { + "kind": "file", + "path": "img_3341.jpg", + "sha256": "5c82a70a12276578ec4b47c0c30e986f6b6cb95c9bc973961b25dc10094bb2a6" + }, + { + "kind": "file", + "path": "img_2077.jpg", + "sha256": "5172fa9a7fe9cb47356de2bb8e89ab4d781bfb014ee06f0160e3f8689d21b06f" + }, + { + "kind": "file", + "path": "img_4406.jpg", + "sha256": "ca016d8a2547882c2034bb593d86625d2ee9497797ae60a9b60ae84c466bd9ee" + }, + { + "kind": "file", + "path": "img_3369.jpg", + "sha256": "c9d968926718f321d3096e862eb09a2e88a8a4c80c5b2a9564e13201609e6ece" + }, + { + "kind": "file", + "path": "img_4360.jpg", + "sha256": "c013720ba63f9af89fabe8a7aff23967ba53d6249d3a0cd7e46c7ce036e4af8e" + }, + { + "kind": "file", + "path": "img_2711.jpg", + "sha256": "29366fb1479bf29cc2780fee3a1c1e1077cf6cef8d35d9ec8105fea66e26971f" + }, + { + "kind": "file", + "path": "img_2063.jpg", + "sha256": "4cd93f339c1e3e8e8c3af32ee7e2677bac8867c5d5d73de648749b5679401709" + }, + { + "kind": "file", + "path": "img_4412.jpg", + "sha256": "7ef1b9e1c61847e2fe43656347951319b04308a3cefe0f23d89912b6861549f2" + }, + { + "kind": "file", + "path": "img_2704.jpg", + "sha256": "5b5e6cf5e81e99ed8754f6f802eeba133eeb0f4f637943a2c235ee41e2f93283" + }, + { + "kind": "file", + "path": "img_4375.jpg", + "sha256": "2f9e45772fefa76fe6610ea5f5c47f0713f1cd1a1f74ca68d8e585c6da32149a" + }, + { + "kind": "file", + "path": "img_4413.jpg", + "sha256": "f44361b188a6d9e481c06f2b2c50dd45a5d419d49ed5dd7ba966e347845d39d8" + }, + { + "kind": "file", + "path": "img_2062.jpg", + "sha256": "cb1a2a11accfd3dfdd23677aa582ea3ee3382b0c56cae5dc43c883b59f3cba4b" + }, + { + "kind": "file", + "path": "img_3368.jpg", + "sha256": "3ff0568ed85beaebdf2b2b342674cc40bfda2017f59766d74b7bca0718724bb9" + }, + { + "kind": "file", + "path": "img_4407.jpg", + "sha256": "5ffe1300253b395f3f5d90814ad486af75b3404992194f98712bd50e5ee56364" + }, + { + "kind": "file", + "path": "img_2710.jpg", + "sha256": "152c636074a80c7b9674e5dc098e3928a81cacce84016bf111a2366bb29fc3df" + }, + { + "kind": "file", + "path": "img_4361.jpg", + "sha256": "566b0b805b27da2e4d110a844016c1c995579f4cd13608c913779c0b6da1b36c" + }, + { + "kind": "file", + "path": "img_1231.jpg", + "sha256": "22b338c13a08d168d63fe31f9e23e0561e5e7eb8f382759e7319ab5d72e1d2bd" + }, + { + "kind": "file", + "path": "img_2738.jpg", + "sha256": "6ad1299bb7ad4cad52fd17495c14610419cb875880e3121ed44bbea15974cef0" + }, + { + "kind": "file", + "path": "img_4349.jpg", + "sha256": "d111bde311b1caf502aa2be1e0e0e71ce7929ccd425186ae7b78ee8233e98814" + }, + { + "kind": "file", + "path": "img_3426.jpg", + "sha256": "5306a2fac90c68f966bee34d6c926fae71705465d2191f946870bb51a001a6dd" + }, + { + "kind": "file", + "path": "img_3340.jpg", + "sha256": "492e2b2ff5aa9f0318374f4a8ce55b1deb3733e13eddb9702d1a0b2479bf86fc" + }, + { + "kind": "file", + "path": "img_3354.jpg", + "sha256": "416f88c13cd98fb67a273702b87d793fa04502ee22af4b57b13cfe1921c15de2" + }, + { + "kind": "file", + "path": "img_3432.jpg", + "sha256": "999606b3e414c09eae7b52b68f9ef3cb55aab638307bc887f4b8670a43b3c2d8" + }, + { + "kind": "file", + "path": "img_1225.jpg", + "sha256": "bb1e41ce17dde416d02d67ee29382d2f3104aeda11123e615af4a8865122f841" + }, + { + "kind": "file", + "path": "img_548.jpg", + "sha256": "27ca052c011a574965c21190ac7c248aeeb6b419f40afadb35b829b7deb7e67f" + }, + { + "kind": "file", + "path": "img_2923.jpg", + "sha256": "f187ffa643fbe2d75b2166dad313534aac14480ad8caac250832e86e42b460f2" + }, + { + "kind": "file", + "path": "img_1594.jpg", + "sha256": "a83224a5baf26beacbde19e2c80a9f76e9a9b71c9838db5645cd7aac75ab3886" + }, + { + "kind": "file", + "path": "img_3383.jpg", + "sha256": "fa063f023f98ed267a7371d0bc5e762073c99029ee55fc4b1bc508140f95b302" + }, + { + "kind": "file", + "path": "img_574.jpg", + "sha256": "777d1bfed59bef4c779ff323cd6e9e717e4c2ae3f37be11601c0359d1bfe34f0" + }, + { + "kind": "file", + "path": "img_2089.jpg", + "sha256": "77e4c875cebcc1670bb127bbd2ae13edbd851dca09c0acbc6404286fb42f9b60" + }, + { + "kind": "file", + "path": "img_3397.jpg", + "sha256": "73757d5d0d6ec55c74afa7c14713c421f98cce042eeee5a142216439df16ff35" + }, + { + "kind": "file", + "path": "img_560.jpg", + "sha256": "fcc2175a7a90c161b9bfb99437dbd6baeb39b8e31cd04b44d43acf7af168c0af" + }, + { + "kind": "file", + "path": "img_206.jpg", + "sha256": "900d4b3cb5312b1b4cfcf69d6349cc2c4b0d51a9c8d055492e367758a4af2fdc" + }, + { + "kind": "file", + "path": "img_2260.jpg", + "sha256": "e854ba1c0d5d0c8e0a57a54eb2b7f17d4bce51733318fc4f82999cfa965ac4fb" + }, + { + "kind": "file", + "path": "img_951.jpg", + "sha256": "db7bbeee84962ceb473f74586e453d40eac7b7332f490f79e1628de453a476be" + }, + { + "kind": "file", + "path": "img_789.jpg", + "sha256": "5c27008ba158f87de53fcde43deb730324182aa6642ac04ac28efec32dd40f16" + }, + { + "kind": "file", + "path": "img_1769.jpg", + "sha256": "32f7e14517e2f68e61bebeb3afbf619963f2e2c8c95c8a43a55ab297830e15ae" + }, + { + "kind": "file", + "path": "img_2512.jpg", + "sha256": "114b92e5d1f94486c37daf1bfff691b9828661cf01af3fa335c0fdf97cb58284" + }, + { + "kind": "file", + "path": "img_2274.jpg", + "sha256": "7681d0eef35a5cd9ba48dff3a30dbedb816fa9fd303c46035ce0bcfaeaf548fd" + }, + { + "kind": "file", + "path": "img_945.jpg", + "sha256": "26d60b125658e5d0625b83cff47e9b89a44a77a9806f5c947a26ca1ac37afd7d" + }, + { + "kind": "file", + "path": "img_3142.jpg", + "sha256": "5aaf7da5cc4a242ac0e3d10ed4848871a18316c299b0753dfd9cdd66084a546a" + }, + { + "kind": "file", + "path": "img_3624.jpg", + "sha256": "5b374a27eec05e42285257783b04ca0a644f673af31b04e23cae6fe1ee820e9f" + }, + { + "kind": "file", + "path": "img_1027.jpg", + "sha256": "7c4a750a71b626c7b4166dfd5c82970e44dec84f184f1accb31096ecc0b1d1aa" + }, + { + "kind": "file", + "path": "img_3630.jpg", + "sha256": "639ef7f02366f2c1a86c9df5024f886936bbeaad4691d7938a8ed1af0c5f8ca0" + }, + { + "kind": "file", + "path": "img_2248.jpg", + "sha256": "1ff0298c2d927c78c0340b5da042afd540b8711afd6ee0a4934271eac444dbcc" + }, + { + "kind": "file", + "path": "img_4639.jpg", + "sha256": "90e9d2315bfeca8f6344f40a49baff3501c569e074fa7a8a2e445d2610a9c75e" + }, + { + "kind": "file", + "path": "img_3156.jpg", + "sha256": "4e073620ae4cd415aceeba605a484a7798c9efd21a20a84e83f9d331036d987e" + }, + { + "kind": "file", + "path": "img_1972.jpg", + "sha256": "7f2d8533b5fee320d2dd53926f726573656992b30c0737ce29c760dcfc40de16" + }, + { + "kind": "file", + "path": "img_992.jpg", + "sha256": "8cfc4628a68577280ffef1bdba2cf3fb68f19adce35d680a652659d44dbadc55" + }, + { + "kind": "file", + "path": "img_3803.jpg", + "sha256": "562e0d78236c86dc22d8885af159cd81905d7894b3b7bf9a15c0634a068c1922" + }, + { + "kind": "file", + "path": "img_986.jpg", + "sha256": "a1519e36453f16cd2685b1c9cdb9aef45985fdf3d54d2a70f7dc424b44ddd960" + }, + { + "kind": "file", + "path": "img_1966.jpg", + "sha256": "2c20012ebcc7851c9e90fe7c34e07cdd6cd1aacc9bda135597adbc43a3bbdd48" + }, + { + "kind": "file", + "path": "img_4836.jpg", + "sha256": "b848bb3515fb4c31912f93e83d5f4e94d143b3c464f2a21de1668faf4b1b5962" + }, + { + "kind": "file", + "path": "img_4188.jpg", + "sha256": "9d8bb4caa1ed4e324ff8b6418c2899ca68145f370ac5915c9d00e64b2a8a834b" + }, + { + "kind": "file", + "path": "img_762.jpg", + "sha256": "a5ed94efc07ceb63d5e13a1cc2ebe2933678123af328649f3e77dec2bd7b3925" + }, + { + "kind": "file", + "path": "img_3195.jpg", + "sha256": "d65b4b30faf5f12cff448791d305b79b9608cb9c08f5ced2ca99570445ac0148" + }, + { + "kind": "file", + "path": "img_4822.jpg", + "sha256": "e703945610f5ec69c10dda523f20cedc78bb6967782b174bd6b0acd66e8410d7" + }, + { + "kind": "file", + "path": "img_4765.jpg", + "sha256": "7794c1b3d7b2b866a5b12d42fca30848f2a38b926c1171a77787014a4c04051e" + }, + { + "kind": "file", + "path": "img_825.jpg", + "sha256": "5cf8e9793eec52468cbeab9610041eac17d86b73d999f23910d824f08804b07e" + }, + { + "kind": "file", + "path": "img_2314.jpg", + "sha256": "a1539ecd637009f6c40d8d8fe045478ad4a49171cac929dac0f9578d5e65456b" + }, + { + "kind": "file", + "path": "img_2472.jpg", + "sha256": "e8a3c65d3534326459a00b92cf900403a813b7ec915858ec5061b4348a4a9de4" + }, + { + "kind": "file", + "path": "img_2466.jpg", + "sha256": "aeb6707caa327c2e2664fcda56fdbdbf4212e051736437a2d84fe6fc58782b66" + }, + { + "kind": "file", + "path": "img_4017.jpg", + "sha256": "e25fa9f9444e7990759845a759508c6f3440528c9ae6ee8f1858cb8050e31613" + }, + { + "kind": "file", + "path": "img_3778.jpg", + "sha256": "49af43e767ecc037f51e572121dcb4800898c1e1e17c5264278b7473e90a62f3" + }, + { + "kind": "file", + "path": "img_1609.jpg", + "sha256": "6682c753f4da9957eec97ff8224a2c705cc3820b6e831b8774ee3a4b34397830" + }, + { + "kind": "file", + "path": "img_2300.jpg", + "sha256": "d78caba296f6a2f5c0051037bcb43e7baf6df1eca086d685ca1fae87b6290254" + }, + { + "kind": "file", + "path": "img_3036.jpg", + "sha256": "1df60972200db519d84456814d94e2ffb2aa1d6dce0dd10ecfb8f5010b609806" + }, + { + "kind": "file", + "path": "img_4759.jpg", + "sha256": "9f7d79b35e22bed081df4830e35c2681e2768dd8f15d03af7d0230dc2d0a90b9" + }, + { + "kind": "file", + "path": "img_819.jpg", + "sha256": "37b0c01521c1fb20b0fdaa5700239ebb1547fa76326caa2843fe9768a76f9ac7" + }, + { + "kind": "file", + "path": "img_2328.jpg", + "sha256": "ae3f3c1367de83e9ac1d2cdfefa7756e5c587789a671e8f0ead9d91a1692e60d" + }, + { + "kind": "file", + "path": "img_3988.jpg", + "sha256": "05f0ed261de5803ced7c1cb2a9cc21d72a8e988ea899f8ee592d6f5c165bfdfd" + }, + { + "kind": "file", + "path": "img_3750.jpg", + "sha256": "589399a3d22341479a97ee844a471015d018499ecbff65c1fe2675c4be21c636" + }, + { + "kind": "file", + "path": "img_1147.jpg", + "sha256": "cb67ebb1bbb3c1b54cc9eecde3fded7f937c38c22549cc78b17b5bd34b27680d" + }, + { + "kind": "file", + "path": "img_1153.jpg", + "sha256": "0f3a39fd79998b8d197c492a18044b38d8c710c47af8b1aa5a23efb966718ed7" + }, + { + "kind": "file", + "path": "img_3744.jpg", + "sha256": "ad29e0574e41315d2950871995d183f85639c8efdea0f9f6a9610a0e1aa4d986" + }, + { + "kind": "file", + "path": "img_1635.jpg", + "sha256": "be96c2b553cb1bfa53668a77bdbe0a801ce4a91753cd1811129c9aa93898a13e" + }, + { + "kind": "file", + "path": "img_1806.jpg", + "sha256": "e5465ca2c30fedf3b266092044d61ca10ac8b7698cfd0d5059eb2fb45779c68f" + }, + { + "kind": "file", + "path": "img_158.jpg", + "sha256": "55753954f7b8b5b860889a28353f4e25f6497ae15975430bcbe36c76148ac732" + }, + { + "kind": "file", + "path": "img_3963.jpg", + "sha256": "47e45a7e42c501b0187f7e01669bd55e898389f22e994807ae466ff5d33308e7" + }, + { + "kind": "file", + "path": "img_1812.jpg", + "sha256": "017f8186b0b9832f6e677ad838473cd23a4e5f0c7f621a4488e457e23cbe1dc0" + }, + { + "kind": "file", + "path": "img_602.jpg", + "sha256": "0f93f80eea75dec670a8b01f1729536ded8347b091c47d3b3d55b240c6e3129b" + }, + { + "kind": "file", + "path": "img_1184.jpg", + "sha256": "05982648ba769bc13bd0ea82332721a6b82574ce349f0b9623240cd74704d7e3" + }, + { + "kind": "file", + "path": "img_164.jpg", + "sha256": "bbd1c3ce8fb05026db736a64a94deef769c81459c69d4f96c83c5da1b35e995f" + }, + { + "kind": "file", + "path": "img_3793.jpg", + "sha256": "8789cf531f50d9c1fa4c6d0a5729de96e90e12d7524dc8fbd6645e45aa247213" + }, + { + "kind": "file", + "path": "img_170.jpg", + "sha256": "53294166d91a1bfd6883a5598387c2ca739577e02012e36d0b8c874a5f053379" + }, + { + "kind": "file", + "path": "img_3787.jpg", + "sha256": "28405e271d8af29c2cfc2e982731c37a639ab84da4a990257e830e2d81845770" + }, + { + "kind": "file", + "path": "img_2499.jpg", + "sha256": "4e0f786e86cb5d1ea1e13d4f9b2a63117ebd2305d226dd9134645cb992ee9f28" + }, + { + "kind": "file", + "path": "img_1190.jpg", + "sha256": "37b04c439824e9504706ae83a7fb2355220a3392709c3013e3ac31bade4bbaff" + }, + { + "kind": "file", + "path": "img_616.jpg", + "sha256": "39481fe85b354b0fc92f38f32d149965d456f3b8a66ae586cdccbbaaab379927" + }, + { + "kind": "file", + "path": "img_4201.jpg", + "sha256": "f66f82311d17918ef7f46a9a8e027e75c1d4f82c2339bcb81ccff56f564b3c06" + }, + { + "kind": "file", + "path": "img_2670.jpg", + "sha256": "98241af5b23784640789949014ea0aede85eba9f91809102e6db0cc411cf04fd" + }, + { + "kind": "file", + "path": "img_1379.jpg", + "sha256": "ad94f738958d16ab18f609eba36bee0c4526ef4dceb98136ad007f72263d9664" + }, + { + "kind": "file", + "path": "img_2116.jpg", + "sha256": "e6e1480ec6c9bd2df04934fcafb8361fca60c3accea21298945e57941abd66eb" + }, + { + "kind": "file", + "path": "img_4567.jpg", + "sha256": "9dccd44bd2d07cb42a70f46b3089ed660e58ab252958f159c9449ee260ddf1d6" + }, + { + "kind": "file", + "path": "img_3208.jpg", + "sha256": "f71ac38ce2033eb8f823ec916f0816f87c4e302187d57408f6abc852a8d21538" + }, + { + "kind": "file", + "path": "img_2102.jpg", + "sha256": "b45676681adcd5f5aea1261c95e634c403b7fdd1657e21553a49dd4c1dd1b90c" + }, + { + "kind": "file", + "path": "img_4573.jpg", + "sha256": "1063c8357a9759f4954964eec5111f4be9bbc8d0d3c4f850bfd6d232bdcfdee0" + }, + { + "kind": "file", + "path": "img_4215.jpg", + "sha256": "3481ae987f059052b5c7646ac362c2250745583bca788dc5bd82dd4a4365ca1c" + }, + { + "kind": "file", + "path": "img_2664.jpg", + "sha256": "f4ad66ff23d17893bf76ba3e3989340bbfe5f421560dd1346f843cd293e11a51" + }, + { + "kind": "file", + "path": "img_1345.jpg", + "sha256": "dba2db0064d9cc6395973459bd60344f212373c3fdabe6c1053269f4b9a7a540" + }, + { + "kind": "file", + "path": "img_3552.jpg", + "sha256": "54d88ef2772133d2516c3ca3a4d80897533d0c36c8ed1781e44db1c8ed7a787d" + }, + { + "kind": "file", + "path": "img_2894.jpg", + "sha256": "67ddae9c375b24aa6f4a77fb7f92cdf574e70adb7f128eb6af7d098d2682256c" + }, + { + "kind": "file", + "path": "img_3234.jpg", + "sha256": "3400299437c4e26d22eeb7ba49ad61977383e4675e19e34e6ba9198d2844bccc" + }, + { + "kind": "file", + "path": "img_1423.jpg", + "sha256": "9956f0506685fec5fe86a0bc087d8471c8941b323e5bcfc43d04b3830de2df98" + }, + { + "kind": "file", + "path": "img_1437.jpg", + "sha256": "ec3274f8be1bdef77e86b7467810d758443fab920a52eddc8e7e70adeafe4253" + }, + { + "kind": "file", + "path": "img_3220.jpg", + "sha256": "d8443d69c919f9fdd6d64d5f359f4b65c96d3767af970439157c9bba6eb10a4d" + }, + { + "kind": "file", + "path": "img_3546.jpg", + "sha256": "f1e2e3666f835697e7db564390509b0cd81998c8da4c781477eb26cb5c088738" + }, + { + "kind": "file", + "path": "img_2880.jpg", + "sha256": "3f6c575b5580990e5ef95588a2909499c7411be3ded13331ec07008acf7e759a" + }, + { + "kind": "file", + "path": "img_4229.jpg", + "sha256": "7e6fcba35170aa52e9165cb53f32e09af98f19207298f9414c01504e13cc77bf" + }, + { + "kind": "file", + "path": "img_2658.jpg", + "sha256": "5abd8ce6c19cbf6883ba55918a441ddb32ae49a9e121ba1fbd74171bc61e6d60" + }, + { + "kind": "file", + "path": "img_1351.jpg", + "sha256": "02697355c19d72304b71e98c9f445b3435262a8e3183897c09a253a52754d21d" + }, + { + "kind": "file", + "path": "img_428.jpg", + "sha256": "98dcda813b1aab4a8d4c35da7d679ddbc840e4a88a45837cf0f9605c777ac6cd" + }, + { + "kind": "file", + "path": "img_3591.jpg", + "sha256": "3e56e8b461322c430a50949a008210547a7783a0f153e7ffc28d61eada817c1c" + }, + { + "kind": "file", + "path": "img_366.jpg", + "sha256": "8397f167621a2e9680aeab8f5c4b5cf3b04e439a30c29d1a1bed86c3e29d7af8" + }, + { + "kind": "file", + "path": "img_1386.jpg", + "sha256": "d24e9f31d9fd6626e59b9963a6cb4982ad2584b2d7cdd59abedb47372e1a1196" + }, + { + "kind": "file", + "path": "img_4598.jpg", + "sha256": "755d455a550e5b1ed8c622474b69109a827754a79aa30d4ded894f3f7c262c7e" + }, + { + "kind": "file", + "path": "img_400.jpg", + "sha256": "21835780a42e152cfacc5985c554a6f086136ee1d297160492b2066ac281f050" + }, + { + "kind": "file", + "path": "img_414.jpg", + "sha256": "ec0f625c54d2c9070c4864d9be9c0aa864fc5ca420e3738cdca50dfd2443f1bf" + }, + { + "kind": "file", + "path": "img_88.jpg", + "sha256": "e979b543cd6c7a3167ae08c01842b0ddd265de17b9929a7d90303dae88bfbce9" + }, + { + "kind": "file", + "path": "img_1392.jpg", + "sha256": "086dc8362997e4b7d1b39d43a6aa0f5e5a89d19893fe0d70d48fb626562c404f" + }, + { + "kind": "file", + "path": "img_3585.jpg", + "sha256": "2a9ac895269087560d67a20fa3142a5905865777c6bc786d299ea84a11883cd8" + }, + { + "kind": "file", + "path": "img_372.jpg", + "sha256": "bd03e5cd23a97549f7af937703b9ced7e79e246d2cfbfd352732a1abca0c36ee" + }, + { + "kind": "file", + "path": "img_2843.jpg", + "sha256": "10cc93b774a838e8210156ad508bc6c05b13b18c0eb1757a55aafd8c5eaa525c" + }, + { + "kind": "file", + "path": "img_2682.jpg", + "sha256": "13401802643a17aca9d9dde72220ff0f54c7d53c8d1fcf2271b5765b9a183489" + }, + { + "kind": "file", + "path": "img_91.jpg", + "sha256": "38937a20f3203695bb4a6996907b6376df5aa2d0c8b659b5a0b6221ae38fbdd0" + }, + { + "kind": "file", + "path": "img_85.jpg", + "sha256": "dc4b87ce52c1856e639feee36b23e7433edc18de4aafa95d4744aa49c18118dd" + }, + { + "kind": "file", + "path": "img_4581.jpg", + "sha256": "057a049cd97724028b95cda5b8152151545a79cf23484bff925e1d96a2372a57" + }, + { + "kind": "file", + "path": "img_419.jpg", + "sha256": "469f9a479392eca3ca1b8dfd75244c7b19a041a983b59e7c3563842399afac8d" + }, + { + "kind": "file", + "path": "img_3588.jpg", + "sha256": "afc7ee0c512d0e594c0f2c16b44fbc955441ebad4f6391a4703f44b113823de0" + }, + { + "kind": "file", + "path": "img_425.jpg", + "sha256": "56662e79cf14493cc94cbdec45d983f7f45f065285d9fc4007a438bb7e8d4e8f" + }, + { + "kind": "file", + "path": "img_343.jpg", + "sha256": "a5d8c64ab53abff604be5b417e76048bb1aa47c7b039371775552d58d2270b7c" + }, + { + "kind": "file", + "path": "img_1348.jpg", + "sha256": "48ea8cd5daa05ce234b459c29e0198f6547790efb09eadec709d530d40613459" + }, + { + "kind": "file", + "path": "img_2641.jpg", + "sha256": "09ecd7966b43425c9b47ff8b4135f50c3edf20116e17c2b20bb040df900e7a08" + }, + { + "kind": "file", + "path": "img_2899.jpg", + "sha256": "efe900862d072d9009d530857c37b8d895db13bd9271b9530b1caba92e775906" + }, + { + "kind": "file", + "path": "img_4556.jpg", + "sha256": "b1522aaef35b6da8c638bba3a5b209fa30f02e2c8a030e79e6448e470c42f477" + }, + { + "kind": "file", + "path": "img_2127.jpg", + "sha256": "bc2a33b246ebc340baf6ae5583b812a73577fa1a567f15364ad7292cb4429519" + }, + { + "kind": "file", + "path": "img_4542.jpg", + "sha256": "415510816bf52fbdfd4888d09fd246f2d040240a8ab1106e3c41068551b7737b" + }, + { + "kind": "file", + "path": "img_46.jpg", + "sha256": "8f6f44cdc53f36a7a3ee9ffb3cf0bbc9434acd56e58fc3edaf8859280207e048" + }, + { + "kind": "file", + "path": "img_2655.jpg", + "sha256": "461e9d3230f23a1d72738a492e6f270ea9603e6a430eefc80b3443ce05d72949" + }, + { + "kind": "file", + "path": "img_4224.jpg", + "sha256": "84bba293d4855dabc8ab5365184c708172f8a41dec34789da007161f961177b1" + }, + { + "kind": "file", + "path": "img_394.jpg", + "sha256": "26c75d933243d443a38d7086bf2f53bc2be45d3e9c8d1d833291e6525c467de2" + }, + { + "kind": "file", + "path": "img_3563.jpg", + "sha256": "9ab48bd3b20c5630f22c201299ac3c36f3b22be32134547fd21347c1b4480a6d" + }, + { + "kind": "file", + "path": "img_1374.jpg", + "sha256": "6c7d55237e0dedaa988307298e4934db3a2590548e348c82352515445a9379e0" + }, + { + "kind": "file", + "path": "img_3205.jpg", + "sha256": "0fae50553a09c2fd9d6cc7e1ae460add7ed899fc85542fe0142d05cb66772252" + }, + { + "kind": "file", + "path": "img_3211.jpg", + "sha256": "3efe1397319f068e9b4e4f5e1d66d791c24b5a176d6dc29141cf045294abfc39" + }, + { + "kind": "file", + "path": "img_1406.jpg", + "sha256": "619a54d7586569f3a42fd2ad0c1bf4651144af6740f4438d8a2a985cd3264aef" + }, + { + "kind": "file", + "path": "img_1360.jpg", + "sha256": "248321dd0339ed3b1601172182b9e5ca0ccebb3f0b76d4ff97d04da79b73011d" + }, + { + "kind": "file", + "path": "img_2669.jpg", + "sha256": "50e60e60ede5165adaf9a497ba2f734a45f9f1dcfa639652294124ecf396ce28" + }, + { + "kind": "file", + "path": "img_380.jpg", + "sha256": "4b167311b466385b01d3a44d82168fc0c8501105d158fde124cee5f79f078f57" + }, + { + "kind": "file", + "path": "img_3577.jpg", + "sha256": "d2f9c42a17a0b74700c09fe8b1b1331820614765f181ee3922702fdcdf531373" + }, + { + "kind": "file", + "path": "img_4218.jpg", + "sha256": "089c6d88f344292810fb60df11d4326613ae7eb8d43d79d0d88e9da639fa988c" + }, + { + "kind": "file", + "path": "img_1837.jpg", + "sha256": "ee3c79d4b978b15b9aee874b75967a8cc34c9a21fa2a8e38304d85de2e68b031" + }, + { + "kind": "file", + "path": "img_2480.jpg", + "sha256": "93d4853e7b7004b657a99f79df9fea1ce612a6d65f177fe0fdc7fff2677e00d6" + }, + { + "kind": "file", + "path": "img_3946.jpg", + "sha256": "064b55c6a369f6a85879a4b20ebcca003e44d5fe37bffd19917223bf2ad50896" + }, + { + "kind": "file", + "path": "img_169.jpg", + "sha256": "2c8f8efbf1cab5ddfeafecb13fa8ecadfc65d88d29fb86d511ae2ab28c775671" + }, + { + "kind": "file", + "path": "img_2494.jpg", + "sha256": "fb3ccf0c90ef6e137f722c5751a29936b47b37570d690994f9ced6667aeceb1f" + }, + { + "kind": "file", + "path": "img_3952.jpg", + "sha256": "bbe0f13a97c93e4840beb44647168d41935547296be374f34b5351c37de33cb0" + }, + { + "kind": "file", + "path": "img_4783.jpg", + "sha256": "1e91a0b68bf30c8de54fd633a53f99b3c8795d8c9716e6127744dcf1bc0ee640" + }, + { + "kind": "file", + "path": "img_633.jpg", + "sha256": "0320a9f7060d2091ac01bc69b32061a3d91e62825b119d7d5729d3541c64449f" + }, + { + "kind": "file", + "path": "img_155.jpg", + "sha256": "f09df33ff4c60f06dfcf43b789b8c27bca2e93a2abe65183f9ceca5e895f4328" + }, + { + "kind": "file", + "path": "img_141.jpg", + "sha256": "829cc81f624c5fa6b2b2923bda102ad5b87b1daa84c821b5af9f149e2e03722c" + }, + { + "kind": "file", + "path": "img_814.jpg", + "sha256": "4e179768abaa1f252772f9a882b18a6de7322f26d9a02ae03bb3c9c91be9584a" + }, + { + "kind": "file", + "path": "img_2443.jpg", + "sha256": "d5b28052eadd206e49947602f611737df59a095388ea7ee909bbe0cd07d44149" + }, + { + "kind": "file", + "path": "img_3985.jpg", + "sha256": "fb4a1aa5cd2c74602ad2b7320f3c532f8c3274070f408039f3808a20e7b3f808" + }, + { + "kind": "file", + "path": "img_4026.jpg", + "sha256": "6392c5856abaefc45c08ec9dfab073d843fee2d5e89561adf381ffc432dadf87" + }, + { + "kind": "file", + "path": "img_3749.jpg", + "sha256": "7d0655f75a6251dc22c0c3e3b67e4ac2f3c29035770c88d854cbc8014286b61b" + }, + { + "kind": "file", + "path": "img_2457.jpg", + "sha256": "ea0333cc2e053f3ee1dd52c3e8bfcf6b40c5ccf3a27ec1fcb4c0f3530d963751" + }, + { + "kind": "file", + "path": "img_800.jpg", + "sha256": "e5fd72c32e073a69b58a44e3c5092a951a408e73ef105b8ef3cb385a298d5479" + }, + { + "kind": "file", + "path": "img_2331.jpg", + "sha256": "990ebcf9247ac8a615bce37491270dbc29f20163a2f1cf23263d133c1f191820" + }, + { + "kind": "file", + "path": "img_4740.jpg", + "sha256": "bf664907478b4551cafe21d08524a08e1c7fbbe88b98bdb810cc9ee5fad36ff1" + }, + { + "kind": "file", + "path": "img_1638.jpg", + "sha256": "e3a8e7c5671acd261df81cd73e0006b3b7e8ba3d97ffd17da68761e0009cd57d" + }, + { + "kind": "file", + "path": "img_828.jpg", + "sha256": "eed6700b8a05151e6b88552fe07711855ac65da3dee20c66bcb1fd0d16ca217c" + }, + { + "kind": "file", + "path": "img_2319.jpg", + "sha256": "d5cecc80e8129b1f99ed9531eba782b6d0fc6c481a56d9ba9e290e4a25c8df1a" + }, + { + "kind": "file", + "path": "img_3007.jpg", + "sha256": "f9f61eaba865f6120f10a55ba4f9fda43b7f334bd945cd9e7efeb62d8b9f5bd7" + }, + { + "kind": "file", + "path": "img_1610.jpg", + "sha256": "861c1fab3e069a54536afafde065f6a4d03b23e9cfaf63ecbf9cfdb4aceffc76" + }, + { + "kind": "file", + "path": "img_3761.jpg", + "sha256": "68c937a3a86169aa77b9e87921cbadd226fe499f4ae9f7fc8f797d994aea8bc1" + }, + { + "kind": "file", + "path": "img_3775.jpg", + "sha256": "1c16fcd1b72ce29d1856249b19230f89802c64cec58027b7eb7d4a8f26fe6252" + }, + { + "kind": "file", + "path": "img_182.jpg", + "sha256": "783b42f89dcb493f8deed103590c0191c213b34d659fcf93155eb3de7e9c3087" + }, + { + "kind": "file", + "path": "img_1162.jpg", + "sha256": "2f3105304c78830ce8c5acde63ea729cdefb809d06ee73c98832908e4d80321c" + }, + { + "kind": "file", + "path": "img_2292.jpg", + "sha256": "58dcdde23505f0ad0dcb9f00ea82a55cca62406e19e698990f2fdb361c0cd186" + }, + { + "kind": "file", + "path": "img_4185.jpg", + "sha256": "8e5fb2663501470db51a513c1dfd418e22008327a68ba684a9465b442c5296b5" + }, + { + "kind": "file", + "path": "img_3832.jpg", + "sha256": "8496eed67d8a669d29a99aad1eec196ee32823822fcedac825920419201fa9b4" + }, + { + "kind": "file", + "path": "img_3826.jpg", + "sha256": "a7ee5514ecd57222cae43d49dd6dfb46add51ba1b24dac6e886e875cd6234547" + }, + { + "kind": "file", + "path": "img_1957.jpg", + "sha256": "6523c22b99f66ef2ebcd87d06748c9b995824aa75e9cc0299e56d24bb28e468f" + }, + { + "kind": "file", + "path": "img_2286.jpg", + "sha256": "445246486a5151059abe032d54c112dcc4a22f6b6462bad6c6237031be156523" + }, + { + "kind": "file", + "path": "img_3198.jpg", + "sha256": "60db2085bb46bfd92053de468bbcd85527de7bf174f73993646497054bf39bd0" + }, + { + "kind": "file", + "path": "img_4807.jpg", + "sha256": "f60f9c5629fc253b0eaf41d415555ad4c786c66192c0c4666aeb91ad4c978765" + }, + { + "kind": "file", + "path": "img_747.jpg", + "sha256": "6f2bd950f44c49bbbabc687b8c0094e0238f887fb440b4e5ade9b263acd334d8" + }, + { + "kind": "file", + "path": "img_4813.jpg", + "sha256": "f7be492c3e0603674d115e52a0e99379a8a71d0247f19b7448699273a28b1991" + }, + { + "kind": "file", + "path": "img_753.jpg", + "sha256": "babcfab769258be6189a4de83161be4bb2ef2e6d888ec647c41265100da192a7" + }, + { + "kind": "file", + "path": "img_1758.jpg", + "sha256": "cb2104713dd48eb751364b6b490ee96886a561d4a73ce573d1825dffc1e6441b" + }, + { + "kind": "file", + "path": "img_1980.jpg", + "sha256": "665ff81a58d4a9da093a5c44cf345e43dce715d37fe3c1a29bd9661f4037d54f" + }, + { + "kind": "file", + "path": "img_4620.jpg", + "sha256": "af3a6c884a15a7e2d6f8a3fe6e18e9963b8611417e0f1a12ab6610877ad94d37" + }, + { + "kind": "file", + "path": "img_960.jpg", + "sha256": "8759b73755d574a15441a7e805d6f5942af9a89f02e56c719b56e1bac22de3c7" + }, + { + "kind": "file", + "path": "img_2537.jpg", + "sha256": "ee2e77edf135563792488370ab465cc2f59b31bd145003ab2a1faf4139ebaea9" + }, + { + "kind": "file", + "path": "img_3629.jpg", + "sha256": "ad08a0f6747707a90589a07a9280e0ebee2fe9d6c32cf28902d47a3f0ea79d8b" + }, + { + "kind": "file", + "path": "img_4146.jpg", + "sha256": "c9beb93a1f854d4270bd70a710de45c0172bfe3119aa9835822940d6d3321860" + }, + { + "kind": "file", + "path": "img_974.jpg", + "sha256": "73bd1702227a0f519fbef7cd7fb74ddf920c15d6d05d21dd7f912f8f42bb685b" + }, + { + "kind": "file", + "path": "img_3173.jpg", + "sha256": "728bf8010add7b40d781e5d67fc823134a5561a55ba9c2ad916bd75a7d9e42e6" + }, + { + "kind": "file", + "path": "img_784.jpg", + "sha256": "f111d03a58b619a56cefe95143a7823fada15c40efaa5fe7c93edf834de082db" + }, + { + "kind": "file", + "path": "img_1764.jpg", + "sha256": "ccb553a416976bb4d00ee715e7e92d441d3e8daa3b0324073c4c25685f343fbe" + }, + { + "kind": "file", + "path": "img_1002.jpg", + "sha256": "33017bd0ea88077b1241c4f293a1563597dfe91ab5355bde94c2050a3dcc4569" + }, + { + "kind": "file", + "path": "img_3601.jpg", + "sha256": "2d4c369a44bd11ffdc5538b7ea5eee778cb390f24374d23d70c07448eea05e18" + }, + { + "kind": "file", + "path": "img_1016.jpg", + "sha256": "7d44334712c38faec731688888443846b6a845604533901fb70ad2bbb5097f6c" + }, + { + "kind": "file", + "path": "img_1770.jpg", + "sha256": "364d43ed1411093f3074ed5884aa75f36b027dad5a83ac87f73b28997e76f1df" + }, + { + "kind": "file", + "path": "img_4608.jpg", + "sha256": "5f2ce36a4e1977920c4f1dc2bc28ad76be3e3bb8f96c540267a8f307b2189f79" + }, + { + "kind": "file", + "path": "img_3167.jpg", + "sha256": "eee3901c9cd73c5830c0b9ffc2858419c993fb70e4eed274ae337b08a5b5f2df" + }, + { + "kind": "file", + "path": "img_790.jpg", + "sha256": "88a15cfa7a1971c8e25701f1c1f2fed15baa11eb1852e471fd554b9d2bd9c988" + }, + { + "kind": "file", + "path": "img_2279.jpg", + "sha256": "6cc5682af6fb7e3191ac1dafaf5ca5745032265877770e2e4a80161e34d3a50e" + }, + { + "kind": "file", + "path": "img_948.jpg", + "sha256": "ac6446f05b05ecee46a6b01a8730de4202162d71c53b1ddd68e27f99c7293ee6" + }, + { + "kind": "file", + "path": "img_4387.jpg", + "sha256": "9cbc20b7667a4dc1d35ff56473b56b0ffaa8b270ce9ecf32367808e7a3fa10f1" + }, + { + "kind": "file", + "path": "img_1599.jpg", + "sha256": "fcf4038050592e85fa409151a3f95132a95850505e4856bcd5a2ee51f4238ec5" + }, + { + "kind": "file", + "path": "img_579.jpg", + "sha256": "88a1859b0a400cb3559fe72a978733e97b0cfc8d5a77d49070aabbc82921acbe" + }, + { + "kind": "file", + "path": "img_2090.jpg", + "sha256": "66bffce09903fca4e45a892ea881245540a78a739eec3b96494b46a313202e22" + }, + { + "kind": "file", + "path": "img_2084.jpg", + "sha256": "0ac86a072acf9205b35bd3a6c538de94fb587b6ef42ab3417671fb547d2f76a0" + }, + { + "kind": "file", + "path": "img_2912.jpg", + "sha256": "9cd38b4f95d6ed1d211bf8ea900a3cc2a68c46ace6078f6f14d9c0bf991b8057" + }, + { + "kind": "file", + "path": "img_223.jpg", + "sha256": "c2bf1a60ffffc5ff1e8528e5c918d5d351b4e6328cb63b34d21d0f2afcd55de7" + }, + { + "kind": "file", + "path": "img_545.jpg", + "sha256": "379e378cd56e9e11a5854bda3dd9c01c11d846e1467febc7d8f7ea7929f5e6cb" + }, + { + "kind": "file", + "path": "img_551.jpg", + "sha256": "bb9d7e10dced76d19ca398edc682697ff500efababf63759fb2eb8717bdfcd52" + }, + { + "kind": "file", + "path": "img_2906.jpg", + "sha256": "706cd5bcddd5d7b37ed6988632dbb5a4a05e835f8d776683c4c07fa1ab42afe2" + }, + { + "kind": "file", + "path": "img_237.jpg", + "sha256": "6b9a2537796aa2c1d42b2bdda3c654a938715f24a7dcb5219917177800bff98f" + }, + { + "kind": "file", + "path": "img_4344.jpg", + "sha256": "cc4643c70c185b0dae644d1454b41677052200f77930ca73031d3956a0f15197" + }, + { + "kind": "file", + "path": "img_2053.jpg", + "sha256": "f463f56abe746f5d11579cb1451bb9e4260e040df6c359a986fbabf81e94980f" + }, + { + "kind": "file", + "path": "img_4422.jpg", + "sha256": "7592bb14b2bec925764585f09444e1db336e9a73953c605f19b65a5a933e6728" + }, + { + "kind": "file", + "path": "img_2047.jpg", + "sha256": "5640363aeb336b42541b1472a073ad006fd2600dec514e02b9a557fd6f3765db" + }, + { + "kind": "file", + "path": "img_4350.jpg", + "sha256": "880d0e4ad3ecccd7bbd4517f706c61c060ce88e6205c484cbfffcf38487cceb8" + }, + { + "kind": "file", + "path": "img_2721.jpg", + "sha256": "f84424f23d13373ec2b492d078d0a407987e7715ecee3630fa94fd88e0e45f05" + }, + { + "kind": "file", + "path": "img_1228.jpg", + "sha256": "01a1194a7c5d55faba8867f92ac908c7c70d3c1e6e0581f4794f9034d2ab467d" + }, + { + "kind": "file", + "path": "img_3417.jpg", + "sha256": "cb9bae25e29d21257572e4c32a2c86195345b2c2899341a99f11af87e504d32d" + }, + { + "kind": "file", + "path": "img_2709.jpg", + "sha256": "e361b5b324fd07249faa8cd9516208adba79167df4a8b3224263f366eee2e80d" + }, + { + "kind": "file", + "path": "img_1566.jpg", + "sha256": "06e87d40aa61dec20137230db27dc67cc2420a3fee20879cbf4a68fa00546f94" + }, + { + "kind": "file", + "path": "img_3371.jpg", + "sha256": "58ee27f7ea1368c2f0b47c0265b7f0cda46fcc09127b34785942683bc332495f" + }, + { + "kind": "file", + "path": "img_3365.jpg", + "sha256": "0a96cfcf715d683af83478b30e16a09c9d0be7121e1ffe6217a2492cda6bafc0" + }, + { + "kind": "file", + "path": "img_1572.jpg", + "sha256": "6e515993adb337f20da4668fd706d64a5aa1fc2631ca3ea8e3a3c1d1752893b0" + }, + { + "kind": "file", + "path": "img_1214.jpg", + "sha256": "0503bc4d49fc420f71e726c6ff7fe1c9d341b14e596d0e175e1875c3bd7a032e" + }, + { + "kind": "file", + "path": "img_3403.jpg", + "sha256": "e6b306d35f7fe1fa7c031f03072c3fc395e842e0bcd44e008ca732c28e95e992" + }, + { + "kind": "file", + "path": "img_1573.jpg", + "sha256": "06de090c5245ee88ed9ee015608080db2fde78395105ee9d23c8b731a2c56bd9" + }, + { + "kind": "file", + "path": "img_593.jpg", + "sha256": "852a21e9dee514ac03dc021cfc79744efc26b601960601818a7c4378985fd2c4" + }, + { + "kind": "file", + "path": "img_3402.jpg", + "sha256": "6cfecaeae7910a6bd9b298f22e024b21ec7cc1bbe0753fe6c531eb910ef90b69" + }, + { + "kind": "file", + "path": "img_1215.jpg", + "sha256": "b7fecaf929d106813381df873284747f322f2c59b009ce505d3e20f3ba1068ad" + }, + { + "kind": "file", + "path": "img_2708.jpg", + "sha256": "beef1993558adee3ccb8a54d3aad686f4c74db8ad37c622f4fb9c1a929ced171" + }, + { + "kind": "file", + "path": "img_3416.jpg", + "sha256": "4af38c0c9ee7849bab7fa69145d4f34f3e7d2da0686dc7856fefa71e7c79745b" + }, + { + "kind": "file", + "path": "img_4379.jpg", + "sha256": "58b935fe8fa608ae15b31453c09a31e4edb90972ddde39ff79b54a231ee97ff0" + }, + { + "kind": "file", + "path": "img_3370.jpg", + "sha256": "42a2bc8e1af924a22271d57f699a0b4b69fbf14b9f30447526561c8546b1f635" + }, + { + "kind": "file", + "path": "img_587.jpg", + "sha256": "eafbd6b7f71b93fd5150c4e6f4e26c2b94f3e7f03ea8b5105272e7b4aeacab8b" + }, + { + "kind": "file", + "path": "img_1567.jpg", + "sha256": "e5b32023928b00e60faad7806b4901e2223e5a623bef3fdfe1b073b490dac93a" + }, + { + "kind": "file", + "path": "img_3358.jpg", + "sha256": "44bbb164c8ee0840563b5e5637f07ccf3475ac946dbe5e65101b531365b9d3fa" + }, + { + "kind": "file", + "path": "img_1229.jpg", + "sha256": "2a5928afb47a3801a0a623f2b091d182539b6212bb9f7555e808bfd996507bf2" + }, + { + "kind": "file", + "path": "img_2720.jpg", + "sha256": "bee7a3033c65041a3c1ab755c8af66be0b9e35589d48a4e7be48bc5a6fe6c581" + }, + { + "kind": "file", + "path": "img_4351.jpg", + "sha256": "ae98ecfe52eb8c84ae6708dd8b9c9b11f73b87c28cfdac65915edd9ebc9a4e0d" + }, + { + "kind": "file", + "path": "img_2734.jpg", + "sha256": "e8f91093eb6970594b093c814aa4bc9a5626a0f3d6784bb9d7d7251fde2b5afa" + }, + { + "kind": "file", + "path": "img_4345.jpg", + "sha256": "a3ecf3a4ff4dc92abe7500e89cacb07b6a3dbd494e91f7ad6e16edabe0ae0f90" + }, + { + "kind": "file", + "path": "img_4423.jpg", + "sha256": "d35544d2ccfbef0a584e20fd08377ebacdb496edd60898a09bc02a3802bc0b13" + }, + { + "kind": "file", + "path": "img_2052.jpg", + "sha256": "b4fb0edbfdb1805cd5b54ea8c7dbffce75a7f19bf2b50f8431054191cdc715a4" + }, + { + "kind": "file", + "path": "img_236.jpg", + "sha256": "80042c44fe53848c39f62c260d4b343a2b65a2b5596cb492ecb6232147bd8bd6" + }, + { + "kind": "file", + "path": "img_2907.jpg", + "sha256": "ca076b65c64cec939a36c2fa5ed6de27d25d8961e6db4642d688fa5a340e6d67" + }, + { + "kind": "file", + "path": "img_222.jpg", + "sha256": "169428b1a7782d99b398ce20506c664ddaaaaa677c1966a0cfb0adcccc5f3b83" + }, + { + "kind": "file", + "path": "img_2913.jpg", + "sha256": "24465a56d06b27a6f5e1a23b35a37248fe4c53aec3275e746228755be76c6cb8" + }, + { + "kind": "file", + "path": "img_544.jpg", + "sha256": "501061b70b8747f8b29cc2a64a8d8d06f191c2d8221cb276215f759aa7e66f82" + }, + { + "kind": "file", + "path": "img_2085.jpg", + "sha256": "364d5ffa2e5bcec5fe42af45959177665817676e567a1d521f8d4577079f899a" + }, + { + "kind": "file", + "path": "img_2091.jpg", + "sha256": "61a37438373aae0ebb1ed0a68b5a33e02ff155d278a5af35c346cc4b0df402a8" + }, + { + "kind": "file", + "path": "img_578.jpg", + "sha256": "71aa125681b99e12900c563817c0c79569798c6adc120f5415c01ae65c158bfb" + }, + { + "kind": "file", + "path": "img_1598.jpg", + "sha256": "e22cd47b0fddd4f0752e5a8e372b569390480b79ef82cfa095bedde35341b4e2" + }, + { + "kind": "file", + "path": "img_1017.jpg", + "sha256": "b1ae4e3288315568905fbc2fbf769a3e13fc73ac125c04b0f979560b0e4c5a2e" + }, + { + "kind": "file", + "path": "img_3600.jpg", + "sha256": "225bcf620f5c4b1a167ae6f031b6dedef5bc9084284d2479a9a4bab8627c53d1" + }, + { + "kind": "file", + "path": "img_949.jpg", + "sha256": "1ad82b90b267d7c3f5a9b1cc957d7f29591c89f4b8d6249b9ea2a82d70105613" + }, + { + "kind": "file", + "path": "img_2278.jpg", + "sha256": "762c5826d89ceebe479120d3810dbedc77f9ea7bcb5817390be1c549ec5ac5b1" + }, + { + "kind": "file", + "path": "img_791.jpg", + "sha256": "bd31e39ed6cd4d770e02766eb3ba908c74606a5d4f1df3d87da72d13f0d78e16" + }, + { + "kind": "file", + "path": "img_3166.jpg", + "sha256": "3eaf73475cec828f11ad33d2c5401e822b0d55fb1984bf3f6696b54cbd9105cb" + }, + { + "kind": "file", + "path": "img_1765.jpg", + "sha256": "3aa329116b0a725a1da32aa1e515caf843ef3b7e0c7955afe0686b491e3ea734" + }, + { + "kind": "file", + "path": "img_785.jpg", + "sha256": "ac56b912c9b6b65b6429d28d5d18876a0d2e08a6fdf8cd7a0753c54a3091372b" + }, + { + "kind": "file", + "path": "img_3172.jpg", + "sha256": "11a642c62792e1f1ac30702b2b05746559e555135d2c0d6fdfed2fd3dc978528" + }, + { + "kind": "file", + "path": "img_3614.jpg", + "sha256": "2a50763e701e9a7393a4c5b0ab6cc4cdf01f1b767fe52bad981823955625511c" + }, + { + "kind": "file", + "path": "img_1003.jpg", + "sha256": "84ff2cfd7eb5a40d6ef408e6a0cf95bc96fbc16f722e938678b33283215988fd" + }, + { + "kind": "file", + "path": "img_2522.jpg", + "sha256": "aaa874ad135ed50d95b6dd6a1c0522b428778c90350523bb21b8a0dfbc665c54" + }, + { + "kind": "file", + "path": "img_1995.jpg", + "sha256": "5358f9a6bfe275305f492cebaf674a1db8978eb8fcc44c98b23e00b80e1c69c3" + }, + { + "kind": "file", + "path": "img_975.jpg", + "sha256": "fef94d952390f8b3b26e64f3627a7c79fbf52a719ae35272feb7b3113a46122b" + }, + { + "kind": "file", + "path": "img_2244.jpg", + "sha256": "533983ec54a88b4596704d8e7012c41d6350f28ec8e44e849327d4a83c12c8ac" + }, + { + "kind": "file", + "path": "img_4635.jpg", + "sha256": "deb33781bebde032318579caf13a9779992c3ed86f950cdf3fabf986d7c22e80" + }, + { + "kind": "file", + "path": "img_961.jpg", + "sha256": "2f709be4c947b5af065f1fdc51c2d649d71b38d58e07b07e7f01a82649ba957d" + }, + { + "kind": "file", + "path": "img_2250.jpg", + "sha256": "d3eb00bd75345f8fe6703462d47e333ad5c4ae27e5feb5094c1502123489daa8" + }, + { + "kind": "file", + "path": "img_4621.jpg", + "sha256": "95d0ebe633415d83c87871854b3f0887cd7a0783f3b2d5864f3b8001cae51299" + }, + { + "kind": "file", + "path": "img_1981.jpg", + "sha256": "d3625dd45dbc1617de80765c8986066cb7defdf3bc6228ab21df76fdc63b21c6" + }, + { + "kind": "file", + "path": "img_1759.jpg", + "sha256": "7e89f9253a0f26f7363382d0adf862a211da203632674413838335bccad4a420" + }, + { + "kind": "file", + "path": "img_4147.jpg", + "sha256": "268b19dcdd4c54edbc0d1043d67aad060ae344ca037d16b1a1811104e5b8d4a5" + }, + { + "kind": "file", + "path": "img_3628.jpg", + "sha256": "4cc89711288fe149a09a780edea25e4efbe6fd1366195948453e452b2b01540d" + }, + { + "kind": "file", + "path": "img_2536.jpg", + "sha256": "f585b8c9e431ca42a8bcda62658fdb7f44a41eb272c1505771a6305a6af723df" + }, + { + "kind": "file", + "path": "img_4812.jpg", + "sha256": "0ea99a537c557aade0d3ab5d26c687d7ebfcbd0c5522f07b018addae9315dc21" + }, + { + "kind": "file", + "path": "img_746.jpg", + "sha256": "6ed0d0ed5623ef7d5514ee9b505a2ed2424182a9077c7f3f3c9794409e3fbd33" + }, + { + "kind": "file", + "path": "img_4806.jpg", + "sha256": "9b1889d6d47c28520160e924a01503f7aeda9fc1369e4cb0428055212abc5a16" + }, + { + "kind": "file", + "path": "img_3827.jpg", + "sha256": "857e541e4fd7ea45049e30948f4e7d921946538c843707169998d597bf46dace" + }, + { + "kind": "file", + "path": "img_4190.jpg", + "sha256": "4f07b60addf3643d01a2397cc24b8cb97cb3a84e672c469726110ff58f48f535" + }, + { + "kind": "file", + "path": "img_3199.jpg", + "sha256": "9d8d7ca731fe7b05f5b277c742a718eecae70e0cbb6083877aa9ce6ad0f17912" + }, + { + "kind": "file", + "path": "img_2287.jpg", + "sha256": "07434a85853bfadd7fd2be9cca1507e9a16591c61b2580b21cbea07302252409" + }, + { + "kind": "file", + "path": "img_1956.jpg", + "sha256": "c16ed3a213abb11c37825f0703c63c40b9631ec0bed1ab18bf0437d769ea1864" + }, + { + "kind": "file", + "path": "img_1942.jpg", + "sha256": "2c47f28b8011d5064af9b9e46398378e9c490276195f2ace959459fe7756f528" + }, + { + "kind": "file", + "path": "img_2293.jpg", + "sha256": "78ff509ff8feb9a8ca6e7f57afef8c55b8e65dfb9ea56c659763b6c01e0486d9" + }, + { + "kind": "file", + "path": "img_3833.jpg", + "sha256": "4cb0f238267956048a244a18c2b56493b0d7c46b2a4da6651da0e15d13a5f28d" + }, + { + "kind": "file", + "path": "img_4184.jpg", + "sha256": "a2990004ff3d26088cf7298a9665289b0e274f3db3513714d1146379f7dfaf46" + }, + { + "kind": "file", + "path": "img_1163.jpg", + "sha256": "9bb0036d27f9a91a9e3eb02bd3f3a397a24262212792c613f4773eef1651943a" + }, + { + "kind": "file", + "path": "img_183.jpg", + "sha256": "7d06a4a1e1c21236674888f55b00bc4ccfcc97f2adbb34ffa72da10e8aa97fa4" + }, + { + "kind": "file", + "path": "img_3774.jpg", + "sha256": "1832d283f9811432f0803872fe16b290ee3de2f718e1d2b26e9d52166eaa4539" + }, + { + "kind": "file", + "path": "img_1605.jpg", + "sha256": "3d19244403f842e798f59f827e66c0fe744a92a2385c10b29454f76505a0472f" + }, + { + "kind": "file", + "path": "img_4769.jpg", + "sha256": "3aa0c47a6dbb9c0373c71f7c7492d15231d9975bd2b85d8b766362f11ecc12d3" + }, + { + "kind": "file", + "path": "img_3006.jpg", + "sha256": "b0023220aaa055e1bd1dfdeb4debd2175c27477907811e7d2337a9af1a262875" + }, + { + "kind": "file", + "path": "img_2318.jpg", + "sha256": "6967875fe623966ac9d210793c6d68c6bf297241fb247e4a3fa708719325bc66" + }, + { + "kind": "file", + "path": "img_829.jpg", + "sha256": "e1a89c4ba0bab522128f8da3fcc937b49250dc17839beef1bf0dc40832703c58" + }, + { + "kind": "file", + "path": "img_3760.jpg", + "sha256": "94fe50aad476b3f647b37263a1941e18ecb126d13c5f9e37910f9a0abd17ae62" + }, + { + "kind": "file", + "path": "img_3990.jpg", + "sha256": "bca6cf9cf79d5f44d53c3e3c0ae91fab9c640fc6ea62d0df38f19ed9633f04a5" + }, + { + "kind": "file", + "path": "img_2456.jpg", + "sha256": "f1bf97c1ba7b66b15b91d9a8725cf484e6410f51b64a3e17750b387ea8ebd55f" + }, + { + "kind": "file", + "path": "img_3748.jpg", + "sha256": "5f00c4c42f83a4f6eed1e6f193b532625e71dbb9690ed869f1c36168c6a93ccb" + }, + { + "kind": "file", + "path": "img_4027.jpg", + "sha256": "43c214e4c2f3b9f4caec7a93de3913c3c6f5b0ffccf089c9e2fe5c6b935f61ba" + }, + { + "kind": "file", + "path": "img_4741.jpg", + "sha256": "59c72078956dae8d69fa0628aa494b749e4389ae26ce98fa44b8f0c630e80520" + }, + { + "kind": "file", + "path": "img_2330.jpg", + "sha256": "aea27e2a7523629e0fec2fc6be8509e2477bf86093e0944f08954bd5916f9c78" + }, + { + "kind": "file", + "path": "img_2324.jpg", + "sha256": "beddbfd328f746932e56cd31959681c5bee789d49735106b969fe29223b6a820" + }, + { + "kind": "file", + "path": "img_3984.jpg", + "sha256": "3212026d88e3fe8c7a44244459065243ce52d8faacd23f69662ebce2dba255c1" + }, + { + "kind": "file", + "path": "img_2442.jpg", + "sha256": "5b825c7f1d9eb2e489712fdd43800bb0cf8f140618917b1965dabe0aed17713c" + }, + { + "kind": "file", + "path": "img_4033.jpg", + "sha256": "9f62bb68f3d718c1db4658d836b15876dbc9313ec995b2364567f7db16142d42" + }, + { + "kind": "file", + "path": "img_632.jpg", + "sha256": "d4af176fc21a5629bb50bc2aab30575ba33cc5a9bd6e4fea41d3ba4b97815355" + }, + { + "kind": "file", + "path": "img_154.jpg", + "sha256": "6951af6641e22f6919c9066dcc08e6add36759bfdeeac8df9ee4c5a5eccdb2c2" + }, + { + "kind": "file", + "path": "img_3953.jpg", + "sha256": "cf162002529f3ff77b187eb418e07987aacf8c6d0e0dde91243b5075c6a62000" + }, + { + "kind": "file", + "path": "img_2495.jpg", + "sha256": "17a4866b3d0a1a0b5f6a3ba98c2bd29d5f82e43129b36bcfc54642854cf6ba36" + }, + { + "kind": "file", + "path": "img_4782.jpg", + "sha256": "d714b1e1a8c82dbecac5638974cccd45456cbd71970847c59a768697c4cb4274" + }, + { + "kind": "file", + "path": "img_1822.jpg", + "sha256": "cacd0fe788dccbe6d2597035f0ed4930c6ccc8a0e603c4b2e42d24bf8a6bd673" + }, + { + "kind": "file", + "path": "img_4796.jpg", + "sha256": "d3161bc7047dcad4d4b778942c84c3f6c9725ba28eea938f54e52614684f2052" + }, + { + "kind": "file", + "path": "img_168.jpg", + "sha256": "6b4f6ffb8aa074a81e927de0613281bb1716153775692e303f7cdbe15e03704f" + }, + { + "kind": "file", + "path": "img_2481.jpg", + "sha256": "16ea0007c03173ab893c1d65d370d5f4d0fec575b3b5e5b5885efb369b62c4ad" + }, + { + "kind": "file", + "path": "img_1188.jpg", + "sha256": "65b0301381512030046e313cb620986388f639e560eea9fc3ceb7a1da9adee99" + }, + { + "kind": "file", + "path": "img_3210.jpg", + "sha256": "23c9f5410bd6e0f1fb52d455aed5e2dcfbc2eb9edc777e87f0dc846a455f2713" + }, + { + "kind": "file", + "path": "img_4219.jpg", + "sha256": "139cd5bcb25ea6d91478e8d980bc9230db72be64d4a12b07cbd2be49d37e4808" + }, + { + "kind": "file", + "path": "img_381.jpg", + "sha256": "4dc158a732567e9feea2fddc33abbcbf6af8f8582c6528326bee037a60198fe6" + }, + { + "kind": "file", + "path": "img_2668.jpg", + "sha256": "492d7e9fc77b99255b3175605a27d9f847017a796e334bd8b737c5f522508ef4" + }, + { + "kind": "file", + "path": "img_1361.jpg", + "sha256": "0c3588991de22ab269767bcd39b2bbd988be6b27dbfec8664ee148845c8ce2b2" + }, + { + "kind": "file", + "path": "img_395.jpg", + "sha256": "b377fb36e1fa9b145697c0e0444bcf6edd6bd474204026900344a8d9e07f227d" + }, + { + "kind": "file", + "path": "img_3204.jpg", + "sha256": "34548b9c5f2555dfc0fca8ab19d380d05a508e2b34a8c6f0fc884f250c297325" + }, + { + "kind": "file", + "path": "img_1413.jpg", + "sha256": "2ba6955b9628d164101ca60d5f08f5a79ba9b9aa88fbc9388056740791ac42b9" + }, + { + "kind": "file", + "path": "img_47.jpg", + "sha256": "34c2e7389e6a5323c441ca93562a42f7c8f1a6a31e10b9a6ad8eb9359b9064be" + }, + { + "kind": "file", + "path": "img_2132.jpg", + "sha256": "d8adf0646b9aecdeef4a34d465dda6d35b23219dce3e047593bd4ad495bf4e24" + }, + { + "kind": "file", + "path": "img_4543.jpg", + "sha256": "e9f9a74205d97d4ceb05bbf2241c9de899f596b98ea438e36d7289b627b7b8cb" + }, + { + "kind": "file", + "path": "img_4225.jpg", + "sha256": "010f4635b26a2eb1ea1d6fff8037313000941dae3f0eaa7eb74974b664942183" + }, + { + "kind": "file", + "path": "img_2654.jpg", + "sha256": "63bc616e06b390f36412556214fa0cb045dd042e485e35917bfae32519a0e167" + }, + { + "kind": "file", + "path": "img_4231.jpg", + "sha256": "bf1c2528fb85f525d20584e982825921ab5b4c274aa8fd92980fccf3a757c36e" + }, + { + "kind": "file", + "path": "img_2898.jpg", + "sha256": "36b9c5ed662c6ad7a86d3ace048687b436330ccb19778bdcfcd1c7180a966e81" + }, + { + "kind": "file", + "path": "img_53.jpg", + "sha256": "197bad9465c18c13ed194c60d011cb83de1e661d958c8afee47fb538da3fb481" + }, + { + "kind": "file", + "path": "img_3238.jpg", + "sha256": "4690e3935a2d6a65c8d06cf716a05386adade6fc9fdb7d6a1408628c5401ede2" + }, + { + "kind": "file", + "path": "img_4557.jpg", + "sha256": "f66cb86ffb3c146a044040caa70e1870330c00ec83b8adbbbafacb99fdab50a4" + }, + { + "kind": "file", + "path": "img_342.jpg", + "sha256": "148f16506a3e5e93e7b74bf3bc4e5bb29b5833bc40a5e2748a085b35b8c1f476" + }, + { + "kind": "file", + "path": "img_2867.jpg", + "sha256": "54a648bffc93d49984d60f4cbafe21b50a9c2113562dc5835e88f434cf478991" + }, + { + "kind": "file", + "path": "img_356.jpg", + "sha256": "4dd8abefecc7c660c529ba666b81d5cc8fbc855e8b599f49c8903cfc79d2e484" + }, + { + "kind": "file", + "path": "img_430.jpg", + "sha256": "0aeda30f0eccf4caa78885719c3bfb8d9fdaa2c37053f5b56e367609c13475b2" + }, + { + "kind": "file", + "path": "img_418.jpg", + "sha256": "2bbe6baaccfe383e0b52947e8232104eb9071fc48acfeacfe04b93df04c33b74" + }, + { + "kind": "file", + "path": "img_84.jpg", + "sha256": "1977540c6f5a2b0769c51a374955013649c58843c9db64b095b8846708535a25" + }, + { + "kind": "file", + "path": "img_2697.jpg", + "sha256": "9fb0217c628b11678b5f7f1ce32f568c939b763727c545b93d5028fa8fbb3bb9" + }, + { + "kind": "file", + "path": "img_3589.jpg", + "sha256": "60fe779ea71ee3a1337e2a011a726fc474c02a5d6c5e2e9503c01432dcffbaab" + }, + { + "kind": "file", + "path": "img_2683.jpg", + "sha256": "2385db8f63b55b0a119f27eb5307aa9357174eb52c31b512b4505941eeca33c1" + }, + { + "kind": "file", + "path": "img_90.jpg", + "sha256": "211b077c0a8813ae70bf11bf267d409b7c869fd329ed87c885e671c902de1a81" + }, + { + "kind": "file", + "path": "img_2695.jpg", + "sha256": "fa39eca7778dc99de6f71e0d45d7825d748338e0aa1d1389b087cd96c5c6c5a6" + }, + { + "kind": "file", + "path": "img_86.jpg", + "sha256": "eb052750244ee1d1d8479e5b3fb7095ed113e828689081b753347459c68ea39d" + }, + { + "kind": "file", + "path": "img_4582.jpg", + "sha256": "13ec84f5aaf8c03386c888c369975dd23e1b1e06f1b69d706664239f207ff179" + }, + { + "kind": "file", + "path": "img_92.jpg", + "sha256": "d4224cfdaa644797f0b9fb6fb70a3344fee95fe60aaa261e99aeeaac6c636e15" + }, + { + "kind": "file", + "path": "img_4596.jpg", + "sha256": "86b55c3fa3403c7d4b8b3d034ded91a6d0f12e0a07d273214532f66b33b871ba" + }, + { + "kind": "file", + "path": "img_368.jpg", + "sha256": "fa5c61ad5d705079c9735b509befc633354d1659da51b5dee224b919cc965708" + }, + { + "kind": "file", + "path": "img_2859.jpg", + "sha256": "82be39bb380081e38b6ecfa4aa313f805e9987990f5a1310bd0c0b6d5bd32d9d" + }, + { + "kind": "file", + "path": "img_2681.jpg", + "sha256": "1cdf35be59efd1a2e1108ff37711bb5ba02950d7dc4692b531bca62284e53ff2" + }, + { + "kind": "file", + "path": "img_1388.jpg", + "sha256": "c51634a235867697fc716a91a363bfd29f7d1016f7f8611f1ee55f04baa98b5b" + }, + { + "kind": "file", + "path": "img_340.jpg", + "sha256": "d59f0eb90886896a27f2f0444365720b41aeae0930c63245093251ef0b4fadb3" + }, + { + "kind": "file", + "path": "img_2871.jpg", + "sha256": "2b78bececa29ef769f991a357627c3d853dce9e842fcb539b7035df222b39dde" + }, + { + "kind": "file", + "path": "img_426.jpg", + "sha256": "17376735c0ed3c308548078a6fef07cb868b42299001d858c460625cbcf4e825" + }, + { + "kind": "file", + "path": "img_432.jpg", + "sha256": "260299524ac468eed71b4f79652a0ba80aeb847440552674bf90619c391919b6" + }, + { + "kind": "file", + "path": "img_3548.jpg", + "sha256": "7701bfef73392778c7dc880f413cde900d34d0aa7ddafbd7b8453a38c02dfcac" + }, + { + "kind": "file", + "path": "img_4227.jpg", + "sha256": "53240871cc94bef9bec163147a8421b6093da847d393fb3cce4248a742528598" + }, + { + "kind": "file", + "path": "img_4541.jpg", + "sha256": "2c885d6387474f32f139f121059012b24f8f4a4acdda558ea98fde0442a19355" + }, + { + "kind": "file", + "path": "img_2124.jpg", + "sha256": "44cea54ff497ee1cbb5d9b35d82f12c1b94f3ff55b84d4c5e48cedd829df7bf7" + }, + { + "kind": "file", + "path": "img_51.jpg", + "sha256": "60d3521ee7cd75b40f499b5e0302e6843639edebf26810e2326c25cbfe958241" + }, + { + "kind": "file", + "path": "img_2642.jpg", + "sha256": "a201a39c220bae95014fe3877e60fa47afbec5c18a9bc46a51e940daafe7c6bb" + }, + { + "kind": "file", + "path": "img_4233.jpg", + "sha256": "6f17654c5ece6062bdda17207e6adc7580f3ab550f362b3073045c06d925cae5" + }, + { + "kind": "file", + "path": "img_1363.jpg", + "sha256": "37a04ec3b641f971ac657ef7158bf6bbf5de6a0b9e364a41602fff24c28da5ea" + }, + { + "kind": "file", + "path": "img_3574.jpg", + "sha256": "5922eabc4e8b9da1ccb30a48c8914292083ca4bc117ac7af3776985fe40a0731" + }, + { + "kind": "file", + "path": "img_383.jpg", + "sha256": "1496e91c2776b938f2ab5a537e26ed610eb534012dae4bf429fe486979947c86" + }, + { + "kind": "file", + "path": "img_3212.jpg", + "sha256": "f0e42754e69f1afc979a2e7be441336150571cc1c6e9626b0fb33a608fbd370e" + }, + { + "kind": "file", + "path": "img_79.jpg", + "sha256": "4d7a7b0f9d2b0f3e8cf33d81a8370eebdd245351349b7086ebd9049963692b40" + }, + { + "kind": "file", + "path": "img_1405.jpg", + "sha256": "a3bb6d48e4a26594569661d4c1c9ff4a3df83cde3703d723cab665ab19058db5" + }, + { + "kind": "file", + "path": "img_1411.jpg", + "sha256": "9ad0f6850e63efae76eb9da626b696512f2ba489339c1832a97c98de65ca99d6" + }, + { + "kind": "file", + "path": "img_4569.jpg", + "sha256": "f00ad3d01fe8f841e5a3728ed747e4aa7cad8a76fb876f541fb5121042d6d4b0" + }, + { + "kind": "file", + "path": "img_3206.jpg", + "sha256": "d90f60258bade282a05fdbbce2088db57ca817a9222a1a747d3d21c0dbf6646c" + }, + { + "kind": "file", + "path": "img_2118.jpg", + "sha256": "7a5b26f6023f36967c4aea6b79766305d7b2557183a74d3a714e4d8e0c692a2c" + }, + { + "kind": "file", + "path": "img_3560.jpg", + "sha256": "6e7112acc499246272764eaa116d82c8f2e2d2cb5d4397a143234defc86f90ab" + }, + { + "kind": "file", + "path": "img_1377.jpg", + "sha256": "c555424ee1ffbd8d305e643853d51aeceb3f22eb635fc08f2b83323d044b09ff" + }, + { + "kind": "file", + "path": "img_1820.jpg", + "sha256": "5e21edad16a2ac651c32aa43f1e9d769e3c718912ffede4b98396a766387ea43" + }, + { + "kind": "file", + "path": "img_618.jpg", + "sha256": "57b59d3655982474b761821062343223dbc69bb2606fb698e1caa7e00fbf3649" + }, + { + "kind": "file", + "path": "img_4780.jpg", + "sha256": "98110aebb82edbc6ac13ca65036bdc71c3e56e99ee4a6005d577ae8a36966786" + }, + { + "kind": "file", + "path": "img_2497.jpg", + "sha256": "fa14d7325277802f1f98e3c7807a8e7665553407b115930e726ef1ab77fa4bed" + }, + { + "kind": "file", + "path": "img_3951.jpg", + "sha256": "8cbbe4db4250adcf5212e5df2148bfe588b4e0782be83365f839f2950d9ae77e" + }, + { + "kind": "file", + "path": "img_3789.jpg", + "sha256": "7c2ccd6f09a8b01bfa930f473bb0231918f3a505f27dec4b811d36047c6cdf5d" + }, + { + "kind": "file", + "path": "img_3945.jpg", + "sha256": "07101946c958139efd0847673164f8fe937e92fb2826e80d39e97c1534146984" + }, + { + "kind": "file", + "path": "img_4794.jpg", + "sha256": "a3a257b3e28f9cf12951f9d0aa64a216d565b88fb4ba97ff3fb10cd7e2f60512" + }, + { + "kind": "file", + "path": "img_1834.jpg", + "sha256": "691e39c11acde49411e7c7a255692269b1e8bf5e8ec1ffbab23c8568c3c6a65b" + }, + { + "kind": "file", + "path": "img_624.jpg", + "sha256": "6ece4f85e9496ef54970adb2d6020d2e5b6a629ba839c446dfa916e43d98a66e" + }, + { + "kind": "file", + "path": "img_142.jpg", + "sha256": "ad1cec5f990e5d99f51146d40ec5aa0ee6528977981735e4756c45786ef73a43" + }, + { + "kind": "file", + "path": "img_3979.jpg", + "sha256": "8c3073cac3b132596f48a726c02049f15fcdb11e29a1370f42761a7dfb079355" + }, + { + "kind": "file", + "path": "img_1808.jpg", + "sha256": "e604b6473b625291c4ae99c0c009b7a87af580302fed3fa3e7b2e9e76fb2a367" + }, + { + "kind": "file", + "path": "img_630.jpg", + "sha256": "9a459a9ecc028acedc7a394d76b51c85c1caef8494b28a1bfc38b0d7ac39d505" + }, + { + "kind": "file", + "path": "img_803.jpg", + "sha256": "c62d9d206d5e0d885baaf7fa7b36aab6f0c626706dbdfef7a77cba6174f25865" + }, + { + "kind": "file", + "path": "img_2332.jpg", + "sha256": "dadf894bb8acc0b749020e76eb3298834709ed4c73fb49995772d7d840f7a90a" + }, + { + "kind": "file", + "path": "img_4025.jpg", + "sha256": "678ce760c9901cea3a5ec1b045773b1d7e8e8ef1248edbb8ecabfd3103300fbf" + }, + { + "kind": "file", + "path": "img_2454.jpg", + "sha256": "40b2e4f77ec9c0f46200c86f084c7ebecd7deec99cbfc6824cea22a0639ffae8" + }, + { + "kind": "file", + "path": "img_3992.jpg", + "sha256": "254a6c2c90299c7af1896fa2ff5f0b5144ab369dd42f3511d2999574bad971fd" + }, + { + "kind": "file", + "path": "img_4031.jpg", + "sha256": "dcb0cfb1cd72aa50e417ccbf6c003b2e77764dc36350ada9edfc3e32b9bafecb" + }, + { + "kind": "file", + "path": "img_2440.jpg", + "sha256": "884e3a2da2d94d92ac4261b1e1c1e36b75c9d203dd13a37f7f88c81845aeeef6" + }, + { + "kind": "file", + "path": "img_3986.jpg", + "sha256": "b7a889dfdc6ca8e95feb23b3fe1cf200feab4b950efb19e33aef1d38fe976c0e" + }, + { + "kind": "file", + "path": "img_1149.jpg", + "sha256": "7b8ea93368be410fab8f05afb04db2f5783cf42a14f3c82df18a397d34f1c0dd" + }, + { + "kind": "file", + "path": "img_817.jpg", + "sha256": "4b738b20a7a1235d510b2f6b35d06bd90cf41977e8e41382430ae40e7c5719e5" + }, + { + "kind": "file", + "path": "img_3038.jpg", + "sha256": "c49bab3db578532a2d8bfbe1c2e055fd7b3f40b83b3fb991c4360bff726f69cf" + }, + { + "kind": "file", + "path": "img_4757.jpg", + "sha256": "dcf75d87e712eebe815b580d14c2d361bbb24aa528cd03ac0e15281d9710b8f8" + }, + { + "kind": "file", + "path": "img_1607.jpg", + "sha256": "d7d5f82d0d931b13c28e1c498fcba392b6196ffee093184c25923f0d82f20440" + }, + { + "kind": "file", + "path": "img_3010.jpg", + "sha256": "d030c30e638153cd6710d33b003f980871e0ab088273e4cb70d5b422aa9f8d6f" + }, + { + "kind": "file", + "path": "img_4019.jpg", + "sha256": "16632d6c1d56106af5b6232ef3cd3bdc31aca4b34a686036e7dae4250eaa48e9" + }, + { + "kind": "file", + "path": "img_181.jpg", + "sha256": "c2f7d12cb4185e762f28dfdeab276a52ecbf13f3198032a6d373495e1b5fb188" + }, + { + "kind": "file", + "path": "img_3776.jpg", + "sha256": "135c9e47e856e93ef8b6d854a63d1121309cf3394d00a3980b7606c364d06ede" + }, + { + "kind": "file", + "path": "img_1161.jpg", + "sha256": "2a9469a10580d35117ea38bfc740cc4ad52e5a509ee4f9d8c5de694fc2b0d1ee" + }, + { + "kind": "file", + "path": "img_1175.jpg", + "sha256": "f14600a5b0a951d001b88a76b451c67ebfa8f66c0cbfceb7c361ffa6d6f22ffa" + }, + { + "kind": "file", + "path": "img_195.jpg", + "sha256": "8aea520a0b83812dc524ccd8281ba617dd0a4deac41fb1cf72f4f4b200410756" + }, + { + "kind": "file", + "path": "img_3762.jpg", + "sha256": "e1a6dc2a1ce83f666ddeedf87d57f93b514ca9db1b8ea674f1b4ea803ddfe8f2" + }, + { + "kind": "file", + "path": "img_3004.jpg", + "sha256": "56269018815c4724491bf8ab34d5bce3d7f0e5d4828c7cf176f8c16e920763b7" + }, + { + "kind": "file", + "path": "img_1613.jpg", + "sha256": "ddca625f22374b0f980805c2c6e48c60bde36047c0f6973c4bd24d4c926f1ff3" + }, + { + "kind": "file", + "path": "img_1954.jpg", + "sha256": "4e857c824e0459048a9dff3c009072785caf79a97e1cafef445512e2c86f5cd3" + }, + { + "kind": "file", + "path": "img_2285.jpg", + "sha256": "0c14bc5f9ddaf0b0f58ca88808b2ce749065aa9d7c7e2ce002c113d6ed90cf9c" + }, + { + "kind": "file", + "path": "img_4192.jpg", + "sha256": "44f2c456e4d9e68660eed59f7cdd6237e4bb59cd644ec295bd504a9399571983" + }, + { + "kind": "file", + "path": "img_4186.jpg", + "sha256": "ae0a82311f16b2a9b53e8879df183ee836f5617e85ec28bad59fff76d7ba39d7" + }, + { + "kind": "file", + "path": "img_3831.jpg", + "sha256": "324cfda1f83883b8cc8608f6536a2a3eeab465d684d311a617c0f8883826c0af" + }, + { + "kind": "file", + "path": "img_4838.jpg", + "sha256": "9c1fbf192177c878c1b2195d5126530daf815dbd8391754b8faac360ed50f9ac" + }, + { + "kind": "file", + "path": "img_778.jpg", + "sha256": "e1c98462ebf92fb1f9a78ad3baf63f804c77107bcfd0422f1e7d6b721bb54d9e" + }, + { + "kind": "file", + "path": "img_1798.jpg", + "sha256": "9f2a8ccc27766c72e691d77baf3bb8e72a7523e0710da0bde9d498b826874f13" + }, + { + "kind": "file", + "path": "img_4810.jpg", + "sha256": "5dd059913b4a13c0921deb4a4de57a2ab19d0574d79490bb91dcc43f018661e9" + }, + { + "kind": "file", + "path": "img_988.jpg", + "sha256": "a7f94f9451133a1b62542b93e3eb88aa9a3458a472b0ad1fc73c31d71d08e892" + }, + { + "kind": "file", + "path": "img_750.jpg", + "sha256": "13479b899780d5a45ac5fc78171f466f6a94533a3da6c416d03d592c8025eba5" + }, + { + "kind": "file", + "path": "img_1968.jpg", + "sha256": "f3ff7a50a8caa5c184df651b27f10ca1e52ddf48c4318b98bd90adf1aac17bec" + }, + { + "kind": "file", + "path": "img_3819.jpg", + "sha256": "7978efe46d84be7458d93745e547b80a10e900082af5f22a5fb5ff4bb9362937" + }, + { + "kind": "file", + "path": "img_4804.jpg", + "sha256": "7f75800bf5fbe89c91bbdddb6da2b06bf4e12e9eb18e4c8357da2c3ce39a00c4" + }, + { + "kind": "file", + "path": "img_744.jpg", + "sha256": "23c7d69d909ce3883b5e47d5cddfc6859baeb8356047f26a7d6a2ecf3a63c2d1" + }, + { + "kind": "file", + "path": "img_4637.jpg", + "sha256": "e1a624022f76b36db13b012dc8735b34fd6611353458fa16a881e4efebeeaead" + }, + { + "kind": "file", + "path": "img_3158.jpg", + "sha256": "65fa615ba738fef74563e2822545ee2e4d9ee8b0e52284fdb4c76dc1363484b6" + }, + { + "kind": "file", + "path": "img_1997.jpg", + "sha256": "9a66f9424bca29f4fa7387debb236da2824010ef52b0a44a04ed2f1622f1f1af" + }, + { + "kind": "file", + "path": "img_2520.jpg", + "sha256": "ed4e1100cedab3db68fe6c6c41cdea029e5fc6554028f7298d9e88cc53424289" + }, + { + "kind": "file", + "path": "img_4145.jpg", + "sha256": "5b9677d6c359f2b876437ac9e8752e27d0dfc4acdae3eb7a8c754871e906e88d" + }, + { + "kind": "file", + "path": "img_1983.jpg", + "sha256": "d6f2521a7fa25ccaa3f919ed0c8a9e0714cabc92bda234cfa2965cab97a16195" + }, + { + "kind": "file", + "path": "img_2252.jpg", + "sha256": "9cc475ab7cfcfedf4e4a51ac210469f1a99d44a3a2a9dfe949eeab9196cc16ea" + }, + { + "kind": "file", + "path": "img_963.jpg", + "sha256": "8f0a5c45cc829e8481126163fcab046035393db60392a6b69d7c3078b23b3789" + }, + { + "kind": "file", + "path": "img_1773.jpg", + "sha256": "5928168f8eafb1626cdd6734fdd3dbc3ff1d6987a24bc22a681f58b55c9e8613" + }, + { + "kind": "file", + "path": "img_793.jpg", + "sha256": "916a417e6b379aaf63117cca8bfac0ff0eb14641d4b8e6b3bfca4055832b4b00" + }, + { + "kind": "file", + "path": "img_3164.jpg", + "sha256": "8eb68c5a49c174d112ab8159cd7d733352800fcc5bd98fcb754a458738ed66c5" + }, + { + "kind": "file", + "path": "img_3602.jpg", + "sha256": "18040ea2d379670fe05f155bc087184d073b988b9b5e86659ae394dcd227dc68" + }, + { + "kind": "file", + "path": "img_1001.jpg", + "sha256": "8e85704ddfb107d21463a3030aef7b510705aad1ea4db895c9e5c7b1aa474c9c" + }, + { + "kind": "file", + "path": "img_2508.jpg", + "sha256": "26620f1aa2fb84b40b8cf18f8cf0a0d2e5d7c7130615fac358a70d71e6a5d779" + }, + { + "kind": "file", + "path": "img_3616.jpg", + "sha256": "e5cc846043cce0af0d84d2f0b4562fb8d6aa699adc3d050769c33e4f68b9e9cf" + }, + { + "kind": "file", + "path": "img_4179.jpg", + "sha256": "db9031f9e5f0c8469b94546bb42f2b8b340fa553c11dc9375e01a478d57f8c5a" + }, + { + "kind": "file", + "path": "img_787.jpg", + "sha256": "239d2975c3077191cc178ca4348f68cca07b1593091d31ecbe541ac4cacb753c" + }, + { + "kind": "file", + "path": "img_3170.jpg", + "sha256": "8ea4e01592ffa47a7f5b51af5c65ec70a409abe30d72f350b41419e8f10085a3" + }, + { + "kind": "file", + "path": "img_2939.jpg", + "sha256": "434fe292440b782f7cd2460aa8eb63ca24a29c581bb1b6e07f638a813f4e06b6" + }, + { + "kind": "file", + "path": "img_208.jpg", + "sha256": "325bea523dcbc204d20c57c07e99c79c7bdc5d5c3a7baeca8e9943d6192bdbac" + }, + { + "kind": "file", + "path": "img_3399.jpg", + "sha256": "f98bea9ef189a6583fdda678f7aae7edfe1f205c2be83b1d10750f5bf911fb2d" + }, + { + "kind": "file", + "path": "img_2087.jpg", + "sha256": "7c1aca6cfdea4d2cd33b8f7ea689561ddf5d1870c9962f392af89b5a84542ced" + }, + { + "kind": "file", + "path": "img_4384.jpg", + "sha256": "09c2cf49a2e39e7124ec13b25931dfaa25f0eb4eb15cfa552dddff78bef5d6a4" + }, + { + "kind": "file", + "path": "img_234.jpg", + "sha256": "e16a087656e77d00ee6ecf268deb53c24746716fbf7c12f3453de869e1f839f0" + }, + { + "kind": "file", + "path": "img_552.jpg", + "sha256": "d55a9a12bbb75721e9786e14d67c13230c8617f6f0f551326345c6a4e0c85aa9" + }, + { + "kind": "file", + "path": "img_546.jpg", + "sha256": "70efaa3662c638e608a08f1a469eefa6f66fb0fecb4281beda19b939931f563c" + }, + { + "kind": "file", + "path": "img_2911.jpg", + "sha256": "49702103a1dadf3eb3b42c7ed75b411e26cb856ad520d06dd7c3768e5c92ea55" + }, + { + "kind": "file", + "path": "img_2722.jpg", + "sha256": "6bd70205df0fbbef4469eade2bbc843dd373f7c03a2ddeab29fbf49fa929fa6c" + }, + { + "kind": "file", + "path": "img_2044.jpg", + "sha256": "8efc354d5d8e19873572aa7344e861a8702efe2ee48a4c9cff0c146cb6590ffc" + }, + { + "kind": "file", + "path": "img_4435.jpg", + "sha256": "9165fe36ee902f5d409f8712985ffbbac5de12e664e73a2c43c8a3205f93ac9d" + }, + { + "kind": "file", + "path": "img_2050.jpg", + "sha256": "889d89c1b67ad770025ccc43dbf55df356bedc92cf3cff827c8bc04924c3dd54" + }, + { + "kind": "file", + "path": "img_1559.jpg", + "sha256": "210d5d60df4ad42925d81c650dc2ca265c646efb77e5cdebd96caff3293ba2b3" + }, + { + "kind": "file", + "path": "img_4347.jpg", + "sha256": "ed1c2e7cba1297f9be1583885aeb9ba1940ac51562af7a87ab8f03bdce0a0d2b" + }, + { + "kind": "file", + "path": "img_3428.jpg", + "sha256": "b5ca315369ca775ab3332ed886658991fbaaec8ac8720ec3534f1c1f265d9b91" + }, + { + "kind": "file", + "path": "img_1217.jpg", + "sha256": "8b945132ddd560070abc328c2a034dd234f854af5227cec8a305bbe3ac8b9ba7" + }, + { + "kind": "file", + "path": "img_3400.jpg", + "sha256": "6a6b1db471b5e366fd4461134b0b79f93107edbbfba9d423351c9bdb48be2540" + }, + { + "kind": "file", + "path": "img_2078.jpg", + "sha256": "87f1f756b2593e84c57b23dd27a2e0771259f2866c30de9a956fbf1246de7f1d" + }, + { + "kind": "file", + "path": "img_3366.jpg", + "sha256": "69e76a787ed79d2873f97fb9e1fa5d9fac2fb9f4a4b2b4e9c3089b9fc43814c0" + }, + { + "kind": "file", + "path": "img_591.jpg", + "sha256": "14776fe725c29d78a73f47323c9c686b3b4a9bb0c982d80d21039792679cbd3b" + }, + { + "kind": "file", + "path": "img_4409.jpg", + "sha256": "61614b524cb71cbd1065e12753173e5c54b44dcdcb72bed940065f0c5972192c" + }, + { + "kind": "file", + "path": "img_1571.jpg", + "sha256": "2a5dfeeba148a8fd3a092d8bd62260ebc2b022b4379a6f1b33db2e4bc9e66747" + }, + { + "kind": "file", + "path": "img_1565.jpg", + "sha256": "7da6abc416bc0dce295f0636ca2539b24bbfcd5ab13abd14f133b6c62f5b9ba4" + }, + { + "kind": "file", + "path": "img_3372.jpg", + "sha256": "a213a552b249fc868937bd658f7796d63264441bcdc5ce9fc89f06df361c2b3d" + }, + { + "kind": "file", + "path": "img_585.jpg", + "sha256": "fafe5a8dd234d2a94ec488fdbd3d89f74d3e4f53142eccacf6556f5b11778ec7" + }, + { + "kind": "file", + "path": "img_3414.jpg", + "sha256": "5222b26914d8a937f8499debf86fa5e4f4cbbc637d1d982e2a776439e0d3cb53" + }, + { + "kind": "file", + "path": "img_1203.jpg", + "sha256": "3bfb613d48036c25424660f0576b4f0bf7a07c45bb93334e3ed7c2a5bdb5f8df" + }, + { + "kind": "file", + "path": "img_584.jpg", + "sha256": "8126b7a9c26e2bb3c133e26a6a3420826c33210aeb71c7012c23ca2f5b378afe" + }, + { + "kind": "file", + "path": "img_3373.jpg", + "sha256": "128fb00caea8f5eaea975d6266ba6b3deef8a2e2be7ad06cc30b0c374274766c" + }, + { + "kind": "file", + "path": "img_3415.jpg", + "sha256": "19d64f7bedc2574af2624713e516d71937611ee06e3afda01e293cbbf03f644a" + }, + { + "kind": "file", + "path": "img_3401.jpg", + "sha256": "8f757de57627506f8949b664242f69fdfe1e3ffed6f7e222970a6a44a434fc64" + }, + { + "kind": "file", + "path": "img_1216.jpg", + "sha256": "9f8236bab7c9afceaa198cbc7b4bb5aa4422e0aa71c4d4d04c967caf24113b28" + }, + { + "kind": "file", + "path": "img_1570.jpg", + "sha256": "37b5ca2f9d138278c293bffeda3e07327bd81b50fb49170bb5aac199321d309c" + }, + { + "kind": "file", + "path": "img_4408.jpg", + "sha256": "5743bcf5bf1cba9b6416a7b9bc8505f03761bf0cc5f0629f5fc4daf9251c8091" + }, + { + "kind": "file", + "path": "img_590.jpg", + "sha256": "d85ec8cb8f4202763578c2709d6a7fb6c101ea9ba61883744e53b9d5c33a559c" + }, + { + "kind": "file", + "path": "img_3367.jpg", + "sha256": "b86d7fb29bffc66db4bc2d5dc900a97107b85ca5772a996e202cc3d36d0e685a" + }, + { + "kind": "file", + "path": "img_2079.jpg", + "sha256": "eb35859653fd348359bea05b4049271af4b83505b59f7b7ad1ae7535899d11d5" + }, + { + "kind": "file", + "path": "img_1558.jpg", + "sha256": "631d9130cafcad2babc58b669851178f2fe183795290b151101bd20d3ff9f5cb" + }, + { + "kind": "file", + "path": "img_4420.jpg", + "sha256": "3c01c083d2e31a0d34aa97daa0154a3c4110d040dfb99fc109096a9cee97f068" + }, + { + "kind": "file", + "path": "img_2051.jpg", + "sha256": "f21d9c13f9fa659b6758fd000023cac13fc405c6e0163cf3642239cf39a4a61c" + }, + { + "kind": "file", + "path": "img_3429.jpg", + "sha256": "f68e8ff08334af4cfd440f5f2055832864787626543364df1d5cb6ef891fa039" + }, + { + "kind": "file", + "path": "img_2723.jpg", + "sha256": "f236d16fd54bfb1c27a0ff1704c57d62d729eafc231c979d890cd10a27781abc" + }, + { + "kind": "file", + "path": "img_4352.jpg", + "sha256": "6d83f133171303cda7188d2b0c548250ad07f68f24bb35d18fe0eae8da89c1f1" + }, + { + "kind": "file", + "path": "img_4434.jpg", + "sha256": "90f2210b73557d8515af99081879e9a3b2a911ee987ac12322e6ddb9a5d1e804" + }, + { + "kind": "file", + "path": "img_2045.jpg", + "sha256": "6b843e38ab36099a1c3e9ab76b4c6dc88903a008c2dd60024b3730973db59f57" + }, + { + "kind": "file", + "path": "img_221.jpg", + "sha256": "27a584cd5784cba2a8c6a0835128d1106a744a18d04d2acfe121173dfc067cf4" + }, + { + "kind": "file", + "path": "img_235.jpg", + "sha256": "137f048c2e22c16677bc9f5202fe7c1d6ec17826f6aef41998603a529ca2fbfc" + }, + { + "kind": "file", + "path": "img_2904.jpg", + "sha256": "e837eb0d76d77d2d545122b4d7676e054a2524aaca46cc3799559cf78a36dd50" + }, + { + "kind": "file", + "path": "img_553.jpg", + "sha256": "604ee2dff72ada606a68065d9cfa5f03c8c8cad1a0c58fe794dbfc446216030e" + }, + { + "kind": "file", + "path": "img_2092.jpg", + "sha256": "1186ac9937fcf702e482324651ca133412a7e0afc05610e4b79e8f24e04c3c9e" + }, + { + "kind": "file", + "path": "img_209.jpg", + "sha256": "19b6b4bdff2845ed79ea7e062c8791c1c89bfa377ef43fc350858b72873d5c2f" + }, + { + "kind": "file", + "path": "img_2938.jpg", + "sha256": "dc40a7f3381e8391c9f62e2fdcc6e3dbd43cc63747551c2fd84bcfa1505e8f7d" + }, + { + "kind": "file", + "path": "img_2086.jpg", + "sha256": "6c1c35dd29a7c4ee45f3c95682084f282d708a662017b385a4d4ad6d2764edfb" + }, + { + "kind": "file", + "path": "img_3398.jpg", + "sha256": "078616394dba2aece5ad0f84fc75d84a318b152358d21ade88bd2daf13cfa8a2" + }, + { + "kind": "file", + "path": "img_4178.jpg", + "sha256": "4782175cc4993501d1e533ea86c6a81da3f1da2bf25a474508c2cb75a5a5f426" + }, + { + "kind": "file", + "path": "img_1766.jpg", + "sha256": "27e8ddec3bdb38a71b2d6af917e63897c1a3fbe231b1a0219c005f4b4ed4f262" + }, + { + "kind": "file", + "path": "img_3171.jpg", + "sha256": "f4da3eb6d3886327a98720d500b068bfbcd8598e4ea6c83e2b9b02c8ca330708" + }, + { + "kind": "file", + "path": "img_786.jpg", + "sha256": "7ffa102ab58491de6cd5bcdb8a3f96f6786daab7b6519facaa133bb435049225" + }, + { + "kind": "file", + "path": "img_3165.jpg", + "sha256": "ed155beeb63e6253270bcdc57e5f2fbf4f005bb96fe14567e164309484f7514a" + }, + { + "kind": "file", + "path": "img_1772.jpg", + "sha256": "79cd9ef1a1c80347ae7b331c757780c51dcdb579ac208fae9f0e1e2f4ea276b5" + }, + { + "kind": "file", + "path": "img_1014.jpg", + "sha256": "c863056b2eccc44d335a4f74ec4e54317c1103a7e05405ba6b52669415a1837c" + }, + { + "kind": "file", + "path": "img_3603.jpg", + "sha256": "f90fd5f600c80c322d6bc96055876212fd7711da23de1cde0ba78a7d2ecb9231" + }, + { + "kind": "file", + "path": "img_4144.jpg", + "sha256": "83bce8515cc2727128707ec399c6666fadfb32b6c1df3fda1b9e38cce1ae501a" + }, + { + "kind": "file", + "path": "img_2535.jpg", + "sha256": "8d67285c33150af6edb6d6207432746199d5c0050c5b2863d62ac612f7512f76" + }, + { + "kind": "file", + "path": "img_962.jpg", + "sha256": "7614e63d2fde87e2364341fac493dde1c6c8b808f875a0d464ff8ec2083e98f4" + }, + { + "kind": "file", + "path": "img_2253.jpg", + "sha256": "57d6076d462c4d8158d3bf2205a4dc061978cef62c6656bb3bb6d571da35215b" + }, + { + "kind": "file", + "path": "img_4622.jpg", + "sha256": "9673e7af41d5990b382427f0fbea1d6f617048088fd8a4efc0125fc4af3f84dc" + }, + { + "kind": "file", + "path": "img_1982.jpg", + "sha256": "df06d25c3ce5b03d971953a70afce101869c84c2bb69e7e9f227e24a5e042dde" + }, + { + "kind": "file", + "path": "img_1996.jpg", + "sha256": "7baf6c94e8a57c3c69cdfda313c1b9432a3cbdeba5aeda46ef90b1933936b3af" + }, + { + "kind": "file", + "path": "img_976.jpg", + "sha256": "31585bcb639cd83876f6676658027641749ddb56cd33e025b682cf700eccd5a2" + }, + { + "kind": "file", + "path": "img_2247.jpg", + "sha256": "209aedff189121f9de2ed5e7433405d22e882c1531a4c02a3f8a3eab13bb8ade" + }, + { + "kind": "file", + "path": "img_3159.jpg", + "sha256": "e63d1d7e4710736b952b7f0b023a8968cbbc8dede4f36608abc0600d675ef809" + }, + { + "kind": "file", + "path": "img_4636.jpg", + "sha256": "ca164492296025526c4e63f2c6f3ecb4dda07b4a3560f9955660ac44327f08cd" + }, + { + "kind": "file", + "path": "img_4150.jpg", + "sha256": "a8b711ff5787fd2055719dfe750944b87493c36af70a8cbf6c69b1ab82dd3d14" + }, + { + "kind": "file", + "path": "img_2521.jpg", + "sha256": "440bd3351173165f61d566a2c8013dd737a41e77c0cc4a1974f113f63a68440f" + }, + { + "kind": "file", + "path": "img_745.jpg", + "sha256": "67483305510143d2e5ce045d722916ec4d5be533daf94451db1f3c521a2dd917" + }, + { + "kind": "file", + "path": "img_4805.jpg", + "sha256": "25f39a57c8f070540c9d33d3d2d3b3e96597509642e5c0fd8fef97394c7f9d48" + }, + { + "kind": "file", + "path": "img_1969.jpg", + "sha256": "f205cfabd9b1fef185c6569032b7c873c74b1bac8021452ce116e9427ddcf35f" + }, + { + "kind": "file", + "path": "img_751.jpg", + "sha256": "3f3d51fb694b4161563a4a43d2bc9f3798a1b10e58066ba7c2bc0ca54b76a580" + }, + { + "kind": "file", + "path": "img_989.jpg", + "sha256": "12469c17e1ddd345c957ac7a811ae8384ec9ea33e0a13a257f73308faee9f171" + }, + { + "kind": "file", + "path": "img_4811.jpg", + "sha256": "789393c5fb94a3c97e138712f31b2728c5bf399268fd37e0b292b37bf3a88e9a" + }, + { + "kind": "file", + "path": "img_3818.jpg", + "sha256": "e244abf3a705fe735c70b67669bc803a56953e808419a2cb810c5ae83e089e3d" + }, + { + "kind": "file", + "path": "img_3830.jpg", + "sha256": "eda7e2b4d3d859635d571a06d9123237b6bdd0427a9640719e111bcd468e0875" + }, + { + "kind": "file", + "path": "img_4187.jpg", + "sha256": "ab39892cf1d5d8887fdbed75504999dde6f5df1b8956519c01c9cdc2b662ee84" + }, + { + "kind": "file", + "path": "img_1799.jpg", + "sha256": "09401bdee1d17cec4f1d1dca2299c358359c6d3a3fb0807c5b1995fc09645918" + }, + { + "kind": "file", + "path": "img_1941.jpg", + "sha256": "f964c3211bcae45863602ef0488459c460e2fad419eecc240dbdd8cac4d6a574" + }, + { + "kind": "file", + "path": "img_779.jpg", + "sha256": "6a4ff1082cbc764c3d8abb17375772511c24b09a19ae950864ad6fca902d6c54" + }, + { + "kind": "file", + "path": "img_4839.jpg", + "sha256": "2d14a35ac137a2bd24ac285b8212b5f722c97a11f082d085f51457e4d8e24e87" + }, + { + "kind": "file", + "path": "img_2290.jpg", + "sha256": "7f70c79d12acf3ce4d3b2e4445ff6a4d52a14227b091b4a3433412c9491c2847" + }, + { + "kind": "file", + "path": "img_1955.jpg", + "sha256": "d2376fdb245e607110998f1edce6b68265a22fbdf8a8a22084a0d2543f08bfb6" + }, + { + "kind": "file", + "path": "img_3824.jpg", + "sha256": "67183b49982bc1b237b7c024b81a643274afa58c7b1c204163f915086db63a93" + }, + { + "kind": "file", + "path": "img_4193.jpg", + "sha256": "434a3ead294e72b017e4475fa605c7342451f1ff77ceb49fb8dafb55d0ba5e84" + }, + { + "kind": "file", + "path": "img_3763.jpg", + "sha256": "e817ab022fd081c7ed9e73dafde6f4b123294f390d14f0f2fdf7e61279e61a6a" + }, + { + "kind": "file", + "path": "img_3005.jpg", + "sha256": "77209057419ec8dfe3f165ecd8f9c75eb321a01fbd58db0ec66757d24048fcba" + }, + { + "kind": "file", + "path": "img_1160.jpg", + "sha256": "a1e91ebba062d7dce922b89407949ff34927a011c5633672c6a68eb0abf73888" + }, + { + "kind": "file", + "path": "img_2469.jpg", + "sha256": "9c0faaed755ad4a677adb1fcf95c27210b9b026edcff576bd42bde7bed85f2f0" + }, + { + "kind": "file", + "path": "img_3777.jpg", + "sha256": "f68968ed6380376b1221c934c367af4904b9507023e8b2f254c99f391a8bac87" + }, + { + "kind": "file", + "path": "img_180.jpg", + "sha256": "1b73ac6eee85ac5dccd95bad6a77e7563fbabbcb9b2dc6bf8c8f9eed64549558" + }, + { + "kind": "file", + "path": "img_4018.jpg", + "sha256": "91a0363999d95b0d20bebe2e757e492514058b5aa59a39d24f48b7a8574c0cba" + }, + { + "kind": "file", + "path": "img_1148.jpg", + "sha256": "423e246148029e01d4699f440e0818e4bdf1c6572e48b5a2bc20e3b6809d78f9" + }, + { + "kind": "file", + "path": "img_4756.jpg", + "sha256": "c22b084cdfd87e3761de4ebf32a9b694f2778b19e8e11712a8551737eb68b2b6" + }, + { + "kind": "file", + "path": "img_3039.jpg", + "sha256": "b9289ea7ca74b93f62c25db7fd91966e8e057d0dd0e1fd7ab5a5f2b1edec616b" + }, + { + "kind": "file", + "path": "img_816.jpg", + "sha256": "598fa2bf484c3ffb04d20dee3fddb64be9d29538a4291f46def0c32de4e1f920" + }, + { + "kind": "file", + "path": "img_4742.jpg", + "sha256": "5a04ab22a70fbea524ba83d1be7382af850becc8bdaca59ac1e02930f38974fd" + }, + { + "kind": "file", + "path": "img_2333.jpg", + "sha256": "af4c58c6e8a4df1086829689daa6b9396cc863868476c69c6f62503216e27892" + }, + { + "kind": "file", + "path": "img_3993.jpg", + "sha256": "fe42f1cb0e6ee67d38b2c0bf34d6836333bce6992979654c1ac88a905019de4c" + }, + { + "kind": "file", + "path": "img_2455.jpg", + "sha256": "d949a8998cb88504bb648cdf198e4e51a16c07cfe1d8f3fea3e283c0f599ab53" + }, + { + "kind": "file", + "path": "img_4024.jpg", + "sha256": "447d95f32a50d1f7e7fc00af80e48de88b535cc9c28684d3298ad4a81efbe457" + }, + { + "kind": "file", + "path": "img_157.jpg", + "sha256": "fb0511c019377d1b5f7a5e2f43453503d6ea872624bd4d622a8083628db4bcff" + }, + { + "kind": "file", + "path": "img_631.jpg", + "sha256": "4b4a80ddf1805b9bf8b1ea24407dff2c74fb9b439cd3779dd6a606647f183722" + }, + { + "kind": "file", + "path": "img_1809.jpg", + "sha256": "a61217fd7d2a2249eb98c349231382c80c31f61fc4a799f4ee7efb0ad3e411d2" + }, + { + "kind": "file", + "path": "img_625.jpg", + "sha256": "30bb22cd0fa914025f082a02ee76d05cc277b8e93a2eafbfa1ef1ad28306b191" + }, + { + "kind": "file", + "path": "img_143.jpg", + "sha256": "a53b67ee2b302dbd9c6b38543a40edcc141d5eac9f7f4e0cae0beede780b3e30" + }, + { + "kind": "file", + "path": "img_3944.jpg", + "sha256": "1a2b0e2cffbdbefd8f78ea75884349edbdcbaeba23e8d47d2c9459600452592e" + }, + { + "kind": "file", + "path": "img_2482.jpg", + "sha256": "4226dba7a4fc3c04662269ee16d7708ce9a7b7d07f18edb6c9b3dde47f93a171" + }, + { + "kind": "file", + "path": "img_1835.jpg", + "sha256": "ffac9ef24662d991713cd6121c7fef95c9d43cc40dd3481b0f1f2560abc67391" + }, + { + "kind": "file", + "path": "img_4795.jpg", + "sha256": "45ad460ba8654479fb64ab9869110350d68430068362b3d69a63dacf0255148b" + }, + { + "kind": "file", + "path": "img_4781.jpg", + "sha256": "2efe9e2b27b1228365c1076b66c53ae4238582a2dac3292736015f42896441c1" + }, + { + "kind": "file", + "path": "img_619.jpg", + "sha256": "1a43e7103b7385f653ce6910030ca60d32020b30be82dc228556467a2f03c2ae" + }, + { + "kind": "file", + "path": "img_1821.jpg", + "sha256": "6936dbd8936a75e5826499587d519e8b30dc1e8aae158de7f24ebd34584daa1d" + }, + { + "kind": "file", + "path": "img_3788.jpg", + "sha256": "17e0a8a5f3ecdaecbb2e1d52137a7b448fae0a0a6688a3b33fc9c80c9eebd340" + }, + { + "kind": "file", + "path": "img_3950.jpg", + "sha256": "ab43f24af775c7f073e9f00fe2a1f6409f2684f4cef76a78fa41f4fd8be93233" + }, + { + "kind": "file", + "path": "img_2496.jpg", + "sha256": "54817ba3505533d44ba77c8908339ad92e61364d6f3cfd18f0130f2e0030f1fe" + }, + { + "kind": "file", + "path": "img_2119.jpg", + "sha256": "0cfd5ebc4c9e31e9c43334155c698e88dde843969ca92af7c1804bf5e4d361fb" + }, + { + "kind": "file", + "path": "img_3207.jpg", + "sha256": "9608e0b3ac4aad3989b6e26fa554e37e93c7a19c6f28f360ccf25645524f5fb4" + }, + { + "kind": "file", + "path": "img_4568.jpg", + "sha256": "0d03e93b4b145602461075ea83bb398716d8dd03dff0836748380298e0de34a9" + }, + { + "kind": "file", + "path": "img_1410.jpg", + "sha256": "2a23b2eaf68d86d6026999b0d809bfc75fbaf93a064863114da3083050305336" + }, + { + "kind": "file", + "path": "img_1376.jpg", + "sha256": "81bcbc4cb5b86badd4e9a76a622fbda7d3522d8125fae2f94da99f5a044a2fd1" + }, + { + "kind": "file", + "path": "img_3561.jpg", + "sha256": "c14f93e7a1f36f789649164551bf571effb4e6ab152b46cb06d7df386fe37ca8" + }, + { + "kind": "file", + "path": "img_382.jpg", + "sha256": "1a23c7bc432f4677f02ec3887f5b7f3f5ce0c011cb4ed5338ca80c36642213c9" + }, + { + "kind": "file", + "path": "img_3575.jpg", + "sha256": "15414e7836f24707fc052824ed665fc2e09f0814a979c5540f624c2b389b0d41" + }, + { + "kind": "file", + "path": "img_1362.jpg", + "sha256": "b3b1320f7b46e23b5f3b4b82b793c85426c8f6132a822d07a67ef8f57136b15b" + }, + { + "kind": "file", + "path": "img_1404.jpg", + "sha256": "45be66fadaa75aba99c38a9ec11236f7f8cbc91508532cf8d5875a2939b18697" + }, + { + "kind": "file", + "path": "img_78.jpg", + "sha256": "47e0ef6a6219ac919615b1d1f22156657cd7494e322a38a1dc4d18abeae584d3" + }, + { + "kind": "file", + "path": "img_3213.jpg", + "sha256": "374a40f93806ebc986b79ccb26f7041c04cddd9fddf94500efc0b79d1098fbad" + }, + { + "kind": "file", + "path": "img_50.jpg", + "sha256": "aea246a2a22ad5f480b9db1ef1fad7457287a32e214147123591e943cd13e15c" + }, + { + "kind": "file", + "path": "img_4554.jpg", + "sha256": "4bf8e9407ce2a68029e88660308f08ccb57a0a1254afb2a4fd293a2a9ac84e8b" + }, + { + "kind": "file", + "path": "img_4232.jpg", + "sha256": "3f3cfe26f459652bf80da7bd14a33987995690d6786289b505744fec8b6dc3e9" + }, + { + "kind": "file", + "path": "img_4226.jpg", + "sha256": "2f46c28c5b918dcf1eadab362fa4999cb0bda5e1197b44a1bdb68269bd429886" + }, + { + "kind": "file", + "path": "img_3549.jpg", + "sha256": "77d8029f9d951e8cb56aa882c5317c75d36b371aa19513bc03809bd60059b078" + }, + { + "kind": "file", + "path": "img_2657.jpg", + "sha256": "d5d482d41ae777a2526c673d0f31e83aa24f42aae1058f0a6f247330f0f8a684" + }, + { + "kind": "file", + "path": "img_44.jpg", + "sha256": "cdb58aacbda68e2b1c69e89dd1cfb746512058bd032dabceb10154cca094b642" + }, + { + "kind": "file", + "path": "img_2131.jpg", + "sha256": "9cb8d3605de222a56ac8ec6aee889694028726f21f6ab5275179c51e357037f6" + }, + { + "kind": "file", + "path": "img_4540.jpg", + "sha256": "4a0ec943844dd726eccb91bcd4a6d03f69a729558ace97d8083c9d68b5ec3e3f" + }, + { + "kind": "file", + "path": "img_1438.jpg", + "sha256": "3611d719a521bd4a08fa48bedeebf9f1b659ae36ebe294bc023af2af48536eda" + }, + { + "kind": "file", + "path": "img_433.jpg", + "sha256": "3aa7edddb852bb71ff6bbcd4f4fc0848e3dd9be4ac4b264754ac35b68800230a" + }, + { + "kind": "file", + "path": "img_2864.jpg", + "sha256": "c2e777c049c389b5ee5e54ffa3af32681d99807ced225e71a1b56552e335402c" + }, + { + "kind": "file", + "path": "img_355.jpg", + "sha256": "bd401aaf9271b0ccead2ece1f5ea91c99074a631e29bbed30e27e65d91b45c3c" + }, + { + "kind": "file", + "path": "img_2870.jpg", + "sha256": "db20c2a30616f1ea2941a846cb24488ac603a7082568352010a108af21e4bf11" + }, + { + "kind": "file", + "path": "img_341.jpg", + "sha256": "f71674b000e59e668bc90a148427dfd35591e07d0f20e6c20f33686661397137" + }, + { + "kind": "file", + "path": "img_427.jpg", + "sha256": "9004ff03178ba822deeb82ed84e67304a2f8dfe6041e5bdebae747c88ce8c0cc" + }, + { + "kind": "file", + "path": "img_4597.jpg", + "sha256": "9df89bd972c0e8495ec3657d5e379c564c2f9fad4439891322bc85552f44d27d" + }, + { + "kind": "file", + "path": "img_93.jpg", + "sha256": "dd1ee752a28373977a5133224c982b5864979169e63ae0fe66d7c4bc4f55fa28" + }, + { + "kind": "file", + "path": "img_2680.jpg", + "sha256": "ccd43570107c4b86dcade3b053f63de4267054379f3fa7a38676ebaa86cbee3e" + }, + { + "kind": "file", + "path": "img_2858.jpg", + "sha256": "15031c75f0a04aff78be2937ec0a491ec77dec3a653a574c93098d8aadb356b2" + }, + { + "kind": "file", + "path": "img_369.jpg", + "sha256": "72b7766a4ce80459d8b2637e59a5302edfc1e625c616543fa2527633a42c0340" + }, + { + "kind": "file", + "path": "img_2694.jpg", + "sha256": "41891ec70f8efff28cd0623742f85bb0365824095a06f79aa80df997ca962953" + }, + { + "kind": "file", + "path": "img_4583.jpg", + "sha256": "2943dbf05cbb1e0be485671cb98192c9701787f5e01c28d33a7134ace1fb4065" + }, + { + "kind": "file", + "path": "img_2874.jpg", + "sha256": "5b31aaaab72976a931f368907fa8d7dac0c6b494054eb27846008d42a7db7c55" + }, + { + "kind": "file", + "path": "img_345.jpg", + "sha256": "9662ee992966e78159db1d36e2b94113e80d202ed6d4827bc27370f7f2afd80f" + }, + { + "kind": "file", + "path": "img_2860.jpg", + "sha256": "6f875d81dd441d9273cb5e7af1a90738b3dba6d41fe13e7b5a436b7e5ab0e9a2" + }, + { + "kind": "file", + "path": "img_437.jpg", + "sha256": "22484488ed361d0b188979e6e0b0edf25a6208a6ed32c6e1c6d1ccf6a9ce5e73" + }, + { + "kind": "file", + "path": "img_83.jpg", + "sha256": "fa57fd3126e92711108937783002af7b3e1f185576b6cae1c62a1363b46115f6" + }, + { + "kind": "file", + "path": "img_4587.jpg", + "sha256": "cba4b6adf72e0a33b2c5366de6fe5f239647c8d3bbb7f6ab3c390a90ec3dd3a5" + }, + { + "kind": "file", + "path": "img_2848.jpg", + "sha256": "dada0160fd22e972cb462b032d81fe349d9ad6bf9be4afe7f2e36c41145ec695" + }, + { + "kind": "file", + "path": "img_379.jpg", + "sha256": "15281d8770e5a78116b8f50ccff8477f9a190075bc39c2b9da29116fca998267" + }, + { + "kind": "file", + "path": "img_97.jpg", + "sha256": "d38d4624431f713ed2baa59c3d6c1ed235db5621434dba63622653a69efd85a3" + }, + { + "kind": "file", + "path": "img_4593.jpg", + "sha256": "44061449fe6aadd820784c7833adc5f886791dba3e1049edce201d3313e0bb03" + }, + { + "kind": "file", + "path": "img_3217.jpg", + "sha256": "c6b4ddeb95dd3db0eba7d6b5f9f4863d8a6b61e15a351cb3166877611945dd0e" + }, + { + "kind": "file", + "path": "img_1400.jpg", + "sha256": "a3ee00d1a7e85d88f414bb88c485abc0bd65c2df84d8621ff74bc051d0410458" + }, + { + "kind": "file", + "path": "img_3571.jpg", + "sha256": "7d89d4253541169d8bcca618af233cf59368680ee94d40ce97ee491ca434679a" + }, + { + "kind": "file", + "path": "img_386.jpg", + "sha256": "8b33425bac4cfb776b9a46c07403cdfaa0681614c9d42ae33369dbd9ddb505a1" + }, + { + "kind": "file", + "path": "img_3565.jpg", + "sha256": "1bd0febdc7d0eef39fba6057866cf78d8ce4a26c382c10f42a585ea67a871990" + }, + { + "kind": "file", + "path": "img_392.jpg", + "sha256": "db9c599b5ae8f9a368ec5dbb761b01db9b05af09e137eef80ae3201667e66186" + }, + { + "kind": "file", + "path": "img_1372.jpg", + "sha256": "0b0231ab62d084bc24899ec1551fe6a76b2cac30d6e8d3579f2ea7634902a4ef" + }, + { + "kind": "file", + "path": "img_1414.jpg", + "sha256": "6d1749d53d3c6898fd2e11e17816c7b56d34119da0eaa2c5618ae434943c3914" + }, + { + "kind": "file", + "path": "img_3203.jpg", + "sha256": "70fcb6448cb0b062d7b61d2af5dd1cde1efafa7a18d670e895b4da0eecc51695" + }, + { + "kind": "file", + "path": "img_68.jpg", + "sha256": "6e68fe8880eed3e39d8891a438b87f09b3cd0a6060d16709712ae7cdcffc516e" + }, + { + "kind": "file", + "path": "img_4544.jpg", + "sha256": "df95219d8c1201bbfc771489d7414c0c2690e6eddf7f59b24a182c2d014ba716" + }, + { + "kind": "file", + "path": "img_40.jpg", + "sha256": "f6ae73fd729e7b2df66245d5512db64dc604a7cccf5b498a8bc734bf27465886" + }, + { + "kind": "file", + "path": "img_2135.jpg", + "sha256": "8c3af8c07c055aeefae0471a220b5e9c215651d3149f043096eadd08504feefc" + }, + { + "kind": "file", + "path": "img_2653.jpg", + "sha256": "bc6315f00d9c391ab04529c57d5432d60d9bd0ae1c12cd6596b2937646440b1d" + }, + { + "kind": "file", + "path": "img_4222.jpg", + "sha256": "eb860afe1899537330ca011646aa496eb9ca882c83c2cd68581089028ebacd2c" + }, + { + "kind": "file", + "path": "img_2647.jpg", + "sha256": "3b163b21e2d875556db514ca41e46bf6d2aa5ebc375c475e9ecc6b0a2dafb39e" + }, + { + "kind": "file", + "path": "img_4236.jpg", + "sha256": "971a5407496c608298b007369a7c071976e1c01f1ce3444a851cd0917a035c19" + }, + { + "kind": "file", + "path": "img_3559.jpg", + "sha256": "9df526f8f8a37ca710060e34fa09444265d4a2c116caebac541127129345898d" + }, + { + "kind": "file", + "path": "img_4550.jpg", + "sha256": "d6a32ec195992add697d517d191cec9634938c075874c31e09ddf9a97bfee685" + }, + { + "kind": "file", + "path": "img_54.jpg", + "sha256": "12660860e0de9d9e26c41e24d7b35c7016bd1f68be46b000776dc309e0fdb303" + }, + { + "kind": "file", + "path": "img_2121.jpg", + "sha256": "d707c73b0a7727299cbb729cc47dcfff3b4038741f57a627ab96e7e94e019dbb" + }, + { + "kind": "file", + "path": "img_1428.jpg", + "sha256": "ba604920f6a64c440513342a58e3367840928a08486b88f3516c66488be3f7dd" + }, + { + "kind": "file", + "path": "img_3968.jpg", + "sha256": "98f5ae28c0bbbfa4d78c213271e52a632531fb2dee651097c467df33f819fc26" + }, + { + "kind": "file", + "path": "img_147.jpg", + "sha256": "b9cd6c9306fb9a2080dd818e98db22df07a0dac8989c9ea101ed69ca8563f0ba" + }, + { + "kind": "file", + "path": "img_621.jpg", + "sha256": "e9d2bd85e20a1637f552f1e9f66dc44f077e19e4efbad4f4fcb279cda695e433" + }, + { + "kind": "file", + "path": "img_1819.jpg", + "sha256": "cdc58430ac0ac5e5b4202dc6308bf33bef9e6d31431755066ffba91118dd2613" + }, + { + "kind": "file", + "path": "img_635.jpg", + "sha256": "4c8c7ce5f7519baa377b981883a7f8dfab0a2ec32e367d22798349736fe1a291" + }, + { + "kind": "file", + "path": "img_153.jpg", + "sha256": "0ce73b7b2fa951a0ed3c348d507cd19bfacc30446dc29f34ca35684a50007bc1" + }, + { + "kind": "file", + "path": "img_3954.jpg", + "sha256": "804ff253deb3671c74eb6f378c8f9a7f6407ee1ae74aa86b5f52b5c8f6353599" + }, + { + "kind": "file", + "path": "img_2492.jpg", + "sha256": "5fb7d8f907a691b6c186a6c660ffdc09c36dccf51320bab391c67a8338add6d8" + }, + { + "kind": "file", + "path": "img_1825.jpg", + "sha256": "41722255beff2e053ec41fedbb1915d4d28d3492268632aee8742dc22e42a055" + }, + { + "kind": "file", + "path": "img_4791.jpg", + "sha256": "dc1099a8796d5e83bce074fc45ebaa93930a6b2d29414fd3b51c9f486d2cd546" + }, + { + "kind": "file", + "path": "img_609.jpg", + "sha256": "471eed1d444ddef3a3c6864388685b09ada031d4f613ad1231e85a7cc897f04e" + }, + { + "kind": "file", + "path": "img_1831.jpg", + "sha256": "8c82b03aefb5e361403bb5a060d0b529dff2fc408f3698d234fb169939305168" + }, + { + "kind": "file", + "path": "img_3940.jpg", + "sha256": "4a6772a3fb138fc95652926ee44ceccf5a85ca375f02cef28a142a5a8376ccad" + }, + { + "kind": "file", + "path": "img_2486.jpg", + "sha256": "b8f7f0ad08a1692458c5db6241b17c5e4847910924cd0a9bd3c5c79c2368e700" + }, + { + "kind": "file", + "path": "img_3798.jpg", + "sha256": "659600f1588bd0711e7c3444515a84feadbaa298b707cf456713dca9c851d491" + }, + { + "kind": "file", + "path": "img_184.jpg", + "sha256": "d19aae06a4eea05d9183f7e8b4da722492206aa71628df4d332803d5d0c7567b" + }, + { + "kind": "file", + "path": "img_1164.jpg", + "sha256": "7c97ca6660f6254b95e08240aa83da0cf82b07faebda63642045f80a1a657d94" + }, + { + "kind": "file", + "path": "img_1602.jpg", + "sha256": "6fbf86244ead4b2ee799d092b77c950442201634fae6583535cfbb0f6078534f" + }, + { + "kind": "file", + "path": "img_3015.jpg", + "sha256": "f0a8bd4cba3913187fef104cfe0564ac49fa4f560dd895d78055d9182c30c1e8" + }, + { + "kind": "file", + "path": "img_1616.jpg", + "sha256": "165c4488fea6880ecc79ab7f7ec557849359be4d8f1295d976df0daa3fc376ea" + }, + { + "kind": "file", + "path": "img_1170.jpg", + "sha256": "ccbf62822021a1701d76117780d2aaeffca98464f173409ac9a487c5b207c7ec" + }, + { + "kind": "file", + "path": "img_190.jpg", + "sha256": "f5f4fec7ac75a20d27d606c684164f0fc6be7db1d9f8de0c4f8448b597837a52" + }, + { + "kind": "file", + "path": "img_3767.jpg", + "sha256": "88c3fc32e485915ef327dbae5f9d8b4d9eff3ccfe34c90b35dc9f0eab58a3141" + }, + { + "kind": "file", + "path": "img_4008.jpg", + "sha256": "79dd9b4d383dc0c903e6a646322dcc773f8ab0cf44dff0209d984d015d3bf439" + }, + { + "kind": "file", + "path": "img_1158.jpg", + "sha256": "960984c7d6b6c4aff6cd31145c7df17058511539b654b024fff49c867b103b78" + }, + { + "kind": "file", + "path": "img_3997.jpg", + "sha256": "49f02bbc16e443ebac08576e3b7d2cd8e86bd8e8912128c5808cdd9e643ea38f" + }, + { + "kind": "file", + "path": "img_2451.jpg", + "sha256": "4672c612fc942a70139ebf80e66add9fa2d72fe63a23e8dc783250c00335b7ba" + }, + { + "kind": "file", + "path": "img_2337.jpg", + "sha256": "5d19d35c750aa17732e6735827452d603d43b16c039b5267eee5dd8a387c1309" + }, + { + "kind": "file", + "path": "img_3029.jpg", + "sha256": "007278e7aa497fa6a70038f3b52e0c279880548d16dbe1d121841cf4ab101cec" + }, + { + "kind": "file", + "path": "img_812.jpg", + "sha256": "d8379f9832eea865f927978982a9c113c135859d5cf7586854671839f71cb487" + }, + { + "kind": "file", + "path": "img_4752.jpg", + "sha256": "a5fb456ceade679305394b219452c220b5707247e787572cdda330fc17a28ae9" + }, + { + "kind": "file", + "path": "img_4034.jpg", + "sha256": "b004ba0ed5fdef8fd5b1803a282015e4c01bafff43b166719945665b4be094b2" + }, + { + "kind": "file", + "path": "img_2445.jpg", + "sha256": "27fb32342c036328c5c84ebf91242714e13074a191fcc942ea976934279d6fa2" + }, + { + "kind": "file", + "path": "img_755.jpg", + "sha256": "6447d834d88d264261f409ce9a0dd0bd3f89f9528b4f08cc5e703a9fee800537" + }, + { + "kind": "file", + "path": "img_1979.jpg", + "sha256": "95d61860a12362aac961dd24926a057e55f8ba75071462328758448db66684ff" + }, + { + "kind": "file", + "path": "img_4801.jpg", + "sha256": "5ab97e8fdffb024338c766b026cd024f914a4da7722abc661bbf20e6c6b7ca5f" + }, + { + "kind": "file", + "path": "img_741.jpg", + "sha256": "2806f47087c4ed97cb311d6d70d0dbfdf0bee41c35cab8f98910ce72cb03c766" + }, + { + "kind": "file", + "path": "img_3808.jpg", + "sha256": "6d80e2eff4349e429722a0d9ba05d47929cb2c99897923202b35f2de0a5f1fef" + }, + { + "kind": "file", + "path": "img_4197.jpg", + "sha256": "e04cfbc6b7d200f5ed63f7778019dc2f16911ab90f23ed5fd1b833bf4fb03d83" + }, + { + "kind": "file", + "path": "img_1951.jpg", + "sha256": "3c32b956b63b10503e9d614dd4fa51574657aaff13d03278703b7593b0ad3857" + }, + { + "kind": "file", + "path": "img_1789.jpg", + "sha256": "03a9f99915114bcd5066f6fe023c63d2c7853b27b541c98a02867ee20e607fb2" + }, + { + "kind": "file", + "path": "img_769.jpg", + "sha256": "e51b8000da442876bceb2db1bd7eaf0d0286459f9cb8d3a4bc63cd23d6189f62" + }, + { + "kind": "file", + "path": "img_2294.jpg", + "sha256": "ed0564950a915ecbc9b0e36e634879ab2293beddae3b7f1943e8cdbda5a66767" + }, + { + "kind": "file", + "path": "img_1945.jpg", + "sha256": "757686e92981af52b192d3d7523eb1269b89c7fa3998eba379f6c177df62a57d" + }, + { + "kind": "file", + "path": "img_3834.jpg", + "sha256": "2bdc54bbcf640a913d02e2f05b031125a1cbf94d44cc11ca4ddd782fe4041c52" + }, + { + "kind": "file", + "path": "img_2519.jpg", + "sha256": "c79ecf207078fb41cc9502186c65184bcd807057faa05daab87105d3f6bb819c" + }, + { + "kind": "file", + "path": "img_4168.jpg", + "sha256": "f818c7fae87d7557748ab4ec9ec4e4d63198bef0f0e2179bb5651de451704024" + }, + { + "kind": "file", + "path": "img_3607.jpg", + "sha256": "8ddbdbff8f3fa96e8b0e3fd693c5433506f95a8f485d79bcfc9a1b207b9b2c15" + }, + { + "kind": "file", + "path": "img_1010.jpg", + "sha256": "8bcb2519398920bd6da904603b5fb8319cd3217301c0df20c34de1ac8996684b" + }, + { + "kind": "file", + "path": "img_1776.jpg", + "sha256": "b3d80ad13f1432e0930c24fcc9fee7d4bb4d6eeeb4adfd6f2a29adedf0b41116" + }, + { + "kind": "file", + "path": "img_3161.jpg", + "sha256": "32df03d38580970486bb80d13a499ed13642ca1f50f769b7f1a2254bbb4c4813" + }, + { + "kind": "file", + "path": "img_782.jpg", + "sha256": "b07db9980f22ec47892519bc6b8f151d3be4bdc01216672510190955005febef" + }, + { + "kind": "file", + "path": "img_3175.jpg", + "sha256": "c206ecbcf009f8f26f11714b86d8a1e1afdb82477831a06407c89c9e59fc4c26" + }, + { + "kind": "file", + "path": "img_1004.jpg", + "sha256": "aecfce33328884cac0b8aad287241dd61c1e8640aa2d8c09a3405eecb5063958" + }, + { + "kind": "file", + "path": "img_3613.jpg", + "sha256": "75a8f2642d5f1c6de22f981f528a254699c00036f529956019c4d9b8b8de27ea" + }, + { + "kind": "file", + "path": "img_4154.jpg", + "sha256": "e2bf26d964c98103a8de7e321401f30dbd78f5faaeefeb7a323c056fc8800b68" + }, + { + "kind": "file", + "path": "img_4632.jpg", + "sha256": "4adfa90e351aa840dd5a20e0ab3364ee088d0d7546ae2210bcee1a29df0e418b" + }, + { + "kind": "file", + "path": "img_972.jpg", + "sha256": "60c06bb94fff573ce392566d1161342b4cc36fca5920f799dd23b14363e58ba6" + }, + { + "kind": "file", + "path": "img_2243.jpg", + "sha256": "74f9debcf8868f3ea0f03c7e66715f5c89f00bf3dcfb1ba8c39042d6d42d53d6" + }, + { + "kind": "file", + "path": "img_1992.jpg", + "sha256": "600b0d563a6319f817afcc6f446f93d938c3df9652aaeeffb0d258e0c92c5058" + }, + { + "kind": "file", + "path": "img_1986.jpg", + "sha256": "c631e73e3869bc411b6223d95ac345f6e78250a62d9c97d49b77c2ebfd80532b" + }, + { + "kind": "file", + "path": "img_3149.jpg", + "sha256": "8a2ea1c00b91a96452d5da5debba382bd33868e35525cfc23ee3dfd7ab441c4e" + }, + { + "kind": "file", + "path": "img_4626.jpg", + "sha256": "a8d7e3fa8443871c8537f1e341b842d0f63430748c43b0baf33f86accaebed50" + }, + { + "kind": "file", + "path": "img_966.jpg", + "sha256": "adf572eb7eac2afcf871e51e0e4613097077853cfefe6f1b8be10e8d557f8de8" + }, + { + "kind": "file", + "path": "img_2257.jpg", + "sha256": "13bc1e07fdd17a566a19c5e383bf25bcb3066a00dc5dae7f56857ba9f846b68d" + }, + { + "kind": "file", + "path": "img_2531.jpg", + "sha256": "faeb46ed9bf159a6a240fb7a78af374ac28828ced7c72d9837a9f39ccb919e74" + }, + { + "kind": "file", + "path": "img_4140.jpg", + "sha256": "a2d3431b208fce8dcc01197c42ae493972e3143d4a4185531921e2178bbe9fcf" + }, + { + "kind": "file", + "path": "img_557.jpg", + "sha256": "5c97e7b352ed6ffd9644de7be1127aefaa1e6272debff4560d1c3e8977d38293" + }, + { + "kind": "file", + "path": "img_231.jpg", + "sha256": "4dd5b16eafb6c516a5aa99e13926ee0d39125dbe128b840ccecbb387f0f95e1a" + }, + { + "kind": "file", + "path": "img_2900.jpg", + "sha256": "eba5873106d9087d93927e7a161e25d0244390e84ac6bae50e6e6e832a91b4ca" + }, + { + "kind": "file", + "path": "img_225.jpg", + "sha256": "cab5159ba55344d6b1b12c5ffc73d154263ab4974e47f3aefbf303b2476f587c" + }, + { + "kind": "file", + "path": "img_2914.jpg", + "sha256": "3d1368acb447b5c5f247df88422e4263d04fc208c02edd236ca8ba69ba3949c3" + }, + { + "kind": "file", + "path": "img_543.jpg", + "sha256": "f97785458cf233c710ef75ae1bbdf223da14d8cae38ff0f3b19050df4f0b5820" + }, + { + "kind": "file", + "path": "img_2082.jpg", + "sha256": "e90ad66d2008d91ac1864c7a6b20229690fd852c7070753fb9e5514aaa4866e0" + }, + { + "kind": "file", + "path": "img_4395.jpg", + "sha256": "67f2a7ee005ad02dc6d2283d174381ad9202920430340a1a5f659a969d25a5dd" + }, + { + "kind": "file", + "path": "img_219.jpg", + "sha256": "9d8d37f13f03fec1b66274a39c4f690c18f8b6026bc31e91685f83789dc99da6" + }, + { + "kind": "file", + "path": "img_3388.jpg", + "sha256": "24146507daa1f6871216b11b3afde434e76c0f164b07c5fdc9ebcf041d83c033" + }, + { + "kind": "file", + "path": "img_2096.jpg", + "sha256": "380f683390d6ab6a4a9e42ef5d063efd045a2d0bde91822b398949295bdab555" + }, + { + "kind": "file", + "path": "img_3363.jpg", + "sha256": "240b4cb6f79c22d67fffdb1372c1beee7ef29b9d091202f0b92d121e2a03bb45" + }, + { + "kind": "file", + "path": "img_594.jpg", + "sha256": "e95c6d9c630be8c3e3e7375edd38a939fc869ffaa4e2aee7bcb9ac682c2b8799" + }, + { + "kind": "file", + "path": "img_1574.jpg", + "sha256": "a87d859762dbb5b7db6304eef8220d61c8ec534234c0453c5fc22481f5355cbd" + }, + { + "kind": "file", + "path": "img_1212.jpg", + "sha256": "4ad168147964e37009136d0d99b8e84bade90d0c553e2a94014a3edacd50292f" + }, + { + "kind": "file", + "path": "img_3411.jpg", + "sha256": "b120edbf0f3a4547612387e00e84c885e9e60034eda97b66caf1310ae29fdeb2" + }, + { + "kind": "file", + "path": "img_1206.jpg", + "sha256": "ca511bcf747a6e504ef73b5d602c4fabc23aa02796fbfb576d79d3ba98502f2f" + }, + { + "kind": "file", + "path": "img_1560.jpg", + "sha256": "c2d22a7dc082aa7c4c3b1fc1432ed73a95e7d61ca66e36dc2150caebfbc97cda" + }, + { + "kind": "file", + "path": "img_2069.jpg", + "sha256": "547a32e1a482b58907c2a81111b10205f26f3cb18c22313512781fd26faee6da" + }, + { + "kind": "file", + "path": "img_4418.jpg", + "sha256": "71d28b72709d88790fa629699855468ea00e201919dd8b67fa0bd665bcf774b4" + }, + { + "kind": "file", + "path": "img_3377.jpg", + "sha256": "11e75188e59cffff246dd6d3734ae4c9fa9793aaf706b624f56990a304fe8a6f" + }, + { + "kind": "file", + "path": "img_580.jpg", + "sha256": "cecabfff26ffb09419a25d223da09036f976ca52572a8f8b2bf971395aef2a47" + }, + { + "kind": "file", + "path": "img_1548.jpg", + "sha256": "8704b44470de885852ecc89d148386e7a3bbbb40c194239ee442e2993f8aa51d" + }, + { + "kind": "file", + "path": "img_4430.jpg", + "sha256": "cdd789bd62d9a94378a947ec815eb638d1399966e7c880482fdc04204dd5914a" + }, + { + "kind": "file", + "path": "img_3439.jpg", + "sha256": "72ce0fa722bb0db267427a8922433471abe7742c92e6956a3ace73bbcf68afc1" + }, + { + "kind": "file", + "path": "img_4356.jpg", + "sha256": "dc625a8f226de569e8a7e360e6289dd1b4035ae925ddb567721f44d9db87d716" + }, + { + "kind": "file", + "path": "img_2727.jpg", + "sha256": "2f3a56045b50d01dd9cfe3c18abfc4bba12adff03d9867aa314ade2c4f9b45af" + }, + { + "kind": "file", + "path": "img_4342.jpg", + "sha256": "c71862c10a7d47ffddad734b4d6ca529b385f6e942fc3db4fdfbb687dc84baa7" + }, + { + "kind": "file", + "path": "img_2733.jpg", + "sha256": "2f338420e260e55d5df1ceb7c4491bc7fff5a031c55a0aed7652ded7d9c4adf1" + }, + { + "kind": "file", + "path": "img_2055.jpg", + "sha256": "2e268492c7d1150914fdd7766cf8808d63f455c1ce11e206dc67e6a3df4f2e17" + }, + { + "kind": "file", + "path": "img_4424.jpg", + "sha256": "23e1291f0bcb1e2da9db0b1a77e508eb766aa10344e16385d481857084ca6158" + }, + { + "kind": "file", + "path": "img_2732.jpg", + "sha256": "9ba32858a812c4f3dc8975cd7ca7c53ead27a408b159832c2e5eff24f6bbeee2" + }, + { + "kind": "file", + "path": "img_4343.jpg", + "sha256": "1018b66c826f21ee19e3edce9291951ef0b6d878b7069e630878ac98ca8f476f" + }, + { + "kind": "file", + "path": "img_2054.jpg", + "sha256": "c1f019735fac73dd69635f6a8fdc4c0456d7cbdeb8f00cbeaf6166a8eb9c8135" + }, + { + "kind": "file", + "path": "img_4431.jpg", + "sha256": "6b64c9ada25238426c180388f6a7889e7dca068d59c8819acc61474d593b1c36" + }, + { + "kind": "file", + "path": "img_2040.jpg", + "sha256": "152caf94852d4db40f6c15b2d58a2ad635718e8bf563f981fe3e1c488d05f865" + }, + { + "kind": "file", + "path": "img_2726.jpg", + "sha256": "97f430c418500c265b4985fc9b7be9b111d9bf4fa4735c9f448c7408485c8629" + }, + { + "kind": "file", + "path": "img_4357.jpg", + "sha256": "27b82dce086244193da1b03e3c5698d5ef0e5367d9b26074b9c38ffa78edad4d" + }, + { + "kind": "file", + "path": "img_3438.jpg", + "sha256": "4e583cf0279295c56f82340651b7f950a1545c36f2a227f6cd16b2468d290d17" + }, + { + "kind": "file", + "path": "img_1207.jpg", + "sha256": "03128fe91dcd294fdfbae61caa43b3180a5c2213897b4c6f6f43c5cb0f0cda31" + }, + { + "kind": "file", + "path": "img_3410.jpg", + "sha256": "812130dda3baddff1b0d32ca9731c0142fd02eeec23eef2cb40903bfba9a7e2d" + }, + { + "kind": "file", + "path": "img_581.jpg", + "sha256": "8615d45b8c13f4d04f885bc7c5ef4273e501353537b12fb5ad84694af308c971" + }, + { + "kind": "file", + "path": "img_3376.jpg", + "sha256": "6190b406892bbcea73b27b93a441d82c5b83209651467810aabe97c657cb2529" + }, + { + "kind": "file", + "path": "img_4419.jpg", + "sha256": "8a9f2d366979f681ac080b3767527682e8e643625852f64a595eb0e100a0591a" + }, + { + "kind": "file", + "path": "img_2068.jpg", + "sha256": "55b606fc87199db9e3b49b851a77627d16cc2f9d23dea71d47f518af4c60e19a" + }, + { + "kind": "file", + "path": "img_1561.jpg", + "sha256": "aff80c8df107f54b063a0f513e050e25dcdb5638aad07d5cf0c45211fd5cc166" + }, + { + "kind": "file", + "path": "img_1575.jpg", + "sha256": "9883588bf414003f58506e50f5f72fe852b7ec3c65a4d169639c4a9a1622c3d8" + }, + { + "kind": "file", + "path": "img_595.jpg", + "sha256": "26943c8aa8854cc64c3a4397657a7f76ec3a95b2fc891d108a6f832d62f00107" + }, + { + "kind": "file", + "path": "img_3404.jpg", + "sha256": "047440d513252ac71ebe11951c25ef4a06a74af495bbbe7104beab0d62b468c1" + }, + { + "kind": "file", + "path": "img_1213.jpg", + "sha256": "086ec35210526db6c43bc9a6443a7db8438fff6a47b488c1d386ad63908d57ba" + }, + { + "kind": "file", + "path": "img_2929.jpg", + "sha256": "9f62ecfba92629efed7b4ec745d2972339082f5889624cf53a716934e9235ab4" + }, + { + "kind": "file", + "path": "img_218.jpg", + "sha256": "c58fa51ca13fcade7678cde54428a6c7ede556f7e1c8ac780f02fc06fb93e7aa" + }, + { + "kind": "file", + "path": "img_2097.jpg", + "sha256": "45c1d1b29d62e66f1d6e3239f84cb63ec29a0c484ff0e1c80830806d21e5a31b" + }, + { + "kind": "file", + "path": "img_3389.jpg", + "sha256": "c218f95b09d16ad0008b4f7eb16a19e7f32d5b1d11bbcb1dac89a2453dc4fa06" + }, + { + "kind": "file", + "path": "img_2083.jpg", + "sha256": "5c0dfb5a41e6f5c5bd11e840d5bd277b65c179a3ccf123e5f3a2d1275e2c81d9" + }, + { + "kind": "file", + "path": "img_4394.jpg", + "sha256": "99b2b70464c0ba613e90f2a74b8346f4971bea9b776e8cc56a05a6d37e2cffbb" + }, + { + "kind": "file", + "path": "img_2915.jpg", + "sha256": "f9f1788d0f1959787ee93b5aec5efc77a104683b17c0710b765b0e1713c52423" + }, + { + "kind": "file", + "path": "img_224.jpg", + "sha256": "c68a7bcf50c0f8c0c1b72b6aeb236faf77d55fc5a51ff5cce5c538b7cf416a9f" + }, + { + "kind": "file", + "path": "img_542.jpg", + "sha256": "af1d0310293e1f08c18815dc0688d3cdb401636c92a31796066a8cbb998951fb" + }, + { + "kind": "file", + "path": "img_556.jpg", + "sha256": "917659118c5281bb8a5494bcecbcda857b55a5fbf4751f51d6f9e17524017fef" + }, + { + "kind": "file", + "path": "img_230.jpg", + "sha256": "1926e86d7ad4d83575d1b08236ee9018b93b60277218d8c9cd5f732c193e5a5b" + }, + { + "kind": "file", + "path": "img_2256.jpg", + "sha256": "6832737571871dcfcf22502055afd645764460a9639b95b8585e68319c9fe8e8" + }, + { + "kind": "file", + "path": "img_4627.jpg", + "sha256": "ed1d12e9922a238304ada2051e309fa9ffbed18f5988ee7ce67f7d5b72469881" + }, + { + "kind": "file", + "path": "img_3148.jpg", + "sha256": "ea805516688c05e919c3838eab3bc8f05d8b99313fc892378851f5bf2ae5f7eb" + }, + { + "kind": "file", + "path": "img_1039.jpg", + "sha256": "be493a4290dade668d0241302aaffb23d00477f3f61c806546d4bf01004b5edc" + }, + { + "kind": "file", + "path": "img_4141.jpg", + "sha256": "b848970ce94da8d7fe3582c2739d21530b76ec236fb03f1decf18afdbf2fe297" + }, + { + "kind": "file", + "path": "img_2530.jpg", + "sha256": "b0378df56c78b59563304990cd4cc5ef3666c461ac6c25ae356ffad64dd0e8b0" + }, + { + "kind": "file", + "path": "img_4155.jpg", + "sha256": "8c7457ed39a741f322121ff5e388fb908fd806fdeacdf0edb5d0cfa9da2876b1" + }, + { + "kind": "file", + "path": "img_2242.jpg", + "sha256": "3d42941b5fca724e1ed6629fad8459786ee0f193a15b6e4765124d6c7c8cad6f" + }, + { + "kind": "file", + "path": "img_973.jpg", + "sha256": "c26962a61057430b99a878ef85bc15808dafe03c8d2eee362fade2fcb8239674" + }, + { + "kind": "file", + "path": "img_4633.jpg", + "sha256": "537e40878c503021bfe473d3a54413bdcb4005d528a8a07b65c764f132951925" + }, + { + "kind": "file", + "path": "img_1763.jpg", + "sha256": "7a6bb105a4e132299bae41f9332cf7192c7e7e9d1857cc6d4aae0238ab473dd7" + }, + { + "kind": "file", + "path": "img_3174.jpg", + "sha256": "5da1ba83cc6525ea2aa50387f921124546416e5f39770246547a30cc70f9218e" + }, + { + "kind": "file", + "path": "img_783.jpg", + "sha256": "c8ef564c787047be67c2834a8c724dad238781e9fb3df30912227a8bea5fb45c" + }, + { + "kind": "file", + "path": "img_3612.jpg", + "sha256": "8644d7a26d467abf853b51e0ca71f5e29218effbc4c1d87bd4d5eda2372cb7ae" + }, + { + "kind": "file", + "path": "img_1005.jpg", + "sha256": "98eadb1b6bb0b175afee651f3609fd19ca6c19d516c19b7d053719cc69f63036" + }, + { + "kind": "file", + "path": "img_1011.jpg", + "sha256": "cde50e402e7beabfa84134d96f90664a479fdc61813720daf9391ad13b00f8cc" + }, + { + "kind": "file", + "path": "img_3606.jpg", + "sha256": "4f6701c0963b60ac0a8bd9a620ac6739c7a1d51f0b650e5edf74e00b139d26f2" + }, + { + "kind": "file", + "path": "img_4169.jpg", + "sha256": "7caccebf5f53a9f0a7da90e053559fe94164fe2ee15396538f6f7d082eab58a6" + }, + { + "kind": "file", + "path": "img_3160.jpg", + "sha256": "806b02a973160eb9f27cfec845f51b1beac377776b9c2ab20fc763c113b41bb0" + }, + { + "kind": "file", + "path": "img_797.jpg", + "sha256": "188bc1052669743d484ad2b39c31416cf68ff4e5d52c8c7c44d63c4f9741f5c3" + }, + { + "kind": "file", + "path": "img_1777.jpg", + "sha256": "82881517fcc2a8f4a2b54148b51ef4fe02a93ae4adae7704d4d5a7dc46f01e07" + }, + { + "kind": "file", + "path": "img_1944.jpg", + "sha256": "552230f7901ded16d53a7baa404c2c36a48be7a8c9011d26d418676986a90882" + }, + { + "kind": "file", + "path": "img_2295.jpg", + "sha256": "791510a18e216a8fcbbe535b2849c9c9bfeb5ab49fee19bf22227d9730599501" + }, + { + "kind": "file", + "path": "img_4182.jpg", + "sha256": "25a13f32722844dad6a3c8693526faa47eb7a3a3da05d5e587dd3d226921f021" + }, + { + "kind": "file", + "path": "img_3821.jpg", + "sha256": "6f4816c36d6c52a52752c6b1d870a5a12759efae7d311ede0f552010be0db86e" + }, + { + "kind": "file", + "path": "img_4196.jpg", + "sha256": "5f74099df5d6daf44ae127d5345734e4c53757be25436a9b64e6af1d9e68ab3d" + }, + { + "kind": "file", + "path": "img_768.jpg", + "sha256": "9729f0db0a32eb5ed5902fbcaa357eb170946f16c9613043623f29d025584315" + }, + { + "kind": "file", + "path": "img_4828.jpg", + "sha256": "c36a25337cf70dbd5b6d9a6f939f033e882ba5cca78618a593cee821750bb55b" + }, + { + "kind": "file", + "path": "img_1788.jpg", + "sha256": "2b83bdae778ac68e902086f8e1f83d9940b9031eff3aad2f4e5dc02dc9d1a8ca" + }, + { + "kind": "file", + "path": "img_1950.jpg", + "sha256": "4ac7987dd96a21a7f34b21544ba1794857ca1feb2ed7608e78f8811e675332c3" + }, + { + "kind": "file", + "path": "img_998.jpg", + "sha256": "7db41f1fe363eb42286ad07a19eb676f5c449629db60ec906b4b18b83aed4e89" + }, + { + "kind": "file", + "path": "img_1978.jpg", + "sha256": "7a9f83cb9439469e29b55424ec961ee88fa0e34f5d1d649fbcf66b8b646201eb" + }, + { + "kind": "file", + "path": "img_3809.jpg", + "sha256": "03f39da1f0e466cbeacbf5fa27f6e53ee33f0edb37ff9c98797a3ae7bed6b2e0" + }, + { + "kind": "file", + "path": "img_754.jpg", + "sha256": "8549224c6c968f6fba643bd64f39b8aad4a2998beae6759a937bb98476df0d84" + }, + { + "kind": "file", + "path": "img_4814.jpg", + "sha256": "c358bb1f20c4027305227937ad39e2067fc89c1055fd363a4c0daec0a249e7bc" + }, + { + "kind": "file", + "path": "img_813.jpg", + "sha256": "69549d1fa5f0fecb079f116eba21f244455c54f9cbcd56af95a7fd621ddd99e0" + }, + { + "kind": "file", + "path": "img_2444.jpg", + "sha256": "824d53ec858d5f0e1b6697b751bb58da8d8eb93d529fa89d3e509fe1e2cd1b84" + }, + { + "kind": "file", + "path": "img_3982.jpg", + "sha256": "aaf8e70abfcd09a3431c99f928656de46ceb130990776395dcfeec24535de4ea" + }, + { + "kind": "file", + "path": "img_2450.jpg", + "sha256": "9e91795076bdc159d894974b8f1a36cf0c644e0623f1ae2d98b4741806aeb9e1" + }, + { + "kind": "file", + "path": "img_3996.jpg", + "sha256": "b0e7d24848687b6baabd8acef5185c0f2f8de3adee46b7789d5ed05700b0d4fa" + }, + { + "kind": "file", + "path": "img_4021.jpg", + "sha256": "e6cb4b72fb0d537c109c0c610f9ae1d6c9e7eeaaad53dec6093840550f700e06" + }, + { + "kind": "file", + "path": "img_1159.jpg", + "sha256": "85f0965fb34152d0d43245ece364f859dfd1f5818a8d50d2b240bfe6cbdb5924" + }, + { + "kind": "file", + "path": "img_3028.jpg", + "sha256": "f31dd615e011ededba6ffe4ff7ecd29e18af375167caebfb0307755c20e9389e" + }, + { + "kind": "file", + "path": "img_4747.jpg", + "sha256": "3fde61cba9fdaf534bcec35855d59d241b726a46c8611e343feafcd0fcc57b4e" + }, + { + "kind": "file", + "path": "img_807.jpg", + "sha256": "fe4acd26846e216d3d51e0f04d32eb0bc93002d265e811f6f954ee81acdea181" + }, + { + "kind": "file", + "path": "img_3000.jpg", + "sha256": "1f728c8e44e9a9135565a0ba055d66065c36f1e5de4c664b1e4333e5398a55b4" + }, + { + "kind": "file", + "path": "img_2478.jpg", + "sha256": "f321556757353882e71aa59b312ca4a6717c56bc6bc51b2c5197e20f222116d7" + }, + { + "kind": "file", + "path": "img_4009.jpg", + "sha256": "9b8c54e1b9ee9eabc24233d799bf181f1067135b517c07f5c7d9329185df8da6" + }, + { + "kind": "file", + "path": "img_3766.jpg", + "sha256": "be26c65f88b3a6afeff148746dc565c7a3e7eed3476fb236d96beff384075cf9" + }, + { + "kind": "file", + "path": "img_191.jpg", + "sha256": "5fc2c65166a42fcfb6c194d05c63117e0a09e131ea660f1ed04681d5dd07d57a" + }, + { + "kind": "file", + "path": "img_1171.jpg", + "sha256": "15262f32781a0c2b7004db1c83da1694fe2315b68996f6c09fbad19faae9c1c7" + }, + { + "kind": "file", + "path": "img_1165.jpg", + "sha256": "21812a7411fc1b92b03d933b2a3a5127d3eb53864c004356922e96d4f5737228" + }, + { + "kind": "file", + "path": "img_3772.jpg", + "sha256": "8c8b05ef4e3962f3c1399eec588624b84440d6f43ef5760c4ef2280e8c343d27" + }, + { + "kind": "file", + "path": "img_185.jpg", + "sha256": "bc0cf974abe673f379b67dd40875120ba24d91141a60539a149e9aec982e9ca6" + }, + { + "kind": "file", + "path": "img_3014.jpg", + "sha256": "ba2445d0863f4a6f5254f8b7627f43049a2e88f63975858d94320754f4888fd5" + }, + { + "kind": "file", + "path": "img_1603.jpg", + "sha256": "02ed4f550d4901e1b07b4545a0b46808adc17fa8f92165b91a65334e685fa402" + }, + { + "kind": "file", + "path": "img_1830.jpg", + "sha256": "1a2f421d52775be937badc29709557cffe46ab26fcf0863faa5ce424b927a8d5" + }, + { + "kind": "file", + "path": "img_608.jpg", + "sha256": "c57d9485105b35155ca5aeb26370ef40689f54d8c3e7074da72e5a29eb5bc2f2" + }, + { + "kind": "file", + "path": "img_4790.jpg", + "sha256": "64ded4d7b06353c681d8ce5a216dfcf8852a6156e8f2f0776fafd6702af44013" + }, + { + "kind": "file", + "path": "img_3799.jpg", + "sha256": "9b5dae0347d2176d4571c2e30989b534ada948c96111cd31bbf22adf6b1c71c5" + }, + { + "kind": "file", + "path": "img_2487.jpg", + "sha256": "b39e89cac92decd2d32fdf7260e482c19f2602f3e3aa0d87cd5aba8f117c245b" + }, + { + "kind": "file", + "path": "img_3941.jpg", + "sha256": "f63c8ac55339967f83e58481800b3f578cde671a16bbab17cd6deae9f07df9c0" + }, + { + "kind": "file", + "path": "img_2493.jpg", + "sha256": "2fd1eb40989403c6c31f19558539a3ee3a2e7d2aa119a83e746f1d745a93d9ea" + }, + { + "kind": "file", + "path": "img_3955.jpg", + "sha256": "7df4a8e489cdac69e1ffecc92a9ce204dc4232fe0dddb8492380f3b53cec902f" + }, + { + "kind": "file", + "path": "img_634.jpg", + "sha256": "50e7dc387bd9be4b0cdf2c29acd3bd15addbdbe5368c3a9bf3e350954915208e" + }, + { + "kind": "file", + "path": "img_152.jpg", + "sha256": "89da80c703f9bdcec3e9d5238ae2f365efc1d6bf95f512aaa2227cca9abc8dfd" + }, + { + "kind": "file", + "path": "img_146.jpg", + "sha256": "3a84f7c980220ab17ff402bd8fbec027fbc5ef5338f9863f0f1a145f697fc6dc" + }, + { + "kind": "file", + "path": "img_3969.jpg", + "sha256": "3e7fe3879fe599c480c9b77e7823bcc049f43d2694ffce3e0e1bd88da8cdcecd" + }, + { + "kind": "file", + "path": "img_620.jpg", + "sha256": "055f01f8793bf6be55cd5f55feba317ebd39d5347a19aacf8eb8770c7aac0546" + }, + { + "kind": "file", + "path": "img_2646.jpg", + "sha256": "1ff051d806ce73faa640500a80fdf48c9fbae07bd0f181dde717893aa19bb979" + }, + { + "kind": "file", + "path": "img_55.jpg", + "sha256": "3ffba0ececa0e0383543325a2144f5cefa4e914abd258be0dfd4ca34fdd0dc2e" + }, + { + "kind": "file", + "path": "img_4551.jpg", + "sha256": "6ee2b41f7dad5596f7df9fb9b82116c6c73cfbcc6853bcbca4154511e1682e8d" + }, + { + "kind": "file", + "path": "img_2134.jpg", + "sha256": "aa31ae0bfa43d601b3773c65650d024eb985101606918e037efe2bcf04a47787" + }, + { + "kind": "file", + "path": "img_4545.jpg", + "sha256": "67b099fa79fabab14c0f2c255093fc7a2cb0d4eece5f81371e7b6fbd093443da" + }, + { + "kind": "file", + "path": "img_4223.jpg", + "sha256": "b6d877f02b7ec0eb88612c522f86a28941ce9b738bdd6669f7326fc4b7ef502b" + }, + { + "kind": "file", + "path": "img_2652.jpg", + "sha256": "11cdb7487074a3ee7251d3059f6ba79f9060f99ec5ac5fe0d74b7f7b4a567064" + }, + { + "kind": "file", + "path": "img_1373.jpg", + "sha256": "fc9ee06ecfa2c111fe8c89141a1115a46477ba67daca41f555e39b47b625d3d9" + }, + { + "kind": "file", + "path": "img_393.jpg", + "sha256": "efaec241f75467b539e4ca1b3a93643a038d0331ca9989d0a6f2e0b72f76899a" + }, + { + "kind": "file", + "path": "img_3564.jpg", + "sha256": "e278d60afe0f4d1dda85a0f868970deb6b5535fa451f9b0929952013f9f4df39" + }, + { + "kind": "file", + "path": "img_69.jpg", + "sha256": "a27f584fbed724c98333c4f2e62d988d832d78f3a0b8fec06d38408d7f9769b1" + }, + { + "kind": "file", + "path": "img_3202.jpg", + "sha256": "610f793041268f3d44733ff3bd4bea6554779103189f1794a7c9a9405b8f6eca" + }, + { + "kind": "file", + "path": "img_1415.jpg", + "sha256": "0c05ddbb1c1040c675be7387185d3ea2f7caf0bd43559241d9afd46dd8582d6b" + }, + { + "kind": "file", + "path": "img_2108.jpg", + "sha256": "70f0b74f9e3638c2a5a38f847423e14611f25f123807dea4d268e516dc2fee45" + }, + { + "kind": "file", + "path": "img_4579.jpg", + "sha256": "92b9242a41782422df1e5694e0750da38f149a56e550fa9674f2db62ae70b457" + }, + { + "kind": "file", + "path": "img_3216.jpg", + "sha256": "28d2f02ab623d46a06c334aff44c826bece305bdd0d69e4b00ab6d00d302c722" + }, + { + "kind": "file", + "path": "img_387.jpg", + "sha256": "a1699d4f1c6df0172ec31b0f4163f9a04f71736b1f04f5fb4d55dffa8f05b5ba" + }, + { + "kind": "file", + "path": "img_3570.jpg", + "sha256": "498542f350c7e28f640518958b709eec82fd2704024588020d7deaf54c88881e" + }, + { + "kind": "file", + "path": "img_1367.jpg", + "sha256": "b762fe335cdb2ed0c28f75f184935311006081fc2995526da2d06ab404e82f36" + }, + { + "kind": "file", + "path": "img_4592.jpg", + "sha256": "6520a6e40a3d022f5b59d721996c36a55686ef495d18289a763318d006674a41" + }, + { + "kind": "file", + "path": "img_96.jpg", + "sha256": "89c40fc28d5af42f65b04c49b157094115a121c329f878914f27546fb9f8928f" + }, + { + "kind": "file", + "path": "img_4586.jpg", + "sha256": "9ea3d5c761e848cd3ea008cc08993610d901372d7bbb828b79767ca8c303ea22" + }, + { + "kind": "file", + "path": "img_82.jpg", + "sha256": "a13aeb1fbff46dc2b7e7f37861f92b0131ea0c407f71997eda71abc9f33de3dd" + }, + { + "kind": "file", + "path": "img_2691.jpg", + "sha256": "a7b211bef2c800c18fd0005425524258a15294ae1713b4ec597e186d368abba5" + }, + { + "kind": "file", + "path": "img_378.jpg", + "sha256": "28b761a1193d9846d1d4aa8008cb77472c5d5a96bb3fd34de240c4a7f8580fb7" + }, + { + "kind": "file", + "path": "img_2849.jpg", + "sha256": "3053a8852007910961b6413b322a54cf4492de131c0326e7feb969f6594acf08" + }, + { + "kind": "file", + "path": "img_1398.jpg", + "sha256": "a88bf5a11b27ef2204322a16504a7c3b10751f5f0567dc1efc607d7971eb1724" + }, + { + "kind": "file", + "path": "img_350.jpg", + "sha256": "b72b322d007445f5837037feae2e069636b376cc0603efc7ebf8810607c896d0" + }, + { + "kind": "file", + "path": "img_422.jpg", + "sha256": "1875e70b1e8159084cc8f3102914d2ef9ae29730a7983d352b3f2507f7ad6dba" + }, + { + "kind": "file", + "path": "img_344.jpg", + "sha256": "bc6c4686aa92214126b6c0f60f47e0b02c746540f82dfb8515bcd7af33de1b5e" + }, + { + "kind": "file", + "path": "img_2875.jpg", + "sha256": "eaee426b27b52b7f28f77077ce5b07ed8371d42a4294fd98de399405fe41e480" + }, + { + "kind": "file", + "path": "img_434.jpg", + "sha256": "ea48418d049d7699853c3ae07b9e89e9f3ffb2befa1cad6c9b5390cbfd7dd8f3" + }, + { + "kind": "file", + "path": "img_2863.jpg", + "sha256": "07f0fbe0b55d6ef09f3008f875bc0baa7757adbbba503b51f0534965bc703265" + }, + { + "kind": "file", + "path": "img_352.jpg", + "sha256": "8fedc64c6957963d73ce9f2d22e7b4df1cc87ff3cd88c8cee91b11154307de54" + }, + { + "kind": "file", + "path": "img_2877.jpg", + "sha256": "1a1ee454adde87cf07aee2b707822967ebf05a1be92ca08c6d6cf2ae00b53e80" + }, + { + "kind": "file", + "path": "img_346.jpg", + "sha256": "68eb1fc25b928bf530b73cefaf8be2d2b5d363e7d873a2121cdb5937e8912dd5" + }, + { + "kind": "file", + "path": "img_420.jpg", + "sha256": "5e1c93930afd64da33b815623c2f172d8f66b8d81f40c7384b9deec5930fd39b" + }, + { + "kind": "file", + "path": "img_94.jpg", + "sha256": "425732a53ff11d320e8ab1f5572ef9b48fc60befc55b65f03fbbd4f21bf84be7" + }, + { + "kind": "file", + "path": "img_408.jpg", + "sha256": "cbe897f7aeaf2a5c8469537753d346876ae253ac3c480b03f4a344cfd07384b5" + }, + { + "kind": "file", + "path": "img_4590.jpg", + "sha256": "17821c3a1a2fbc0e979f8ab301352a9ea49ca533041cc159be61e0cb040c3bb5" + }, + { + "kind": "file", + "path": "img_2687.jpg", + "sha256": "29cc5229e89aa2228dc6dbc62ec9421573e2938756150431d480caca973ae20d" + }, + { + "kind": "file", + "path": "img_80.jpg", + "sha256": "ec2ee5fbd289643d97c81e10f315904741173ba88970ea4482c911512811b646" + }, + { + "kind": "file", + "path": "img_4584.jpg", + "sha256": "36bc5ba3410e0311da1195b7718cc4b4b0813c60fd861c8ba624f0b7a44c3d58" + }, + { + "kind": "file", + "path": "img_1417.jpg", + "sha256": "62dd3d7395358eaffcebee9ee71e7a4fb8311a5498a5f69c90b3039d1ef6ebcc" + }, + { + "kind": "file", + "path": "img_3200.jpg", + "sha256": "d69ac84a4c43b38f5ab912e6cbb395663ae21e2852afba1eee12b63545d96d30" + }, + { + "kind": "file", + "path": "img_2678.jpg", + "sha256": "f5777c7c7abf67353503e4460b33298c3f8feb8c72a8e53ac3f1697acecb958d" + }, + { + "kind": "file", + "path": "img_391.jpg", + "sha256": "3d03b4d283c15b40a4daacd6628674ffa42130ec906381e37b4528b20697533e" + }, + { + "kind": "file", + "path": "img_3566.jpg", + "sha256": "e3fdd2cc8cd6b017533dffe08bdf3ce2fdb4b669ec5be7537bfcea4320578b1e" + }, + { + "kind": "file", + "path": "img_1371.jpg", + "sha256": "414631f335ebc91c5811f65e3ea6ca4b099fea5d68e7140585dea4f897ce1237" + }, + { + "kind": "file", + "path": "img_1365.jpg", + "sha256": "50493608f21b8b8dc2cdf349a921c13db01db55b9dfadf8d57aa568f034ef06b" + }, + { + "kind": "file", + "path": "img_385.jpg", + "sha256": "2dc125e6246d8d89bddb560d509d48615e071397c281b05c4f2bfabaada24cdf" + }, + { + "kind": "file", + "path": "img_3214.jpg", + "sha256": "0773631f90bd41d020b588ee622f27327c39e676a99334b03aa2685d36339292" + }, + { + "kind": "file", + "path": "img_1403.jpg", + "sha256": "1aeefa37c26d60345984d33755e27c163c69b7db0886ae13e2875bd6cd9c4f69" + }, + { + "kind": "file", + "path": "img_4553.jpg", + "sha256": "7086568452216fcc7cfe78c29d75357af3516abd737ac24f7e663ab89e63cc79" + }, + { + "kind": "file", + "path": "img_57.jpg", + "sha256": "50e5a96e9da367fad278181079a2ed4860cdd7ea466893b893d9faa06faaa627" + }, + { + "kind": "file", + "path": "img_2122.jpg", + "sha256": "9aa8acf7d1471c5846ffddac41da83a7d5bf2a95d22591787430b4689a7ce464" + }, + { + "kind": "file", + "path": "img_4235.jpg", + "sha256": "e9f34722f6d9ff13efde8df79399ae18f1def3f02fe677ea1ca7b932c5315422" + }, + { + "kind": "file", + "path": "img_2888.jpg", + "sha256": "db58282b99c394dd9f3e8bc4e989016b1302905711b8808740aa6d3e9ba9a3a8" + }, + { + "kind": "file", + "path": "img_1359.jpg", + "sha256": "596ea356e7c75c5b6f18e113772897608a0d350c0fe2a147d88584b10931d119" + }, + { + "kind": "file", + "path": "img_3228.jpg", + "sha256": "c839c752966336225b8527b649671dd78e99879197d97f41dbbb6334acb771da" + }, + { + "kind": "file", + "path": "img_4547.jpg", + "sha256": "7383415f601c36a0cb636254c0ce1e864bbbebbcb7adf790663feda271991d3a" + }, + { + "kind": "file", + "path": "img_43.jpg", + "sha256": "d0bf24a8cd189a3b5625418777cd13f01af0e56319697018c9fce0b6913ef793" + }, + { + "kind": "file", + "path": "img_2136.jpg", + "sha256": "74cbb85c48df2363d88cc3180fce2d51932ac0e6f8d22525c059f71f370f8144" + }, + { + "kind": "file", + "path": "img_150.jpg", + "sha256": "9e238dd0c7427a6be5184f0180690bb612a8b50d9f1f8a6d8e37f46c835db112" + }, + { + "kind": "file", + "path": "img_636.jpg", + "sha256": "694c82c1f60c39837ed5eafe2e199ce8010ecc2a77e23135b0ae6b6b3bcb2e35" + }, + { + "kind": "file", + "path": "img_622.jpg", + "sha256": "57fe697117e69765bf7435b14940c144e9bc4e8fa2d361e4c1bfd87f25fc39fd" + }, + { + "kind": "file", + "path": "img_144.jpg", + "sha256": "45933aaf9710b3ea1fed28c3079f258586890e4a010bcecd20f9824b56bec6d7" + }, + { + "kind": "file", + "path": "img_2485.jpg", + "sha256": "d35f3d6187fe13e29be2d58f0c1054fdd1b7d4a48acdafdec945169c0e6396f4" + }, + { + "kind": "file", + "path": "img_4792.jpg", + "sha256": "a4f466f13255dbe40fe87de1733909f9738524144c1ca65bc7a4343ebb537e2d" + }, + { + "kind": "file", + "path": "img_1832.jpg", + "sha256": "3496d3d1e1bbfb55fc2758a6ae86075a111e1f7bb757b7e4d2260c0eaa926b0b" + }, + { + "kind": "file", + "path": "img_1826.jpg", + "sha256": "fef30a8f22440dff927837c7203223d0caadfa1307cc201f3092fcd3863376f3" + }, + { + "kind": "file", + "path": "img_4786.jpg", + "sha256": "f1719c36a69664456549fc63b3757dc8b66acb004e02ac2414280827d28a0e87" + }, + { + "kind": "file", + "path": "img_3957.jpg", + "sha256": "ef12e550eba53436604f908d304e493754f0259fd9036a22d4cc17fa764d7e13" + }, + { + "kind": "file", + "path": "img_2491.jpg", + "sha256": "3aa87e9da9d3275c10a6d5829b8394332d0c0e147b6844779d2b60a988d44483" + }, + { + "kind": "file", + "path": "img_178.jpg", + "sha256": "d95c0a052a954df71fa2f0a126246c7a526192a6c3c91d6b4dede1c46c4d1beb" + }, + { + "kind": "file", + "path": "img_1198.jpg", + "sha256": "6a101f40ec59d2316190d7a998c1a684ffb3007cf4a9d0dcd49c9778f880b123" + }, + { + "kind": "file", + "path": "img_1173.jpg", + "sha256": "a44b29bc3ac0f282c28ba690c6ed8c80e82ccf3b7a8172580e55c184d68363fe" + }, + { + "kind": "file", + "path": "img_3764.jpg", + "sha256": "1d3b90bea97fbcbc61adc47f7ae98f9e962832e182dfbe23f8b00d4f55a27df1" + }, + { + "kind": "file", + "path": "img_193.jpg", + "sha256": "5c3ce7176c438dd507d119ef80943f78eff3c59ef404291bfdbf4e15ceff74e2" + }, + { + "kind": "file", + "path": "img_3002.jpg", + "sha256": "654682325ea456a6181b9621f8b18208df93bead8c7f74427c13b333fd32d125" + }, + { + "kind": "file", + "path": "img_1615.jpg", + "sha256": "ac262fa6fe366c3fed9577562bbe1377ed35f56668f5938fa6b5adf6c67a7a39" + }, + { + "kind": "file", + "path": "img_1601.jpg", + "sha256": "eb9ce32b1caddbf5f8c71580586f2a7befae23ceee5fd30f8785968bc217cc96" + }, + { + "kind": "file", + "path": "img_839.jpg", + "sha256": "4334e8e5284f512a9b678f9e6ea00f7535c9a3e8124023ff5a68612d2ffafdc4" + }, + { + "kind": "file", + "path": "img_4779.jpg", + "sha256": "d875407fead94038bff0598affb5795ece009ae7a3827f81a2e9a966f6763882" + }, + { + "kind": "file", + "path": "img_3770.jpg", + "sha256": "566305ef97ac3bc902893c997d9d33a86ae1028a6afe174f6b9858e9d0641fe3" + }, + { + "kind": "file", + "path": "img_187.jpg", + "sha256": "e3439c0bcfb182b4fcf92c1f5ebc8aaca6ae7ae1ede0ef21de7fcc4429f0a59f" + }, + { + "kind": "file", + "path": "img_1167.jpg", + "sha256": "f027ef6f57628c7419f8ba9d458aa47b534e9774a0de87e6a87f62f0920867dc" + }, + { + "kind": "file", + "path": "img_3758.jpg", + "sha256": "2fb594a2ef7f344b54182732444c17deee7126c8e25cb9b2b482e677c1df66ac" + }, + { + "kind": "file", + "path": "img_4037.jpg", + "sha256": "2185c49d3b93c26b86eba4d74c4f6bfe56a7f0ec6f20da8aa6134faa53f9ea02" + }, + { + "kind": "file", + "path": "img_3980.jpg", + "sha256": "64355b503c5fa33e1ea9288304d06cdaf804614fdad789659f585eaf4507635e" + }, + { + "kind": "file", + "path": "img_2446.jpg", + "sha256": "7cc50302c25df9b62e09188a933eefa7e1d2b301de6bac4e521e0e5f3bba086e" + }, + { + "kind": "file", + "path": "img_2320.jpg", + "sha256": "09184d5d5effc689b08188fd93c841f3fb0d0aee69976d6be41d0d6dc1e62658" + }, + { + "kind": "file", + "path": "img_811.jpg", + "sha256": "caae35dd67bb7bb9a07a83124154b2f52798f061abb56285d078f9584c8bd13f" + }, + { + "kind": "file", + "path": "img_4751.jpg", + "sha256": "c5613bd0d43187967ceea60f0cce7e0f2df86167ddd4e605853503580f15b70b" + }, + { + "kind": "file", + "path": "img_2334.jpg", + "sha256": "e3a39d61412a529a01a69f1b3e5816b526fe288aac5a9178580b7c3e481704b0" + }, + { + "kind": "file", + "path": "img_805.jpg", + "sha256": "78148ce84bec847279ee32bf24a75474aee68a0d4f2369fc9527d5b904663890" + }, + { + "kind": "file", + "path": "img_4745.jpg", + "sha256": "3259d92afdb9b736ce0d9b17406e7fec149b8237abbbcfb19642879514949cef" + }, + { + "kind": "file", + "path": "img_4023.jpg", + "sha256": "dc2a8eccda6fef0d556faa6e8d70c07b88c0cc5f57047b1f3510833235bd94d0" + }, + { + "kind": "file", + "path": "img_3994.jpg", + "sha256": "913f152a8a37b6a7f7aa0559216f312ded9a27edd4fcff5fe91a8ab91f8560f3" + }, + { + "kind": "file", + "path": "img_2452.jpg", + "sha256": "3120350adf552ba670d3b8ff196208bcc2b41aff0893e2905910d22a0bf4d437" + }, + { + "kind": "file", + "path": "img_4802.jpg", + "sha256": "a53ad51eeb7b2bd1455e356532dad5bfce2f36e6cac7afdd0e3aed3a712e8022" + }, + { + "kind": "file", + "path": "img_742.jpg", + "sha256": "2f267ea82b0593b8627bd745a743a56d5972966394dd36d551d4bb819e33cb34" + }, + { + "kind": "file", + "path": "img_756.jpg", + "sha256": "886700d1335e65e12941f78b646d03b5d0e534b1a91c02cfb52fac499537e2f8" + }, + { + "kind": "file", + "path": "img_4180.jpg", + "sha256": "8f668662478e63cf63705a44d4a0688abf9c490f5f89e713c5ee9f6723830694" + }, + { + "kind": "file", + "path": "img_3837.jpg", + "sha256": "9ed670bde06da40b69207c49d2fa5026a079558e713bfcc731ff852ee36ee0a1" + }, + { + "kind": "file", + "path": "img_2297.jpg", + "sha256": "cd0fc203fbd0855afcff91eeb31ff7c5e4e78ded0952cb4210a0efc241b54b16" + }, + { + "kind": "file", + "path": "img_1946.jpg", + "sha256": "90c317303d763bcc3fa49212d5cfa95cb55dbe1ad064cb0d98e7594b8b5d9a0a" + }, + { + "kind": "file", + "path": "img_1952.jpg", + "sha256": "6298a33d1774aa66581812d82243b526a77f7eee90499402f55fbd7f782c84b4" + }, + { + "kind": "file", + "path": "img_2283.jpg", + "sha256": "dcf1bd3ce4bc8f46c3a215337c79da3c28899efd26c1c48f8cadde9f30098a99" + }, + { + "kind": "file", + "path": "img_3823.jpg", + "sha256": "8f34b69670fc5dfb1ba6700e75652a6249b1745f225b18fe7f8e65eb7b5f8596" + }, + { + "kind": "file", + "path": "img_3610.jpg", + "sha256": "caa3d7080cae8f06ef2bf94d171698a87ad7bbbc7bc413c432fe95627856a8c0" + }, + { + "kind": "file", + "path": "img_3176.jpg", + "sha256": "830f3d031dc6255aa629268330ab786059f8f8e7140b808cc16a69ba6812d21d" + }, + { + "kind": "file", + "path": "img_781.jpg", + "sha256": "00367a71fc3f6543f2281049880e2f3f72078d50cd21e25e54767d6a35376a11" + }, + { + "kind": "file", + "path": "img_959.jpg", + "sha256": "034c89bbe61468a0d32d36197feb7c6e3bc3092775afa2308da1c8f2d6a81522" + }, + { + "kind": "file", + "path": "img_2268.jpg", + "sha256": "50dc097cc13194376b424260bddfd28862439fafd78323c90298fb92f22ef5c2" + }, + { + "kind": "file", + "path": "img_1775.jpg", + "sha256": "6817b46900d40218e3571486841a46fcdaa1be826bdfe7a9b18d7c06ba6dc2df" + }, + { + "kind": "file", + "path": "img_3162.jpg", + "sha256": "5cfe19e0d7ce2287dae58d8fa2f0efec07fe36a1477744be87938ac8d8e89e9a" + }, + { + "kind": "file", + "path": "img_795.jpg", + "sha256": "d3770942ff07bb1d6fe8008791ec49ac2ab47a9ca7e84134750314d73da3d979" + }, + { + "kind": "file", + "path": "img_3604.jpg", + "sha256": "cff47ef1d8b32776a44768a76cc57145a39c0b09b314060515ac95bf4804fd6c" + }, + { + "kind": "file", + "path": "img_2532.jpg", + "sha256": "d9069b20b4ef7e7f867fda90b932898abbafc581240ad489fee08acc3c113726" + }, + { + "kind": "file", + "path": "img_4143.jpg", + "sha256": "23ac8cc844cbb51d71b0b7602765a878c5344931eefdb52a704ec06acb9ab130" + }, + { + "kind": "file", + "path": "img_1985.jpg", + "sha256": "463f1128d6a4a3f16401acb2f841db1315df4ecfc0f062052a0452e2cada2d1e" + }, + { + "kind": "file", + "path": "img_4625.jpg", + "sha256": "f71e8d27cef735bf745fc57343fa1b4898730f6a7c18f40dd7de1d5f7e7af28f" + }, + { + "kind": "file", + "path": "img_965.jpg", + "sha256": "356ea180f5a3ed2e0d236ac9b76130f186ab972b1b3eb583e4305b3875010327" + }, + { + "kind": "file", + "path": "img_2254.jpg", + "sha256": "fadee563ac51472d21ac64c1edf3ecbea772afc11f38d01aa58e204f359fa3bd" + }, + { + "kind": "file", + "path": "img_4631.jpg", + "sha256": "c6ef2b9c7cb2f85ea5600ad3e378514bb7225b8013b8b508665597e01d993235" + }, + { + "kind": "file", + "path": "img_971.jpg", + "sha256": "b70a01c07627384374f94943a92cf5a37425309ee0c8e434edca039dbaee0c39" + }, + { + "kind": "file", + "path": "img_2240.jpg", + "sha256": "4f29551b7da09600537801b3a414dfe6f2af9025c4e8e2818bd9357201a7c3e4" + }, + { + "kind": "file", + "path": "img_1749.jpg", + "sha256": "c2f664c601b2e3126cc73034b1041c5fe2f48813185481941c20e4cb152c0c1f" + }, + { + "kind": "file", + "path": "img_1991.jpg", + "sha256": "df75f251c9039dd3c5402f9465ab900ace5afc6ecf2cc50d66707c8fe5607e42" + }, + { + "kind": "file", + "path": "img_2526.jpg", + "sha256": "f20bb17fe857bc6fdce7d1a70ea5aaee015c77bfe4f960e59582be64b3d0bb4f" + }, + { + "kind": "file", + "path": "img_3638.jpg", + "sha256": "924d78960c56f0e544ecbd727cdfcbbbfa9b344f5b21e2f487feec90f45250d9" + }, + { + "kind": "file", + "path": "img_540.jpg", + "sha256": "eefcc5868eca41f716b60412f9e06f39838fa94d83e0b21fed0d44458c6b2230" + }, + { + "kind": "file", + "path": "img_226.jpg", + "sha256": "8084e96bd9fc9f328133380d2d24c5e88263d30ca37237d4ed46e8afd915df2b" + }, + { + "kind": "file", + "path": "img_232.jpg", + "sha256": "4797f692184d592426d966701c09df8e987e98832594b7b8f59c12ce385b2172" + }, + { + "kind": "file", + "path": "img_554.jpg", + "sha256": "ea2db77418a2d7d31d340aa3f403716942eebbf8ff79c5ab2b0f89afc4a9486b" + }, + { + "kind": "file", + "path": "img_2095.jpg", + "sha256": "fa80c1479b4aeb532f4d18ce952b883501f637191cd6ff64458c8d32e0593d3a" + }, + { + "kind": "file", + "path": "img_4382.jpg", + "sha256": "c1e0f7936d061630783eb30ce4e165e6f9373518e5c106b0121cac4dfdcbdd1e" + }, + { + "kind": "file", + "path": "img_4396.jpg", + "sha256": "5b87dac18a829f905791b7519d45e6960173a6e6dc3ed8cbf6d137d44cbc8b5e" + }, + { + "kind": "file", + "path": "img_568.jpg", + "sha256": "b44b987735dc92aab6cc8f8683a738b0ce625d598f20aa6b92c89a0c69ef5e78" + }, + { + "kind": "file", + "path": "img_2081.jpg", + "sha256": "57143e1e19968b9a3299257b3dbf6111ac8dd7fd2da16bb8c3b3e88caa1d0dd2" + }, + { + "kind": "file", + "path": "img_1588.jpg", + "sha256": "70b3d9b3670dc1a1f2d6fcbad26c3fca94300afd40a4750ffe7c94b787ea77f0" + }, + { + "kind": "file", + "path": "img_1563.jpg", + "sha256": "ea8dd0dc98cea073bb06a51eee902354693a2c05d3d24be32173d15eebd9fb90" + }, + { + "kind": "file", + "path": "img_583.jpg", + "sha256": "0ebbc71034708e5d5569642330d1e1b71679aeb5c7d42c444296bc125d93b821" + }, + { + "kind": "file", + "path": "img_3374.jpg", + "sha256": "2c68208f6d8b927db6b71da61bfd64386f3ea58f99aa217717f78c7ec0461aef" + }, + { + "kind": "file", + "path": "img_3412.jpg", + "sha256": "bd2b7b88519f19368b73caaff3f05e7be30bf3ffc437278921b3b8cf2d55b553" + }, + { + "kind": "file", + "path": "img_1205.jpg", + "sha256": "aadefad354d48b5ac5fa3cf62212dfc51034416cae037c949eb12e2732ccbc41" + }, + { + "kind": "file", + "path": "img_3406.jpg", + "sha256": "24f9572efa5e12da0073c011aac153586b869e69ce8b51d8094575597a2d98b3" + }, + { + "kind": "file", + "path": "img_597.jpg", + "sha256": "8c2637ddce881c152074ed3a2e3277dd44a8361238ec878f73883dcca6cdeaf4" + }, + { + "kind": "file", + "path": "img_3360.jpg", + "sha256": "8127f700d1d7fbe95b19e9e3df24a5e796ca69ff92b5cb33e63b3a652d013265" + }, + { + "kind": "file", + "path": "img_2056.jpg", + "sha256": "da7a0508699ca3881b43d9e64299ae0c234e6d8859a662c299cd80b8185b652b" + }, + { + "kind": "file", + "path": "img_4427.jpg", + "sha256": "45af00d376c32cf277c402578975decd76dbd78431d83f487dcab8bb42f680a2" + }, + { + "kind": "file", + "path": "img_3348.jpg", + "sha256": "507aaf40b96d3e5bf9a9d7a36fccbda70d7f77e695d02153bde5990f49b375d7" + }, + { + "kind": "file", + "path": "img_1239.jpg", + "sha256": "da11008e4340c91468616326ceff92cc3a1dddf67c5704f878032ea8ee2c2601" + }, + { + "kind": "file", + "path": "img_4341.jpg", + "sha256": "93cc52a4d8032def54a53e97d702e77efaf03ebd361535d98d4c04018a22ea17" + }, + { + "kind": "file", + "path": "img_2730.jpg", + "sha256": "2845e035025f998c07ebe692e300bf06d4e75047fa065074e8fb1bcb3c563af8" + }, + { + "kind": "file", + "path": "img_4433.jpg", + "sha256": "b8417e68bc50d6558115bbc29767f83d9ef356d6296b3ad1c485587ec2f24b8e" + }, + { + "kind": "file", + "path": "img_2725.jpg", + "sha256": "20f1338ace5e65329bf72d9723aca4ddefa479f5ffccbd6d86071b2a323e4fec" + }, + { + "kind": "file", + "path": "img_4354.jpg", + "sha256": "cc76e8295ed2830283f26bfb816d1ee7822bff915a1479b600147c3b8403438b" + }, + { + "kind": "file", + "path": "img_4432.jpg", + "sha256": "e330913a19678878e40050c04d6c309205506bc9175b69145d1ae1f7ac6eaa28" + }, + { + "kind": "file", + "path": "img_2043.jpg", + "sha256": "d5e72852ab9e93a836bda8e4c2bb74f612a0eb349d6abfdf08fb81f90c6d6c59" + }, + { + "kind": "file", + "path": "img_3349.jpg", + "sha256": "4784efe6a2a9369361e066e1b986c32b76d298fa3fe68e7c87ca600f67ef0c54" + }, + { + "kind": "file", + "path": "img_4426.jpg", + "sha256": "d4d9695c6c42150263a6e8563f22347b0cacd3598a1ba8d358813369ae2f48bb" + }, + { + "kind": "file", + "path": "img_2057.jpg", + "sha256": "0f62c8dc5245c9f894fda3a922d5e3498a5bca3fb478a5ef7027c3856445177c" + }, + { + "kind": "file", + "path": "img_2731.jpg", + "sha256": "7713066b579774b092e1ea04c7253f8e480d15b1da717bfd565338606a56caee" + }, + { + "kind": "file", + "path": "img_4340.jpg", + "sha256": "7db6aabc10a8a55bd3ec54fb8a77dcbd43f67e880368a8546a812b6b10b12489" + }, + { + "kind": "file", + "path": "img_1238.jpg", + "sha256": "a01e83cf8edd528fb5c41c4281acbc8a68631c36fdd46825501974f32743ee7b" + }, + { + "kind": "file", + "path": "img_2719.jpg", + "sha256": "09338cdf197b3d32b686ba388140bbebcf71571a38c21bbd3641dc9e5422e1ca" + }, + { + "kind": "file", + "path": "img_4368.jpg", + "sha256": "e5d42b6939464cdb2fb285a1b1760da29aab0a765abc6505a4a9dc70b19f30e8" + }, + { + "kind": "file", + "path": "img_1576.jpg", + "sha256": "0fc745b0a3bd4ad52f2057e9fc643586e3d8d3af07da2cccef9d546da059b484" + }, + { + "kind": "file", + "path": "img_3361.jpg", + "sha256": "cef733743f89197b2d981432118984b5c5f52dda30739e19371a7201b4d90ea4" + }, + { + "kind": "file", + "path": "img_596.jpg", + "sha256": "06bee582c9daa20758efea7a22e4444a470346df45831db80343205488a905c4" + }, + { + "kind": "file", + "path": "img_3375.jpg", + "sha256": "e48d75c4cb0811dc8967254923f82a70faa90fe86f840465a5598f6d041b647c" + }, + { + "kind": "file", + "path": "img_582.jpg", + "sha256": "0c9a594ca0da7231fedcfad6f49c985797920f765e36c322380ea4873dd29afe" + }, + { + "kind": "file", + "path": "img_1562.jpg", + "sha256": "4376aea8ed8fb9d580fd3c4d2305840aa9cde6da80c8c6bfd7b786ffccf069df" + }, + { + "kind": "file", + "path": "img_1204.jpg", + "sha256": "26d76b390d0667db994404f030d03c22aed779da4e3844415d172b32b469a32e" + }, + { + "kind": "file", + "path": "img_3413.jpg", + "sha256": "266f3c061a8acae93c023707bee62e57d651bdcdffb9a2fda6982fd8016fe177" + }, + { + "kind": "file", + "path": "img_4397.jpg", + "sha256": "00c8d697fdb2ee230f675286c9b59f4f42921bc7118b2e2a057c0b58b40400cc" + }, + { + "kind": "file", + "path": "img_1589.jpg", + "sha256": "0615413dfbb34a919aea40401c74c599db967d5ee825e6929f59719ce80006e2" + }, + { + "kind": "file", + "path": "img_2080.jpg", + "sha256": "9c19bcfc38b0a5af9445e20c4fe6eea79d3aac2798749c682c780fb72a0f2d9d" + }, + { + "kind": "file", + "path": "img_569.jpg", + "sha256": "eaafa2583aedb9d0aec256c5fff52444759ffd25fef1bdd6743e7c1e4bd3474f" + }, + { + "kind": "file", + "path": "img_2902.jpg", + "sha256": "8a0639d0455575d38c5f83355c6a559d6befb36c33aacf58e3b3bc93ade68400" + }, + { + "kind": "file", + "path": "img_541.jpg", + "sha256": "15658296f5d0fae2c30a7b9096d4bef077eaec0e39f28a817577496e53ced170" + }, + { + "kind": "file", + "path": "img_2916.jpg", + "sha256": "1cc2f5168cb89cccaa3f5c7f4c46b4a87eccabaa6a14392dbf6028c96476a623" + }, + { + "kind": "file", + "path": "img_227.jpg", + "sha256": "c8f5f7599e7038ba498788c9b431b55bd07f2ebe1f147e9e5088e21b9342713e" + }, + { + "kind": "file", + "path": "img_1990.jpg", + "sha256": "905eb0ae1f7002f6cf6f77b3777bd2c7b4caaabc56e1ef76ebae5d5a443bf8e4" + }, + { + "kind": "file", + "path": "img_970.jpg", + "sha256": "9dc2d3b62fb0ae361ad8e9e7bebf63d77b1770cfd144bc452362278f2ab4e0a9" + }, + { + "kind": "file", + "path": "img_4630.jpg", + "sha256": "5d66ac955c8bb14976f4204cef749a8c32146559fc9f83b4363dd36082b52688" + }, + { + "kind": "file", + "path": "img_3639.jpg", + "sha256": "e66593456f79aff3c1908ba77babed101139b8c0b0f821332ed1f44d8d94e554" + }, + { + "kind": "file", + "path": "img_4156.jpg", + "sha256": "fd83f3e237f03e2c2c73186a63afbd1caba8686bbc21998452437326831e8daf" + }, + { + "kind": "file", + "path": "img_2527.jpg", + "sha256": "eebf1c462619fdeb9cbdb1677566b51492638ae9ec1896c84a672217e217d834" + }, + { + "kind": "file", + "path": "img_4142.jpg", + "sha256": "e3c5c348105dbd50bd198594f1c800009c8e9b095aba3327acbe20d270d2f46d" + }, + { + "kind": "file", + "path": "img_2533.jpg", + "sha256": "9fbe50de2ad803fe07b892d72b919aaf47a77f07ff8df6be158940104ff1bec4" + }, + { + "kind": "file", + "path": "img_2255.jpg", + "sha256": "4e6b80c16ad762207ede88f85e079255ca2f4e539a726dd7de0966eae7670a6a" + }, + { + "kind": "file", + "path": "img_4624.jpg", + "sha256": "ba077c8cd8bf1dd58612363f12c5bbf7c2c76bae507bf01dcda9b933a758ca49" + }, + { + "kind": "file", + "path": "img_1984.jpg", + "sha256": "2d13b7dcf5791432f904b9bbcec055b714350056863cf69e3ef2c09275212202" + }, + { + "kind": "file", + "path": "img_794.jpg", + "sha256": "3f4890b965aee3e331728fb2acc6b0c948814e875d96054f1027673ed627ac38" + }, + { + "kind": "file", + "path": "img_3163.jpg", + "sha256": "e1fa4396b437ff669513e7d6253a649380980ca1f3b06100adc306f979043e01" + }, + { + "kind": "file", + "path": "img_1774.jpg", + "sha256": "0ad14b4de5dc34363e004ff2a7d92dc272726b45d8e56104d477da1246109eeb" + }, + { + "kind": "file", + "path": "img_1012.jpg", + "sha256": "9432fbf58ae9176707bfe39d308a61de4cad09a62b0542e748905005632b83c4" + }, + { + "kind": "file", + "path": "img_3605.jpg", + "sha256": "5804de890f95a4b9e799dbba6f28c48ffe1ac2c5134b78751b81986aa11fd119" + }, + { + "kind": "file", + "path": "img_3611.jpg", + "sha256": "ca5b65ed9d9b00060e8418317693de9a8ad02e4396b71f011ae28a935420183e" + }, + { + "kind": "file", + "path": "img_1006.jpg", + "sha256": "ae69f7459ce4519462e6a864e4002cc8bce9215bbfdd341fdd42462b19edd279" + }, + { + "kind": "file", + "path": "img_2269.jpg", + "sha256": "d7af39e0ce815358f8b89d81136f7adbdd70378f5cfae3780ea776547741fc8e" + }, + { + "kind": "file", + "path": "img_958.jpg", + "sha256": "92ab94820508f4b6c8ca464c18db9c9df1af9b5df695a547e9ac37f33bb612ad" + }, + { + "kind": "file", + "path": "img_4618.jpg", + "sha256": "c04be3f695e8a25d47e2ec227f669226e871153e8ad1d3d16fbe3fcb73f5b006" + }, + { + "kind": "file", + "path": "img_780.jpg", + "sha256": "536665cad8d0cec39daa820595087ca8a1dc5fefc8478b1b2aacc99068b42429" + }, + { + "kind": "file", + "path": "img_3177.jpg", + "sha256": "b6be9124b6767696a813f2de99955063dc946c03ecb05636b5f92996eefde32a" + }, + { + "kind": "file", + "path": "img_2282.jpg", + "sha256": "5f029b35c9a56ecfb007a5188bf17c8d58fd11606974e57815cab38e21af7362" + }, + { + "kind": "file", + "path": "img_1953.jpg", + "sha256": "d88113f6e65e69f968505298c47a215ec6c4566754f8b800f9552478155eb4a1" + }, + { + "kind": "file", + "path": "img_3822.jpg", + "sha256": "498b9459c9e90ed83f1c31477ef12a0c34e245ec382f360bb956f28f373222f0" + }, + { + "kind": "file", + "path": "img_4195.jpg", + "sha256": "c5f65e78d6ce6d836f40a7f1206caafc7b67f491d13c1cc94015c6392a5f7eeb" + }, + { + "kind": "file", + "path": "img_3836.jpg", + "sha256": "a7c27e7a5f2c0772a1991946bc254843d09c331c85fafbc5c4f1e6b58228a307" + }, + { + "kind": "file", + "path": "img_4181.jpg", + "sha256": "0cebbdac4dbbf785d691b8fefd4b59eb75bef4c2bda37aa7e35232ee7e888ed8" + }, + { + "kind": "file", + "path": "img_2296.jpg", + "sha256": "600c4a917e0fac4ff0c4750fddb4b97ce18f17d84bbfa23b2ef1adfb05d5d7d7" + }, + { + "kind": "file", + "path": "img_757.jpg", + "sha256": "70652da4a19584a263e550a9d8d3273f50b8788904aa0cfa9f59d12dc5048c54" + }, + { + "kind": "file", + "path": "img_4817.jpg", + "sha256": "1faf15c8ba264131bb4146a20f9b57d0021fea028d29274f72cadcc2aae204e1" + }, + { + "kind": "file", + "path": "img_743.jpg", + "sha256": "b834676f1895010a0deefee636ba94f1142acdd6aed65511ee4d1393a6897fb2" + }, + { + "kind": "file", + "path": "img_4803.jpg", + "sha256": "9c37d8f614f41c11944bbace81d9c86c99cd590486d64489fb541c59a612a71b" + }, + { + "kind": "file", + "path": "img_4744.jpg", + "sha256": "4d5293510993802df403486fff5d3e2588b8e468e592b84935c55c5cdee1301c" + }, + { + "kind": "file", + "path": "img_804.jpg", + "sha256": "57d48e49d65aa9dc9ec49f37cdb0e7c15e1d920f94cf99823c2e9029aa61d418" + }, + { + "kind": "file", + "path": "img_2335.jpg", + "sha256": "92c17496721dc1520ab6ce1c06e768e08ff4e3b0d6e94cbfd842063ab7b2f386" + }, + { + "kind": "file", + "path": "img_2453.jpg", + "sha256": "676ee072da912ceee4360fb93e0a28a5318c33c4f8ff4cb4f7a5679281dc05c8" + }, + { + "kind": "file", + "path": "img_3995.jpg", + "sha256": "e43e7fa759baeffb5f2eae07ac113f8a24888d289ab4d91e1f6a28b276bddd62" + }, + { + "kind": "file", + "path": "img_4022.jpg", + "sha256": "b56f7ba9eb432183149c4c92f4e0b7cf42a2a79dda49b441388546820d2c4b8d" + }, + { + "kind": "file", + "path": "img_2447.jpg", + "sha256": "abb83def8f5955625960b05c290e3dfe4a7b3fa4544d44b61d599c0cd48b77d0" + }, + { + "kind": "file", + "path": "img_3981.jpg", + "sha256": "2aefdbae3ae84d7496aa494e02d443f7d0b0257084aaaa486833738335959640" + }, + { + "kind": "file", + "path": "img_3759.jpg", + "sha256": "7d871a2b777b7fea7a2c4b95ecfd4da5aa8ac1b2a4eea25e4c597999cf67ea0b" + }, + { + "kind": "file", + "path": "img_4750.jpg", + "sha256": "89a4fdb39553dbc2660fb394a577e4be674e153f562753445a388f508f4c6b6a" + }, + { + "kind": "file", + "path": "img_810.jpg", + "sha256": "ea90f11fb831bdc8d132fff40052260f06e68771cc147cac4caf5ad3aca9892b" + }, + { + "kind": "file", + "path": "img_2321.jpg", + "sha256": "4f27315235acd48719abde2c6c75b4d6e2afed3e363d065e39344b8cf878caeb" + }, + { + "kind": "file", + "path": "img_1628.jpg", + "sha256": "d2abd5ee7dcfba3fcd33cfa35565319228a23b04fb0f3b2e4e1dbb9600844927" + }, + { + "kind": "file", + "path": "img_3017.jpg", + "sha256": "6feb535d393ca82ab808b01f17cca9d5054650205e60b11f37cf860521f515dc" + }, + { + "kind": "file", + "path": "img_4778.jpg", + "sha256": "8503b804e2f14e3190cdb0a0afff5e92f285d599d659fb4825c465bdae8b530d" + }, + { + "kind": "file", + "path": "img_838.jpg", + "sha256": "28db5ad8ae35ec15bd5d0cf171096854e33d533bfd4c926577d977be1474a1ea" + }, + { + "kind": "file", + "path": "img_2309.jpg", + "sha256": "9f35f3fcd55bfcbdbd46ba70ffc1d11e495a0755f9ed49f7417ada10e8a5610f" + }, + { + "kind": "file", + "path": "img_1600.jpg", + "sha256": "f1cdad2e329c09097ddfba7fcdabcdfaaacb67d34ac4ae766fdb347dc72a0289" + }, + { + "kind": "file", + "path": "img_1166.jpg", + "sha256": "f9864b0ed0cb808fbfa86b005fbf6771ccc8466feff9df50242f40f950834900" + }, + { + "kind": "file", + "path": "img_186.jpg", + "sha256": "0542dec689fe6997781d0a9686e6325410435056af93ca1d8274cefe1a9218e4" + }, + { + "kind": "file", + "path": "img_3771.jpg", + "sha256": "cf3d8d5b38cc6ff1124d021b4dec240cef0ef180cec3cb35187e4b80d827f78f" + }, + { + "kind": "file", + "path": "img_192.jpg", + "sha256": "45498c1001f8d351f266627e01ff6987c58142c1bf4cea738c9577220f8c97ab" + }, + { + "kind": "file", + "path": "img_3765.jpg", + "sha256": "01303450d733f58d591de159905032436deb7181c7189431e2510c74ef6c37ca" + }, + { + "kind": "file", + "path": "img_1172.jpg", + "sha256": "69d95c947f12db5f200fe45a8ac54ccc69f3be49bad78c9cc5c9176948333aaa" + }, + { + "kind": "file", + "path": "img_3003.jpg", + "sha256": "086f69c320f17e846a10826a208995af69e49c0d38b5771cc60783419627e0c7" + }, + { + "kind": "file", + "path": "img_4787.jpg", + "sha256": "1adc39204bdaa21752c49331d411b588d62aae6b5e5d7457f115372cbabd8df4" + }, + { + "kind": "file", + "path": "img_1827.jpg", + "sha256": "7948ce44a61cf6d82bbef18236ab675f11fe7514872e094eedd6539533858b3c" + }, + { + "kind": "file", + "path": "img_1199.jpg", + "sha256": "d86df72c1cff36315f27622b8c8dfe216c8b5ef4b68892d097bd39c2a1926ca4" + }, + { + "kind": "file", + "path": "img_2484.jpg", + "sha256": "f9546a7de164b43a9aada9c621c12a1a7e16e183605cebf2b093ceb4c9855af4" + }, + { + "kind": "file", + "path": "img_3942.jpg", + "sha256": "ea1a304a60f5be45028aab47781398d073d7184e2aed42c0ea6a2ae97b7b4dfb" + }, + { + "kind": "file", + "path": "img_1833.jpg", + "sha256": "f97d0210d1bfc865cff328ae8ddab2ee31cd1d60546bac1f5566e47260912451" + }, + { + "kind": "file", + "path": "img_4793.jpg", + "sha256": "7861bcbdf9669c70a1acf381d942b82fbf2628180802aa92a5125f7c393d64ed" + }, + { + "kind": "file", + "path": "img_623.jpg", + "sha256": "99d1f3cfcd9cfc8f43e086271576fdb308201ff32a917389bcf953bf1ed23378" + }, + { + "kind": "file", + "path": "img_145.jpg", + "sha256": "46830d49e11e91781490ffdc35318519ad21df7e6140283edbfadfb9567a5689" + }, + { + "kind": "file", + "path": "img_151.jpg", + "sha256": "46cd8176f6d5b402099ba82a67a56279c0077e6457f3748b279a73c248102596" + }, + { + "kind": "file", + "path": "img_637.jpg", + "sha256": "b999f84a3f18f241b2a780137301e32c3c34088f56866079c56ee0be0186c528" + }, + { + "kind": "file", + "path": "img_1358.jpg", + "sha256": "be50a32041fe4dd2e876e00455916c7ef7a7e08d0061ba3fb11645f76e36874e" + }, + { + "kind": "file", + "path": "img_4220.jpg", + "sha256": "6e05d64101ff2b3ac5b6994ecca2608309de4e1ad935113f32f2764901977e0f" + }, + { + "kind": "file", + "path": "img_2889.jpg", + "sha256": "3836de063992051bdb227603a7d06d348860722a7d3cd3af3205a0290bac9a92" + }, + { + "kind": "file", + "path": "img_2651.jpg", + "sha256": "79fe0b4a0db07bc7f21fa8c643e15c9af6c716c09636ab892d2ae88de6ae4306" + }, + { + "kind": "file", + "path": "img_2137.jpg", + "sha256": "a21bb30660c5aeb759888f85516ab764830c73dc9709eec78a8eda88f8019f34" + }, + { + "kind": "file", + "path": "img_42.jpg", + "sha256": "ae4fde31e0f630072b4ccfb79761677f5a62ffe2cfa172df0175242dd373947e" + }, + { + "kind": "file", + "path": "img_4546.jpg", + "sha256": "c3498f5138d0bcf752f752550db37ce90c1074c33d990d24314a662effeeb9e1" + }, + { + "kind": "file", + "path": "img_3229.jpg", + "sha256": "4701c28fec61023c13254ea5eee373b7149dfefd246fa9158feb6877317c47df" + }, + { + "kind": "file", + "path": "img_2123.jpg", + "sha256": "c080c5218a7f38713af80dfb3647e40baaa0e51f34ac02a523a55cee5b0ad940" + }, + { + "kind": "file", + "path": "img_4552.jpg", + "sha256": "5d572f4d441fc8b7b7f141f0caf30883a30bb2f3ad37a3580b0489e83003106d" + }, + { + "kind": "file", + "path": "img_4234.jpg", + "sha256": "3248f3dba981ea24b5ea4c5852915c8a44003c27f27e49beed03a6009ddbefc0" + }, + { + "kind": "file", + "path": "img_2645.jpg", + "sha256": "3a53f18f68f8aabfb46d5122a57bc39a760676ba5e51705d0d7f3f7bd2ab555a" + }, + { + "kind": "file", + "path": "img_3573.jpg", + "sha256": "55334b48e010339f22fcf50c4ea6e997bc196de2a5c61e99f2fa21168e01311a" + }, + { + "kind": "file", + "path": "img_1364.jpg", + "sha256": "7fcf6ed4f50ffdf234369ce3f4468abf562c091c29ea1c7db023cb33605d2fe2" + }, + { + "kind": "file", + "path": "img_1402.jpg", + "sha256": "1e8168307c130f942ee5ea091e57506cf99bbea4a94436352dd31296dd18be20" + }, + { + "kind": "file", + "path": "img_3215.jpg", + "sha256": "226c3c1d30d7cdfc320a589e13c9d7b14a0ad79fa5155f5e424e41200f4afea6" + }, + { + "kind": "file", + "path": "img_3201.jpg", + "sha256": "29a93e67c0efa0568c1a063e06965092634ac1eb0ff5c6380894f704ea207287" + }, + { + "kind": "file", + "path": "img_1416.jpg", + "sha256": "aae0912677a11ff3be182914a2ae116475b39a35fc600e76ef8ec02af6bd4de8" + }, + { + "kind": "file", + "path": "img_3567.jpg", + "sha256": "c6e108be0cf7fef22397b11f296a8d5cef0b8a674f09fd58246d2d0229a4390f" + }, + { + "kind": "file", + "path": "img_390.jpg", + "sha256": "b10fbc62a35236b7c1a04c0ba9e85c69676e0a0ffef9f7ad5870f6ef3273f1eb" + }, + { + "kind": "file", + "path": "img_4208.jpg", + "sha256": "ce385223d41d533e9fe889dde44ec94bccf43f052f5d47f7aed5e4bd5844f48d" + }, + { + "kind": "file", + "path": "img_2679.jpg", + "sha256": "e6b7f17e3a9c888c36f2cb275336e8dc4c0dbdab9a3d92dfe752674ce46ac188" + }, + { + "kind": "file", + "path": "img_4585.jpg", + "sha256": "e0f328a1ef53a57982bd193040d2e39199e3f65b0ad8e98d61dc41de54cf6608" + }, + { + "kind": "file", + "path": "img_81.jpg", + "sha256": "d8710aa50e0564403d6d145f9e9257fcf69601fa887cd6debb587ced7a13644e" + }, + { + "kind": "file", + "path": "img_4591.jpg", + "sha256": "b8b6b30437e27e9314a4a0741195010093d73ceb691f0e4c456b0cfc2f1fa488" + }, + { + "kind": "file", + "path": "img_409.jpg", + "sha256": "e3bcca833ac7575c5f94e0afbb7065ed7b08a1431c23dc4b7b464fb7556af7b8" + }, + { + "kind": "file", + "path": "img_95.jpg", + "sha256": "2c000a8963e1e5c72962d1f0b98a62c395f0c8fd2fc4398b2df451a259580ec2" + }, + { + "kind": "file", + "path": "img_2686.jpg", + "sha256": "cc59b275e843ff23ee09635a05ff01c51db711c814fde3700dd15e092370ee19" + }, + { + "kind": "file", + "path": "img_3598.jpg", + "sha256": "e8a9e751d5be52e723b4943e22ea74870e5abe7ff39e1c8cb394007ce0c699d3" + }, + { + "kind": "file", + "path": "img_2876.jpg", + "sha256": "de6e001cd57f90eb2ffb310615cd2ed6e78f595c520260cd93be5ceaf074867a" + }, + { + "kind": "file", + "path": "img_421.jpg", + "sha256": "a26a8babc99f22cce9a7a560f06dd3627f05d52b98f7dbfada0b058e2d8d2f4e" + }, + { + "kind": "file", + "path": "img_435.jpg", + "sha256": "bc1d76bedd966d391fec7ca077e7057784f94735dd8059528f7e836f5fb72828" + }, + { + "kind": "file", + "path": "img_2862.jpg", + "sha256": "46b78b80f5a4630ce0818af5feb9f7b041ba70b5b2ab9a0b7ef4cc1b35eaa742" + }, + { + "kind": "file", + "path": "img_3299.jpg", + "sha256": "a37b1f7391dabc291c2d76685997d64a4e859d2382b254a11d87eb482cf70fc4" + }, + { + "kind": "file", + "path": "img_308.jpg", + "sha256": "974e11b8edfbcfe28dc6f2b13f28705fa6216bae2faf31c902eaa729ec3380be" + }, + { + "kind": "file", + "path": "img_4290.jpg", + "sha256": "8857721b7586c8202b59f06228013bc1c37004e3dcd34cabf74aeda6d4cd8903" + }, + { + "kind": "file", + "path": "img_2839.jpg", + "sha256": "ee083d8f4d704471a3c1f428fd9c1e3f46c20671ae97e9c63b05f67ba6fa5721" + }, + { + "kind": "file", + "path": "img_4284.jpg", + "sha256": "4ce3c54a9a2bcc9eb2eb637ddcbfc64a82f569e8c2dcc8d37284eee2a5ca0b11" + }, + { + "kind": "file", + "path": "img_2193.jpg", + "sha256": "ce72cac6a1fdb68d3419e18f66f8e0c95c473a50d107711a30e220d972ae1dfb" + }, + { + "kind": "file", + "path": "img_334.jpg", + "sha256": "947bc6765b7d209a7b5bbbd5470b3f6ee2008b73b13335e8dcddf852093a6dde" + }, + { + "kind": "file", + "path": "img_2805.jpg", + "sha256": "002be275548e1d6019ad993a41bdffa2af1ef20d84547e80f5328a118a349013" + }, + { + "kind": "file", + "path": "img_320.jpg", + "sha256": "6c8aad8f9e9d6aeb73e2ac2f892f9ebe1d06df390cb5a6a5a48ba15306819d2b" + }, + { + "kind": "file", + "path": "img_2811.jpg", + "sha256": "de72df51b45706f54477adbbfbc022b9ed6ccfc2b3386c893ec4b8ee741e142a" + }, + { + "kind": "file", + "path": "img_446.jpg", + "sha256": "511c5ad823160eb37990609d746aa98263c8bee160ca7cbeff90fdc60ff46f47" + }, + { + "kind": "file", + "path": "img_2144.jpg", + "sha256": "93a8857bd73e391c82967d7ab0e6739be506ee244598f9277c3118aba3a9e43d" + }, + { + "kind": "file", + "path": "img_2622.jpg", + "sha256": "94e93a5834373830b4fa578f9cf6e3244ad99fe972835e3edc9ae7edc54f22da" + }, + { + "kind": "file", + "path": "img_2636.jpg", + "sha256": "637a5abdbe4840734e5e6bec6d90cccb8ab4c65cea488f21d8f7c7bd5d1cb2e5" + }, + { + "kind": "file", + "path": "img_3528.jpg", + "sha256": "58899dd6e990eb5dd3ed0dae5f9aa372df4c810ed2bca03fa5dc939ba8864ff1" + }, + { + "kind": "file", + "path": "img_4521.jpg", + "sha256": "21d0f2aa62b7123957f66ac482b5ca0aeb60e73ca8e5fb0f8c80be485da30a0a" + }, + { + "kind": "file", + "path": "img_2150.jpg", + "sha256": "490604777a8fb99b514a645620ecd2622abf5f1314e20c1f1aa93971aa4c2269" + }, + { + "kind": "file", + "path": "img_25.jpg", + "sha256": "d230430171314b4ef6f008aea571928f2dd601513a9b8afafce96d977b89f55a" + }, + { + "kind": "file", + "path": "img_1459.jpg", + "sha256": "e35b62c2fd8fffdb2ef87838f3ce11353fac3b5915d866c83537dc725f8209f9" + }, + { + "kind": "file", + "path": "img_4509.jpg", + "sha256": "ba8a7e926bdf0e5fa574a47ad2b0b4bdfa32c5a35c757329f90443f2261a7450" + }, + { + "kind": "file", + "path": "img_3266.jpg", + "sha256": "a60a816f1cba7b6bf221a5c2789c8f51f4a748a13d9106d228520226c81e7c77" + }, + { + "kind": "file", + "path": "img_491.jpg", + "sha256": "823a32972338cd845c7298de2ab8ff97ad3c9a2bd82593c7d91b0bf3affd093b" + }, + { + "kind": "file", + "path": "img_2178.jpg", + "sha256": "ce372d9ce196794eeae987f3d941ce716c6140c5e7898466f8d1452285c033e0" + }, + { + "kind": "file", + "path": "img_1317.jpg", + "sha256": "39e074dbf5ca063376ffe7a36e8d67589f423033753b7549445cbde77c2788e2" + }, + { + "kind": "file", + "path": "img_3500.jpg", + "sha256": "9e39c2d058ad300cb4d4c3ea0eefb7f54b72df034d072162f91a8d62e0daf727" + }, + { + "kind": "file", + "path": "img_3514.jpg", + "sha256": "b14f980d2654b65115f52a9bf9883c508c155be0428991cd2a1b52de0841ce11" + }, + { + "kind": "file", + "path": "img_1303.jpg", + "sha256": "1f7078a6e37a1772e35c76ac977588259d668e995227c351c910c5b3716c483b" + }, + { + "kind": "file", + "path": "img_3272.jpg", + "sha256": "0ebd391fb4501a3b4c1686f103bd2f20a44d92f6faba3200c139ad72d16844a9" + }, + { + "kind": "file", + "path": "img_485.jpg", + "sha256": "2cd8f23597a9facaf4c36bfec52655df37653ed1a01fc923817c78246f0f4397" + }, + { + "kind": "file", + "path": "img_19.jpg", + "sha256": "86f2e56cd749778fca29421d58619d93fab249eaca355d85e9b21ca9d2dc00a0" + }, + { + "kind": "file", + "path": "img_3925.jpg", + "sha256": "339222ec69f032caf87a8300e2dfd22114dde1e722864187ac36b5573047a2e9" + }, + { + "kind": "file", + "path": "img_4092.jpg", + "sha256": "6ee514ac57ce90a2c6cbfb125fe2411a4de0da445d40829dd2dfaa2db70ddf22" + }, + { + "kind": "file", + "path": "img_1854.jpg", + "sha256": "86f36acad87ae7377e269af79e3bf0a67d2079f4d292f1aceb58089d80a822ff" + }, + { + "kind": "file", + "path": "img_2391.jpg", + "sha256": "9cf9a5a46174b7627b3505fb8e3ebfb77e4f05313d7aceee361b623bb233238c" + }, + { + "kind": "file", + "path": "img_4938.jpg", + "sha256": "8b8c865501b3cb385b1bed5f6b68215e422b83f13a621bd9917452ebb10476f3" + }, + { + "kind": "file", + "path": "img_1698.jpg", + "sha256": "2125d2028cf7bdafb25bd96ff7bd76223c4f08645a55e1a00dcd3d771fe38660" + }, + { + "kind": "file", + "path": "img_1840.jpg", + "sha256": "d4845aa6e23e879bf6868cb0669f89a74fdbc23d957411ce00b403021da89bb9" + }, + { + "kind": "file", + "path": "img_3931.jpg", + "sha256": "d9343bb35e40245821799efa4a20b2d4b77f6fe15ed44081593fd5596aa7c61f" + }, + { + "kind": "file", + "path": "img_3919.jpg", + "sha256": "8701b47e198e71732c942d89bb43001c8735bfbeb26931e45b2c58aeb72c5427" + }, + { + "kind": "file", + "path": "img_136.jpg", + "sha256": "a6141113f160463ac0dfe553934b8ecafeddef96615cae19efcbfdf7b7cf5c6a" + }, + { + "kind": "file", + "path": "img_650.jpg", + "sha256": "7d57515f6afeea57d5592adf1d26805894246bd5830312037c78fbb138bf6f0e" + }, + { + "kind": "file", + "path": "img_4910.jpg", + "sha256": "9e8e7bd88a388210183dfad5f0a906d72bd58312dcd95a1a97ca40dfaac627b1" + }, + { + "kind": "file", + "path": "img_1868.jpg", + "sha256": "704bcf3c0ce99cdf506d72e2293576d26dcee5037af135f21199b785b3c89186" + }, + { + "kind": "file", + "path": "img_4904.jpg", + "sha256": "d4758a09f6eae42e67f67268cb93a1aff9017f80c510f2a33a3a656ce226b44a" + }, + { + "kind": "file", + "path": "img_122.jpg", + "sha256": "6708cf8ba5357e1b4d93a4438e7d3b875543452d107edf5d88dbb69a9c5ba166" + }, + { + "kind": "file", + "path": "img_1129.jpg", + "sha256": "908a7ffc8bc57eb149d8e6f6109b7942cf5deaf9c60c91546bc6d0626398fd72" + }, + { + "kind": "file", + "path": "img_4051.jpg", + "sha256": "9768d1b14ada811edb878a465512a4c4fee7cc88db7491f02f1001448eaa571b" + }, + { + "kind": "file", + "path": "img_877.jpg", + "sha256": "d0cdfbbe1c97a5d4e2b6af4cd8ed4fc2d7198150e18ad592f3a04c264f0cf6a0" + }, + { + "kind": "file", + "path": "img_2346.jpg", + "sha256": "f6db3f250baeeadf1bb8b6aa82cd7e2533f87f9aa613ec6ccf0c68506f09a01f" + }, + { + "kind": "file", + "path": "img_3058.jpg", + "sha256": "d77095fd6b29f23aaec831557de4865819c3d12b685fba503865f0909f3ec846" + }, + { + "kind": "file", + "path": "img_4737.jpg", + "sha256": "9963400ab4a86e4c3d4a7c0bbf4f84b85f07d3d71ff847a2a8a3e23e842000c8" + }, + { + "kind": "file", + "path": "img_1897.jpg", + "sha256": "36b52864ad49e9dd565c7ac04201c374789a6678b67696fb2a44578f7866ff70" + }, + { + "kind": "file", + "path": "img_1883.jpg", + "sha256": "3fcb213387b02d192a97176f538e4cfa8f8ab48c6360f46957c49c61e5222178" + }, + { + "kind": "file", + "path": "img_2352.jpg", + "sha256": "6e1e05f3f038ea8ffa80868cbb2aa46d2e5e16b7c3657b745a4e03ca3e319c31" + }, + { + "kind": "file", + "path": "img_4723.jpg", + "sha256": "1f42afaa2b80a473c4fc7d9810e081b4e358b58819d9730bd56ea26fb597653e" + }, + { + "kind": "file", + "path": "img_4045.jpg", + "sha256": "6cdf7decad3512a7eca12e43657d2a25d64822a59a65089e23fcf429669bdcf9" + }, + { + "kind": "file", + "path": "img_2434.jpg", + "sha256": "212e6a12ea4e3493bbfa34cbb6ed2ce75ecb8f9912b6b0f3e6f3d6f90b2f6aae" + }, + { + "kind": "file", + "path": "img_1673.jpg", + "sha256": "3fdc946e8f7208c4299d9d8c8cb2ef6f6b5188c3a0addb1f97321b8dc86361d8" + }, + { + "kind": "file", + "path": "img_693.jpg", + "sha256": "7b3143a7694705abc91693783ec53f804178ebb651df4da471bb133576c19784" + }, + { + "kind": "file", + "path": "img_3064.jpg", + "sha256": "0eef9586ad470c60b57217dc43968ab3f8b3d772fb6ae2f29ae520c2180ecb21" + }, + { + "kind": "file", + "path": "img_3070.jpg", + "sha256": "d2ee2484de8eb31818f7580e9b30286866ba693364c848c48594dc4d8b135581" + }, + { + "kind": "file", + "path": "img_1667.jpg", + "sha256": "c03511a37e8992bef940f02ae5a44ccfd72c2e03423060405199171b0be870b6" + }, + { + "kind": "file", + "path": "img_4079.jpg", + "sha256": "e2a0b2266af4cd278d17892fe30a583ad19740303b20fd6c98fdd343adbbe692" + }, + { + "kind": "file", + "path": "img_3716.jpg", + "sha256": "3073a68513f4a6025114f4f27c0720aad8df50fae62be2ae6ccac0c4bd683c0d" + }, + { + "kind": "file", + "path": "img_2408.jpg", + "sha256": "649606368f499c564c87fcd65c8b3cf9f980100adeda4df11c8e96c4c397a9e3" + }, + { + "kind": "file", + "path": "img_3689.jpg", + "sha256": "dbdf6e3b2225518f5e30157ec08355e1b8df390725ee7f3e81d4baaed6362d4c" + }, + { + "kind": "file", + "path": "img_3851.jpg", + "sha256": "7f0f4fedb2cff2b03e18eddf74d0e36e05a477a5cce4c391c2cb704d96720eda" + }, + { + "kind": "file", + "path": "img_2597.jpg", + "sha256": "4c81c6ef96557b4d1eb958b9680fc4b623e05aa9f203d7e6062f60c55b0b690a" + }, + { + "kind": "file", + "path": "img_4858.jpg", + "sha256": "3c3de76a081785a6811c360959f90ad850e5d741624261b5215a342fd8ce5e21" + }, + { + "kind": "file", + "path": "img_4680.jpg", + "sha256": "9cb3276dadbf4d7ca7ff9b7fcb3a4cf5d80d7345e20f2ffad73d8167d248de22" + }, + { + "kind": "file", + "path": "img_718.jpg", + "sha256": "f967d746b777a4a5b1cfa760db453d82f754f2554b11111e806ad28f57749c46" + }, + { + "kind": "file", + "path": "img_4694.jpg", + "sha256": "45a117f8653d2417e5c955cbb421220cdebf9ecad4a65f8f82612bb15580313f" + }, + { + "kind": "file", + "path": "img_1934.jpg", + "sha256": "bce1b698dfa9448c88bec4e8a90da5394c63098ab0d819ae37d13f1ae7ef8f73" + }, + { + "kind": "file", + "path": "img_3845.jpg", + "sha256": "1ca8c1d5a6821600284f652cc34c62bf4e484b3d2c675ac8cd157727c51c6748" + }, + { + "kind": "file", + "path": "img_724.jpg", + "sha256": "48138e5994917703d6b80f0b22d35a1164b5bfef58e423ba42c70ff692f68327" + }, + { + "kind": "file", + "path": "img_1908.jpg", + "sha256": "c407f62fea6e7fee50c4f82f38c0ed3f0393d6a2b5dcc82a0eea0341b7844cb4" + }, + { + "kind": "file", + "path": "img_4870.jpg", + "sha256": "b427a2b4e458f32b62d6b02d93e4d9ea79b1a9854f1ff68eb6ffbeadf2c00af8" + }, + { + "kind": "file", + "path": "img_730.jpg", + "sha256": "b93f6bef516e5d21b93a5b823808b01c6b628232400080e953a6763c2c095eb3" + }, + { + "kind": "file", + "path": "img_3879.jpg", + "sha256": "b299b3f5e0ea581f1d72da577f03bd83bbc5fb925c8bbefa0a4235d23e615695" + }, + { + "kind": "file", + "path": "img_3892.jpg", + "sha256": "1b158db0e8f2cf1e5b994e1d2e713f61d4f8645f57099f4513c8dc69a6233d10" + }, + { + "kind": "file", + "path": "img_2554.jpg", + "sha256": "c0eaa19de032cbd6101a52afac73f6b1a4379c1a1aabfdb0c63996e9a93fd5ef" + }, + { + "kind": "file", + "path": "img_4125.jpg", + "sha256": "e9be3194a7fe8f5f337cb0dd9530d78ff234ad3bcc1b3f1d0f295f2b0db70dd7" + }, + { + "kind": "file", + "path": "img_4643.jpg", + "sha256": "a86507d8176c2b82892d6a1d2b80786229231874fe47d3a2d716c3a376160e3c" + }, + { + "kind": "file", + "path": "img_903.jpg", + "sha256": "da3ed70d34474b1e56cfaf22d2de772b5fca1cf7a0c8cb043ccca6e0c85002c2" + }, + { + "kind": "file", + "path": "img_4657.jpg", + "sha256": "743f8ff3736c14ca622d9f446bc8076139d7db6c18b559f0d7aae4e6e5a61d63" + }, + { + "kind": "file", + "path": "img_2226.jpg", + "sha256": "be94a13febb895ecd159607204aa3c8e36acb90f4d648caab03ff172209ad88a" + }, + { + "kind": "file", + "path": "img_917.jpg", + "sha256": "6cdbd3806a8f71926ab286b22de6fa31409481470d5f1d830158f33aa8fd9421" + }, + { + "kind": "file", + "path": "img_3886.jpg", + "sha256": "2ad788e2ad8929fd8bbab60370957b7f07ce1ef64ef039fe2601c93ae2aed3f3" + }, + { + "kind": "file", + "path": "img_4131.jpg", + "sha256": "a4f53fb6a1c251882736cf461babb2823ce3c9eff2655431baf1e7d829274036" + }, + { + "kind": "file", + "path": "img_1049.jpg", + "sha256": "3e92b990fb96debeece81ee31a92fe581473f972837037f3c2d17835dd834715" + }, + { + "kind": "file", + "path": "img_2568.jpg", + "sha256": "96015d1ef530e664cf0d5c3f443dc4675cb5ec1b37d8b7421d26a5ba83e18176" + }, + { + "kind": "file", + "path": "img_3676.jpg", + "sha256": "f7cc77c62381e48f405a0e589ac7fa357cc98c89e96d79952e5f22a2e1de2296" + }, + { + "kind": "file", + "path": "img_4119.jpg", + "sha256": "e64d3ed62fa281092bf20e538fb7122694da672c86d889bd94f47d46e9262e7d" + }, + { + "kind": "file", + "path": "img_1061.jpg", + "sha256": "f79648273fbcf35cf91130e8e9aa068b9392e3f06ccf4034371f0f610fa8697e" + }, + { + "kind": "file", + "path": "img_1713.jpg", + "sha256": "fe5f203ce8d4d4a96ce2f6ed8c3025da79ce9fc9aad1cf7b2387eea2b4794d23" + }, + { + "kind": "file", + "path": "img_1075.jpg", + "sha256": "f5bc749d1d6d08a78248b5ba18737b237d32f06283b04ccc1b4a42192709ef40" + }, + { + "kind": "file", + "path": "img_3662.jpg", + "sha256": "29ec3dc441a7de21dfae11f73e5f73e95acd5e9b12d0f20d012f1e527a6bd58d" + }, + { + "kind": "file", + "path": "img_2795.jpg", + "sha256": "a133b3398d6e1fb66984f880308a87923405b5c70c2da615b509a7f145de0d80" + }, + { + "kind": "file", + "path": "img_2781.jpg", + "sha256": "cf0c79acaeaccbd75a098d39fd08263146159d29cb94dd43a92f728a88a3d75b" + }, + { + "kind": "file", + "path": "img_8.jpg", + "sha256": "3006363dceeb260b93f5293d71b54a3f394cb9f61c2dac11a77a2750c6fbe984" + }, + { + "kind": "file", + "path": "img_2959.jpg", + "sha256": "288c58e379354b0b5266aa52e83d87b72006a87c1a10852b2456dac55d777ae4" + }, + { + "kind": "file", + "path": "img_268.jpg", + "sha256": "93ffe2e4df70f23b93772737fe8d2a9d4998d21080c62aa05aecebb3fb1afabb" + }, + { + "kind": "file", + "path": "img_1288.jpg", + "sha256": "07bc67e80a68894ff96259883cce8853af699f8ebe0cd996f439b467c9085c42" + }, + { + "kind": "file", + "path": "img_2971.jpg", + "sha256": "ec354002892e915e8a9cd824f8b5b0df655673ec4def1be975f836be42fde398" + }, + { + "kind": "file", + "path": "img_240.jpg", + "sha256": "be2d2bae7346f7243f9a59d81f7f539eaeba64f2dc192c03d6afe37ba9b4825d" + }, + { + "kind": "file", + "path": "img_254.jpg", + "sha256": "4f80c26da02b44fe567138d82367e34e734d091b5eaf261dc5d14da7c3b04564" + }, + { + "kind": "file", + "path": "img_532.jpg", + "sha256": "f991c8ee6c4b354367c351c8388e208e2e896a17eca2686ef6ee23f823186332" + }, + { + "kind": "file", + "path": "img_1539.jpg", + "sha256": "ff50dcb09539d9b5cafe9669f8dc14d54ba5c567633039e5cc1e186f057e3867" + }, + { + "kind": "file", + "path": "img_4441.jpg", + "sha256": "7882b83f353c8fa8dc0479fb89a2f342d29d1a999c2ab1a3c9e71990b757ae92" + }, + { + "kind": "file", + "path": "img_3448.jpg", + "sha256": "b79a14a1d6c75790eea513f7059a63b9c0a2b7a4efc256fac59cf2158747fc99" + }, + { + "kind": "file", + "path": "img_2756.jpg", + "sha256": "152b8a9796906e733b1a9cdaaa0ab82fe6c0ce2f7350042de2a716bea9b2a188" + }, + { + "kind": "file", + "path": "img_4333.jpg", + "sha256": "84ac958b726cab6dcb21456b6d632985a9dc61c53986da128376072188625048" + }, + { + "kind": "file", + "path": "img_2742.jpg", + "sha256": "4dcc470c5c370e6c2c1eb1c3b6aadc5edddd15e45a18516da422b937da0d48a6" + }, + { + "kind": "file", + "path": "img_2024.jpg", + "sha256": "655457e8c808b34fa626c57358aa6e2d183257ea6b09ee0c9fa381a60cb0e60b" + }, + { + "kind": "file", + "path": "img_3312.jpg", + "sha256": "72f882babefb343fc91b14b93b1ad3fdfe71d26be6070cd6b7d0219723e3858b" + }, + { + "kind": "file", + "path": "img_1263.jpg", + "sha256": "7941ae8fbe1eeebb39477208d46fc4ffdeb189aa09291a749382f6aa5d6093be" + }, + { + "kind": "file", + "path": "img_3474.jpg", + "sha256": "9fda893aeccf00fad8c3596cdc4fde4975b9f0f8f5249be9314b90c3265bce26" + }, + { + "kind": "file", + "path": "img_283.jpg", + "sha256": "8a7b07cdfabb45e3ed99396c289110ce569ea527d1e907467b3de5eaa98715b7" + }, + { + "kind": "file", + "path": "img_297.jpg", + "sha256": "a45e02c81c8324f945916cb086f13973337ebe429933fa4ecd0361d2fedd870a" + }, + { + "kind": "file", + "path": "img_1277.jpg", + "sha256": "1e7849c8414e9ebe1e7f3febbfd93d90ebe205aba80531f2a66806f79f9c563c" + }, + { + "kind": "file", + "path": "img_1511.jpg", + "sha256": "c907d5030e4f8906acf1707916652fd34084fe2200ed7ee594187bfd804ffced" + }, + { + "kind": "file", + "path": "img_2018.jpg", + "sha256": "bb2af70e17c2898628f72941a5714190246bf5ad7276fd28f401fd9d8f3d9b0b" + }, + { + "kind": "file", + "path": "img_3306.jpg", + "sha256": "2bc09d98b15521aa12e4d18f468c213fcb576dc2939da0722fa62371c1d93f1c" + }, + { + "kind": "file", + "path": "img_4469.jpg", + "sha256": "a1313b94af322d2bb04ef9359c75d1bac5ca863aa5d0aee4e3dd5c081a83fc6d" + }, + { + "kind": "file", + "path": "img_1276.jpg", + "sha256": "f22b1444fa74e070f7d3f46bcf31f5419b31e7b7f24a645abcdf311e94050d02" + }, + { + "kind": "file", + "path": "img_296.jpg", + "sha256": "f971a33e977f9b21b7c540249e347c597f66fc349b14b61ce918e741501e7b1e" + }, + { + "kind": "file", + "path": "img_3461.jpg", + "sha256": "fe8cf23c8b31034a7a12e1e113d5e0ae6c03f8bd989af665c808d9ced3f750cf" + }, + { + "kind": "file", + "path": "img_4468.jpg", + "sha256": "4e2a528c60d46062510f6c4561eace209b86a69d5ea889244f9117bc75dbb98f" + }, + { + "kind": "file", + "path": "img_3307.jpg", + "sha256": "60d703a1001320130596f4a86be6fc786c66cb8a72d81b2d17b1cbda215c8e5e" + }, + { + "kind": "file", + "path": "img_2019.jpg", + "sha256": "f0a96a1b62456f29ca3e85aa4d034d9d58aad28513a8d678a3f74037dcf75866" + }, + { + "kind": "file", + "path": "img_1510.jpg", + "sha256": "fde7d887d86c77881620ac391fa80d13ef813281024fe455d40079426515627d" + }, + { + "kind": "file", + "path": "img_1504.jpg", + "sha256": "5f4d4370fd7b3ba008a56bee4b08867a6b381227c3e11106f96019ed882db6be" + }, + { + "kind": "file", + "path": "img_3313.jpg", + "sha256": "8e7e1d77763412433810b5cef99e10800472d37314d0fc3e27b809546986c06e" + }, + { + "kind": "file", + "path": "img_282.jpg", + "sha256": "6d1e3f9cfab15a835c9bd5a1480db862e938f0cb89cf2bbb102ec87e0b1e1c59" + }, + { + "kind": "file", + "path": "img_3475.jpg", + "sha256": "3f705e6642f905642f6ac56325cc6a5713187bea9fc16eb5af638216f350aa51" + }, + { + "kind": "file", + "path": "img_1262.jpg", + "sha256": "6a5ed82c19cda825e4eb519564e9f8956f754c48852210c609673d047843d24f" + }, + { + "kind": "file", + "path": "img_4454.jpg", + "sha256": "4b0345bf7cca9647268ba4e76d9f3e28dc3a4358d3ab960e0336bf7cf85c38ba" + }, + { + "kind": "file", + "path": "img_2025.jpg", + "sha256": "43285b9a45d9712bc2ed8ded8ef3d5c6f24658f117e86d73c13bdd723f1219c7" + }, + { + "kind": "file", + "path": "img_4440.jpg", + "sha256": "f99c43497c019f3da92d27b93bbdb2ace792c3ced1d713040112d45df948ef22" + }, + { + "kind": "file", + "path": "img_2031.jpg", + "sha256": "315e1da2cb1fceb8b83452d9b8db4cc17af54ba5fc907e80e6ed5f3a84843068" + }, + { + "kind": "file", + "path": "img_1538.jpg", + "sha256": "3e8aaf7324f1b9cc4ecbe2df0a152222e8030ed5b9624d414d56485175715643" + }, + { + "kind": "file", + "path": "img_2757.jpg", + "sha256": "1364f460119c9a4e2b39c2da156bd73372dea688477a9df32cc0c9fa568c6d35" + }, + { + "kind": "file", + "path": "img_3449.jpg", + "sha256": "e466d4cfa2c4ca78c8dad0b2f20de41f25dc454b0704fcf2ddf6c9cbe1a27d3f" + }, + { + "kind": "file", + "path": "img_4326.jpg", + "sha256": "51e6a8aca8a4b956fe8a1e723cc4170614a69338c2d1cb2a6ec8fd04504df5a6" + }, + { + "kind": "file", + "path": "img_533.jpg", + "sha256": "0c0fe5961fbcd6460e7427185c6ae6a04319e3ab4e482e5e05e8753ab41d71d3" + }, + { + "kind": "file", + "path": "img_527.jpg", + "sha256": "55f051b39e79ba4849827105c67c1e41f9c1a24030f732fde817b48c7fd13915" + }, + { + "kind": "file", + "path": "img_241.jpg", + "sha256": "9fa57a4cc189100f671a404e88bfb2b9d71d7ab8cb00daa4d6570faedbe178e6" + }, + { + "kind": "file", + "path": "img_2970.jpg", + "sha256": "a165dbef8282703f7a8f4d1a2bd5cdd1fda99d56e2985f34ab3bf87bb673a31e" + }, + { + "kind": "file", + "path": "img_1289.jpg", + "sha256": "e658029a979b7e8ca259468f7e7d9a92e0111b18d21884909363417efae53790" + }, + { + "kind": "file", + "path": "img_269.jpg", + "sha256": "aecffd68e65306686d0810dbf68b850ea8f02266a917b989216983ab0d0b130e" + }, + { + "kind": "file", + "path": "img_2780.jpg", + "sha256": "deaed82b7312f872db85635308723d0453f87083c3a2f8b19bc43253f6e21ee1" + }, + { + "kind": "file", + "path": "img_4497.jpg", + "sha256": "dfd69ed4fab7babf6e2b1163bd18e7b41c143c0b0c701912e7a715f468d48db1" + }, + { + "kind": "file", + "path": "img_4483.jpg", + "sha256": "44fc48d723b2007c0220daea0b8c79ed6df5e6b57378bfc3d184222a7d9e89cd" + }, + { + "kind": "file", + "path": "img_2794.jpg", + "sha256": "706026d0b53a75c215e99f0ec03e36f54855ea8baaa8bdb95ee40aaf1f01b072" + }, + { + "kind": "file", + "path": "img_3105.jpg", + "sha256": "e8bc440310eab556be4a5101e79d9f8bd268a81702719c261f2f1c02198b2acd" + }, + { + "kind": "file", + "path": "img_3663.jpg", + "sha256": "442a91324749f95f0e10932954cc07f839f5926213dc4a49fb39334b76f09645" + }, + { + "kind": "file", + "path": "img_1074.jpg", + "sha256": "cbb51f5a54b5bc1cf3eddcb1ed14294b3ad6ce5b4006f03822f7b20d089f3259" + }, + { + "kind": "file", + "path": "img_1060.jpg", + "sha256": "9bd3dfe39eb1b57acff9f52d5a973b5740e40007bdc208a2e03d6d44fee26b27" + }, + { + "kind": "file", + "path": "img_4118.jpg", + "sha256": "1a166467b8eeadb77a103904f036c161cf8ece0de71ea74e14024c9435c7edcd" + }, + { + "kind": "file", + "path": "img_2569.jpg", + "sha256": "ccb1d4941d292734a6146682d22554d49dc0e1575565aeba11151f9b553dd520" + }, + { + "kind": "file", + "path": "img_3111.jpg", + "sha256": "e7809b84a9e9e941acf35de5c8ace1a5f3db59ac9eb478467380e5fec1a02ddf" + }, + { + "kind": "file", + "path": "img_1706.jpg", + "sha256": "b932ecbf30bf5ceaba11c15ba7af0e99e0a8465d9f0e3d39d3c22d52987ea917" + }, + { + "kind": "file", + "path": "img_2227.jpg", + "sha256": "826360a128975005c1f1b4f94ce5218b9a1419ba989b567e0083462069be8236" + }, + { + "kind": "file", + "path": "img_3139.jpg", + "sha256": "591a765f919d36e98564a89e10361d3f7155c94a5109a1a207115ee84c05d300" + }, + { + "kind": "file", + "path": "img_4656.jpg", + "sha256": "e2b3fe0f6ffe8df32c119173f6d349f0599a34e22ec787058f6f7d2e20dc04a9" + }, + { + "kind": "file", + "path": "img_1048.jpg", + "sha256": "003866a3b694fe12548b4d3ce193d2a2063826b868b484224ab0d0a367e1a1eb" + }, + { + "kind": "file", + "path": "img_2541.jpg", + "sha256": "c29d5efe3e37cdae4d75a400e8e50f0548dabeedf09cc2f89d3a9402ec154e55" + }, + { + "kind": "file", + "path": "img_3887.jpg", + "sha256": "c96e5737395830c9612614d07c28857fad4a0f48f4da5e855bef9975870e5d73" + }, + { + "kind": "file", + "path": "img_4124.jpg", + "sha256": "3c24d3b88cea363865c20612591ab1e20ffe8323052435f83fbb6eb4495517bf" + }, + { + "kind": "file", + "path": "img_2555.jpg", + "sha256": "045ed2a896e1deb7d7e03ec0d9235942330809797cb69683c8b4a943da66b0be" + }, + { + "kind": "file", + "path": "img_3893.jpg", + "sha256": "dcdfc081b17299e9de056dae51d0bb94fd52536b8b02df9ef72162d1d9951fd6" + }, + { + "kind": "file", + "path": "img_902.jpg", + "sha256": "85987952e5eb975a8d51a946d44311f6491635e9f1f620e1d47caba679e8ce87" + }, + { + "kind": "file", + "path": "img_2233.jpg", + "sha256": "fb64315825803bbf77f447d829694fb9578b29733596bf5c8a04bc83c54d1756" + }, + { + "kind": "file", + "path": "img_4642.jpg", + "sha256": "38321e0d46c15cd257e4453a827ab36cfc02858840fa3566f6a6c3c77e78d588" + }, + { + "kind": "file", + "path": "img_1909.jpg", + "sha256": "b6f0027261b9b35d838334aa37ea1fbc103430dfd6a1ef8b94ae6b2c411a73ac" + }, + { + "kind": "file", + "path": "img_3878.jpg", + "sha256": "e4a25ed1bd2ddf35aadc6a43a44169a3262896a067fb820b34f6c1997fd6c896" + }, + { + "kind": "file", + "path": "img_4865.jpg", + "sha256": "91fc70ef1d404a163ef3741197aa3dcac2bb975380abd3fe8ab9f6f6106f149b" + }, + { + "kind": "file", + "path": "img_1935.jpg", + "sha256": "a7264c5ca6ecb75a002d36aa1030943e96d4761670ded4bdec546baad14a9c14" + }, + { + "kind": "file", + "path": "img_2596.jpg", + "sha256": "a7f921c880b7db64df7ee061bb7cc3de008c90adc1b4dc8e8370cf715b462710" + }, + { + "kind": "file", + "path": "img_3850.jpg", + "sha256": "5561f154a4fec823846979685585379fdadf5b15424f2ecee63c6ff95c354b1e" + }, + { + "kind": "file", + "path": "img_3688.jpg", + "sha256": "06241d298f695fe7626da6ad1dbdd4f9e8b5d6ee3acb27d9890a1bea096aa6a8" + }, + { + "kind": "file", + "path": "img_719.jpg", + "sha256": "7133de8f6eebce33802d03dd2e133faadf59ae925e1fd864c68c0e07ea77bbec" + }, + { + "kind": "file", + "path": "img_4681.jpg", + "sha256": "77b1b1df842ecd03fadc9843586259389b9f824a009499bbb0f74b518d6ba4e0" + }, + { + "kind": "file", + "path": "img_4859.jpg", + "sha256": "87effc92a441e921876985a1be1bcb9820616952b117d662402adb1b2a8dee4e" + }, + { + "kind": "file", + "path": "img_1921.jpg", + "sha256": "99472debbb5d01c4af317f39c30dd5a7a43bb4e8c586addd5dfb84848a84f927" + }, + { + "kind": "file", + "path": "img_1666.jpg", + "sha256": "85183c1247ce9f95e4278e8b0f6f2effe60557e792d1cccab6c5aaf88b844261" + }, + { + "kind": "file", + "path": "img_3071.jpg", + "sha256": "1b5eaac7a3904df479b2a566f7923843d5159ada56737c436836d3d2c8393435" + }, + { + "kind": "file", + "path": "img_2409.jpg", + "sha256": "6aa864023a29b606c2a2aa0253ef2f2adff0ec81a3a9edb2a91d1f7077d83b56" + }, + { + "kind": "file", + "path": "img_3717.jpg", + "sha256": "dbb6b467dc88881b804e793b23b17ee10b186c6d270b28bb124d61de3ee8f69c" + }, + { + "kind": "file", + "path": "img_1100.jpg", + "sha256": "f8504589a62234cf2fbb76d6ec9bae3987c52f0db73cbc0a05016a92b0ef446e" + }, + { + "kind": "file", + "path": "img_1114.jpg", + "sha256": "c6a6bf0b286022583ce6cdc7c8aa7cac6dcb25d441ebe9f1f75bf1ce46297903" + }, + { + "kind": "file", + "path": "img_3703.jpg", + "sha256": "1fb3539525e9f96f8ba350333f450dad9da4ed76e28eba297a00a70eb807eacf" + }, + { + "kind": "file", + "path": "img_3065.jpg", + "sha256": "4e1fbda0ddee7321013aded36c83d139edf6d2b50aff2ba005434bcca95bcefd" + }, + { + "kind": "file", + "path": "img_692.jpg", + "sha256": "96e9bfca8db016823c57e838fda09214b79b818edddc8cdefa465cfc677f2087" + }, + { + "kind": "file", + "path": "img_1672.jpg", + "sha256": "1bc00f8453c6550e1a55743279359d69d7feea250ff768c921182764f583e08e" + }, + { + "kind": "file", + "path": "img_4722.jpg", + "sha256": "5a117023e0460ebce8ca7c8a97d2d4dd1883073f683772c1837e58d1ae225eed" + }, + { + "kind": "file", + "path": "img_2353.jpg", + "sha256": "18478e5a8c2095d919739129e73c16ac32f4b75bb14ab05c85ecb7eed12f3747" + }, + { + "kind": "file", + "path": "img_862.jpg", + "sha256": "241b4a788e2b8cfd99d8a0da43ef1dabfdabb44d13be8803f9215fb648b33f29" + }, + { + "kind": "file", + "path": "img_1882.jpg", + "sha256": "de316fff6228c7a103fe5d17bb43a50d37bf65153b83326cfc92e7671c61d935" + }, + { + "kind": "file", + "path": "img_2435.jpg", + "sha256": "f202fd8d0e1215c642f9cdddedd6a9b99eed31f9ef5c7900ffdcfdcabd6f447e" + }, + { + "kind": "file", + "path": "img_4044.jpg", + "sha256": "f4cde9a2e58f3f3c2c007b5d81059cfede3fd5f8e7367f935a04510eb8b1b70d" + }, + { + "kind": "file", + "path": "img_4050.jpg", + "sha256": "922115f51a3c09febf853fd5e3dfffbe3f9f4620262c2028e092f6883fa893f5" + }, + { + "kind": "file", + "path": "img_1128.jpg", + "sha256": "f714fc2aae28ff0ae602bcffe849f26e4118793146b07ce97736f7181628beaa" + }, + { + "kind": "file", + "path": "img_4736.jpg", + "sha256": "eef670d1c98f8585a90669bf32a345f138401aa5f0b631ec1d935a5c5d793d3c" + }, + { + "kind": "file", + "path": "img_3059.jpg", + "sha256": "95458ba1d02aa3b3f41fdcf6775a2c09333ad8652d9e98bad0250a72ef996da6" + }, + { + "kind": "file", + "path": "img_876.jpg", + "sha256": "592f1077f1a16d1e3d88ffa7ffe793bc0d6bcbc0d1eb0a378832a08987b5a6cc" + }, + { + "kind": "file", + "path": "img_645.jpg", + "sha256": "00e37fce24af17224e803608d2985f14956612dd0f176578fffc9f7e7c463528" + }, + { + "kind": "file", + "path": "img_137.jpg", + "sha256": "e433b27ac33524448ae4138173c5be7a442f964f0dc70a2293a118a529f89809" + }, + { + "kind": "file", + "path": "img_4911.jpg", + "sha256": "1a61a407c79070eebeab0093651660668cfde1c535b6528301341111b042c0bf" + }, + { + "kind": "file", + "path": "img_889.jpg", + "sha256": "292e744602df5e20b50f653538141d9ebe27c5f404e58ee1bddcc62b258f376e" + }, + { + "kind": "file", + "path": "img_651.jpg", + "sha256": "fcc5d1d146c195ccacab8203f8ac7a61d7c29c559813652e4f09ec157662100f" + }, + { + "kind": "file", + "path": "img_1841.jpg", + "sha256": "84e448ade4a3b4380d09543311a44f1a25bf18b51165b93693ada93bfcce524b" + }, + { + "kind": "file", + "path": "img_1699.jpg", + "sha256": "21142f581995d71c0f5e1184348e56969f9c80b3d3872e1a958ae480c0913e16" + }, + { + "kind": "file", + "path": "img_4939.jpg", + "sha256": "cc4d2ce1128308e1afe3fd4fbb6dcbf0b99ff4f9d8a394ceadf38ce798c2a0f6" + }, + { + "kind": "file", + "path": "img_2390.jpg", + "sha256": "924d2a77f2cf4b0d08a2d53439fa8d682ea3217542f40b43eed3d212673445d9" + }, + { + "kind": "file", + "path": "img_679.jpg", + "sha256": "3a2e766016c0a692bbe00dcfb68d6830a726cd06cbbce3963914a3c4d6b0f8cd" + }, + { + "kind": "file", + "path": "img_4087.jpg", + "sha256": "d849b9e6b21070cfb615c83302b7d5216e40233ad0ba03ca8d6d22ccfa1bbf4b" + }, + { + "kind": "file", + "path": "img_3930.jpg", + "sha256": "6ef983415904c76a20b7cac6600a01ce238be5bedaa02d50c8628a233b53ac01" + }, + { + "kind": "file", + "path": "img_4093.jpg", + "sha256": "6dbf5e279645850bcca6766b4517d260b94d99a411d254029a2dd9b4bb8574cb" + }, + { + "kind": "file", + "path": "img_3924.jpg", + "sha256": "420c272d912b5501a1243981197c0f850b3746b2a197aceb70c45dfbe026e321" + }, + { + "kind": "file", + "path": "img_2384.jpg", + "sha256": "040e3ae0e14f633cd882cf7dfff2ade2c6c5902293da01216d6674ac69285a69" + }, + { + "kind": "file", + "path": "img_1855.jpg", + "sha256": "f1d9c328c2033b3529990686df5764a63c484b80d10e968881f6bde201ec68bd" + }, + { + "kind": "file", + "path": "img_1302.jpg", + "sha256": "82f79df66584eba3b65af6be0285227f15e9f6b63b2d82822f8d4ce375d471ca" + }, + { + "kind": "file", + "path": "img_18.jpg", + "sha256": "3d7487608135adf1b676b84ed48dba5ead66699cb929041a4f643ffa14c3dde3" + }, + { + "kind": "file", + "path": "img_484.jpg", + "sha256": "9d565115bf062ee508b1de94ee68dc5c8925ae56c23612031edabc50e757ae14" + }, + { + "kind": "file", + "path": "img_3273.jpg", + "sha256": "c404e572997b23abdfcfabf20167674d224a0e106200c002c48a6bacb370befd" + }, + { + "kind": "file", + "path": "img_1464.jpg", + "sha256": "b2533f263b522a4e5e9c2237fa0ab053f20a5fed1617435fe8fcc08c0c7231f5" + }, + { + "kind": "file", + "path": "img_1470.jpg", + "sha256": "6b1c678f182f91470ee73944d2d075d6359c6327ef0dfba7e1a37ad129518819" + }, + { + "kind": "file", + "path": "img_490.jpg", + "sha256": "82aa6a789de4365185872d1e1f46fee0fc8ed900227fa2ab29bc0b32c9fadcca" + }, + { + "kind": "file", + "path": "img_3267.jpg", + "sha256": "f4a21de09100ce518260cfe778fcd08f004c6fb2e8e4acaf739b79b92a76ccdc" + }, + { + "kind": "file", + "path": "img_4508.jpg", + "sha256": "236775ce6fda87f2688ece7674bcd49af433ac52c3132459ec7a0977727e325c" + }, + { + "kind": "file", + "path": "img_3501.jpg", + "sha256": "fc5a70431e269e34f1f5ae46c57d0f169ac597e40b07ad6a4727b9a0f51d2d70" + }, + { + "kind": "file", + "path": "img_4246.jpg", + "sha256": "bda4279654e50ac8cf75d4db3242c97fc0f976c83fefb626086053a1d078f463" + }, + { + "kind": "file", + "path": "img_3529.jpg", + "sha256": "9bad7006b40eca287ccbf71813bb9bab9e5dfc457cd042cf8796a20d2b7c6ce9" + }, + { + "kind": "file", + "path": "img_2637.jpg", + "sha256": "657f261c07c32a2608357823c9898cf7c8ce65eb1a5504c921f2a4998f737480" + }, + { + "kind": "file", + "path": "img_1458.jpg", + "sha256": "843c01049efe28fc0026a6327e3a26f80a286f2ad128c283af938ab2ba314914" + }, + { + "kind": "file", + "path": "img_24.jpg", + "sha256": "38b71b8899c0fa8171cd48e91941510ee43679bd47742ca581bae707b53c1f0e" + }, + { + "kind": "file", + "path": "img_2151.jpg", + "sha256": "9632b4641282d7cfcd5200e49d2a24f0d5c212d4d9062f0226d304e4028bd9e3" + }, + { + "kind": "file", + "path": "img_30.jpg", + "sha256": "62cb6006101f9e9da55d108af85503a5f43f7b5c42906f44c0331ac9d527891a" + }, + { + "kind": "file", + "path": "img_4534.jpg", + "sha256": "3b6fb1d76e7b3fe9e9a4876f107717d52d9558507439354a9a7323ef84930ae9" + }, + { + "kind": "file", + "path": "img_4252.jpg", + "sha256": "a59897eeef962a2e04ee430510788b32b9014a129bc152ae51b1a3e933fd6144" + }, + { + "kind": "file", + "path": "img_2623.jpg", + "sha256": "ad57afd45dada3c0db8273e03e3e2fe9dad2abc5d9b681b408373cae6a0aaf54" + }, + { + "kind": "file", + "path": "img_2810.jpg", + "sha256": "3efdf3e86689d877db274d64d5fb83ff1c92d7ff6538626c663d7d74d7dd3cf6" + }, + { + "kind": "file", + "path": "img_447.jpg", + "sha256": "12f5c24d61f47407b80938a32077a384c78514162f6c0249090a6a89638ab83c" + }, + { + "kind": "file", + "path": "img_453.jpg", + "sha256": "ff3eda1faed011241ecf65bb17c3d46a4ada60efacc353a5d7033244a4678ada" + }, + { + "kind": "file", + "path": "img_335.jpg", + "sha256": "9c57d0c11bb65b7aeffb0c419d09b9109ddded761b70bacac9a8a825cbcdba7d" + }, + { + "kind": "file", + "path": "img_4285.jpg", + "sha256": "5db30863c250d6bcdee849400b894916399dbe3c1a02fd04acd8577ddb82e6c8" + }, + { + "kind": "file", + "path": "img_3298.jpg", + "sha256": "3e92fbd06ca2c63b7408f4d5ea6a9317dd7b7910da71e01c4a31df35dc51b393" + }, + { + "kind": "file", + "path": "img_2186.jpg", + "sha256": "c4172cd0f9cd1a3a94a53d20172b9d8f0cc4d24d5ac3816443f923c149dc04ba" + }, + { + "kind": "file", + "path": "img_2838.jpg", + "sha256": "d37231c54821c8987bd84a45429277a25e06316b774d40e44049e954866079dd" + }, + { + "kind": "file", + "path": "img_4291.jpg", + "sha256": "98d6e0249a3f52ae709cdcbd74aa1ea24611b180f609a373eb5a87cec75b6283" + }, + { + "kind": "file", + "path": "img_309.jpg", + "sha256": "329cc77a567f6eae8cd8cc27a4dc1a45c1f8e27a15cce0ce25410bae2abbff83" + }, + { + "kind": "file", + "path": "img_1499.jpg", + "sha256": "fbc1dfd6249ab5380ff656cf8e84ff609673bef97f4f4cc7d39c727b6f642968" + }, + { + "kind": "file", + "path": "img_2190.jpg", + "sha256": "33e78c7589add651784c7abffde540678d6b640443917aa3a012836d5b7dc7d6" + }, + { + "kind": "file", + "path": "img_479.jpg", + "sha256": "9dd8c9dd9eb8e461da0346313cf042618575702167c330fed39a7d13debb4676" + }, + { + "kind": "file", + "path": "img_4287.jpg", + "sha256": "188256898cc1f1849905b0b2a76b670e1af902c7ab0c443e781833e963d70b94" + }, + { + "kind": "file", + "path": "img_445.jpg", + "sha256": "10c65a847e94144a80043068695e66f1e6236c01c12e7092605006c49544c7d0" + }, + { + "kind": "file", + "path": "img_2812.jpg", + "sha256": "4478b1fe45363bfe138c268725fec9f1e1b25666b8042a0d572df3d59e2e2316" + }, + { + "kind": "file", + "path": "img_337.jpg", + "sha256": "b54976c1981a4cd5822d6aa586eece1f060814c44aa8d00525b32c86b965e226" + }, + { + "kind": "file", + "path": "img_2806.jpg", + "sha256": "6f94d3a68578785203b13f4e20fd3daee871075defb20b2bdfc69fd10595f750" + }, + { + "kind": "file", + "path": "img_451.jpg", + "sha256": "dcd7cb1dc76e4ac161143ec1c41c042053ad5a1a263217683ba17a97ebf0377d" + }, + { + "kind": "file", + "path": "img_4522.jpg", + "sha256": "cab9c50090cf6a94d006a111c6e4bf3580e1dfd7d21185be2b9bb68c4d314473" + }, + { + "kind": "file", + "path": "img_2153.jpg", + "sha256": "7060ce99f30b0bb145a0338277c7729b66f85e268e0572fdb0b5a3ac4163daa3" + }, + { + "kind": "file", + "path": "img_26.jpg", + "sha256": "97b714d2857b52f34016d389272b8b0085fd58bb4536a2a973fa193f0d49c20d" + }, + { + "kind": "file", + "path": "img_2635.jpg", + "sha256": "04000e95e4ccc7d2864f97c95d163a529e9f536937e24cdbf1860c01e2381a00" + }, + { + "kind": "file", + "path": "img_4244.jpg", + "sha256": "0c0c49e39dd0551603a6302fb9ce011ab2181485b8caa4f52cfed15296565607" + }, + { + "kind": "file", + "path": "img_2621.jpg", + "sha256": "2fe78896f6ad374519fd68ec67e9921f551d441fb40a6a698cf6b0af85b6efda" + }, + { + "kind": "file", + "path": "img_4250.jpg", + "sha256": "3988b353908c607aaf2ebe41e212a69c2fef7a29cb62ab85b1749a76bba7eb65" + }, + { + "kind": "file", + "path": "img_1328.jpg", + "sha256": "94affa2d3fc0f1d79199d34d1a8af366ba2cd1ced5f7f29df2fd36ddd69d5627" + }, + { + "kind": "file", + "path": "img_4536.jpg", + "sha256": "052a9962b1d8b3fc2a9b4de13f59fc5663af24c4837664c73e59e248b65b735b" + }, + { + "kind": "file", + "path": "img_3259.jpg", + "sha256": "ab74ed7cb9ab0003f4738160cfba56b4063a0e1abd32afcc4380d71f04871efd" + }, + { + "kind": "file", + "path": "img_2147.jpg", + "sha256": "4e046593050d5e97775cee94b539dae0556cf1c5317b5bc5e93dcecca43acaaf" + }, + { + "kind": "file", + "path": "img_32.jpg", + "sha256": "655fbe6951060c831807a2b6081c7402445ca74bb8f5a40f7f15c63429ca6764" + }, + { + "kind": "file", + "path": "img_1466.jpg", + "sha256": "3b5611786f89b8e93353d88b92d309ac5339adac27c475f2377e4a35640e1990" + }, + { + "kind": "file", + "path": "img_486.jpg", + "sha256": "e17e908e35d2c3e352595e113bb687b4e72be0448fce6c53665053b7f2af9805" + }, + { + "kind": "file", + "path": "img_3271.jpg", + "sha256": "9b6222991b0b8d2a36d66c18ed5d837660349f3a202496806654ae4d6206490a" + }, + { + "kind": "file", + "path": "img_2609.jpg", + "sha256": "44de4362f2612b0ea736a57de983add0dde21cbad1e1a3f10b767ae47fa5ae10" + }, + { + "kind": "file", + "path": "img_4278.jpg", + "sha256": "99dcce16e76c212105ffe2a998c34439a91690f13e8eac9a41243a456e89c023" + }, + { + "kind": "file", + "path": "img_1300.jpg", + "sha256": "174ffa5a3e10e993204a74aca3001114d5229e3194fe692444acfa5552f0d8b4" + }, + { + "kind": "file", + "path": "img_1314.jpg", + "sha256": "079bf74352fe3c2a901b22ddf802df8c34d588350bd0519f804f51fcf59fa574" + }, + { + "kind": "file", + "path": "img_3503.jpg", + "sha256": "c1136b90265d18dabf05a3a2175c9791a26b491490a99c8e7d1fcf1630730d1d" + }, + { + "kind": "file", + "path": "img_492.jpg", + "sha256": "0b32ecb3586bdb4788f0561d6567880d695c5d604e4d4438038771e33f2d0c74" + }, + { + "kind": "file", + "path": "img_1472.jpg", + "sha256": "53bebb9903a97762837fdda7934af2f839f1de2c2d19a3696831380129b62ff2" + }, + { + "kind": "file", + "path": "img_4085.jpg", + "sha256": "b4487ae743a6d3144da39838270a4fce76c0e60cebf7969f6c001227af37e6cf" + }, + { + "kind": "file", + "path": "img_2392.jpg", + "sha256": "940a9d872faa1d650ebf9fc8a0f2f608eb4bb342dc0824b7c59873200197afff" + }, + { + "kind": "file", + "path": "img_1843.jpg", + "sha256": "ccba1d018ad378e6521b227b760337fc8f1c9715692b871ef228d6da185d27c8" + }, + { + "kind": "file", + "path": "img_1857.jpg", + "sha256": "c10834a67014d48775aa7aa515e435e39168a01689c1f64d48339df9e5d720a8" + }, + { + "kind": "file", + "path": "img_3098.jpg", + "sha256": "c1d1f3b592cbf93b64e758241991e462727227f57408313b5ebdfa907235a61c" + }, + { + "kind": "file", + "path": "img_2386.jpg", + "sha256": "e6c4c60e1017ca0f6f24bdcc886395eb2b1eeb39dff0afa45fc9987d32c59e2c" + }, + { + "kind": "file", + "path": "img_3926.jpg", + "sha256": "c60812d55badb598dcb6e1572d6f62ae2d2e53b3e2b0f86175d6772672250eac" + }, + { + "kind": "file", + "path": "img_109.jpg", + "sha256": "3449cf9332f46508ec0ac61f2d9a56f8514c2aa9471e7a6513f825935f7aaed4" + }, + { + "kind": "file", + "path": "img_647.jpg", + "sha256": "e775d738c661a4797532052a62e7317ff323a67734b3cef1b93324bf1da7aca7" + }, + { + "kind": "file", + "path": "img_4907.jpg", + "sha256": "ee0d4615e63ca58fd2093367a27265aa5ea83d5b6f6412b36047442f2ee27d78" + }, + { + "kind": "file", + "path": "img_653.jpg", + "sha256": "7afb4e76d74d2bfdd9bc907e7cf7ad8341745836316da0607e30a131e70c977f" + }, + { + "kind": "file", + "path": "img_135.jpg", + "sha256": "82d149bc31ebfe85047e8c3095b9a2b8494a8783070ffa0be695d9afb648075e" + }, + { + "kind": "file", + "path": "img_4046.jpg", + "sha256": "fa2fb7921a29b792f3fa7141b689ae804e5a92bfa2099b4762afe44142c545b9" + }, + { + "kind": "file", + "path": "img_1880.jpg", + "sha256": "10e2174ba027bd11d02905fbf407dcd23b0af4aa2bf694fbd69901ad831583d2" + }, + { + "kind": "file", + "path": "img_1658.jpg", + "sha256": "8e9d0b857986e6dfd51d98343d94ad4f70b8c5aeee113bbf32d26cbf211af540" + }, + { + "kind": "file", + "path": "img_2351.jpg", + "sha256": "85dde3a64011aede43b8bee4b0fb8865efe119d3126c17136fc3e6f051822257" + }, + { + "kind": "file", + "path": "img_874.jpg", + "sha256": "4e0ec83f4ae463fafeb3d4128a4ea4281d36dcfa4b18aff52a5b0030e7780478" + }, + { + "kind": "file", + "path": "img_2345.jpg", + "sha256": "6dd98ad2520b15c15a9e3386319f7928e87da088c389dd66cf97e04681ccc652" + }, + { + "kind": "file", + "path": "img_4734.jpg", + "sha256": "ee415371edc22c6cd63f133057953fcd2b04e7978d01bd021cb4da4df8747ec5" + }, + { + "kind": "file", + "path": "img_1894.jpg", + "sha256": "d952f63675485a4115324f63377137485bd42c83ce4a59cf1d97c4d53b1bb327" + }, + { + "kind": "file", + "path": "img_2423.jpg", + "sha256": "57b2b0f0c6927a6e38e3a82b7434919d7c59c4dec6103383855d78e47c9d391a" + }, + { + "kind": "file", + "path": "img_1102.jpg", + "sha256": "683824c454591f6add1fef8880d671bad4a52328de9da40ba500d4c43baaaa21" + }, + { + "kind": "file", + "path": "img_3073.jpg", + "sha256": "3c8aaa1a2176b3bef93ce5538b027152b230cada8996f7f61b20eff19baae443" + }, + { + "kind": "file", + "path": "img_1664.jpg", + "sha256": "02129c1269cabb6de55b5474833b1d276be78f39c91268ca6097ce21dd0765dc" + }, + { + "kind": "file", + "path": "img_848.jpg", + "sha256": "1a31e8e1b02a396aae834986fdbc48b1e3c6df861244774cc73e97444a14b4c9" + }, + { + "kind": "file", + "path": "img_2379.jpg", + "sha256": "5ecadddb5992d6c426cd9958d724f97edf12bd2ba3ab3bd39b73ed8caab0bc5f" + }, + { + "kind": "file", + "path": "img_3067.jpg", + "sha256": "b29a550112c0e0b90c6afeb61024a50c5f4e2245e71837b80a15ecc33a9bb8d6" + }, + { + "kind": "file", + "path": "img_690.jpg", + "sha256": "aa82233b6f552d5996de02a25ed425eac84b7000214ac1ecec8ad90ffafc4cd6" + }, + { + "kind": "file", + "path": "img_3701.jpg", + "sha256": "ff26d83f11ec7c74511bf9ecb1d775ac7c791109f10121a11644292f356da6f4" + }, + { + "kind": "file", + "path": "img_1089.jpg", + "sha256": "c43e0820b702c6dcfa9918cbf768f9f3d1ca12ea7f03fc8fa816022caf32169a" + }, + { + "kind": "file", + "path": "img_3846.jpg", + "sha256": "a91bd5bb0d3a2fbce471b76fb8ebd366a01ebf3ab79d9bc38f40a958b685645b" + }, + { + "kind": "file", + "path": "img_2580.jpg", + "sha256": "8870c068086107433b9ec2b9c9339517db29e694d1012a5d74874708114852bb" + }, + { + "kind": "file", + "path": "img_1937.jpg", + "sha256": "36ac438a469800f3a9687beca460199dd651a15387c63848a228efa2598a5045" + }, + { + "kind": "file", + "path": "img_4683.jpg", + "sha256": "dff7cf69e301b4d4b411580de93566fb48a34f2cb5932e04b14970ea90501ef1" + }, + { + "kind": "file", + "path": "img_2594.jpg", + "sha256": "61f607eadb72137bd453aef346f36bd5a76a79a14c7afe8df796708e2fafd631" + }, + { + "kind": "file", + "path": "img_4873.jpg", + "sha256": "14ddbb64288c25fcabd6a636c5319272e8cbe332cedd46aad54f44465364f4f0" + }, + { + "kind": "file", + "path": "img_733.jpg", + "sha256": "a0365583af313d4ee52f2f9260a2e4211ddd8251ecb0066f062d9ef811b4b0fe" + }, + { + "kind": "file", + "path": "img_727.jpg", + "sha256": "b39e4246ee8da071b85bc53f53f624c9cd40e5dd5cdc1135072113f6996f4608" + }, + { + "kind": "file", + "path": "img_3885.jpg", + "sha256": "a423afce1afd51f1949002228db2e0d509be7a86fa9de0f7fef5319515de1d1a" + }, + { + "kind": "file", + "path": "img_2543.jpg", + "sha256": "2b28aa294861a3f362366e2cd26022e0e03fbb48912b866a32fc0c888b635d73" + }, + { + "kind": "file", + "path": "img_4132.jpg", + "sha256": "76b717519a466b6cfcd6c0897b52bc432c22bdeb673fe080f586ed08742e9b95" + }, + { + "kind": "file", + "path": "img_4654.jpg", + "sha256": "5ec710c0716f02f279462a41733f7da9d204bfae06c0bef45de63a5505fea965" + }, + { + "kind": "file", + "path": "img_2225.jpg", + "sha256": "280904e2ccbd7d77fac76e483193496980b885670f56531c0922827f66b9a458" + }, + { + "kind": "file", + "path": "img_4640.jpg", + "sha256": "62813ddbb57f117567c1a61424ac4d6537f8368ebb20f9d09966c5bc48f4feeb" + }, + { + "kind": "file", + "path": "img_4898.jpg", + "sha256": "21bdbe6dec0753f442581f6e67030f5f5eaabbf1b4dd705723e4dc5126e65603" + }, + { + "kind": "file", + "path": "img_900.jpg", + "sha256": "fa7315b16dc4d78b88a52e30c0177528434035dc0c7d158a20cc2a6191aff3be" + }, + { + "kind": "file", + "path": "img_1738.jpg", + "sha256": "edebfd5c4657300da06fff7d4e591ded5c935b6cd1fd017143acb357b3d7d731" + }, + { + "kind": "file", + "path": "img_3891.jpg", + "sha256": "0472d40d4f8feaaeb764185de78f908a71f3bf29c61f3f23a3196503bd64b5c9" + }, + { + "kind": "file", + "path": "img_2557.jpg", + "sha256": "8cee91ae0cf90e5f77f86dc9db5b942e085b827964195cb5f3791cbe09b2fdc5" + }, + { + "kind": "file", + "path": "img_3649.jpg", + "sha256": "4efbd459d1eed4d83b19dfd164b1bfba2a31ff50bbc9853e80a401099a3b1362" + }, + { + "kind": "file", + "path": "img_4126.jpg", + "sha256": "784140b62e25f963c1d3a2f7fdaa0b08b8923fe68ed73ed8996706979036c791" + }, + { + "kind": "file", + "path": "img_1076.jpg", + "sha256": "603ee195b9434141f7667e6680c3df4f31f7796a419064a7b5c281f20e937422" + }, + { + "kind": "file", + "path": "img_3661.jpg", + "sha256": "2e106f23cc8d093a6e157d990ba6caccfddde93dadaae3d894d0db7a6372dfac" + }, + { + "kind": "file", + "path": "img_4668.jpg", + "sha256": "5ec54228e4246896b15db5b6b95dbf4c07100973b8881d6b6a50d16d419face5" + }, + { + "kind": "file", + "path": "img_3107.jpg", + "sha256": "a79bb26631a2edc0be345942d17cef5d2318c39f499bd1b718dfbd1e6711ac27" + }, + { + "kind": "file", + "path": "img_2219.jpg", + "sha256": "63c4926e8afe0f3954d9f163a52998d089ee87cc704570fa17ac3348767742d0" + }, + { + "kind": "file", + "path": "img_928.jpg", + "sha256": "b94832c1b1d297c843f0b4d209d3c58451746244941804fdc8a39637323b425d" + }, + { + "kind": "file", + "path": "img_1710.jpg", + "sha256": "298f6ed7a92c4747411c867e290d03c721ed14ee05c074e67ec4a567e54bbbb5" + }, + { + "kind": "file", + "path": "img_1704.jpg", + "sha256": "392a1a39deea56cfc00c6e9649f4e886d0d43c230e590178287d0d7c82b7be6b" + }, + { + "kind": "file", + "path": "img_4495.jpg", + "sha256": "b02901bc26660651afc15ebbcfda997fe097a7cb48d2deb450d6d88ca2f13074" + }, + { + "kind": "file", + "path": "img_2796.jpg", + "sha256": "9a7fd8bd5a8d468d2a31d67c6f691e69a6a042194311733a59268c517bc7feb2" + }, + { + "kind": "file", + "path": "img_3488.jpg", + "sha256": "43f2769e083795867f1297242d82a9c058d69a752b93894eb9b4c25f728a3b30" + }, + { + "kind": "file", + "path": "img_519.jpg", + "sha256": "248cec0d4cfcf7fe199c0b489e0e83293ed2f0d09dc59fbe67bb8bbd8ce753e0" + }, + { + "kind": "file", + "path": "img_4481.jpg", + "sha256": "00a8c5dd3a208ef8c114cdf09b09c51c8e0c1ce33b7fbda0c0fe539ea917ad12" + }, + { + "kind": "file", + "path": "img_531.jpg", + "sha256": "82eacf9da132c19f02522e6205febaf69d1e518e2e541a2f23fb6a7e405aa48f" + }, + { + "kind": "file", + "path": "img_2966.jpg", + "sha256": "b7d8db4137246d216716dc8658ccb5d7dadc992ce657e2b75bc305d49dd1c72b" + }, + { + "kind": "file", + "path": "img_257.jpg", + "sha256": "41d6b628629dd0df15c4d475cf51675b9fb26b830125b359044061c1b5bfa460" + }, + { + "kind": "file", + "path": "img_243.jpg", + "sha256": "05e1e0e3ff3bd784339d472e5d423123a26f4e412ed1c55fa4bb473022168a18" + }, + { + "kind": "file", + "path": "img_525.jpg", + "sha256": "d5292415755f4801ae674b68cf6ce7afca94fe556c27b3758cfb4ae603e75ad7" + }, + { + "kind": "file", + "path": "img_2027.jpg", + "sha256": "e2dbafd1d02a373c225884e14775ddd1b841cd12c48eb0e66add3038611ad094" + }, + { + "kind": "file", + "path": "img_3339.jpg", + "sha256": "ab6ffe82557220656777004f4e145e78639c6cde6c27e2820194ecdb1aebb0a4" + }, + { + "kind": "file", + "path": "img_4456.jpg", + "sha256": "62c60d6160b6f7d189fa34a4abe5a633c3402f037a14377c005e972e7e3763f0" + }, + { + "kind": "file", + "path": "img_1248.jpg", + "sha256": "d8680809dff676a2eaf6c3a63765ffe07b52eff41e3efa9435c14b12a078f0f9" + }, + { + "kind": "file", + "path": "img_2999.jpg", + "sha256": "9ed2bb7de6f6da12f9b5888554ecc5028d9dfca447f752befee4cff82bce8bce" + }, + { + "kind": "file", + "path": "img_2741.jpg", + "sha256": "4fa9d68ad65066900c632ce9a9264572079ac0d5d26a7e726a91c3456cdca0ae" + }, + { + "kind": "file", + "path": "img_4324.jpg", + "sha256": "97ecd39908c4832c025212090fc3fb200d41c5d85ffc3fdeb9f28d7f6532f469" + }, + { + "kind": "file", + "path": "img_2755.jpg", + "sha256": "593328228ce46704c390a5d08a11ebb991d7b41fe81c009f87217cbdc47f48e6" + }, + { + "kind": "file", + "path": "img_2033.jpg", + "sha256": "e7cea536e2bccec6c742eaf61a3e771e922935cef20077cdffc6010b71b0d5c1" + }, + { + "kind": "file", + "path": "img_4442.jpg", + "sha256": "1d7044fef68aac3e85adabb5a15af7defa1cc7c3b7b5ed5e0df311865e6ceecb" + }, + { + "kind": "file", + "path": "img_1512.jpg", + "sha256": "e9ee850b9f9a31d96908ee82da3cd74622a2cbd35d62d20c153b9fea42780c73" + }, + { + "kind": "file", + "path": "img_294.jpg", + "sha256": "930c3bafe999affe7966e33c05a8e21624597e889049ada15aebbf21d3800726" + }, + { + "kind": "file", + "path": "img_3463.jpg", + "sha256": "183c3ba4bfcc18b02171901d1cbb486299f0d8c33764f6ce35e413d43aabd492" + }, + { + "kind": "file", + "path": "img_1274.jpg", + "sha256": "88acf8baedc2f98354c953f625993aa1b60ea752d027d5dd961d67a02efaefc7" + }, + { + "kind": "file", + "path": "img_1260.jpg", + "sha256": "a2ac505e91714a655fead677ded65d120b723b0b2433939708f1445ff70c6376" + }, + { + "kind": "file", + "path": "img_4318.jpg", + "sha256": "bb9d0fc7e49bef548e5d84c930adb3192c4f735f9a51605157e6c1230160fa6a" + }, + { + "kind": "file", + "path": "img_280.jpg", + "sha256": "e963cb93cc613aa4061c4ae1a3f7bac60b26a833129e0002cef8b348ebab379c" + }, + { + "kind": "file", + "path": "img_3477.jpg", + "sha256": "5889b3c1c093119c90c700ccb52470b70abeb1a0e3980d899496b28ebb4e4e5b" + }, + { + "kind": "file", + "path": "img_2769.jpg", + "sha256": "6377e79342c51883a99eafd63ea344ed3fd29e5f4bbd9bae6acf3cf2bbbac11e" + }, + { + "kind": "file", + "path": "img_3311.jpg", + "sha256": "6a5cd75bd4dee4b14d45ea328adf911ec6d77075b9b9aae97eb0574408d55c62" + }, + { + "kind": "file", + "path": "img_1506.jpg", + "sha256": "791f2defe337d1947778d0f0e12765e9732e40eda50fab86f7e71ecedf631383" + }, + { + "kind": "file", + "path": "img_2768.jpg", + "sha256": "89088d86e3df63bd5bc8a59057c079767baa83d084f204be99e1b7ed3d6e1689" + }, + { + "kind": "file", + "path": "img_3476.jpg", + "sha256": "b9858b6381fc0f453d8acd3ef43a61c93064d687305d9c029e6385e3174584fb" + }, + { + "kind": "file", + "path": "img_4319.jpg", + "sha256": "ceb329babc619a140d83a0a724e4e0681b150a0f82453d34206e2fc09159d7b2" + }, + { + "kind": "file", + "path": "img_1507.jpg", + "sha256": "d00798edcd8a042951c971e2f24cbfceacf79868b2cdeeb019f5b9c11af55113" + }, + { + "kind": "file", + "path": "img_3310.jpg", + "sha256": "e4adfa4468493d143c710882287044ac2611bf8c5bdf9e90830c54a7e24d5a4a" + }, + { + "kind": "file", + "path": "img_3304.jpg", + "sha256": "cb888f23894db58492ed7c72a7d941d6a244e00aea1e6852a79a493f44c479a5" + }, + { + "kind": "file", + "path": "img_1513.jpg", + "sha256": "0a313d28c7a2efde42af5e015a2f38f0198256554376776cb3ed7b7fd43e9b57" + }, + { + "kind": "file", + "path": "img_1275.jpg", + "sha256": "a6c53929f99eecd2d70b5813ede254771f6b3a8e8c6e28093ac027f58be46a52" + }, + { + "kind": "file", + "path": "img_3462.jpg", + "sha256": "9b0b3543c3aa10de9ad0b185fec4e67b30b70c8a0ef35a72cd5094f59d18bf36" + }, + { + "kind": "file", + "path": "img_295.jpg", + "sha256": "d2170217907fed4d197f584e9e11650681722a644a97e73517238124b592c259" + }, + { + "kind": "file", + "path": "img_2754.jpg", + "sha256": "e1e7140be3fcac206bb6b3370b954e4606e23a69902ec7113a5223b8b0246517" + }, + { + "kind": "file", + "path": "img_4325.jpg", + "sha256": "0532b7786c4f3a95aeba4af89c4ae8addafac34cb8d556b7321a80720374a570" + }, + { + "kind": "file", + "path": "img_4443.jpg", + "sha256": "78a42dfb1f0ba51c088ba390de4dc956bab2c6d08fb685d06fcc954b3369df15" + }, + { + "kind": "file", + "path": "img_2032.jpg", + "sha256": "a24168eb796e41f51133b64eb91e49ee5bc9777504c2054b884f98bd97bd2fa9" + }, + { + "kind": "file", + "path": "img_4457.jpg", + "sha256": "f2e523ce177b7e9ce12e41b4613111cf014813d9501903016419867bc84ecf26" + }, + { + "kind": "file", + "path": "img_3338.jpg", + "sha256": "3404612aaf032e7db1f8107dba32156e3871aea1c88ee1c10f8f78e22ec8d895" + }, + { + "kind": "file", + "path": "img_2026.jpg", + "sha256": "117df9ebe6805f66644a3bcf26bd0388de791abf5f7dfb634c92a53a4628e454" + }, + { + "kind": "file", + "path": "img_2740.jpg", + "sha256": "c271d7835974acc160ffb876446b76affb5787b850486ae0fda86c7b5d101964" + }, + { + "kind": "file", + "path": "img_4331.jpg", + "sha256": "ed19b02dd74a5603b62e507f4d480f85e8c8f677edf6df30c841b5c280ee9387" + }, + { + "kind": "file", + "path": "img_2998.jpg", + "sha256": "716a73a12eb2afdb26cb84f1d9bc5ad4012a083af41e9a3ca6a345f20bfa7fac" + }, + { + "kind": "file", + "path": "img_1249.jpg", + "sha256": "17ccbaa57b974c7e07c95c1208f5f1da0ddace5ce47c90d911068faef23e431e" + }, + { + "kind": "file", + "path": "img_2973.jpg", + "sha256": "9e4df909300c2a41e51bfd7fd62e9fa41fb73918e8ca4170a6e1af7ca114102a" + }, + { + "kind": "file", + "path": "img_256.jpg", + "sha256": "61cce5ea583303272725a378f0c8131ba78569384981cedc5e0b6e0e68bab6a9" + }, + { + "kind": "file", + "path": "img_2967.jpg", + "sha256": "c78467e84ff236cba069ec84f7bf305ebf4740db962af16bfc2abe198d7818f9" + }, + { + "kind": "file", + "path": "img_3489.jpg", + "sha256": "c52f6bed925e56cef9c3563c026540e4fdb98dd8f141231ff2480dfd1ba54617" + }, + { + "kind": "file", + "path": "img_2797.jpg", + "sha256": "2f71189e20fd3556ab8167f7a564cc98e8ca99161363dc72a95a58b9b1e82e5c" + }, + { + "kind": "file", + "path": "img_518.jpg", + "sha256": "bb82f52af526822ca98a83fe054664f968365f30f6497ceff13d5421260ee118" + }, + { + "kind": "file", + "path": "img_4494.jpg", + "sha256": "ab11fe118e0f491aca7f2b3e7a74d3621a8b590e473bcc8b3593af4a26c051d9" + }, + { + "kind": "file", + "path": "img_2783.jpg", + "sha256": "03eda02944b097027567314c4a7b73803948a4ab36c3408755f6422e0e77f2dc" + }, + { + "kind": "file", + "path": "img_1705.jpg", + "sha256": "a721b76944b71802eaa171355fe2751b66bcea101513899848c987dc0ef26817" + }, + { + "kind": "file", + "path": "img_1063.jpg", + "sha256": "51ec48a513ddd9b2640924aba6f4c1fb8856f655f2c1f8bf09a70bc6f3e6ce7c" + }, + { + "kind": "file", + "path": "img_3674.jpg", + "sha256": "05359904a64cb9b32d963497316156da8d791f7a440a7153a5adcfa07d9113c0" + }, + { + "kind": "file", + "path": "img_3660.jpg", + "sha256": "ed1aadfd7b2463e3b6fc9e11dd50eaef2c054a998d05e366bed2f9db80f91bd3" + }, + { + "kind": "file", + "path": "img_1077.jpg", + "sha256": "f4e90f03b8c32da30f8ca244cdd2636f1d2092fe51e58082e2990d2fad4b9970" + }, + { + "kind": "file", + "path": "img_1711.jpg", + "sha256": "aa1c3b3eebab3e0bfa1736d668299391d7eac44449331fbb047a46d19888d10a" + }, + { + "kind": "file", + "path": "img_929.jpg", + "sha256": "35f7ba693f1fde29bae9826427402c368b174ba2248e930c1cf24f6ff55648a3" + }, + { + "kind": "file", + "path": "img_2218.jpg", + "sha256": "ed1b5a364caf0e0190eb017b8f7ebcfab4aedb674fc0e9a43ef35fa307221930" + }, + { + "kind": "file", + "path": "img_3106.jpg", + "sha256": "dd7574fca93819455110985a30afd04491f197719a111129b4271611d2708d69" + }, + { + "kind": "file", + "path": "img_4669.jpg", + "sha256": "e83cbfd879f0bbb8c98ad24fee205d0d45062c752d78ba5a5d2d83100055eab0" + }, + { + "kind": "file", + "path": "img_1739.jpg", + "sha256": "bfa8c67e8d9df49eb4b4cf89ec599922d90ea13113e96edd73b5afbaa580e9b2" + }, + { + "kind": "file", + "path": "img_901.jpg", + "sha256": "754eaff399949a3d7c5a270f677fd4746eb03ed905cfa5e77df44703061d21dd" + }, + { + "kind": "file", + "path": "img_2230.jpg", + "sha256": "6bf33b5d24b9951b42d6c22e1346548e34c1064985765b1f93640dd64fa25053" + }, + { + "kind": "file", + "path": "img_4641.jpg", + "sha256": "a9d556c905a83e57a5fe74ee33e45c829ed79ea10b6791145e7258a319bf1900" + }, + { + "kind": "file", + "path": "img_4127.jpg", + "sha256": "b444687fe7327d991658bf4eb10ffb031aa0871da693dbbab7aa17a0bd8e89f9" + }, + { + "kind": "file", + "path": "img_3648.jpg", + "sha256": "1eda9cd25715b96b3662854507c6974c92ad49ffd591f3cdde38c84f725d5770" + }, + { + "kind": "file", + "path": "img_2556.jpg", + "sha256": "8e202e5331c8268235539ab9cc655321f2c2507277a886816b0571bf79f572ef" + }, + { + "kind": "file", + "path": "img_3890.jpg", + "sha256": "f884955b7256c1224bcabc6e62b390767119c39d292da98ec0111bf0e81159ec" + }, + { + "kind": "file", + "path": "img_2542.jpg", + "sha256": "64fb328627217167cb55c336dc5df4ffff5c67bb8f4eb8315c0847113261a31b" + }, + { + "kind": "file", + "path": "img_3884.jpg", + "sha256": "c063689786f787e0f0fd275dff8ace03a20e498528f8888d01832a4096802db6" + }, + { + "kind": "file", + "path": "img_915.jpg", + "sha256": "e43e52f5de67b2d44b266e429a0a4876170f5192bcc9a82c47e42dc70472c8d2" + }, + { + "kind": "file", + "path": "img_2224.jpg", + "sha256": "781ec8bd712ea7623aac63751665af9037b2d89fb5b9bd0e3dc32d6e47c0db32" + }, + { + "kind": "file", + "path": "img_726.jpg", + "sha256": "6fa2091d19ebad324c58fa6bd1864083c5afb6661b9b018ea151b335827e3366" + }, + { + "kind": "file", + "path": "img_4866.jpg", + "sha256": "68fab42db6dfee7a8a7a57ae7d73e2c63a65c9ad50082f766e3d04ba9b69e599" + }, + { + "kind": "file", + "path": "img_732.jpg", + "sha256": "e45bc44ac21b6c0504d75b2aa08684b7e0d4e53bd590f92d27d228c650a51563" + }, + { + "kind": "file", + "path": "img_4682.jpg", + "sha256": "fd311f6609ec17f7cc187700f48b15dbb473c55042343e524ca4ccd57b326d09" + }, + { + "kind": "file", + "path": "img_1922.jpg", + "sha256": "1a05aa241051ac42e9426570eb8245b82ca5d15798ec1cbe8d1477e46bdb8a7b" + }, + { + "kind": "file", + "path": "img_2595.jpg", + "sha256": "55ce2ffe54471d5c7dba5adb42aac43ffbdc4a45dacb207e14dd11492f2f82a4" + }, + { + "kind": "file", + "path": "img_3853.jpg", + "sha256": "606d2601573650827fc2bf4de393ab40f8b281c05c045813122cdfc831071b4b" + }, + { + "kind": "file", + "path": "img_2581.jpg", + "sha256": "1fc075a0cca123cce40d49651e2538446e204ff4e36b72131aab5bc757b12844" + }, + { + "kind": "file", + "path": "img_3847.jpg", + "sha256": "a03a1763e18b144e2c690467fb287af1083d34dd738a5cb548eb2e2c9a2125c8" + }, + { + "kind": "file", + "path": "img_1088.jpg", + "sha256": "a4a9d2447c7c8020d4218960db2bdf30ecc6ab0d56acafc861e6da9543412d6f" + }, + { + "kind": "file", + "path": "img_1936.jpg", + "sha256": "a672c5985bf54e27536f40d3cd1461330462afd6a135b0ea48f7d180c88baf25" + }, + { + "kind": "file", + "path": "img_4696.jpg", + "sha256": "0a0fa8c06f135fe73c39917a67cdc4940d3dcc8922d2f7d007a529eb1a24d652" + }, + { + "kind": "file", + "path": "img_4709.jpg", + "sha256": "df1603ea53f777559ff8190cf4b582a7a647628b0c2be8a6d48133b308118c9f" + }, + { + "kind": "file", + "path": "img_691.jpg", + "sha256": "ab43196394cc90119952356d663e4e02a6cd1de7ca5208bc00465f29049a45bb" + }, + { + "kind": "file", + "path": "img_3066.jpg", + "sha256": "3ee975c477b83a7cd1df71a67ea8104fef8acea187b71aabe33f309de602f1e9" + }, + { + "kind": "file", + "path": "img_2378.jpg", + "sha256": "db9a24059a966ec1d4b5412cf1414e72090e69b53097a9c0ee8af8ef28ba99f1" + }, + { + "kind": "file", + "path": "img_849.jpg", + "sha256": "c5aa574c35add6875ae8100cd335465dbc91f333e7c91a6ba8d2c953c53e9029" + }, + { + "kind": "file", + "path": "img_1671.jpg", + "sha256": "63d1353e0666cae9b8c3085078da12923dbd5349dac7e19f9a2faa44a5bbcf50" + }, + { + "kind": "file", + "path": "img_3700.jpg", + "sha256": "d1eb11bd21b248be414a0d5ca25d0505dd3a7f37562be43ae5cf54c4652bba73" + }, + { + "kind": "file", + "path": "img_3714.jpg", + "sha256": "ef03b7b6648dec11fa5488844b5cfea9b940a420e0e55678340fe7908cce17e5" + }, + { + "kind": "file", + "path": "img_1103.jpg", + "sha256": "50407899dee6210d82c7e54bd20afc84f45384b8b13547185af433598d1bbb26" + }, + { + "kind": "file", + "path": "img_1665.jpg", + "sha256": "f7097782451df66e5eeb50c7c8a338345e8642489c0935d28245f77be95dcba9" + }, + { + "kind": "file", + "path": "img_685.jpg", + "sha256": "b7c75ad4e718a539d3a882cf3f270876f32974199ed5bc54ff4fc0f3e18366ff" + }, + { + "kind": "file", + "path": "img_3072.jpg", + "sha256": "c503277b99dd1fc79fba8749b3c47673e06c1579f2ebbc461b04429afc7c10aa" + }, + { + "kind": "file", + "path": "img_1895.jpg", + "sha256": "50089c241c1792a00ad753d6f00402ef981f526436b657195075129958e933c0" + }, + { + "kind": "file", + "path": "img_4735.jpg", + "sha256": "22afc3d028d5c90fe42110718c0299d8a668604a46d3b9398e63880f26c99534" + }, + { + "kind": "file", + "path": "img_2344.jpg", + "sha256": "09d18bffcfb19f86a5b35b799cbc53a1221e551a7b1dc4a406c74fda108974ad" + }, + { + "kind": "file", + "path": "img_2422.jpg", + "sha256": "6457ae417e466cc394c8291e0914c7d117861f38e440acaf7c9246f5ea41e642" + }, + { + "kind": "file", + "path": "img_4053.jpg", + "sha256": "d9e42af7628f51cbc510311ce602a4a32ba8334e0b8edf6c97e9342015487455" + }, + { + "kind": "file", + "path": "img_2436.jpg", + "sha256": "ec641a4e492f4730edda624a4fd0e499684954631dc24360cf7faa416dd35aae" + }, + { + "kind": "file", + "path": "img_3728.jpg", + "sha256": "0696910d4b6cf43e7551906b0e08e85dc94016c92048a0e0944a3694125ae5d2" + }, + { + "kind": "file", + "path": "img_4047.jpg", + "sha256": "0e8d49903de76cae9d0b51aa490cef59b6f3fe3aa670ffeae8283b9e29c58254" + }, + { + "kind": "file", + "path": "img_4721.jpg", + "sha256": "39e522c0cd07f5d25f7ca228edc91fae2b908c8ade113588363cb4f508e1809b" + }, + { + "kind": "file", + "path": "img_2350.jpg", + "sha256": "5887305b1b5605c11cb78e56dbfa90f8d364ef04d13f4e6145da50eee795144a" + }, + { + "kind": "file", + "path": "img_861.jpg", + "sha256": "8758a24dc30de393f43b2efe033eefa5172afe8484bb17f8a2a217cbb30da356" + }, + { + "kind": "file", + "path": "img_1659.jpg", + "sha256": "fbcf2e7b298598bdfd31edf6883e10645a85416340a18437da38f58549491ae5" + }, + { + "kind": "file", + "path": "img_1881.jpg", + "sha256": "78670f91d1a38ec99102bf4d7cfc71021a7c2b05d17073d0553d1c3cfc3ee0f8" + }, + { + "kind": "file", + "path": "img_4912.jpg", + "sha256": "a5013065b8d010516219b2e2dd2e8cee73a689b45ef076e121f0e286aa7c6ce2" + }, + { + "kind": "file", + "path": "img_652.jpg", + "sha256": "e748ecbb36dc365bc1978bf8753011bca28583ee01530796445cf32fdd8772d2" + }, + { + "kind": "file", + "path": "img_134.jpg", + "sha256": "33b87dcf1c961ad79267097ff2689c0c9a1ad38bee8a3190bfc9611ce9e173cf" + }, + { + "kind": "file", + "path": "img_120.jpg", + "sha256": "6172f68a566333af941161d857579da9565a23d945c989a484607f04e60f2368" + }, + { + "kind": "file", + "path": "img_4906.jpg", + "sha256": "dd99051200cf796e0d4500a2943d73dbb1bfcc6adb0e6f48e78b9695969ff2df" + }, + { + "kind": "file", + "path": "img_646.jpg", + "sha256": "11f0a5cb1950bfe14379d2ebd11bc6074ae59dcc672bcea05f56f2e220b2fc11" + }, + { + "kind": "file", + "path": "img_2387.jpg", + "sha256": "9b8325230156fa287ed31feb227eacdc251ab321118c45225b81ef9c5a4b11c3" + }, + { + "kind": "file", + "path": "img_1856.jpg", + "sha256": "888c29059ccd8086bfe570f66908f6feb7379c803c4029c55f4efb355fa0d282" + }, + { + "kind": "file", + "path": "img_108.jpg", + "sha256": "8f767b4de9f6986d5904e5d141e84ecc93357041fe0c1e5eeacc0c4ce518531e" + }, + { + "kind": "file", + "path": "img_4090.jpg", + "sha256": "56c843aa28951126da37512ea49790df6ed1260cc81b74ddc525b3894d09983e" + }, + { + "kind": "file", + "path": "img_3927.jpg", + "sha256": "2ab32fc278d34349cfe37356b896d25a1263b59b015624ed45cde78be68767b9" + }, + { + "kind": "file", + "path": "img_3933.jpg", + "sha256": "f5279bfae94b05f5b6074a5143e256ef438d140bfe0e37288e0af964798fd2cb" + }, + { + "kind": "file", + "path": "img_1842.jpg", + "sha256": "7e0681f54e846a82472dfad5dfcb9da0621837a2001ebc5c3ca3ea01e27df6ad" + }, + { + "kind": "file", + "path": "img_2393.jpg", + "sha256": "09433d7c41b4ceefb87d827efe20b27a5e7bcb87398ded1c36f384ddefb6cd00" + }, + { + "kind": "file", + "path": "img_3502.jpg", + "sha256": "60f0c52db98fcf164de5b9061b35961ac64c95842c3e6a7717d422228573b7e5" + }, + { + "kind": "file", + "path": "img_1315.jpg", + "sha256": "4178fda4ee3c5becc4452a19eb2f7028816685d4b3509950390f7e7c279a2407" + }, + { + "kind": "file", + "path": "img_1473.jpg", + "sha256": "3f902777698bad5c60197c84026468b266dee2846b97311d40fa795825f656f8" + }, + { + "kind": "file", + "path": "img_3264.jpg", + "sha256": "51fb84dd2c670d0fbdea1ffcc18ffe82735428c9027192886204ec73b018a9ac" + }, + { + "kind": "file", + "path": "img_493.jpg", + "sha256": "61a3a7c2f57dceb9fcfb80d6cbf54b6bc5290a3d81d7511a52ae2889f5750de9" + }, + { + "kind": "file", + "path": "img_3270.jpg", + "sha256": "5e692b9bd3119b4191046ef429be8fc3d37bf3c1b57e31fe9e6285276e8844ab" + }, + { + "kind": "file", + "path": "img_1467.jpg", + "sha256": "f95301575dea44b5176c9bd1331ebe30470d21bceafc8de7c4592387cec118d6" + }, + { + "kind": "file", + "path": "img_4279.jpg", + "sha256": "4b661a2ac9cf9b63cef56f39d5aa5ddc2ed7aa1a69c6edf9a53fc9da3e1d1592" + }, + { + "kind": "file", + "path": "img_3516.jpg", + "sha256": "22a522988488d9c82b35576b35879fa9ad1f028ac7b6c18ddc31edcdd2b7e76a" + }, + { + "kind": "file", + "path": "img_2608.jpg", + "sha256": "805acab428249aeee36c2afc36be38de40986e6e95a33125fb41c42b615ce027" + }, + { + "kind": "file", + "path": "img_1329.jpg", + "sha256": "f479cea99dbe2998b7979e650d74e45a2c45188654e7fffe2b55d0166ee7c184" + }, + { + "kind": "file", + "path": "img_4251.jpg", + "sha256": "b467f6865a7d53db6f8a65b6121eeaceda60ba5cc5d591e8823778d9d10cca8d" + }, + { + "kind": "file", + "path": "img_2620.jpg", + "sha256": "58c99c7f65ba4f1e939c1ce908f869e9457d78dc18500ef4788e77744898bcce" + }, + { + "kind": "file", + "path": "img_33.jpg", + "sha256": "9a3f57a3f67c559396be8035f6ecfb393ebc7285ecb468657d6847bb36396bd5" + }, + { + "kind": "file", + "path": "img_2146.jpg", + "sha256": "0f0747fa48b27c31978103ac707ff787211a4ff58b46f6cec492e173e30ffc4c" + }, + { + "kind": "file", + "path": "img_3258.jpg", + "sha256": "559aafd922efb0409d489aef65b9f1ebb51267f9b03216a09cd1398a3ac152f3" + }, + { + "kind": "file", + "path": "img_4537.jpg", + "sha256": "13a336715a17eb0092e19b5fc4faaa9d99fdd7edc6f3a3b25521d42a9244651a" + }, + { + "kind": "file", + "path": "img_27.jpg", + "sha256": "ade47b89afa104a8bc3ac5caa34d0ad3f6bf77182fbf4f2b71c7f5c06e2f6dce" + }, + { + "kind": "file", + "path": "img_2152.jpg", + "sha256": "5609185687f89180631b66b05b7b83d444b6c94f613bda37b0413ed822df1674" + }, + { + "kind": "file", + "path": "img_4245.jpg", + "sha256": "3df6438c0a9b640e71dcaf9a3521d9956689f878ed12534ee6678f80c170d4a9" + }, + { + "kind": "file", + "path": "img_2634.jpg", + "sha256": "4cc15b8fd244623313754145fc6c990d3b5eefcf8bdc56d9c186410d0cd2ad48" + }, + { + "kind": "file", + "path": "img_2807.jpg", + "sha256": "44f48815ffedf353532d8164262b216fe4c96bb506c956bc0d88d986d9f7384a" + }, + { + "kind": "file", + "path": "img_450.jpg", + "sha256": "a672bdb866233ad75b07f16e7317bb0eb9501692f2e748e781c0e4c0e86589cc" + }, + { + "kind": "file", + "path": "img_444.jpg", + "sha256": "fdebacd6335430ff8ade2addbb3f8cf33de6b7e3701f8a772711a6124401c76e" + }, + { + "kind": "file", + "path": "img_2813.jpg", + "sha256": "aa6c67a63d38dd57b8d4d888d6ec7f0eb21133eb426712b6ce015539ccb13b69" + }, + { + "kind": "file", + "path": "img_322.jpg", + "sha256": "a077b6e6abf3a2fd128f7a9ea19a67622bb4466009360ca1ca9388879ffa4361" + }, + { + "kind": "file", + "path": "img_4292.jpg", + "sha256": "289a533acf0a7b401397e7cdfd76a3143a22ad2a1be3c1c7733ed7dfa5d7fb6b" + }, + { + "kind": "file", + "path": "img_2185.jpg", + "sha256": "743fbd632c2a5e0d31947913b22b7e634254a194c0b3a22ddec840a550eaa6ea" + }, + { + "kind": "file", + "path": "img_478.jpg", + "sha256": "bb4a74600e248ec4a4556dda3f760b55d520d6cbeb4465d1eec6579189eeacf5" + }, + { + "kind": "file", + "path": "img_2191.jpg", + "sha256": "4ccaf7b498b862dcd41bc98847ed6254c7333d4a37fb9efe5ee7cde4bbc69b4d" + }, + { + "kind": "file", + "path": "img_2817.jpg", + "sha256": "8585cf22404f4ccfc52c0bfae9df5fee052f39be0f5df54e4b33ae70233db7c1" + }, + { + "kind": "file", + "path": "img_326.jpg", + "sha256": "11ae083d14075d8cb1a74d1984e358aaba58946a4ba6db2048e913f08e3e6884" + }, + { + "kind": "file", + "path": "img_454.jpg", + "sha256": "ff4c11639f31603e33fb2937402bd582a5468739b4ff6e920199d0ee752b94e3" + }, + { + "kind": "file", + "path": "img_332.jpg", + "sha256": "ec82d65a99bd00536af84050b65a3f4b93065da5fe15721a369493f6ec4798c6" + }, + { + "kind": "file", + "path": "img_4282.jpg", + "sha256": "68ea021de79cc4dc51ea964266a15da2b6010e966f513c9bd1dadd1bd71290b8" + }, + { + "kind": "file", + "path": "img_2181.jpg", + "sha256": "b5fb5484214efb187d175fbd036ddcb3ceef8534ff83e10c258f8e20317698d6" + }, + { + "kind": "file", + "path": "img_1488.jpg", + "sha256": "11521323143694afacd0b5a07969fab061628a885773048b27a984038a97c53c" + }, + { + "kind": "file", + "path": "img_4296.jpg", + "sha256": "1de1a805578ecdad394175400ac59a36dbb284aafb7df9efdcb50cf7bab41c03" + }, + { + "kind": "file", + "path": "img_3512.jpg", + "sha256": "d243fdb03df4801fed4bfc454a13920d24fe098be8da7c188e159f81e5f86da4" + }, + { + "kind": "file", + "path": "img_1305.jpg", + "sha256": "c07203ad4482c72c2c808f07c78c5e7d745284f353f8301af5fa7a108d3c9427" + }, + { + "kind": "file", + "path": "img_1463.jpg", + "sha256": "47d100b7e19ef5cadf9980a4886a9bfb3dee5b48ef2631f2cacd1b96218282d9" + }, + { + "kind": "file", + "path": "img_483.jpg", + "sha256": "1bdc3ae542613e94abf5ae13b5a0357b27c75dfb3afcf417ffdcb19a004ab54d" + }, + { + "kind": "file", + "path": "img_3274.jpg", + "sha256": "e12922568424b2baa779b77753b24cf0222482d5f15e68e4d79071e2b3e995af" + }, + { + "kind": "file", + "path": "img_497.jpg", + "sha256": "ae5ba4a6723e208b1fe1667b8edd44bc906eaff86bc0b5965cb3b772ba45e94d" + }, + { + "kind": "file", + "path": "img_3260.jpg", + "sha256": "5877ae6d2f3c3e75e8e66de09b84caa613631001d9e39718ab9dcc1ec6bd3e11" + }, + { + "kind": "file", + "path": "img_1477.jpg", + "sha256": "dcbbc5eccc9c0de544f5274a932317332fa110e56434a7295fc43e47052d60dd" + }, + { + "kind": "file", + "path": "img_2618.jpg", + "sha256": "72cf6206542ce29362d4a9992084490fec852b22b476ab423ae8912bc168da41" + }, + { + "kind": "file", + "path": "img_4269.jpg", + "sha256": "47a1c2aabbb2efdd01cef99ed3c2b890ca6a30e89a66efdc7fb1e8a2c8e17799" + }, + { + "kind": "file", + "path": "img_3506.jpg", + "sha256": "4f4f41430b2f2494f43fd356761edc0c31c93cfd688b98a43f284def1b1381de" + }, + { + "kind": "file", + "path": "img_1339.jpg", + "sha256": "9d4695dbb0508534c12879dc5b94c6750189c32fdb22c72b8e8ed26be9af2941" + }, + { + "kind": "file", + "path": "img_2630.jpg", + "sha256": "d23228b17f4bcf049aec9e9f93f7c3ed4235d3bfe578ac4cb8526a1d5ae284ce" + }, + { + "kind": "file", + "path": "img_4241.jpg", + "sha256": "65aead0b30df3d39805763da3f6373c59101b0dd22d9ba56b950f5d946e967b2" + }, + { + "kind": "file", + "path": "img_3248.jpg", + "sha256": "b189e418e8c197cc3fb9c6ddb6c6c7df85f8ad08496ba4bce93d037cd389709e" + }, + { + "kind": "file", + "path": "img_4527.jpg", + "sha256": "8e8813f84d6bd038589e06dd31da5c6427ade02254f7047cf0f2044f05dfb352" + }, + { + "kind": "file", + "path": "img_2156.jpg", + "sha256": "cec9d9faf37a1f98daab65c0d6c99b3f0e573de8e16403710dc3ef970ed354cb" + }, + { + "kind": "file", + "path": "img_37.jpg", + "sha256": "145adaa968ec97b94ff3fc0adcb6ed361227a26ee4cd217a423983b143737f7e" + }, + { + "kind": "file", + "path": "img_2142.jpg", + "sha256": "4af9df169636d30144c89afffcba03901655e3c55ae372a89886c319860c7ebd" + }, + { + "kind": "file", + "path": "img_2624.jpg", + "sha256": "37d9dbeab6978e658d520424b19376a4a3803a2b51ec9bdd93afc833d645a4e8" + }, + { + "kind": "file", + "path": "img_4255.jpg", + "sha256": "51391bed6041dfe691145db11f5a6c0261d52cc1835f46743841cc56c350955b" + }, + { + "kind": "file", + "path": "img_642.jpg", + "sha256": "035240f5640f968f953db2f5c381097852df0f80538da9932461a218e811b187" + }, + { + "kind": "file", + "path": "img_4902.jpg", + "sha256": "91b2ea3f86596dedcef69917a325fc96d70238702cd0aa5fbc82c1c9fd374062" + }, + { + "kind": "file", + "path": "img_124.jpg", + "sha256": "43420d942ee77973d7f311c9d740b0f128f720ebf9e83878490e5a9b8c9d30bf" + }, + { + "kind": "file", + "path": "img_130.jpg", + "sha256": "2e4faef234f3f9729979be89a53f82024b3e9f660a2960c179164e96860c3a9f" + }, + { + "kind": "file", + "path": "img_656.jpg", + "sha256": "b267ea950fc52edaa912f199327ee3c76638d68c393bdc1a376967740b32c74e" + }, + { + "kind": "file", + "path": "img_4916.jpg", + "sha256": "d70d36e9211a108b83873e10fcfb029654936ee9b5c9d1368c5a1d0ba8175fb9" + }, + { + "kind": "file", + "path": "img_3089.jpg", + "sha256": "e2778b261f6df164b38dabf7fb198d281e2cf4d768b5c8959126b007e4cae749" + }, + { + "kind": "file", + "path": "img_2397.jpg", + "sha256": "eadcfa7346db4b52b23b2078434d0d151eb49ca5720b601992a1be99373ce400" + }, + { + "kind": "file", + "path": "img_1846.jpg", + "sha256": "aeb7ef384bb6a90f872e79b9904efa6fe92c9a0d9cde2ddb1510f7cd5b3480df" + }, + { + "kind": "file", + "path": "img_118.jpg", + "sha256": "cfb9e799b007db8ff0c7a3950a5e2ef0f473297ff583f011294b030c66e80536" + }, + { + "kind": "file", + "path": "img_4080.jpg", + "sha256": "3444d5844dac40aa82470021e8ff28fda3ab3d3ec1ede40e4d9fb972a6b6587e" + }, + { + "kind": "file", + "path": "img_3923.jpg", + "sha256": "81d7766de0d1717af8bc2e1b3b0448ef1b4b8ebbbfe03f8b458e1ab33abdbfd3" + }, + { + "kind": "file", + "path": "img_4094.jpg", + "sha256": "0bace469431bcae73ce2c8e4a92d8ed572dfeddc9e0fec129598ccb23eada22f" + }, + { + "kind": "file", + "path": "img_1852.jpg", + "sha256": "fc02de2ad2f6769b9612e0c8c82c3896614367a0db1926178ad0b95f46deaf84" + }, + { + "kind": "file", + "path": "img_2383.jpg", + "sha256": "b7de9831822192b6adc4a3000170ee7548b3d7fb18b414d55127975211792fa8" + }, + { + "kind": "file", + "path": "img_2368.jpg", + "sha256": "cfcb044fb8c3af24e57822b0c329a42c400f1e52bc9ad346c785912d8de162da" + }, + { + "kind": "file", + "path": "img_859.jpg", + "sha256": "a395a84d2992c8cacddff95cad18ac080d834c6c8c94233b5c2b61b69661fe0e" + }, + { + "kind": "file", + "path": "img_4719.jpg", + "sha256": "2b5e71939251c95b886467bebcb9c15dad7f5a25d6785795a2f74a6fcc96825e" + }, + { + "kind": "file", + "path": "img_3076.jpg", + "sha256": "a57cda61d2788af836021733a0adbac9c8242f60b7152c8de0f989854fb7ec7f" + }, + { + "kind": "file", + "path": "img_681.jpg", + "sha256": "de21d2443025390a0979604a460311163bc07e38e18c0812aec882195221d382" + }, + { + "kind": "file", + "path": "img_1107.jpg", + "sha256": "d79d486066614d359301c66a5eda330757092e532558e97c9437767a254ee18e" + }, + { + "kind": "file", + "path": "img_3710.jpg", + "sha256": "1eb699ef5135f0aae4d9eef2d57df863561994b0732d3f2954b78562056d7737" + }, + { + "kind": "file", + "path": "img_3704.jpg", + "sha256": "1d5d79288b805685c6db3eb9a11b390b30dd97ca343ae0128fb139021c44d1fa" + }, + { + "kind": "file", + "path": "img_1113.jpg", + "sha256": "3db67d425f2a0619c22cc3cb72d9210e6cb9ee80bca790c0060f4122a144cfcc" + }, + { + "kind": "file", + "path": "img_1675.jpg", + "sha256": "6988e2352faf55362218b755ce98dfcb703a425a71b9397e28968b711a3e4b83" + }, + { + "kind": "file", + "path": "img_695.jpg", + "sha256": "78c650bfff18c7addfb03f19b70bf3a742820a470f7cb9abe27d89747a2d73ad" + }, + { + "kind": "file", + "path": "img_2354.jpg", + "sha256": "4b66ce98a7c68f4b2ce729a10ddd9d306f232fd9f13ea987025c36c6468bc13c" + }, + { + "kind": "file", + "path": "img_865.jpg", + "sha256": "ce0a0151ee7455939d9d5ea4c92613db25b5cf420d73326a2b9c8c6bfa9b56d2" + }, + { + "kind": "file", + "path": "img_4043.jpg", + "sha256": "98e89624e4b1fa81a1749d35e323dcf3162f35c48532d623a8f105d73dd1f666" + }, + { + "kind": "file", + "path": "img_2432.jpg", + "sha256": "7269e7213ad7423a08400f985cf85e9d0b9acc3408359f356534aa8c5bb608bd" + }, + { + "kind": "file", + "path": "img_3738.jpg", + "sha256": "c4a7556d3369c75d8cb7e128300aed8597f254871a13fee7b609c4b9f60b0ce0" + }, + { + "kind": "file", + "path": "img_4057.jpg", + "sha256": "c32cb1181229a590729710c49ce87b975ced859ab95d8e56abdf8e3a2f99a898" + }, + { + "kind": "file", + "path": "img_2426.jpg", + "sha256": "e5236937affc1c5273abaca396127e8ae3f7c1e6d8d1b2a7410ccea74030c65c" + }, + { + "kind": "file", + "path": "img_871.jpg", + "sha256": "b033592415b585bedfed91bdbdc6e2b5cec2bff03416b49fbe2092064e84891a" + }, + { + "kind": "file", + "path": "img_4731.jpg", + "sha256": "56ff293edf8eec33274dbd02b52c86135f0abe01635a5092269ca34c81f27fce" + }, + { + "kind": "file", + "path": "img_736.jpg", + "sha256": "eb0b430e7edbc88fd87063f19150c765a61a7dde9777f04e6bec75a401b0fd0a" + }, + { + "kind": "file", + "path": "img_4862.jpg", + "sha256": "1157db1ebe9f66cc50bdb46036a528c861f7f56725188f82db7c1b48c2158b47" + }, + { + "kind": "file", + "path": "img_722.jpg", + "sha256": "726aead35aec51058184d67f51b56c8dbd29166e272243472d49fa49ac717d12" + }, + { + "kind": "file", + "path": "img_1932.jpg", + "sha256": "bd35f48f6a10d37adf9b0849820da73bfc977ad448a907a8d61ede2f00852796" + }, + { + "kind": "file", + "path": "img_2585.jpg", + "sha256": "03a1249219a8d94a20bbd145e1289972408d94a334526ec7cd9d58a7610c30cb" + }, + { + "kind": "file", + "path": "img_3843.jpg", + "sha256": "11ab4bb74a9998d54ed53b8639bae1b306ad6e239c64c06612ce09266dadd036" + }, + { + "kind": "file", + "path": "img_3857.jpg", + "sha256": "63bfe0b9afbc0efdb966cb77b88c4e55c7a864a198f90ab6784bf9ce3da4d8b7" + }, + { + "kind": "file", + "path": "img_1098.jpg", + "sha256": "c485eb3137853d731d57fa56ecf146ae57c708f74507a42051906e1474687e7d" + }, + { + "kind": "file", + "path": "img_4686.jpg", + "sha256": "d49f7d17ee7e98cfdde76a8db38174fedf50caed07f9156bb0195958bfbcac14" + }, + { + "kind": "file", + "path": "img_3102.jpg", + "sha256": "4b83703a2017bd973484ee52625da1ce6b30ace7f1a596b718746645ae24557e" + }, + { + "kind": "file", + "path": "img_1715.jpg", + "sha256": "a909f2a912bd7e42badbb662f584e3eb91af8acd93311f820be2abcee4d32113" + }, + { + "kind": "file", + "path": "img_3664.jpg", + "sha256": "6b042a38ffc65420d39f30662ad56920faaf0f19569d249413bbe74734b312b9" + }, + { + "kind": "file", + "path": "img_1701.jpg", + "sha256": "0ed2544f4af452dbdae74730be516031e29476a149eb437683f46573f85f504e" + }, + { + "kind": "file", + "path": "img_3116.jpg", + "sha256": "a091d203338f71e260ee87fd7fc67a55dee0e950a9e52fe846e07e953a749753" + }, + { + "kind": "file", + "path": "img_4679.jpg", + "sha256": "5ccfd15696d0fc67dc5b8ea66690c6773b5bc779cb864b058706631cf9e72949" + }, + { + "kind": "file", + "path": "img_939.jpg", + "sha256": "df881b9baad06b92f8c82b6f4494da979574e8b6b3abfc4dbb5ae1c6d3b7d548" + }, + { + "kind": "file", + "path": "img_1729.jpg", + "sha256": "62f1073e21f296e95e7b46f3223684d72ae391f1c0be8678c76415073f5971d9" + }, + { + "kind": "file", + "path": "img_4651.jpg", + "sha256": "95128b404892e9324e89044e26e7f2d81d31ee068129b865d9186517ce9ae38e" + }, + { + "kind": "file", + "path": "img_4889.jpg", + "sha256": "89cd66bbc6ca7f07f0688df0d7b77f5fd2758c27fd01c560f3988a267eda0ad0" + }, + { + "kind": "file", + "path": "img_2220.jpg", + "sha256": "0ae3307692f753e303e6b11a24eb8057374c71a0102ef667e010d1416190e4b9" + }, + { + "kind": "file", + "path": "img_3880.jpg", + "sha256": "5065430968fcb5501b782ac245aadc6122b9b025163cf3ec22444f11f9fa17f6" + }, + { + "kind": "file", + "path": "img_4137.jpg", + "sha256": "2219b1fa0c4bef4c267a66a8f7c483888e3a75c5517b6d5750e8d056699d6780" + }, + { + "kind": "file", + "path": "img_3658.jpg", + "sha256": "a449175af547b58ac92bfde2e03672d9ffd4a26e5fe108a93f676c83e1ddfd16" + }, + { + "kind": "file", + "path": "img_2552.jpg", + "sha256": "17b76f2a37ef649732fc4f0bf26f31690be0975d00af77e047845507ed2b179b" + }, + { + "kind": "file", + "path": "img_3894.jpg", + "sha256": "acadba2194be7dea63e6c7785f4fa066609dca935f6e6c76f2ffa0b77e67318c" + }, + { + "kind": "file", + "path": "img_4123.jpg", + "sha256": "144556e6f89c0b9d891446b91a2d3a20084777982665a5dd4517f549cd29c822" + }, + { + "kind": "file", + "path": "img_4645.jpg", + "sha256": "d3f621a7a0375a5c977951a2466642668ed820a438237031ca775d206d5f06c7" + }, + { + "kind": "file", + "path": "img_905.jpg", + "sha256": "d630a76ba3024cdcd4d31995c5f6fadbd94e04439cf052f496caefd1153d760d" + }, + { + "kind": "file", + "path": "img_2234.jpg", + "sha256": "2f053add4e0efc4c29bc76d8192bce370b713b97db0e4f476c40562792b6a562" + }, + { + "kind": "file", + "path": "img_252.jpg", + "sha256": "872d51ddf654a6a374b705aa5a5bf763c2499f1e9daf0f9177b189843047f6e1" + }, + { + "kind": "file", + "path": "img_2963.jpg", + "sha256": "5204fa27ecf16e0ccb99fdddbb59c2a212b8668d993974da7d1acdb280e8c955" + }, + { + "kind": "file", + "path": "img_520.jpg", + "sha256": "ff3d8bff457c525585a4ad74856df5ceb125e3ce20c85b2762b7e6fd3beaec0e" + }, + { + "kind": "file", + "path": "img_2977.jpg", + "sha256": "716f8a05eae1a5496a22153622d9727784d74c60c26f8f29727b031a61cd132e" + }, + { + "kind": "file", + "path": "img_4490.jpg", + "sha256": "0c021d0e93022408882ead83132147e26c52a8ba80d93f071094354d65a529c7" + }, + { + "kind": "file", + "path": "img_508.jpg", + "sha256": "9ef2ee3893065cc5e980989fb80f9c66b830c6a9deb594babc93aa204d43c4cc" + }, + { + "kind": "file", + "path": "img_4484.jpg", + "sha256": "7258e188d71fdfdd0b4b7d95f1ae312923e4fedea7f9978fe79cdd4226418b65" + }, + { + "kind": "file", + "path": "img_2793.jpg", + "sha256": "932df027ee2581feee33c5812b507340a257e3e4478d24f64a25e703be56226a" + }, + { + "kind": "file", + "path": "img_291.jpg", + "sha256": "d7c50b750376e7959c90f0e270bea3a594cffe3d6f2a232fe5afe045eae92706" + }, + { + "kind": "file", + "path": "img_3466.jpg", + "sha256": "12150eb5fc604e1c5bdb2405d4a403cbd921ea129a8ee31d16709ea8a9835f55" + }, + { + "kind": "file", + "path": "img_4309.jpg", + "sha256": "45f70f5f192ef2734c6ea6ce18ca83486abee20fefc80997e2ce68425505e398" + }, + { + "kind": "file", + "path": "img_2778.jpg", + "sha256": "32619ec02b3ec611397c08e35aedbf8f6d60a47aaf8ae5b8a8c546384433a1d6" + }, + { + "kind": "file", + "path": "img_1271.jpg", + "sha256": "2e9a7546b708b28cb486ee2924a9fa640acdd50c31d1bbc7a455085386d547c8" + }, + { + "kind": "file", + "path": "img_1517.jpg", + "sha256": "6f49f12cf25fd784a91de6a23a0a49387d5d69ff3371c285b5ec52682fe59842" + }, + { + "kind": "file", + "path": "img_3314.jpg", + "sha256": "84af1520bb7860b1e39b9c13192d9c74473fc7a50719e498a3dfcfbcfa41d44e" + }, + { + "kind": "file", + "path": "img_1503.jpg", + "sha256": "178d77b073b8ec3d95c8c5216f135d53b419fd30d76d117e8e9db2084f33f4b2" + }, + { + "kind": "file", + "path": "img_1265.jpg", + "sha256": "bae69aa870514222d97ae5df252954692a080f15f2c2b2456e676f1a8c2b9c45" + }, + { + "kind": "file", + "path": "img_285.jpg", + "sha256": "04160d9a0afc931f1e8e6ed5105244a7c5b16065c54cb91971b57cf834aa436c" + }, + { + "kind": "file", + "path": "img_3472.jpg", + "sha256": "663668f4ef18d021daab09a66656e52ac6d3822518ab66978b29243031fe6662" + }, + { + "kind": "file", + "path": "img_4335.jpg", + "sha256": "bb3d01cbaf181e1e7cb0d22fe3d8d3c40451604a465ea31d11fe3ec81df1d6cc" + }, + { + "kind": "file", + "path": "img_2744.jpg", + "sha256": "27e7af74a9798a2c2ea721e84fc0a272e8a5ccc5e27774eae0e527fc2cc4cc4f" + }, + { + "kind": "file", + "path": "img_2022.jpg", + "sha256": "b9bf7f51b7ca20cf36c973f8f7d25754ed1936db35a296926084e85b85b8de82" + }, + { + "kind": "file", + "path": "img_4453.jpg", + "sha256": "373ff982d1d102f3037ba37c4def1a89ed68d3f6fb83d3cc7179671bf0ec1750" + }, + { + "kind": "file", + "path": "img_2036.jpg", + "sha256": "3cf9f44b5b6c7d767dde8fd8f658028580fe6280343248c36375c3a8eb95965d" + }, + { + "kind": "file", + "path": "img_4447.jpg", + "sha256": "3e26c9fc75ce8376be2b27501fd83383da14e227e376184e501c67dec9cb62c1" + }, + { + "kind": "file", + "path": "img_3328.jpg", + "sha256": "a117741e89fb87d249ce6e6ecaffb8d835f310ac45d54d3f6d4f25138dac4539" + }, + { + "kind": "file", + "path": "img_2988.jpg", + "sha256": "2fd5c218f647fef20ddd29f58e0ed884edcdf81cb1870019628af1bf11106a3b" + }, + { + "kind": "file", + "path": "img_4321.jpg", + "sha256": "ffd2fa79714b1349e0d6cfaa27c6c97c22e45e030468a47d67c082a9aa87b9ec" + }, + { + "kind": "file", + "path": "img_2750.jpg", + "sha256": "a47abea7ae166349fa23befa51491dc9a3c3687a2f2c49bf2ec21ef4608ba3ce" + }, + { + "kind": "file", + "path": "img_1259.jpg", + "sha256": "bfe05dcdb2d4f5545c093ee39ba38de4696d255158a876b51de8075d8b1bd91d" + }, + { + "kind": "file", + "path": "img_3329.jpg", + "sha256": "1faf9e23a8ce6bf6f9f78e268e949f8f6c8f88f329c82321b04efd4a60e990b7" + }, + { + "kind": "file", + "path": "img_4446.jpg", + "sha256": "ac2dbdc16b78e8e8f5597260b3247e5268ccae99dfcda9cde911ac63bb44a8ae" + }, + { + "kind": "file", + "path": "img_1258.jpg", + "sha256": "6d4e96306b47c5a180a439c957b2598997ea28e910c86c8e7257c9439a62eeee" + }, + { + "kind": "file", + "path": "img_2751.jpg", + "sha256": "79a8b576372f9e745dfb8ce2b864e4da53b5932498a61a36fdb6bfb53c3b1ee1" + }, + { + "kind": "file", + "path": "img_4320.jpg", + "sha256": "9c9cb62352155759f283f3f668567171d404d70dcab4ece365315c3f071c92b9" + }, + { + "kind": "file", + "path": "img_2989.jpg", + "sha256": "8eaac26086a316750442c63b8d649f0e9cbcef389df22c515fba07003d11b72d" + }, + { + "kind": "file", + "path": "img_2745.jpg", + "sha256": "d851fe2d3340afd8cb50559135ed3970469f4a86cfe2044a88fd9dc443486e5b" + }, + { + "kind": "file", + "path": "img_4334.jpg", + "sha256": "0b79ee2ed251453d0fd2829b233258fa8318db92d662263d1a6e4f4f326e0ae8" + }, + { + "kind": "file", + "path": "img_4452.jpg", + "sha256": "fb9847723e97f27de6afb3de8ba9ed088fdffeeddb61f46ebdc023b6990a08e7" + }, + { + "kind": "file", + "path": "img_2023.jpg", + "sha256": "088e7866bc3d53b89b315fd7a14549fb2bde86366bb5bbe089d3ffc5da96c662" + }, + { + "kind": "file", + "path": "img_1502.jpg", + "sha256": "5b7b39db9e1594c5a83a08051b423e68799f7351085298d5224fd5b4f119da0f" + }, + { + "kind": "file", + "path": "img_3315.jpg", + "sha256": "27f1435e2f9a13cebf68bcd015f5b2f52cfe24751ed4df0d262f36644421bdfa" + }, + { + "kind": "file", + "path": "img_284.jpg", + "sha256": "04ec30a4d73fed142e90686a18e1b948d5044fa0461813d1574fbffed5c3554d" + }, + { + "kind": "file", + "path": "img_1264.jpg", + "sha256": "7c5458b2b3c0c98520370f28ee1d44d6e0e706f170de60423fcbb6bf7167ca69" + }, + { + "kind": "file", + "path": "img_1270.jpg", + "sha256": "7bbd72982f3a68d69efba427ece046dc2db6d06c7516b8657d23a110f36c1e06" + }, + { + "kind": "file", + "path": "img_2779.jpg", + "sha256": "ee7f3e376c072211d328f4b81ff947551f1018e2d12bffe15c98297e87d254d9" + }, + { + "kind": "file", + "path": "img_4308.jpg", + "sha256": "1f83f3f29a57b76fadd817c4e97f85f8f23a4882f6b42db3e74f48097c295978" + }, + { + "kind": "file", + "path": "img_3467.jpg", + "sha256": "f3a78e2cc9367b0a007d18a07ee6f7ca4a6f93a98028c2b564a557ff53f7321c" + }, + { + "kind": "file", + "path": "img_290.jpg", + "sha256": "40764f5ba368c82964ae31e25c53f0647f316c7b7b05ca4b525228e9ddcd394e" + }, + { + "kind": "file", + "path": "img_3301.jpg", + "sha256": "a026b5ca9080a7f1f82725d1279bd7799f1347fffba8a6684f16e18919430d65" + }, + { + "kind": "file", + "path": "img_4485.jpg", + "sha256": "5a98e441962281fe0512a87e47f4e07522ca7e71b2afc4c06f536831cceb9909" + }, + { + "kind": "file", + "path": "img_2792.jpg", + "sha256": "07a99ab53899664f68171c6e9dca72b54b9b25eca4b7572a903dd55bac2328cd" + }, + { + "kind": "file", + "path": "img_2786.jpg", + "sha256": "f9fc8ac5110f02f74ac30b1f708f26786a80083c1e2a2376537f0efe6204f955" + }, + { + "kind": "file", + "path": "img_509.jpg", + "sha256": "c1f34571f4270ebf815fafff1033cb0ef6e0813d2fd8faf7d12c02584158bb51" + }, + { + "kind": "file", + "path": "img_253.jpg", + "sha256": "476235d0799f33248dffc8dffed02590b4964a21ee6889e741bbd70b7ac24ba9" + }, + { + "kind": "file", + "path": "img_535.jpg", + "sha256": "f31eaece8869dfa279f689683a7f8aae881a24dbd7eade6fef0467266038b2d7" + }, + { + "kind": "file", + "path": "img_4122.jpg", + "sha256": "ae1bcdb03418ad48066ccd0812289c9524cc87a3d3027bc3ae2ad6740aca6e39" + }, + { + "kind": "file", + "path": "img_3895.jpg", + "sha256": "549ecb0d1d4c99698c3c82403fed9df0dbe15d6d6149e8d17132bbad76ba09f5" + }, + { + "kind": "file", + "path": "img_2553.jpg", + "sha256": "7e8338fed367916a353b4655fd8e65adff89a233d48af3023e82327653ff27a5" + }, + { + "kind": "file", + "path": "img_2235.jpg", + "sha256": "c30cdaaec4304c08a1ff723beaf618e90079f1fb73f70ec2b906c17387e0b90c" + }, + { + "kind": "file", + "path": "img_4644.jpg", + "sha256": "e95e34df4bb90c7c0bee7739be8cde2fa72027476b6795c92576a3402fca1be9" + }, + { + "kind": "file", + "path": "img_2221.jpg", + "sha256": "d4da9e244539fc10b0d7ce44d4d6e765d5bcb60d1bd7efaf6b59307e232d2c2a" + }, + { + "kind": "file", + "path": "img_4888.jpg", + "sha256": "72e1a1c01f995d38df7083f1684ffb12950b2de2b68866828ecf082d79a88642" + }, + { + "kind": "file", + "path": "img_910.jpg", + "sha256": "9034962bc7407179fa54b48eafa97ddf6dc3fb4b021187eda1e4e8bb66c4065f" + }, + { + "kind": "file", + "path": "img_4650.jpg", + "sha256": "16f9169a656b5182bd1c2c801487a0fe76fe523b0c1066205c1a8dc1369df14e" + }, + { + "kind": "file", + "path": "img_1728.jpg", + "sha256": "631c9ab380455ec400779a2a04946b09a56c8503802582e24345727ff55675c4" + }, + { + "kind": "file", + "path": "img_3659.jpg", + "sha256": "fef7112ec27955e067a61e48817c917342563e577ab04667699e2ddad6189399" + }, + { + "kind": "file", + "path": "img_4136.jpg", + "sha256": "a34d50abf2ac1fd228b3e3f44a7765e91b3a4d05362ecf6f6b395fb6628a8b4f" + }, + { + "kind": "file", + "path": "img_2547.jpg", + "sha256": "c55c4aec827604a04a945dee1db791d6beacace42236e9d438408f2d12249334" + }, + { + "kind": "file", + "path": "img_1066.jpg", + "sha256": "b7c7dbc7c0d37efe53720a8677814362fc9bab2bc2b6c6599936a0fb8de5b3ff" + }, + { + "kind": "file", + "path": "img_3671.jpg", + "sha256": "ba3eaf6e8d7155577b14288bb6724891fd0ed12baeb0ef72eadf941efea6a46b" + }, + { + "kind": "file", + "path": "img_2209.jpg", + "sha256": "0cf8e8a083c2d4eef43dcc65a0a8e45d3e4fcbb2899d946268fc38b1076a3722" + }, + { + "kind": "file", + "path": "img_938.jpg", + "sha256": "0e073ec127cde6f7a8291f74a2f0efe5c75624369183da488ede3d1039064bfd" + }, + { + "kind": "file", + "path": "img_3117.jpg", + "sha256": "aa61fdbd28505557aa3f148a19457689cb450ea654c46346598e9c9dcf472589" + }, + { + "kind": "file", + "path": "img_1714.jpg", + "sha256": "5b7b161448a6e276ef361013920270b705fc78c2ce6ee7e1e8907daf27f84998" + }, + { + "kind": "file", + "path": "img_1072.jpg", + "sha256": "671442ac19e7065a5817bb35efd4f41b2bb97e0c8f9810d56810aeb4d7791e0a" + }, + { + "kind": "file", + "path": "img_1099.jpg", + "sha256": "6410417c881c2912e2ce9fd74e6a2fb35582685258ba98a76bdd4de2620bf9c5" + }, + { + "kind": "file", + "path": "img_3856.jpg", + "sha256": "7a49bf52bee54f9bcfc1a31c4f89ab8b8a5ee68a7eed7d83d78df3a37ad1a660" + }, + { + "kind": "file", + "path": "img_4687.jpg", + "sha256": "c157db599901b221c20b0b886fc683c6fe427c37e766c0f9ed0d8197b11149f7" + }, + { + "kind": "file", + "path": "img_1927.jpg", + "sha256": "5689cd3f576cf728b1b421484b253c538e334bce64785f62d925b9fb3916bc1c" + }, + { + "kind": "file", + "path": "img_1933.jpg", + "sha256": "ef1939a15b47e0e2360f1ca8bd173f785cf7af7a802e70ed19d54a2920b5b754" + }, + { + "kind": "file", + "path": "img_4693.jpg", + "sha256": "17ec884a37328cc19984d5b9d8c8abb30f2c2e3c56c7ad5d7e96bd9c9a5bd8d8" + }, + { + "kind": "file", + "path": "img_3842.jpg", + "sha256": "52e357ac891354bf8c78596288251678d0b6a333bff7c5c5c433ee43c96ea2dc" + }, + { + "kind": "file", + "path": "img_2584.jpg", + "sha256": "70eca374b69bc8cda3264169b561a0b4386f557e708714f580b4870aee65f35d" + }, + { + "kind": "file", + "path": "img_723.jpg", + "sha256": "189cebd4cf44337711a60136f3d81c8485fa6c7ba3281d2e1326b72dcd64fae2" + }, + { + "kind": "file", + "path": "img_4863.jpg", + "sha256": "6bd220fb99acadf118953cea08e2668c236df92694e88cd614442fece079a4f8" + }, + { + "kind": "file", + "path": "img_737.jpg", + "sha256": "083b5af5ba4b15608fbc966de66672e4b9aeead71ae1630918559d7d3a322e2d" + }, + { + "kind": "file", + "path": "img_4877.jpg", + "sha256": "d33045ff0f6d103ed2b82c9635bb0548f3b5d3e8d16b4aafca80efb5765e161e" + }, + { + "kind": "file", + "path": "img_2427.jpg", + "sha256": "3f7b2f17870c198ee9b74c8beb8034bf718e73157bfaf94b6d304c6332d74c67" + }, + { + "kind": "file", + "path": "img_1890.jpg", + "sha256": "a4d0578b71af4f70f67d36c40941cc3caaa6db7b2abdcd129b7db39a546f2cf5" + }, + { + "kind": "file", + "path": "img_4730.jpg", + "sha256": "3960d1f20026b9df64950f504a4bdbbe339d6febb30e5cbd9ab9bc03576dbde2" + }, + { + "kind": "file", + "path": "img_870.jpg", + "sha256": "e63ff93e44400af04b8a49ddbab88e7030156cf278e5c40dd0a586b2663912a4" + }, + { + "kind": "file", + "path": "img_2341.jpg", + "sha256": "4aae870ff01005d39fbc82d108b76e05714401bed365f1b542a70ee65afd77c5" + }, + { + "kind": "file", + "path": "img_4724.jpg", + "sha256": "c90624ee360f96995083e56453953e69e6d9625da5575a9800a120d3d5b05c0f" + }, + { + "kind": "file", + "path": "img_864.jpg", + "sha256": "88661f9b5c59879ef2e188694341cfa16d4a131fb7f3178cf4be29fcee93c8e4" + }, + { + "kind": "file", + "path": "img_2355.jpg", + "sha256": "42a515bc143f8bb7d17723b09a338d86f1d1ffc32bc582c6800d14969e7c9403" + }, + { + "kind": "file", + "path": "img_1884.jpg", + "sha256": "eeccad053d918a9aec6c8d237685f47b30cea151f2094538493b7891ff9b3e10" + }, + { + "kind": "file", + "path": "img_2433.jpg", + "sha256": "f21d2c0e626c5a390391f4c1d06e14b6c542c3b6fdd4f23f1ae535552358a2bd" + }, + { + "kind": "file", + "path": "img_4042.jpg", + "sha256": "2e903985f244e2964b35991429be0fb7d711ebdc3102343e1ae9294e3767daa4" + }, + { + "kind": "file", + "path": "img_1112.jpg", + "sha256": "ed5fee83f70c9cfade370cd29727b60c5d6994b308a12c2e8736e9deebcfae13" + }, + { + "kind": "file", + "path": "img_3705.jpg", + "sha256": "f88b6177daf186fc59cd0b046e145397671d9f6227e7c4635f0e173fea8bed5b" + }, + { + "kind": "file", + "path": "img_1674.jpg", + "sha256": "c7966bee007c8dff49cc9842059932084abb1f640c0cf421b6e11c599cfea24c" + }, + { + "kind": "file", + "path": "img_1660.jpg", + "sha256": "9d5601e706a8681c69b8f6b6453773fb13fad6d28f3099aa5bbb915782d2d46f" + }, + { + "kind": "file", + "path": "img_680.jpg", + "sha256": "19587243041f3b035ba76ea79a75219f004c7e7652b56dac72e8f3f0a1551476" + }, + { + "kind": "file", + "path": "img_3077.jpg", + "sha256": "b8389cafbfa7923d15da8402a51f1897e4a4327a7c3552c16aff3c68ff9da917" + }, + { + "kind": "file", + "path": "img_4718.jpg", + "sha256": "b84e2f6492f139cfa327618c4bdb2098642acb938c4d6f5dcbc9cbc93a8b2372" + }, + { + "kind": "file", + "path": "img_858.jpg", + "sha256": "5478d99b7de384cc42299d00a9384dacc13bc196e49fe6bcde10d178630a880d" + }, + { + "kind": "file", + "path": "img_3711.jpg", + "sha256": "75fd7424c635be7269c724523644c04ead3b6351f107450e5653e6eaad607fef" + }, + { + "kind": "file", + "path": "img_4095.jpg", + "sha256": "c256282eedfb4a49a24e1c0bdd60b03237fadbf6d49c670c3a05817f32f230a1" + }, + { + "kind": "file", + "path": "img_3922.jpg", + "sha256": "3e4a0d7832a1268da4b3403af4735aa19e57d3f9ee0865d05993051f1afee896" + }, + { + "kind": "file", + "path": "img_2382.jpg", + "sha256": "ea3be14a333b99bb440c7d76a8f9e6e1af2895989fed8e43ba4e84f1236dafda" + }, + { + "kind": "file", + "path": "img_1847.jpg", + "sha256": "dd1bc56b45112ce7d50f62dc756f2ed67b0b1c08aa0238462bebe9a5859fc7f1" + }, + { + "kind": "file", + "path": "img_3088.jpg", + "sha256": "558ff21e8adb1103bcf70c510255f935cac80a00599787f064a4180049125dd0" + }, + { + "kind": "file", + "path": "img_119.jpg", + "sha256": "7f809ec987497ca0886353e4565aa6cb0f8e9f6ba314304685e740ab038acea6" + }, + { + "kind": "file", + "path": "img_3936.jpg", + "sha256": "799eb648122ca08b9ecdafe3a474300991f2895ddafa3933d19d57236cdd59dc" + }, + { + "kind": "file", + "path": "img_131.jpg", + "sha256": "918fe8be31841616650660ce76e520c9f32d5d030f09cc504a8c18ae25e0ce5f" + }, + { + "kind": "file", + "path": "img_657.jpg", + "sha256": "85dedda0c500ba1e65bdfd9984c9c010e8ee6b679f2c9c1a1775fabd0ac373bc" + }, + { + "kind": "file", + "path": "img_643.jpg", + "sha256": "923a8b08494f72d126728e5e67d51a0a32412b431a2dbd4b9f6b3b7174bed576" + }, + { + "kind": "file", + "path": "img_125.jpg", + "sha256": "53c23bae764172ec0803d3fcf7f612178807607101bd393d6b9faeb629441ca0" + }, + { + "kind": "file", + "path": "img_2143.jpg", + "sha256": "7c42b98bca547ac58a5277cecb32c71c7168e2f73e575c804358995a0bbb718f" + }, + { + "kind": "file", + "path": "img_36.jpg", + "sha256": "a1b1430c4b0311612d2745db440e09f53321e8b05eae9985ef76bb1c4a199ac8" + }, + { + "kind": "file", + "path": "img_4532.jpg", + "sha256": "9f29591dd7d5c4463958a22dbc4c41f5f5a322c89ab480374503fabf71dce57b" + }, + { + "kind": "file", + "path": "img_4254.jpg", + "sha256": "694d0b8f42bf5d624ec9337cb272351d8310b05b326f6d90ccc73e2169b7e361" + }, + { + "kind": "file", + "path": "img_2625.jpg", + "sha256": "cc3f0a841252d14523bf1be096ba5753336b531f4f05f3d79f1d4809121285de" + }, + { + "kind": "file", + "path": "img_4240.jpg", + "sha256": "81b6a51b8399c78f08b46646742b554552a03f2e9a9d7814c46d14ca8a21cbd9" + }, + { + "kind": "file", + "path": "img_2631.jpg", + "sha256": "f6eb0da9ab94733aa69054f284b2405d18c97a0cfef2e6f9d1011760f1e16ec7" + }, + { + "kind": "file", + "path": "img_1338.jpg", + "sha256": "6c4f020d16e17dada25ff54000206e85da8948b4a1b821090ec5fbac27d7583b" + }, + { + "kind": "file", + "path": "img_2157.jpg", + "sha256": "9dff8088615894463b81d2451e66de1aa68790af45ce18f2fdc6e7b5cfb57262" + }, + { + "kind": "file", + "path": "img_22.jpg", + "sha256": "e1d56957816b64379769dc200b8aa74374c5f6353e5ea4669ce3410f837c407d" + }, + { + "kind": "file", + "path": "img_4526.jpg", + "sha256": "4669d5f5e4d5809bd95f217e84d2e9cb8fca4cc4047ca3646a6d51115ea5c0e9" + }, + { + "kind": "file", + "path": "img_3249.jpg", + "sha256": "d94c8e3dd846cc10d66fb8564dd7ba7092e3384d68ed0c358818340315203777" + }, + { + "kind": "file", + "path": "img_1476.jpg", + "sha256": "693eacfe3d3f4b74db3034669c02cf3a1d6edbcaa3b123ff0549d4537c8ce81c" + }, + { + "kind": "file", + "path": "img_3261.jpg", + "sha256": "33328e03ed83a2684893981662f1652b7958b2c7b49f839e65dadd2f8bd00dd6" + }, + { + "kind": "file", + "path": "img_496.jpg", + "sha256": "83309e61c4bbdb760095c36d44f36e07d605c91e06029503cd5745b519a1815e" + }, + { + "kind": "file", + "path": "img_4268.jpg", + "sha256": "3cae0cbae9757f9bff567cc09de1ddaf18e6db11a0a92fe97728cbd45c76c107" + }, + { + "kind": "file", + "path": "img_2619.jpg", + "sha256": "75752857d8e549480e0722eb5f6c9dc170e65e7449ebe97d3ec5f91c4b2be6f5" + }, + { + "kind": "file", + "path": "img_1310.jpg", + "sha256": "f84b9bfed52f379c1bdcf588c8fa8161ef435266864922d4fc57859af3aafbd6" + }, + { + "kind": "file", + "path": "img_3513.jpg", + "sha256": "b0c363297d3fbf58801904a5773b6a8c48e12c1a26ee7069dfc3436334e558bc" + }, + { + "kind": "file", + "path": "img_3275.jpg", + "sha256": "64341f337ea101516700622b84e830b28cdc510407eb0605ebf7d2c9f9ebc2c2" + }, + { + "kind": "file", + "path": "img_482.jpg", + "sha256": "1a025f51c2b32439b9c2b3051d3f0641b4effe9a9e93bb264a9e82eb924cc998" + }, + { + "kind": "file", + "path": "img_1462.jpg", + "sha256": "789da244ea6567f10244d5b7ad91e473158d06fd25b6c1f8e7b1998ee828700b" + }, + { + "kind": "file", + "path": "img_1489.jpg", + "sha256": "9418163bf6aa850528df399afccb40e9125d2cebd7761ed225d44ed09c324c2d" + }, + { + "kind": "file", + "path": "img_4297.jpg", + "sha256": "6a1de166f538492f9379f761eda8be4a21901c1b76f62653687afe92f584e30e" + }, + { + "kind": "file", + "path": "img_455.jpg", + "sha256": "ce2b9ad39d9776d30076c95106b013fe36edd5d68723f5ac453dd0dec365c598" + }, + { + "kind": "file", + "path": "img_333.jpg", + "sha256": "a0226e40ca055f56134ece1d92e0cca4e972618327ed03dfbb2f50e5597b7bc3" + }, + { + "kind": "file", + "path": "img_2802.jpg", + "sha256": "cb4eb568d22f47b213f92e62335830b85d1dd8ff4d9e9d69ee28c314083d6790" + }, + { + "kind": "file", + "path": "img_327.jpg", + "sha256": "3dd8cd5c8046c20450865b95dbbe2fc0d782548103cef54e8d174d2c78343a96" + }, + { + "kind": "file", + "path": "img_2816.jpg", + "sha256": "60d0de0173dc40f95f4655abf4d93701d143b3ccfedc36215d9597f38bdff062" + }, + { + "kind": "file", + "path": "img_441.jpg", + "sha256": "46499a93f1c1c39c2936166934acad0b66682cd012f44712c16d127340b369cb" + }, + { + "kind": "file", + "path": "img_2800.jpg", + "sha256": "d5f0ef7e6b0f7486f2241a6ece64b0d3b0b239f864bba3cc5413a57a7b341290" + }, + { + "kind": "file", + "path": "img_331.jpg", + "sha256": "c9b54d7165d8ed7fdf1867a262b7ad6523697fe227c696f1615670c84183c38f" + }, + { + "kind": "file", + "path": "img_457.jpg", + "sha256": "d3aa2db2aafd451b43914ca64cfa04f527ee6a4ce3fe9877a8b541bc33cb7e56" + }, + { + "kind": "file", + "path": "img_2814.jpg", + "sha256": "00e180ba856e9ba2a8e24da6343fe772a5804f8af916528f397e77928a3097a0" + }, + { + "kind": "file", + "path": "img_4295.jpg", + "sha256": "4fa6cb355e53dce65b72cf8bbc140142d8b8dacb83fe0670c649deb5324a013e" + }, + { + "kind": "file", + "path": "img_2182.jpg", + "sha256": "be28e9015d92433c82bf9e3d141faf29ded303d74d89bded235f2eb9ffff2ba7" + }, + { + "kind": "file", + "path": "img_3288.jpg", + "sha256": "88681db65075d7001e877fcc609c0d0e22108d6b4f4fbb9356caf3a1ff6ef159" + }, + { + "kind": "file", + "path": "img_2828.jpg", + "sha256": "a56be21946afb709f31c870ce82358325bc53590f1fc0609eaf15610222ef5d0" + }, + { + "kind": "file", + "path": "img_319.jpg", + "sha256": "9dba0aef14e1c4c147a5d6be4835a6b8a45648d585eacb86aabbaaa7390bc2e2" + }, + { + "kind": "file", + "path": "img_1312.jpg", + "sha256": "052d11797c73abea471fceb00d860822d73ccb326d28f700c62a1af649890f59" + }, + { + "kind": "file", + "path": "img_3505.jpg", + "sha256": "030f3af1275e42e9150c6990884fd3924418127641cbecee5b62ba2404c2ed5d" + }, + { + "kind": "file", + "path": "img_3263.jpg", + "sha256": "13f792207783b21fa4dafae5887cf206e2e4c442252a50c93af960ea8dc85ff0" + }, + { + "kind": "file", + "path": "img_494.jpg", + "sha256": "d043ec04b5796723e4a60142c7cf04cec8534ecbd27ab65cc16e15b6d49de00a" + }, + { + "kind": "file", + "path": "img_1474.jpg", + "sha256": "2f500d78a170d31184ff1fc3e9273b90079e249d2da3b796568b5f07526df573" + }, + { + "kind": "file", + "path": "img_1460.jpg", + "sha256": "99e83e1f90ec9c4a4f9ecb5080c5683e779840c76fda5cd98c3d44428320009a" + }, + { + "kind": "file", + "path": "img_3277.jpg", + "sha256": "764519490ff624de133cc3b8238ea71b05c2a38c9312e902f9d6bf411d40b635" + }, + { + "kind": "file", + "path": "img_4518.jpg", + "sha256": "9e0d9b7244f7b496c0d415a1938b44b00ca00ab14e0b725bf101277c5cf59ed6" + }, + { + "kind": "file", + "path": "img_2169.jpg", + "sha256": "e1cd9d8e7dd5a1a9d2554b8d2ec87182abbf23f172ddf40776e385efb5281c88" + }, + { + "kind": "file", + "path": "img_3511.jpg", + "sha256": "05d7f2bd429ad4d860544609659960304a51396fbee96563dc85249028b941e4" + }, + { + "kind": "file", + "path": "img_1306.jpg", + "sha256": "d91a48377b7728fb1b6b643058c0c435c5a4ea65e4216cc5d65d08cffb404fcf" + }, + { + "kind": "file", + "path": "img_2627.jpg", + "sha256": "dd44b4b082ebc2da7fd28556a75c4274f7eddebf6372140b8c12bcd903f0c4ac" + }, + { + "kind": "file", + "path": "img_4256.jpg", + "sha256": "cba865793aeff81c3f45df8f9397dcdb2e7bcf60ed99471b0ceeda24e8f85551" + }, + { + "kind": "file", + "path": "img_3539.jpg", + "sha256": "ab206f1dc485d42e9ee175c888abaaf40ce159a67e7c3eefe384474038ca0c58" + }, + { + "kind": "file", + "path": "img_1448.jpg", + "sha256": "3b30c90912488e0cbef8e1feb6fb0f8cdd8de7b298ab907e093ea7c23cb920ce" + }, + { + "kind": "file", + "path": "img_4530.jpg", + "sha256": "156ce8143e3b4ece1eb598f7eb10ab000ce8149a83e73df5c1bf56249e19f08a" + }, + { + "kind": "file", + "path": "img_34.jpg", + "sha256": "4705ba7756065139b73d7243e8e411c1e0bee309c82baea5888385f89c7f1bfe" + }, + { + "kind": "file", + "path": "img_2141.jpg", + "sha256": "935fd4ac0f65883798f9854047b3c0b6c352ef71d4bb837050e674e612e2be8e" + }, + { + "kind": "file", + "path": "img_4524.jpg", + "sha256": "42f5204ed47bcc05fdabd2a5afcab0df752e5679a64abe0ad99e0158cd12b35c" + }, + { + "kind": "file", + "path": "img_2155.jpg", + "sha256": "b8e1df538bb1ac1d509f22f72bef7186fc28e2c42c76ecffc05a62699af155ba" + }, + { + "kind": "file", + "path": "img_2633.jpg", + "sha256": "3493777aeb0cc1df0e3bc0447ee3063ac774a19ed21f28d54a063606c73d03f4" + }, + { + "kind": "file", + "path": "img_4242.jpg", + "sha256": "9bb499ec16f98b9ffdcf36bed851dbdb28ab80014e116b81cd342152879173dc" + }, + { + "kind": "file", + "path": "img_655.jpg", + "sha256": "e5c4eb496bcd54344d22b62c7b2d8eeb419518031cf66ca8cf381d9e5b381325" + }, + { + "kind": "file", + "path": "img_4915.jpg", + "sha256": "f9fe304647f66793225637a52d8af961bacf7722965506672b1a14ef4db1afb2" + }, + { + "kind": "file", + "path": "img_133.jpg", + "sha256": "808ba5eb8e20c0c4080fc56f8ccb5066aebcd51ff7e97a118f9b1511fbb96365" + }, + { + "kind": "file", + "path": "img_3908.jpg", + "sha256": "e126e8a31a1552a0e00618d3190868f937fe87e701ad771c359d481150d45085" + }, + { + "kind": "file", + "path": "img_127.jpg", + "sha256": "7e8383a4909739d48326285e13636eff9991858dd3ccedacc809f9215e3a697b" + }, + { + "kind": "file", + "path": "img_1879.jpg", + "sha256": "152b36a859d67b6568ed8827aa0f121532be5b6052c63183896b10bdacd6f05b" + }, + { + "kind": "file", + "path": "img_641.jpg", + "sha256": "80f3bed55318fd76298d25cf9a16508f04eab335f97b073ec6a643fbd70a5597" + }, + { + "kind": "file", + "path": "img_4901.jpg", + "sha256": "4861a160b1f43fb50e5c9111a74ded780762d83c6ef1ff10d1c996fccdaca1f4" + }, + { + "kind": "file", + "path": "img_1689.jpg", + "sha256": "ab3326d405f4561964417fcaa65a3495957fb55b903b602760d869bcf2a1f2be" + }, + { + "kind": "file", + "path": "img_669.jpg", + "sha256": "8c18e3b5060c3d08a03824d2fb425ea6c2426bf759cb27b7a306621597b29b4e" + }, + { + "kind": "file", + "path": "img_2380.jpg", + "sha256": "260cc04c62a9c3b227651d0b71479ad2706c6223bab3616fe3dc031dc7b4c04a" + }, + { + "kind": "file", + "path": "img_4929.jpg", + "sha256": "a55bcbe7a195fde26cf7fc57707566313d1032a225eb2302710dc76424b315e6" + }, + { + "kind": "file", + "path": "img_3920.jpg", + "sha256": "468efe72351ad36284b5ddc1c5d3de390de04a11197b0f75275f18372e8ae5f7" + }, + { + "kind": "file", + "path": "img_4097.jpg", + "sha256": "4a5d2dad14467c5d161b4e886fe71418afc4ff70e242c8125dffaa21c97403f0" + }, + { + "kind": "file", + "path": "img_4083.jpg", + "sha256": "8af0e4660e57987e4741ee6b2e93810bfa06cdaa7f13ee55f5f223f4fc33de68" + }, + { + "kind": "file", + "path": "img_2394.jpg", + "sha256": "3d02b5c05dfcf5b83b83c539204d510919c0c44a465ad7482d4f0fb8a0f6a74b" + }, + { + "kind": "file", + "path": "img_1676.jpg", + "sha256": "1459bfa28725fb4a1eaab4fd175a4d3f360e70ece6f6eb7360393c39e59e77bb" + }, + { + "kind": "file", + "path": "img_696.jpg", + "sha256": "dedcf83cda38ebdbd6177c6ca8bbf9601e8a05fa78a058ae9e19703f320dcb07" + }, + { + "kind": "file", + "path": "img_3061.jpg", + "sha256": "0d68d3b949e291e550c18bbc422f29fb5edc83111fa953994a04055ccaa34543" + }, + { + "kind": "file", + "path": "img_3707.jpg", + "sha256": "9c64da05cbec8437c9d1abe663222e06e849cf33325d00b18273a180370d1ce4" + }, + { + "kind": "file", + "path": "img_4068.jpg", + "sha256": "9d8c7c3f4b11d09f3a988edf3a4673afe08817cab6c6203963c1a9af32b3b594" + }, + { + "kind": "file", + "path": "img_2419.jpg", + "sha256": "aa65418b002b3755038ed1a31b8129db154f4d5181a15215d76a2295f3cabfcf" + }, + { + "kind": "file", + "path": "img_1110.jpg", + "sha256": "243889af7021a0e3e35a16eda2e931b491976f8e32589e7d380dc680579548d6" + }, + { + "kind": "file", + "path": "img_1104.jpg", + "sha256": "61f8290566bee4c6002086a15e46154d6418e66eff7782fa44acf0b41ffb7055" + }, + { + "kind": "file", + "path": "img_3713.jpg", + "sha256": "f86e4646d25e055e62992689976c2eeef3d8b585c4fca39cacabdab1ddcd12c8" + }, + { + "kind": "file", + "path": "img_682.jpg", + "sha256": "8193f4b7f4b2a76bfd0eaf711544ceb8e933f4534ea24277bdf011e8b3f7b362" + }, + { + "kind": "file", + "path": "img_3075.jpg", + "sha256": "88224137b4def4784618c0677eea1e4f21f0c8c8d9c24c3ef36c9f0b6200c4e2" + }, + { + "kind": "file", + "path": "img_1662.jpg", + "sha256": "7d02d0fb97599b6d7578b551b02eda42867f71a969573e419874b539a611581f" + }, + { + "kind": "file", + "path": "img_2343.jpg", + "sha256": "049e409a917dc21a4a367bdcb345ddfd3b93f4b9c43e0af8436b6b8119604874" + }, + { + "kind": "file", + "path": "img_872.jpg", + "sha256": "68adf37c22674264cfb9b74a82d5ac9ceca7d34ffd38360ea0da1bb49e940a8f" + }, + { + "kind": "file", + "path": "img_4732.jpg", + "sha256": "6f611d2464f2cfb58cf58bcc291434a38c2fe09f24376d64bb66cd170c97f563" + }, + { + "kind": "file", + "path": "img_1892.jpg", + "sha256": "069a41a42a8e600a16534327d4035569e829d7001b124fa63a4ea2b938073d1a" + }, + { + "kind": "file", + "path": "img_4054.jpg", + "sha256": "358636194b24871c4e7f2534ff73b8f89f30603cad99e6554a4115ac40ab584b" + }, + { + "kind": "file", + "path": "img_4040.jpg", + "sha256": "29d00350ceb2f33222a492616dd63b8b761588185c560cc1f6e8fd791ac6d2ec" + }, + { + "kind": "file", + "path": "img_2431.jpg", + "sha256": "d145066c89a9635ed8fc7a039f40d00c10f275c26039dd9174f4110f1446af61" + }, + { + "kind": "file", + "path": "img_1138.jpg", + "sha256": "28fa5e7a5df9ab058b2a6e51b416040f5c66a83ba29ba4d1eb4e5f86e2e79ad6" + }, + { + "kind": "file", + "path": "img_1886.jpg", + "sha256": "2ab5d6e93ad72aac7f0dc0a84c5fd0e593c92423f22d4c14a1afc443f88ba521" + }, + { + "kind": "file", + "path": "img_2357.jpg", + "sha256": "fc621ea87575d999c18eb3a6497e536d9812df0bba4be0949f663078267f6ce5" + }, + { + "kind": "file", + "path": "img_4726.jpg", + "sha256": "60722a66a1ca64a407f0b0e73f720ea2c48bb00c871db299cc5922ff9a18f012" + }, + { + "kind": "file", + "path": "img_3049.jpg", + "sha256": "5be34b6ea74fed0dbc5fdf333bb2d9b53843a081c15f85805c7c4dede98dcda7" + }, + { + "kind": "file", + "path": "img_721.jpg", + "sha256": "5f2f349d9236354f576f68bac71a3d2c9cd22dd6c019402a445d1d70f03198f6" + }, + { + "kind": "file", + "path": "img_1919.jpg", + "sha256": "cdf2c9ff2bea5b0af584fe344d4df61a8fe2346e646a3385d01de1651ecc89c3" + }, + { + "kind": "file", + "path": "img_4875.jpg", + "sha256": "6557fa0151da8346ccfa61ff877bf4fa5f590f6db39977e0ff234671f0a351d6" + }, + { + "kind": "file", + "path": "img_735.jpg", + "sha256": "a4cd33d8e3df886e646cd25ff3863f7955226edd84dc7ea410372bb39feeaa82" + }, + { + "kind": "file", + "path": "img_4685.jpg", + "sha256": "5af3d276d1d8c2f4e8ba063c41619df8ec478e1d9dc547ebc58683480194841d" + }, + { + "kind": "file", + "path": "img_2592.jpg", + "sha256": "989a74c7cb79ab973d97367d21408e4a137d524448d29da3dd6de55052a47f2d" + }, + { + "kind": "file", + "path": "img_3698.jpg", + "sha256": "a45db532c887f026f673e97bce695570af2e36019dfa87de7489aac1b18b3e11" + }, + { + "kind": "file", + "path": "img_2586.jpg", + "sha256": "d2937d14fd17702ca7d56466364a7bb4a909f08c0c011f555d3313f84d61e8d1" + }, + { + "kind": "file", + "path": "img_3840.jpg", + "sha256": "c652fbae9ad19614a24f4536a64e12f44c72b72e6715cde611f9d0aec287e961" + }, + { + "kind": "file", + "path": "img_4849.jpg", + "sha256": "226ad8eec60e5b326c3492bb36b06881bc223a5b9fabf4ec35eec950a3de8d22" + }, + { + "kind": "file", + "path": "img_709.jpg", + "sha256": "80235ef5dd7195c0bcb7d52572aef571602ed7103adafd24989d92e6b4c9c6e8" + }, + { + "kind": "file", + "path": "img_1931.jpg", + "sha256": "432341674478f0988c85b776686846280142e709922c625145b6154462feb0b8" + }, + { + "kind": "file", + "path": "img_3115.jpg", + "sha256": "2b6a6b9535ba55532079ed333f8eca1ddceadde739d698ae72f9432035d170d8" + }, + { + "kind": "file", + "path": "img_1070.jpg", + "sha256": "99a92a510d0d0479ad323acf2f067cc2f7caa67c8df8a4cefecdf13fe878de8a" + }, + { + "kind": "file", + "path": "img_2579.jpg", + "sha256": "ba36ed41c7530d27820df54bff1760b28e7e84e4a94d6159bc016cd26a23a086" + }, + { + "kind": "file", + "path": "img_4108.jpg", + "sha256": "237ae65bb12c41ede9148c908d081dfc996e2b3f6a51e1d7f777cf2b47646bb3" + }, + { + "kind": "file", + "path": "img_1716.jpg", + "sha256": "a143c1f51d37ec5d37c73ceabcbdd20d6272951033e2a76c53640dd58ee8b62b" + }, + { + "kind": "file", + "path": "img_3129.jpg", + "sha256": "07a3777a8c280000be10124da562e5847dc5b19bfac98f9b549f0def3b7977db" + }, + { + "kind": "file", + "path": "img_906.jpg", + "sha256": "d140e5b3919fcba1f52005c10f27effb8b7fe8b47af20adb004a86c13efdcd38" + }, + { + "kind": "file", + "path": "img_2237.jpg", + "sha256": "5fb994e2d14b4b61e2f00cf87a33f28fbafc15ca3b03fb22b6e6cc7d79437545" + }, + { + "kind": "file", + "path": "img_1058.jpg", + "sha256": "27ad8242c8c25fc9dab76f731ed39e6dac7867a020c1e468873b2a4076a3939c" + }, + { + "kind": "file", + "path": "img_3897.jpg", + "sha256": "c5872d4857e43518f00d0ffda54a58eb71197a9f144930e66a45d9ee9d3e9416" + }, + { + "kind": "file", + "path": "img_4120.jpg", + "sha256": "6d542f09316bc8bfcbd2576c2f5a53c3dc5e1452e1ff5bc2f42f0d4135f41a2c" + }, + { + "kind": "file", + "path": "img_2545.jpg", + "sha256": "f84295f3ea03aa459d911bb9b54fd63f107820a5e14f76b23f67c27c76e1d47e" + }, + { + "kind": "file", + "path": "img_4134.jpg", + "sha256": "8b604fb3794a7750dd5e5d2c2e82f28a55dcfa6f29e8f687a432b5f617c55ed7" + }, + { + "kind": "file", + "path": "img_4652.jpg", + "sha256": "a80484126086094b0a3fd646a2133bfc555aa793c2b02a6d16d6419ffbc48ca7" + }, + { + "kind": "file", + "path": "img_912.jpg", + "sha256": "f20c41f0c30528cf9769932e6ddcdbe66667cb4c312a2118d2a387153bfdb4d8" + }, + { + "kind": "file", + "path": "img_2223.jpg", + "sha256": "ab5d1d40f7920304f34af8be83c3b6cac3f51cd7db8c19e847a996fe1d0fe189" + }, + { + "kind": "file", + "path": "img_245.jpg", + "sha256": "44a935e417ac075fe7c37dce8c5bf89740df206baacb2e4620d3b4c96290ea45" + }, + { + "kind": "file", + "path": "img_2974.jpg", + "sha256": "659ee922e5f57b52100e7e28221af51f07064ee36baaf5461a37bebbf8a1ea4a" + }, + { + "kind": "file", + "path": "img_523.jpg", + "sha256": "563852f5b5030dac5b06a55519b113d48f72b168db08e2b178458e6b5b93c0a3" + }, + { + "kind": "file", + "path": "img_537.jpg", + "sha256": "49dd43f3ca83e6ad6233e3eb95b50a5723a360afbc3184ad1924a7faebd93041" + }, + { + "kind": "file", + "path": "img_251.jpg", + "sha256": "4d97a839733229a78cca6bbd70be0a0f7f1eca191831376da2efe45d8cbe6c35" + }, + { + "kind": "file", + "path": "img_2960.jpg", + "sha256": "3d89d5f1aec91caf414349322874630234076120f0ccd7d7bccd832423102433" + }, + { + "kind": "file", + "path": "img_1299.jpg", + "sha256": "d4cd5c95e4c42002b39770eef6c816dce687535cc3654b52a78fb8fc5f727941" + }, + { + "kind": "file", + "path": "img_2790.jpg", + "sha256": "c12a80e350fddb512b59b8772fdff009db6ab1ac41aee743875250957767ea79" + }, + { + "kind": "file", + "path": "img_279.jpg", + "sha256": "4c8b02dc1a16a814b6eb76020a9f650e8fc196c3dff578092662d97b89622f23" + }, + { + "kind": "file", + "path": "img_2948.jpg", + "sha256": "e6fde7c57ffe1da0a403463b51d1433e30ac33106bdd41f923c14ad197b7a6b6" + }, + { + "kind": "file", + "path": "img_4493.jpg", + "sha256": "7207d937198cf8942140af568f1d35bb096a1c6f95e95a728a71515763781c1a" + }, + { + "kind": "file", + "path": "img_2784.jpg", + "sha256": "9677ec08d6fde7ba78d0a4ae6eb0056862e41360ff93253b5a97f2e1734758c9" + }, + { + "kind": "file", + "path": "img_1266.jpg", + "sha256": "3240f6a8c003e1b030f1b75991d1ad04b4ec61003fd5ed1d0085e4698e89bf39" + }, + { + "kind": "file", + "path": "img_3471.jpg", + "sha256": "d1e734cece3be001b24855fc22e81af6121033b6bda35eacae8e394a63005090" + }, + { + "kind": "file", + "path": "img_286.jpg", + "sha256": "104963834b4646bc058b30948b9a3ef787f945e1a2927a62772920f4113d684e" + }, + { + "kind": "file", + "path": "img_2009.jpg", + "sha256": "cccdf945bd31a9d1b8984874b7e659154c480d8a5ac7f5b3f49916ce29c7a3cc" + }, + { + "kind": "file", + "path": "img_4478.jpg", + "sha256": "2f65163b6595748d33c1ce5462e2bc53f71e20136ebc371037b1546b50267ba8" + }, + { + "kind": "file", + "path": "img_3317.jpg", + "sha256": "2415d52fb67141aa2f2b072563fb65627440232f10b20e3cb202188379be1dc5" + }, + { + "kind": "file", + "path": "img_1514.jpg", + "sha256": "f3f83b6ea84aba1f03724588471eb64db14d6f23b75609c1767e8df741323b5e" + }, + { + "kind": "file", + "path": "img_3303.jpg", + "sha256": "fc660a236551b4dc507942a0d59fc4f84809cf3bd1a75ed5d33341da450ca823" + }, + { + "kind": "file", + "path": "img_3465.jpg", + "sha256": "58576fe46140325895c28df126ff66f10b7fef390c9b378853acf74fb55023c1" + }, + { + "kind": "file", + "path": "img_292.jpg", + "sha256": "199db7dd367e78fa17b0d8240ea029778cd5784e48cb8c727c84c97bb6d2eae6" + }, + { + "kind": "file", + "path": "img_2753.jpg", + "sha256": "60d9255823fd9bf5c9e734550be6bdf83fc0813e505770837cb7eed34b79edae" + }, + { + "kind": "file", + "path": "img_2035.jpg", + "sha256": "47a733941ba837cc768db2e2552789d13e5e464dbfc0a189190af92ad73fba07" + }, + { + "kind": "file", + "path": "img_4444.jpg", + "sha256": "2eb15aefa29b180b86a514235335a0589efc152badab9b5cfff03f7f0956028a" + }, + { + "kind": "file", + "path": "img_2021.jpg", + "sha256": "98ffa178b180f61a02a74e30f8510b9045a6bb835f348e5ea96b413b52059ff7" + }, + { + "kind": "file", + "path": "img_4450.jpg", + "sha256": "7d65437ff376b90069a4c19a653dcfc729278cfd20d42e5ff00eae4c8ab62310" + }, + { + "kind": "file", + "path": "img_1528.jpg", + "sha256": "1edd7d24f1625ffdfbeac4ed2fe611ffa3c54a015dca0731516edd8e250f0c2b" + }, + { + "kind": "file", + "path": "img_3459.jpg", + "sha256": "923e28874d843d695c580fef23d034be5f5c0c70f9378454e621e571b320f4f8" + }, + { + "kind": "file", + "path": "img_4336.jpg", + "sha256": "4a709e6a21264f7369517de06939a01168db4aa538658041e83a67335861fcaa" + }, + { + "kind": "file", + "path": "img_2747.jpg", + "sha256": "82d9bac0527a4d6f0549817977f87b79a8577a97319185a17a177dfe4825a019" + }, + { + "kind": "file", + "path": "img_4451.jpg", + "sha256": "a6e825f1c64468b599e182716334dd72e40ebcc10265c165e972ff8cdb4bf017" + }, + { + "kind": "file", + "path": "img_2746.jpg", + "sha256": "90e9e81bef1d710084116ab545e816e8ef32635fff8dad1b9b064ad344a6f872" + }, + { + "kind": "file", + "path": "img_3458.jpg", + "sha256": "2cae8e23fa437e40802b5e64967c4e363db39973aa8e37b6cc9a9dab044aa4e2" + }, + { + "kind": "file", + "path": "img_2752.jpg", + "sha256": "64769e91d74c091ba1ad7803dd82045101c067b885295cb7fc98c6c84d4f5da6" + }, + { + "kind": "file", + "path": "img_4323.jpg", + "sha256": "5da0ae224a5ab5d6c18ab59ab50a02748bd205b165568fc0af9eefbb6a2a5621" + }, + { + "kind": "file", + "path": "img_4445.jpg", + "sha256": "ad743075dc9395ca4aefefd259ab42e26f68b3fa25bca3df284847de18f13fa4" + }, + { + "kind": "file", + "path": "img_2034.jpg", + "sha256": "b14d1b793b771bbbee70d4af90b666ea2b7af91c18042a66ded5a43ff6a313c4" + }, + { + "kind": "file", + "path": "img_3302.jpg", + "sha256": "1da23c242b22a0b3c9825271c15b9ed6346e511622f610541d1a296db80bbfa3" + }, + { + "kind": "file", + "path": "img_1515.jpg", + "sha256": "b5df6c6859a89b2deb53b28de7cf20147e1cb3e2f28550e376e75517d84db059" + }, + { + "kind": "file", + "path": "img_1273.jpg", + "sha256": "d8ea791cabf9e2bf399aa864a465c86d380c9b78754116d9c78b74a2f72c3c38" + }, + { + "kind": "file", + "path": "img_293.jpg", + "sha256": "4769b316f5cd15bcb6dee0396eba9a9a740b089e53bf5279bdf0d46de38041f0" + }, + { + "kind": "file", + "path": "img_3464.jpg", + "sha256": "a340c3feed8698fbbc844210fc26faa8e476fe5c8baa95c96c3e293f4208b975" + }, + { + "kind": "file", + "path": "img_287.jpg", + "sha256": "1e8501ab38236bcbfb008a309efce80afdeb5953afbc5e18a3848193d8e1a7af" + }, + { + "kind": "file", + "path": "img_3470.jpg", + "sha256": "06e78ba7a38bec9ea3fdbab997980bc2d681fbcd53c61daeeed9a9e416f03c41" + }, + { + "kind": "file", + "path": "img_1267.jpg", + "sha256": "505bcdef41442b8d9aca918d98c1c1f7843df9eb3b5a16145718fd2ad533ac4c" + }, + { + "kind": "file", + "path": "img_1501.jpg", + "sha256": "113248f3d7302d3e0bd5d1d87ec1c4c44373913ad34a8f169d5a7c3f71c5628b" + }, + { + "kind": "file", + "path": "img_3316.jpg", + "sha256": "af9fa48b7a9c7a545ddef04410e4a74a24399b0711aa576090fef227bb0b75d3" + }, + { + "kind": "file", + "path": "img_4479.jpg", + "sha256": "5fd5332745188915e5b0218648d42bfa034d4f0a8483ff9daa32412b5e7d2199" + }, + { + "kind": "file", + "path": "img_4492.jpg", + "sha256": "13df0453a74562a014f09a0f7af1d8b99fdd667b39c1a307ad75eaa0c39b920b" + }, + { + "kind": "file", + "path": "img_2785.jpg", + "sha256": "ba713afad4a6fb1d182ff75707ec815505805aaa8eb9c8963c805c1811ec8ce1" + }, + { + "kind": "file", + "path": "img_2949.jpg", + "sha256": "f32652abd2411477aaddb70e7fa0297418875d5fedb4418db3642a6ff077c8bb" + }, + { + "kind": "file", + "path": "img_278.jpg", + "sha256": "5808bee419aaf03ba1d13bc579c9adb3fe70e4f92a75038460fe1bd760195ff7" + }, + { + "kind": "file", + "path": "img_2791.jpg", + "sha256": "3fcf84aaddd2aa6a0192f48b1eed7bfbf1060bb59ac922e8bba121640a384dbf" + }, + { + "kind": "file", + "path": "img_1298.jpg", + "sha256": "4ff9263ca143178bddced8db92adb7e6e69177085320b9d360606d27fd3b82ad" + }, + { + "kind": "file", + "path": "img_4486.jpg", + "sha256": "767e70cfc4980f0173279b29eb33c3394fe0907092b97baad178363a68083943" + }, + { + "kind": "file", + "path": "img_536.jpg", + "sha256": "1f09c757f02b40fec2e687b93c3b126b12f4ad6d0f89323e04636e739fdf40b3" + }, + { + "kind": "file", + "path": "img_2961.jpg", + "sha256": "739bb2c9daa5efdafcdf401134ead793a2a4e9d47203d5aa0356c31bed835739" + }, + { + "kind": "file", + "path": "img_2975.jpg", + "sha256": "bf3d59f56bef50c9c6ba344d19cc841a4a8ad3074496efdae457d2ab52b7c556" + }, + { + "kind": "file", + "path": "img_3882.jpg", + "sha256": "8fd7119de5eb4d0a11a6cd250d77e7ba40fb30f935166998f0ada7d105e1ea13" + }, + { + "kind": "file", + "path": "img_2544.jpg", + "sha256": "91e7c0bb538c8b685c694c6719d6469e7477c4a01f85b09aabafd5e7516e5123" + }, + { + "kind": "file", + "path": "img_2222.jpg", + "sha256": "7905f053be8807eca21732d908a36bfb2e3b21bcb89fd1d3b7ab022f4f181c56" + }, + { + "kind": "file", + "path": "img_2236.jpg", + "sha256": "74cf8f2a167eae5d0bf2765543cdd2e5152c22214bcf4f40d4058d5e82a23d05" + }, + { + "kind": "file", + "path": "img_4647.jpg", + "sha256": "16a97ba7ea7d89a11ac900d64ee7d89ec1eadfd28eb111e601512922d71fd3e5" + }, + { + "kind": "file", + "path": "img_3128.jpg", + "sha256": "25c564b312da7cd51f7369893ece1bb586ef1389b5e2dba588e4b17ed7603051" + }, + { + "kind": "file", + "path": "img_4121.jpg", + "sha256": "2391cedde8e390776364211a9b4ae60880747a77f9286fbb3ac7aa09bbc40015" + }, + { + "kind": "file", + "path": "img_3896.jpg", + "sha256": "c2a96476616decdbbb74d419b089d699747c73a12aeb4c6277b7d12ffdf1e9a3" + }, + { + "kind": "file", + "path": "img_2550.jpg", + "sha256": "fcbbe1cda9107f2ea12040816612dc95a267a3a16010f26d0b748808afa68cf9" + }, + { + "kind": "file", + "path": "img_1059.jpg", + "sha256": "5ebdf3318aa839c02df1526ed43d9f51ce7cd35d2fa22ce9e5090cdfd1ab16eb" + }, + { + "kind": "file", + "path": "img_3666.jpg", + "sha256": "c9cc59561bc9852874e9846e9265e7d50661aabdf81d30f551d039b1e195b602" + }, + { + "kind": "file", + "path": "img_4109.jpg", + "sha256": "5ce083cf49b5d56686e52246120a01db06618238c6dc6c5df49c877701b0680c" + }, + { + "kind": "file", + "path": "img_2578.jpg", + "sha256": "27bc9b345a442f4fa1efd13b22ad30efbb28e33c74c0a6e31880bade2290a8bb" + }, + { + "kind": "file", + "path": "img_1071.jpg", + "sha256": "a80c1df42727b2c5f0a77ba75d1eb807bf833e2318e5f14a75c3f221fea4f524" + }, + { + "kind": "file", + "path": "img_1717.jpg", + "sha256": "9ab76f5a6a70e60be39b35865d89382e8a54fbf107517d4de88a1f1b4997d149" + }, + { + "kind": "file", + "path": "img_3114.jpg", + "sha256": "e5c0a18b3fd2107c7612bd073a80c7fbf5b600b761743c6af0d8aa6cd241be94" + }, + { + "kind": "file", + "path": "img_1703.jpg", + "sha256": "444f5f1a3806fcf0cc5e80765fb92b63bb1f0d07d44251f7033cafddfad9d92a" + }, + { + "kind": "file", + "path": "img_1065.jpg", + "sha256": "06b48e037df48f10974d9a176826e412947c63eed82235b5339a08bf06f9b0e2" + }, + { + "kind": "file", + "path": "img_3672.jpg", + "sha256": "64e9747f5b53b28d73fa81602d6ae1d0787c1ba298a9b760fd31c0c8a6566638" + }, + { + "kind": "file", + "path": "img_3841.jpg", + "sha256": "a9272fccae53ef73c5bc0372f1a6266aeb0faca32840e206375505ea38b253be" + }, + { + "kind": "file", + "path": "img_2587.jpg", + "sha256": "335428bf7760cfb077e3c37414e5f0124ab8577fbd8b948e7c5c01e3503312fb" + }, + { + "kind": "file", + "path": "img_3699.jpg", + "sha256": "45aa23452039107e3af5b7f539b0fffedea2fe9dba7d8e46a5e8b868ee511af5" + }, + { + "kind": "file", + "path": "img_1930.jpg", + "sha256": "d2ffabe516ecf339498dcdca55914a085fafe1f0e2d0be0e744c27e8597cef8f" + }, + { + "kind": "file", + "path": "img_4690.jpg", + "sha256": "5eadaf8dbd68e79c5fb69eb3714ed568451a6d5f6b460c7b0f9c934d8c3a54f3" + }, + { + "kind": "file", + "path": "img_708.jpg", + "sha256": "69cb79879ae6024d9a4f8e13bb272bbd25bba59b400e9427457f2b5b4f00ca1e" + }, + { + "kind": "file", + "path": "img_4848.jpg", + "sha256": "5e849f9dbae91c1328d1e5e4c4320c6b073f8de231a998367c38b4954edbea6a" + }, + { + "kind": "file", + "path": "img_4684.jpg", + "sha256": "08d48f9e507e5a430cce3f793782137ae58e1b4a87c35bf6e35f0e0e1c318462" + }, + { + "kind": "file", + "path": "img_1924.jpg", + "sha256": "edaa83671636b7769ee8a398c204c862d9009999c1a1453aa056bb41227329fc" + }, + { + "kind": "file", + "path": "img_3855.jpg", + "sha256": "91a4649c6e8ba78086fe34cc63e6826aae4782b69804df3b12da658f61b9eafb" + }, + { + "kind": "file", + "path": "img_2593.jpg", + "sha256": "fcfcc745708243def319f83cdfbf1697e267de2c688f874561c901eaeb2870dc" + }, + { + "kind": "file", + "path": "img_734.jpg", + "sha256": "d680fa531843eed9bbb370b70f5c3e3b33da8b285305cc3d68c0173463c1ec4a" + }, + { + "kind": "file", + "path": "img_1918.jpg", + "sha256": "9af0c44aeeb6a72392c3742504a580fdeabb6d2514db666933c7c70c29b3f959" + }, + { + "kind": "file", + "path": "img_720.jpg", + "sha256": "9e1a67fab95feacd882c940bbc3220bc178dff10c4a4f91e15b4d951290cc316" + }, + { + "kind": "file", + "path": "img_4860.jpg", + "sha256": "0074864ce97f28603a9d77c0ac324fcfe7ccc736776ae3ea5beddfcfb775203a" + }, + { + "kind": "file", + "path": "img_3869.jpg", + "sha256": "06715daaa6c5f4fa8acbfbed6de89ecade96747fffa3da2edda1b054dce591fe" + }, + { + "kind": "file", + "path": "img_1139.jpg", + "sha256": "a55c3128c0e6cb5657dea0e72c17e32815f7e8fc76c460b6134bf27774907ba5" + }, + { + "kind": "file", + "path": "img_2430.jpg", + "sha256": "c0af5692629e347efec590774812799aad419e29d5d8b60a039fabe6e0745ac2" + }, + { + "kind": "file", + "path": "img_4041.jpg", + "sha256": "32a5563507dba4eaf4cdf943c83dbe1fb311e29054ef622bf5163b610b43d49f" + }, + { + "kind": "file", + "path": "img_3048.jpg", + "sha256": "c287fb308ccd852372f2bd20e10680794adc6fa6aab8e693b1446f703e14b723" + }, + { + "kind": "file", + "path": "img_4727.jpg", + "sha256": "81be35b6ec174736cd54f33ccfb3bbd3bdf8ee7a67062e53a9f838c8e3440372" + }, + { + "kind": "file", + "path": "img_867.jpg", + "sha256": "19972c9878b5f8b490e97b8fc80e3d2446c8aad99b2ffa07727c27825f6704bd" + }, + { + "kind": "file", + "path": "img_2356.jpg", + "sha256": "c5f6752d88a68b56b2e64a595b134c66f28ed2844323671a51a7b89df3be5acb" + }, + { + "kind": "file", + "path": "img_1887.jpg", + "sha256": "6eac3925447a63fb2f3f0bc8dbab49e13a53e2b89ad37019ae1921ced1b1203c" + }, + { + "kind": "file", + "path": "img_1893.jpg", + "sha256": "b0261e9b41428517471e356340774535ad2afc99b6242b48b1ae717599a2a6a4" + }, + { + "kind": "file", + "path": "img_873.jpg", + "sha256": "1609685401bb1465e5f20e03286e98cfec7ecca5f28806e7dd630398c1f4d9a7" + }, + { + "kind": "file", + "path": "img_2424.jpg", + "sha256": "1d93b8b3fc8c102d76859fe157a6177ff1f8c1f77b6bbde1a30308331a78fea8" + }, + { + "kind": "file", + "path": "img_3712.jpg", + "sha256": "785f4a8a2fb6399162bafe8d32c4c376c2baf5fbfce171118c34fe1efe80abfc" + }, + { + "kind": "file", + "path": "img_1105.jpg", + "sha256": "0d8db60c2dbed5fe850270e6a724df25bb4f397bf68982b35ecc34955f756bf8" + }, + { + "kind": "file", + "path": "img_683.jpg", + "sha256": "6545d10bde26795fcf2e0f2348c5359799450aff5a510a2a351316c7b5ce0e66" + }, + { + "kind": "file", + "path": "img_3060.jpg", + "sha256": "496575aa09925c564e84923ea7d6770e21e060ae21f044fc6798244eeaf0be06" + }, + { + "kind": "file", + "path": "img_697.jpg", + "sha256": "08d34ffa5d559d9f4fdc4517becb93f81ebbaac315cadb876ab211651cb1330b" + }, + { + "kind": "file", + "path": "img_1677.jpg", + "sha256": "cd244475df16e826a1eb717cae59d47ee4f364875b0403e247c01ec70f6d8f6a" + }, + { + "kind": "file", + "path": "img_1111.jpg", + "sha256": "bad7d3dc0f8ae915c5c17302f41193b20905086db046f7c1af3286c54b2f08c6" + }, + { + "kind": "file", + "path": "img_2418.jpg", + "sha256": "a0e3a0527af6a75f696df967b849885b1045625e0b4ade9a887a8fc4b6f96519" + }, + { + "kind": "file", + "path": "img_4069.jpg", + "sha256": "27decea51216f6398c133bace6ad2294999bbf74237ef82bc988b8d4bc921ba7" + }, + { + "kind": "file", + "path": "img_4082.jpg", + "sha256": "5264fa99fb61159f691dc01d0ee39d9079838243d071c5941315f2f181377b0c" + }, + { + "kind": "file", + "path": "img_1844.jpg", + "sha256": "b88c71aad7a1f117c5afe2447efee29b54ba2fe7b890a9946a42fb87f39e60a8" + }, + { + "kind": "file", + "path": "img_4928.jpg", + "sha256": "554a06917cfc5bf7dabc505208d372019ab0d1fb325f7df4129a03eef6c3b2f2" + }, + { + "kind": "file", + "path": "img_2381.jpg", + "sha256": "906f5b1ba408e6d1c7245a744d2dd031263bab6b4380916ed0174ca63e139f2f" + }, + { + "kind": "file", + "path": "img_668.jpg", + "sha256": "3c9978a948565ee6d4a7bed3d3ef583d78aa8fcfd732ca36fb64b5691414031d" + }, + { + "kind": "file", + "path": "img_1850.jpg", + "sha256": "df1e2fea22c08c0bdb45fb20f97b035b5dffa2fefe49f121a102ab2427f8cb9d" + }, + { + "kind": "file", + "path": "img_1688.jpg", + "sha256": "7845666cde6c54e65df18dfec6e3407c155cd778795d917d1079170929a5691e" + }, + { + "kind": "file", + "path": "img_4096.jpg", + "sha256": "906b851fc527e3983d48a4114fa3a0d694b184c629bf71a772439f58b927c453" + }, + { + "kind": "file", + "path": "img_3921.jpg", + "sha256": "e6a550eb5dddf212b7a4e98788d41991158d5f9f793d0fc9c7d1b0427a2de6d6" + }, + { + "kind": "file", + "path": "img_126.jpg", + "sha256": "0a6eaddb5e51d7308d9ebab95da8b24d4e69179dbc9c5336eabbe1141e4070c5" + }, + { + "kind": "file", + "path": "img_4900.jpg", + "sha256": "37c9f80a7141332e67025d9433e3039a767b91a1db82b46f692c1d595366c5fb" + }, + { + "kind": "file", + "path": "img_640.jpg", + "sha256": "e3e46e4c893bbe8440934284476b5d84e143b771555cf2632e2f73d55ca6157e" + }, + { + "kind": "file", + "path": "img_1878.jpg", + "sha256": "f90fa75471cb1412caa619b9ca93951bc419f80cb1dad2589e72db9a45beabff" + }, + { + "kind": "file", + "path": "img_4914.jpg", + "sha256": "1dc062e93c5f1bf5f81f29ac66ff7b085f7867691655f32d8a5d3cdb967e347d" + }, + { + "kind": "file", + "path": "img_654.jpg", + "sha256": "50c012661e803b55381aae766a1dcccadfae21dea541f2a0d89c18b66b3f8836" + }, + { + "kind": "file", + "path": "img_132.jpg", + "sha256": "6f632155e8a346b1faf46aa1628a8c0c3739907addae46c6e34f130ec20cfa7f" + }, + { + "kind": "file", + "path": "img_2154.jpg", + "sha256": "c6b4061126d8ce8b77d2c86d2a8a9aa1f71ab486bc6fad1e91434a0b85b54760" + }, + { + "kind": "file", + "path": "img_21.jpg", + "sha256": "98b61f371e01cfea15a71c6c1e2be828d8e6bb24c5925cc8306d84de96bd397e" + }, + { + "kind": "file", + "path": "img_4525.jpg", + "sha256": "35eb86e9f136bf18414ca0347c5b1e5e46f3fc6a6228653e5df2b85334623c38" + }, + { + "kind": "file", + "path": "img_4243.jpg", + "sha256": "6aabc882b3d9c20000a0a6e5d641284ef58b78acbbeb247f4ea0e1cc36887db3" + }, + { + "kind": "file", + "path": "img_3538.jpg", + "sha256": "88ed31bfd184d598d084dba8913cf991502abd0c66194cbbcc14cb7203b6c232" + }, + { + "kind": "file", + "path": "img_4257.jpg", + "sha256": "3e2174d7ea50f5b7472c76aaf3704cc8663e340a1814d62285620be85f800b7c" + }, + { + "kind": "file", + "path": "img_2140.jpg", + "sha256": "2f261e2f2e6b8a0d89ec6f946b7214e8d9d17d905ed1af79e27be69037277d64" + }, + { + "kind": "file", + "path": "img_35.jpg", + "sha256": "e889000b72bfdb97ded39c61e395fd82d07f5942ef2c387ed6b35afd75553a44" + }, + { + "kind": "file", + "path": "img_4531.jpg", + "sha256": "3b97b5070428cf3ef4d94e77a605d501512505daf28ce8d8008bac62984026cc" + }, + { + "kind": "file", + "path": "img_2168.jpg", + "sha256": "d1ce0914a5f5d2f5f47c0e8a9ad72a93cb9d6149bf3a91e076cca65eb677a586" + }, + { + "kind": "file", + "path": "img_481.jpg", + "sha256": "1fc46ca4c4b81eeab81a1ddef95a7b1bf7d198e1cd20c05c751ae1665c810a76" + }, + { + "kind": "file", + "path": "img_3276.jpg", + "sha256": "30b0c7533e4b63e7c5ade9c2b9d22deac6e739b1ff2c08843bb728cbab226a4e" + }, + { + "kind": "file", + "path": "img_1461.jpg", + "sha256": "40d430de981bd9a15044932175e07ab55b2ce5bef8db754f8e2ffb063609d3de" + }, + { + "kind": "file", + "path": "img_1307.jpg", + "sha256": "b37bdad42b92bcd89131a571a9d2abfe7ea49aad2da6476f97944b0484141ccb" + }, + { + "kind": "file", + "path": "img_3510.jpg", + "sha256": "03afff52da05fee2034b7e6b4e61b88506061a93df644db1e1ec0bc783bbf62f" + }, + { + "kind": "file", + "path": "img_3504.jpg", + "sha256": "0e4b842a83660747df5ac65bc677461b6729eac988e957839253b35f7be56577" + }, + { + "kind": "file", + "path": "img_1313.jpg", + "sha256": "74ede34ff6b0b977ef2408f2e5ccba447dd2fa137c404ff4958040e2d3718a89" + }, + { + "kind": "file", + "path": "img_1475.jpg", + "sha256": "59a7e6880f42b04d90f140e0900d902001875ceead7ee7abd11e61479aca2476" + }, + { + "kind": "file", + "path": "img_495.jpg", + "sha256": "b40f74fe2513d4b5aba441a948a4e7ef8cf1bae8884fc55ea42958c0277d23ce" + }, + { + "kind": "file", + "path": "img_3262.jpg", + "sha256": "fc5a377827de0304258d609d5c48307d2b27348b9a56114e56a65052c260d9d2" + }, + { + "kind": "file", + "path": "img_3289.jpg", + "sha256": "f410038ee8a1aab642cbaed2a091ef5ec33df7a9237b83c6c1c9f92d3b713a0e" + }, + { + "kind": "file", + "path": "img_2197.jpg", + "sha256": "46831cc855700aa95b12b713ebeac7e5b0d078724c5158aaacefeb1beb253a54" + }, + { + "kind": "file", + "path": "img_318.jpg", + "sha256": "ee6a141b7ce4c42f3bcf9b48ba6c03f802e78005676b3965abad085bd0baf72a" + }, + { + "kind": "file", + "path": "img_2829.jpg", + "sha256": "ac01aa7236202e1244bfffbba29c8d554896412e9dba8837c316ed351b98f12e" + }, + { + "kind": "file", + "path": "img_4280.jpg", + "sha256": "3062c00a43aba8a91068af0a2c64fd95098280a4e954b9625a58c3e0955c698e" + }, + { + "kind": "file", + "path": "img_4294.jpg", + "sha256": "195cd7a00e2a41c770b74effd15b386c29b6b230661879bf78038a6b1bb278ff" + }, + { + "kind": "file", + "path": "img_2183.jpg", + "sha256": "4c5b4d44f07a579e6e3463b11f68ac068eb71b263b3f942e76d7c166164098da" + }, + { + "kind": "file", + "path": "img_442.jpg", + "sha256": "77401162fcbce83c30ecbff81298dfe99f344013f51b698d61aa979291174f2b" + }, + { + "kind": "file", + "path": "img_324.jpg", + "sha256": "1c14faf81857fed028816609e7e685e02a2e64a8d00e301e5681ab4c7960546e" + }, + { + "kind": "file", + "path": "img_2815.jpg", + "sha256": "6fc63424540685fbb78fecfaa66e114c3009d9fd234261a28309c5ab92d0405f" + }, + { + "kind": "file", + "path": "img_330.jpg", + "sha256": "5535ca55c39d16fc072fdd10760bcc1271e7d067da735df6a559d2656ad28433" + }, + { + "kind": "file", + "path": "img_2801.jpg", + "sha256": "6c98d573768c3208671fde04a0687b4a321c4602d98395ed669f32eefb46016b" + } + ] + } + ] +} \ No newline at end of file diff --git a/tests/data/resources/pu-user1/apps/app2/datasetcmp/samokat-lite/v1/metadata.json b/tests/data/resources/pu-user1/apps/app2/datasetcmp/samokat-lite/v1/metadata.json new file mode 100644 index 0000000..628b8c6 --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app2/datasetcmp/samokat-lite/v1/metadata.json @@ -0,0 +1,31 @@ +{ + "@context": "https://schema.org/", + "@type": "Dataset", + "name": "HSE-Scooter Dataset (Lite)", + "description": "Датасет содержит изображения с комплексов видеонаблюдения на проезжих частях и дорогах общего пользования, включая зоны пешеходных переходов. Облегченная версия, состоящая из 10% датасета HSE-Skooter Dataset.", + "creator": { + "@type": "Organization", + "address": { + "@type": "PostalAddress", + "addressLocality": "Moscow, Russia", + "postalCode": "101000", + "streetAddress": "20 Myasnitskaya Ulitsa" + }, + "name": "HSE University" + }, + "contentRating": "General", + "dateCreated": "26-08-2024", + "keywords": "images,scooter,roads", + "maintainer": { + "@type": "Organization", + "address": { + "@type": "PostalAddress", + "addressLocality": "Moscow, Russia", + "postalCode": "101000", + "streetAddress": "20 Myasnitskaya Ulitsa" + }, + "name": "HSE University" + }, + "size": "186MB", + "version": "26-08-2024" +} \ No newline at end of file diff --git a/tests/data/resources/pu-user1/apps/app2/datasetcmp/samokat/dataset.yaml b/tests/data/resources/pu-user1/apps/app2/datasetcmp/samokat/dataset.yaml new file mode 100644 index 0000000..fa7c443 --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app2/datasetcmp/samokat/dataset.yaml @@ -0,0 +1,20 @@ +apiVersion: unified-platform.cs.hse.ru/v1 +kind: DatasetComponent +metadata: + name: samokat + namespace: example-namespace +spec: + box: samokat + filesApiSecret: basic-auth-credentials-not-hashed + versions: + - contents: + files: + path: files.json + sha256: 41950cc6a79e76019678f4c6426cc5ed4b92a6749746fd8cfc55876a24331b38 + metadata: + path: metadata.json + sha256: 8ac0b89460c19cf0ccdb10a47db5f964f3ec4c7ec10b6c09965bc72175bfa0f4 + readme: + path: README.md + sha256: 18f8fc8919ec6b1e9e0274c5bf8caab8e06e37e478ff5dbc9f8bdaa73263046e + name: v1 diff --git a/tests/data/resources/pu-user1/apps/app2/datasetcmp/samokat/v1/README.md b/tests/data/resources/pu-user1/apps/app2/datasetcmp/samokat/v1/README.md new file mode 100644 index 0000000..9e1d505 --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app2/datasetcmp/samokat/v1/README.md @@ -0,0 +1,5 @@ +# HSE-Skooter Dataset + +Авторы: Грошев М.С., Сластников С.А., Чертова Э.В. + +Датасет содержит изображения с комплексов видеонаблюдения на проезжих частях и дорогах общего пользования, включая зоны пешеходных переходов. \ No newline at end of file diff --git a/tests/data/resources/pu-user1/apps/app2/datasetcmp/samokat/v1/files.json b/tests/data/resources/pu-user1/apps/app2/datasetcmp/samokat/v1/files.json new file mode 100644 index 0000000..39b46b0 --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app2/datasetcmp/samokat/v1/files.json @@ -0,0 +1,24733 @@ +{ + "kind": "directory", + "path": "data", + "files": [ + { + "kind": "directory", + "path": "test", + "files": [ + { + "kind": "file", + "path": "img_3284.jpg", + "sha256": "03d4995239a480ab76b7f859ad63e28b26e1d3bb692b591651026de76e2a5825" + }, + { + "kind": "file", + "path": "img_1493.jpg", + "sha256": "b947e3ee84f134694d35b16ea354288c0c4638bfb5192fbb6a557b80e4e9f403" + }, + { + "kind": "file", + "path": "img_2824.jpg", + "sha256": "12a736e7e492a233a188102058a87a784944860e40165308fc52a8a465520f6b" + }, + { + "kind": "file", + "path": "img_301.jpg", + "sha256": "1fd909b3022b0781b632ae27eb9e979e219ddb8240be5ce783206bef674baeac" + }, + { + "kind": "file", + "path": "img_1487.jpg", + "sha256": "5507051466cedca2bf607f4388c911d932348b1bbb017d192e467940332b814c" + }, + { + "kind": "file", + "path": "img_1478.jpg", + "sha256": "4da100514d93557e278a5d1b18dcd33c87194bbd588ca7d2957a1ac895392c4e" + }, + { + "kind": "file", + "path": "img_4528.jpg", + "sha256": "aec479d8913b1a781a10765bbbdd48a508f7e6fbbe252aa98ea8ca5852190161" + }, + { + "kind": "file", + "path": "img_3253.jpg", + "sha256": "cc4b095d42a4ff058f2b5f223695904990caf6063db2e961f88274be2d40c244" + }, + { + "kind": "file", + "path": "img_3904.jpg", + "sha256": "bd26f0010ae0b35dc5b78c1b999b1135022625e33666cd13fbcf61442ba1a310" + }, + { + "kind": "file", + "path": "img_3910.jpg", + "sha256": "f5ec19d25c44d9280424da202ca4fcddb7fbe0de199fd9737eadc148cbff394a" + }, + { + "kind": "file", + "path": "img_1691.jpg", + "sha256": "55e5076f0e7959d9359942069f7e1f0afbb7403a16237f2f43e7e191fc66bc2f" + }, + { + "kind": "file", + "path": "img_3086.jpg", + "sha256": "d9335129c673675c0687310119e3b43a580d6be37655677e3967625d1bed1096" + }, + { + "kind": "file", + "path": "img_1685.jpg", + "sha256": "556ce3e95fa570616af276b943f999e32d1d89b76687668c0364c39570bae423" + }, + { + "kind": "file", + "path": "img_103.jpg", + "sha256": "87f11881ef6a8d9091d8b530bba6d7a82b095c6fde8a2dcfa8be9d8c70c34e69" + }, + { + "kind": "file", + "path": "img_4070.jpg", + "sha256": "3ea96eebdf7e2ebd3e7e20e20434c4cbb56d7233e57f68fad017cac61d2185e5" + }, + { + "kind": "file", + "path": "img_856.jpg", + "sha256": "a28205ea4a7404c1319203c611b41c32581eaa9aa2a34a0da2bc5a73ea6c1dfe" + }, + { + "kind": "file", + "path": "img_3079.jpg", + "sha256": "7686a02345d8d8cdff09f210fce8c81d50e7b60ac10d04f59e1097318fbc16b2" + }, + { + "kind": "file", + "path": "img_1652.jpg", + "sha256": "ffc3ef9e1c699514534182845f00fbd761a84cf2f08e7c2594d7e0d59cbb844b" + }, + { + "kind": "file", + "path": "img_4058.jpg", + "sha256": "7b714ea9ca969af4a7a9bae0e662f70056a3d9fc0fef48c3a68079b3b57d56f7" + }, + { + "kind": "file", + "path": "img_3737.jpg", + "sha256": "4750cbd58c52152eeeb124e56e418368b641dc340d23b02f4b8f78665df0b55a" + }, + { + "kind": "file", + "path": "img_4689.jpg", + "sha256": "80dac8fedd751b9e2b2ff4d3093f850d851de9f7c89fcc7d5c25b80778bc2014" + }, + { + "kind": "file", + "path": "img_1097.jpg", + "sha256": "501951278aac37d8dcc0e2e64d8628e5e289656c7689560dea545fe681bad78d" + }, + { + "kind": "file", + "path": "img_3119.jpg", + "sha256": "6fb3a975d6156d80b0d2af589e7ada4a1a38224579807830929e9317b2c677c9" + }, + { + "kind": "file", + "path": "img_1.jpg", + "sha256": "6dd7946deb14cd2a81641db85099a930d067d0b6f1e1b452869311a6785f2782" + }, + { + "kind": "file", + "path": "img_2950.jpg", + "sha256": "7db459c8b0db87c08a827180c78bf221cc3d25032e1b52ae9e4e048ccd40fc02" + }, + { + "kind": "file", + "path": "img_1518.jpg", + "sha256": "cf839b5027338c313b65841c6a167208cba715f71dc8afd334c58ac00db8cbbb" + }, + { + "kind": "file", + "path": "img_4306.jpg", + "sha256": "07f00646bcc9a8f9a7b4305d9ca605c082bc27d2a5d653757c12c41bd5ee07a3" + }, + { + "kind": "file", + "path": "img_2763.jpg", + "sha256": "1b7587e2646a8a4bce58ae1ba4bc7d70f733049faee4902e074104bffeed2aeb" + }, + { + "kind": "file", + "path": "img_2005.jpg", + "sha256": "b593510f0b41d18dff82cc236c2d99a8e9a1c521670d1b29ab6d202cd7114700" + }, + { + "kind": "file", + "path": "img_3333.jpg", + "sha256": "e899f88dbd66fe31f328423b0d46a3b36f37d45a9ecd2aa5e7a8bc72da7e9abf" + }, + { + "kind": "file", + "path": "img_2993.jpg", + "sha256": "55aba1f94f5fe2affa14e21a79db3f3eb1e998c3e62ef3159792d04af30a5d1d" + }, + { + "kind": "file", + "path": "img_1242.jpg", + "sha256": "8e7280c3085cfe1c98de155729db68feeac094a0e51de01126341e63b771dd17" + }, + { + "kind": "file", + "path": "img_1256.jpg", + "sha256": "562aa7c706b63314c5b6dcde7210a0f44315a1903ff6108aa5850fd423102288" + }, + { + "kind": "file", + "path": "img_3441.jpg", + "sha256": "644844d5b1468b3517d7144fe9dc231faa0a4ff2ba603f3c074c9947fc483478" + }, + { + "kind": "file", + "path": "img_3327.jpg", + "sha256": "3ca77db1d8da1c9e5138eb95b2817035c0635e4e770ce748de26050979b2ce84" + }, + { + "kind": "file", + "path": "img_1530.jpg", + "sha256": "052a177b32ed9a45fe774c4c0436693f957a1fb160df6ef8a1f264e6e5d64a79" + }, + { + "kind": "file", + "path": "img_2986.jpg", + "sha256": "02cba3d25ed1f2487b45ce3c969282dafc5c1c4c64b2b770806d663050c863f2" + }, + { + "kind": "file", + "path": "img_1257.jpg", + "sha256": "75d94836cd8f7a1e40d8eb00768f14efcbe9361fcc5f067a95c051b635e4baad" + }, + { + "kind": "file", + "path": "img_2762.jpg", + "sha256": "13835bef6b5486e90bcfacb10acd13b8264f77349a1b29b63f9e3608496cf65d" + }, + { + "kind": "file", + "path": "img_4475.jpg", + "sha256": "7f6ed38744cabe3f8eebdd5138dd290324ef6a24bf6680ba2ee287bde7c96bee" + }, + { + "kind": "file", + "path": "img_2004.jpg", + "sha256": "9075cfea1010dd654840e20e0175f0cac2a50910e803e45929f0833b38ee9c54" + }, + { + "kind": "file", + "path": "img_4307.jpg", + "sha256": "c77cd52e8355402db56d68acddc71a1de5ab1284c540273659b8a0556234194e" + }, + { + "kind": "file", + "path": "img_1294.jpg", + "sha256": "663963eb670ceca50a9b6c5fb12f94c9604dc8f66e05f4f1be8c93907019f393" + }, + { + "kind": "file", + "path": "img_1280.jpg", + "sha256": "5ae22426b46d00c5a28e7fef4343763b58d0eccabb210d7422829f1705fa4911" + }, + { + "kind": "file", + "path": "img_4893.jpg", + "sha256": "39b39f4c081d903ea52976c06219e9c7dce5a7f6a54b825d951b513f030e7b89" + }, + { + "kind": "file", + "path": "img_3642.jpg", + "sha256": "569ae852cb26070a28daf37adc829b06cc798e9c78ba60a3ca6992d1605134c9" + }, + { + "kind": "file", + "path": "img_2548.jpg", + "sha256": "c07ca1023bd94815f06367312d20681eb2292ad9b93097dec7288c3487da987d" + }, + { + "kind": "file", + "path": "img_1041.jpg", + "sha256": "1af5afbf4cd1916d6f439b5da504bd374e616072e3adf387db170cbbb7a6ba84" + }, + { + "kind": "file", + "path": "img_4887.jpg", + "sha256": "1cf7bdad12919ebe2755af44f594db0768833013b080c889cfa59cf8cecb2bf1" + }, + { + "kind": "file", + "path": "img_2206.jpg", + "sha256": "bf9ccfc2596bc8c7de5a81b7bf1285b695ac13f63504f24224a4be15ca87bf70" + }, + { + "kind": "file", + "path": "img_1069.jpg", + "sha256": "bc4c73b7fd66517047acb4e848cca154ffc19d566dd037bf4a11616d9533bb3a" + }, + { + "kind": "file", + "path": "img_2212.jpg", + "sha256": "484b09b568a1ca08e96b82518f1d6301fbfb773e28493c9bc4cc73f4d49d7058" + }, + { + "kind": "file", + "path": "img_4663.jpg", + "sha256": "1b1c109bdde8150c7d4307f583bb234ab8fcf14f34f4562bfef3745590667849" + }, + { + "kind": "file", + "path": "img_704.jpg", + "sha256": "23fdf0d8dae75d389e5ed1a02dbce4ba78d90e7f03c5c8ed8e6d634bd73662f8" + }, + { + "kind": "file", + "path": "img_1914.jpg", + "sha256": "40db64bd9cf3c44df389770b39a9d18df9f86cf6f18a3c628754737caff44ee9" + }, + { + "kind": "file", + "path": "img_4878.jpg", + "sha256": "a95f1a8f885bbd7ec3b34d9093ee9b102f746f256f2763c477eaf296cfa9a0bb" + }, + { + "kind": "file", + "path": "img_1647.jpg", + "sha256": "a55f2e3bec545492bffcf35a80b8119da60522488343633a34ff8f60e9742369" + }, + { + "kind": "file", + "path": "img_1121.jpg", + "sha256": "264d0308d1a0e1c8cdfa0f5aace2a9898c4ba733fda6c8cb8a0c81f8e1ea1c39" + }, + { + "kind": "file", + "path": "img_4703.jpg", + "sha256": "07c7fc7036188b72c887ec23b0b173aef196d94ac617525e55258058fc850f95" + }, + { + "kind": "file", + "path": "img_2400.jpg", + "sha256": "f540ded9e71d7155db1216a12f2dcac56c8d0c34f63a53c8ba30c8b2bee49686" + }, + { + "kind": "file", + "path": "img_4071.jpg", + "sha256": "033b0d45831fdcb0523a1a4a34f63a7ce5381a5c98d71f20c61971a4ee4f4b29" + }, + { + "kind": "file", + "path": "img_116.jpg", + "sha256": "56f3eb7c29d9ee1a06ba71d9f9bce0ad9d211470c129831b4e8e3d2e75e4695d" + }, + { + "kind": "file", + "path": "img_3939.jpg", + "sha256": "3a5ff4bb664a1ac3d0624d07c7d106786a1e44d9764a7c07ea2b23ee72911eb6" + }, + { + "kind": "file", + "path": "img_3911.jpg", + "sha256": "00324e743c02d5cddd12fda228329014ca2c99da651f6641453ae6750786e6a8" + }, + { + "kind": "file", + "path": "img_3905.jpg", + "sha256": "3236c9a291f07e7b5d8d8262aad1278e302adf4a320d290c0b60a243f041a56a" + }, + { + "kind": "file", + "path": "img_3534.jpg", + "sha256": "40ab4689a14d9c14c4dd6d6a9719202f6b1a5ea67de81d41472b9c1f62d5784c" + }, + { + "kind": "file", + "path": "img_1323.jpg", + "sha256": "106e66f17596aa51d634d310b70d37f289d431d9a56d03db5f37b9e05b925ba5" + }, + { + "kind": "file", + "path": "img_1445.jpg", + "sha256": "0105693326221bd76c7418e22eed05b43340804f61da82f63205e8aaa169bc18" + }, + { + "kind": "file", + "path": "img_1337.jpg", + "sha256": "7ce515bb79d13c630095fd5646e6359bac29c012f2af6efeede019a11865cf65" + }, + { + "kind": "file", + "path": "img_3520.jpg", + "sha256": "abf71e4205eb41369b7cb672addcfc989bbf15982217afbab7fcb8be8a6f92fb" + }, + { + "kind": "file", + "path": "img_3508.jpg", + "sha256": "f4e21d170cc9d6750b47ec947a087840d909ee0505247da0ba07d7fc5a890966" + }, + { + "kind": "file", + "path": "img_11.jpg", + "sha256": "a79b29364b9ab7aa8abf1d3ddc7c3cccfc645ed7f7a41b89489b96d2efff22a6" + }, + { + "kind": "file", + "path": "img_3291.jpg", + "sha256": "1a80e8a0efa51fdc6fb9060e8fa39e43a1e0203f206890938b8b0182e53dec2d" + }, + { + "kind": "file", + "path": "img_464.jpg", + "sha256": "8d68a288082569449b3c9df53d821a3040e5c0351cedd4115ef1b08e1e4d42a5" + }, + { + "kind": "file", + "path": "img_3293.jpg", + "sha256": "f0df6745e26d4e9320c2fbb6152eb21dca589267e7363fb22322fd3f3cdd9ee8" + }, + { + "kind": "file", + "path": "img_2833.jpg", + "sha256": "544aace00dfa09bcb517c73aa5fd52a7b3eeb616a2a383c69b38e82379f9f455" + }, + { + "kind": "file", + "path": "img_316.jpg", + "sha256": "f61cf622bf1a9dd12e79a9f8f83b189b7e2092ea8bf7038a16267241e5987f98" + }, + { + "kind": "file", + "path": "img_3287.jpg", + "sha256": "1bc41690e383153a9a2ae1a8b5e7880c759a485bb380ed99f967d3c820bb30bb" + }, + { + "kind": "file", + "path": "img_1490.jpg", + "sha256": "299c33d3df1ce43d2ddb4d60e77f304ae8d9a0df1b9f279f378f90c81f796a1d" + }, + { + "kind": "file", + "path": "img_2172.jpg", + "sha256": "a82383a3110bcc373624967a880141a85a34a72384f8eb7e0415010f70d36308" + }, + { + "kind": "file", + "path": "img_3278.jpg", + "sha256": "f3ab6248f4aec28e4be5d8316b5436a15855a43e4af334865ca0162bb71bc056" + }, + { + "kind": "file", + "path": "img_1447.jpg", + "sha256": "99c4c681cb4c2335e231484d12397875bdd532859df48437ab9058571b787a0c" + }, + { + "kind": "file", + "path": "img_4259.jpg", + "sha256": "e2a6f6830aaa6493c0c52d2ab91ced23f74a50b2f91b70703cc6a513e7f94299" + }, + { + "kind": "file", + "path": "img_1335.jpg", + "sha256": "007f4082c757e4e46b065aaf8005336ee6fa2a692736ee1efd0697491b7d31c5" + }, + { + "kind": "file", + "path": "img_896.jpg", + "sha256": "15771a25085dbbfda8e44178a706f89a4ad0a85d1cb88d1b565164d019dfd240" + }, + { + "kind": "file", + "path": "img_128.jpg", + "sha256": "f466b18aa8e24347254be8699f510995579cf0430d67268e21a6b66b5d1d1b02" + }, + { + "kind": "file", + "path": "img_4098.jpg", + "sha256": "b0cb7831b009cf73f8b2a9fd2caf425dafbe59afef8d371bc4234e0af1faf0ee" + }, + { + "kind": "file", + "path": "img_1679.jpg", + "sha256": "ce3ba88d373c8b7e7e29d2db1ecdb770647d46d6a9f97f102be5bc31a49358aa" + }, + { + "kind": "file", + "path": "img_2402.jpg", + "sha256": "cdac4b9a830194ca6946fa2769a6504750c13b7be2fabcf44956b6f77e3df259" + }, + { + "kind": "file", + "path": "img_1651.jpg", + "sha256": "e639048dc66b298baee4e3946512e404be41e75ec9dbb1fb97aacc3e1f082a14" + }, + { + "kind": "file", + "path": "img_1094.jpg", + "sha256": "678aa202f2e8e309078d03d2d7651e7f0e0bfa9223ad9f21be4a246bf40fb059" + }, + { + "kind": "file", + "path": "img_3683.jpg", + "sha256": "349e046c111ccc0b854f342b7d764371344eef8656e237b6d41cdab6ce4e3e94" + }, + { + "kind": "file", + "path": "img_712.jpg", + "sha256": "cb2d22b870eae7506faa556588f191386cef5e14457c389f53bea598b82d4ffd" + }, + { + "kind": "file", + "path": "img_3697.jpg", + "sha256": "c4a9717ab3d1872bd46d4dd91ea9a7602f2b29581220668e7b46fe3b907a7aa8" + }, + { + "kind": "file", + "path": "img_2562.jpg", + "sha256": "8566d887e63c91c99ea8993771769afcd3eed38ff8643618a12c4221b5a15b92" + }, + { + "kind": "file", + "path": "img_2204.jpg", + "sha256": "a93df1b066b43555d3d8b8657af988f6c2826e25180c6fbb8108524c05de1e4a" + }, + { + "kind": "file", + "path": "img_921.jpg", + "sha256": "07affc0693ed9244e02e910538b0582776c10f5a622d192792d8b439d35aeacc" + }, + { + "kind": "file", + "path": "img_1057.jpg", + "sha256": "f08b3147dadf7ab83f0109b01251e2db1f7217f4e9939c616ff1b0396a1578a4" + }, + { + "kind": "file", + "path": "img_4891.jpg", + "sha256": "8b444f4b0d21176ee9cb08c97e85bcc1a95d82a88925def8cbf70acad159d94e" + }, + { + "kind": "file", + "path": "img_2947.jpg", + "sha256": "e301eb6f395f869a4f162eadcb3ee41be5f7630717ca8886c2c3f0b7c2fb47ec" + }, + { + "kind": "file", + "path": "img_2760.jpg", + "sha256": "3141e147cc61ffa3a8ca7d4a3cff578122dadb3b52afe1433d53dbb717acd09f" + }, + { + "kind": "file", + "path": "img_2774.jpg", + "sha256": "b3c277fadef9824a80e4eb21497ee6193948c123a2ca760aa4c3af2dac94d3dc" + }, + { + "kind": "file", + "path": "img_1533.jpg", + "sha256": "2884a30cf9bd23ceebe62221d773a8247477435d355a6a6d76b1edf343551b81" + }, + { + "kind": "file", + "path": "img_1255.jpg", + "sha256": "d3661d48e209a6778161258a2a3ac96216d58f0fc77dc8d5b783b54beede49cc" + }, + { + "kind": "file", + "path": "img_2748.jpg", + "sha256": "5622014f98996917ded2d964e27e8d39d5c79e419a288dcf9fa7ba186787ee5a" + }, + { + "kind": "file", + "path": "img_3325.jpg", + "sha256": "a697aaacbf62eb9ac10be139a902351207d7988cbeb7085eef2eb3d5f0fb22aa" + }, + { + "kind": "file", + "path": "img_3443.jpg", + "sha256": "51b0c9b60c9e215dae170c575ab440c2d6f1b35d6d50d4c0590bd3748d77eeb3" + }, + { + "kind": "file", + "path": "img_2985.jpg", + "sha256": "3b7f13afcd285bab89a2f6f84206892c3e42244f20f90f672ea324f635ae4667" + }, + { + "kind": "file", + "path": "img_3319.jpg", + "sha256": "7ef084993ae60c45a55c487860fcc2321990f71f1d9d0c79fa16e89a212bfd17" + }, + { + "kind": "file", + "path": "img_1268.jpg", + "sha256": "c9ef8bf091d326632692c3df709317e8b97df3b7638caab950958ab1da80c6c2" + }, + { + "kind": "file", + "path": "img_2952.jpg", + "sha256": "38d27e550d3cfc8490c796cd8b4d2d4fc71c27f2c004679adbb6704790fd6976" + }, + { + "kind": "file", + "path": "img_511.jpg", + "sha256": "012312470e9b9e0cb8b58f333b264a96b2befef8877a653e2062a45833012c5a" + }, + { + "kind": "file", + "path": "img_4884.jpg", + "sha256": "1dd132d41993a0bdcf8f97a605e981bf01c073178a1f8302cb5ec410cd3a75b7" + }, + { + "kind": "file", + "path": "img_3655.jpg", + "sha256": "9fb330561beec52f855c0b959178a757986a8081a59a7af550aaec5d58389337" + }, + { + "kind": "file", + "path": "img_3641.jpg", + "sha256": "4ea9ca173e7d28f838eb8bb31d9f63698dff6476ae4641edef321ba1202a6437" + }, + { + "kind": "file", + "path": "img_3899.jpg", + "sha256": "8689623db134512714f0720ef91cc835ca4d62b579d97cfd1f87592b60fd3fb7" + }, + { + "kind": "file", + "path": "img_908.jpg", + "sha256": "3df3e684a40c63d56d7fe54f8399945c7f8b65dde91b0e0fa49b880d9d02a47d" + }, + { + "kind": "file", + "path": "img_4890.jpg", + "sha256": "208514b524940b394351a6db94fc965ddfbaa226a704c9fc9fe67294c9238bfd" + }, + { + "kind": "file", + "path": "img_1730.jpg", + "sha256": "1c69a2a379a7976c683007ca461c07fbec0850fb2d676b5f0845732dca5bd305" + }, + { + "kind": "file", + "path": "img_1718.jpg", + "sha256": "5a1a6eff17175733c8548d1be1b355e3b58ca4866f582a1568089bf539be6175" + }, + { + "kind": "file", + "path": "img_3669.jpg", + "sha256": "e43e79f997d87fd4d7e55e9a4a37f2d73d5e4b8ab3980f859eefe16883933193" + }, + { + "kind": "file", + "path": "img_4112.jpg", + "sha256": "91c857a4424be08839f59e83a29847ffd2a9d6a95289abc8b55d7d32bc98b2c8" + }, + { + "kind": "file", + "path": "img_2205.jpg", + "sha256": "e2419401b355376982936d682700cd3df96f5a48d16eb1dde2963023709cdd09" + }, + { + "kind": "file", + "path": "img_4674.jpg", + "sha256": "599e33ca432f9e981741dde1825158a2ec0c74dc9b94b55e5fb8c7b5ac8b27ba" + }, + { + "kind": "file", + "path": "img_707.jpg", + "sha256": "6e1c2b69f03600d9742c64563697478f1ba62d2b3dbdcabfdeaa4b81d3aacd5c" + }, + { + "kind": "file", + "path": "img_4847.jpg", + "sha256": "013d6ae586b0cef98a9aafaa28bffa2643105d75af6eca94bab9f2706e478c62" + }, + { + "kind": "file", + "path": "img_3872.jpg", + "sha256": "960d279ea4d6f35c79a1e5c5a5e44302d923c4c0c687e621c4cd55378e0f9a80" + }, + { + "kind": "file", + "path": "img_4728.jpg", + "sha256": "51af88288fdcc255efc7547f894ead6a80920b08fa75e54f2c2c4562393d5863" + }, + { + "kind": "file", + "path": "img_3047.jpg", + "sha256": "8734dd17f6e0a32aa0b63198baf566088006d21b4407c9ae8005c56b07d1b5d7" + }, + { + "kind": "file", + "path": "img_1136.jpg", + "sha256": "8193d8c19699acd41bdb31604185f0c67ddc9a6618308958b952618c7a208410" + }, + { + "kind": "file", + "path": "img_1122.jpg", + "sha256": "43f3d0314b0c689944fd06c3439835ff5089c92d892769bff25cb1a2a5f9a153" + }, + { + "kind": "file", + "path": "img_4714.jpg", + "sha256": "c07b87413c02dc4397d51da2887757cd43e053d1b853910fff4b191c0e8e58eb" + }, + { + "kind": "file", + "path": "img_101.jpg", + "sha256": "a1dadfb6239db1546d511e593ebcf82e2563463ffb6bfb2f994be96d65869b9e" + }, + { + "kind": "file", + "path": "img_4099.jpg", + "sha256": "9157220ca81d008d3ce56385b923bf32dc81e11f3f844a1ca2cdf66465178c37" + }, + { + "kind": "file", + "path": "img_3906.jpg", + "sha256": "1b1db29822a7e790e84ad5e9a3bb04229a06241fa7615d08fe206e67d023d879" + }, + { + "kind": "file", + "path": "img_1334.jpg", + "sha256": "d16744250ceddf824b0b3f5f0277793219397298f091d8ebfe808edd6bc6764f" + }, + { + "kind": "file", + "path": "img_1446.jpg", + "sha256": "93ff954991c8c9e1a02400e3290fec58e9fc27ea1047e53a18df99cfe0929c19" + }, + { + "kind": "file", + "path": "img_2629.jpg", + "sha256": "aa2ad6a7c6a36f80e0a58d2e9c2704dae1d576c5308343bb046c4dcd257089a6" + }, + { + "kind": "file", + "path": "img_1320.jpg", + "sha256": "e7caf505644dda1016a58a2ec4a3b31ffce510ea3cb0dd251b03fe7c4d6f1fdc" + }, + { + "kind": "file", + "path": "img_2601.jpg", + "sha256": "9899245e8ffa481059b3c844b271be3326851da33959b304e1b1a8c81fe75820" + }, + { + "kind": "file", + "path": "img_2167.jpg", + "sha256": "009cec2b07521cf92a7d4d6e28f1e0c0c2b7d6344f6776f3fa9df1280fde7dec" + }, + { + "kind": "file", + "path": "img_4516.jpg", + "sha256": "80c1a7176f71d8843f3f25dec5fad3385f48b162eda04f7ff5c05851ebe435d3" + }, + { + "kind": "file", + "path": "img_3286.jpg", + "sha256": "802c67847466870fcea8511dd2a7ee7de880b04e8931d52d8f3c4c3a8c377dd6" + }, + { + "kind": "file", + "path": "img_2198.jpg", + "sha256": "d17ad0fc6ec51f7687588790e8bd71914343ac80e2d7b0f21d79a835ededdb3e" + }, + { + "kind": "file", + "path": "img_303.jpg", + "sha256": "239054d25291f2d4177d5b40b7912c1abe43cda9a29b4eaf0d8218c9ce877c40" + }, + { + "kind": "file", + "path": "img_307.jpg", + "sha256": "6ff4ec31c4a4abb1b974d1f3e3c7e3d66039fbe0abe5cde32b222729c467cb69" + }, + { + "kind": "file", + "path": "img_3296.jpg", + "sha256": "9f43c22e5be5f2e3afe2ca22c9cc19e7150dc5186cc5aade92e7f4edb60db76d" + }, + { + "kind": "file", + "path": "img_2822.jpg", + "sha256": "1d623407022385386e77cbe5e7b8121359aa9e1875bcdd3a5d8987918f6ec827" + }, + { + "kind": "file", + "path": "img_1324.jpg", + "sha256": "dd03824666c3a9acbcc3fc3507a8832ab9a7fb7386c8096022a804a6d2b2d6f0" + }, + { + "kind": "file", + "path": "img_1442.jpg", + "sha256": "4b6a80fdc3706dc30205cfa278acfba5bc52b7d1d2c74bcf0f73b2bacb28bfe2" + }, + { + "kind": "file", + "path": "img_3241.jpg", + "sha256": "ef801cf503d21abed5224153aff624dee6e6befaa740aeb948b9254c5ff9f353" + }, + { + "kind": "file", + "path": "img_893.jpg", + "sha256": "cbca56e32a4fee88df7727b110bd8267dfe37b9d7167ede7f6b6614463d02831" + }, + { + "kind": "file", + "path": "img_3043.jpg", + "sha256": "c35625e5874cda732f8cae8a5f68d8a58b9f0100150b420ed0a9d4c5ad723fb6" + }, + { + "kind": "file", + "path": "img_4704.jpg", + "sha256": "6be4fac1293ecd73c3b787bf1cd4f214ff833a28da15699688ac512bceb1f473" + }, + { + "kind": "file", + "path": "img_2413.jpg", + "sha256": "995b5c2eaf4029405aeb15384889e7b56e7d446553d69b127d6fef694cc6a5ff" + }, + { + "kind": "file", + "path": "img_4076.jpg", + "sha256": "71276aa84a4fa1e060dd4839ca5e532f0f4b867f3a70ac0f0689a77394a37024" + }, + { + "kind": "file", + "path": "img_1907.jpg", + "sha256": "11456d7c649f21b0464cc7fc207cead675aafaa8cc3a8f0c9dace53ba6ce7532" + }, + { + "kind": "file", + "path": "img_1734.jpg", + "sha256": "e02ff7da29ea7b60342e5ffa7b44846783a66aee656302c09f7494413fbef7e6" + }, + { + "kind": "file", + "path": "img_1052.jpg", + "sha256": "b4b0bd8871d548c6a3a2c8fa5cb611320dc048578b7b76d14cda07ecd41f8942" + }, + { + "kind": "file", + "path": "img_3651.jpg", + "sha256": "e60f910d43f569dcf4f810176c171e8d365b2a32dedbbf5847e99ff21a55c115" + }, + { + "kind": "file", + "path": "img_4880.jpg", + "sha256": "2c69684ad6f5e08a2cc4c517c91080c78eda9963cc423072c4133784150deb33" + }, + { + "kind": "file", + "path": "img_2567.jpg", + "sha256": "ad3b08632efefed21955fb3e4aa52f6cf992572078b48a214665b7c46385042c" + }, + { + "kind": "file", + "path": "img_4116.jpg", + "sha256": "4fecda559aa675d303ae2d642908d7c2bffb09ebb37f46fff2f85e78bc5c0083" + }, + { + "kind": "file", + "path": "img_3679.jpg", + "sha256": "d73003d11473f42bf78f3c5142b1da0c9b646622000777083e92e437dc91219a" + }, + { + "kind": "file", + "path": "img_4102.jpg", + "sha256": "4066b2d379f2a3d04f0ac5e52920448483cb2fd3a732a2e24eff43f126be67c4" + }, + { + "kind": "file", + "path": "img_1536.jpg", + "sha256": "5313ac80ebbade276dd141e3e07693db27676cda9f2c5fbf7ae2658602a69898" + }, + { + "kind": "file", + "path": "img_1244.jpg", + "sha256": "911d4aed8233a8c240d4a26ae7c8e135280107e4a64db5bc488d7e24ee0ddc7c" + }, + { + "kind": "file", + "path": "img_2017.jpg", + "sha256": "64c5a80711e83103f70e4392c7947e93ca0bb0f384691e002f7b17bbcb363776" + }, + { + "kind": "file", + "path": "img_1278.jpg", + "sha256": "02ce456ee87e23acc482043175fadf30414d1292de1bf5c1c9a5fb7af78b9ebd" + }, + { + "kind": "file", + "path": "img_4473.jpg", + "sha256": "6729184f0c329b43f1438c55d8ab6f514ad91afcda7f72ed18192357cc2eca4f" + }, + { + "kind": "file", + "path": "img_1251.jpg", + "sha256": "eab02b50a30e101bc22a1928c583605227eb0423f9c0df13c6701c13ff0d6497" + }, + { + "kind": "file", + "path": "img_3320.jpg", + "sha256": "c7714e023d03b66e1a43c03761f32e528b6957906454b855c412b8898a4080cd" + }, + { + "kind": "file", + "path": "img_2943.jpg", + "sha256": "71cdd864b90a7c63c5cfef2a15da0416c8658d5cb8cd734ad2f4d9636ce53109" + }, + { + "kind": "file", + "path": "img_272.jpg", + "sha256": "1e5605c990e0b3f6c23ad15e8be1c006723167a98c3ed59c7d2fd5af794a7d37" + }, + { + "kind": "file", + "path": "img_2200.jpg", + "sha256": "beb0972c1af9255d6493f232648e4f58fa681b03bd8db672de57134b2858d6e9" + }, + { + "kind": "file", + "path": "img_4895.jpg", + "sha256": "d78f49f85618039e14fa77473d210f4ff756d5ce198aa1a5ca56d9d6e45ce9f9" + }, + { + "kind": "file", + "path": "img_3693.jpg", + "sha256": "bf373efe5d3e8713855ba124f221c5ad534059670e8046f27d662ab71008863b" + }, + { + "kind": "file", + "path": "img_4842.jpg", + "sha256": "64bff6a492f6aadbc1fa129334c3696f2186f8c8741d305af37d2b38f94ccf05" + }, + { + "kind": "file", + "path": "img_716.jpg", + "sha256": "6c1cb5280848198a9a1cee1c1eb8c6ec1915ac8dda5cdf5cc7ad753db546bd54" + }, + { + "kind": "file", + "path": "img_3718.jpg", + "sha256": "019c7a4d8dbe2d48cd35c1eca91fb57af137092e10e837dce3d6384dbed85c9a" + }, + { + "kind": "file", + "path": "img_2412.jpg", + "sha256": "e29316b5c44f82ba4c10d2208c0e41a4edd9e95e217534aaa44a429bb0dd5ed1" + }, + { + "kind": "file", + "path": "img_2348.jpg", + "sha256": "32e8f5bfe4be9b7406ddf68aa8c68e4c18b55b9a303f03edd58a8c8fcdad6141" + }, + { + "kind": "file", + "path": "img_1127.jpg", + "sha256": "5f79904080ec75a7cd9f4aec25b4eb389809386a6e299386864351ad25d17b47" + }, + { + "kind": "file", + "path": "img_3903.jpg", + "sha256": "6ac947c0d7259f3b8077394308f027d6f597f9ab162e4d18d5da1365e613bed2" + }, + { + "kind": "file", + "path": "img_886.jpg", + "sha256": "fe2298a187a22f35153ac7e23b03549b58539a20314a12d7c1de9dc9bfeed380" + }, + { + "kind": "file", + "path": "img_110.jpg", + "sha256": "18e6f5f809595d70c5ed63a657d4bddf472029049578fe9619c13fe1504523b2" + }, + { + "kind": "file", + "path": "img_4922.jpg", + "sha256": "0fc4e6b1854ba89ca9e8b2ca51815b564f8874f1287eef79e3845c019e278f25" + }, + { + "kind": "file", + "path": "img_4275.jpg", + "sha256": "713758812ec92ea017af5ffdf8912659104bcaec5378cd8491145869167c1a69" + }, + { + "kind": "file", + "path": "img_2176.jpg", + "sha256": "818aff324c5bfc33de515c974f80a0cfa95a7297e47bed8958ca4e650921f793" + }, + { + "kind": "file", + "path": "img_1457.jpg", + "sha256": "575648865d28d5348d68cabe0e3e95a37421c71ab3cd1a90c53e078dff76da62" + }, + { + "kind": "file", + "path": "img_4249.jpg", + "sha256": "5b9b9f53bbb2ffa43e6a6a2be4f59264fa53c1bdeb54393d3c1d783b6ad73d67" + }, + { + "kind": "file", + "path": "img_3283.jpg", + "sha256": "f374faa80a3212c8c49be26b713c463e8f2d86e389bf4dc2bb9e89b06b54988c" + }, + { + "kind": "file", + "path": "img_3297.jpg", + "sha256": "645724363c7c73fee5d317e0415c3a6fe9abcf29740a5c0d5bcb5bfb48d63190" + }, + { + "kind": "file", + "path": "img_1480.jpg", + "sha256": "4778a487c35e837d9d4b7cc42e377f1671bfd152d76431fb0a9b12469a616a4e" + }, + { + "kind": "file", + "path": "img_476.jpg", + "sha256": "48eeee9e47505aa87a73b0ad2e443b3452f9030d92e6084541088f652259a0da" + }, + { + "kind": "file", + "path": "img_1496.jpg", + "sha256": "24f55018073fab2d3caa17d9f197adffd85eaec395bfcf9d507470a6a6d0f2e2" + }, + { + "kind": "file", + "path": "img_2835.jpg", + "sha256": "423e21bde6b2864006bc936b5801d23e408676864e6a42f93b6a7d3acc58147d" + }, + { + "kind": "file", + "path": "img_3524.jpg", + "sha256": "7358ec9ba3dd95a045682f85957d605bc8927ee006b6272bf36869c1cdf93f86" + }, + { + "kind": "file", + "path": "img_1333.jpg", + "sha256": "6203e2e964274ae68f5538c1aafa8d4611c8eacdec4b77c7b947274d355888d9" + }, + { + "kind": "file", + "path": "img_3242.jpg", + "sha256": "186aaca105937e3e0b7f682fa88718c52db9309c52438d56e8a49d297219939a" + }, + { + "kind": "file", + "path": "img_2606.jpg", + "sha256": "6e19afe244b5a16a39ef61f714557cd2662226b39917dcd68b4998eacd7259b0" + }, + { + "kind": "file", + "path": "img_4511.jpg", + "sha256": "02d54a54e8a45cbd6c946f436c717caf0c1c3533c6baaf64ca2503b2ed6ee534" + }, + { + "kind": "file", + "path": "img_112.jpg", + "sha256": "2f424db962cf7b0f3ed05609fefa596af9c22c1598768f2238eebb664b159729" + }, + { + "kind": "file", + "path": "img_106.jpg", + "sha256": "26a9a391d28c0ef7c3049c912873917f2f1e98de98a3070c7daf717a554791f4" + }, + { + "kind": "file", + "path": "img_3097.jpg", + "sha256": "0cf4ee0117c3fb6f1f36d4457ebc69094886478c80fb24824c3734799b6d4125" + }, + { + "kind": "file", + "path": "img_1680.jpg", + "sha256": "5f09057d4d1f0bea9fbc9534d770563af55f8dda353f5474d8e0297e8c85e89b" + }, + { + "kind": "file", + "path": "img_890.jpg", + "sha256": "d6747804031c20848200d26051a2fcfe0e72d93466e0837e072b012142ab976d" + }, + { + "kind": "file", + "path": "img_3901.jpg", + "sha256": "844c4c7ae2a312a9aa32cf34b4320ccb5f6dbd168f2c7658bd5c57b3d6803281" + }, + { + "kind": "file", + "path": "img_4061.jpg", + "sha256": "6f2c290426819d857abea03e8c7455af72defc983b4b4add41b99052b04edd02" + }, + { + "kind": "file", + "path": "img_2410.jpg", + "sha256": "57c22bf04e7cd8cf6c1dbd1456466a031e9581c2c733af278022daf5abc2aafe" + }, + { + "kind": "file", + "path": "img_2376.jpg", + "sha256": "6dd1ea3a084a3255323392e1b839489ebc9683bb52ec6d6a9e97993161b847ae" + }, + { + "kind": "file", + "path": "img_4707.jpg", + "sha256": "a22930cb8bbac18e6d3aedf1db92d3e744d6d8bcfd37fb9dfadd96f0a10e87ba" + }, + { + "kind": "file", + "path": "img_3068.jpg", + "sha256": "a9e1d74d83e467a185ba15ebc45cdb0a5f56d18facf31b421e937ecbb5ae6851" + }, + { + "kind": "file", + "path": "img_4840.jpg", + "sha256": "55f8d83ebddbcf0415efb1ef2b35767b9cceb8d6ab2daeae1b118fd9d41d9bc6" + }, + { + "kind": "file", + "path": "img_700.jpg", + "sha256": "bcdb2133fb981f008f441c261218121b033cefa946d6cf309dbd4ba384a05ccd" + }, + { + "kind": "file", + "path": "img_3875.jpg", + "sha256": "2cf328a2e05cb03b6525bdb6698dcdb5574505518e238b2143dcf53f46f28b4c" + }, + { + "kind": "file", + "path": "img_1045.jpg", + "sha256": "6768870d8290dac8d59ff83e70e762aad0e6b071fb1655332cfe65fa4730a458" + }, + { + "kind": "file", + "path": "img_1051.jpg", + "sha256": "88fa9fb792e414cb8e63333533ed41a8666a3a8cee572ca7fc8948ada132103d" + }, + { + "kind": "file", + "path": "img_1737.jpg", + "sha256": "513820ac18e83eea5b2527df9acfd9c0f9e98cff1cdf265835dfe9356551f044" + }, + { + "kind": "file", + "path": "img_1284.jpg", + "sha256": "f1eaedd1c0a86a14955c79c944c5e1f43cc3f8525c1958e12b9fe2bd65fef7b5" + }, + { + "kind": "file", + "path": "img_2799.jpg", + "sha256": "850c047aa4194d56f1fe0169bb8dcbe5974a0828db6781925843530809681da4" + }, + { + "kind": "file", + "path": "img_2941.jpg", + "sha256": "c0e05176862d450f92b399a4969055a2aa7cc7afc7d47cdf2365c927f6031b4b" + }, + { + "kind": "file", + "path": "img_2969.jpg", + "sha256": "7254622f86a13fef93e0a9ac0f22edddafea688854f15e4ef1d5ab5a06054f45" + }, + { + "kind": "file", + "path": "img_2996.jpg", + "sha256": "36382d5b1784f26bb19f430afb4d7ad7c2268adf9d50b4783fc99fd72d771a23" + }, + { + "kind": "file", + "path": "img_4459.jpg", + "sha256": "5043996eb23289f92e1fcf5f6b9c38d7d79030425b65fdccf8964590f72f2ee1" + }, + { + "kind": "file", + "path": "img_4303.jpg", + "sha256": "7faa7fe5d8153642febfe2553c86cc93daeb1d906b506bf9cfb0d88cad7a6430" + }, + { + "kind": "file", + "path": "img_3478.jpg", + "sha256": "90b25649992344e621e03dccf3dfa672c397b6ad8123dc663cafb8237a133f61" + }, + { + "kind": "file", + "path": "img_1508.jpg", + "sha256": "49066442fbf4c96c4af10086c50c432bc8e1177d47759e387b37349597b83bf9" + }, + { + "kind": "file", + "path": "img_2767.jpg", + "sha256": "bc5b54126620af73270b1781971a73fc860dcf53839a1212554c51f6a72d7618" + }, + { + "kind": "file", + "path": "img_3479.jpg", + "sha256": "07798c789cef10b3b241bcc7d007ad851e8820c238537cd83509ffeeb8166a06" + }, + { + "kind": "file", + "path": "img_4464.jpg", + "sha256": "47ac223c71ca13288fef45ad8384111c8db138676f8257a00db841f037e483cc" + }, + { + "kind": "file", + "path": "img_2029.jpg", + "sha256": "2c24cba27c007ea90a19f1c337d33516c3eab2e7b5928a80f8512eb54e3f6bdb" + }, + { + "kind": "file", + "path": "img_1520.jpg", + "sha256": "58fa4a5b0360eb23c312c0f5550bc9ddcccda9551808e4c1228967a56c725632" + }, + { + "kind": "file", + "path": "img_1291.jpg", + "sha256": "5dcb644e4d0eaa89a94c02736dcd666e10135639c30b8959a18e0618a4de0ab7" + }, + { + "kind": "file", + "path": "img_503.jpg", + "sha256": "21d56381e337dbac89bf2b2df79b275fed676fa8988caa0362b7789a28e5662b" + }, + { + "kind": "file", + "path": "img_926.jpg", + "sha256": "0f2bc8d14b177de3ea66876659b736bd82a0b6b9076f5d56b1da4abcde6264de" + }, + { + "kind": "file", + "path": "img_3121.jpg", + "sha256": "e97ae23ea2898b97654f7e36e0902d69e690717c3b32cd70039c563c839f6e65" + }, + { + "kind": "file", + "path": "img_3860.jpg", + "sha256": "0820beda28b525b67a740d2de28aae607a12ea9b518093146b65a778870052e4" + }, + { + "kind": "file", + "path": "img_3874.jpg", + "sha256": "ad6624eb7079c786e435f7780ccf49a82766c422ab4b806952e6e28386db4b64" + }, + { + "kind": "file", + "path": "img_3684.jpg", + "sha256": "16cef993673c9f141214ab8481ef507006d183acafd9ffcacdc0caf8279750f5" + }, + { + "kind": "file", + "path": "img_4712.jpg", + "sha256": "e30617592cb60b11a960b1c7ff750e05462cf76a909facb5fb987dc1e0885bba" + }, + { + "kind": "file", + "path": "img_1124.jpg", + "sha256": "3867be435b954f1eec02364fad3511ba0b6bdd0d8bc4ce0714ce739e3435b8d1" + }, + { + "kind": "file", + "path": "img_3733.jpg", + "sha256": "a2cb04edbb6a2e8eae8aa0b7999f902b39679d22d6257bcc0dc4e616d058715a" + }, + { + "kind": "file", + "path": "img_1642.jpg", + "sha256": "4f7a027a95c73e9bdb1483a5c3c045cc04ade3693a7660cf9acfcd6bcae3c835" + }, + { + "kind": "file", + "path": "img_4048.jpg", + "sha256": "d2348959682097f83e4e9fbdf04c6c096fe120d1b6197c35d6e8530ec096f44c" + }, + { + "kind": "file", + "path": "img_3727.jpg", + "sha256": "dcbe51cb641849040567ea699afd797f9bc09387921d0ebcb180590ec244e4ad" + }, + { + "kind": "file", + "path": "img_1871.jpg", + "sha256": "11c65bc1c50cb953ba9885e367291d2bb93391ab7151d92105e1446835d4d357" + }, + { + "kind": "file", + "path": "img_2613.jpg", + "sha256": "b530e6bcd7cfb82d0729123ea6f06c7c7b3bb0baaa9bd3d854cc4782eebaa3d6" + }, + { + "kind": "file", + "path": "img_1326.jpg", + "sha256": "b472b87b609145f4ce3ca40ac5457aadfc16cf23c5b20312bd415d3f388e24e2" + }, + { + "kind": "file", + "path": "img_463.jpg", + "sha256": "9a6d146c46b350becbfadd280d7677b8858b2c2bacef05ad0650375b16f7270f" + }, + { + "kind": "file", + "path": "img_3294.jpg", + "sha256": "ba2711dd3609e7721d6cbb529a4659ba737f4cdc3668852a3ba23b7cd2164843" + }, + { + "kind": "file", + "path": "img_2820.jpg", + "sha256": "d49cee787d7cfc2b44e228294219d5c037760e6a2ff306fddd8133a11e5d29ea" + }, + { + "kind": "file", + "path": "img_98.jpg", + "sha256": "6f12977674954326ea3e7498be264f7b277c079a72ad06359ae84dbf78fc4fd3" + }, + { + "kind": "file", + "path": "img_2853.jpg", + "sha256": "041ce149e3f72eed6da0922b9536b8e593f9bdc3bf40f3bab04cc6907b1ba0c2" + }, + { + "kind": "file", + "path": "img_2106.jpg", + "sha256": "f1b38900629792fb0abe2613d2182be9fad94ac4b9712a1fd605f33c08ca39fb" + }, + { + "kind": "file", + "path": "img_2112.jpg", + "sha256": "32cfec6c243af7e1700211050cd3c772a18f8583d32c5cc6341b574b4cda0094" + }, + { + "kind": "file", + "path": "img_4239.jpg", + "sha256": "050af89ba53dd2ab43cf258d3e82ac00dbb6284bcc9415302464cd11af5f103c" + }, + { + "kind": "file", + "path": "img_3967.jpg", + "sha256": "fd9b4d9907b041dd3d7fab52d11f4126508cbc1b041d033805a0fe357b742219" + }, + { + "kind": "file", + "path": "img_3973.jpg", + "sha256": "d2e95f04a170565bf8f977a284221713f3a3f023f8e6d80a6a5bb562592f1c1b" + }, + { + "kind": "file", + "path": "img_1194.jpg", + "sha256": "7de6e3e691e5fc2ca1c5e6af222110dc959dd807c967340d5b494619196dcb99" + }, + { + "kind": "file", + "path": "img_160.jpg", + "sha256": "0cd63b76544af443032288a44917b55819a307081a973a17b36c3506ccefc703" + }, + { + "kind": "file", + "path": "img_1619.jpg", + "sha256": "c1449fdf2282443e69432ee04adbfff78e51edccdc655413d26d8f54e65f6bb1" + }, + { + "kind": "file", + "path": "img_821.jpg", + "sha256": "06045feccde31055aaf7a015c62d6a80905d1b6917e5884ed707ea2a7491d7a6" + }, + { + "kind": "file", + "path": "img_809.jpg", + "sha256": "1335467970fe5b29672504ffa9fec086a53e4514e11e3a5627b9032d69ec1e84" + }, + { + "kind": "file", + "path": "img_3026.jpg", + "sha256": "4f5bc075c98b66b22e47d466c22b526992832e8cee24e2ea8d4a398ed4d81754" + }, + { + "kind": "file", + "path": "img_4749.jpg", + "sha256": "6479563e2dc6aaec3cdba585fdb7ca511df8c821e5c68838142448a9d5c958a4" + }, + { + "kind": "file", + "path": "img_4826.jpg", + "sha256": "8b5d863eb3fc9f7e3bff1a7f092e2fb24e87c64b5cc195f15376d0cbc87889f4" + }, + { + "kind": "file", + "path": "img_766.jpg", + "sha256": "6f87727d5a398537452bf657009e8d165f703864cb489ad857e722a63b925a6b" + }, + { + "kind": "file", + "path": "img_4198.jpg", + "sha256": "7e0704c167e933c512b2f3137014ab242747637adb3d0f56363ba3b87f88b411" + }, + { + "kind": "file", + "path": "img_2516.jpg", + "sha256": "3c8c4dcb29a0ee6600b1306e33a148b009841f621c577db7759705588d531560" + }, + { + "kind": "file", + "path": "img_4167.jpg", + "sha256": "287d8f3666180433c8457f3d5cd38c6916611403599e15886ff65ffe62597a70" + }, + { + "kind": "file", + "path": "img_4173.jpg", + "sha256": "9a0cac57e3b7d34bf752960567afdadd0323db961f7cda97e112377480713e25" + }, + { + "kind": "file", + "path": "img_1023.jpg", + "sha256": "0412b9f7460847850cc9b0b7f73ee7e3d7e08a379dc9f7fecf61248daf89fa63" + }, + { + "kind": "file", + "path": "img_2258.jpg", + "sha256": "7c62e1dc1f1484486d15d53c6b750a67dac868a1baed88f558e18cd3e38ac2f5" + }, + { + "kind": "file", + "path": "img_969.jpg", + "sha256": "b2ef234d5b99da3c21ddc853b7e90f2f7dd357d7448744b8463e9486a61b7788" + }, + { + "kind": "file", + "path": "img_1584.jpg", + "sha256": "6116904e37bfa9543665860475a52db13cf40b541e806aebfcfa72527b9ee830" + }, + { + "kind": "file", + "path": "img_570.jpg", + "sha256": "f6bcf0d3128e00ceb0ec3944045d5678d58d31b8de5f86f4035315403ecae74e" + }, + { + "kind": "file", + "path": "img_2099.jpg", + "sha256": "45d3370275630421cceae5800b12d99eb18967b7b08023d10abc1094ae3e1cf2" + }, + { + "kind": "file", + "path": "img_2072.jpg", + "sha256": "f6e76598a3b697e33a26cf2ff5afac3c531b673a91c2feb9d1b4f3a911d56d5c" + }, + { + "kind": "file", + "path": "img_2066.jpg", + "sha256": "2bfbd8e5de90b1a8bec3798920a04b93112914e29273c489c351f15ff682f0b6" + }, + { + "kind": "file", + "path": "img_4417.jpg", + "sha256": "28f777b4f688710269849027e05a784ae8000b889c5ea8501fc3244a3c5c008f" + }, + { + "kind": "file", + "path": "img_1234.jpg", + "sha256": "d0302c19097b32a4a7fca71405748af5c87a56bb235a17222feaefa8372fd996" + }, + { + "kind": "file", + "path": "img_3423.jpg", + "sha256": "2af7d808ca4a1f50f44b7875feb7176a83b674bcd3734df6c6b727d4deb6fe4f" + }, + { + "kind": "file", + "path": "img_4370.jpg", + "sha256": "9ca732ebf5c994035b705414d04ca0c2f22b35121262d9fd4f8adf6f93481482" + }, + { + "kind": "file", + "path": "img_1591.jpg", + "sha256": "826f5bf28070a6a08e443a1ba6eccd61b3231dc821d8d17c98952fe455120104" + }, + { + "kind": "file", + "path": "img_2098.jpg", + "sha256": "308592dd9dcfd34893513e610cdf22fd2b981accacce471a6803d8bfa22562a9" + }, + { + "kind": "file", + "path": "img_1988.jpg", + "sha256": "6e3c8fe5592b4ad652a8b7198b218372421c9eb9ecbbdc9aebe341b4570b41f9" + }, + { + "kind": "file", + "path": "img_3147.jpg", + "sha256": "6ad98ba5cc1e157ad10aca99685d7bfe97f70822bdd0203ac135a3d2a91081c3" + }, + { + "kind": "file", + "path": "img_954.jpg", + "sha256": "ae5e64478e14ebafc18ac2af12a10317e48d4f9b291523df58182e98ae17c621" + }, + { + "kind": "file", + "path": "img_1778.jpg", + "sha256": "02e800e77f3590289b5d1304678d917508da047b709964d3af63f83ed5c6b427" + }, + { + "kind": "file", + "path": "img_773.jpg", + "sha256": "276299517f4c7381e5ff16fb0f904f0dba4d879db253669a1d7ef0b18d87d03b" + }, + { + "kind": "file", + "path": "img_3184.jpg", + "sha256": "8b54dc4f7cb743e95d5d684fb9347c9ea577a060207b0987768d8661e9002dbf" + }, + { + "kind": "file", + "path": "img_767.jpg", + "sha256": "489fe8d949583c6d56ef2da64de74f5b5556ed058dc32de5409b470de1d84f27" + }, + { + "kind": "file", + "path": "img_3806.jpg", + "sha256": "5bbe4367d656911df5ac89da178393ffacb5c01606bc70ce193e7cc38aec83eb" + }, + { + "kind": "file", + "path": "img_1977.jpg", + "sha256": "f31f6bfc5474e05bcdff6f836e84d936db143c4c44179248985317ce7b4fde6e" + }, + { + "kind": "file", + "path": "img_2339.jpg", + "sha256": "ae581b4ac785fd4a77d980295ad90a395c51d51a43efa3854e766d16ad90ee1b" + }, + { + "kind": "file", + "path": "img_3999.jpg", + "sha256": "614cfa16d1d6314b814e9535ee001422a9ccf0897463b094dd7a4f664705242b" + }, + { + "kind": "file", + "path": "img_4760.jpg", + "sha256": "27172290d7b7c013be347f5d4b06c260c17c59b8dddfb76d60be28c4dd0911b3" + }, + { + "kind": "file", + "path": "img_2311.jpg", + "sha256": "0a1917b4009443235651ac7c9e41f99edccecf1f981b7b4d899888bec00d6992" + }, + { + "kind": "file", + "path": "img_1618.jpg", + "sha256": "d6bf034144a860689058dfbc024ec5a8fd977525733e738853c1adf329dc471e" + }, + { + "kind": "file", + "path": "img_4774.jpg", + "sha256": "8c9af16c1e8def46412f118d9fdb5a217d86be4f9af0bfe6622df4d6b5d27bed" + }, + { + "kind": "file", + "path": "img_834.jpg", + "sha256": "4ac4b5b13aa6301a5d8129f26d214d464311d55fef113938528c598a106dfbd5" + }, + { + "kind": "file", + "path": "img_1181.jpg", + "sha256": "4e9bb33f578d12dd091c2c85a999c66ad0978102e0344a9f5e5ecb0fe098feaa" + }, + { + "kind": "file", + "path": "img_613.jpg", + "sha256": "91e9400a095d3487c38fe11eb60404fe5b26390acf177999cd1faac1c5e4fe6b" + }, + { + "kind": "file", + "path": "img_149.jpg", + "sha256": "740ec3eca16cea632681dbd447d237193b6004f800f72e1678d153dd3e2d5625" + }, + { + "kind": "file", + "path": "img_1368.jpg", + "sha256": "18258341c17be9650251935fab3d270c63bac172ee1d5f2ecda27f3f445a5181" + }, + { + "kind": "file", + "path": "img_363.jpg", + "sha256": "363f58c4664c9efe5dd0d03910b9d28e4dd5064b1230540b3f34fc71d0bc5046" + }, + { + "kind": "file", + "path": "img_1397.jpg", + "sha256": "e7b03f41c99bb3af91c2cdf1fff94de722d6e9ba8aafcca6b772db0bc1a235b6" + }, + { + "kind": "file", + "path": "img_411.jpg", + "sha256": "058b6d207daea05862eba1851c2c78162bfca53510cfdbe34793a0d57f824b81" + }, + { + "kind": "file", + "path": "img_4589.jpg", + "sha256": "7f07f5b583a7cc3572900a6f7db53836707f35dc252463432dc5f3270b61831c" + }, + { + "kind": "file", + "path": "img_349.jpg", + "sha256": "8276cf164afcbcb4e0416cb94310475ffd2d1d9652e4ba161173508939454dbc" + }, + { + "kind": "file", + "path": "img_2878.jpg", + "sha256": "8e183ba53a6e059fc56f2477370217caf818de541ddd8757e6813ed7be8e59d6" + }, + { + "kind": "file", + "path": "img_361.jpg", + "sha256": "ef8e7e2b58d114a9aa3a0d58ee133251bae337273c05f75b4c2048d91169d5b3" + }, + { + "kind": "file", + "path": "img_2677.jpg", + "sha256": "90c5fd08d4633150a2a18921b4192b45c06a59a59bdd26d33edb8e5afc2beeb5" + }, + { + "kind": "file", + "path": "img_1418.jpg", + "sha256": "97593b060c4096f7db96cbda0a43608ab27f17a3d93bff47642a6e7af9710c10" + }, + { + "kind": "file", + "path": "img_3227.jpg", + "sha256": "461b6b56fca3d1087d7cfcad9d8a9c3485861cc6be3d67255253b8409d7a67cd" + }, + { + "kind": "file", + "path": "img_1815.jpg", + "sha256": "a03375399bd850ddb373b1f77a36cbe5ecbf310d3ca08c9d755a31fd77906b05" + }, + { + "kind": "file", + "path": "img_3780.jpg", + "sha256": "953ddb5ea0c51527fec71ca2ed786e5b8fc622d19d4d4ae64cfcf5314c283faa" + }, + { + "kind": "file", + "path": "img_611.jpg", + "sha256": "64bf9c3ef215bc955b61c3cc2de789f8517d15db12e5532d0e5ee54ce39807b5" + }, + { + "kind": "file", + "path": "img_4004.jpg", + "sha256": "eec19289eec6f39cc2a81e1ec549be6065b51b72dee7ea6adca8c296d0510417" + }, + { + "kind": "file", + "path": "img_2475.jpg", + "sha256": "2cc5d04bb10578490ccafce5f937430a8ca78d7444d5c7c38d211fbd96b09b28" + }, + { + "kind": "file", + "path": "img_1168.jpg", + "sha256": "96552032448edd8a03a1db4497baa91f6d910ce69f545d4e45de4a15f37a2bab" + }, + { + "kind": "file", + "path": "img_2461.jpg", + "sha256": "84a8cd27d3cbbc7ea90d9cf2c2466f221cfae2d955df2ce7530e9d20f6fa8765" + }, + { + "kind": "file", + "path": "img_3019.jpg", + "sha256": "39438f6a7501223977f1d40c91d1c0ea312e6a6a4d34790be26ef1cefc293f09" + }, + { + "kind": "file", + "path": "img_1626.jpg", + "sha256": "1c984580e964ccf83b7097cbda16ceadaf97a1cd6102be4bb936928b0663efe4" + }, + { + "kind": "file", + "path": "img_1975.jpg", + "sha256": "90eae66598d691285ef42030f1a8d4d60d0d7073b701ff53b808ac8ba7277462" + }, + { + "kind": "file", + "path": "img_3810.jpg", + "sha256": "af44f0824f1583e33443dc19d9dcf26f59a1172f4a225ce437b8cdb7aecbc8b4" + }, + { + "kind": "file", + "path": "img_1949.jpg", + "sha256": "e8c84528ffda90346159e76052e53bd030b6a9f479c56204a68eb7c8b936a8d1" + }, + { + "kind": "file", + "path": "img_4831.jpg", + "sha256": "876cb0fc40273b72b665a5d327c5e4e4982faeb3f0e32761fe750e820c834dc9" + }, + { + "kind": "file", + "path": "img_3838.jpg", + "sha256": "72e6d63a9a939e8893eb578a9d292b41ad7f8053bb3d0214143217e17434101c" + }, + { + "kind": "file", + "path": "img_2273.jpg", + "sha256": "fe64fd763b4b73ccd0e8ba989d41922775516c8db53ec1a5cb6212f3047c293e" + }, + { + "kind": "file", + "path": "img_942.jpg", + "sha256": "d46f841af9184ec6209f9baff73236d7f8deea302c9495383561e92fb8f6503a" + }, + { + "kind": "file", + "path": "img_3145.jpg", + "sha256": "1fd7032e310c8e3bf7e06a2fca6be3db8f594e5f991279a3d0e88ae507d77b46" + }, + { + "kind": "file", + "path": "img_1034.jpg", + "sha256": "5671b7694f8971a762b6691273773d2317d4da9328280f9ead8ea8e0313271d8" + }, + { + "kind": "file", + "path": "img_2529.jpg", + "sha256": "c72a1915233a68ed26b68d3c09016be715830b9d25ed91c64011356c1025ca6b" + }, + { + "kind": "file", + "path": "img_2924.jpg", + "sha256": "73b660191b88c87bcf22b8b11473924fa7f561262171b08ebb1f0455efe68979" + }, + { + "kind": "file", + "path": "img_4414.jpg", + "sha256": "20ce49711b02d1cf0cc20b08de84088a57dd0f1a800f1cb0689a96d8a3568411" + }, + { + "kind": "file", + "path": "img_2059.jpg", + "sha256": "44f3f5f039e0a5fb36886eeaaf79dd8a578ffed9df44479a27116c1a46f8a06e" + }, + { + "kind": "file", + "path": "img_3347.jpg", + "sha256": "b389c9b043d4ee876ae92f87185ece0accd3bb9e8e95fa13e5ae5849afccc07e" + }, + { + "kind": "file", + "path": "img_3353.jpg", + "sha256": "a6f1dcaa946932c1e7c1c414806466fe12e7eca26429c26e94ab63148d4c3028" + }, + { + "kind": "file", + "path": "img_1544.jpg", + "sha256": "f8e50febf107b5eb0e87c7044adb20581ba9bef8e5c26e0815498891480e4386" + }, + { + "kind": "file", + "path": "img_599.jpg", + "sha256": "23ad0540c093108f05a6387fc3d4f2d68a101844fa54004b803f3fc6dff4f4b5" + }, + { + "kind": "file", + "path": "img_4415.jpg", + "sha256": "25e3e71728b9a5c56468d6f0a52918eb41a885f76adfc9f82760f51df64436d1" + }, + { + "kind": "file", + "path": "img_2064.jpg", + "sha256": "e1ff0cd77e13d448286d458ff648d59c251c272b431f8381e0877d92946ed231" + }, + { + "kind": "file", + "path": "img_214.jpg", + "sha256": "a43d95279b6736e135d1b0b63a18c2e555f2062f1ca2a1ab648d36e0d270cf7f" + }, + { + "kind": "file", + "path": "img_3385.jpg", + "sha256": "f23a0197aac2543b4157d0cf1bb21ee31160d0fec34e32661d4745170b3583d8" + }, + { + "kind": "file", + "path": "img_1021.jpg", + "sha256": "bde60bbbe241356cae55ca742d982e2742c81256e82554b1bfed7739d618bdf2" + }, + { + "kind": "file", + "path": "img_2528.jpg", + "sha256": "a49ba2bc0acbf5b673678d514fd8c3f689b58dd184c9b17f5b2f15edd722a94a" + }, + { + "kind": "file", + "path": "img_3144.jpg", + "sha256": "e42f23c78e8276ee31d76ddd31a21e2adf1c44088f0e8037281457dcc3daba64" + }, + { + "kind": "file", + "path": "img_3622.jpg", + "sha256": "f808245c75bd4a74a368517dd363205998c680adba13a33fc568158f70e11063" + }, + { + "kind": "file", + "path": "img_1035.jpg", + "sha256": "3d3d935cb61b8f7699a6a2ac38f29cb4511b10b7943ca9b668e9e1cf6f11dca1" + }, + { + "kind": "file", + "path": "img_2514.jpg", + "sha256": "9d5432974edec7d170db6ae675f6bc262fb2e80708ec069d9b76314f26e99bbf" + }, + { + "kind": "file", + "path": "img_3178.jpg", + "sha256": "a1bf99ac8498642d119473dfa35f26ec0340f02a954820a651360d7aeff0e403" + }, + { + "kind": "file", + "path": "img_4617.jpg", + "sha256": "8cf8c17c1e7b7a0614d859bcf94d3adddf851a881b47e1be5b60108b5c706dc1" + }, + { + "kind": "file", + "path": "img_4171.jpg", + "sha256": "5b7b55ee9a7c3d19f0b78ddaaefcdda2dc1d543fc037c22613637cff87eff5b3" + }, + { + "kind": "file", + "path": "img_2500.jpg", + "sha256": "4e8b6de4f94d3c0a547bda7da0b731e02441f79278e14703c038a0b71f85120b" + }, + { + "kind": "file", + "path": "img_4824.jpg", + "sha256": "b848bb3515fb4c31912f93e83d5f4e94d143b3c464f2a21de1668faf4b1b5962" + }, + { + "kind": "file", + "path": "img_758.jpg", + "sha256": "0990b524205b429b14b70bddf38a1a46c1306beaeacd8adfe62f13faea5f9223" + }, + { + "kind": "file", + "path": "img_4818.jpg", + "sha256": "784312353c32b2e2f1b925c15d1bcb214a21e46b92bdb87a1a90dd8c05af4035" + }, + { + "kind": "file", + "path": "img_3756.jpg", + "sha256": "b2a0c1d486138db8b2178e94cad15d652defb30fd39f62de92a06c3df54b9eb3" + }, + { + "kind": "file", + "path": "img_1169.jpg", + "sha256": "2fa6a0299d5acfe84980713073f6f20164e415f68b25f3df9fca223099c31e35" + }, + { + "kind": "file", + "path": "img_837.jpg", + "sha256": "506cc011af97d7f8dc84708efdd3ef8d38c3f89ab425a88686f665f970ea75eb" + }, + { + "kind": "file", + "path": "img_1828.jpg", + "sha256": "63892d97ecb2a50797ec52e5d2d8bee7375375cdb37cffc7f8fab0eb11ad9af4" + }, + { + "kind": "file", + "path": "img_604.jpg", + "sha256": "2132a3d278b2c7e9714a7a261fe0e7416fb9c04ff1f02491761fe779cd7e56a6" + }, + { + "kind": "file", + "path": "img_1182.jpg", + "sha256": "a4b15af797051c3c46d0c98e40b794d5425e9503f804ec60b0b2f37b25cf0047" + }, + { + "kind": "file", + "path": "img_3795.jpg", + "sha256": "f209175e4c8e950df185f12033c061015489f1c098e03542af38802fa4b819fe" + }, + { + "kind": "file", + "path": "img_2138.jpg", + "sha256": "871520b560d0c43b2bc5dc158a3a29a34fb7e110b8b248794c70048a60d6e4c6" + }, + { + "kind": "file", + "path": "img_2886.jpg", + "sha256": "cb19176dbd7466e25a41e2ab32c07029edd0ca72ea98a603a7b39fc67a302796" + }, + { + "kind": "file", + "path": "img_1343.jpg", + "sha256": "3df685ca3cc9584e059a5e4f94d417f764e1d3f8e27d1dda029610bc1d1ab703" + }, + { + "kind": "file", + "path": "img_3554.jpg", + "sha256": "99248d0f2e5cf6acf5ca79e8ebb1d0ed346ba4c57829ccfd710795e8cdc70200" + }, + { + "kind": "file", + "path": "img_59.jpg", + "sha256": "bfe1198135477fd849a3a011b04e05b09a713fa3908caec24fff98fd05ad37ff" + }, + { + "kind": "file", + "path": "img_2104.jpg", + "sha256": "a79a82cc3b338c4788fb27cd5e61ea778b57e5446293c89e180a6cf2c1c9e4ac" + }, + { + "kind": "file", + "path": "img_2662.jpg", + "sha256": "668cdbc49a4781ff0ab1427773e653986a0349aeed39c46e4caaaf8c132f132d" + }, + { + "kind": "file", + "path": "img_3568.jpg", + "sha256": "d52c4aaf10c32133aad5c9d47571d48aeb262c82f09ed38fc945e4dc5d38be4d" + }, + { + "kind": "file", + "path": "img_1419.jpg", + "sha256": "47dd70c1b537139f174ccdc4e656085f10fe97b427c111e4c4b287a4745f6861" + }, + { + "kind": "file", + "path": "img_412.jpg", + "sha256": "fe67c95856edc646eb161c7a9d77596155165242beabc51a9f4e8a09abaa19a5" + }, + { + "kind": "file", + "path": "img_348.jpg", + "sha256": "59c86b2f675a5a0544bf283e281136b9cae4acb2005c3176b8e034d9af834e25" + }, + { + "kind": "file", + "path": "img_364.jpg", + "sha256": "0da88514eb0bcf38b19496f12710d0697c2faa38f750c7a2ae50c1dce033fd60" + }, + { + "kind": "file", + "path": "img_2841.jpg", + "sha256": "aeced89cbca477958e9b95f126625fd1b70ece67479bd514bd2851edeb07715c" + }, + { + "kind": "file", + "path": "img_1421.jpg", + "sha256": "dcb86163c759511110d08c93867a2ba5aaa5b9a6f46aca0bc1790020d420228f" + }, + { + "kind": "file", + "path": "img_3544.jpg", + "sha256": "816b2c220230a859361ceb6699fc69634dccb76419447cd057b28a49d061f76c" + }, + { + "kind": "file", + "path": "img_2672.jpg", + "sha256": "4687921ffbd80ac028061be66e77ea82a995820fcd336ebdffe8f21f3e0fca10" + }, + { + "kind": "file", + "path": "img_1838.jpg", + "sha256": "40cf3d4caaf6379bf329ad585c4499d64194bb43325e1f268bf55babd2913554" + }, + { + "kind": "file", + "path": "img_4940.jpg", + "sha256": "f01397993b13de3c8673ab3af80b05eab892f32edec8d19405332d7d0eea8029" + }, + { + "kind": "file", + "path": "img_3746.jpg", + "sha256": "345a01bd9e9803a8317272b311e06d4ee2cb9200697ae3112f4bbbf480043b58" + }, + { + "kind": "file", + "path": "img_1151.jpg", + "sha256": "32ce359d8e22798d23017f95867587970dc53969fb8b780d76afac892b156fe8" + }, + { + "kind": "file", + "path": "img_2470.jpg", + "sha256": "71a189160940a4ca3b0b386a413b6b290815fbe8377685c2715e9bb7146217eb" + }, + { + "kind": "file", + "path": "img_2316.jpg", + "sha256": "ab6b7656cffe93139292ba30a7425725375f8b6ddcb35e36ce466be243b1b75b" + }, + { + "kind": "file", + "path": "img_2464.jpg", + "sha256": "57511f25274976f157de8ef6c474efeea3abbe1e5d95393af8e07c0c72d37e47" + }, + { + "kind": "file", + "path": "img_774.jpg", + "sha256": "825f88c960db3b152c3f7949c12c2c9f3aad60bc2adb7ded6ef072b5329f6fa9" + }, + { + "kind": "file", + "path": "img_1958.jpg", + "sha256": "c484a067ee056e68a917c4c0144173d84e5a113d070e4ad7726f09f184af2a83" + }, + { + "kind": "file", + "path": "img_990.jpg", + "sha256": "1b4b7ecd5790659ea9fe9529d3589309427e8ab70a558d08960f3a52912b94ff" + }, + { + "kind": "file", + "path": "img_748.jpg", + "sha256": "2fe761248031730cf8e78ce0a1ba0b27992280f1c11c798ea580f26335dc6666" + }, + { + "kind": "file", + "path": "img_1031.jpg", + "sha256": "48b441b5eb357093c67a22121e6f0a85c9c888d757905663bdb113940c78ff30" + }, + { + "kind": "file", + "path": "img_3140.jpg", + "sha256": "0ed7f1f0c6c38ff3f473d303051e9bfd30aa39133b7691ae86e0c7e4fd18f667" + }, + { + "kind": "file", + "path": "img_1743.jpg", + "sha256": "4ba9e6618402e2da13a5db95cff8fe307a5cec0b77dcb5a6df028398ec7cf91b" + }, + { + "kind": "file", + "path": "img_2262.jpg", + "sha256": "917eaf0ed1f01a69a0cddc28b6cce7b451d428a999e45da1f81f645313a528fd" + }, + { + "kind": "file", + "path": "img_947.jpg", + "sha256": "7f7783234a9567cefe30c7a8edf1ee0e12e53b42e38d5a291ec889d0dfdc5d37" + }, + { + "kind": "file", + "path": "img_3381.jpg", + "sha256": "365bc5cd89c73ea510576d62bc3fd0c79d18854a1e410512d519478a954820fa" + }, + { + "kind": "file", + "path": "img_576.jpg", + "sha256": "fb6b3f289729272b8847b731725a98dd8bb439976bfbb144e80162d9aa3ca568" + }, + { + "kind": "file", + "path": "img_210.jpg", + "sha256": "d7ae71cf534c6693db8e9d026a2d7098772441014dac54a7bd4a99073602e402" + }, + { + "kind": "file", + "path": "img_4388.jpg", + "sha256": "a73372ffdc0134595d3450cb35860dcd78f9e648fef9a6e76237681ea5892796" + }, + { + "kind": "file", + "path": "img_2935.jpg", + "sha256": "9d66b08bced92670e91bf663fbdb1299d929cc90aaba67e5bf5919f6a7540ea4" + }, + { + "kind": "file", + "path": "img_1582.jpg", + "sha256": "6d956ee697d5c61bc9c441007f945271b19aa67f89846fc7a360a19bf542acc3" + }, + { + "kind": "file", + "path": "img_3395.jpg", + "sha256": "2ecf6eda9413b2a8435efae15575fbd538916f9a00759e511548dbff7099f641" + }, + { + "kind": "file", + "path": "img_1233.jpg", + "sha256": "58cc227861cd904730ad67e2a4fa5d3a6492f40dcccfca8dd8a512071879599c" + }, + { + "kind": "file", + "path": "img_589.jpg", + "sha256": "14e6ab09fe6aa1cdbe0d09f4227763395f35b8bf01836407fee7dd1d77cdf220" + }, + { + "kind": "file", + "path": "img_4362.jpg", + "sha256": "b03e79a38cda0346048a70b39df48283d8524e22bca61826899ca16454e10250" + }, + { + "kind": "file", + "path": "img_4410.jpg", + "sha256": "0e746535ff601ec5e4203b31d84efe4055b7f85e419395a4a2d284fe47866ad7" + }, + { + "kind": "file", + "path": "img_2061.jpg", + "sha256": "b002cdd93380cabeeb0ca7f6fc2b70c23e7238554f4bc47d69575a8403a54efa" + }, + { + "kind": "file", + "path": "img_3419.jpg", + "sha256": "7e02c7d911caaeebe0cc52b4b9da58d342eee42d837ab09d0ffdcb8dd51c8090" + }, + { + "kind": "file", + "path": "img_1226.jpg", + "sha256": "12c11f994dc665d1eb8a727849ce173ba10c145b179be86c3337eef7f0aefa1e" + }, + { + "kind": "file", + "path": "img_239.jpg", + "sha256": "8fcb611c46ac6bc76430e2bb518ae9f0760d291e7c42372e6f981b834249d4b2" + }, + { + "kind": "file", + "path": "img_1597.jpg", + "sha256": "b2e700a77ad7ee810a08fb94bc88089ce8c5107e669bb6e472b6a59a52c3eac9" + }, + { + "kind": "file", + "path": "img_2920.jpg", + "sha256": "5e2aa2f909d92f861ef96d5cca5d753aace006dda88946382e7b9f5a9fb2ef64" + }, + { + "kind": "file", + "path": "img_2277.jpg", + "sha256": "a8837d4aa0b3975867333310bd7d73d781359f2f99089d78574008849845e6cf" + }, + { + "kind": "file", + "path": "img_3169.jpg", + "sha256": "143978355e8df245f1c360f47f1f3a72a571acf7b828d023dee0453eaa89c402" + }, + { + "kind": "file", + "path": "img_4160.jpg", + "sha256": "9a5f2450e76330f7b3881920fcee35af5426c502b17bac8c063d2b5fc3fff7a0" + }, + { + "kind": "file", + "path": "img_2511.jpg", + "sha256": "8502a1964ac776e92c85f5c44ad96fec1599a10a5dc882cb75db40c93edaf2f9" + }, + { + "kind": "file", + "path": "img_952.jpg", + "sha256": "aa503018914c580430326b58f5880945888e59bee8da50ca96c02860cdb5fdc5" + }, + { + "kind": "file", + "path": "img_4148.jpg", + "sha256": "1bac6bc137ebc73fd16b9b2c61c808ed3b5db68d594d00c236d4672a01f10cb9" + }, + { + "kind": "file", + "path": "img_1756.jpg", + "sha256": "8c1b56ca3db3c409dbd3c88643a6d67f89e8a8c185b3a50777f14547f07b38b7" + }, + { + "kind": "file", + "path": "img_1959.jpg", + "sha256": "46323f67e0a4d90e76a7076247dd8048d99b3acd724745a007dede12e6239731" + }, + { + "kind": "file", + "path": "img_4821.jpg", + "sha256": "3d5def5f734a7c1183139d70ce5ed71496c99b34542fe198c24c635a16fedef7" + }, + { + "kind": "file", + "path": "img_3828.jpg", + "sha256": "7806c8bb334392833bc82b98cfff60c32d361243873930e1e0d393aff1c43c09" + }, + { + "kind": "file", + "path": "img_3182.jpg", + "sha256": "59ff8c9e7a272b2871ced839dcbf7d68e25ca3438d61b9addfa257abaf987b0e" + }, + { + "kind": "file", + "path": "img_2465.jpg", + "sha256": "e7e370e0d587108f1e746dc3346d7a1ea3776f47bb20c2791963038ccd1bde49" + }, + { + "kind": "file", + "path": "img_4000.jpg", + "sha256": "17abfcc285fa4f645f9cec3d962b06a184173a495c32eb8a0b34723b44d9d5cb" + }, + { + "kind": "file", + "path": "img_198.jpg", + "sha256": "2c12fde6bf3f94d1b0efd70586253707cd16775774a7c9d7fcde23e9fb010fe4" + }, + { + "kind": "file", + "path": "img_1150.jpg", + "sha256": "923f3c5c6071e448025ce667cd9bbfe8a502dfbb0e65ac09dc2bf47cf3a538d2" + }, + { + "kind": "file", + "path": "img_4028.jpg", + "sha256": "975c68032545efe2f877847c2d61fbef56b927c4a50f5be2abe314ac1fa448ac" + }, + { + "kind": "file", + "path": "img_167.jpg", + "sha256": "74d0536631251e81a7fd27497b8310d63452c0f93f8f93c38b4c582df0582969" + }, + { + "kind": "file", + "path": "img_4941.jpg", + "sha256": "a1af05b9c5a43d9204670793bf56492ad76d4b012833bd0b0f905b24abb4fccb" + }, + { + "kind": "file", + "path": "img_1839.jpg", + "sha256": "106a41f11ba0a3f2309e6e793d4211b7ced9dd9ba72da907f8e2b886c659282a" + }, + { + "kind": "file", + "path": "img_3579.jpg", + "sha256": "be181dc63d66fe38e2c2564328b295c8fa78611040bb146cd68afd8133b27cee" + }, + { + "kind": "file", + "path": "img_74.jpg", + "sha256": "7352abb3a1e5077136d4d64222045075a20b0128766232e116350306db2e516f" + }, + { + "kind": "file", + "path": "img_2115.jpg", + "sha256": "42eaeaa480ea8bb00c28cc79f0f0cb85c6df7625a9b4e9dc167a76eaffdaf1ad" + }, + { + "kind": "file", + "path": "img_3545.jpg", + "sha256": "1eb05a320ba64b13723bb59b8564eab3da87f27844212e264caa5197fb05fcae" + }, + { + "kind": "file", + "path": "img_1352.jpg", + "sha256": "42580e3fb1b8311273b9ecebfbbdafbdb716e31ee2cefb7777cdddf59a892e65" + }, + { + "kind": "file", + "path": "img_1434.jpg", + "sha256": "53944485445c2fa494e8ce7e5f7cf4f78f3ede74b37eb37e78890452df4c699b" + }, + { + "kind": "file", + "path": "img_3223.jpg", + "sha256": "18f7235a482782edbc57b34a653119234bb2433bab5bfbaa1567de0acd3d4675" + }, + { + "kind": "file", + "path": "img_415.jpg", + "sha256": "ecdbfec9d2ca8a903a8f742e8a4c16a033f58f942ae9fcf8e9ce9fcbd2fb2a71" + }, + { + "kind": "file", + "path": "img_2842.jpg", + "sha256": "6b5900ab1c55846db2eef57b6b986d72a5a70413b26ea0abf5f55c0978fdb9b0" + }, + { + "kind": "file", + "path": "img_1387.jpg", + "sha256": "7b136e04f620714e42045ca7719479dd4b6fc0c8766eb17c6864f7c706fc5e50" + }, + { + "kind": "file", + "path": "img_2895.jpg", + "sha256": "a0d855ff100369da3c745ea4c2e470c8fecb47b3ecb8033e4fa14acbbb5bb553" + }, + { + "kind": "file", + "path": "img_3553.jpg", + "sha256": "99c1b8902cda23911a7bf9b6909ffcb926b84534582b11624fa858a488e24e84" + }, + { + "kind": "file", + "path": "img_1344.jpg", + "sha256": "e20d82191cdcb82150921091412f757cce2b9e83175f82393edbf96e1cc969e4" + }, + { + "kind": "file", + "path": "img_1378.jpg", + "sha256": "55c248bd5efe73a1847dfcb71b5d3c9cc85bcd4a5e2483deba1c8b40aebc4235" + }, + { + "kind": "file", + "path": "img_4566.jpg", + "sha256": "9633515e23c8f6736dd06eff0a385105d619584b93e3bfb95410db0952e04377" + }, + { + "kind": "file", + "path": "img_62.jpg", + "sha256": "79afca05c6290fd374ebb3e125968e0beaa6704b8ac8d52f44d88698a98f9f91" + }, + { + "kind": "file", + "path": "img_171.jpg", + "sha256": "ee7239c922924aae56983b3cfb9859dfd239871a3c48a1b8fc9cae7554dda663" + }, + { + "kind": "file", + "path": "img_603.jpg", + "sha256": "efb047c0ffdafc60db9d5bf4825022ab705ae52ce108d03bc9f0dd698bfbaaf5" + }, + { + "kind": "file", + "path": "img_1620.jpg", + "sha256": "c116f5bc8ca489ca74e022c913ea51fc64f86538e5a12ae82c55373c160a2296" + }, + { + "kind": "file", + "path": "img_4016.jpg", + "sha256": "34aeed8543f3250e47e9ba29df24bd8e860f9c2f7ebd3fb8df68ea36442584bc" + }, + { + "kind": "file", + "path": "img_1026.jpg", + "sha256": "689925a8784972781b7fe5dc56957a143854fea22e58ae42441a39a1572efc7a" + }, + { + "kind": "file", + "path": "img_1998.jpg", + "sha256": "cc8f206d43a37ec8c056f9580afabbf55a45dd87de59d476969fc9bfe95a9dd1" + }, + { + "kind": "file", + "path": "img_4162.jpg", + "sha256": "82af86c422855010d62eddd26f01b94989adafdd2911b484c1f869a99cadcc35" + }, + { + "kind": "file", + "path": "img_2261.jpg", + "sha256": "11f82d14304ec181121c9050b9b5f1a19c775648476b8c6a1414e29de50624f8" + }, + { + "kind": "file", + "path": "img_4176.jpg", + "sha256": "072874a3aa7b0b6c97c463c4a89149f945e55203a0e1b01a6ad2d7d233c572cb" + }, + { + "kind": "file", + "path": "img_2088.jpg", + "sha256": "81f23604e436b19037e9ed10cc8f1a5f5842f268bcd52e783c7aa071451574d6" + }, + { + "kind": "file", + "path": "img_1230.jpg", + "sha256": "b7f50f1284b3ea703eb9ee8c2bf0d78b2cba8df912669be9b0bfab23c3a520f1" + }, + { + "kind": "file", + "path": "img_1218.jpg", + "sha256": "3b404bf629398a5d4657c28c8df4aa05cebdc6720e23154ab1a76ed0b0468e2b" + }, + { + "kind": "file", + "path": "img_4374.jpg", + "sha256": "9d5680bfc6306ef20d6efc4f513b6ce1b7d0807b00eddcaa305ecaed983f3514" + }, + { + "kind": "file", + "path": "img_2705.jpg", + "sha256": "d467cb189207824da5302ad6322c19e86f7c3ad822a0c2d3424ed4b68a091453" + }, + { + "kind": "file", + "path": "img_2076.jpg", + "sha256": "728fe895526bbbe9c4dfe40a572d108a34e0d4ae0db02bb8d3e3c80b2c8b5c13" + }, + { + "kind": "file", + "path": "img_1219.jpg", + "sha256": "2639a16f9270b44043a34971575a7ea4ac0f2358d13152529de98ca405d33638" + }, + { + "kind": "file", + "path": "img_1557.jpg", + "sha256": "9259b2725e77ac2809fc022a95a6d1d883e4e3d741e522ac943a0fda0bd95b1c" + }, + { + "kind": "file", + "path": "img_1543.jpg", + "sha256": "792853f82d75834b3644bd30c783f253d32a36b63f694c77510561e4d4190975" + }, + { + "kind": "file", + "path": "img_212.jpg", + "sha256": "7ab522397ff763845ed7ad01f5139461965dfdfd0c8f5c06386f8a1359429358" + }, + { + "kind": "file", + "path": "img_1580.jpg", + "sha256": "136591b40c2539e7726ed1b0634f1335df6eb39aaf8dc2a7a0c7f357a43ccdca" + }, + { + "kind": "file", + "path": "img_2937.jpg", + "sha256": "1b72bf8065e4b50b227090f23649aaf1bae00887301390c131571469c73694a9" + }, + { + "kind": "file", + "path": "img_4611.jpg", + "sha256": "edd9c6b704a6b7dc0c68164b0c174b51a261648f086dfa0a21be11db1e9abc70" + }, + { + "kind": "file", + "path": "img_3618.jpg", + "sha256": "8ba1c85703af90fecb4e99988f25dc0342af623d65ff65b139b4891bcdde084f" + }, + { + "kind": "file", + "path": "img_4177.jpg", + "sha256": "84f36022ad131f47838a45032f20b89d23f222f2811202b264da7c71611983e7" + }, + { + "kind": "file", + "path": "img_2506.jpg", + "sha256": "3f7a7d126bbe6acae8773bb09e859881b5aea7530d995045478680ad53af1e02" + }, + { + "kind": "file", + "path": "img_4163.jpg", + "sha256": "473922267b04345ec5f416b21ec296107af38cf6d08e709804cf5af6ad1d01c8" + }, + { + "kind": "file", + "path": "img_4605.jpg", + "sha256": "3f49e31f638a38f68da4679c77a0ea7fffb56082a12537301bbee4d57d9ade4a" + }, + { + "kind": "file", + "path": "img_1755.jpg", + "sha256": "8760ad024b88c0bd3106b07545a076e5081dd1248866f0b6858b60580aafc807" + }, + { + "kind": "file", + "path": "img_1033.jpg", + "sha256": "b7a18323f9adaf1eb41d21e24177046de6c7aeb8caa447dbfde63899e8fc2c17" + }, + { + "kind": "file", + "path": "img_979.jpg", + "sha256": "01e239cfa5af55a8b322c2f83f023c043f724a1bf1c037e8f3330fe574d50e48" + }, + { + "kind": "file", + "path": "img_1999.jpg", + "sha256": "6f105ed6c90a3013b72c0402d12cf4c702b165e002cd3b3ad96c0fd097598c1d" + }, + { + "kind": "file", + "path": "img_1741.jpg", + "sha256": "46416030f7a40ab8f646c6064cac5f67fe4a5867ab0e89406c06c0612eb594ed" + }, + { + "kind": "file", + "path": "img_3817.jpg", + "sha256": "9ad1090c717b3dbe8a42fff373038d898caa95c344db0032858cbef93965344e" + }, + { + "kind": "file", + "path": "img_776.jpg", + "sha256": "b40b3363ba965579675d9f22fcdf00624470dd73cb521231a0929c38f1667161" + }, + { + "kind": "file", + "path": "img_3181.jpg", + "sha256": "6421cc55c5aa39b7cd61dd0c65d2890769377a9cc744c702ce591d56eaa9ac42" + }, + { + "kind": "file", + "path": "img_1796.jpg", + "sha256": "17c59af5480ccb3f1c8bf54b5a44b173dfaad400537e4de485ef4630f8e0f6df" + }, + { + "kind": "file", + "path": "img_1782.jpg", + "sha256": "8f3eb318ced243c2976b783dae144a69c1343111d7852f8f8a4c83458c5137e9" + }, + { + "kind": "file", + "path": "img_4003.jpg", + "sha256": "ccee9048034973b051c910bb3ff5e214277e1b43615cafb9c6cedc40f0ba1dc4" + }, + { + "kind": "file", + "path": "img_4771.jpg", + "sha256": "6846fc23767aaa0d7bf9519602762dd8ae972ea1e4fc6c3fb6177346b2a18ca3" + }, + { + "kind": "file", + "path": "img_831.jpg", + "sha256": "3c25b8b4b2f25be3b0da376203d19ea7d56cabb030fecc4b96f51d4d0ac147b2" + }, + { + "kind": "file", + "path": "img_1621.jpg", + "sha256": "f6b4763f6e2001c4673ad0aa5303f36eb759309f5fa4c105ae0dc3bfadfb0c0b" + }, + { + "kind": "file", + "path": "img_3022.jpg", + "sha256": "cf5c1bd5dd093d9fb23d1bdd93de6828e8625262795711da51602d604ee67dfe" + }, + { + "kind": "file", + "path": "img_3977.jpg", + "sha256": "d16e30828ac8a32e92742d7363c3244d47cdc6f9c248f22bb2e8d148fff15e56" + }, + { + "kind": "file", + "path": "img_399.jpg", + "sha256": "b7310873dd72498e43e39844c9d9341be5150d03b7e9b2f3daf777c760ee030b" + }, + { + "kind": "file", + "path": "img_63.jpg", + "sha256": "9f06bc6632b86d9d027b89a77f69b89883b453c9f007c8ca1d50fc35dc6d2e60" + }, + { + "kind": "file", + "path": "img_77.jpg", + "sha256": "5f40eccaf6f8d3fed49223fb546efd79b430cef6985f6e9bd949295c52b04aca" + }, + { + "kind": "file", + "path": "img_2857.jpg", + "sha256": "b49207933b1f66d1802d0848f3acf1d2ae362d920d8f330bf32faf9f636e12a7" + }, + { + "kind": "file", + "path": "img_4595.jpg", + "sha256": "2d4171f55cd2ed416eeb678d78c1cc52340ec0a1d70d32abb3877c99da38076f" + }, + { + "kind": "file", + "path": "img_2696.jpg", + "sha256": "15be178e45f12e36dde213546d159eac5e2d8d4fa9028f893293b5d06c08ee72" + }, + { + "kind": "file", + "path": "img_357.jpg", + "sha256": "c5b86e319e0313e24b2b42824437b229737509178e860b1c7ef23c96306f0c90" + }, + { + "kind": "file", + "path": "img_2866.jpg", + "sha256": "527eed4b9c8d782657090ee7edad49555ab2cfc08400e53bc24396472b031d78" + }, + { + "kind": "file", + "path": "img_431.jpg", + "sha256": "2e417d64dca2b02c4792b9a6038d235d07944d0dade189e727352e0b8738bc82" + }, + { + "kind": "file", + "path": "img_2872.jpg", + "sha256": "002d3c977e36cb271878e9e3fe576d12f594f224940143f1eea012db028da591" + }, + { + "kind": "file", + "path": "img_4230.jpg", + "sha256": "3a1faff6bd2420bd5db32559bbb31beadf574ab868229852835e076ac8611fac" + }, + { + "kind": "file", + "path": "img_3239.jpg", + "sha256": "75fe6472fe3e574df449d2057268577e55b060ae91fb95396d4487f983b46ce0" + }, + { + "kind": "file", + "path": "img_52.jpg", + "sha256": "a5b66f0fb9e159cbed7e9459d545c855ef8acd7b60015ebadf463fb7d7211603" + }, + { + "kind": "file", + "path": "img_2133.jpg", + "sha256": "2e0fdaa95fff269b9bf1b5299996fba1682310f80e675eab11cb78f9381d27c2" + }, + { + "kind": "file", + "path": "img_1412.jpg", + "sha256": "4e7664493fad39c2906b7668a7b131b26e573afef56ba2dfe522c6d056773892" + }, + { + "kind": "file", + "path": "img_4797.jpg", + "sha256": "9ca6880e2dcc6b8aa66f52cfcb158bfd563ac47c6c83622d154658f1fd7ef404" + }, + { + "kind": "file", + "path": "img_1189.jpg", + "sha256": "20953fe682c04757b7f2d483447287fc45f25d2b74f8d71fb20b1d6ad7bb7639" + }, + { + "kind": "file", + "path": "img_1823.jpg", + "sha256": "299e4025fcd89d67380dce4e3044a23d4848db8afba8ebcc90f4b8382474bf52" + }, + { + "kind": "file", + "path": "img_627.jpg", + "sha256": "3f6723434d88cfe8efa404f6b5f798e552426218868f20df0fe7847b4e33de71" + }, + { + "kind": "file", + "path": "img_2325.jpg", + "sha256": "a4d59880791dfce58a58c1a079ed199de373e67f2b57fa53f196ce3b9978336e" + }, + { + "kind": "file", + "path": "img_4754.jpg", + "sha256": "b5d523c09c7fe2c156405e347dad29ee2619f0c37cb3f78ffb24305110d447aa" + }, + { + "kind": "file", + "path": "img_4032.jpg", + "sha256": "44c77c679ecac6b3a113d474ef3546864cea6edd953ada9c91454372e71f21e0" + }, + { + "kind": "file", + "path": "img_3991.jpg", + "sha256": "b0c2f03bc675951f520558b6469822b86dd2d88e2842db750d1078891d787fb4" + }, + { + "kind": "file", + "path": "img_4768.jpg", + "sha256": "df00ec7690b21850ca8b45a9c8982e29d04f771c6bcf26d1ce6dddb1528eb7b3" + }, + { + "kind": "file", + "path": "img_1176.jpg", + "sha256": "c603313bb383f918a747ae6e2083187035da8e0a354f05a10b373f21375afbe8" + }, + { + "kind": "file", + "path": "img_196.jpg", + "sha256": "789c5a2b6ca29f9b68c203b7145f667146672d3051149e24e61f257ead4950c7" + }, + { + "kind": "file", + "path": "img_1604.jpg", + "sha256": "3c0898ccd307af22d92865176e9defa881367e1bfa41c07fdec006e7447279e3" + }, + { + "kind": "file", + "path": "img_3013.jpg", + "sha256": "d047645a5314ade12cd901d7406e961603798f8af7b35c9427777befd8556248" + }, + { + "kind": "file", + "path": "img_1943.jpg", + "sha256": "e576c39203c3a59f077c36a30ba42efd52d4c4c23abf9564042f97536e444230" + }, + { + "kind": "file", + "path": "img_4191.jpg", + "sha256": "8c2c85d8b0d06c086cea10fe9f700630922ed709e6b4bf9e9451fe6a74113271" + }, + { + "kind": "file", + "path": "img_2251.jpg", + "sha256": "0e9dd83da757b8e0a4169ec41b457c8443c3306832f414f12b174d0d0c75bb4a" + }, + { + "kind": "file", + "path": "img_2523.jpg", + "sha256": "d08bd6d09e7b17cb29e05ae80d0667b06406205c0340dbd4e08aa806750c89b0" + }, + { + "kind": "file", + "path": "img_4152.jpg", + "sha256": "81dff826da1114154079e2171a6b13f13be2f2c21def4135fc397c4b014e002a" + }, + { + "kind": "file", + "path": "img_4634.jpg", + "sha256": "d5855b17e0fd82be9ed5396c70036c7245dd897e77e8fd4d2288c0a021ae66fa" + }, + { + "kind": "file", + "path": "img_2245.jpg", + "sha256": "5f67ed68d428bab50e8e890001f5f03b4896a2d451659f7fbd5be7c28f13aa9d" + }, + { + "kind": "file", + "path": "img_1994.jpg", + "sha256": "4f2def17c0adc77298634fbc0d779c4c3ae1f4e54f40e2bc3535823b0cfdb9db" + }, + { + "kind": "file", + "path": "img_3615.jpg", + "sha256": "a67f0d98be5ac904a117815557ab26f89aae4a4647d0a9e8ebf199ef1cadb4d4" + }, + { + "kind": "file", + "path": "img_4393.jpg", + "sha256": "898a5aead48943f85ffa1c64d3a664d659682cdf31f698153cc154c4ae23c045" + }, + { + "kind": "file", + "path": "img_2735.jpg", + "sha256": "320ac39f96d08b1aaf6a063e0ff73346fd5a1c1bccf7df14f30e0fd96d532cdc" + }, + { + "kind": "file", + "path": "img_3359.jpg", + "sha256": "0b98d8f604ff5a945f70283a518e25e8481e9f922a9c2e84d00bd628009daee4" + }, + { + "kind": "file", + "path": "img_4436.jpg", + "sha256": "681087b44af2c18ef17eb2977637d55f8ca300a4a3d35a15f16864327e40f582" + }, + { + "kind": "file", + "path": "img_4378.jpg", + "sha256": "e6750f5fd6b62d882f2fd38ae88c21c6fc9f03ec7323ff5fbde1e97552755950" + }, + { + "kind": "file", + "path": "img_1200.jpg", + "sha256": "a9dde123d1f3fac6830a3de7a0eda57ef39ce6dbf69f406d9fdc43566f730635" + }, + { + "kind": "file", + "path": "img_586.jpg", + "sha256": "8d5a7751574ad362650a2c9d02a7941f198259f09584e1b80ca457d9cf63e4b9" + }, + { + "kind": "file", + "path": "img_592.jpg", + "sha256": "2286974e579bf9a5446f447be491d48846ab3b85ea0fcff5c7b58355c67ddf52" + }, + { + "kind": "file", + "path": "img_3364.jpg", + "sha256": "24244c68e1d105be80044c34b38b9d9b9cb75937b486151f987e93ce3664c411" + }, + { + "kind": "file", + "path": "img_1201.jpg", + "sha256": "2581ec8ca870a2802c7d2492c01816bb1027978d5379787db24ee10e1e68deb9" + }, + { + "kind": "file", + "path": "img_4437.jpg", + "sha256": "e41d4079003c747532b189c3277aeff28c7648ece34a162085e2f4514b01f4fc" + }, + { + "kind": "file", + "path": "img_2046.jpg", + "sha256": "a3496b3319bb47df5dde9b949f9312df94d6e8dfa0b78a1dc9ffeaed06d7ed30" + }, + { + "kind": "file", + "path": "img_550.jpg", + "sha256": "087a721cba4744c3ff26d1f359d860c1c9f36476e83b17ab56839701b21a9873" + }, + { + "kind": "file", + "path": "img_4392.jpg", + "sha256": "1aa62fde5dea243077d96b6cbaaaf951445a591018aefdada44e93d960406820" + }, + { + "kind": "file", + "path": "img_4386.jpg", + "sha256": "7f35cae7308ee5f29dbfeebe9a30d9e5f172b4d48952f1d25b7290d8c5e64435" + }, + { + "kind": "file", + "path": "img_4609.jpg", + "sha256": "8ad6da5cce6188ae0e9df5fdbdeaf6ee3ca492686f3e0f6a4a1e15219e6fbec4" + }, + { + "kind": "file", + "path": "img_1771.jpg", + "sha256": "4c3b5cf91a6b4b84ec0b93242a61f90d4aa3bccf84b51d4af720faf5344b85d3" + }, + { + "kind": "file", + "path": "img_4153.jpg", + "sha256": "b4e472b2d847972d332f99e4f4d9a7a3609f59114bbb235a0463f7e0a8760378" + }, + { + "kind": "file", + "path": "img_752.jpg", + "sha256": "cdece0ad4802f9f7907e605f07dcec1461e5334e8ce1474ad342ff0b73e753b3" + }, + { + "kind": "file", + "path": "img_3012.jpg", + "sha256": "84aebfbee169f9a966f83b865e916cffc8c2ac9aee1cbf2104576eb6792a51cc" + }, + { + "kind": "file", + "path": "img_1611.jpg", + "sha256": "025218ea5228e33649e1a6ead7dffe1c8d409a5a840c4ab13f96c99dc3ae3ec6" + }, + { + "kind": "file", + "path": "img_197.jpg", + "sha256": "e98b8a0eff77d1f2ae6851ffc26c0ea9436d12b810f2aa28fd3b72f41f5c60e1" + }, + { + "kind": "file", + "path": "img_1177.jpg", + "sha256": "6cded5090b0e8167d6712c1f711700755598ba7fe7582cf492d7833df06dd881" + }, + { + "kind": "file", + "path": "img_1639.jpg", + "sha256": "94db7d70c0374b791735e42a0b9dfd530302c1f5a7d32075aca1219e08a2f35c" + }, + { + "kind": "file", + "path": "img_801.jpg", + "sha256": "9a167ef0de384d12cd6baa399d9ff90fc651978fb37235c47c6044da70947aa0" + }, + { + "kind": "file", + "path": "img_4755.jpg", + "sha256": "17e927cba5feb14a571ff8707c8c0dc3bcf5fcbeb15c8e5513c3ad42ddb97aa0" + }, + { + "kind": "file", + "path": "img_815.jpg", + "sha256": "f3539d62ad9b37a0c7924844a9d26254642b06e7fc84e8568ae5e2dd2b63465c" + }, + { + "kind": "file", + "path": "img_140.jpg", + "sha256": "001d4ab5e8ea86d5608bbf01b3a2a680f8ddfec5967be63b35613eb1edddfec4" + }, + { + "kind": "file", + "path": "img_626.jpg", + "sha256": "31e09da1e7bc4a88ca6c2c35c215cc91bb4aa2671e892d325e1a342fdd1118eb" + }, + { + "kind": "file", + "path": "img_1836.jpg", + "sha256": "dff4c68533e65da27b781b61b14de4a38410e7dc52adc259f9e1568f9ee9fca3" + }, + { + "kind": "file", + "path": "img_3947.jpg", + "sha256": "f35908581f9a63478db1f3e1c6e989ed4fd28f3c47d156e1d3c29495104d903c" + }, + { + "kind": "file", + "path": "img_1407.jpg", + "sha256": "df8c7d858ab16828ad720ee30de32421e7247f6b9747b55cb49171fce675fbe0" + }, + { + "kind": "file", + "path": "img_3576.jpg", + "sha256": "c9e1ffb62f1c1fbe5cecec69b9823c06f54f7e099cbb3e2217aaee6c2590cbc2" + }, + { + "kind": "file", + "path": "img_1375.jpg", + "sha256": "d63294f202f8e8959775ecf5afc410fdc25dc86aa61097e0ca940175d94f5cfd" + }, + { + "kind": "file", + "path": "img_3562.jpg", + "sha256": "53fd9ec3da53e9c1321541a97acee912d14565e3926c2299d25e2a2f08391f4a" + }, + { + "kind": "file", + "path": "img_2640.jpg", + "sha256": "6604ee7d253529563c2fd276ff8d268f727a8f6b7ad28c97d6c1f6fb060f2920" + }, + { + "kind": "file", + "path": "img_1349.jpg", + "sha256": "7b5f433ace91b826c4de4d208409770fa2ff218b6f8cda2123f193607dc495ac" + }, + { + "kind": "file", + "path": "img_2126.jpg", + "sha256": "d3073888c548571e62c20893bb9a1b70faed999d031593a2f5588cdde4d838f0" + }, + { + "kind": "file", + "path": "img_424.jpg", + "sha256": "54919e7573b1c07b485df9379fbdf63b59b1e580dbbf938895a7a54de6406fe2" + }, + { + "kind": "file", + "path": "img_2873.jpg", + "sha256": "d4754f34c5d50b165a0296ada7a5b11d657ad8989414330ff991d6eaab6a981a" + }, + { + "kind": "file", + "path": "img_4580.jpg", + "sha256": "3216e6dd0437cec240b55f0dfb467b2670b19a61b0d65a54ba3a847928ebd824" + }, + { + "kind": "file", + "path": "img_4594.jpg", + "sha256": "49ccba220c7a219488270fb2da77d2e9c9cfd0265361bfbf5d71dda90bca6385" + }, + { + "kind": "file", + "path": "img_354.jpg", + "sha256": "f8dd504c7aed4c708803e9a03dca3b7debc3bc147ccee5567813a6571ea891ba" + }, + { + "kind": "file", + "path": "img_2865.jpg", + "sha256": "fda4c4172c3982d23c12d2354bebe1c437447d9b35e7e793d772b0c04f8e446e" + }, + { + "kind": "file", + "path": "img_2656.jpg", + "sha256": "7edc4a6963b3e5c09e486960d368f6c4789cced4920128bbd0c42b08c5941da2" + }, + { + "kind": "file", + "path": "img_1439.jpg", + "sha256": "8ad2fa4e4f32693d5ec50d42bf89c56222fed27fad0ef346883778744d458b03" + }, + { + "kind": "file", + "path": "img_2130.jpg", + "sha256": "6e5629c378fae6e8e1cfc1c5cfc0f0a4d1d15187f5c8d42c183165c401b88b73" + }, + { + "kind": "file", + "path": "img_45.jpg", + "sha256": "3a2165275115fb39905827b8f33911ed26fd44173b937982bf6b35e06a245310" + }, + { + "kind": "file", + "path": "img_4555.jpg", + "sha256": "a8a4fc5834c0cfef4f84e3f0f10d82b5dc6ff94413a5987d3c88c406752c28de" + }, + { + "kind": "file", + "path": "img_397.jpg", + "sha256": "23c01e3dc9b801cc405b3f526b2271a792cea98622a85b4ceb99e40282a52cbe" + }, + { + "kind": "file", + "path": "img_2483.jpg", + "sha256": "783d1474f9e8b3e9b18b0c199064babb78373bcd17413c5a860f3b18ff6ddf97" + }, + { + "kind": "file", + "path": "img_156.jpg", + "sha256": "4c68ba615204e2494a6099f4168428aa127c18b4bdc18822c014af5db0395209" + }, + { + "kind": "file", + "path": "img_4743.jpg", + "sha256": "4fd661b0e57ab91f904908f87c40d9baf52b9d34bee84b4509239e544806d0ea" + }, + { + "kind": "file", + "path": "img_2326.jpg", + "sha256": "c1bf8899bbea476c918b15b0a42b78add9a7eb2b434510f0979f3a8ae4aef707" + }, + { + "kind": "file", + "path": "img_2468.jpg", + "sha256": "1eea9bb2b49540d1816284fafab6d4ae6a3af7d9320244224e76eee584e87b07" + }, + { + "kind": "file", + "path": "img_3825.jpg", + "sha256": "f9568d4ea7e12e4d4ef0a65d9005563431f3f3f233cb6dc9d222106f73f01808" + }, + { + "kind": "file", + "path": "img_2291.jpg", + "sha256": "ffae49c1316784a7093b71b568703387d18c353ed7265b915b4755a70a605e63" + }, + { + "kind": "file", + "path": "img_1940.jpg", + "sha256": "c01047422964f9f0add5ef2fd3d6a159271ebae8a140c1b1ba4fa875f72dbf75" + }, + { + "kind": "file", + "path": "img_2246.jpg", + "sha256": "0c6b191cd62e51f528c2d36c99142f4e0698eb4facd5cf32f94c77a5161eb2a6" + }, + { + "kind": "file", + "path": "img_977.jpg", + "sha256": "5735e4f3273329a9c1f9665820ffcdca0c95f4b33f51c937d868aa509940d84c" + }, + { + "kind": "file", + "path": "img_1029.jpg", + "sha256": "85afe3010d6da882278a27c57c27252ddde5ec6a8bf58dea31379d4ba7a560aa" + }, + { + "kind": "file", + "path": "img_4151.jpg", + "sha256": "ef60f8bbca37c485bc458f5fb0d0d166687737607bb6123a3b715fe5ab038359" + }, + { + "kind": "file", + "path": "img_2534.jpg", + "sha256": "5dcede3378e080e2825bfe634afca0455b47dd1e265a8a62d973a6ed6f91967c" + }, + { + "kind": "file", + "path": "img_4623.jpg", + "sha256": "fd127840251b58a3b81366e642c1cdf75424e26fdbf386936a4745f55219e72a" + }, + { + "kind": "file", + "path": "img_1015.jpg", + "sha256": "3e70b197d441b9d5d404a802d04d8da006b09988620ee50fe0d197cb44de266b" + }, + { + "kind": "file", + "path": "img_1767.jpg", + "sha256": "864725780685e4d95a74a9c84874578490b915f4a1db161016e0aa2f1947db23" + }, + { + "kind": "file", + "path": "img_4390.jpg", + "sha256": "12477c9518ce8656891bdae84bd7a27517b920383d243187212fc353deb78a29" + }, + { + "kind": "file", + "path": "img_2093.jpg", + "sha256": "0801fa21ffe8ecd183e0e0f49a7ce35cfc41472fe857cfa1f0a11596939f325c" + }, + { + "kind": "file", + "path": "img_2905.jpg", + "sha256": "7df7292ddd63287ca8e2cfeafa8af8080c6a07e4cb9948847e343efcba953763" + }, + { + "kind": "file", + "path": "img_220.jpg", + "sha256": "ef530ab73ad9d81aea9b397614ebfdd466c11301504a86fa869100fc3dc9de8a" + }, + { + "kind": "file", + "path": "img_4353.jpg", + "sha256": "35f75739d3897b2685f62e62c76fe9bb6fad163eb50952edeefecd59b90097a1" + }, + { + "kind": "file", + "path": "img_4421.jpg", + "sha256": "4cc2b1d2cfbebaf18a535f22cbd5f87038f3ddf97ca0ef46c374cfba702e0d45" + }, + { + "kind": "file", + "path": "img_2736.jpg", + "sha256": "1dbc3c67feed687cf318cba9a51f9ff8ac13add80e4c8052a7ddf8add2404323" + }, + { + "kind": "file", + "path": "img_1564.jpg", + "sha256": "085ce354b708c0038a2ab6ce929053753b6572ec2796f17d1780778e8763f3ca" + }, + { + "kind": "file", + "path": "img_1202.jpg", + "sha256": "41b7a43bb1d456b94160334cd0f1ab0b8042bcc72814dadc5517d2072657f338" + }, + { + "kind": "file", + "path": "img_2737.jpg", + "sha256": "68e6df2f34d6807e3c32b624e11a326d922488c3fdd63ec5615235c602bd6e81" + }, + { + "kind": "file", + "path": "img_4346.jpg", + "sha256": "4f117e20eb5ca4a1b9f2083744dea2c085c1bce18fa83e22ce882397adb9c2f8" + }, + { + "kind": "file", + "path": "img_547.jpg", + "sha256": "1d013aafb6986d5f8d8226f16fd25d32edd06bec20be3b19a8ea1915767ea59b" + }, + { + "kind": "file", + "path": "img_2910.jpg", + "sha256": "a3601ea440291d87dbd97c5050c0dda632a85d17e04b27125b48e4d5552904b3" + }, + { + "kind": "file", + "path": "img_4385.jpg", + "sha256": "90d7df03a297031054c63e301ee6b41ff41a13c3fc9ee686df87c30cf1c1e803" + }, + { + "kind": "file", + "path": "img_4391.jpg", + "sha256": "22125c40ab2984ad8da05e1bbf22e8bf50ff47e783954fc9a592b34fce7d647d" + }, + { + "kind": "file", + "path": "img_3617.jpg", + "sha256": "00f60328453ba556a6d7023ab7921df221be58ecf6560b6b0cff808abc00159a" + }, + { + "kind": "file", + "path": "img_2509.jpg", + "sha256": "5a5d85cde730a6854c3527f9f80ae28dbe18c911eefb92fb2051a8c3383e2e1c" + }, + { + "kind": "file", + "path": "img_1000.jpg", + "sha256": "ed004a30d9cab949d5585646d1a368922817ecb177a7fab402ea1e9467ccb4c0" + }, + { + "kind": "file", + "path": "img_792.jpg", + "sha256": "63c978e77378d5cf1fa95384dc13a69c9f3eae11c5cc5204879620fdede7f6ca" + }, + { + "kind": "file", + "path": "img_1028.jpg", + "sha256": "122b5e4a123da280a63be1eab44dcc37eb24dc1abce604ba5e494d286d6c55e0" + }, + { + "kind": "file", + "path": "img_2284.jpg", + "sha256": "7d49e91b73ab811afe2418fddd38cdea7d7cc9683dd22f8c3ec6ea8e69820282" + }, + { + "kind": "file", + "path": "img_194.jpg", + "sha256": "bd658ee3b328bd1adade3d060486427e7c32eb3c73cf4f7d9f350df0dae87dbd" + }, + { + "kind": "file", + "path": "img_1174.jpg", + "sha256": "1e4710059b62febbb1292659b345daf76f423288153d1be42e649e92f435e550" + }, + { + "kind": "file", + "path": "img_1612.jpg", + "sha256": "6e5ddb18e50bb58377629a01f0e94ae80855dccf37b63271d1fbccc422ee94e0" + }, + { + "kind": "file", + "path": "img_3011.jpg", + "sha256": "74230014530c28aa2b26ce0568335c69f2db3e598f14702b41d5a69419c0e98d" + }, + { + "kind": "file", + "path": "img_1606.jpg", + "sha256": "8c08cef95089dda197aab431610f51a49782e7b4bb2a4da3b1d92f536db74867" + }, + { + "kind": "file", + "path": "img_3987.jpg", + "sha256": "8e33a3d57602ac183a4be56d348017ad63e2cfdff7164617788478907d7dc0f4" + }, + { + "kind": "file", + "path": "img_2441.jpg", + "sha256": "f931f6fe75c6f61be5f674b3864a6d374a73b67bc79ce5eb363163ccad3d8cbe" + }, + { + "kind": "file", + "path": "img_4030.jpg", + "sha256": "089c95c9285b55967eda61658be8380a3b832d4ae7170b102a9603782508e445" + }, + { + "kind": "file", + "path": "img_2327.jpg", + "sha256": "a6bd64886c50767e9b86f491764d3ca842db71203b370f669bce247b6ea028b6" + }, + { + "kind": "file", + "path": "img_802.jpg", + "sha256": "e59468062f8db8f488666b205ca54b77fd8e918c928960044eee7bef8b4f584e" + }, + { + "kind": "file", + "path": "img_3978.jpg", + "sha256": "84c055206ba5ea7a8e90bc3c6c74c26e37f0b7454b37c15f7e343b935b7f3195" + }, + { + "kind": "file", + "path": "img_396.jpg", + "sha256": "1f4ba50c9ba6ef0c4c2db74c6c933bfd51c3b824f0aa4e82ca88eeaf952acb98" + }, + { + "kind": "file", + "path": "img_2125.jpg", + "sha256": "53a85a8ace99437924b8a65643cf9d0f3295452b5784730054f03f292ec5e317" + }, + { + "kind": "file", + "path": "img_2643.jpg", + "sha256": "d99af16d5e744f921df339a285a68c70c40bfbc444c6718be8617cd67846dcb1" + }, + { + "kind": "file", + "path": "img_1389.jpg", + "sha256": "1bba6cc8236f0cb3c420e51ea0983f585fd93c32bdc6cc8eb9859bb48f4ddabb" + }, + { + "kind": "file", + "path": "img_87.jpg", + "sha256": "52f7a24aba32bd6c06d66b0c8009bbed9526ebf07cf1db2495c3ba0c55a64c17" + }, + { + "kind": "file", + "path": "img_423.jpg", + "sha256": "e122dada4d3026aa9c965f457bbab037215f8ad8907f86705cc5bb228d90dce2" + }, + { + "kind": "file", + "path": "img_351.jpg", + "sha256": "e3a026eba2bb3ef31d1eee1fb48433d27634f56f6c287c58204a49f770de933a" + }, + { + "kind": "file", + "path": "img_1399.jpg", + "sha256": "812905119bafbc290656297c02d89ccd6ea57773414984c1ed1f8da325721272" + }, + { + "kind": "file", + "path": "img_2690.jpg", + "sha256": "db66095db03f4991bf3bb2ebc21a0ad8fded73395d0509241d2e1a9668cc2da0" + }, + { + "kind": "file", + "path": "img_2684.jpg", + "sha256": "a6320f314cd5bc6f389df718ceebbe3769d962c9a9e99fe877be6fcd7b7b701a" + }, + { + "kind": "file", + "path": "img_4578.jpg", + "sha256": "0e4f74206c04ecedbece6dd007a3e15c92e60d24bc98dbf293d1c36ca1817347" + }, + { + "kind": "file", + "path": "img_2109.jpg", + "sha256": "e1880fd538771def5ec11d6948433c90b8b79f6dc43e95ab0d55331dce370384" + }, + { + "kind": "file", + "path": "img_1366.jpg", + "sha256": "95b83fe7a7ba884b1d23ce400e424e5a478dbda595c300fdd807009705bd98b3" + }, + { + "kind": "file", + "path": "img_4785.jpg", + "sha256": "4cd6df98b29ac1d53ead8efe3c226591cf80ce9e9acf695512273b09d1e51d7b" + }, + { + "kind": "file", + "path": "img_3773.jpg", + "sha256": "bc8de538bdb83f08ed7c681be9396346e80825c96999e0ed063b7be63e1d8e6f" + }, + { + "kind": "file", + "path": "img_3001.jpg", + "sha256": "269d1984a7b38b592ac1e116b54d3f62e2498ea49685e2ac6f6e67fd710b329a" + }, + { + "kind": "file", + "path": "img_2479.jpg", + "sha256": "816f7627d27c4384a2d6e445eccc74ef147af315eb2e6758a7ff9e2fca48643d" + }, + { + "kind": "file", + "path": "img_4020.jpg", + "sha256": "13bfc8d75e04b27c6a8effe45ca84f52b5c8cf488f736458fcbb7c40599b2bf0" + }, + { + "kind": "file", + "path": "img_806.jpg", + "sha256": "153b537475760c37c1f8f4856ca11d6308719d2c418ba374d7bbd553d4f376ca" + }, + { + "kind": "file", + "path": "img_4746.jpg", + "sha256": "0087f36d5c8e29e0d4b5fe0229f80fb530d8f6c2a46dd86bb46f2b894fddefb9" + }, + { + "kind": "file", + "path": "img_2323.jpg", + "sha256": "4b79bee836a39ae3baadce64ee76bfb181c5a70016281dc415b564132f693169" + }, + { + "kind": "file", + "path": "img_3983.jpg", + "sha256": "3f7cf8182886742017a4aceb5f5a699b65ca1c19a2672ff41304e64bd54c3132" + }, + { + "kind": "file", + "path": "img_4815.jpg", + "sha256": "37c608e33debad5ad72d4d72e5e1bb479f715c9e201e59ba3d7eb8268555b3a3" + }, + { + "kind": "file", + "path": "img_999.jpg", + "sha256": "2bae10a72123830129132378ce5c209d0f4d8bb0d3bbbb8cd373b8601823c923" + }, + { + "kind": "file", + "path": "img_3820.jpg", + "sha256": "bc084b792a15faca2ea306c487000217f3e7855b045b13abe9e36d6240b12ba7" + }, + { + "kind": "file", + "path": "img_2280.jpg", + "sha256": "a50052cef5dd8c825c81bc6c7b13a8493596924afb735598fd8d7a428d88591d" + }, + { + "kind": "file", + "path": "img_4829.jpg", + "sha256": "5af3228c6011a66596ebb49a945472efe63c1d44d1ff52b2d0cdcdfab98d063c" + }, + { + "kind": "file", + "path": "img_4183.jpg", + "sha256": "068d565446f93c02e963e0f3dbe09894a5df531a9d5f4418295f44372e7949af" + }, + { + "kind": "file", + "path": "img_796.jpg", + "sha256": "62ea8748717d62b0dab64aeccf35ecc52724b9647fac7780ec45733f896476b3" + }, + { + "kind": "file", + "path": "img_1762.jpg", + "sha256": "4d2584da5f6d30dbf60d8f84e5407bbe4a4064671bd9c56ebba881eb7a350712" + }, + { + "kind": "file", + "path": "img_2525.jpg", + "sha256": "dd4509a7606455f4b188dba2bd2c9a40ba2fcc46d914f7cbaf7e11a372714ea2" + }, + { + "kind": "file", + "path": "img_1038.jpg", + "sha256": "51f168866cc32c6e8398c8506a0c547701bb9e686594286c4f996cc9974a6839" + }, + { + "kind": "file", + "path": "img_4381.jpg", + "sha256": "7f70f789a1254775bfda2d4a66463db533949942053ca585118a0dd7acbf6434" + }, + { + "kind": "file", + "path": "img_2928.jpg", + "sha256": "2d8698634f25a58a72f3fb89fbfc588546d6b036772224465494d93da9e86695" + }, + { + "kind": "file", + "path": "img_3405.jpg", + "sha256": "5e14bcca20023d65300d86a217e61b5a61b524f4d80701177cbc5c7caf46053a" + }, + { + "kind": "file", + "path": "img_2041.jpg", + "sha256": "53a8103ee517c52b9e81ea80cebe5b40f35a82c2bfb338eb3062c50e071c13eb" + }, + { + "kind": "file", + "path": "img_4425.jpg", + "sha256": "7d84345ef8966941c9b51152b8211063c57b58e90069b78ec24f60eb0e3f1fa4" + }, + { + "kind": "file", + "path": "img_1549.jpg", + "sha256": "c7cdedadb9bfc50bd4ffc743c6969a4bff28259b5a6d0769dccd6f213eebdc7f" + }, + { + "kind": "file", + "path": "img_3362.jpg", + "sha256": "670e4efaa627ceaa052eb8bbd0e48cf32b059a6480410ff727dc1f5305df9d7f" + }, + { + "kind": "file", + "path": "img_4380.jpg", + "sha256": "7a78ccf664369257a79ca4325da6784d68c1a7ea7041cd8ec932eb21f372473c" + }, + { + "kind": "file", + "path": "img_2901.jpg", + "sha256": "1c0ba1a19cb34a7e044e9ff4b7b317684a50787472864b7c1fcaeedbd73ca546" + }, + { + "kind": "file", + "path": "img_967.jpg", + "sha256": "0f48edd75456e6ebb7903c684ed8250752fafd800b88e72de935db05d92c10c5" + }, + { + "kind": "file", + "path": "img_1987.jpg", + "sha256": "53ae76718386b89d7c1c4d612e254a59b46a7205adf4bacf02a2c2deb95c2070" + }, + { + "kind": "file", + "path": "img_2524.jpg", + "sha256": "015c4f57a81cc66127292307510e74b660a3b4443cec4bcb3a7b86e30e3920f9" + }, + { + "kind": "file", + "path": "img_1993.jpg", + "sha256": "401938289506de8bfa16e9ea8b866ccd80af2d6e8a297535584570fc7c699015" + }, + { + "kind": "file", + "path": "img_2518.jpg", + "sha256": "3f206f2501fb9fd052aa73bf56c51c6d46caff9ba75106c1269fee70453bf6e6" + }, + { + "kind": "file", + "path": "img_3835.jpg", + "sha256": "7ef3a7553818992c4c3c09a68a769ba931b1fc0b052bd085fb9e708fc5305454" + }, + { + "kind": "file", + "path": "img_2281.jpg", + "sha256": "9cb94e211ae861cd844f4393a3965c1f3e0d77a0eefd6bd174a40a1d984252de" + }, + { + "kind": "file", + "path": "img_740.jpg", + "sha256": "8b8ba6adf45dd36a5ce83c39de3bea561dfcea9d30d82813667952b5b2b5662a" + }, + { + "kind": "file", + "path": "img_4800.jpg", + "sha256": "27486245d8a28de69edb4ffc16fc66fdd03255b486cfcf9db2c8ad0be9ef031e" + }, + { + "kind": "file", + "path": "img_4753.jpg", + "sha256": "5dcb2f7f522ca12c9b03784b249fb087018fa454d31fbc9995cbaee0be3be97b" + }, + { + "kind": "file", + "path": "img_2322.jpg", + "sha256": "d221ddea84d3ff9001599e9ceff2ee8da9ebda63e5fc731d6c385c0004795aa6" + }, + { + "kind": "file", + "path": "img_4035.jpg", + "sha256": "dab9379e1a91bc23ced2843044191427d638561e053fb7c71d5b0244fd9e407e" + }, + { + "kind": "file", + "path": "img_2336.jpg", + "sha256": "afe214954f8606e181c4243e9df04f7b65e1111c8a7be334800d5e3206df6e29" + }, + { + "kind": "file", + "path": "img_1617.jpg", + "sha256": "52ece3473f64dac94649f906e158e4eb184e21ee357a117de8d1499d83e1c1aa" + }, + { + "kind": "file", + "path": "img_4784.jpg", + "sha256": "796197dd15804deb19113f4d87a56fa8231fceabddc46232e132d4ca56fa4b39" + }, + { + "kind": "file", + "path": "img_1824.jpg", + "sha256": "54b693092cf60c32d8d85833c00e7b8c2d6b2d94bab077a525b50d57cf70d25c" + }, + { + "kind": "file", + "path": "img_1818.jpg", + "sha256": "a77a62687a60077598b63452efae61422b3ee24473f2b717982028ef66abe18b" + }, + { + "kind": "file", + "path": "img_3558.jpg", + "sha256": "c7810e97cd65ff1a5e25ac54abcd9bd11513b340ee6546278f664826c2a027d6" + }, + { + "kind": "file", + "path": "img_4237.jpg", + "sha256": "c5c4845f487f631b81621f20513b86464cfc5da81f57c646d561eef73208b14e" + }, + { + "kind": "file", + "path": "img_1429.jpg", + "sha256": "b72ea33f9b2ace713ed671203fbbd1650d739de1053e6d8f80cb6a7f4e7266cc" + }, + { + "kind": "file", + "path": "img_2120.jpg", + "sha256": "e5539e75f68987b39092c5e9d6da4b8694212a186eb5ee100e8bd4ed38ad9af2" + }, + { + "kind": "file", + "path": "img_41.jpg", + "sha256": "409513655bee7d79e9502d78893a1a0317a87f76532a1fb356e2b0836abd3eab" + }, + { + "kind": "file", + "path": "img_1401.jpg", + "sha256": "a61f0c6ca9d02288ed7d217bcaf06d0104f61ec70f42f5ffcc3ba6387d4fc529" + }, + { + "kind": "file", + "path": "img_2685.jpg", + "sha256": "af450181d046ac5da0aec9dd6e4dfadbbce2f6006c5a269fbb0eadb9905c5db3" + }, + { + "kind": "file", + "path": "img_2861.jpg", + "sha256": "6f653173325c2a2b3a2fbd2563f392ddef364a0e4761ecf26bd387b83c3a6df9" + }, + { + "kind": "file", + "path": "img_436.jpg", + "sha256": "78ac6eb4d437ccd1a6847ece3859ed2d5f3094542b9d47b13c4d393b47a6b17e" + }, + { + "kind": "file", + "path": "img_3599.jpg", + "sha256": "edc71cba15c2b3222b2a41ed89d01dfc98fed2151d629d6d4680345756510056" + }, + { + "kind": "file", + "path": "img_2693.jpg", + "sha256": "8f0a0c44d69f0ef75c4cf301dbd17e31080f71dc13a68b5ed37687ab97416e7e" + }, + { + "kind": "file", + "path": "img_4209.jpg", + "sha256": "0e63f530f4641bcc25573865ee07752845b6c7e15d26a705c96efd119aa43fe2" + }, + { + "kind": "file", + "path": "img_3572.jpg", + "sha256": "0e1587178953b050d5ea3dadfa617ca9881ca041d3d6747db40a7ba3a65a6cd1" + }, + { + "kind": "file", + "path": "img_2644.jpg", + "sha256": "953e2def562a5da5f80309ae1a8d7aa88eec3d1597a91ea98ee8f8b64b7f44fc" + }, + { + "kind": "file", + "path": "img_2650.jpg", + "sha256": "bffecb19bf9bf6c0fb066002fcae8ecb0cbf89fe154d09c27e45f375a86736d4" + }, + { + "kind": "file", + "path": "img_4221.jpg", + "sha256": "4553ccfa718cde946fa055e8b9a94ac40589ff314bab2db4f2d16ba1d590b791" + }, + { + "kind": "file", + "path": "img_3943.jpg", + "sha256": "09dd67ab523e42c21fe39a78dd8569704bec5d5a0eee5f12d511ac8a785ef5b3" + }, + { + "kind": "file", + "path": "img_2308.jpg", + "sha256": "37daf389b3133792fd4992146a6d91bf826e08e5d893865ac22c42fcb6a08cb9" + }, + { + "kind": "file", + "path": "img_3016.jpg", + "sha256": "e8e52468b0287dee9cbbef49b400c7a4ff63f3196c4890d3cff2803187be907f" + }, + { + "kind": "file", + "path": "img_1629.jpg", + "sha256": "2d14525254c12f66df35b34f165cf05b604ab17a643d680add748ac4420b0d59" + }, + { + "kind": "file", + "path": "img_4816.jpg", + "sha256": "021616a42d163e824b60f00c60788bde7b7d9463adff3eb016e91eb3127978d4" + }, + { + "kind": "file", + "path": "img_3189.jpg", + "sha256": "681f003c9c848281be32fcf80d62d50624aec9d14d4f53df7414c0f3e1262e29" + }, + { + "kind": "file", + "path": "img_4194.jpg", + "sha256": "f4e01fa1837314f508dbd37435ea1a13d407bd2d11a901624cf7e6073415c2b6" + }, + { + "kind": "file", + "path": "img_1007.jpg", + "sha256": "bb454bfcee80c5d9b87efc2c16587f82eae52be74f55f3a4ae286cff70e11c3f" + }, + { + "kind": "file", + "path": "img_4619.jpg", + "sha256": "089a269ac7994b2da633eeab8fa2df4363aa79c0e6f49011ff3b77788cb05683" + }, + { + "kind": "file", + "path": "img_1761.jpg", + "sha256": "e9efc044395bdc8a930c5de8f9a6175f638b910f598c51ebf7417ed5486eee27" + }, + { + "kind": "file", + "path": "img_1013.jpg", + "sha256": "96c33d8878cfef64d96af0583def110dd56471fd875dcf821f6c5e1be751804e" + }, + { + "kind": "file", + "path": "img_4157.jpg", + "sha256": "08af2db21920a26654b0aa68372e0b8aa66d191f60c1bc78a458da066b4d2d79" + }, + { + "kind": "file", + "path": "img_2917.jpg", + "sha256": "61708b8b9afd448116d23ee269a7aa852f62b5c1221483c99e910340e50c468d" + }, + { + "kind": "file", + "path": "img_2903.jpg", + "sha256": "d1b239fc5b0ec2d0f7d2887252cb3cfe49f9ae2e3eb801573a23b9068507eaa0" + }, + { + "kind": "file", + "path": "img_1211.jpg", + "sha256": "3a0ce2b8d2c4636bc526e03d00d8980cf05bfaf2bd2cf1104e7fbe283a36cbde" + }, + { + "kind": "file", + "path": "img_4369.jpg", + "sha256": "c91582bc4a89eef2a8934a1ff27f0728bbacea1cd9bfa56b90a9d4efdf9ca83e" + }, + { + "kind": "file", + "path": "img_2718.jpg", + "sha256": "aa3d9451594dcdf8189200d0cf7fbaa6f9f32eeeb12b5e6d56f2871d74557b2f" + }, + { + "kind": "file", + "path": "img_1577.jpg", + "sha256": "ac9deb443f031f13b09f4a65ba0dc6127859a35f80adf709fa9b1b10c059d74c" + }, + { + "kind": "file", + "path": "img_4355.jpg", + "sha256": "b504a7c275348d8933791d622f409a688048990246db7a0a17c62569358613aa" + }, + { + "kind": "file", + "path": "img_2724.jpg", + "sha256": "408f052a0d2e20f981b5b5e81086dab86cdbd754329882e0a003d652618b984b" + }, + { + "kind": "file", + "path": "img_2042.jpg", + "sha256": "174d3407d15b83aa3cda4523a51dfff39c3e242adedc0820b2461f8626816bd1" + }, + { + "kind": "file", + "path": "img_3407.jpg", + "sha256": "9ae3c0ff6eacc7904fc7551e49cc243cfc89041eecece84eed5c009fa0b25407" + }, + { + "kind": "file", + "path": "img_1210.jpg", + "sha256": "40ac12a50d8e7a4ffa9007ba60228cfbf4fea16cc520a253ecd2f699a08198bc" + }, + { + "kind": "file", + "path": "img_2094.jpg", + "sha256": "f30f337146802dd87c423565c0f1eccc6242395836883b4832ed6947a0da15a0" + }, + { + "kind": "file", + "path": "img_4383.jpg", + "sha256": "7d3030b4686c629c1e5730486fd4deefaf47021195e44effd9a9bc3ef7a80b0e" + }, + { + "kind": "file", + "path": "img_233.jpg", + "sha256": "e574b28373a09c8b1d405a515604803cb50162ce4ce05ed78e981e15fbbd216d" + }, + { + "kind": "file", + "path": "img_555.jpg", + "sha256": "683ca4911773dc4feb7e6fac8158b8776fde0175816dfabf1f86ba85aec715c0" + }, + { + "kind": "file", + "path": "img_1748.jpg", + "sha256": "a4e92eb64504d4c0c9b9468fad12858018649685c71e45719cecb96d00aeab56" + }, + { + "kind": "file", + "path": "img_2241.jpg", + "sha256": "9b252b1013af7a9654f72d74a56268e70c7e0ad2e3473e2757db11c0a81ff816" + }, + { + "kind": "file", + "path": "img_964.jpg", + "sha256": "e449c16589bf8a4dd10f484768e9d68075e51e40bf25c440377a3b4326b39408" + }, + { + "kind": "file", + "path": "img_1760.jpg", + "sha256": "802c0415d71ba886c9fe311e5c193b920c654410ea96a910b0bd5e0178b4a49a" + }, + { + "kind": "file", + "path": "img_1947.jpg", + "sha256": "2e278acec9b8463b095f394c48abbb29f7d311f733fa1fde6a7a0fe10b2bbeb8" + }, + { + "kind": "file", + "path": "img_3188.jpg", + "sha256": "f20c4ac68332d9a25a34e0b0ee2eaf9083d19df57d6ecbdc5f71987bc8fe18a6" + }, + { + "kind": "file", + "path": "img_4036.jpg", + "sha256": "bafa89c1e629f01505216f8ac1eff0cd34a250f70fb4e3569cb0af0d02ea62ce" + }, + { + "kind": "file", + "path": "img_1614.jpg", + "sha256": "953f95380e3844493ee65f97c86e60a0932d90e4367aa2d0d4e235a9d211147a" + }, + { + "kind": "file", + "path": "img_179.jpg", + "sha256": "15e0e5f027bcd2699dfc88e7afe39076ee77036096ca98db7130783e1e8f749d" + }, + { + "kind": "file", + "path": "img_2490.jpg", + "sha256": "209458b2362f89fa870c3445581062d9cce7f682df13bb1fc7b17c5533c1f150" + }, + { + "kind": "file", + "path": "img_3956.jpg", + "sha256": "6fb901b7868cff44d85df2c7c22c8e4d0199de0a5dfa4b6af3de9d4d2b7c7158" + }, + { + "kind": "file", + "path": "img_56.jpg", + "sha256": "c53189fe22e92f3863798c22e67a21ff1ea79f4ae0aa6ee6249c6d10a215298a" + }, + { + "kind": "file", + "path": "img_384.jpg", + "sha256": "87b8ae9464052d3828a5ad9ef81e653848a522f632e8e9ec8bea539dbf9a6aa8" + }, + { + "kind": "file", + "path": "img_1370.jpg", + "sha256": "8810346c21902f00e1e7b78a0d91f5604e7cab2ebbdd689326513b4b57061604" + }, + { + "kind": "file", + "path": "img_2692.jpg", + "sha256": "c09cc74249d14316d17ef548ea382350b9d0061e9f54e2ff7fe93ba62f480c8a" + }, + { + "kind": "file", + "path": "img_347.jpg", + "sha256": "594454d9ad7e86d82bed20b3fcfd7304d5f32eb461e21d6cb198ed7adf28e8df" + }, + { + "kind": "file", + "path": "img_353.jpg", + "sha256": "500f5c4419bfa8020af57b4cd06ae61c74d4d38dbabd5a12bb3370e304d8fa0c" + }, + { + "kind": "file", + "path": "img_2187.jpg", + "sha256": "bf796fe2e3bc5395d9cc1ac29698c3b84a0758b0a94edaf4db92f6f44dddb175" + }, + { + "kind": "file", + "path": "img_452.jpg", + "sha256": "b8b592c0faa7fb78c8c3fb7ec7edfad16a8ca52648634d24d1a521ac60d598f6" + }, + { + "kind": "file", + "path": "img_4535.jpg", + "sha256": "75fb17ee703d9e0d85e3583736aed9d770007d10b3564355ff6c48562fb90914" + }, + { + "kind": "file", + "path": "img_31.jpg", + "sha256": "2940c096279b52a247c90c17df56d7b59e7ee295a2719cf3c43cf08b4f95e596" + }, + { + "kind": "file", + "path": "img_4253.jpg", + "sha256": "6695800701639ce7a93c14a0c144f928ff5524ad0bf2339d4d4387869e835349" + }, + { + "kind": "file", + "path": "img_4247.jpg", + "sha256": "de53ec0ecfbaa15c80420d38ba2397b68a9272f8520f8a44a76b3172726e500a" + }, + { + "kind": "file", + "path": "img_1471.jpg", + "sha256": "eba95dfb294601b6f5d87d28a1369b677688b75159276db7c099ad82e9a43f4e" + }, + { + "kind": "file", + "path": "img_1465.jpg", + "sha256": "35a680022b081375ff2b271f9ac4cc11a1315fd814bfa556c24ba47752b5bc2d" + }, + { + "kind": "file", + "path": "img_2385.jpg", + "sha256": "a251516b1c261fd0f42c26e3ef2f61430531579d5a56d27581f14152dd7ca03b" + }, + { + "kind": "file", + "path": "img_678.jpg", + "sha256": "06eab15bbb1dd2b4fd34edbae3f0c3bf486607eebbf042204e86ad5d48dc5274" + }, + { + "kind": "file", + "path": "img_4086.jpg", + "sha256": "f596587c83429e8fe244ae13b06ea5a229e82147f162e68f846deb40ce33c710" + }, + { + "kind": "file", + "path": "img_888.jpg", + "sha256": "f742bb11d185565e3d617c61ce2f4102cdb53a15e063e8b297b1d008a7eeebe7" + }, + { + "kind": "file", + "path": "img_644.jpg", + "sha256": "9ec9a49be23243d7bbf7343b04757ceb4b3c5f927a9920e375b14a0f530cd6bd" + }, + { + "kind": "file", + "path": "img_2420.jpg", + "sha256": "9aac7b957a66c13780476d5360f25420801901eeabe58f46c70f28e8bf3a17f8" + }, + { + "kind": "file", + "path": "img_863.jpg", + "sha256": "758680af9458b31c527cc47e3a726524809bca4c387248cdc2557e4af2e27306" + }, + { + "kind": "file", + "path": "img_3702.jpg", + "sha256": "9cfe1874d041c5427e4f30bd17d0c310097e1bdd8d809429274a5065e684005e" + }, + { + "kind": "file", + "path": "img_1115.jpg", + "sha256": "36144f3be3307d1bcfab3b712e28474caa05967f9e0a720966573bffb3f8146d" + }, + { + "kind": "file", + "path": "img_687.jpg", + "sha256": "32b07a9393fb6da8e2c78ae60f5d2b5529b16af698fc299c9af0b65ab6f8994a" + }, + { + "kind": "file", + "path": "img_1101.jpg", + "sha256": "45b47e59972399123234262b7b71a71986d541f70d0d73692d92f796e3d2a6d3" + }, + { + "kind": "file", + "path": "img_1920.jpg", + "sha256": "37c4e814ab04e0a1226eda209d067a4ea7a9ef1ae1aaebdb12c92e451e0ad2c5" + }, + { + "kind": "file", + "path": "img_2583.jpg", + "sha256": "9c4b81c7cd6134194034c5fa457ad2c595d7b0232549fba63848c8b81c0508dc" + }, + { + "kind": "file", + "path": "img_4864.jpg", + "sha256": "266cd832f7f125e586a16168c46d682972f43ba24c282db3597e1e8735032f77" + }, + { + "kind": "file", + "path": "img_2232.jpg", + "sha256": "561e43fb815ce7a2749e76274e0335acca8757745b8b516801dc009ad539b427" + }, + { + "kind": "file", + "path": "img_3138.jpg", + "sha256": "326c74dac3c20a4da62d324c9cdf1e2dc1b6cfeb8587122270548f5170917f28" + }, + { + "kind": "file", + "path": "img_2540.jpg", + "sha256": "649ecfc0532481861b46c62728579c7506097572dd8dfc906e35f479c981e13c" + }, + { + "kind": "file", + "path": "img_1707.jpg", + "sha256": "d79c2fc701cd3875c4ee1c06793ee5d1a98dce27eec76eaec09b704b367d8b17" + }, + { + "kind": "file", + "path": "img_3110.jpg", + "sha256": "d34fefe796122e6f45be02f8f75442d6820f96f93666e4576ac35e8afd895b6b" + }, + { + "kind": "file", + "path": "img_3104.jpg", + "sha256": "99fda2d5b2fa5d25a68c622a072d9889565ba411bfa65ad2ff1085c9383bbe90" + }, + { + "kind": "file", + "path": "img_4482.jpg", + "sha256": "0cf4540852323ad617d3a10a5f4e0ed495b258f1f3aabea27533e59224bdce38" + }, + { + "kind": "file", + "path": "img_4496.jpg", + "sha256": "f7c0a75f4e8d25b418c70545e6e85e89ba94605b9c3a6fd7902be390731671fd" + }, + { + "kind": "file", + "path": "img_526.jpg", + "sha256": "d4b5f5623904f917d3856852094ab8432a7f681b109a15a1a2a6e2de659d0fc9" + }, + { + "kind": "file", + "path": "img_2965.jpg", + "sha256": "f7847fef946cf2539ec569e81478d26302ff398d2b5108555d089a9ce4874b12" + }, + { + "kind": "file", + "path": "img_2030.jpg", + "sha256": "ae7ee6be52e32b02a87111753e77c87673076642a8a18262ee7e246c3527cbdd" + }, + { + "kind": "file", + "path": "img_4327.jpg", + "sha256": "3f01c76144e564229a62ca73257149ccebb0e5d56db52088287eb0bd30a56844" + }, + { + "kind": "file", + "path": "img_4455.jpg", + "sha256": "d6089d11fca7f1af22f3874e287f6072ef9ea585f4173e50539ec2a6c34e12cc" + }, + { + "kind": "file", + "path": "img_1505.jpg", + "sha256": "bb1da369584da032ed7424b0d11e40b2dad5f50296e2d9d0770bc6b7e1ca55db" + }, + { + "kind": "file", + "path": "img_3460.jpg", + "sha256": "d0050bea77e5a78e16815260a31017de337c7eec0f10a870efc6a70b6acc2766" + }, + { + "kind": "file", + "path": "img_2743.jpg", + "sha256": "1ef748439bf4c1bf896a868b39c18cc472f3c253c8a7d3d02f1c43c2c7029deb" + }, + { + "kind": "file", + "path": "img_4332.jpg", + "sha256": "e91f2bf3762fc35734a6033693197c43551db13e9d222898ccd1d85169e41ae8" + }, + { + "kind": "file", + "path": "img_255.jpg", + "sha256": "42fa5745a68abb63bf23c7105df2d0e9fdd5a89e74d37a70d4c46da5215085b7" + }, + { + "kind": "file", + "path": "img_2964.jpg", + "sha256": "39aa72907ca654e777a27efb158ac430c0b43d14f83fa1320cb2926ee19f057f" + }, + { + "kind": "file", + "path": "img_2958.jpg", + "sha256": "cff248ddd2e68929fad1fa27cea59534115e11d4a06ccd2167bf856d83ac8a2c" + }, + { + "kind": "file", + "path": "img_9.jpg", + "sha256": "856dacc973e484b3c73a3678d77bdbf41df828d010d76aedbfb50f618c3c9546" + }, + { + "kind": "file", + "path": "img_1712.jpg", + "sha256": "bffda89556722d3de4ba769a788762869d99c8683d12732ac91c77ed86b5c4a2" + }, + { + "kind": "file", + "path": "img_3677.jpg", + "sha256": "e4ef08bafc877c84e218f165e0790be3ae1e308342fef7181bbd4aad36846ea4" + }, + { + "kind": "file", + "path": "img_916.jpg", + "sha256": "3f5243751cef5cc2947ab4dbac2ce83bb3e70cdcf599b9a86761f72c85dd9e64" + }, + { + "kind": "file", + "path": "img_4130.jpg", + "sha256": "42c622f27cad66a82ce7c9b8abb5848291b6e10dc790dc725a00a34ce550adfa" + }, + { + "kind": "file", + "path": "img_731.jpg", + "sha256": "bd78451914d1fb21fdbd48adff8cfc60b1746ce9660e1369bb132906c629d6dd" + }, + { + "kind": "file", + "path": "img_4871.jpg", + "sha256": "1d3b526a6e6b7420a909f810a4043e61fe07a9c6af03210c056e8ea937e396d0" + }, + { + "kind": "file", + "path": "img_725.jpg", + "sha256": "593a1570b8a7e95d397601ca894684cb87fe908858dd7c6f37875cc1ab69759d" + }, + { + "kind": "file", + "path": "img_4695.jpg", + "sha256": "afc6788c1d332e0d2905cfe938cc021353e1073d0f22ebca989c1cf29819ade7" + }, + { + "kind": "file", + "path": "img_2582.jpg", + "sha256": "256f41a53e044256e4c739dc20927c8ff035aba782e5833bbae6b53426d9c333" + }, + { + "kind": "file", + "path": "img_3844.jpg", + "sha256": "9f0a05399a090397c0f84b6607adb7affda36ff4f4595ec1a9e1bdaa8533a4fa" + }, + { + "kind": "file", + "path": "img_686.jpg", + "sha256": "6174901560fd9f5c4d8259ce7ee5354f63f84209ce0e367c0c0afcfda1f0bd3e" + }, + { + "kind": "file", + "path": "img_4078.jpg", + "sha256": "5d7aa420a11090d36c1dd40072fcb83b5a28bdc07747309a64fe9133ec50b655" + }, + { + "kind": "file", + "path": "img_2421.jpg", + "sha256": "26da86a914499ae026eb1d15e62606cc96dfa17dd3469e9061913f0c6cea046e" + }, + { + "kind": "file", + "path": "img_1896.jpg", + "sha256": "2442e0d495c19f38415a447942ea0dbda236d606f5e52fe43d6802bd84bd180f" + }, + { + "kind": "file", + "path": "img_2347.jpg", + "sha256": "3192cf98b24523bf75df9cb67a9bcf286d2bec7efd44b5bad2ac9e2e5fe41599" + }, + { + "kind": "file", + "path": "img_4905.jpg", + "sha256": "567945226a3c2adb55c56fa0000e429a411f33b8091a92168333f85b967a309f" + }, + { + "kind": "file", + "path": "img_123.jpg", + "sha256": "6b9c122313ac94155d9030688d62b3cf90db5fcefc79d0abcf1ca3149fd409fe" + }, + { + "kind": "file", + "path": "img_3918.jpg", + "sha256": "b935be407291673e8d762229f10441a30869360390ad3d16ea75314391351e8d" + }, + { + "kind": "file", + "path": "img_1869.jpg", + "sha256": "6c29bbef7354e522f571ca54cf47b88dc25860b4b78a3a4f0579f38ef0c23886" + }, + { + "kind": "file", + "path": "img_3515.jpg", + "sha256": "1001ac9ab2148865c8983106ccabba1abc9d574803ced5f0fb1ac49f0f74300d" + }, + { + "kind": "file", + "path": "img_2179.jpg", + "sha256": "63f8b797e46833d0c550d22c1986f3b3132b61ddacb2dd3c474791382abf0ae9" + }, + { + "kind": "file", + "path": "img_1316.jpg", + "sha256": "2d26c3e7f686011f75d3ba340541b8f8631fac8d78935c801eda3920191dbe08" + }, + { + "kind": "file", + "path": "img_4520.jpg", + "sha256": "4eb0b491201c94aa8768be2da01392186ac248f8d6b801426e4502043eaeaf4b" + }, + { + "kind": "file", + "path": "img_2145.jpg", + "sha256": "9d615f03f69746779b615f5458cb14ba81b5e0102ccbd245759de52713876c9c" + }, + { + "kind": "file", + "path": "img_321.jpg", + "sha256": "81c5bc6415effd89f182e18095f93932054ecbc622f93a90c1ffe9c9fc88a5d0" + }, + { + "kind": "file", + "path": "img_2804.jpg", + "sha256": "0cfd87d75d5bfe5d1637d4a7b45662b0bb834dbf6f87ddf8c0483861ca1b86a4" + }, + { + "kind": "file", + "path": "img_2192.jpg", + "sha256": "e64ff23761c327d4873f5fdba26365d49a68d09f42d08074aedda517dc397c95" + }, + { + "kind": "file", + "path": "img_4293.jpg", + "sha256": "fb855aa8ea67f908e81f7693271a2490cad45f063aa57e701d5cdf6d76586b37" + }, + { + "kind": "file", + "path": "img_2184.jpg", + "sha256": "0ce7dca09aed207b58ad0773f594da588d393b2721dbeff6574187b7e59b296d" + }, + { + "kind": "file", + "path": "img_323.jpg", + "sha256": "1b035b39e14a56b96c9e4c00a884443d2e441d6c85ae901687af15cd53524357" + }, + { + "kind": "file", + "path": "img_3517.jpg", + "sha256": "096adf5c7dcb9ed94f56f494e0b86dde3f7ceb6d03405d5b7864435a7ecc0481" + }, + { + "kind": "file", + "path": "img_3265.jpg", + "sha256": "bf00745a96d41fe930e19cfbfe4dd6a41dd48796c547b3e1471644b2439ac634" + }, + { + "kind": "file", + "path": "img_3932.jpg", + "sha256": "0f36f41df788ed8dc755d58efcdb3f68c6dda8aeadce28ea455f6422dce38adf" + }, + { + "kind": "file", + "path": "img_4091.jpg", + "sha256": "e77295380233a00fb13c49652ec07098e81c86a6dc25a1b700dec904c787a5dc" + }, + { + "kind": "file", + "path": "img_121.jpg", + "sha256": "57c7e585f431fa370965addc8b4985043f979e685e64c41788251db3b3111f5e" + }, + { + "kind": "file", + "path": "img_4913.jpg", + "sha256": "2535986e749bed64d7cbdd0710051017fa8dc68d59ee75c4ab0bbd3725350b37" + }, + { + "kind": "file", + "path": "img_3729.jpg", + "sha256": "927c8df1d7abf11db06f0e3ee0fb64a2b75b5b1ce90efc0cb97dc1875fd1d44d" + }, + { + "kind": "file", + "path": "img_2437.jpg", + "sha256": "152badf68a18d2c32836aec11191a7c02a279118ae5ee8df52986b1a4cfb2ab1" + }, + { + "kind": "file", + "path": "img_860.jpg", + "sha256": "77c733eabdb4af18542e76fc8cd23b56b4f7d0905d7e626ee783766c694def26" + }, + { + "kind": "file", + "path": "img_4720.jpg", + "sha256": "ae950a4a842a83b33a84475430036110b58a08ec5ab33990f4b52142ad557896" + }, + { + "kind": "file", + "path": "img_4052.jpg", + "sha256": "a033493477559f5447114c564a7cf67b573e93a8139670c7aaf5c4f26ac23f1e" + }, + { + "kind": "file", + "path": "img_3715.jpg", + "sha256": "e9e127fbbeda5aad426714cb38cc76422a7f5c40274c176c88870b95a120b3c9" + }, + { + "kind": "file", + "path": "img_684.jpg", + "sha256": "2198ab04b6ae1e73cd17b4c888f279e428200031ca33e2f6d73ac39d692a5210" + }, + { + "kind": "file", + "path": "img_1670.jpg", + "sha256": "3ce9d248f71b14b01b3da03e3624d904e8050605c46fb0c1ddc4ecb4e6687ef8" + }, + { + "kind": "file", + "path": "img_4708.jpg", + "sha256": "09b64507150072d8c3bd0e317e2a4bb092ac08614c31d58e3cdc242b2faabc21" + }, + { + "kind": "file", + "path": "img_1116.jpg", + "sha256": "a76c05343d74edc151cc7ea0fd04b808f9c1fd5a065eca0400455c4615ff4696" + }, + { + "kind": "file", + "path": "img_4697.jpg", + "sha256": "7fb843e4d5c73a14782cf34660d404dd2e12023be2835ea55dd9f7ed513fd673" + }, + { + "kind": "file", + "path": "img_1923.jpg", + "sha256": "de0bffbae894906f3413532b2a3b7b3abcd60c242e1ef0281d9471c5386ffadb" + }, + { + "kind": "file", + "path": "img_3852.jpg", + "sha256": "e7baf45d0fdb3047a9205d727511ba468c84afd17dfed203e5df852744290426" + }, + { + "kind": "file", + "path": "img_4867.jpg", + "sha256": "096208bc89f42427c05007ca22b98f206751affa21f73bfb47d0ff4f472f966b" + }, + { + "kind": "file", + "path": "img_914.jpg", + "sha256": "3357175e449aa9070b535e64fd52915df63e82448c1a2bc47e30a5f88ae9afa3" + }, + { + "kind": "file", + "path": "img_2231.jpg", + "sha256": "0cda9382aebfcc2535c8f33c0ea37a459e74cefc101d71e3677a05506be0c04e" + }, + { + "kind": "file", + "path": "img_3113.jpg", + "sha256": "79e3b0c75a79e188999124648e5096680982ea133a198880e8cc5ea7014c291f" + }, + { + "kind": "file", + "path": "img_3675.jpg", + "sha256": "5fb9917a461491d131d6996267d81d3e15c83b13a80a1cd46957b9368fc95ff2" + }, + { + "kind": "file", + "path": "img_1062.jpg", + "sha256": "5bb433ddcd1e690bdd268e675ec5e207eadb841cc67a1e5830f64dde7715f46f" + }, + { + "kind": "file", + "path": "img_2782.jpg", + "sha256": "2f52120420e584c3ab54be1dbc8ca06f6d6152200e1a4846972e12052aad4135" + }, + { + "kind": "file", + "path": "img_2972.jpg", + "sha256": "9bf7952cd4b42d5df0a8fc9441aa27b3658f045e774d35fe972c23d2b725278f" + }, + { + "kind": "file", + "path": "img_4330.jpg", + "sha256": "d3781e9dfbb92a4013ccedef1dc7e17df7c34cb821a9b6cf0d7c29bbd9f79501" + }, + { + "kind": "file", + "path": "img_3305.jpg", + "sha256": "3845c504258c0a016e05562402aa5d60437266334ccd27cb1d5645e0fc28823b" + }, + { + "kind": "file", + "path": "img_281.jpg", + "sha256": "33250274cc31ceec47518b2a52cda5679f71997e96764e05bbe5c2e185f2ba8c" + }, + { + "kind": "file", + "path": "img_1261.jpg", + "sha256": "94507bbf421704156b41910a68322e07346730f7ed4fd2b1f28e5f9b86eaea12" + }, + { + "kind": "file", + "path": "img_242.jpg", + "sha256": "3e921c41915591f29b7a6665a1d77939182413b30489449e40bac41c0cd3a9e0" + }, + { + "kind": "file", + "path": "img_524.jpg", + "sha256": "0d8baeb547548b4de3bbcf79cb3cb091fc2322455f00ec780a8ff415a1c7c3bb" + }, + { + "kind": "file", + "path": "img_530.jpg", + "sha256": "e135c59b146bba0e64118c9a549063915f035ee19266483fc628504cc88dca81" + }, + { + "kind": "file", + "path": "img_4480.jpg", + "sha256": "88fa02ed163a07030400a29eddbb5d64df2281f918d746619e47863589afbc12" + }, + { + "kind": "file", + "path": "img_3112.jpg", + "sha256": "cb4f65044a1416f6879d1e3ef80d3c9564d77ef1b697d7b29f44db1335ec1058" + }, + { + "kind": "file", + "path": "img_4899.jpg", + "sha256": "41bcf42faf5dceac225a2bb00f14aca940adb3b922b1d488119e91cddbe24639" + }, + { + "kind": "file", + "path": "img_4133.jpg", + "sha256": "8742ccfe0f7a799138cd9f97d808b5833da1fb198afb563cd955b40113845ab7" + }, + { + "kind": "file", + "path": "img_4655.jpg", + "sha256": "ef9a73191aca7ee2a58b6dd488f92ff3abefa8bfd7aba95b92b195b37401d025" + }, + { + "kind": "file", + "path": "img_4872.jpg", + "sha256": "ef060f47f7fea5d6ab86039ac6778e167740e34a7e6183c8d6e88e65536f51cf" + }, + { + "kind": "file", + "path": "img_1117.jpg", + "sha256": "b5b00fd0437d41cc188f7b94dca7c509b3d6c5bdf89cb1d51ff0d44ea9b4abca" + }, + { + "kind": "file", + "path": "img_875.jpg", + "sha256": "156f709b229fa1fe3c1c087160f202359388cb59b2dcca4fcf2523277614acec" + }, + { + "kind": "file", + "path": "img_3099.jpg", + "sha256": "e446ffdf05e60c12269543e776db0d9bdc32b7ca2ce8635cb63176b42d5617eb" + }, + { + "kind": "file", + "path": "img_4084.jpg", + "sha256": "40620bfaa01510f2273ca5f18d63d3eefa1f9b24aa6d848a7afb1d17aefed43d" + }, + { + "kind": "file", + "path": "img_487.jpg", + "sha256": "82a650c0096b2b7d2d624f0febba3892c7adef6a236f1b4a4bfda1e085d05d7b" + }, + { + "kind": "file", + "path": "img_1301.jpg", + "sha256": "c4da95b8a88368700e8cacc5c4a888cc1ec2c1059663bf3dfa1087a80a12f7fe" + }, + { + "kind": "file", + "path": "img_4523.jpg", + "sha256": "2120b956f609984bc26a91c205a120115a0de33ba5b1f5d38d4f9bfb28e302b8" + }, + { + "kind": "file", + "path": "img_336.jpg", + "sha256": "e49aa28d1b9403f53213102839cf9744db174d7a0e714bd1b93980fa4e772173" + }, + { + "kind": "file", + "path": "img_1498.jpg", + "sha256": "12df76a0dc9a4020aae2a349956ad136a2a011e535e6a4a538b19f2119ef4991" + }, + { + "kind": "file", + "path": "img_4286.jpg", + "sha256": "5bcc4937cb61955ad8e62ffd81c90c34ca49458f48207e5273e9ca654877b0fe" + }, + { + "kind": "file", + "path": "img_440.jpg", + "sha256": "4248a144533b3bba54c9491517e447eb7c074c9808adafff65ce3c1936ac1f81" + }, + { + "kind": "file", + "path": "img_2803.jpg", + "sha256": "e0dd65e55ddc2f4f78ef6b7c097098dcb3f2da1fef7d8db7b194950196f2fb58" + }, + { + "kind": "file", + "path": "img_2195.jpg", + "sha256": "facfb69a47396639cd8e29cf79e4c9ec8b389921c616ff724e4b5ce9a79eddb8" + }, + { + "kind": "file", + "path": "img_468.jpg", + "sha256": "b1dae6c24aa6f711684ce1d5cdda572b47155707d9803c31eb91cb67522589d9" + }, + { + "kind": "file", + "path": "img_1311.jpg", + "sha256": "3c3b8c1d3313f4a913749d9e044fa5b97fc6c689ee0cef1ba3c0e1b5bf3189bf" + }, + { + "kind": "file", + "path": "img_23.jpg", + "sha256": "84a4c20f5e7a27bceaeaafcb49666f32d7a113a94c9fd8066d7f6aef24aa0dcd" + }, + { + "kind": "file", + "path": "img_4533.jpg", + "sha256": "08fad876427b0a7d88ee6f74d7a27b025a80cf6c269261d8f94e9f86ebbe175f" + }, + { + "kind": "file", + "path": "img_3937.jpg", + "sha256": "351d4ea26546cf9a28c72592b6176f2d3752a7cd73892a235d68ee0f3895e9a8" + }, + { + "kind": "file", + "path": "img_1661.jpg", + "sha256": "6eaff44f528e45a0dbb967ba23595d986c1715b643b9cbf425584b13b54292c2" + }, + { + "kind": "file", + "path": "img_3062.jpg", + "sha256": "affabe5501f9d6b30f388c9619c729bf9a8d72e9615e6eabaff1187e24da5780" + }, + { + "kind": "file", + "path": "img_1885.jpg", + "sha256": "dce1a90707fc3399c25e97160bc473625d268c9acdf5157af1f5ada2560dd1b1" + }, + { + "kind": "file", + "path": "img_4725.jpg", + "sha256": "e96f67b907bf2bfd078735712056dcca2a1204e4cebc6c6f70ecff13037ab03d" + }, + { + "kind": "file", + "path": "img_2340.jpg", + "sha256": "becb66506bb901475e4ec0848622a7e90c76bda94c7ca94cfd7b2141aa3b6972" + }, + { + "kind": "file", + "path": "img_1891.jpg", + "sha256": "d6dcaaaf7cbfc0b15eae621612437cdeefd45ed071b9c2a5e4f6e56ce752dff9" + }, + { + "kind": "file", + "path": "img_1649.jpg", + "sha256": "a24ca42be85e4e6307c5c737f2979390306e16a8ac13ea891ee785089dab2990" + }, + { + "kind": "file", + "path": "img_4876.jpg", + "sha256": "08d40056e155adaa22d0e7e843b3d67ef305d531af6147c53b0fdfd2618387ae" + }, + { + "kind": "file", + "path": "img_4692.jpg", + "sha256": "44f250c8311ef409cf5ae916cac61aaf36dd625131e3ee2d0a09ff060d3f1469" + }, + { + "kind": "file", + "path": "img_2591.jpg", + "sha256": "6eb67488c8c0d532e4a3be5662db8dabc5303a060f1f2595f32efc529a42cc5b" + }, + { + "kind": "file", + "path": "img_1926.jpg", + "sha256": "704bba139316c19153aa8ee4e6707631afac901b0b8777f600d64997b6e47a49" + }, + { + "kind": "file", + "path": "img_1073.jpg", + "sha256": "990e9c0620b0f9124393ff73aa946ea4cc253fab859f5bf5f477194392aa2156" + }, + { + "kind": "file", + "path": "img_3670.jpg", + "sha256": "9d141cfa2a9e2be3c0eb3be604d9a9faef4ffcaa22c1268d0386b223f27d108e" + }, + { + "kind": "file", + "path": "img_1067.jpg", + "sha256": "0109ac6ab549c67a3123f74262739329109b430cd6d0d2b19cae8833d8cd19eb" + }, + { + "kind": "file", + "path": "img_2208.jpg", + "sha256": "cc27a57eeac0e7234dc2f9bd67eaffe4835fee0201f34143e7892bc71aaf999b" + }, + { + "kind": "file", + "path": "img_911.jpg", + "sha256": "dac38d3ad149b88a3cd092bd777cdb5b011bf6b04c91e51a35894031cc639c3f" + }, + { + "kind": "file", + "path": "img_2546.jpg", + "sha256": "8c61ea01a8908e09e1f8e408b6d814d5423a1f0397558b4409568a26e735b71f" + }, + { + "kind": "file", + "path": "img_534.jpg", + "sha256": "1d0126467ff2ac00026336682ffa32e72ac07c7319c96bafd65dfe3c71c1b365" + }, + { + "kind": "file", + "path": "img_246.jpg", + "sha256": "69159b00a0fa172b0022543f6499105ee177d896572fa7ebbb4365c1ab60d0e6" + }, + { + "kind": "file", + "path": "img_2787.jpg", + "sha256": "d4e58f1236c91f064e84922951e44181991e54da36ab9e179c1396fb7fcc5e37" + }, + { + "kind": "file", + "path": "img_3499.jpg", + "sha256": "a39d549e1ba90edad1a1300c0c541b4ae8030cb798d70bd9cacd334918a64daa" + }, + { + "kind": "file", + "path": "img_3300.jpg", + "sha256": "7b064fa8ee1f350e138e83a328b111a2d9f7d95e91edb9d350cf86d54c7ae3b4" + }, + { + "kind": "file", + "path": "img_2037.jpg", + "sha256": "5053867ffd2ddfd2baa6e8bdfea023cea1724ee5a36cf230971ff96bb5c9838b" + }, + { + "kind": "file", + "path": "img_3473.jpg", + "sha256": "b7f0d130d69cf455ae249eb1852ccee1cb7bc05c0f6fe0dd58b23c72f92740d0" + }, + { + "kind": "file", + "path": "img_1516.jpg", + "sha256": "742917778ee276bbb16e1c7ad9984a7e50afa41c1eec1bc0a583af3a69d11785" + }, + { + "kind": "file", + "path": "img_3498.jpg", + "sha256": "e1096e5447ba67d21720c16c9eba7a6b84d64f129878432b95acbbd1e0958414" + }, + { + "kind": "file", + "path": "img_4491.jpg", + "sha256": "b0a43d41aadaa5c917c53f12a330d9bad03b088e7dcfc3a9519f36951f1332fb" + }, + { + "kind": "file", + "path": "img_521.jpg", + "sha256": "cded6b0a84fd083ca3892d36be2de4da594dc3bcf29064adda5f85b1ec8b80ff" + }, + { + "kind": "file", + "path": "img_2976.jpg", + "sha256": "1320f818caadf3077db657b5fff69dd9e039f6cfdae6d85b151ea256a52e22eb" + }, + { + "kind": "file", + "path": "img_247.jpg", + "sha256": "467e909fa5ffd113a296392f7efd6df40a789143acc954ac18c848bf6a38a3b8" + }, + { + "kind": "file", + "path": "img_2962.jpg", + "sha256": "76fa769dd1221f76ef130ef830090824d6af6fd8af81e4f89661fa547f2df312" + }, + { + "kind": "file", + "path": "img_904.jpg", + "sha256": "290b34b8635d96b0e853aa0a86a773333b5270b3d8e629bab81676e844bf395b" + }, + { + "kind": "file", + "path": "img_3881.jpg", + "sha256": "bd02a1efd3ddcf7bf03c0292d1c5227c03bf9a8b4ec63009ad4c15fa7c294f31" + }, + { + "kind": "file", + "path": "img_4678.jpg", + "sha256": "6e9b5f0e5cac8b7ccc2c3f3b59152fd51ff04fa99316d8a15e3ca9557d09e4f8" + }, + { + "kind": "file", + "path": "img_1700.jpg", + "sha256": "6fcc03f54b2a20b1ef2971d76aeca6264041ad0d6b06da721d49bef9a94a46de" + }, + { + "kind": "file", + "path": "img_3103.jpg", + "sha256": "25d1dddd2ea55fb48743671f485dca1928bb76dead2e91e27de5dad535cde7a9" + }, + { + "kind": "file", + "path": "img_3665.jpg", + "sha256": "a067553a5b0c5b6086f7f86db407c9e56941aee85c8a346db02dba28c9bdf05e" + }, + { + "kind": "file", + "path": "img_2590.jpg", + "sha256": "c5e643b11372522f461b46f7ab81c5c2f75a0a611d347f60fb7c4f3963a29266" + }, + { + "kind": "file", + "path": "img_4056.jpg", + "sha256": "11e8e8176aacc973f680f3d73ff7b0d3bafaae0d7320e9675ad028bc9c4d6430" + }, + { + "kind": "file", + "path": "img_3739.jpg", + "sha256": "5e916f5a5c2e6c0a1494276536bb1ea3f7b98574d771f2c94a9f3f9f97f5547d" + }, + { + "kind": "file", + "path": "img_1648.jpg", + "sha256": "54407b3bbfa1ed328fd5d081acd56647ba157fc94ee144a841478e4778ec94d3" + }, + { + "kind": "file", + "path": "img_694.jpg", + "sha256": "9a11a4c0dcea276dcfef923a7dd2e61c4216292b0a68d63a4e9452a9e6c9adb4" + }, + { + "kind": "file", + "path": "img_3063.jpg", + "sha256": "15d7cca994d6815863c984bf778e68e416a23a12c04372e725a4cc3574b0badd" + }, + { + "kind": "file", + "path": "img_2369.jpg", + "sha256": "9e0ad15e0d61093d58e57abf4f1b468e7d01676f067d9621a97e3dcc14752f44" + }, + { + "kind": "file", + "path": "img_1106.jpg", + "sha256": "945745d5b31fa901ca1e8f32ddb0f8e4c46b8663d0e655066f3a0e388b9dd9b1" + }, + { + "kind": "file", + "path": "img_1853.jpg", + "sha256": "a2f4ecc6e7566471736928ee8dc471c75031f75667fdc53334031b1e7fc2b0ed" + }, + { + "kind": "file", + "path": "img_2396.jpg", + "sha256": "5bd5cffb2bb0d89bdcba4ff98e362f2981a821b2c8cf551cf4d6ca5fb3abcc5c" + }, + { + "kind": "file", + "path": "img_4081.jpg", + "sha256": "9dfba2925573e7e2af20032a7e4feba0a086f4b54a9c63a869bd5a00edac7cef" + }, + { + "kind": "file", + "path": "img_4917.jpg", + "sha256": "cb4e467286e24acba7a844ed5bef030dc763749ab08834efeadf024574df8251" + }, + { + "kind": "file", + "path": "img_4903.jpg", + "sha256": "dd3078d378ac1cca40a5e4f7dece71bf41f4053f1b6645fa184a6c003c13823a" + }, + { + "kind": "file", + "path": "img_3507.jpg", + "sha256": "a38ba7e7d4c9a838d2cae68ddaa5fdf5b30e0d7bef6ecc2cfb7393678c84d13e" + }, + { + "kind": "file", + "path": "img_1304.jpg", + "sha256": "c559a2dab2c0c84c3616637868ed0f0ea538d745365cbaccb0260e1769be9139" + }, + { + "kind": "file", + "path": "img_469.jpg", + "sha256": "1aaa1a062f145f00c105ff680fbc423546092eca2794a9f701045a7c19b38290" + }, + { + "kind": "file", + "path": "img_2180.jpg", + "sha256": "b8650c6f403e0f4d05524fab425defc20dc96ef33a8b1f05efc7b61230b985f5" + }, + { + "kind": "file", + "path": "img_4283.jpg", + "sha256": "0ee74a4ca9e3afc1b46e0af6e4ffbf2a64542469830c0925f45123f85347e5ee" + }, + { + "kind": "file", + "path": "img_2194.jpg", + "sha256": "1edcf7438f828024af551e2690c4760ba341de70cfb60d5a48615ea585622b9a" + }, + { + "kind": "file", + "path": "img_443.jpg", + "sha256": "27aa13cbe6b948b61acd0c7fb639ee52a12706d3c9a426911795751da6b37597" + }, + { + "kind": "file", + "path": "img_325.jpg", + "sha256": "0c084ace7d462e9aee84ba72e291b034d21bd69865b36d225c0267bc16abbf26" + }, + { + "kind": "file", + "path": "img_2196.jpg", + "sha256": "d798222a7c00e41a84b4f41dcc01f5e4d7ad8bdc38cd2c3a57600a4d5d9e8284" + }, + { + "kind": "file", + "path": "img_4281.jpg", + "sha256": "60ff33db5e12aa79afdc5f86c48b38aad83ab3701e5d452399d5d09a3c5ba81d" + }, + { + "kind": "file", + "path": "img_480.jpg", + "sha256": "e86c675e1dc091d034402349cbf7ec0e2e6b222cd82dc16007fe5062eb51191c" + }, + { + "kind": "file", + "path": "img_20.jpg", + "sha256": "ee7492feccfd842f310105abf08d72616505d7195a3aad506ef3affa61988fb5" + }, + { + "kind": "file", + "path": "img_899.jpg", + "sha256": "23133bc88a6238af3412062c4ab3a51fc92762205d0a384dff4f5b63ccb041d1" + }, + { + "kind": "file", + "path": "img_1851.jpg", + "sha256": "1d77c406de4c6c50fd19df8c1a51bc9d7ac91a00aee6727b7ec56eabb4a48bb9" + }, + { + "kind": "file", + "path": "img_3934.jpg", + "sha256": "7d97ef3092c177d6f48782fa0087b391c354a656ee6c476ba87b028ac2a26675" + }, + { + "kind": "file", + "path": "img_1845.jpg", + "sha256": "b7f02efe2c56589e348c3a894397286cc9b23753401e2719c24d4dede4c72c49" + }, + { + "kind": "file", + "path": "img_2425.jpg", + "sha256": "36507550574f37181c4579bdaea8b94d06519a9c2983331569329849bd5898b9" + }, + { + "kind": "file", + "path": "img_866.jpg", + "sha256": "7a6759f9b06bf9a04b4042e1fc4b658775dd7de38f10154fd19016f26caf54d3" + }, + { + "kind": "file", + "path": "img_4861.jpg", + "sha256": "cc6e0fc01afa9cd13be92a6d05e2dbf65f3fd8ee065dffc2fd9cbdab7ed1e014" + }, + { + "kind": "file", + "path": "img_3868.jpg", + "sha256": "fd544bfdafeb41de8d78c08919c4dde8776bf8060162aaf249d1bc86dc057b1c" + }, + { + "kind": "file", + "path": "img_1925.jpg", + "sha256": "62a68a7b2db478bd300dc7da7ce1636c87f07b841627025fad3d8d3492dc8132" + }, + { + "kind": "file", + "path": "img_3854.jpg", + "sha256": "c8a4eb7eeb0200be0651265a6495046c1def858be7d856dd2d6e99575c627e93" + }, + { + "kind": "file", + "path": "img_4691.jpg", + "sha256": "0b7c449d0b4d54c19d70f769264ec63a65a45efd8057f519b09101e516227c18" + }, + { + "kind": "file", + "path": "img_1702.jpg", + "sha256": "07d995b94bb10898b644f13c7ce2b3ed21f70e800c2009bf01bf4391ec4138c2" + }, + { + "kind": "file", + "path": "img_3673.jpg", + "sha256": "625ac2df8553c7c3b1bec9c5e62d47e474c0381c5f2c5b9b19b7156d28560755" + }, + { + "kind": "file", + "path": "img_1064.jpg", + "sha256": "7e08867f9a90d3494158db876deb9f72604ea42c7f1819f602948a82cbd361b3" + }, + { + "kind": "file", + "path": "img_3667.jpg", + "sha256": "9eac3068be721556f0436a9f6cd2e28a344e4f7bd0fa0bed4c9ebc48bb8481bd" + }, + { + "kind": "file", + "path": "img_3101.jpg", + "sha256": "f398c80065ebfef7c899270017988755e6f37a3252d984df02dd3bff77b097c7" + }, + { + "kind": "file", + "path": "img_4646.jpg", + "sha256": "32f14358fd93f9ebcdd82790f02a68615e5a6eaa3b0cec1b3ec2ba93d3a1311a" + }, + { + "kind": "file", + "path": "img_2551.jpg", + "sha256": "870ac7231b8a7680c61721b6d288fe209bf2a891a4f75bfef3f6e3c6a602eab1" + }, + { + "kind": "file", + "path": "img_3883.jpg", + "sha256": "daf9d1093d76229421b6f240f6c0e43cf3ba61520b04fd9c0d461280a96ede9b" + }, + { + "kind": "file", + "path": "img_4487.jpg", + "sha256": "877d6fc2d2958cdc30df8a885ac424494d3520e8bf10ff073e8e707c916579f5" + }, + { + "kind": "file", + "path": "img_1500.jpg", + "sha256": "d2d1563213615f8bbb851cddc32d35ac42c8a95acb51bc7cc07918954dc5ca9c" + }, + { + "kind": "file", + "path": "img_1272.jpg", + "sha256": "8c32c35e9db3211ea48f9f20cabc27372e0d05b4cd2da54dc03840dfd1b076c5" + }, + { + "kind": "file", + "path": "img_4322.jpg", + "sha256": "8a243a65a97f1af1ff9d318cc93226ab98bbfb8ed5328690cdf6f569fec9094a" + }, + { + "kind": "file", + "path": "img_1529.jpg", + "sha256": "9740fc3865030b8043d88c871b8b438cf75d94ff6bc669b5b70ce089011e75ff" + }, + { + "kind": "file", + "path": "img_2020.jpg", + "sha256": "6e4b49f89a7ea226ebf73694249bc93d24f97464bf3932fbc44d27509dd004c6" + }, + { + "kind": "file", + "path": "img_4337.jpg", + "sha256": "dd0c9047a5e441b552a5a8e12ef760c188ba30a3ecb38ab6c9d9320233fec4e9" + }, + { + "kind": "file", + "path": "img_2008.jpg", + "sha256": "86a38f7ba54ef20e2fe639fdcb974363d55733cba088173f9c231d177bfaaab8" + }, + { + "kind": "file", + "path": "img_250.jpg", + "sha256": "68ddc94c26c9bc4d9d73322ee8ab7d4167147e5085dd67be130ea2adf33ed1bf" + }, + { + "kind": "file", + "path": "img_244.jpg", + "sha256": "482c8f1afbbad0199ef84cdbb540a83c135f95b36a094be12f81e232359e1c20" + }, + { + "kind": "file", + "path": "img_522.jpg", + "sha256": "30c5c0a8a967e764d827c898663e6273ef58f25756f62ba8962c0da38342c636" + }, + { + "kind": "file", + "path": "img_4135.jpg", + "sha256": "aa8d0ae3093b59b5685e571b1037334875c56363d455e60c61e6c2b5dfbae6a7" + }, + { + "kind": "file", + "path": "img_913.jpg", + "sha256": "7df2867b547feca015137bd2ddddfeedc58669ab1af5eee176f8db5f4b3290dc" + }, + { + "kind": "file", + "path": "img_4653.jpg", + "sha256": "d21b571003d7d4d4264e8044da1a95d44f00ba047b4c4d11eb9d599e8696ac1b" + }, + { + "kind": "file", + "path": "img_907.jpg", + "sha256": "f8f21f103de3b9b8c7808dd6cb430e27b5d158b0525824482fe1d8cff4985931" + }, + { + "kind": "file", + "path": "img_3100.jpg", + "sha256": "06b8f6380c492e56d48a46f066e64b85c21692d3344614073d269de1c79b2eb7" + }, + { + "kind": "file", + "path": "img_4874.jpg", + "sha256": "babbb05578086b8fb23c05cd08ee6c8d44e01d05519497f869604f46badd6bbb" + }, + { + "kind": "file", + "path": "img_4733.jpg", + "sha256": "ceea55de182fa34515b8f615bdf9dcb54b264097062b0d7d5ce8b5918e28f484" + }, + { + "kind": "file", + "path": "img_2342.jpg", + "sha256": "c2004fa99aecb2d9798a7ed6c7ef3c6ea9e258ce2dc9291abe789713c024fa75" + }, + { + "kind": "file", + "path": "img_4055.jpg", + "sha256": "62beacea482b33062389cedce2bb0fa1d194f87a05890c24457aef93a2e5c852" + }, + { + "kind": "file", + "path": "img_1663.jpg", + "sha256": "9d1258a9c6699f35094c4fefdb5f984bde5b69f7302e8eaaa67e9f0ba25005c8" + }, + { + "kind": "file", + "path": "img_3074.jpg", + "sha256": "bdb02298099231ab4c36aeee3c4f5740e93660e028bfd0c38cf2298f793a22f4" + }, + { + "kind": "file", + "path": "img_3706.jpg", + "sha256": "91c3e92c41d0d6be7241a836e34b0f6d387bbb60f747a1e67e3f068a4d1a0081" + }, + { + "kind": "file", + "path": "img_3935.jpg", + "sha256": "7803a774cfdc36a50a26ed234bbc52f27d7efe4c5930756d2454691e62395408" + }, + { + "kind": "file", + "path": "img_2395.jpg", + "sha256": "1e0c5c5825272f356d58158600e6bd54727b522add1022fbe22c2741f810754c" + }, + { + "kind": "file", + "path": "img_3909.jpg", + "sha256": "838cfd52997a75940c90ebb61befec6c8f1e91ead9dba34b4f883d17bb1388b4" + }, + { + "kind": "file", + "path": "img_898.jpg", + "sha256": "a46722bceccb8561eca47f3057892ba4e7c09255447f0cad40249eea3b75819f" + }, + { + "kind": "file", + "path": "img_2632.jpg", + "sha256": "f1a799773fcb0d317fa98c9b5e98d6a689c515cd72593f427567bfa42963ae31" + }, + { + "kind": "file", + "path": "img_2626.jpg", + "sha256": "c9953157887a8a8df57a31fe6a91ecb8581b0f775cf7e335bd6dfb56a4a40f10" + }, + { + "kind": "file", + "path": "img_1449.jpg", + "sha256": "032f408c985c0490757f51c113237f2c54b0a3f8c7e33275494abdf5a6d0f97f" + }, + { + "kind": "file", + "path": "img_4519.jpg", + "sha256": "ab309b06f5849b636aafffde9c42a50d16db82cd07f2d577b57dc99af94abeda" + }, + { + "kind": "file", + "path": "img_456.jpg", + "sha256": "aadb30a739ccfffba49b99c5027da441ad135d3de938f5b0937c44a6c061220d" + } + ] + }, + { + "kind": "file", + "path": "test.json", + "sha256": "349be99702a174c694f1c85f75a6df16717fb7079e99b6ad000a01ddbbb9be96" + }, + { + "kind": "file", + "path": "train.json", + "sha256": "e671519b630179f715ea40ea91f9408b04481173bb10165b4fbf1c9a64643c34" + }, + { + "kind": "directory", + "path": "train", + "files": [ + { + "kind": "file", + "path": "img_329.jpg", + "sha256": "faf2677f3ca705e774e8be35fad06c715c748f9b6c0ecc2ab1d008a2be27f6ea" + }, + { + "kind": "file", + "path": "img_2818.jpg", + "sha256": "147de0cc73bda02652f384120dd7b03fffba53c5bdf8c2eb453fa373ba45abd4" + }, + { + "kind": "file", + "path": "img_473.jpg", + "sha256": "8f5d790ddfc77724119ce7deebcf2fbe0234ac677fca5bd0876ee3cd3e67a8f3" + }, + { + "kind": "file", + "path": "img_315.jpg", + "sha256": "833a5b99daa3783af4e22f934be65476621069129a685a28a727360f2bdccf26" + }, + { + "kind": "file", + "path": "img_2830.jpg", + "sha256": "c43dd9ffc2ec3d929923590884eac2670c6261468402fd43134b4c9b9966418c" + }, + { + "kind": "file", + "path": "img_4299.jpg", + "sha256": "8235f77d8ad5957c1d4e281441c6dc51152c07e66f6cd6ca292f28d0c97322b1" + }, + { + "kind": "file", + "path": "img_3290.jpg", + "sha256": "5183f3cf8f79f497d8034b54bd06377cd22e1fb99666ffaa2df0ef7903386b5a" + }, + { + "kind": "file", + "path": "img_467.jpg", + "sha256": "648db9e75c5b66561a4d3a0a381a3bfcc514bdeb7c31ec14bb10ee4971141630" + }, + { + "kind": "file", + "path": "img_4514.jpg", + "sha256": "5fdd25c2134efcc725276b4cf3a2253762c76b8960499bed63ae5c2392de835e" + }, + { + "kind": "file", + "path": "img_2165.jpg", + "sha256": "7fd1aa10326bbacf85b4f7944ec00a5357753906d4689489ca3211dd5f2f6462" + }, + { + "kind": "file", + "path": "img_10.jpg", + "sha256": "37753610e7de2b2f94804d2d7c3bdf9857b5d27808b1115d03c6cf2bbb12ec76" + }, + { + "kind": "file", + "path": "img_2603.jpg", + "sha256": "ae576a2e5783ac5b30aabd54c83fe39322ac6dba1487a86f174337ad73f53e86" + }, + { + "kind": "file", + "path": "img_4272.jpg", + "sha256": "3662d5e3ccce138585b18daef2c465026aeaf3304c95ba5d1971b047cdb0bbe9" + }, + { + "kind": "file", + "path": "img_2617.jpg", + "sha256": "ff4023348d1d786678d27e4a346cf08649be6f02cde92d811d61de05de33589f" + }, + { + "kind": "file", + "path": "img_3509.jpg", + "sha256": "dda7f0c92e80a8cacb494c82c74b5571b9b8f70228d378b3f6660ed7f69c9a0d" + }, + { + "kind": "file", + "path": "img_4266.jpg", + "sha256": "b6a3ad708c16aca606c62aeb1fa516e4e52eb927dce487ca8a9e0f8eeb4398df" + }, + { + "kind": "file", + "path": "img_4500.jpg", + "sha256": "fa88a93e77a75a2d48fe5bdcdcae774353a2b49f5a6644847b54b1a5d1fb2add" + }, + { + "kind": "file", + "path": "img_498.jpg", + "sha256": "31865cf24d1364700e04d691b6f0e7eb6f89f97525a4c73fcb2f2a810f48928f" + }, + { + "kind": "file", + "path": "img_2171.jpg", + "sha256": "38df83d28e64d4cedf6fed01287cc96da36987b7c5d6d52439b707bb0fe41466" + }, + { + "kind": "file", + "path": "img_1450.jpg", + "sha256": "0cf6efe3bc573728432e75df9dc112aa8fd4b360edfeb7eb17d8ae9da5e39102" + }, + { + "kind": "file", + "path": "img_3247.jpg", + "sha256": "58aefc984bdc53118b4964525a94383a9451f9096e173d0dcfe4b08cfccbc45c" + }, + { + "kind": "file", + "path": "img_2159.jpg", + "sha256": "5866768337aaf0710cee68af0e7be0595fb4b03e63d24de12ba51dcda6867abb" + }, + { + "kind": "file", + "path": "img_3521.jpg", + "sha256": "799b8065e022f598b23bd109bf1d527075dae2701c65c058745bae934fc7477f" + }, + { + "kind": "file", + "path": "img_1336.jpg", + "sha256": "fdbd397abb325d488b51ffda974441d4077d6012a0859cd9b9cd3f4ff86625c9" + }, + { + "kind": "file", + "path": "img_1322.jpg", + "sha256": "1c20a5183dac804f115bd6b9bcf1d2e912520c8de6d53b572fc83a35b2e00c64" + }, + { + "kind": "file", + "path": "img_3535.jpg", + "sha256": "60d02cba1bbf39082db1df86afb2177c912337b59f18d804b85ead182345834e" + }, + { + "kind": "file", + "path": "img_38.jpg", + "sha256": "94c2caef6eccc76bacf9482ea4419b2be8e5d6fdcbaafe5fdab72bdae17253f5" + }, + { + "kind": "file", + "path": "img_1444.jpg", + "sha256": "06b7fb209a45d05e2fd1c8787ca852e69291db31a1be7f0d3d307acc99d03999" + }, + { + "kind": "file", + "path": "img_895.jpg", + "sha256": "502b5c7d9487a07085e42f26e633ec6c27703c8e37f49a2b25ef00be250880bb" + }, + { + "kind": "file", + "path": "img_1875.jpg", + "sha256": "f0f365475e28d9b40049384afe9cc70943e267d4310932b12bd3ad97ea9d64c0" + }, + { + "kind": "file", + "path": "img_1861.jpg", + "sha256": "031aef53dc87411225157370ce5cc56439513fa5a267eb50340a47aa798fc8a2" + }, + { + "kind": "file", + "path": "img_659.jpg", + "sha256": "bcec276b5dbe336659ec5153fc6fce47823ff02ba29a7e6a81b1f67a286224b8" + }, + { + "kind": "file", + "path": "img_881.jpg", + "sha256": "e2118cd781a5e5f1bccad7274a82d551178fa2bdc26c4c1c3ffec2f56289ecad" + }, + { + "kind": "file", + "path": "img_4919.jpg", + "sha256": "61d931a4f6f62f28564a901e23443cd71f0e73c8ce92f3df33623c8051fc28a7" + }, + { + "kind": "file", + "path": "img_3938.jpg", + "sha256": "215244ec3edea11447df2e60768b0639e210ef985bea119424318f6da26d739f" + }, + { + "kind": "file", + "path": "img_117.jpg", + "sha256": "e6a8da41fd6d052c7088dbfc2f2e449930c6ec9bfb76459e0e38ed67602c22a4" + }, + { + "kind": "file", + "path": "img_1849.jpg", + "sha256": "3833f2cef2cf004282a268219fd45681783ab79d106c26a010badae23bf84c82" + }, + { + "kind": "file", + "path": "img_671.jpg", + "sha256": "b9bb2882c696fd055808c627cf487562e4fb389224f76ecd38a799761f898489" + }, + { + "kind": "file", + "path": "img_4931.jpg", + "sha256": "6b42880a7ae0e2d572feed1391031552c26553e85c2a696faf0f38c8820dab8c" + }, + { + "kind": "file", + "path": "img_2398.jpg", + "sha256": "b37bb30ce50350b5e3b0367b764440787ed0e2c6ee54c3dfdc847d2ae17bf611" + }, + { + "kind": "file", + "path": "img_665.jpg", + "sha256": "3cef877bbfae0b3bc48f9a7a5f71964e358855b1133c5f7ef7ff74aae738d2f4" + }, + { + "kind": "file", + "path": "img_3092.jpg", + "sha256": "fc9a13e1f7acc2ecc8d8c1f29b2fb45adedb77246b4a29cae68d9b13185b065d" + }, + { + "kind": "file", + "path": "img_4925.jpg", + "sha256": "f05095c5a3db98c9eacbde006c41766f315978b9df4f85bf494747e22ac02142" + }, + { + "kind": "file", + "path": "img_2401.jpg", + "sha256": "9f5bfd1078e4e562f8d96591d3b113dc5de90aeddbecb009f0b1dd7b9e52305b" + }, + { + "kind": "file", + "path": "img_1108.jpg", + "sha256": "54e8b4bc45b93cce37ced8af5054af1db9299300e3f7ff88071101d91d525efb" + }, + { + "kind": "file", + "path": "img_2367.jpg", + "sha256": "efe025c8929e5159feb0ac348346d8cb3261fd588c5450536bba5cfd4eec8aa6" + }, + { + "kind": "file", + "path": "img_4716.jpg", + "sha256": "e38d69a41f25f01591d49f766bf3cd3693fcc567539af226655716bd8b8dadc7" + }, + { + "kind": "file", + "path": "img_842.jpg", + "sha256": "6f81be0b8b63dc529e732f24e082f63004f3d57690778311ac15921a0d579235" + }, + { + "kind": "file", + "path": "img_2373.jpg", + "sha256": "5ebfcb354b6cdbf0b1995d556e3e9c022cea2d456db37df39b55df575deb030b" + }, + { + "kind": "file", + "path": "img_4702.jpg", + "sha256": "ca83d63a40c710603abe20065c187f9d1c500e185b10039358c8875326f4784c" + }, + { + "kind": "file", + "path": "img_4064.jpg", + "sha256": "b69b6579f8996b8eb037dd9f061c421ccaac2f5fcc2196fb0732271a5b22ba79" + }, + { + "kind": "file", + "path": "img_2415.jpg", + "sha256": "99c2537df205455a64c5ac97c680127f269f746c7b91b080062dbdb7c0626b17" + }, + { + "kind": "file", + "path": "img_1134.jpg", + "sha256": "7cae3a375e63d400a0432deb19e8d3321f7185b9bb53764ffdf14f8e88e82554" + }, + { + "kind": "file", + "path": "img_3723.jpg", + "sha256": "ed263943cb07cfdf73a60253c6445229de7c2d3e1bc004321b2e0a5f5307ebcf" + }, + { + "kind": "file", + "path": "img_3045.jpg", + "sha256": "717884dd471f52e0bef5daef2af3c454939863250e317018b2e96dbc82ac0986" + }, + { + "kind": "file", + "path": "img_1646.jpg", + "sha256": "b34f3184b761aec50448606a4deb32100de0844e0489a3c43f379ccccd4f54c2" + }, + { + "kind": "file", + "path": "img_3051.jpg", + "sha256": "0dae6d3b35bfecc5b06c970ba7a0dffde1850e9a29f30a3cfe2a74b8de141db1" + }, + { + "kind": "file", + "path": "img_2429.jpg", + "sha256": "48cf8d0e941dca31e71445b6728f6f43500a6305b1b7254bf0f060d3354c072d" + }, + { + "kind": "file", + "path": "img_1120.jpg", + "sha256": "e9628f076c05916077148c6b3fc117cc664d139bde92b329251ba45e892ea485" + }, + { + "kind": "file", + "path": "img_3870.jpg", + "sha256": "0101c3ceb83afbc614e871a9450e8e53db31ac65a01c55a1335e1ca300315e35" + }, + { + "kind": "file", + "path": "img_4879.jpg", + "sha256": "0ff38a10e89118c52704ed0bedb6ac485381af3e6db9ee68e260b5f0e3e9d347" + }, + { + "kind": "file", + "path": "img_739.jpg", + "sha256": "cb5211aeeba8a0facb8d7f6b3169c0bc8dec0ac1c095c07bf1654e4686d26bbb" + }, + { + "kind": "file", + "path": "img_1901.jpg", + "sha256": "fe57bba6d9b6481bae473163cb6e0c70dc34f104b3d2233770ab140de474478d" + }, + { + "kind": "file", + "path": "img_1915.jpg", + "sha256": "c36d7d84aa724698ba30c3aaccce6e33ee547ca323131fbf2c983949ac1462a5" + }, + { + "kind": "file", + "path": "img_3864.jpg", + "sha256": "289264fd7dc4665a59eb6f0cde7f3219e5a19db709f1bb67ecd525c64d701763" + }, + { + "kind": "file", + "path": "img_3694.jpg", + "sha256": "f9f66ae698c45c5459bb55d81e2d186cdc024b4eb1151d723ec4c12bbd4508e1" + }, + { + "kind": "file", + "path": "img_1083.jpg", + "sha256": "42cc563056a06033649caa65f96cdb6a5f5cdd2e67de13e42412e3de026f2d43" + }, + { + "kind": "file", + "path": "img_4845.jpg", + "sha256": "d7322d83f5296908284e3a76886962d301a2ab02d0789c31a766d2602c657d6e" + }, + { + "kind": "file", + "path": "img_705.jpg", + "sha256": "2ce6c4dd6864fb43c71f4dc567919f6553740bce5c4b44bf9f7d306147e1d1e1" + }, + { + "kind": "file", + "path": "img_4851.jpg", + "sha256": "6025b29f814c0d366751734ff13b76e981c76270e4236cd36ac2ae27215c2fe9" + }, + { + "kind": "file", + "path": "img_711.jpg", + "sha256": "b73c4281fbc6b2fbaf3e3b02cae485b276eb9c12e452f66520affa249859cce4" + }, + { + "kind": "file", + "path": "img_1929.jpg", + "sha256": "a83e943d21721a14956ed735e34f5b62cfc651a4b600e8f28f6d4e1740a61e0b" + }, + { + "kind": "file", + "path": "img_3680.jpg", + "sha256": "dc4c109f0bd924ad0a26b41f3d9c4c6b8af39f90a955373c88316f93b9266527" + }, + { + "kind": "file", + "path": "img_3858.jpg", + "sha256": "74eadfc00113e020d6f3a88091dfb8a6a6311e36effe515e36bb1db2e94e4972" + }, + { + "kind": "file", + "path": "img_2575.jpg", + "sha256": "4e1c815efb824b86c6bdd9d82e138ff27d1c21099d0ad9feb6d85808410396ae" + }, + { + "kind": "file", + "path": "img_4104.jpg", + "sha256": "5402f7744eb473af6896ab03fa470b3cca449d9fa074a0e461e31dab0157433e" + }, + { + "kind": "file", + "path": "img_4662.jpg", + "sha256": "9f2dd407d3ca096cd993c00f0dcc20bfdda106c857d0fc964cdd5850df8139f3" + }, + { + "kind": "file", + "path": "img_2213.jpg", + "sha256": "20a8bed36861982b1c6d8cd8b440a361269a253af7bdf0a3ff063d23615a0031" + }, + { + "kind": "file", + "path": "img_922.jpg", + "sha256": "a7d8f2db5ae23ee0e5cf4ada04aa6b2a433f858a52a1909a1fde66965a39a490" + }, + { + "kind": "file", + "path": "img_4676.jpg", + "sha256": "1633bd5afa0871cf044b2817337a926faf9d49b29987c48a4ff96502bbd7bf51" + }, + { + "kind": "file", + "path": "img_2207.jpg", + "sha256": "9ecaa8fc28989d1c13738dd190503e673cab2f6f8da830dcfd8bbb240d675590" + }, + { + "kind": "file", + "path": "img_936.jpg", + "sha256": "ce89ceb2149270cc58517655a98a0dcdd52e12cff298aaaff13ad2437ccc9f55" + }, + { + "kind": "file", + "path": "img_1068.jpg", + "sha256": "764ba2aa359c5b33e5c56b233e107693f209483994d24cf9a59752ef59fa65d9" + }, + { + "kind": "file", + "path": "img_2561.jpg", + "sha256": "3379fefd6e0c35c9dfcd1a38dde91193df41a4a48335a6d1657060c325d6c1b6" + }, + { + "kind": "file", + "path": "img_4110.jpg", + "sha256": "bc2e5f4d064928d327d5f08cfc6120c52c2f3986d933aaf35ce3d2700622860a" + }, + { + "kind": "file", + "path": "img_1040.jpg", + "sha256": "452cfab645fe3bed073a887c699bcb140b8a7e075df5d56f034c12bb7747684e" + }, + { + "kind": "file", + "path": "img_2549.jpg", + "sha256": "6e3ab91a90bdc11060c945f18c1ec9b481d7e7578cb361366675baa724f7eb08" + }, + { + "kind": "file", + "path": "img_3657.jpg", + "sha256": "311ba44b0a5d04ae9505c6d3c402fb010106068a289db8f4af82b74fcb0a53a1" + }, + { + "kind": "file", + "path": "img_4138.jpg", + "sha256": "1e6255266488178b53d15c7f51b14b0b8e3c67fb8dc8c69954774133748c9df4" + }, + { + "kind": "file", + "path": "img_3131.jpg", + "sha256": "4a1b4061a58f6d2a0d6e3cdb947dc4752090edad47da0b8ce14ae86835bde4c0" + }, + { + "kind": "file", + "path": "img_4886.jpg", + "sha256": "7873067f650aa2c70afb42d2c74b1a483187c7597645e8abb539e11b3ca95ad3" + }, + { + "kind": "file", + "path": "img_1726.jpg", + "sha256": "e69a57f1651af30686947db372bb9e02a60e53db3e65c1bab4a6e8d74e5d600f" + }, + { + "kind": "file", + "path": "img_1732.jpg", + "sha256": "2a556c0803e0f5bff9d590c2725062ab879dc457e26b1da25d1a8394d3f0009a" + }, + { + "kind": "file", + "path": "img_3125.jpg", + "sha256": "950035c4fba0cd968fe0b219d2403c5866876df9eee18387b4a0061ea85b9a81" + }, + { + "kind": "file", + "path": "img_4892.jpg", + "sha256": "b9a8f279b3d2941c44c3e876a5151af8914e55dfcd59f25e3725d9d9d821b455" + }, + { + "kind": "file", + "path": "img_3643.jpg", + "sha256": "07be77915cc0e9edb68c0aa74eeec2fe351d2a7002cfcb99b7a071274758990c" + }, + { + "kind": "file", + "path": "img_1054.jpg", + "sha256": "bb113a362d7fd5c426daae6f97185cc8f358f582d0b4363179ba2f0e9d90cda5" + }, + { + "kind": "file", + "path": "img_2978.jpg", + "sha256": "392392581a82eee1581fd2e44663123c2e2e52d5a8eb4b3716f2fffb96e9b87b" + }, + { + "kind": "file", + "path": "img_249.jpg", + "sha256": "f97683a401349d266ccffe0a97b58792d1b914e07003556ba6a33325161f8bbf" + }, + { + "kind": "file", + "path": "img_507.jpg", + "sha256": "4278d774368c7489e0d00d1577f3623f1acfc9fe120b1cf3adeb97438b6523aa" + }, + { + "kind": "file", + "path": "img_1281.jpg", + "sha256": "06f5a228fb366495e2a94551452ac455ce8ffcf7479a65adccc52bebadf594e5" + }, + { + "kind": "file", + "path": "img_2788.jpg", + "sha256": "1280e0252f6b3b5dfeb7d6d987b6c4ee62f6547f41769c9118447928c214a802" + }, + { + "kind": "file", + "path": "img_3496.jpg", + "sha256": "4af35a9254bc0081e16239a044c475effc3ed6e95ce46d4e3d4806e7e8a916ca" + }, + { + "kind": "file", + "path": "img_261.jpg", + "sha256": "6c3e1024fd6d10a036f195b3f3e6ad687f41614bb7631438dbd9c749716e2cb0" + }, + { + "kind": "file", + "path": "img_2944.jpg", + "sha256": "6268ec316ba18309457d431511e3ab442ae22ef463b2fff57eb61cd0feda2236" + }, + { + "kind": "file", + "path": "img_3482.jpg", + "sha256": "d325b846b0abdef08942ba91505f354fc468d8ec445547caf7532ba2c792672e" + }, + { + "kind": "file", + "path": "img_275.jpg", + "sha256": "8378b2e2ba305fd62f4c05a8fcf177535207d97f766e9d87f3bc15f0d1616ac6" + }, + { + "kind": "file", + "path": "img_1295.jpg", + "sha256": "17983dafddb179e1221cdad559aeb7e5a1358d6ea6264ac3e479c2c3bcf378ff" + }, + { + "kind": "file", + "path": "img_513.jpg", + "sha256": "69a99b115da8f380b9cd70ab059eb642a963a42cd1008c89676683ae34eeee54" + }, + { + "kind": "file", + "path": "img_2011.jpg", + "sha256": "7a221220a66da14db41fba0c97a4ab44c6c7cd11190a8be5bc69fdcc910b18d5" + }, + { + "kind": "file", + "path": "img_4460.jpg", + "sha256": "06956496968db302950fce6fcab844e8cdc362654e557f997878cc817322d7a1" + }, + { + "kind": "file", + "path": "img_3469.jpg", + "sha256": "27666677b2bd25ff926c64b5d0fd39d09c45c678f212c6851c9eeee10b4a8b59" + }, + { + "kind": "file", + "path": "img_2777.jpg", + "sha256": "d0bc8d31957319a455e349d9321ece033734f3f69169e68c6b95b8929d5db80a" + }, + { + "kind": "file", + "path": "img_4312.jpg", + "sha256": "4aa68461d8265f0c119ff5d15dbd4b2d849d8acb78665f2c51d8093d4686c152" + }, + { + "kind": "file", + "path": "img_4474.jpg", + "sha256": "3997d5c76291a4c67077c68e87ee504ea8a1ac8618aa6f19ea1412967479a089" + }, + { + "kind": "file", + "path": "img_1524.jpg", + "sha256": "74230bdc5ed0d036d2cf96d0932cae53eb5a5eb3abd43fbff4a1eb165de77c0a" + }, + { + "kind": "file", + "path": "img_3455.jpg", + "sha256": "b4ab7cbe8338f5d86e0c60b25826151a80fc952c51c5ad3b9db83f7741b4fb41" + }, + { + "kind": "file", + "path": "img_2987.jpg", + "sha256": "8bc89a8b3e864be63079bc2239de154d67d107771779caba00ab9c3004eb3e76" + }, + { + "kind": "file", + "path": "img_2039.jpg", + "sha256": "81efc07ff89de7f86bc3d3e61906c81900c61951d36a499ef8bb3ab4821ade69" + }, + { + "kind": "file", + "path": "img_4448.jpg", + "sha256": "78674cee7af3836a2f57e1001b4fe208f31956e3ab0895781b73796da111c5a3" + }, + { + "kind": "file", + "path": "img_3440.jpg", + "sha256": "f9d54b384a7c6e95b71a44b08808cbe3ae0d6c08ff676deb321d2819091f3df6" + }, + { + "kind": "file", + "path": "img_1531.jpg", + "sha256": "222833d8a764848211c7d0c265a4ee3f3d33c08cbc25f500f27cfa7d07118549" + }, + { + "kind": "file", + "path": "img_4449.jpg", + "sha256": "a3f4de77b281467a865106a00d10c21975e9cc62d80f5c37f0d378c1bb8da4d0" + }, + { + "kind": "file", + "path": "img_3326.jpg", + "sha256": "d0a5239663a9d62909073360cd094e5a944a0e1239f7ff826b1ae46573a505f5" + }, + { + "kind": "file", + "path": "img_2038.jpg", + "sha256": "2d3aa36d009c53c11980aa1c69f0d27a1516f983ae5521794de116f870de674b" + }, + { + "kind": "file", + "path": "img_3332.jpg", + "sha256": "bfb1237547a47095cde3a345ae3ff99edbce93d2581de5b80096ac6f9137a6b4" + }, + { + "kind": "file", + "path": "img_1525.jpg", + "sha256": "77c6fd5142c882098a6e85e2c39d07bebb5c0c995a59e77369167cecb14b9d33" + }, + { + "kind": "file", + "path": "img_1243.jpg", + "sha256": "a2072df95c9d7b2bf2513d4921d810de685d19640288bf57876795775bba13c3" + }, + { + "kind": "file", + "path": "img_3454.jpg", + "sha256": "1071556ed77c93222a6b99147e6df1b690f40042c2bc8d3df8232487770d324b" + }, + { + "kind": "file", + "path": "img_2992.jpg", + "sha256": "1bfce4e017bb9d60236edb125623286b7629bc7d066033131d23ab9cf1e526a9" + }, + { + "kind": "file", + "path": "img_4313.jpg", + "sha256": "546c3214882cf3887c074b413d7a0d5b6f6b532582bd554bae3983eea1db890a" + }, + { + "kind": "file", + "path": "img_1519.jpg", + "sha256": "ba2daea1670d6e1b2e311b0cbce0a85a45abf05f4f7ccf1003ab1ad86c15237a" + }, + { + "kind": "file", + "path": "img_4461.jpg", + "sha256": "d8de46e2b815256f83e168e3beb358044f9ceaafa828f9d9233b97a81fdce2fe" + }, + { + "kind": "file", + "path": "img_2010.jpg", + "sha256": "047911d691889dfb91496f12cc03f28e478edcaf6bfaa4636eb490abdfd98513" + }, + { + "kind": "file", + "path": "img_2776.jpg", + "sha256": "2eff8afebbdad55599408b69798288e6abe8ad41b38d3397f136de0ffd0cec9a" + }, + { + "kind": "file", + "path": "img_3468.jpg", + "sha256": "621d0e7b7b9813245f731b1d8b47e13cbd2512ed98bf2ffd07c3a77aadbbff4b" + }, + { + "kind": "file", + "path": "img_274.jpg", + "sha256": "525a43bf806a823d311b211b09a6d94159dd0b49b2227d0d79ec4803fb1ef2fc" + }, + { + "kind": "file", + "path": "img_3483.jpg", + "sha256": "35b2e46703fd1741d7e7cbc7671a6056e3849b569f1a0da06ade3557e66eecc7" + }, + { + "kind": "file", + "path": "img_2945.jpg", + "sha256": "d9302cfcd8098888d7653be4fa3c8a4aaa82d2336150ba6ba4ccf44a3d5cec00" + }, + { + "kind": "file", + "path": "img_512.jpg", + "sha256": "f8ef54d87f0fc8cb7b81afea7c0adf6c6425833414a52010c853b072c3922b56" + }, + { + "kind": "file", + "path": "img_506.jpg", + "sha256": "f4b76a0f5e9851fa13e098bfcea88cf956d788f353c7e5ca1d9c21b4b6876b82" + }, + { + "kind": "file", + "path": "img_260.jpg", + "sha256": "95ab9003076ca633d0328013bdffe68b9b1d6f435556a5b1c72b60402f295b0f" + }, + { + "kind": "file", + "path": "img_3497.jpg", + "sha256": "6fc3dd3aa6b071016118f4301b6039a94583c5d2514d672825fa8af7db93a312" + }, + { + "kind": "file", + "path": "img_2951.jpg", + "sha256": "d57b2a50059544432580e79eb7907fb66e5de13112c57762d891774c1d9c92bb" + }, + { + "kind": "file", + "path": "img_2789.jpg", + "sha256": "230dad027ef96d422bd8bcf27a137512de433d93e0c86b0ff216bf7ddcb1d62a" + }, + { + "kind": "file", + "path": "img_248.jpg", + "sha256": "689a32ef6aab5106cbe4a5890dfec2988fac6c2df5f623c1d724707bd38cb18f" + }, + { + "kind": "file", + "path": "img_2979.jpg", + "sha256": "73d15d8a0ec26eceea7c402dff19558a3ebcc082c98c771cd21e61b7f7b81d9b" + }, + { + "kind": "file", + "path": "img_3124.jpg", + "sha256": "d7e4f384299e7d7fe2a675f3153b8c03fcedd07d85daba18dddc35c3f2b645e3" + }, + { + "kind": "file", + "path": "img_1733.jpg", + "sha256": "355f52944dfa4c5c5cc0d0e78ba81d45fed880ef0e2c7d670e4adc811503e467" + }, + { + "kind": "file", + "path": "img_1055.jpg", + "sha256": "e5e7c76bffe49068f7ca2f405dbfbe36a61d41269acebb9a278495b58e252715" + }, + { + "kind": "file", + "path": "img_4139.jpg", + "sha256": "c282313ee573659796e5d61246a375be9416b2490cd585628a81369bf1e4c733" + }, + { + "kind": "file", + "path": "img_3656.jpg", + "sha256": "90675f0935b192258552433ae92f130ec36f7564b7551a82c7f90c737fe4e0ae" + }, + { + "kind": "file", + "path": "img_1727.jpg", + "sha256": "47df8c43f0e223b1a7fc2a2ab6f1b54aa3e85b5ef32ed5986a7e03dc16c63cdd" + }, + { + "kind": "file", + "path": "img_3130.jpg", + "sha256": "c43d6b15b536a0dbb1418cefbb353f538e8622ce8bd44deed8f4dddaa4783186" + }, + { + "kind": "file", + "path": "img_937.jpg", + "sha256": "7b0d3bf58b5509b8f82f7d0d7a013816aa9807e574e9d4203efea8a5f4e0b7c7" + }, + { + "kind": "file", + "path": "img_3118.jpg", + "sha256": "d6721f65fade4f42f11802fbfeca0a03ce684391ee97e95d79127fd978937964" + }, + { + "kind": "file", + "path": "img_4677.jpg", + "sha256": "449f6baa2800105530c404e90296813613f9bf578b531d50d5b88f8726b4d0a6" + }, + { + "kind": "file", + "path": "img_4111.jpg", + "sha256": "ff5c9e390c8368bdb8f08a7c9248d593eca42a78ef58294f6522d895fadbe2e8" + }, + { + "kind": "file", + "path": "img_2560.jpg", + "sha256": "eda3cc019ada44d7790db90c8346d277c1dc66bb6bdd7e95df7e1cc7437f556a" + }, + { + "kind": "file", + "path": "img_4105.jpg", + "sha256": "5fbbc5afe85361be31cbb818ed6cf04ee661b7df83e53ac0e32a0f126c32f683" + }, + { + "kind": "file", + "path": "img_2574.jpg", + "sha256": "be96cca71bfa9453d7795e79f52de6020f4d05f78f74bb2e21a52852cc00353b" + }, + { + "kind": "file", + "path": "img_923.jpg", + "sha256": "49fe087a9c392b18c9c40837d799a56f1e7b067fc681d91974b8778889c3000a" + }, + { + "kind": "file", + "path": "img_1928.jpg", + "sha256": "2c941296d67f5d5ff9c47cb44af30ec47a774f1d7a66e1455a77b2430daee7b0" + }, + { + "kind": "file", + "path": "img_710.jpg", + "sha256": "2f5c9303ecbbfeb81d345524c35b1bdb91e2307faa12abea20ca309497a0e18e" + }, + { + "kind": "file", + "path": "img_4688.jpg", + "sha256": "04f54a1dd464ced30b5e5bd4c61608e2f0427009abf08dbd9f2821108cc9dad3" + }, + { + "kind": "file", + "path": "img_4850.jpg", + "sha256": "589e154566c1ab5794fddce693a9ea3719017d269fb4bff76bb979df33c6a9ef" + }, + { + "kind": "file", + "path": "img_3859.jpg", + "sha256": "9bec6da6f9d3791908d5c8d370c10b927d00b07bfb4489821bcb510c490000d1" + }, + { + "kind": "file", + "path": "img_3681.jpg", + "sha256": "4cb0476474dfce8837c0193d06d389dc82d16433a08689cf3a3cafbebc14ed4a" + }, + { + "kind": "file", + "path": "img_1096.jpg", + "sha256": "433846e0352e7bb391a3fc078d33a5dc6e99b3780f1457768e0a97143bb5f70f" + }, + { + "kind": "file", + "path": "img_1082.jpg", + "sha256": "95c5a1b5d965bc90f91c55a184fa45684f8b4416cd502f7360f3c9e91026c63f" + }, + { + "kind": "file", + "path": "img_3695.jpg", + "sha256": "48430b89685cf85cdf493ea5ad07af55b06e6f437ab2da9fe33a8f7e8b89f653" + }, + { + "kind": "file", + "path": "img_4844.jpg", + "sha256": "1fc44e500b160a7ede767227a9ba94809c022fa811edb603f9ca18266926d317" + }, + { + "kind": "file", + "path": "img_3865.jpg", + "sha256": "fa43f6aaaaae6c8ad8a990f34706ce2fd03f7ca71fefea975c826840ac4a52bd" + }, + { + "kind": "file", + "path": "img_3871.jpg", + "sha256": "468c0ed2df65e3b759563b3a5ab77ee8edfc0253cf52846c074ceca108ae7acf" + }, + { + "kind": "file", + "path": "img_1900.jpg", + "sha256": "197e9d8440a0b0e1f25911fbaf049c84022ad6d2d74f9779982945be47d8a4e4" + }, + { + "kind": "file", + "path": "img_738.jpg", + "sha256": "b673a349c865768ec41c0f11a5d951097bdf6e970f74856f96ebdec5a433f46a" + }, + { + "kind": "file", + "path": "img_3050.jpg", + "sha256": "fd4a3f90a8fd3d79f2a0b571f6dbc6e49eb2f5e1bbfcd5990bb6e2e7144b2f27" + }, + { + "kind": "file", + "path": "img_2428.jpg", + "sha256": "d44eead1487ba92951ab8796d0ab2a9026b81b5a13998090527f5027093fecd0" + }, + { + "kind": "file", + "path": "img_3736.jpg", + "sha256": "df20c5ef8318257d5695055f07e3ccf67074759dbebf95f8e7a974e64ca3bb9d" + }, + { + "kind": "file", + "path": "img_4059.jpg", + "sha256": "1d2e33d8041975ed9edd11ac82c8f699e01f2cbaa87966339b292c55d8913ad9" + }, + { + "kind": "file", + "path": "img_3722.jpg", + "sha256": "9b709bc6b3262a1cb1c02671d1bc5ab09caf00dd1374fd8bf0dcb7170df76045" + }, + { + "kind": "file", + "path": "img_1135.jpg", + "sha256": "5952913f90bf528e76de65b067d2fa60e59e0dc432c5708eee3a4914b9d009b5" + }, + { + "kind": "file", + "path": "img_1653.jpg", + "sha256": "ab530177f3959848595ad6a4303c4e0d91deb4d5aae43fcb6d9c7a8446bb78a0" + }, + { + "kind": "file", + "path": "img_3044.jpg", + "sha256": "eefc69bf62614dd5016a4f0d8db64b94f642ab22b7a987388385207c617a40b3" + }, + { + "kind": "file", + "path": "img_2372.jpg", + "sha256": "ad45663775b742c2d9d85c2190ed8e0da24446df3b36ee31e009b1638ae9c7dc" + }, + { + "kind": "file", + "path": "img_843.jpg", + "sha256": "ec0094d58e80494c74764049bc313037d1eb64422da99599e66c58014128b618" + }, + { + "kind": "file", + "path": "img_2414.jpg", + "sha256": "f297c0a27803d4d37ecca2ee028d10da0bd125b22d15ebd71188a18e31540d3f" + }, + { + "kind": "file", + "path": "img_4065.jpg", + "sha256": "868ccb6b07ca8e2d70b6d72c6453da687b23fa2dc5d771605ffd1ba4113f9873" + }, + { + "kind": "file", + "path": "img_1109.jpg", + "sha256": "78082d2e4042e7ea80396f1328329ddd57324f39c3119e775b21a0b4021ec1a9" + }, + { + "kind": "file", + "path": "img_4717.jpg", + "sha256": "26b3dbe011d76f09d5a1aff6327d72ff89a59c5041bde274639085d3ce95f651" + }, + { + "kind": "file", + "path": "img_3078.jpg", + "sha256": "5763426f058927134dc7eef92b01d2993dd0194714e060d2f9316bcf62af7375" + }, + { + "kind": "file", + "path": "img_2366.jpg", + "sha256": "e049160030446937d034e2f1337da8e0ed01b0e6f4e7c3e79cd18acbd90e1ce0" + }, + { + "kind": "file", + "path": "img_857.jpg", + "sha256": "f91ac3aa852483655f316d51df92ecfff7602cb6eb5160bf719e7847c68607cc" + }, + { + "kind": "file", + "path": "img_1684.jpg", + "sha256": "42fd4d7a0617e31133ad360298b1b90f32b8162d126a7816e58c5220ebfec69b" + }, + { + "kind": "file", + "path": "img_4924.jpg", + "sha256": "0067186fae286e70a5e9d75c101ec229fa74e640001b9e5f1cb63b33e3385b5b" + }, + { + "kind": "file", + "path": "img_3093.jpg", + "sha256": "82ef57e8258ac5f60585910383ecfd6da92d10973c54898bb561a388da24828d" + }, + { + "kind": "file", + "path": "img_664.jpg", + "sha256": "d5517aab5a4c5d2ec62255b16dd66254ec9ab10328442be484f4bbe74882b335" + }, + { + "kind": "file", + "path": "img_102.jpg", + "sha256": "82c0ae8e64f87d6663c40565f7a1cebffc886c037839d8dc370f6373c36893b2" + }, + { + "kind": "file", + "path": "img_2399.jpg", + "sha256": "379956f5a1a708bd952df431e980de66aff58ab4c25c7ed5e5c10ed2a45394c2" + }, + { + "kind": "file", + "path": "img_4930.jpg", + "sha256": "14821637e4509e044594732583050b52fa8799285b1bf17340de222ebeaee851" + }, + { + "kind": "file", + "path": "img_3087.jpg", + "sha256": "e960a1cc48caa405db6f6df0a48ca25209df1efb316727c9baf47920f965ecb4" + }, + { + "kind": "file", + "path": "img_670.jpg", + "sha256": "fde568c7b5fa2c3223b8588865d3e831f97d3cedbf118df4c4863c74b31cb600" + }, + { + "kind": "file", + "path": "img_1848.jpg", + "sha256": "37b603a9316b94e560736f4658dc5d89c3b7fcbfd1b1086bafcdd68bec8081d2" + }, + { + "kind": "file", + "path": "img_1690.jpg", + "sha256": "8330083cd58d2f8a7c1fd6c4865c95d506f9b891924ec853ba87e75c164808fa" + }, + { + "kind": "file", + "path": "img_4918.jpg", + "sha256": "e2e670c65dda89491c30edbc1b78517282b74d65923a59356bf13d9ce3e2bfab" + }, + { + "kind": "file", + "path": "img_880.jpg", + "sha256": "7ac47de71d0ec067484489beaab733f9d8191ca5338fafcd845ed2a39e3c566a" + }, + { + "kind": "file", + "path": "img_658.jpg", + "sha256": "ed499f59c5b61836b2cf49bf652acef74e0fe63b65fe2bab768b0635671a3ff1" + }, + { + "kind": "file", + "path": "img_1860.jpg", + "sha256": "035411db5d846946a460cd200ea1f7d8d57cf44b39e532403780437469b8c9be" + }, + { + "kind": "file", + "path": "img_1874.jpg", + "sha256": "e30a8b7992b4f3f760f3ffab1f256e6096b7dd09143dcaa466ee15d5cf97319c" + }, + { + "kind": "file", + "path": "img_894.jpg", + "sha256": "ee147298471179f304a6d4cd7977d2138b9cf331854cda826751171f1ac52d1c" + }, + { + "kind": "file", + "path": "img_39.jpg", + "sha256": "12be95f29388e4d0f12247c0ceced60d4b2e3b8974dae440f8bc042a8af1d951" + }, + { + "kind": "file", + "path": "img_3252.jpg", + "sha256": "f4349f11923793540f0d77665d25727d9d7e4f95f430151590e58cf807170f6b" + }, + { + "kind": "file", + "path": "img_2158.jpg", + "sha256": "5babd758bde7b1038c1ebee7f253feea7a18697392be30450e9d5e2e260e1876" + }, + { + "kind": "file", + "path": "img_3246.jpg", + "sha256": "a4804ab8eefa53fdd3c502e3b5dbf3d9d6d2a54bbea9cbe0fbe717b65a34fdcf" + }, + { + "kind": "file", + "path": "img_4529.jpg", + "sha256": "0e31bcc79fe078bff03f3cb47675e5ab831ac6f161dee8bf597ab267005a707e" + }, + { + "kind": "file", + "path": "img_1451.jpg", + "sha256": "1ed6eac9e35f22c06bf455ce637bda99e3c9b2223ec661f1a55bbb887bb8f2c1" + }, + { + "kind": "file", + "path": "img_4267.jpg", + "sha256": "36c42e23c111ccd544e04dc846b3e325559a32a813aaf0fa00a17147ba3b3a6d" + }, + { + "kind": "file", + "path": "img_2616.jpg", + "sha256": "4d043a2b670a90d345ba78c812e25d7a55a2fd6024dd334fc7b74ea7f86afd10" + }, + { + "kind": "file", + "path": "img_2170.jpg", + "sha256": "0781c83baa004dde2d22283e54abd85cb63936bd99e917c1a5cfe044323c96b6" + }, + { + "kind": "file", + "path": "img_499.jpg", + "sha256": "0c54a8ca1d715906ec0b4808abaea6b4505aa42ed4be34d5313863ac6465f124" + }, + { + "kind": "file", + "path": "img_4501.jpg", + "sha256": "d481538a42034c603ca2c3d731f9e0932d4c9e06fc821666596279019e6ec3b5" + }, + { + "kind": "file", + "path": "img_1479.jpg", + "sha256": "5dae28c63cbb5c49f049bff583dcbcabe56ca3ac6d3d31f71ffaec9ca812910f" + }, + { + "kind": "file", + "path": "img_2164.jpg", + "sha256": "c3ca75b48b6af3cb88746851c4e25a831b2f1a61b89da6b94a57b9a436ec91c1" + }, + { + "kind": "file", + "path": "img_4515.jpg", + "sha256": "8d35ac81c9042c67ef7be389a8fe20fdb83445f9ab53e844af47b9d0cc0f8c26" + }, + { + "kind": "file", + "path": "img_4273.jpg", + "sha256": "ac947d3026bb85ac1f1dfa3677f9d310b86ecda4cbf4d2ecde5db652443b4f94" + }, + { + "kind": "file", + "path": "img_2602.jpg", + "sha256": "633902bf959e969525e8220082d0a1d1282298fec12af137de8041c2e25de7d0" + }, + { + "kind": "file", + "path": "img_4298.jpg", + "sha256": "fe51dc76455a2c1acb574643208c274c5585d23852af920d87bd0665bd4b63ae" + }, + { + "kind": "file", + "path": "img_2831.jpg", + "sha256": "616850fe9e065a39d76454f844d44f1cf252e75b16b16213b6e92cd35dd7baad" + }, + { + "kind": "file", + "path": "img_300.jpg", + "sha256": "383ec8e2608be227e841728178696e413bad2009170c94d20005fd6ccbda7710" + }, + { + "kind": "file", + "path": "img_466.jpg", + "sha256": "e81a72c4238ad425dea10e38814c06bdc80fdb6e78391ca9be2fb0c7c642fa36" + }, + { + "kind": "file", + "path": "img_1486.jpg", + "sha256": "edb3ff733f317ef0019a51da8e2e5da8488a86e6380c8c32e0b15a3f9003f7d2" + }, + { + "kind": "file", + "path": "img_1492.jpg", + "sha256": "9ee42d136cea733bb0762340ed545fb166cc107bc94f42091c6e2bb1998e58a6" + }, + { + "kind": "file", + "path": "img_472.jpg", + "sha256": "9a87f9cd8ef2ae6963e65b4859ca0dbc41c183217acd7b98c533cf180069edba" + }, + { + "kind": "file", + "path": "img_3285.jpg", + "sha256": "f7ef0d210a723a1bafe4e21b299aad39ee9e707990f28c1ff28a2ac92911092f" + }, + { + "kind": "file", + "path": "img_2825.jpg", + "sha256": "92402af6e7ebbfa4b4256921e2a060dde842e506fe583482cb3257885d27e61d" + }, + { + "kind": "file", + "path": "img_314.jpg", + "sha256": "63a700c7f189efc7a82c9908e279507275da9e30c09cd78a4a5b208a31167ac1" + }, + { + "kind": "file", + "path": "img_2819.jpg", + "sha256": "f29876ca772a894926e45b96b04577297257f7afa3559d17e14fea34279109ae" + }, + { + "kind": "file", + "path": "img_328.jpg", + "sha256": "20ed6dd7130c84683555acc1738b67552e8317189ed6064eb4d586fc1298f1a2" + }, + { + "kind": "file", + "path": "img_458.jpg", + "sha256": "7d36901c81b3c497f6cf7af69170ad13fede4d9c65da7e58f1c40fd99d9005b9" + }, + { + "kind": "file", + "path": "img_1484.jpg", + "sha256": "162a92466fada22384c0403ba0a83792caf307f5abcba9973c6e161ef3b42133" + }, + { + "kind": "file", + "path": "img_302.jpg", + "sha256": "35d214fb6845fb77e0e8372b3f16ff9fc700039834e7e971129a303f170255d6" + }, + { + "kind": "file", + "path": "img_2827.jpg", + "sha256": "3d3040ac2197bb33415a138e5acf63bc940bef62da3026929fefac631702ec72" + }, + { + "kind": "file", + "path": "img_2199.jpg", + "sha256": "eddc17dfd839c1027cf18a68dad652461631a62470983ec3693308ea23788fb4" + }, + { + "kind": "file", + "path": "img_470.jpg", + "sha256": "bcd1383f1f0198cbb056a58bf9c03fb61ce9f0a87846cd089ffcdfded129122b" + }, + { + "kind": "file", + "path": "img_4503.jpg", + "sha256": "a2f45eb30b8895899c8eb71c114f49ac766fc735a569f5e2df0303fe24ffd338" + }, + { + "kind": "file", + "path": "img_2614.jpg", + "sha256": "3629791992f0986dd2558da2b6a04e94f173c953f37e32942ff96e16daeafbba" + }, + { + "kind": "file", + "path": "img_4265.jpg", + "sha256": "04311ed3df9f4ec297a77ea832dc176b64347be248ce322969975eba1a0e0ba7" + }, + { + "kind": "file", + "path": "img_1309.jpg", + "sha256": "5946859bcd84182e68649e34667443127a538a04b83150d859138c13fa5cfb6c" + }, + { + "kind": "file", + "path": "img_2600.jpg", + "sha256": "aa5757e811dc18e0a1677522f272e1f4bd1cc88cf236dd961042707e1814b134" + }, + { + "kind": "file", + "path": "img_4271.jpg", + "sha256": "3c199163bb13bcd7f1071539c30786db497f59bceaa146e481be6e22cf1c7912" + }, + { + "kind": "file", + "path": "img_4517.jpg", + "sha256": "e2e7abd81988352737a97d50799873a97880f340bdca97c10158a0961edee1e8" + }, + { + "kind": "file", + "path": "img_2166.jpg", + "sha256": "f958e80dea89be69ab5a2ccd1ebb4fa420572f5ae4532d75347da3dba1910d62" + }, + { + "kind": "file", + "path": "img_13.jpg", + "sha256": "ff741f1fb94c50e1311d192bdbaef95d97a2725b4b4c6ac82f3842659f7d824a" + }, + { + "kind": "file", + "path": "img_3250.jpg", + "sha256": "653a9b8d612a4816616ceb49e0980137efe5874062d74e11a315eef7401a18af" + }, + { + "kind": "file", + "path": "img_1321.jpg", + "sha256": "f441ddd94c42d19374398aa23160983750b3307484316d2ea23f14a85c15a33d" + }, + { + "kind": "file", + "path": "img_2628.jpg", + "sha256": "cd1436fd1cf92e75418ecfb0f50f31bbe3f84ebceb419a671fc6b957a781dc54" + }, + { + "kind": "file", + "path": "img_3536.jpg", + "sha256": "233b2fc1422677e8fa4045c4ccd1d9caa3b859471b9551043280b8c4e0e16301" + }, + { + "kind": "file", + "path": "img_3522.jpg", + "sha256": "0793d3338d673c4fbb6651cef86e9686297a992d888a1146a146a5fed06fbb27" + }, + { + "kind": "file", + "path": "img_1453.jpg", + "sha256": "6126f80122cce78bfbfe425510e923ae26d96ddcf7e4d4f42b9e5686d2da8ad9" + }, + { + "kind": "file", + "path": "img_3244.jpg", + "sha256": "e22f0c59149ea3768f910d05b883f25d093023e182fc5cdf94d47ad7208e7fef" + }, + { + "kind": "file", + "path": "img_3913.jpg", + "sha256": "e456b4eb70723d0d1a64a7eb5b601eb169d0cb4ca7d9754ff736738b4d35e7ec" + }, + { + "kind": "file", + "path": "img_1862.jpg", + "sha256": "b9c5ff6e468d5aa6037d00faaf716359accfec3b9185490dc16047a5a5df7520" + }, + { + "kind": "file", + "path": "img_882.jpg", + "sha256": "e70d1e7f2c07816c7294dcfe11a43f43f096ea74eb360113f8831fc7a2def526" + }, + { + "kind": "file", + "path": "img_1876.jpg", + "sha256": "2c58336c180506efaf538eef9a4b6bef06ce46cba10328c52a240ef5cbb420cc" + }, + { + "kind": "file", + "path": "img_3907.jpg", + "sha256": "fcaf3b33c2a85232fa68661ca72772b9fad62b85f0b99aff64d943604dcffb77" + }, + { + "kind": "file", + "path": "img_100.jpg", + "sha256": "5f2bb4af9be2522b048521ec9767412241179997c7bfa1b10c171cbced6fe236" + }, + { + "kind": "file", + "path": "img_3091.jpg", + "sha256": "e47de452a6f70e94a98f6cd69036ad0880f881673677415058277a5d758fe784" + }, + { + "kind": "file", + "path": "img_666.jpg", + "sha256": "e9cd3f576adc4c987582c09977d8a38e3fa7aee52f319617caa491af3a4dae19" + }, + { + "kind": "file", + "path": "img_4926.jpg", + "sha256": "469027ff5bb57a1a90520e52cb5a0e031c1bae82a823dc961e3106d206b55c8f" + }, + { + "kind": "file", + "path": "img_1686.jpg", + "sha256": "b3925804a6b9bf2f2af85565e2c1af7b3e02ac0c86579780de889cbd4ad4cf73" + }, + { + "kind": "file", + "path": "img_1692.jpg", + "sha256": "f6e4623a5b44e5696dbddf5651ac9c841699b1a7cbd1b0b4bbb0014178268447" + }, + { + "kind": "file", + "path": "img_3085.jpg", + "sha256": "c601667c149495b7fb5182df0f2c8e646128c592b1a2a5cd2d7e93c0e51d2d31" + }, + { + "kind": "file", + "path": "img_672.jpg", + "sha256": "6741e970bbcd8bcfe3f4942e10e17c1e89d2f93e688a0448b385a6403d46bd99" + }, + { + "kind": "file", + "path": "img_4932.jpg", + "sha256": "153621cc2bfa27dd7ec4e0c9bad25d935c6a64a70cb6d719f4793c7a0d96e1e3" + }, + { + "kind": "file", + "path": "img_114.jpg", + "sha256": "f50709957cdfc76b8268784491c0334c1250cd1482a91a3ae583e5e00dbef827" + }, + { + "kind": "file", + "path": "img_4067.jpg", + "sha256": "c9bf671d832dae408931d872ebda8f14e4fe18a2e8ab73e9b1b66f7b31c69930" + }, + { + "kind": "file", + "path": "img_3708.jpg", + "sha256": "6b336a8b83800a07404d6953b41fba5582764caa36a2d5acd54a4e602fb18038" + }, + { + "kind": "file", + "path": "img_2416.jpg", + "sha256": "1d67e13974f19c1a15cd6c79927a7c569124211b2f80f1ba1913020746115b76" + }, + { + "kind": "file", + "path": "img_841.jpg", + "sha256": "94d7f467135ed01457c30d5fddad99eef9d1e1024101d0e6370a00cbfc198ece" + }, + { + "kind": "file", + "path": "img_2370.jpg", + "sha256": "6ed5b27f46c2ff22a578f440bad549ff0f3ab59f34cb6c5171e2b51644cc41ac" + }, + { + "kind": "file", + "path": "img_699.jpg", + "sha256": "ee1b76f08c30285e0f9ffb5b354b1b7dd8cde860f3cd13efd052c78f468e2acc" + }, + { + "kind": "file", + "path": "img_4701.jpg", + "sha256": "ac343a6a9a2f296fda23e124fb3cacd835dc1b223790ea6ebf9ecefa8c5b604d" + }, + { + "kind": "file", + "path": "img_855.jpg", + "sha256": "c979fe171a3ac04fb1834d670d5ce65b999dc17bb11e2cef7db3d4be32d8275c" + }, + { + "kind": "file", + "path": "img_2364.jpg", + "sha256": "9adf8002df0762d16e0aa3161a38334954aff29fa88cbafbcf00676699af5c11" + }, + { + "kind": "file", + "path": "img_4715.jpg", + "sha256": "a56d06c33550c4d2f7ec85ec73e5dd15f9720071805d2d55e82e639a3e9d1ab5" + }, + { + "kind": "file", + "path": "img_4073.jpg", + "sha256": "671e56da154b63969125bbe2e1fa727f40a1ad13d686efc9b4b233edce8ff87e" + }, + { + "kind": "file", + "path": "img_3734.jpg", + "sha256": "2327a912d183ba269519739ba286498665dcf5146472dfd345f3174c4d3402d6" + }, + { + "kind": "file", + "path": "img_1123.jpg", + "sha256": "35ac1203f807ddd0f14779cd4f6ab4c4af9b2cacc1df07756bcb907125b83a2d" + }, + { + "kind": "file", + "path": "img_1645.jpg", + "sha256": "733bf76c306f83b89a99993f791b18da2a2500149c5014af6b1c435ab6fb559d" + }, + { + "kind": "file", + "path": "img_3052.jpg", + "sha256": "fe4f9133b42c5e891b76197a19f10d4f9eb6758b7a87ac8fd6746c690f21d3b9" + }, + { + "kind": "file", + "path": "img_869.jpg", + "sha256": "0b3aff62a1c6f2ac0cbb1d752daed2cd9328246a5475661183b6ee0d1c01ba0a" + }, + { + "kind": "file", + "path": "img_2358.jpg", + "sha256": "0c2c185276546b85f2eba9209a1c5eb1c16854a1b0caca1d1f5d34dd86e31150" + }, + { + "kind": "file", + "path": "img_3046.jpg", + "sha256": "86f76194bfb7eb6ea55d8a387a9f4b1572359e3cd979d096b0cfd7c69c57262f" + }, + { + "kind": "file", + "path": "img_4729.jpg", + "sha256": "a58cec6253f41cb51c7311d8be6d5d11242a31a0809f6f70e110f37577374e1a" + }, + { + "kind": "file", + "path": "img_1889.jpg", + "sha256": "c58a6785c70034a4b0a032f309244c8136299ea6785c89f19b0546634f509ef3" + }, + { + "kind": "file", + "path": "img_1137.jpg", + "sha256": "7e279787170c5ff1352f867dea6fd801ad87f4591d5fcf2f962c3b01d68d6953" + }, + { + "kind": "file", + "path": "img_3720.jpg", + "sha256": "693db3317d2b7afa4e261de5d3c4c0747eb68e3305ea64939bedf19acedca029" + }, + { + "kind": "file", + "path": "img_3867.jpg", + "sha256": "867ee1a9e81610ac6374231987632cba8106f6de4450dd8527e0396ad23d5e19" + }, + { + "kind": "file", + "path": "img_1916.jpg", + "sha256": "cdcf658348c1f7108dada8b1498533c9a01b0f0b2357c4ca98ea4e2f94d5337c" + }, + { + "kind": "file", + "path": "img_1902.jpg", + "sha256": "eb8394d9b8896c10c365587021786758a43c875b21d2a2f382c2eddf79b83a43" + }, + { + "kind": "file", + "path": "img_3873.jpg", + "sha256": "28ec509acb06492a7aa54d09542363e8cb7c979917a7b7fc931fce604dabdf7d" + }, + { + "kind": "file", + "path": "img_4852.jpg", + "sha256": "77643057ad508c953aa39123235845f85807c5d3d92fede99ce93a23e514bf92" + }, + { + "kind": "file", + "path": "img_4846.jpg", + "sha256": "d0b0f9d09ffd91434ce3f9de7d08ed17c1ae75e0251fde607d53fc3ed30e09a5" + }, + { + "kind": "file", + "path": "img_706.jpg", + "sha256": "402191eb5a647773ebdf1847fe0ce559d96fe74cd8ad6af22a96284c2a8ea258" + }, + { + "kind": "file", + "path": "img_2589.jpg", + "sha256": "4ad9e350028fbe53943eb2f4c203d2d8589a3e13525e70bba8bceaa3011fdc6d" + }, + { + "kind": "file", + "path": "img_1080.jpg", + "sha256": "62135caa9e11c93c58bf84752b0c09e4752a72070aa1b96127075b62671e4d45" + }, + { + "kind": "file", + "path": "img_4113.jpg", + "sha256": "8227f138109ed094338ec9915ce205b92b402522c5beb025d5bc7d9938bf2503" + }, + { + "kind": "file", + "path": "img_4675.jpg", + "sha256": "9ecdc7cbd983275d4a6ad17545351b9c0c3898db21f1e8242cc092ead991b059" + }, + { + "kind": "file", + "path": "img_935.jpg", + "sha256": "d5880e6ea9b34ebb78030aa67debc69ed85cf5ff5552d74687f3e152f5a08020" + }, + { + "kind": "file", + "path": "img_1719.jpg", + "sha256": "85053aeb8d23fbffc249987f7094f528548de1f8791757b56b1bfacdc0ec0d00" + }, + { + "kind": "file", + "path": "img_4661.jpg", + "sha256": "9d1bf54807d39ffa60aaa97a3d875d855f16316739056bfa0600276c63eaf918" + }, + { + "kind": "file", + "path": "img_2210.jpg", + "sha256": "59e63c0c9afdabf1288c4a6658042112c1fc6c1c60396f69f492cc74228fbc04" + }, + { + "kind": "file", + "path": "img_2576.jpg", + "sha256": "a94f4ec46abf29e5d54dd55885665dd84a1722ec7d7a62e8e89c50db810e231c" + }, + { + "kind": "file", + "path": "img_3668.jpg", + "sha256": "c1118f3f380751772bcb0c7a65cfe24e91ced57f777c848ee421138496ec68e7" + }, + { + "kind": "file", + "path": "img_4107.jpg", + "sha256": "7610fb4c56650621522c31ec2a3b508c0eec5d2dbdbe3bd6f2530f38ae6bd9f9" + }, + { + "kind": "file", + "path": "img_3898.jpg", + "sha256": "e374bb1589c3ad348fc32d9cfc778173685e5dcfb88278f0ca91ae3a8367a201" + }, + { + "kind": "file", + "path": "img_3640.jpg", + "sha256": "8ba3393016c0aecb8b90f805428b29afbc2bb15368a2919b5faafba8043e5335" + }, + { + "kind": "file", + "path": "img_1731.jpg", + "sha256": "91521020fe6150973b03c9b48ebef217ec40cf0116e1481be999246158337a73" + }, + { + "kind": "file", + "path": "img_4649.jpg", + "sha256": "4cbbb9871bd7bb0fcb52c21adda991aea44ff9884d3615fb1e89a86d0d3b073f" + }, + { + "kind": "file", + "path": "img_3126.jpg", + "sha256": "7a66c7ea77c2e34e3277fd26ac62c716778168aadb2e0c8b4ad4408e6567e779" + }, + { + "kind": "file", + "path": "img_2238.jpg", + "sha256": "5aa4ec0b0022bc2770386455c047fff565ab1ca8d89ea243228f6951c586ca17" + }, + { + "kind": "file", + "path": "img_909.jpg", + "sha256": "7be9cd64e2a1c4c993c0c5f31ea15f74b5a5bbd4109e54fd176d34b09ece7779" + }, + { + "kind": "file", + "path": "img_3132.jpg", + "sha256": "fcc2896a5e3722295003f45d12e435293ede4dc6a7a61b45ef8de55f29411cc8" + }, + { + "kind": "file", + "path": "img_4885.jpg", + "sha256": "e9d92b029b7546bca86f2dbd16fc22c58d5604792d2375b04d5e01d8436f1bab" + }, + { + "kind": "file", + "path": "img_1725.jpg", + "sha256": "9797e7a0988a6bbb107c848c892b85d19444eb3ee12b791e52af9b08768bc6d2" + }, + { + "kind": "file", + "path": "img_1043.jpg", + "sha256": "264ed34dba7517b2fb68534a09d160091c4179b2ecccae97c9dea641ef4dc762" + }, + { + "kind": "file", + "path": "img_3654.jpg", + "sha256": "94d84890ea48d8dadb587a4f16f48f3e71fa24d9af70ffb730b4e3362a4e80ab" + }, + { + "kind": "file", + "path": "img_538.jpg", + "sha256": "5014e658d5724207b16ef28f37c10d18b04b3cff989395c347f45e2ad1e26d98" + }, + { + "kind": "file", + "path": "img_510.jpg", + "sha256": "99ab442928f1140dd02d589afda91af8804a533da50d6862e0860b576239dbdf" + }, + { + "kind": "file", + "path": "img_4488.jpg", + "sha256": "0e50e3a1688913c6e6dc4eb6d514de55adb2e89fd5f6b9c0723aea06ce00ceba" + }, + { + "kind": "file", + "path": "img_276.jpg", + "sha256": "8021f82eefc61da3a91d96ab3b3cb65bcc50bb163583221d5ae1eef7839641be" + }, + { + "kind": "file", + "path": "img_3481.jpg", + "sha256": "1741116b66308cb39f502619000144848090333151b33e9cd0769814e5b0793d" + }, + { + "kind": "file", + "path": "img_1296.jpg", + "sha256": "eb8b5d8c6dc1fdb91189752a439a65e12654149fc187ef0e59d8753939ada2fc" + }, + { + "kind": "file", + "path": "img_1282.jpg", + "sha256": "19deb04a94980152262c4ce67bec6592c9bd917348900f6f3823ab6e7c5a252b" + }, + { + "kind": "file", + "path": "img_2.jpg", + "sha256": "ce364fcc28f23e387862c94d4c515e954e94048c4a18cdbba28084800a6cb3c2" + }, + { + "kind": "file", + "path": "img_2953.jpg", + "sha256": "8e1ec52bb6773dd37fa34b864a834d716fa6e1ab558a68e455045853a01c5a2c" + }, + { + "kind": "file", + "path": "img_262.jpg", + "sha256": "321e99a06eb36debcd58df10768ce3a4122dc4927c8f5f4b296de5e0ffd60b07" + }, + { + "kind": "file", + "path": "img_3495.jpg", + "sha256": "97b2fe4b2b41e7539a0969c488ff00404d01283549d5df4e02198f99af697362" + }, + { + "kind": "file", + "path": "img_504.jpg", + "sha256": "c1ffc93c7a5968357fff1a0cd7bd7c0c0eca3536726adab3e6586eac64109570" + }, + { + "kind": "file", + "path": "img_2006.jpg", + "sha256": "5135d0167661b1e5a11eeae6a99d9f5bc463ca6f2d59fe33432a62cf6797c95f" + }, + { + "kind": "file", + "path": "img_3318.jpg", + "sha256": "6576ae2157e534b90cbe73e8157f032a63c543c0d5309807fee4a8c6fabf6ac4" + }, + { + "kind": "file", + "path": "img_4477.jpg", + "sha256": "e8665e8daab95f4acac9c5b8d895f0307ce6e926c975466adaab7f9d467a9d96" + }, + { + "kind": "file", + "path": "img_4311.jpg", + "sha256": "2b7da090a9b5e9a8cdc3cb378d29e2f27afe54917480d355fb95770a8847756c" + }, + { + "kind": "file", + "path": "img_289.jpg", + "sha256": "89e9634d5756c923377403e84a32476804fdecd04a20c4c9888511a7fd78f8db" + }, + { + "kind": "file", + "path": "img_1269.jpg", + "sha256": "70b91fe6432daef5077cbe40d7ddb6a5aadbd61d22dea247f5df24cb7f841e94" + }, + { + "kind": "file", + "path": "img_4305.jpg", + "sha256": "1d2b46ede0ff0c62722da78aece23e830ae151e77326223fc0b97e4f098db118" + }, + { + "kind": "file", + "path": "img_2012.jpg", + "sha256": "291f8f29afbe308fda17ede9c4d1a87e8500fc06eb6b1b566b26e8d71e2d732c" + }, + { + "kind": "file", + "path": "img_4463.jpg", + "sha256": "6f4166102d807393b5b07c1ee289f8e5bfe77f1756b0c66811d6f35b55eaa3ef" + }, + { + "kind": "file", + "path": "img_3324.jpg", + "sha256": "4d474aab5a58d92a0dab5c1dd8ef4be61ed3524cce838d753c9b4f44ab179770" + }, + { + "kind": "file", + "path": "img_2984.jpg", + "sha256": "07ee53d8b7ee228a00b5b6d8788d2a67f122b6be46f97d6979cf0ee1233a1f28" + }, + { + "kind": "file", + "path": "img_3442.jpg", + "sha256": "d873a3da127a83246da4d64bad0ede66a3b17ae1493b4611328f53942b2a776f" + }, + { + "kind": "file", + "path": "img_4339.jpg", + "sha256": "37191bf58e28b8d987d6882b7ef28f5465825ed22d844bd3cd9309b688c617c0" + }, + { + "kind": "file", + "path": "img_2990.jpg", + "sha256": "220df9094e2b461aa38e175ede1250a7bd827de4866c02f05246095784d80256" + }, + { + "kind": "file", + "path": "img_3456.jpg", + "sha256": "6534aff8353fd1a929e5aab2f8c3b2908db2742527b1c3343da54fa58e058a6e" + }, + { + "kind": "file", + "path": "img_1241.jpg", + "sha256": "141c24900bc06bbc3544b4f55cb69fcb7e735cc42edb46e5f6f5ab4acc0c2676" + }, + { + "kind": "file", + "path": "img_1527.jpg", + "sha256": "d8a0a344a5b2448983940e50172310e8ba571c8bf8b8d2e51f632aecf4db5cb3" + }, + { + "kind": "file", + "path": "img_3330.jpg", + "sha256": "4cd72aef6e1ee7e144399f9895e04a3d9f77c237c7957c0fbe54a2adddf707d6" + }, + { + "kind": "file", + "path": "img_1240.jpg", + "sha256": "f8654818553fa9213b3ec212b88a0a0e7c5d406ee6730eff8a5d0ddb6e1b8619" + }, + { + "kind": "file", + "path": "img_2749.jpg", + "sha256": "eff2a517f19c36552a13d6b616441be04a4ab2cfdf3f14a8db359b7b2da57884" + }, + { + "kind": "file", + "path": "img_3457.jpg", + "sha256": "7a50214295353dbd0623d4f552520b332ab6ed21a4996add462e2824abeb088f" + }, + { + "kind": "file", + "path": "img_2991.jpg", + "sha256": "e4b34eb175667926546236bcd5dc2b520e9b58cb8a4e5b975438bc5dc74cf6f3" + }, + { + "kind": "file", + "path": "img_4338.jpg", + "sha256": "754a403a4bc1f17136584f18f16c0c598d0ede684294292757d28a45abe9cbbd" + }, + { + "kind": "file", + "path": "img_3331.jpg", + "sha256": "eb52fc84db47cc91b2e4250fc28f4eb4d7bd10bfd7d7ba8f6bb9f8c2e647a1e3" + }, + { + "kind": "file", + "path": "img_1526.jpg", + "sha256": "810c8d01d39fc4728aab6ece8cb8e2083c65faec8564965caff020723d45d0e5" + }, + { + "kind": "file", + "path": "img_1532.jpg", + "sha256": "4b2bcf74cdc0833014ed072d1381807090f775b18407783573c21acf35d10869" + }, + { + "kind": "file", + "path": "img_1254.jpg", + "sha256": "833528cf37663d7fa9ea6d38c2a829f74edf88da60d0d192845610b7f026a4ec" + }, + { + "kind": "file", + "path": "img_2775.jpg", + "sha256": "e93c42737e84cca0e4a246a59853fc5529e8713a484f024a376b97543aa9025a" + }, + { + "kind": "file", + "path": "img_4304.jpg", + "sha256": "c610352da5e4c4804dcf3edadf64dc7cc95f13c6d2a925aa2f3b17526406b07e" + }, + { + "kind": "file", + "path": "img_4462.jpg", + "sha256": "a65a7411d79a27117b6f288955b746f2a0d33b2ad518a8c54b294282dc435bf2" + }, + { + "kind": "file", + "path": "img_2013.jpg", + "sha256": "96ddc123adcd4f8cf5dbc819324384736c005b5f8f7d6f280f4bdbf47635e8ac" + }, + { + "kind": "file", + "path": "img_4476.jpg", + "sha256": "e3f35393a2074d8163fcf66f8b57f5a6547708329f2f4937b898be23ba8ecaf0" + }, + { + "kind": "file", + "path": "img_2007.jpg", + "sha256": "11df3d76f5adbf83b4d8ca5eead7d007ab57a1c6478a438cc07beccf1480e1cc" + }, + { + "kind": "file", + "path": "img_2761.jpg", + "sha256": "857cc87e02beaf0d473de99d6a25f4a81ce051c6d256b90319c3ff17c6316564" + }, + { + "kind": "file", + "path": "img_288.jpg", + "sha256": "34613a89801b9d6ed3b2eedb42a8a5c018ef64aaf3a32e735a72c454d4ccb97a" + }, + { + "kind": "file", + "path": "img_4310.jpg", + "sha256": "06331663623464dc94eab02a0b6b1bbd2ca6ad84413a61d2c2ebf535ead1df1a" + }, + { + "kind": "file", + "path": "img_3494.jpg", + "sha256": "83574748647509154eb1466923e23e1c918fcdbae428304a4861deb5c48b664a" + }, + { + "kind": "file", + "path": "img_263.jpg", + "sha256": "8f8ba747c89f0b5741b07bff7edd28ec7ab28eeb7f6d6c9c25914959646b53a8" + }, + { + "kind": "file", + "path": "img_3.jpg", + "sha256": "5376b428a34f988a9516212a95721ed44d78c970e129a15eb219a5e4539078ab" + }, + { + "kind": "file", + "path": "img_1283.jpg", + "sha256": "cdf4113a2ef29da6e2878c09e07e9f02cd02ef510749b79dcf450724fb1c0e47" + }, + { + "kind": "file", + "path": "img_505.jpg", + "sha256": "213509f275084121cfaab15c3665c95883881814f72553043074364d889eca1f" + }, + { + "kind": "file", + "path": "img_4489.jpg", + "sha256": "a719494e1a58d48e85ea26c5cf742402a4fe2512d4412d664cf59e1f4be4715d" + }, + { + "kind": "file", + "path": "img_1297.jpg", + "sha256": "057e2d52bcaa3765799eb81bf8468165c0e478a7a958448773bad1dfa322b504" + }, + { + "kind": "file", + "path": "img_3480.jpg", + "sha256": "78ed65a17e7332b4dd3522a7b24994fcb66e84d2b29df99e4fbf3d8078b5de4b" + }, + { + "kind": "file", + "path": "img_277.jpg", + "sha256": "2a4e50b1db9b911febeb1db349d20ac1721bba2a791e26906d478059820737c2" + }, + { + "kind": "file", + "path": "img_2946.jpg", + "sha256": "45769c469a86b56fd96b12a9b1b065ade6bbcbe9f3728b02f3ed0ad3331ce029" + }, + { + "kind": "file", + "path": "img_539.jpg", + "sha256": "1d10c0ab2c5c762c000134cf59cffae68e278a33173347c5a5c19ff23dd0c517" + }, + { + "kind": "file", + "path": "img_1724.jpg", + "sha256": "8929e9d6dc3e9d7fb88408296e653d268b38f4902704d138949116bd765f6eb3" + }, + { + "kind": "file", + "path": "img_3133.jpg", + "sha256": "785150c945a30199db1a0bb842e693dd00d3446c64515d7bde9be72ce70283ab" + }, + { + "kind": "file", + "path": "img_1042.jpg", + "sha256": "ddab9a66291fe3ee908b1af9ad1081cd5fc8212f2e8690faf3e755f8d0fea2ea" + }, + { + "kind": "file", + "path": "img_1056.jpg", + "sha256": "0133cafa849604891fb325df7a64259dc4abd93106fe47316ce6e22a20edf96f" + }, + { + "kind": "file", + "path": "img_2239.jpg", + "sha256": "f42bb8fbe9e4513320b655822fee53c8c65f322b3d20de083f96439c0817c415" + }, + { + "kind": "file", + "path": "img_3127.jpg", + "sha256": "834d5451ced9b322b28d8040e68a1afb984b5783344b4188a6c60a497a96e67b" + }, + { + "kind": "file", + "path": "img_4648.jpg", + "sha256": "008f8f3a6d991ea7a2f2699801f73bbf97d56edcd2dbf3a9cfcaecbf9094ccd3" + }, + { + "kind": "file", + "path": "img_920.jpg", + "sha256": "f94e1f2d7d04dc130bac90d9abb912c78980d83abcd3c7d0d863d2d973c2b958" + }, + { + "kind": "file", + "path": "img_2211.jpg", + "sha256": "43bcb213c01f7ebbd8abb91e81dd4f313bed8e14dbec362993380b4d6a8c4658" + }, + { + "kind": "file", + "path": "img_4660.jpg", + "sha256": "1b41ecd7ae9e76931016367ad22e9fc0207c50dcc908f6caab646d60b1112bdb" + }, + { + "kind": "file", + "path": "img_4106.jpg", + "sha256": "e86f8e37e785225f68bc32794b6b8239e6399a924e6d38cae5bf7ecdbad4d448" + }, + { + "kind": "file", + "path": "img_2577.jpg", + "sha256": "7c8f6f47493f629a9e9394af1935e8d6a08b47858ee64dee3b87108f1af44868" + }, + { + "kind": "file", + "path": "img_2563.jpg", + "sha256": "3715ee2b347e068181e15c1a171a9d2b37da428f6ab1d0f364cb5af4d981ab62" + }, + { + "kind": "file", + "path": "img_934.jpg", + "sha256": "51f503d19b4d67933cc82f45df156a5cb1398210d29f0b986dd326895e4101fa" + }, + { + "kind": "file", + "path": "img_1081.jpg", + "sha256": "0f93548c9aeb8a1d32b87d6e6822bfb318cbc70b54cb94d88e08fb40d78938b5" + }, + { + "kind": "file", + "path": "img_2588.jpg", + "sha256": "70b95d66ea603c836652138d585516bef2f6a8ca4b0d676aaed4029ba8e78d28" + }, + { + "kind": "file", + "path": "img_3696.jpg", + "sha256": "fce4b3aaa5de180c647617b2b2c693beec56679b74b263bc1ec39a8950674c91" + }, + { + "kind": "file", + "path": "img_3682.jpg", + "sha256": "145759e576ab5e69bcd30ddeb823ea6b17cd5043c811bf6e13e38f76976c4f20" + }, + { + "kind": "file", + "path": "img_1095.jpg", + "sha256": "41487ac64a4c639072d662be51b6122bc58497c052a1291bc1a3c4ddd203e39e" + }, + { + "kind": "file", + "path": "img_713.jpg", + "sha256": "a2ba01f9d6e9facc391ea6ee791844a2d30a39cdec8a8f1e5fe74f93c21a8dc8" + }, + { + "kind": "file", + "path": "img_4853.jpg", + "sha256": "c2e2d2fa91a515e07445cdb7d0e90e2140aa3c82adb6f2ffd845990f9d4c90a0" + }, + { + "kind": "file", + "path": "img_1903.jpg", + "sha256": "0b99843a66d61aa82ad97bb8fa8e8b1910d2a51fc0f30dbdb11e233a0b3951b0" + }, + { + "kind": "file", + "path": "img_3866.jpg", + "sha256": "9b48a90b63c379b2aad68fc638dd9ac26ac80e94a817846098f6d759845bcb88" + }, + { + "kind": "file", + "path": "img_1917.jpg", + "sha256": "7ac30c6468c585f1cf30d7d9c951363b44d9e73cfe64d0a299275da05e500f3f" + }, + { + "kind": "file", + "path": "img_1650.jpg", + "sha256": "3c15200d7935cc41778cff98e31d48993b97e4e74038ffd12e06511bdd6d9296" + }, + { + "kind": "file", + "path": "img_1888.jpg", + "sha256": "5ea09d6a886a3e03b43aacd9661aaba5111d7b4fe3c0c2f7cd115d9929d7d101" + }, + { + "kind": "file", + "path": "img_2359.jpg", + "sha256": "dd1e95cbe6e5f35e014276108a67793d93824a7f989c58608c2224256e3ff04b" + }, + { + "kind": "file", + "path": "img_868.jpg", + "sha256": "e7f161cba1c5fc67b691b0efcf829f2b4a4467636c4d35fccf85fefbfa8eae0e" + }, + { + "kind": "file", + "path": "img_3721.jpg", + "sha256": "b160a83cebeadbf03326bbe79a62c1c0ecbb0b5e2533e26163d9465c69e293f7" + }, + { + "kind": "file", + "path": "img_3735.jpg", + "sha256": "df432d4456a1643abfe48e05784f63810c99864331aaaac72a1092c09aa33611" + }, + { + "kind": "file", + "path": "img_3053.jpg", + "sha256": "1179aacd0cadc0f1f180ba0929c6cb6e990bb7d4cb435dc7771aa7e4a5c65cea" + }, + { + "kind": "file", + "path": "img_1644.jpg", + "sha256": "74845a08c06b85cde58f39e94020b27a03012fa64a99c564cd9751f41d60836a" + }, + { + "kind": "file", + "path": "img_2365.jpg", + "sha256": "8dba7d81098c6758780e21efd6a2167f1960fbc5ce21d6f80c9330b6f2cdd39e" + }, + { + "kind": "file", + "path": "img_854.jpg", + "sha256": "056735193bef649accec68f07849264b8cf631c298ed459fe62694268ee8ba98" + }, + { + "kind": "file", + "path": "img_2403.jpg", + "sha256": "5223a4b1a2b55d2cade90fc863bbc2b188d33f29c550a219c41340bb252354c8" + }, + { + "kind": "file", + "path": "img_4072.jpg", + "sha256": "76dc77b7689672d2b5a7c3550cfd3e9a7c9f7e1acf2023d0aa23ef1164c758fd" + }, + { + "kind": "file", + "path": "img_2417.jpg", + "sha256": "4f84838d10b3d8f9cc86f893f3e18f6a8449e53dde7de70a398c6745c19eef31" + }, + { + "kind": "file", + "path": "img_3709.jpg", + "sha256": "846aff4dd9ed5b44d9e68172449df3c096835fb7786958e99ac7521701e1dc17" + }, + { + "kind": "file", + "path": "img_4066.jpg", + "sha256": "64cbd904e169c672845bbd5fe2530bb9f80710951a07b85aadec2776a85a38b2" + }, + { + "kind": "file", + "path": "img_1678.jpg", + "sha256": "430d5971cb0ce09c679c502eefacd0d3de6b72fbeefbad590383191113ba129b" + }, + { + "kind": "file", + "path": "img_4700.jpg", + "sha256": "4de35e475785cb9fc2303d3c89d9a051f4a76cfa8d5d216e83143ce9e7442b4a" + }, + { + "kind": "file", + "path": "img_698.jpg", + "sha256": "c52b1da9d26e6ff97fdf3a349a2f4732f504e69765a2b752cc819e4910ebc962" + }, + { + "kind": "file", + "path": "img_2371.jpg", + "sha256": "c3eee71e866eb7ebfeb92b5b06bb0900f43901eea5f4a560c97ea2d2c4598ee6" + }, + { + "kind": "file", + "path": "img_840.jpg", + "sha256": "cd62d86df0e4925a52802b92e8f98860cf52d4e9ed9a19ed9574370d5259d204" + }, + { + "kind": "file", + "path": "img_4933.jpg", + "sha256": "3bc8e3b53b7a2e4f15b0d9b347b4623197f6a8c819b2bebdf1ba57e7f3288a71" + }, + { + "kind": "file", + "path": "img_673.jpg", + "sha256": "e2137f233a0a4b1a3e3df37aa8f4cb34442d5134a5a5cc0202ec02096628194e" + }, + { + "kind": "file", + "path": "img_3084.jpg", + "sha256": "170d142eb5aadfdda2041e7192bc680397fd1ea80c4186ebac77bf15b1ceb4d9" + }, + { + "kind": "file", + "path": "img_1693.jpg", + "sha256": "c30d175aad2e580f19cecb675c7a19660f4e945b54f51ab741aaa8d01372041b" + }, + { + "kind": "file", + "path": "img_115.jpg", + "sha256": "5470f777c5bfc1a537460ca5c09692d82f0c0f06b596828f41b811b09ee8ff00" + }, + { + "kind": "file", + "path": "img_1687.jpg", + "sha256": "17655e924212364e2ee25f08091bbaa70b9eb7357b4ab1ea9c9408f64edab05a" + }, + { + "kind": "file", + "path": "img_4927.jpg", + "sha256": "fef7e20e2082773aadcc5a894f530c1998b43b36bf937de7f46052111f729c6d" + }, + { + "kind": "file", + "path": "img_667.jpg", + "sha256": "4492dbc03726689ab9e18bf95a39eb2144e96b3b9a9912a3915965d9e6871efb" + }, + { + "kind": "file", + "path": "img_3090.jpg", + "sha256": "bab8c9dc06f5443cc9053af17faf9cc4126569d04e274c5634c0dfa7890d98de" + }, + { + "kind": "file", + "path": "img_1877.jpg", + "sha256": "6b7e791bfc331a6a88430a3f41bbe7c22d5e2316a568e9dce3d1245165a6d51c" + }, + { + "kind": "file", + "path": "img_897.jpg", + "sha256": "49db6edda50cd910a8dd53c991185472ee2b14bdd8b99aaadf7a89324145b13f" + }, + { + "kind": "file", + "path": "img_129.jpg", + "sha256": "2803e8481bc264e3a56b1fd45543d2eb956f36d7607e1e0f128d8f1270669f28" + }, + { + "kind": "file", + "path": "img_3912.jpg", + "sha256": "70a22e99e532aade76adda70dedbd8c1d42503925fcc9f6d0748cf635e5e91cf" + }, + { + "kind": "file", + "path": "img_883.jpg", + "sha256": "0bab91742c7c3a2af32401c4f49cceba990d78eb70899c0d60317bdd4b2ece98" + }, + { + "kind": "file", + "path": "img_1863.jpg", + "sha256": "391a666e1dc8c169deaad8cb28f6f65d7664877154252b3a92a4800b014d240a" + }, + { + "kind": "file", + "path": "img_3523.jpg", + "sha256": "8302b036e01b1a1c93b38a67fca594581f707456d47a8c5f1f8395f47e908f49" + }, + { + "kind": "file", + "path": "img_3245.jpg", + "sha256": "a3c77a70029415f85be76388bec2d4d3291b4d6be630170d74ffcdda2fd0d50d" + }, + { + "kind": "file", + "path": "img_1452.jpg", + "sha256": "bd5255f731aea618d575f996f2dafe47c26fb59f4fb153248fb249f3b190c8d2" + }, + { + "kind": "file", + "path": "img_3251.jpg", + "sha256": "27c8a396dc19b44731c17a7b6090cbeb1e02438120a7084f927a642cb3bdbc16" + }, + { + "kind": "file", + "path": "img_4258.jpg", + "sha256": "a5d538d9717c5c3ba43afd3402ef30770f8e56dfd46c8b7455fe1ff6daf86b03" + }, + { + "kind": "file", + "path": "img_3537.jpg", + "sha256": "0bdd1ab74e752bf113f26ffd227a1964eeebc2a66641a556145e6e9f37963fb3" + }, + { + "kind": "file", + "path": "img_4270.jpg", + "sha256": "d44af8c254ecd77f8ca7992e7eb94e09bbdc21d9a865f61650a0869b1f88e7db" + }, + { + "kind": "file", + "path": "img_1308.jpg", + "sha256": "cbb2770a31ccdbfe842460e69c99045c63fb386f35ec2a195aaeded00c5e4639" + }, + { + "kind": "file", + "path": "img_12.jpg", + "sha256": "374d33ebf4bfa641553827db233f4dea63d96c40dabe572f23bc9a8d38f008c0" + }, + { + "kind": "file", + "path": "img_3279.jpg", + "sha256": "a51b7ee9dc9ea23593449529465e57988fb1bf7759692990f781977400b6adf0" + }, + { + "kind": "file", + "path": "img_2173.jpg", + "sha256": "65f2387d869a400c0dfc3e5137866a3ebc2dcaaed4447bd5ed1cee9c2d0d06a3" + }, + { + "kind": "file", + "path": "img_4502.jpg", + "sha256": "d9d5ca9cb9f53826b01105a76c0e7f39d31ef3fda0a740db929fd771437eb7f9" + }, + { + "kind": "file", + "path": "img_4264.jpg", + "sha256": "c2915ef3538c36e944922a9fd2dbca7afd9c7b95019b37c91c6787a37633d5bb" + }, + { + "kind": "file", + "path": "img_2615.jpg", + "sha256": "44ce67dc9e35ea2931f5ad652891ec7a93e55ebae67a495f5de080f1a841ebec" + }, + { + "kind": "file", + "path": "img_2826.jpg", + "sha256": "912e03f5bc2e48c5e3bc719738d890a58026a57ff1912b89f544f9f12a5b23d7" + }, + { + "kind": "file", + "path": "img_317.jpg", + "sha256": "46309f766c29e3d8895d4c2cffb42080093409bdd04c922f5425d2c408e305c0" + }, + { + "kind": "file", + "path": "img_1491.jpg", + "sha256": "6c64a21b626d3f8064cf12846b7cfbb3a375dee08c0e09da6cb17c588ce57e71" + }, + { + "kind": "file", + "path": "img_471.jpg", + "sha256": "c821758962a776a94701bdffb332bcc78093d48e2d3dc637214d7b3e5e05a302" + }, + { + "kind": "file", + "path": "img_3292.jpg", + "sha256": "7acd35cae762d81adf9b2e6e5c46617569dac92f1e246fde2818663a1171720f" + }, + { + "kind": "file", + "path": "img_465.jpg", + "sha256": "520ef94a096da000a93903b4ec29c7c44a143a7a47f9983cc50bfc2c4f92f3ca" + }, + { + "kind": "file", + "path": "img_1485.jpg", + "sha256": "fc7390a39e67f795ac04f791b27e58bbff5cc9a1126aea1cc6a9f6473fbda230" + }, + { + "kind": "file", + "path": "img_2832.jpg", + "sha256": "ca46877c00c8124885dd738154abdfc8c07dd53ca0580cab49b901103b616416" + }, + { + "kind": "file", + "path": "img_459.jpg", + "sha256": "29ed02897d567f680c8c3819080159d3aeedf38475f37ec690c7406aaa8ea21d" + }, + { + "kind": "file", + "path": "img_2836.jpg", + "sha256": "e231f3cab865a2d414ff78a48519a56f9004f26e1e4a3dbe92f3297c78e3462f" + }, + { + "kind": "file", + "path": "img_1481.jpg", + "sha256": "b4eee136de8dca5a1d50d1dcff475bc8a410e430c1356cf89aacd2a8ac07bb6d" + }, + { + "kind": "file", + "path": "img_2188.jpg", + "sha256": "662172e5025157f2bb226682831a38bda4807165278c18a04b4ae0b2501bdbb7" + }, + { + "kind": "file", + "path": "img_461.jpg", + "sha256": "9118a4ec82e9fab7965d6e3d4a45e1e76abc9f129e7d67b1759fa08e6cdfa999" + }, + { + "kind": "file", + "path": "img_475.jpg", + "sha256": "8ce085c2d4a947d525621b64ee229956130fffae9b871b961f4d236cd5d892db" + }, + { + "kind": "file", + "path": "img_3282.jpg", + "sha256": "047c67c2291cd5dd071e43d09b5ea827dd91516fc8190c27a7610b98f38b210c" + }, + { + "kind": "file", + "path": "img_1495.jpg", + "sha256": "f239294f841dc10800407bb8d466132f7b0681301ae83a04c3814e884dd1d793" + }, + { + "kind": "file", + "path": "img_313.jpg", + "sha256": "3be44f1ba16ee269a25e9db35361a748b6bc8528fe58fe2625bad9e8cdc07c3f" + }, + { + "kind": "file", + "path": "img_449.jpg", + "sha256": "2689b07563e3b9bb37a9a5224eec2c92d8fc30fdcd0cf45d263bb292f2297e36" + }, + { + "kind": "file", + "path": "img_3533.jpg", + "sha256": "2f443c01c9fb45979005810a8f2a7f8e6762191f03cddbba360e3fd4ecd27e31" + }, + { + "kind": "file", + "path": "img_3255.jpg", + "sha256": "aac462c268fa3012454109212a61fae68ab1e14f5b61489b379160670817a610" + }, + { + "kind": "file", + "path": "img_1456.jpg", + "sha256": "375af7965786fb208bc38f3618c8b8ac07e83182035e0f9c4f5cbd38b0e69165" + }, + { + "kind": "file", + "path": "img_2639.jpg", + "sha256": "7ea576130527db836e4d28e13a9b68cc5dbda5e068bd6d70eca0706b8c26dfd3" + }, + { + "kind": "file", + "path": "img_4248.jpg", + "sha256": "9de904a1b2ad76bb3c25391607cec591e843dbf1447fda408029b30280caa031" + }, + { + "kind": "file", + "path": "img_3527.jpg", + "sha256": "e73a6511f959c93a529493027abd0ded7d7716e11b04f0716cc1b0004888f63f" + }, + { + "kind": "file", + "path": "img_1330.jpg", + "sha256": "5d03744aa8b5e3eaabfebd720990ae1fe306492cb9ed12d6d0d1b536ab75e8c9" + }, + { + "kind": "file", + "path": "img_2611.jpg", + "sha256": "6ff9c71762326559d6916bf595d13bc39952b31bfd5a10f537e596ee23d93d7a" + }, + { + "kind": "file", + "path": "img_4260.jpg", + "sha256": "06d12a3e7e09703e45902fa8e518054818211c72c69f6029513ea701b417abc5" + }, + { + "kind": "file", + "path": "img_1318.jpg", + "sha256": "5ae6cfacd9fd57d50ed6c4834f26b440cbbdc5311c5d30e040a5adeff20ae7ef" + }, + { + "kind": "file", + "path": "img_3269.jpg", + "sha256": "9ef825b7963ba23ecdb2fc59483dc5a115fe14c9b62b39b80b423999c51438a4" + }, + { + "kind": "file", + "path": "img_4506.jpg", + "sha256": "0f75690f22740c334d0769e25a4296b15cde150ef48a7715a2b35b4e7f311115" + }, + { + "kind": "file", + "path": "img_2177.jpg", + "sha256": "183bcb9f174ea5f699ead64fc306fd1062a65f809cb6b6526fb7d6b591a70b54" + }, + { + "kind": "file", + "path": "img_4512.jpg", + "sha256": "7e917f4903ba939f86f18d757397ad1614a15a73209a88574a007e34ba5cc8b3" + }, + { + "kind": "file", + "path": "img_16.jpg", + "sha256": "4c621ea232203baf3855e1ecef9adc1e82a5f46aa67792f78478023ad6a2eba7" + }, + { + "kind": "file", + "path": "img_2163.jpg", + "sha256": "52ef78775ade15533d0f4dc969e08a3c0a0e4f7f82ac04be82484222962a0032" + }, + { + "kind": "file", + "path": "img_2605.jpg", + "sha256": "91103750577ed6a34178cd707ab442978b11667dbef48b0af82119b9f25086e5" + }, + { + "kind": "file", + "path": "img_4274.jpg", + "sha256": "375c8ed900273beab45dcf00b1a5eeb57c06f6227df5942f865e7530cad2b848" + }, + { + "kind": "file", + "path": "img_3094.jpg", + "sha256": "4de0d1fc2f1a1a0ef62a25454efa911b99afa75c42a028477e9f7714518daa17" + }, + { + "kind": "file", + "path": "img_663.jpg", + "sha256": "f4fdd717f0769788dc63b5b20bd2801221794f58fd1d5c458f59088288c7bfb4" + }, + { + "kind": "file", + "path": "img_4923.jpg", + "sha256": "6fcd0a1d38a772ea4754f6e6a8c93f91307f65195d6127073feb99c457c63c69" + }, + { + "kind": "file", + "path": "img_1683.jpg", + "sha256": "a8a4974ee637d34adecc6fb92f564e3193697ad10d306bd998b9d98b6a4f7403" + }, + { + "kind": "file", + "path": "img_105.jpg", + "sha256": "7bf7681bc14e71f65ee0569b6982bd70aa2716c594b918d1b8dc5b3cafc6814c" + }, + { + "kind": "file", + "path": "img_111.jpg", + "sha256": "46e2abbd8e930c871318858c40bb1496adaa6d1ab3fff5e9cc6db6bd828d605d" + }, + { + "kind": "file", + "path": "img_4089.jpg", + "sha256": "83bde88553d52bf5c1dd730569dced772310fadcdaa484c9bb622ab7ac6723c3" + }, + { + "kind": "file", + "path": "img_1697.jpg", + "sha256": "3172b4d0ca9da5c86f5de1afcbac2d2455fb0883a131015fe41359a82f39ad7e" + }, + { + "kind": "file", + "path": "img_3080.jpg", + "sha256": "551c0d3f1c748cbc8bedf0e3495cbfbb4b353a4cd302873fee9bfdfb42e8c182" + }, + { + "kind": "file", + "path": "img_677.jpg", + "sha256": "ddab0c2be3adb0a011079802f17eb85f10615eff2c88576f1d50531238122867" + }, + { + "kind": "file", + "path": "img_4937.jpg", + "sha256": "b999460a3821dd281384df4c404bd6b82a992058b1f87e3435fc38d5a97ab641" + }, + { + "kind": "file", + "path": "img_1867.jpg", + "sha256": "a60cef2924d2eb28ef3aab6cd9ec3a019cf5a6be32a6283d0e7584c56dc8b963" + }, + { + "kind": "file", + "path": "img_887.jpg", + "sha256": "1004be0e26e6fd65020a60a350a991f4ea7d600c9e207a8be5e82177a4174033" + }, + { + "kind": "file", + "path": "img_3916.jpg", + "sha256": "ab9918cf30193ee4c8398eafcb7d76ef74f4ca8728558960040c3b74ddb8cde4" + }, + { + "kind": "file", + "path": "img_139.jpg", + "sha256": "5a314c1e5c0f3c219807004069c3c682fb05eea7524d174b82d7b0948d220ff3" + }, + { + "kind": "file", + "path": "img_3902.jpg", + "sha256": "85d6daf24eae12d8102f5cb00828241757ba6a984872394974bc0155e1b0977c" + }, + { + "kind": "file", + "path": "img_1873.jpg", + "sha256": "480068f28c518bc1e2c4c187450d3376817787c2b96aa96b785fa5c95525744a" + }, + { + "kind": "file", + "path": "img_1898.jpg", + "sha256": "d4c02b1f5cd6e837f7073b06393987cb98238b0e095742b80ffb3bd0675f3bd1" + }, + { + "kind": "file", + "path": "img_1640.jpg", + "sha256": "70ad36bb0d1f358e0ca9de292d8498945d7057d33cf5882983b85666e4a0f463" + }, + { + "kind": "file", + "path": "img_2349.jpg", + "sha256": "d54ac1eb6adbb43aa9c646ab6f90ce4f6c65c9df515ede9e229c7b001fef31b4" + }, + { + "kind": "file", + "path": "img_878.jpg", + "sha256": "321f7db3dc75fa42c2acf478598050d24ed2f36f1b2fb902a02cdee044edd2ba" + }, + { + "kind": "file", + "path": "img_4738.jpg", + "sha256": "77e8380487a64f96c344d2b6d42cf17c082181b4c0f8afa58325486965e4729e" + }, + { + "kind": "file", + "path": "img_3057.jpg", + "sha256": "9d2f571092847df37c353d7687f0bdf3b63bdbbf31b04e58aac4766db8e7859f" + }, + { + "kind": "file", + "path": "img_3731.jpg", + "sha256": "86b8cb08547a7019d32c6349c334d0a9d893e3470ca6ed31a7d3897046e7c464" + }, + { + "kind": "file", + "path": "img_1126.jpg", + "sha256": "d644b67ca0212d3ccb373a1b6045ffcb0c9ff796ad238e2b72cc234c697f1f24" + }, + { + "kind": "file", + "path": "img_1132.jpg", + "sha256": "d5817becf264ddc3e7bafc23eca053e4c7798b5ad73cf4423671530a2d4de338" + }, + { + "kind": "file", + "path": "img_3725.jpg", + "sha256": "6f6cdadecdd0a5d1f5b53ae29c1675e0eed6b1271c17f3e396c5236f9ddefc59" + }, + { + "kind": "file", + "path": "img_1654.jpg", + "sha256": "9eee731e6bd86b0928ad64d000c8329521566a876ea048192ed2a76215921a8f" + }, + { + "kind": "file", + "path": "img_2375.jpg", + "sha256": "b9faf9b16376515a53464b79be16f0e31ae8387c2aa1ba278640759fa29c9131" + }, + { + "kind": "file", + "path": "img_844.jpg", + "sha256": "b1e0711d500077b96ea5682c7bb3076c79f1a004c1c27ecdb8180d84d8e6fbc3" + }, + { + "kind": "file", + "path": "img_4062.jpg", + "sha256": "9e45a6c5601e00f0c50b26260d0d410fccfc8f7e5d8e85f6980464f4145559de" + }, + { + "kind": "file", + "path": "img_3719.jpg", + "sha256": "2f2b6c463a7dc29afd0016c6643ac962a22cfe65dbdabc0966738fd9ec7789f2" + }, + { + "kind": "file", + "path": "img_2407.jpg", + "sha256": "c482e17746b7170eee9b891b66722dc3361f6bbcd221b08f53410c72bf6a54aa" + }, + { + "kind": "file", + "path": "img_1668.jpg", + "sha256": "716b4928ba3676100134eae6c4fc00c612863e44787f0349c23dcee2a98f7a98" + }, + { + "kind": "file", + "path": "img_2361.jpg", + "sha256": "21b9141004cb6c5c3838562110e0f92822b5b73e332d1a52d0836ebd1da70c4a" + }, + { + "kind": "file", + "path": "img_850.jpg", + "sha256": "72bf383332836eb9b797d6e40e1ab9e04ce8d65f8e221c12ea2488a64a47bb96" + }, + { + "kind": "file", + "path": "img_4710.jpg", + "sha256": "a4bbc0925a22d362f6d3f99053bd9bcbeafbfa359c9fd0c7dad8ffe2d9b694ef" + }, + { + "kind": "file", + "path": "img_688.jpg", + "sha256": "63102a714cc1d4562c7f7fbe190a5da2eff2eaf4e59522949eb9a50bb26f7210" + }, + { + "kind": "file", + "path": "img_4857.jpg", + "sha256": "de5a2d8c3a172fff18fcd35d76fc51d52297239685a41133bf0f647c15ef5397" + }, + { + "kind": "file", + "path": "img_717.jpg", + "sha256": "eb5ccd5035fef095b2054755e4a29b95a83195f0cdb38afc854e27d4d23d7d1c" + }, + { + "kind": "file", + "path": "img_1091.jpg", + "sha256": "b684d59896f21dc899e0c1ab70016d38c19c8ced4f9c596bfd9ddf20dfdb3e43" + }, + { + "kind": "file", + "path": "img_3686.jpg", + "sha256": "9635a5ad34ba5d13f6a386088049eadc77ea5267b6ace0aa1ba5cb77068fe07f" + }, + { + "kind": "file", + "path": "img_2598.jpg", + "sha256": "06df7d77989eb72c1b52fb4da3050b841288388c5cfc36ef2523081bb134161c" + }, + { + "kind": "file", + "path": "img_3692.jpg", + "sha256": "331baa214760ac6972fa691553e0c9ab971e22bd0219e088a5916c1c9d2f1aaf" + }, + { + "kind": "file", + "path": "img_1085.jpg", + "sha256": "8c2a0b1dd4df353ebfbad4ccfd3adc06a847d20b05be6e8a5cb80353e225f0e3" + }, + { + "kind": "file", + "path": "img_4843.jpg", + "sha256": "a14c9cf19a512bb84f2ead64f064b03a6fa6ec5dd0ce0ccadfa07e8685a30783" + }, + { + "kind": "file", + "path": "img_703.jpg", + "sha256": "d78271310e3a716ab2e3907bfdf68d64f986c34c106530c057e866a6839540b5" + }, + { + "kind": "file", + "path": "img_1913.jpg", + "sha256": "bfd1ffbe421406ac688aba130b145a86fc6b132f9cc2eb8b4164c37edb99924d" + }, + { + "kind": "file", + "path": "img_3862.jpg", + "sha256": "fb7898a7c4fd4f8796e44334307c0f47da140625a25a482fce750f7116b7cbd2" + }, + { + "kind": "file", + "path": "img_3876.jpg", + "sha256": "513b29ea5703779db0d15feff3cb55f162535fcac286a0d3d4492e9b6e3ef376" + }, + { + "kind": "file", + "path": "img_3123.jpg", + "sha256": "8f157c2b4a31c2744bd4d10bbd88f37456afa8634f404f4d8b35f8cea7f6af59" + }, + { + "kind": "file", + "path": "img_4894.jpg", + "sha256": "fbd5154fcd56c182e8b9cc73d3e348ba9f3de07259cb44a47c7ff0584751194d" + }, + { + "kind": "file", + "path": "img_3645.jpg", + "sha256": "ffd248db273cbd759e452470e9e1fe61ef87c07ffd5936917261ab8fe7696feb" + }, + { + "kind": "file", + "path": "img_1046.jpg", + "sha256": "f30aab3415a4ac291bf4fd2fd0dbe2dbd7865190fc27b4d8b94a857c5915e581" + }, + { + "kind": "file", + "path": "img_3889.jpg", + "sha256": "2629a27b67594c195ba97f3bb8a4d456f6ec2a7927c45e03497741f1212a280f" + }, + { + "kind": "file", + "path": "img_3137.jpg", + "sha256": "7ed39ea17eb4d5d44bf74250461d5d13b82075aa862f11e7871f1170a661500f" + }, + { + "kind": "file", + "path": "img_4658.jpg", + "sha256": "3b97984d0d1bb69e775b1a1085a8bc6ddc04cb05bbd09ee337cf9e0930103054" + }, + { + "kind": "file", + "path": "img_918.jpg", + "sha256": "e2e7b8ccc5af4c10a9e6abb6b0b80805832af2277f9316fee6172376ae3fb24d" + }, + { + "kind": "file", + "path": "img_2229.jpg", + "sha256": "1b30e786e4491cd50bc345d4122f2edbbdea3062a91f29f6913a04f75ed666a4" + }, + { + "kind": "file", + "path": "img_1720.jpg", + "sha256": "b40ad0a2e882225b53ab7e25671c053e0976edc0b15d4d739a07fc8741bff551" + }, + { + "kind": "file", + "path": "img_4670.jpg", + "sha256": "57c21ca3807a0a81a95d2ef395dfe6f494f9f0b3885da8717ef394045381967a" + }, + { + "kind": "file", + "path": "img_930.jpg", + "sha256": "92d5e2035eee379d0bfa108907a06294495dede74a6dd5ee4daf4014e9d1e25c" + }, + { + "kind": "file", + "path": "img_2201.jpg", + "sha256": "84d6890441e069fef9a5771203a1690748474ad0d93df60a946cb00f18a28a8e" + }, + { + "kind": "file", + "path": "img_1708.jpg", + "sha256": "fe39bc54eaf98bc26b47ef2a0e5fd812bb2a58166989efeef6d1696a52ced164" + }, + { + "kind": "file", + "path": "img_2573.jpg", + "sha256": "c9c674c29f876e080786b53808d61585b31f8db8191d302bc11454720f126cec" + }, + { + "kind": "file", + "path": "img_4664.jpg", + "sha256": "5f3a2833abe3776a314991273e5d1e7f5b061feb5b2a68fc446ea6f1a008d2fd" + }, + { + "kind": "file", + "path": "img_924.jpg", + "sha256": "1fbf1c7f57551a262c3ce1b0944a23ece171def7e90f397fe642467f33fa61c0" + }, + { + "kind": "file", + "path": "img_2215.jpg", + "sha256": "74138d01640821dc232b22aaf2e18c74ac5ccb23368ae8fb5784649241d633f8" + }, + { + "kind": "file", + "path": "img_273.jpg", + "sha256": "a2381880111a2ebe0db1535f4e18b60da303cff98e8f7bad97b4497f750dbbaf" + }, + { + "kind": "file", + "path": "img_3484.jpg", + "sha256": "761ca647fc472aa247d6fd0444a3d9dfef022bee2b3be2d462c2a2f2d2fd6de7" + }, + { + "kind": "file", + "path": "img_2942.jpg", + "sha256": "14c7713ce08881800fa3786dabc53a56e1fb319d10fb4ba36384ddce56587c35" + }, + { + "kind": "file", + "path": "img_1293.jpg", + "sha256": "082d46f57b3060b2cf2ebaa5c6d42e2d359446f3521bae9c80c79820078a0560" + }, + { + "kind": "file", + "path": "img_515.jpg", + "sha256": "fe3b0e557bd44ceaf15405989fdb8e18f78e871a2a27a3f74f81b89842c5a995" + }, + { + "kind": "file", + "path": "img_4499.jpg", + "sha256": "2099a6da47b276ab2516f74849895055dc65054041b05afd443602ee6397464b" + }, + { + "kind": "file", + "path": "img_501.jpg", + "sha256": "d789228456c1ce03e5298cafdf510a3b40c4806bf25f89017955cb28ba21153e" + }, + { + "kind": "file", + "path": "img_1287.jpg", + "sha256": "1c8cecfafa143ad8931cd28086dbee72c346aa6657d9e3763cb9b6622f6d4d15" + }, + { + "kind": "file", + "path": "img_7.jpg", + "sha256": "277c5a5f48a15da859693f5d014295f40fe4e3750c259028d7a74db9cfc03f0f" + }, + { + "kind": "file", + "path": "img_267.jpg", + "sha256": "78decee8b978e616b24d67fb4654efca5ba7c30b228072dea044a736ec196e40" + }, + { + "kind": "file", + "path": "img_3490.jpg", + "sha256": "67f63bccd0e3a951ffa318bd2bfc22ce73ac15832e948a39e80e92835b65f1cb" + }, + { + "kind": "file", + "path": "img_2956.jpg", + "sha256": "5f37e84098219f01f5918bddaab00f073ad9fdea0f8eee924822966770bfe925" + }, + { + "kind": "file", + "path": "img_529.jpg", + "sha256": "64385744fa6fccd5031c94f6d018d34095ec63f515fd096e41677d3b537f2101" + }, + { + "kind": "file", + "path": "img_1250.jpg", + "sha256": "6b8a2c454c53e81a4484eba729de3cb579a20abbfbbb9292f11335af9df5904f" + }, + { + "kind": "file", + "path": "img_3447.jpg", + "sha256": "5e8d8810c26358e153ccdec8833b680e1577f78ac8c806bb687ff9c1a0198d7d" + }, + { + "kind": "file", + "path": "img_4328.jpg", + "sha256": "7f43df585797a132b8cc250ffe5af073ad66dce631a4f0c061210c5cbb792d79" + }, + { + "kind": "file", + "path": "img_2981.jpg", + "sha256": "6b80ca1ef5cf0c202416c9894bec19a79cad4f9d0869c1c615733ce5d5aa3ede" + }, + { + "kind": "file", + "path": "img_2759.jpg", + "sha256": "ccec7fa778a8b575f47bcb66073e80f5b624686a72983c6c1b7ebd3f31170e0b" + }, + { + "kind": "file", + "path": "img_3321.jpg", + "sha256": "b38b6a2adaa3b7dfa5e1ce6156d1e2324b6348dc6c81be6e938d0e4b68a3cde7" + }, + { + "kind": "file", + "path": "img_1522.jpg", + "sha256": "8f63e14db83bc1d516b20051aa53214c36fc157663ec4d3cf112780406dfa7c0" + }, + { + "kind": "file", + "path": "img_3335.jpg", + "sha256": "09f923de73190ace4635656114151d0e4c28fb12fc35bda880758e8df87f3a91" + }, + { + "kind": "file", + "path": "img_3453.jpg", + "sha256": "3c5200eaf9c2632655b2425939256aa261005ba8acebbb0f752738f974fbafad" + }, + { + "kind": "file", + "path": "img_2995.jpg", + "sha256": "88f3be64968b85fbf07204006da21904a8acb72658f16eea2e3220ff09399735" + }, + { + "kind": "file", + "path": "img_4314.jpg", + "sha256": "d1bcf3edec008a5610c8cf60908728ced6f847cde317d4694b5f87302f58893c" + }, + { + "kind": "file", + "path": "img_2765.jpg", + "sha256": "729325b7b7b1d26c7e0de9971357d7b1ea7429a6d13e940ee70aad3c42054ab1" + }, + { + "kind": "file", + "path": "img_2003.jpg", + "sha256": "05be7fdbb124a4265e020c105e0df1a9673522829020694ecbc36c6f5259e0d5" + }, + { + "kind": "file", + "path": "img_4472.jpg", + "sha256": "b97f8746ca6181b5f6c0bf455b0ecbfaf96d14ec79269be22e0eca5089621eab" + }, + { + "kind": "file", + "path": "img_4466.jpg", + "sha256": "8bfe94189d680fe8dfb1e1d2a087af82b0dfd7009c905504d0d2655198c762af" + }, + { + "kind": "file", + "path": "img_3309.jpg", + "sha256": "d0174ae263a6a159f3106bd621722625a252f8673bbda9459958aab6342edb18" + }, + { + "kind": "file", + "path": "img_298.jpg", + "sha256": "5624ce92124eeb1d074482579e7c89515203b9eee77a73378c85e1afff3ce029" + }, + { + "kind": "file", + "path": "img_4300.jpg", + "sha256": "11bb523fd56e84ee53d029ad146facfa58d1c3e0490d80917168c5070fc54ebf" + }, + { + "kind": "file", + "path": "img_2771.jpg", + "sha256": "1d7cf238f3955cc3b1bef9f4bbedbb7833e5fc6cb7c9d9835db467635cfb28ca" + }, + { + "kind": "file", + "path": "img_3308.jpg", + "sha256": "3811292b460307fb963f014815326a321c55946f1e5990c91eebdb3d4d73196a" + }, + { + "kind": "file", + "path": "img_4467.jpg", + "sha256": "6eae13eca4167bcedb1f16f78152d656a4d3f863ceb1ec460e2c8ce4f90b4312" + }, + { + "kind": "file", + "path": "img_2016.jpg", + "sha256": "c37371932bebb27cd57313f66fda33c2c0fb16dc870f8d0ae5a089eda52c2a61" + }, + { + "kind": "file", + "path": "img_2770.jpg", + "sha256": "8758cca57dc5e24735b457b68dec35237c222f3d382b8053dfa070ec6370a928" + }, + { + "kind": "file", + "path": "img_4301.jpg", + "sha256": "e39ac7cc2e45d8c7d3f5ee824e2060ef496118a1ab332a450504b9ccd0caf8a7" + }, + { + "kind": "file", + "path": "img_299.jpg", + "sha256": "cca3376d8075e937092af645c409d013316a63cbabba0c51a5538e1cb143d192" + }, + { + "kind": "file", + "path": "img_1279.jpg", + "sha256": "014122c98d84466386f3e85aae840c41c201cd1bec9306cec001823776716d63" + }, + { + "kind": "file", + "path": "img_2764.jpg", + "sha256": "6c9bf314aee076acaf7af759b21edca9facd0f40bc1b99df83f71b3d3b9b4163" + }, + { + "kind": "file", + "path": "img_4315.jpg", + "sha256": "08e738d0eca93ecb33451cb4eacbe97c0ca9c53da7b370af4d8c1983f31f8030" + }, + { + "kind": "file", + "path": "img_2002.jpg", + "sha256": "360553a8d462c67340fbced6b7c800b446e6e0a7ef51cd84433b50469839ea39" + }, + { + "kind": "file", + "path": "img_3334.jpg", + "sha256": "2ff90c3bcbc996ab7cb48b8d3ff7dd08a900c4ea75ea9db6f2482c0aa566b568" + }, + { + "kind": "file", + "path": "img_1523.jpg", + "sha256": "b5b7efe0b2b7b4d9eb9d4cc6f40fc14109b02a932c79519e013b2cf1c3352a94" + }, + { + "kind": "file", + "path": "img_1245.jpg", + "sha256": "ea3c372f430cfb78f5283ad52ecad7ad3fb18a7a6c5695d8149b82ca54875f2c" + }, + { + "kind": "file", + "path": "img_2994.jpg", + "sha256": "13fd7b684f7729e8e1a3677c05207aeb61bf87f87138ac82863a2d8b4b27a30a" + }, + { + "kind": "file", + "path": "img_3452.jpg", + "sha256": "b3e7cb1c949ad61eb11cb462cd0977a9358ad5ab81eafbe0bc62f5da84bd6bdf" + }, + { + "kind": "file", + "path": "img_2758.jpg", + "sha256": "47fb99bc2bc592260412665d0395079ee5d68101d0707677324dd71a890e8807" + }, + { + "kind": "file", + "path": "img_2980.jpg", + "sha256": "e6d77225611baf70c4c8d1ca7e4d04a475da1f85958f91ee938644d61baeec9b" + }, + { + "kind": "file", + "path": "img_4329.jpg", + "sha256": "6ef18bb04febad84369f4b17e27f6866b36ec5ccccd17464f3753c664cfe2755" + }, + { + "kind": "file", + "path": "img_3446.jpg", + "sha256": "9b9fca4806a3ffef140de4f1ab0ef6d835ec39576a63ed16e42d61c9b9a77d9f" + }, + { + "kind": "file", + "path": "img_1537.jpg", + "sha256": "da9e0b5f890de16f1e42793163f0d6d3dccb709c0476fc349f984f44dc5c76ed" + }, + { + "kind": "file", + "path": "img_528.jpg", + "sha256": "5b87af3bb3465154c9f99d6165a83c17ab61bef90783a92154b13514d965a365" + }, + { + "kind": "file", + "path": "img_500.jpg", + "sha256": "cae4d51a9da67dbda3078242c82563d5aab1a1b7a4037a33454d21dc1decfc0e" + }, + { + "kind": "file", + "path": "img_4498.jpg", + "sha256": "f6b8a54f32524cf37984ae2a04895b1c776ad4ada1a26f99fcd4bf1759fc1657" + }, + { + "kind": "file", + "path": "img_2957.jpg", + "sha256": "57ab8d0ec2148d83ed91c51adab619920cfc624dfe047f2e6344480a2f99cdd2" + }, + { + "kind": "file", + "path": "img_3491.jpg", + "sha256": "490bff6ea0cb814e3c25ea7c237d86dae6ae2ff1d3a9afc5554dee9599bd1a05" + }, + { + "kind": "file", + "path": "img_266.jpg", + "sha256": "51d9e59ad9c51c215e6b9afb2db5eecdadd33fe4ec5df3086cc8c2dfd8bb959c" + }, + { + "kind": "file", + "path": "img_6.jpg", + "sha256": "4e0bc00f2c2b105f853a7ab45bbbd45d92eec46466fb740c0d94159982e04a46" + }, + { + "kind": "file", + "path": "img_1286.jpg", + "sha256": "5ed0b18994bb90138a93e7df60078de6e0459fde7f7567096f230fd013741608" + }, + { + "kind": "file", + "path": "img_1292.jpg", + "sha256": "31932a32b4a5d48b36819bb971dd141a0bc99a47d91b0df30b4dd5b994ad42d5" + }, + { + "kind": "file", + "path": "img_3485.jpg", + "sha256": "93416dca47f6aa462ec0714c0f23c28d173e06dffcb508d694e9b7908c645493" + }, + { + "kind": "file", + "path": "img_514.jpg", + "sha256": "00010bbc1d23e41eb6364945d83f5a5f3009f4986207cc52f0827d7bf248253e" + }, + { + "kind": "file", + "path": "img_4103.jpg", + "sha256": "06fa4d2e956c65f9aac21cf4e4eba817892d38233097eac8d7effc4ca28c27a4" + }, + { + "kind": "file", + "path": "img_2572.jpg", + "sha256": "d6dcfe40e07ff2b31c055242edb7c0b2fcac1f409aa491d0fe3e90a1ee0824d1" + }, + { + "kind": "file", + "path": "img_2214.jpg", + "sha256": "41c5677f478ded3a176157cd35d2a5ec6534321c5fd70888a010328800f9b101" + }, + { + "kind": "file", + "path": "img_925.jpg", + "sha256": "7d729883c2ce79aabd3673cd45eed668cf97f4c52c1cd666f1ee7454804862d4" + }, + { + "kind": "file", + "path": "img_4665.jpg", + "sha256": "25fa5e4668e1df1c8e513b48fb9f0ca456197419d28d3caec9f234902abe47c6" + }, + { + "kind": "file", + "path": "img_1709.jpg", + "sha256": "23c1f6f049ba215ebfa346de8bdceb7dede613b7d397db99c02eefc1823e0408" + }, + { + "kind": "file", + "path": "img_931.jpg", + "sha256": "971bdbbb210a00b5bb1b5e77288772f74bc88a84aa56030d2fffa56403c26168" + }, + { + "kind": "file", + "path": "img_4671.jpg", + "sha256": "75de93f7a2eef260b0d784e9910177199f0ed072eb22088e73b7d9bf04775eb1" + }, + { + "kind": "file", + "path": "img_3678.jpg", + "sha256": "172c26f5828b1f0f3eb39c182e8344e6743a315577c8b1cf35d0871815847f25" + }, + { + "kind": "file", + "path": "img_4117.jpg", + "sha256": "d580ef7d2bee49dedab2c6f2dd40991d5e690ae5b918dbd66c2326e101f1af91" + }, + { + "kind": "file", + "path": "img_2566.jpg", + "sha256": "08cffdc56ab486fdd0129a3e1ecc00d13630b8872cbd8eda2176c17ae6f73a2c" + }, + { + "kind": "file", + "path": "img_3650.jpg", + "sha256": "0c8bbedafed699a12dc7bb45f6f4b4958ef74fa65d2ae7fe5aa646233963795b" + }, + { + "kind": "file", + "path": "img_3888.jpg", + "sha256": "53aabd1d20b036a7bcfff220ce73bddc6db1a391cfd5418d0ae96f5c1fc874f6" + }, + { + "kind": "file", + "path": "img_1047.jpg", + "sha256": "02135bbd54e5b669ab053a7480374507090fbbc30e1256a7d52b6758156b954c" + }, + { + "kind": "file", + "path": "img_1721.jpg", + "sha256": "bcae6b80a0e7fd10044fa6ffc66ceb350316722085ca5255368c37aa29d11b69" + }, + { + "kind": "file", + "path": "img_4881.jpg", + "sha256": "ee7b4844224acaace8e183d5f9f63e418aa3d43d8a4cac68c1f7daeb13d4e385" + }, + { + "kind": "file", + "path": "img_2228.jpg", + "sha256": "b90eedc489e5287a743f334e038135aa5c6b87b93fd19fb731209326f2640048" + }, + { + "kind": "file", + "path": "img_919.jpg", + "sha256": "e6f3c0d276712f855e60eb5d78757abeb91b5119a5473e8474c5c2ba424a8238" + }, + { + "kind": "file", + "path": "img_4659.jpg", + "sha256": "14532e3dd976ec6ab80e1e99c1f845a5c2d46685c0abd8c1a16f6db3fea0d201" + }, + { + "kind": "file", + "path": "img_3136.jpg", + "sha256": "7f85ae73b99a05442127540de452e4e173a227dc7ce9a36c1bcdac7ea39c1ae1" + }, + { + "kind": "file", + "path": "img_3122.jpg", + "sha256": "5446aa2271b16d58ffbd22790cb23c9ebc219ff27dc66e96010de651b80942d4" + }, + { + "kind": "file", + "path": "img_1735.jpg", + "sha256": "a47d86c048291bbf75d4aa8446318a4f681721123481405e80a9993102439858" + }, + { + "kind": "file", + "path": "img_1053.jpg", + "sha256": "7b15ee941f14ba4b2b2e28a64d3c2dda3cac0fb4678942b587d64749efe1bd35" + }, + { + "kind": "file", + "path": "img_3644.jpg", + "sha256": "1243f30748cc4a66bc1f4d975def0baf57406d4f03c2bb74668ba664238d4013" + }, + { + "kind": "file", + "path": "img_3877.jpg", + "sha256": "dc963a3a42d665110ec2df841696f09f5b08001875a1ed3d065c3a6a500471dc" + }, + { + "kind": "file", + "path": "img_1906.jpg", + "sha256": "c256ca24895d46d7fe611f5d5f5b3845a3da5ef16bd0d7d6724de9710898895e" + }, + { + "kind": "file", + "path": "img_1912.jpg", + "sha256": "ee9ee89df5756edf99a4b32ba0b2cebe279adc710154de3688b2506b0348a5ea" + }, + { + "kind": "file", + "path": "img_3863.jpg", + "sha256": "564620f283f03f7a02f7c885046cadc3edacffb06b86fa3c92d7e9877e361076" + }, + { + "kind": "file", + "path": "img_1084.jpg", + "sha256": "8b59ff7144a3b4b306ef6ea4ea01aa773509e8e1e575da70dae6d2d328b83fcf" + }, + { + "kind": "file", + "path": "img_702.jpg", + "sha256": "d4c1033f71c9d7f1541f2a28f7bc499335e8aeeafe49883c0ccd0df6b4f78e6a" + }, + { + "kind": "file", + "path": "img_4856.jpg", + "sha256": "8df17ac09fc53db52f60f5e2f38c85b186f2371ff792be1c81b7baea72057a3d" + }, + { + "kind": "file", + "path": "img_2599.jpg", + "sha256": "8349591a9b45eede9c32aac08dbcf66eebcbff7e09e69083c11e3f884f57236f" + }, + { + "kind": "file", + "path": "img_3687.jpg", + "sha256": "5e3ccb6a3531fc398cf0b556f3859fd43d1cd9cc67610d2941a165fa60107894" + }, + { + "kind": "file", + "path": "img_1090.jpg", + "sha256": "0c22974fc72837154751544eff9fedb1095119e08591250f58c05ad351839ef2" + }, + { + "kind": "file", + "path": "img_2406.jpg", + "sha256": "52ed9c47225fa7a936888436fc7ad5bbd3f382e21bfe976f822144f94bcee607" + }, + { + "kind": "file", + "path": "img_4077.jpg", + "sha256": "94dc218c223822bcfb66278bcd312af68395fb4905d5d0e5fa3b24daf2981fb7" + }, + { + "kind": "file", + "path": "img_689.jpg", + "sha256": "9ce1e0bfe6739876670f69e70709a1d51f01b17e9dbaed676b2a60ad68648def" + }, + { + "kind": "file", + "path": "img_4711.jpg", + "sha256": "5e02a627c7cc055aa1ff5573c560f9b823f82cdded3d6364e14d66cfcdbb4065" + }, + { + "kind": "file", + "path": "img_851.jpg", + "sha256": "473eb85b96d115354dbc03b9417cb34ec696c13b19d9f58db75cbc7cbbf6ce9a" + }, + { + "kind": "file", + "path": "img_2360.jpg", + "sha256": "384e3cbc671e0c0d2be92b9f3cd5f98c6f11c9403ef8ba4c07e2d6a4b2c4a8ae" + }, + { + "kind": "file", + "path": "img_1669.jpg", + "sha256": "c6a6ecb5932f7da3f526beb747c1caa61b73e411d18b038ed51017f47cfb22d3" + }, + { + "kind": "file", + "path": "img_4705.jpg", + "sha256": "a5e13fe0dc6e9c76e34839d80302a6a3dc7fd9822bd1eea8c63adaf2fb3d4814" + }, + { + "kind": "file", + "path": "img_845.jpg", + "sha256": "fd8a698d476e78592f50b40f245a8bccd27c2d32c765576699f49ffd67d556bc" + }, + { + "kind": "file", + "path": "img_2374.jpg", + "sha256": "a021ac067ac94a0f3cd65cde02539d0ee03c4f953251e0f506c316a110cba71d" + }, + { + "kind": "file", + "path": "img_4063.jpg", + "sha256": "f19c0ad2fa0fa8971cb03f91fba8fc672404c73808b4577bb849e37c1eeacb3d" + }, + { + "kind": "file", + "path": "img_3724.jpg", + "sha256": "e3e8f0a51cc9934b7f64e86c3989af0d24583f972d608c2d7913d3a0aee5da9f" + }, + { + "kind": "file", + "path": "img_1133.jpg", + "sha256": "ee82fa67571ef4733811b21a4545cce5c861f72824dfa3a26d2eb95ae224a893" + }, + { + "kind": "file", + "path": "img_1655.jpg", + "sha256": "4625c0006973aacc0763c49c5dee0508d2182d0fc6f9feccfea2df3d347cbebe" + }, + { + "kind": "file", + "path": "img_3042.jpg", + "sha256": "43d4b7bda974936fa9a88faf445e9afa88628a89fffbf8094312172656ed20c3" + }, + { + "kind": "file", + "path": "img_3056.jpg", + "sha256": "cbffcd387dbbeeccb9e0bcceaaa61d2195707b90b75b63ce23ef4254ed8cb4bc" + }, + { + "kind": "file", + "path": "img_4739.jpg", + "sha256": "2a8389e1ae86f9e3a46781daf72f78189ba45b2525183d80ebff23bfeb7898b9" + }, + { + "kind": "file", + "path": "img_879.jpg", + "sha256": "58b6f52cb155275543d8e43997aaa31f60aeaac5fa1d53a8e314abc3fd0dd868" + }, + { + "kind": "file", + "path": "img_1641.jpg", + "sha256": "c3ccbeb396b726b32ccbccccbbe14c79f8a3f0ed049116a55b72bc8d930d2781" + }, + { + "kind": "file", + "path": "img_1899.jpg", + "sha256": "fdbe94f50c8875ef4b48ccaffb03e26e4736c7e3312fa61dc1db525b69a48b42" + }, + { + "kind": "file", + "path": "img_3730.jpg", + "sha256": "fb62fbd4d56dd41be268f12eae02ac7fd60fd8ed4e2bb9825bed83f565ac222b" + }, + { + "kind": "file", + "path": "img_1872.jpg", + "sha256": "a1eaf01acc0002053153a8fbb291a6e894c80335e90169f07f1486e0d9de8e2f" + }, + { + "kind": "file", + "path": "img_892.jpg", + "sha256": "25fa96992188f77415cdaac50714188e054d0daee0b36815ea07d1f3d39ae9f2" + }, + { + "kind": "file", + "path": "img_1866.jpg", + "sha256": "bc7e364615c7ed43b9e2d54d7ef0f9679526ceb50f0003c036d05d363123f839" + }, + { + "kind": "file", + "path": "img_138.jpg", + "sha256": "860406d808663972c2b782927005625e301f243756fed7ec9eb05837a63f8d1b" + }, + { + "kind": "file", + "path": "img_3917.jpg", + "sha256": "230a916b322b6d68cb76ed224f340e4481a8ab8af5c7326ba54958c92f8e70e3" + }, + { + "kind": "file", + "path": "img_4088.jpg", + "sha256": "13e06a89e3c3cc45b547fde88d2aa173e94ac9c6ed7caa7dcec711a0e70c5d5a" + }, + { + "kind": "file", + "path": "img_4936.jpg", + "sha256": "4933502548798f81a88c82020b6beb67c4feb111e3c0e63fcb4464a0c34c74ed" + }, + { + "kind": "file", + "path": "img_676.jpg", + "sha256": "2d7d336228ec0cbe8a1b24d4c9ea81646af9e5f696ab17cb10a31d9cb83e0437" + }, + { + "kind": "file", + "path": "img_3081.jpg", + "sha256": "953b2fe97aa0a45ba017cf10de2583334beaa145471d714870957a23ecb079ff" + }, + { + "kind": "file", + "path": "img_1696.jpg", + "sha256": "d306b78d6225beca127eba7bc88b81cc8b03760330b096f01bccd02ac0a919dc" + }, + { + "kind": "file", + "path": "img_1682.jpg", + "sha256": "d6327995fecadaa5b07fc67e97f8197407e9e98b1eeed154812406b6e2da566a" + }, + { + "kind": "file", + "path": "img_662.jpg", + "sha256": "7ab866f506eca8dffd80aa09e28d45552327ec5db1adbd61319e40fb995ee685" + }, + { + "kind": "file", + "path": "img_3095.jpg", + "sha256": "d493fbf12cc2c6aa493e715000948939364e69e99345dc0521f57de1ee80c53e" + }, + { + "kind": "file", + "path": "img_104.jpg", + "sha256": "0181353325ad6276a9d520dbbd4d6c05cef4930ee76c541daf433fb5404788eb" + }, + { + "kind": "file", + "path": "img_2162.jpg", + "sha256": "82148cd3da72f635aaed4f32e06d311d55503b4b78c5931c0be6a9471f363ce1" + }, + { + "kind": "file", + "path": "img_17.jpg", + "sha256": "6447331bf5b53542d50ffcc392fa441718fd9984ce632695f0398fb99509f1b6" + }, + { + "kind": "file", + "path": "img_4513.jpg", + "sha256": "c159314bc34b0228d5f1e3aaf20c0b09d91212a4234a8585bcb32835075f6448" + }, + { + "kind": "file", + "path": "img_2604.jpg", + "sha256": "c163435088fa3982ec9b7c40a4572a570beb6dd2f5c96e23743c5091f21b78e1" + }, + { + "kind": "file", + "path": "img_1319.jpg", + "sha256": "49b77dc406f85f8cc2e72eb1cf383efdf07b6ef79adfb936e1bfee51bd5f7ed0" + }, + { + "kind": "file", + "path": "img_4261.jpg", + "sha256": "2e878793991d92493024a883bbbcb65af99c619161952f7eb3acfc18c1cb20f0" + }, + { + "kind": "file", + "path": "img_2610.jpg", + "sha256": "493e79816cb9885f6898ab9f4ce0afd30a24fe4da9a4d3bf21e4cf67ba5a993a" + }, + { + "kind": "file", + "path": "img_4507.jpg", + "sha256": "1b0c6e500783439dd46b40cc7caef6802707faa30124ba201891c7a5d2b497d1" + }, + { + "kind": "file", + "path": "img_3268.jpg", + "sha256": "0c7f910986adf97d9d9cab1b8c22384e99e21abee7a0813bf0e6747d9d42f136" + }, + { + "kind": "file", + "path": "img_3240.jpg", + "sha256": "f31774273adb15d0925e61742a24f29d7d93dd5fce6e1e8df11b76fa652c6225" + }, + { + "kind": "file", + "path": "img_1331.jpg", + "sha256": "30bd10fc78da8410aa9181f4bed5259a1afd4b52ee881d18d9d55a4e5e352920" + }, + { + "kind": "file", + "path": "img_3526.jpg", + "sha256": "83df3ee563568dc3cf516e637b2b81980d52afbc9db11524598b18f5bb6e3105" + }, + { + "kind": "file", + "path": "img_2638.jpg", + "sha256": "e0604b4efad5194fef25eff9165998a2190c5fc74cc1df6f3a4b1f66172d9c97" + }, + { + "kind": "file", + "path": "img_3532.jpg", + "sha256": "aba9d4db7eea61c49e2525f367fbd0a844a0269af73eeef2c720aa670c3c6eb9" + }, + { + "kind": "file", + "path": "img_1325.jpg", + "sha256": "0d7db137ff77ed70af0ca2835217c35917225e6321f6bec03b7db71d6a9f5c80" + }, + { + "kind": "file", + "path": "img_1443.jpg", + "sha256": "4ba1b5aae03d1fd6fa2de4040d3d33065c443ed5876c2f5d808b760f4b81aa7b" + }, + { + "kind": "file", + "path": "img_3254.jpg", + "sha256": "65d969ffe6e45fac2e02c4f965beef724baf2f70f2a30c25ee97cb79b292ea3b" + }, + { + "kind": "file", + "path": "img_448.jpg", + "sha256": "c5b87ec278bcf45c360ffb7d2366bf7bc48a2b04c0b11842bceca5f1fc399b8f" + }, + { + "kind": "file", + "path": "img_1494.jpg", + "sha256": "165412f8c7854124641bc8746f8c42016955a7c7be819b06cf2c20126479b16e" + }, + { + "kind": "file", + "path": "img_474.jpg", + "sha256": "97d766cbd17311837085740cf7dd8b8979c62484513a23113305499020493f36" + }, + { + "kind": "file", + "path": "img_312.jpg", + "sha256": "9c103f1c8da1a5472925bb98efe5d55d302fd553f8ff9b269345c80441fa815e" + }, + { + "kind": "file", + "path": "img_2823.jpg", + "sha256": "9c3c59d96b84fa8f9399a906a1957b8abcbec53052a2276bd039114c013c6713" + }, + { + "kind": "file", + "path": "img_306.jpg", + "sha256": "b3f76fbc4b64db6308617fca8920c77acbaaeb7e9aa582bdd5c2cab2d46cfd4a" + }, + { + "kind": "file", + "path": "img_2837.jpg", + "sha256": "475fa0a13a83dbc7633bcb82bc128cc1ef22dcfd9525a3f44572e0139309a0e0" + }, + { + "kind": "file", + "path": "img_460.jpg", + "sha256": "d730c4c0a38163f8f2de8f26686ee1393287a50b602ff012e8a0e11196a3cf3e" + }, + { + "kind": "file", + "path": "img_2189.jpg", + "sha256": "8944b3f441461407e2c19e9734c6229d700397f104f6c9f0d4a5c1afd76b013b" + }, + { + "kind": "file", + "path": "img_2821.jpg", + "sha256": "82ccc5770f2479ec8ed281b34a0a17ab71d94109ba1e0e282931b69c9ca8d889" + }, + { + "kind": "file", + "path": "img_4288.jpg", + "sha256": "81688ede2e983e105679df00066056709fbe361c0e4959564d8eb4ff6bec1052" + }, + { + "kind": "file", + "path": "img_310.jpg", + "sha256": "bf5d66d9f1d3179689a816c8302ebc1075c1678c9c3f66638075fa4cd2da1771" + }, + { + "kind": "file", + "path": "img_3281.jpg", + "sha256": "66615777051d6ce6b26f76d164784ada9b687010cfbda3488a74384f6468f1e2" + }, + { + "kind": "file", + "path": "img_1482.jpg", + "sha256": "2eea3a44530899f2de6968dcca4ebf9f1efbbdec17ff1b5bc026b0d2e875be84" + }, + { + "kind": "file", + "path": "img_3295.jpg", + "sha256": "af9b0f6a304b682fb89f3b29b39d86f0f60d144d63e31bc202cea4b482f92c90" + }, + { + "kind": "file", + "path": "img_462.jpg", + "sha256": "413bc6c0e2cda149a003bc5b439a6d792cf5661f612e72697dcc121da0060d2e" + }, + { + "kind": "file", + "path": "img_304.jpg", + "sha256": "ae27cc0a92584df00ede85abe2853299c051fd08ba4ee9ae3f2ee54b49b290a4" + }, + { + "kind": "file", + "path": "img_2809.jpg", + "sha256": "5cac769ada6b92a5fa3531d73e996b74d4cc50a023e7a98ddc8fb074c7ef3c47" + }, + { + "kind": "file", + "path": "img_338.jpg", + "sha256": "27383c55c5bf9b3e196141c12ffbd2eae85f303e34ba2f7b39eb272a7fe3be95" + }, + { + "kind": "file", + "path": "img_1455.jpg", + "sha256": "c59e648e9330fc903e4d135cee1f07af55664f2436b1072fd464d7301eeedc83" + }, + { + "kind": "file", + "path": "img_29.jpg", + "sha256": "1eb03a0aba12c960bf562da3b0723f5c6180aae3de1e463999d9e35c6b64f89d" + }, + { + "kind": "file", + "path": "img_3256.jpg", + "sha256": "f9472d065c6a9a99e57376815a0aa38239096a6eddfe5a141f8efe54e7273175" + }, + { + "kind": "file", + "path": "img_4539.jpg", + "sha256": "5af56df9e282146facf61110736d54a74ed39c974aad191c955e2f2efcb6ff50" + }, + { + "kind": "file", + "path": "img_2148.jpg", + "sha256": "86ff852e8099c3104868afac6239dc913201e2d057c2baaca6968f50beeda813" + }, + { + "kind": "file", + "path": "img_1441.jpg", + "sha256": "e1ab120f45a66ba7ee6f5bd21268f7cac056cc2b482a02951992486747f425c8" + }, + { + "kind": "file", + "path": "img_1327.jpg", + "sha256": "41373b32ab0955315bcfaad754654047204f3f910733a940849d6a94b61cfec0" + }, + { + "kind": "file", + "path": "img_3530.jpg", + "sha256": "6924edb1adc0d981e25a836752b35a3859b64ad30d5168f65da0449ff9e511cd" + }, + { + "kind": "file", + "path": "img_4277.jpg", + "sha256": "7af6f6d4450b3922d3e230ecebbcd1f2f8812fe5a7839274a0f75ca4c3374f82" + }, + { + "kind": "file", + "path": "img_3518.jpg", + "sha256": "1fce2255819b6b562a6d64eaac2307767a36d564cab2e21684208a6afb4410b2" + }, + { + "kind": "file", + "path": "img_489.jpg", + "sha256": "8b5d87aea1c078f3c02a431937e643586a9f46f25b05c4113e64bceea05f3e2a" + }, + { + "kind": "file", + "path": "img_15.jpg", + "sha256": "eb5c9168c69cc79e766dba0bc5809287555f87d4532fc5e5af248c13901649a2" + }, + { + "kind": "file", + "path": "img_2160.jpg", + "sha256": "d73787ce3b83f70ff304020d5a14a47f1a40f853b2c27704cd70e9aa70b7f9b7" + }, + { + "kind": "file", + "path": "img_1469.jpg", + "sha256": "82ff62be6c4697222e37339dc3590d926d4b62d6761b7625131ecc7e243318b6" + }, + { + "kind": "file", + "path": "img_4505.jpg", + "sha256": "cf4427136907743c22fbd860a3c785bcf443f38ece534fbac1b0a21aeaca202d" + }, + { + "kind": "file", + "path": "img_2174.jpg", + "sha256": "55a06745f53bf85577bb6e799c1eca2c2b6f10f7967507e9be439e0474af1c92" + }, + { + "kind": "file", + "path": "img_2612.jpg", + "sha256": "3dadb52a377b9c0003d54254aad5ec817483c2326e2525d0c1bc562c907b4860" + }, + { + "kind": "file", + "path": "img_4263.jpg", + "sha256": "00122cdd36b7c7dee515e62e8af2a34ba68ee0262f42a130209fd069fb610c50" + }, + { + "kind": "file", + "path": "img_1694.jpg", + "sha256": "ee9c39876aabff0aa94174b5539c6d0defab70e26867c0f385b2b125ab2d2de3" + }, + { + "kind": "file", + "path": "img_674.jpg", + "sha256": "912299d222b5ba879cb814fd2b5c348dd170404530fb45b3b03a1cabc109d4b0" + }, + { + "kind": "file", + "path": "img_3083.jpg", + "sha256": "bfb42eba8a22dfcfa89ba03d4f93aeb2f4429596cb5b01f0f0b416c7c1282864" + }, + { + "kind": "file", + "path": "img_4934.jpg", + "sha256": "7c9dd162765aca86a424c071749838f25fa9ce0f0878509da2d3e32175d0ecc3" + }, + { + "kind": "file", + "path": "img_3929.jpg", + "sha256": "07405cca6820a2c0c7a31ae75a2c79e81289becdf4cebcd7541c70c85bcabb3a" + }, + { + "kind": "file", + "path": "img_660.jpg", + "sha256": "cf5b832aaa458e8e986cb9e68e1869d4f7f88c5af243482d49784987aa76a273" + }, + { + "kind": "file", + "path": "img_4920.jpg", + "sha256": "a763d83a0efabaa2108e9d92b3cd90f6bed752f2325308e12d03075733c4dd76" + }, + { + "kind": "file", + "path": "img_2389.jpg", + "sha256": "a28870bd2275482f74cd3016df23556520a0287ef38a78425d8b6eebcc52534f" + }, + { + "kind": "file", + "path": "img_1858.jpg", + "sha256": "b6ef240381badd88e3b13978305b335b5a8acbd6617cb0d204c62e5dda26f472" + }, + { + "kind": "file", + "path": "img_648.jpg", + "sha256": "70ff4797f1ee38788f1dab4a20e99c6a8f02cc38072cc5ac7c9aa1b982d93ba9" + }, + { + "kind": "file", + "path": "img_4908.jpg", + "sha256": "82cf76c5fe95487e9f93f2cd56785830564fbdb1ef8a441392bd0a63e0eeec3f" + }, + { + "kind": "file", + "path": "img_1870.jpg", + "sha256": "2f2727607a60368faa2dac9866f14d071ce222bbc45ede4879b2dd6d033a65f3" + }, + { + "kind": "file", + "path": "img_3915.jpg", + "sha256": "cbba3dd9e0990c033e404f9826f08eb833be7cdbb4891b7f0eaac62a50d3bb58" + }, + { + "kind": "file", + "path": "img_1864.jpg", + "sha256": "12d5e1226d5ee4b52576517d43596ba9f1c7e199a751646c0c7931777235c5a6" + }, + { + "kind": "file", + "path": "img_884.jpg", + "sha256": "e30bb90070536feb31c006a045912eb97562af7a16d5bb582b60d9eec0abca9c" + }, + { + "kind": "file", + "path": "img_3040.jpg", + "sha256": "8c8796164c795c946017a2a5f42a00cf4bf20c96fbc1a74330e048a52eeff784" + }, + { + "kind": "file", + "path": "img_1657.jpg", + "sha256": "a92da1d451734ed2f4a605bdce932572b1d95a9df22775850bb7706f7394b6ff" + }, + { + "kind": "file", + "path": "img_1131.jpg", + "sha256": "43eacadd3b58c845c60dba30ece24b2c414e52cb0590d011bf82993145d0e1d0" + }, + { + "kind": "file", + "path": "img_3726.jpg", + "sha256": "a156fd1f70ed07c3b71cd91e40d94042de3c5921d309b98834e5c7170a3f4eab" + }, + { + "kind": "file", + "path": "img_4049.jpg", + "sha256": "6f61939b5e027d72329bfd162e7b9953e61969ec3a37d8c64eac42192618de1d" + }, + { + "kind": "file", + "path": "img_2438.jpg", + "sha256": "7a4a84f871819409671cae18c7618cec6f04f17799aa3f519f8346b5ba40f7b7" + }, + { + "kind": "file", + "path": "img_3732.jpg", + "sha256": "a9a32da8aca94e442498ff3e5da7f6024857bbacdd51c0f5f4f13372de1bc5f7" + }, + { + "kind": "file", + "path": "img_1125.jpg", + "sha256": "54bed68a64365fb99028e491b21c77e93e8e4c360b2b8ac27e287a60480cfd0a" + }, + { + "kind": "file", + "path": "img_1643.jpg", + "sha256": "d33a06c0644d8658b1a0079b1d4102f977f6cdc5be352d287e5ae230709eef47" + }, + { + "kind": "file", + "path": "img_3054.jpg", + "sha256": "75443588baf69989b0e770a909efcbb7431c2386348d083f2542a89a5d6e87f3" + }, + { + "kind": "file", + "path": "img_2362.jpg", + "sha256": "0a7e6135f8b551ce9aec921c509e4c9f52802b0f95b5868220702bc8b56d4442" + }, + { + "kind": "file", + "path": "img_853.jpg", + "sha256": "42ee87f429953488ed35c37f3ddac0fb494c9334cf688439a63d8980cff160d5" + }, + { + "kind": "file", + "path": "img_4713.jpg", + "sha256": "02f1454f3c5e7eb616eafa082bc0d7a19b9607dd69f50464a3863ebe55390d17" + }, + { + "kind": "file", + "path": "img_4075.jpg", + "sha256": "0f92b96747de084f700c5d2cc1b7c9597ad8a63c878fe59d2a8e92bb9ca5e178" + }, + { + "kind": "file", + "path": "img_2404.jpg", + "sha256": "03cc9111d6d48d574257b5b3ae0e9a17fe96f9279b7d99e5c7841183294b88f1" + }, + { + "kind": "file", + "path": "img_1119.jpg", + "sha256": "bbbf5499d79f2ac2c30256ff4ef10700e33e15bed8819b24825b44b283f9b531" + }, + { + "kind": "file", + "path": "img_847.jpg", + "sha256": "c30593ef4c08a24357e6b9aa58d0cd8d97d3824409299f8da149cd7f9ee43035" + }, + { + "kind": "file", + "path": "img_1938.jpg", + "sha256": "7310657d0c85e1fbba2d5188f5a6b94cc51d8d82c4b388cc8e4987222d479969" + }, + { + "kind": "file", + "path": "img_4698.jpg", + "sha256": "9f891542d74623d3e362d7293920e0e3cb4793cbbec82debe62802cde21cb077" + }, + { + "kind": "file", + "path": "img_3691.jpg", + "sha256": "ed46976b646a9616cecb819b3b4724405286da069a0cb5c38c0d76fedcd44ef1" + }, + { + "kind": "file", + "path": "img_3849.jpg", + "sha256": "8adb9c87ef116609ac9574ceea1c8fd7e2d7e50dd8cddb7ac3cee3b34df1c60d" + }, + { + "kind": "file", + "path": "img_1086.jpg", + "sha256": "c4cd0a05d1a99337dbfbce4b94ce7502dbbe792916db16efa3cf2626683b69e1" + }, + { + "kind": "file", + "path": "img_1092.jpg", + "sha256": "61a7a789238c33a14b46327345a55b5da872ffa22830bd59788c0096b65a10f5" + }, + { + "kind": "file", + "path": "img_3685.jpg", + "sha256": "f0f8f62d654b9c9daeed47257c6ede57ce117155a38c76a30478aefe7714f7b4" + }, + { + "kind": "file", + "path": "img_4854.jpg", + "sha256": "34134c7ef95670d9f56301995c0937f575da0f29b2d088a1b046e1609369c859" + }, + { + "kind": "file", + "path": "img_714.jpg", + "sha256": "0defead6ca07d028b0e7c9e90ddbe76cb96a0406d242f69eee3dade85331c9a8" + }, + { + "kind": "file", + "path": "img_1904.jpg", + "sha256": "3ea5702f3381735f5126f56aab53e3bad5e6929cc42cae9eed902e0ad5a2a276" + }, + { + "kind": "file", + "path": "img_3861.jpg", + "sha256": "93ffcc5edb159df0f790ddc0abb06fab12a45481cfb5f522dc7f2e27fa1d10c0" + }, + { + "kind": "file", + "path": "img_1910.jpg", + "sha256": "3e269292cf4ddedd9373941abcf83d6e633c66446592868d9cf4bfefbba7130e" + }, + { + "kind": "file", + "path": "img_4868.jpg", + "sha256": "34f0912b55577b46872b6880232a40983b8d264f03ae528a011ec2fa27ddacab" + }, + { + "kind": "file", + "path": "img_728.jpg", + "sha256": "467434cf2407be0a1789f099c29f781131127cc915039ca33ff50aa0adbe0963" + }, + { + "kind": "file", + "path": "img_3134.jpg", + "sha256": "c9050ef9155c04ba687bffbcfe8c5f04ee630c4b1cb8542890128c5772ad8e31" + }, + { + "kind": "file", + "path": "img_4883.jpg", + "sha256": "df6fc00b5ff9ae30b529a34c9cee71e79318b7ca61db16d2c4ccb962705c9eb5" + }, + { + "kind": "file", + "path": "img_1723.jpg", + "sha256": "18a00b8f243bc4d88695724b5f7002e7dd3733e637605ba5fee01ae1ba3f4df1" + }, + { + "kind": "file", + "path": "img_3652.jpg", + "sha256": "0b24db9da03d9455fc268b0b506a1f806a1cf2d5c46dea6f8c440970765481b9" + }, + { + "kind": "file", + "path": "img_2558.jpg", + "sha256": "ef5de2fdd8eef526809c8a4d875f32eead50e69bda63ca5498dcc969abce7f9c" + }, + { + "kind": "file", + "path": "img_4129.jpg", + "sha256": "632901a63c70fcf3f9015bcaf7d488ed70ce82ccbe9c4bfd8d0c4d62783a4f61" + }, + { + "kind": "file", + "path": "img_3646.jpg", + "sha256": "9f58a8fd17ab877fff7a6a575b26c14d94153d20e84ca7ae709fdd734b530e92" + }, + { + "kind": "file", + "path": "img_3120.jpg", + "sha256": "aa8b59995948ced6a0acf9f3fc72036c6f4a649bc66824730a33701ef7fd942d" + }, + { + "kind": "file", + "path": "img_4897.jpg", + "sha256": "4044dc1bfdb1dc0e2c8c3f5766850fa02de55dfc0765aa4a13f1ee501d348591" + }, + { + "kind": "file", + "path": "img_3108.jpg", + "sha256": "a4933d4614d1dc17e5bd614afe398060813334286db0e6d42a91eb941507b02a" + }, + { + "kind": "file", + "path": "img_4667.jpg", + "sha256": "f2d337a16f75f4e57deb3a0fcf2202a68a4b40255d55359601ffc411b2616bf5" + }, + { + "kind": "file", + "path": "img_927.jpg", + "sha256": "c64bc0d506df6d7e61540439927928ba9402a1108cbb25dbc2bed4b4aa0d8470" + }, + { + "kind": "file", + "path": "img_2216.jpg", + "sha256": "66666eaba0674d6f9f5f495f82e61ca7bea4f1d83c8d63d3b1c4bee6fd6b4f1b" + }, + { + "kind": "file", + "path": "img_2570.jpg", + "sha256": "cf793286db889cef35226d4120da6b04849d3b0827d89e5433f28a61e7253b0b" + }, + { + "kind": "file", + "path": "img_4101.jpg", + "sha256": "8e0d6787558fd0de8aba84b4b5583e3b018212e6f9c7be83abf1b10c1401ade8" + }, + { + "kind": "file", + "path": "img_1079.jpg", + "sha256": "c984d822546616eca7b501fcbb9dfd6c7f0c30aa8fba84e3a3822d7849663eb2" + }, + { + "kind": "file", + "path": "img_2564.jpg", + "sha256": "ee2f359d9babe58d8e64fac6a56879a034970885bd14787fe6046c6da0d3b43e" + }, + { + "kind": "file", + "path": "img_4115.jpg", + "sha256": "95c103bbb32adecb938d7815679bdca8475a65ca10ee3e5431e644333910fc94" + }, + { + "kind": "file", + "path": "img_4673.jpg", + "sha256": "bd778a08b07f74d005d8f4f637691a0540d28681a1427e6681f407d36fee1d7c" + }, + { + "kind": "file", + "path": "img_933.jpg", + "sha256": "fa3de50c3737c652597338171ddd9e32b6d726efca7f47902ff2ab54e0306dc8" + }, + { + "kind": "file", + "path": "img_2202.jpg", + "sha256": "87660bcd1a1141fd3bfb37fd8879852fc65a96ce60091933258187d40befb571" + }, + { + "kind": "file", + "path": "img_4.jpg", + "sha256": "def287c0827c6c84d75bdb69c0fc435463cd00de2680465639d88bb6df854acc" + }, + { + "kind": "file", + "path": "img_3493.jpg", + "sha256": "9335f26f737e1f14162d79a2fb0679686e8d5fa71d777a901a304cd5fc4d15b6" + }, + { + "kind": "file", + "path": "img_264.jpg", + "sha256": "9845695b765e6869de8fa43da9274aaac9455501015f72ba5e75402559a0fa44" + }, + { + "kind": "file", + "path": "img_2955.jpg", + "sha256": "b4331764b2497dec02e8497f9baebf4c1c8687e7f69ff669815d740a012f756c" + }, + { + "kind": "file", + "path": "img_502.jpg", + "sha256": "a29a3376e67288416e1f71818840c75a5eaa5712bf8aaa25420ffa39ef4acc1a" + }, + { + "kind": "file", + "path": "img_516.jpg", + "sha256": "5595eff570ab93f80e270c5541fc11cc8bfff9475410fdc1fae520643b4c897a" + }, + { + "kind": "file", + "path": "img_3487.jpg", + "sha256": "b3918c01878557a0328bcfdb1a467702c677f7b572e43779767eab6fe1418526" + }, + { + "kind": "file", + "path": "img_270.jpg", + "sha256": "f6f48595140e368a26c7272c5347ae927e62d9761c02b65f3c643c68fca4fb95" + }, + { + "kind": "file", + "path": "img_1290.jpg", + "sha256": "acc86e8ee25a790416b3656b4b938c56ea9ccf733f4035d96f8fb52f09a6fa6e" + }, + { + "kind": "file", + "path": "img_258.jpg", + "sha256": "007ae4fe8b830a1c79dd7c8414d2e4c4a99e68c3b1abb2e9e177eab449b29e7a" + }, + { + "kind": "file", + "path": "img_3450.jpg", + "sha256": "a708940cc0f8395231f86d61d4b7c3f78d86337a06ae0b5c7b8d69e3c940fb0a" + }, + { + "kind": "file", + "path": "img_1247.jpg", + "sha256": "750165e322de6d6c622ee2a7c59ea90d5261a3c4541fd1f9ca10971dc62358e2" + }, + { + "kind": "file", + "path": "img_1521.jpg", + "sha256": "049f2d4551c56c7d6687dbf925b4be273c48c26ab0fa27cf91232e5b172377f4" + }, + { + "kind": "file", + "path": "img_2028.jpg", + "sha256": "05f0436acaac25651239d946da9e458ab2505cf88dd0dcdd615fb416bd965dbb" + }, + { + "kind": "file", + "path": "img_3336.jpg", + "sha256": "da84c4719d0f74a96c3b523932aa5c7425925420a96c21174d3915719782c68e" + }, + { + "kind": "file", + "path": "img_3322.jpg", + "sha256": "4f73f30f67e0db7ef700929b0555b8944edef5b3627e85573b00a65fc0c73585" + }, + { + "kind": "file", + "path": "img_1535.jpg", + "sha256": "bfcfdeb8a78ce457a2199b2a8badedee7e7793c67b32f9a2d8d9d6fd3d139ef8" + }, + { + "kind": "file", + "path": "img_1253.jpg", + "sha256": "6722ffca29e3871cf3ed8d0191a5ca83dadb4b5934b1f5edcf3a9ba2113c9a58" + }, + { + "kind": "file", + "path": "img_3444.jpg", + "sha256": "7eaa54a87db5c78a28e206bfbf96b7739dad5ae9f2520843450fa22e5531c18e" + }, + { + "kind": "file", + "path": "img_2982.jpg", + "sha256": "055dddcfe5956f970dd84abe1b38779c435edf73c0e63e154a12f5a9a96cbe15" + }, + { + "kind": "file", + "path": "img_2772.jpg", + "sha256": "4095f53fbdae498b7c3b552b4d3667d07d7f7322e1be6aafcdc4ab904fc7e8bc" + }, + { + "kind": "file", + "path": "img_2014.jpg", + "sha256": "27d291fc92132b5bb57bafcfea86ea34cdc2a5a7be948a8982092df9450d5964" + }, + { + "kind": "file", + "path": "img_4465.jpg", + "sha256": "e6e24f6602150205b7bf5e545b5becafd133fe20e360ed4216dafd3019c2f4b9" + }, + { + "kind": "file", + "path": "img_1509.jpg", + "sha256": "13673364a7f614a39c908de8a8de90da2167c9b570b8a902c867675747fa2123" + }, + { + "kind": "file", + "path": "img_2000.jpg", + "sha256": "e5a1defa66b8aa115c0ec796327b08786a705dd6c2d3da057d8eaad90be97ecf" + }, + { + "kind": "file", + "path": "img_4471.jpg", + "sha256": "8bffb6b70d27bf947a2ed129b8e992a29403288b2ea1313e33e9ccb704c938ba" + }, + { + "kind": "file", + "path": "img_4317.jpg", + "sha256": "dd2fbf5fa6c192dc49d152750ccef1f67b8391cfb7b1d04a48e6ea54b15e06f8" + }, + { + "kind": "file", + "path": "img_2766.jpg", + "sha256": "7c96a35632d774d78d4ae867c14291f55a18c1662234dd58b3d48d9f48f81f59" + }, + { + "kind": "file", + "path": "img_4470.jpg", + "sha256": "09609d760637914307426c4c4b81bf52b6245d90a54fb8ae176983d655491a0b" + }, + { + "kind": "file", + "path": "img_2001.jpg", + "sha256": "26c3f4bdc477013ea1384850d8acd3276992509c51c31ed831fcd61d94de74ce" + }, + { + "kind": "file", + "path": "img_4316.jpg", + "sha256": "a29bbdfe7817c4f0c6411e15042826e5758d65e7e4c8f48a1a6cece571ce7996" + }, + { + "kind": "file", + "path": "img_2773.jpg", + "sha256": "ee4cba530a4d2e040777c65e9f588923e50904db0feb1778ebe598d6ae0f5e35" + }, + { + "kind": "file", + "path": "img_4302.jpg", + "sha256": "9b50cbede73fe58f3f7e0352f3b8ebc914f5a4e2a475a5b8668109c7f68bd89a" + }, + { + "kind": "file", + "path": "img_2015.jpg", + "sha256": "8623aa372005a2f00f3d49d5981579cd0da38c5b5483034873d82e73e09ecc6f" + }, + { + "kind": "file", + "path": "img_1534.jpg", + "sha256": "9dc6fc0c19b4564eb75dfbf42aa98be7af4513f26505db37dc9e252e412ead4a" + }, + { + "kind": "file", + "path": "img_3323.jpg", + "sha256": "d4157258334b263e4ff68417bff678adf37dd69f19e95de68ff9af73b0a8d33e" + }, + { + "kind": "file", + "path": "img_2983.jpg", + "sha256": "fc3e975b1ab9971bc93b879bcfd6df1b935dc4a6e39e243f4290765275c21934" + }, + { + "kind": "file", + "path": "img_3445.jpg", + "sha256": "33931e1f66bcf5c36b735245dcd053ea503aca71554c96862061b8fc09eb452d" + }, + { + "kind": "file", + "path": "img_1252.jpg", + "sha256": "78549426909ee2911a73f044d99231beb09df36b7501355eca70b55627d53942" + }, + { + "kind": "file", + "path": "img_1246.jpg", + "sha256": "7d1fea7abd1b06b5d2eb35ac480ef01ead608cded23eb5494fb97c9254e29bd1" + }, + { + "kind": "file", + "path": "img_2997.jpg", + "sha256": "6c382d21a4e95e615980ec36c725128fdb28989e7d0b31f9b3692e5d58b853c8" + }, + { + "kind": "file", + "path": "img_3451.jpg", + "sha256": "7b5534743d668206735f64a3c7b928e9e4e402ac1ca1cdaece33aee288ee1307" + }, + { + "kind": "file", + "path": "img_3337.jpg", + "sha256": "1630a2691f1e5521118c743fdcd641e812104f29cc83e1d08f15def14c2ea86c" + }, + { + "kind": "file", + "path": "img_4458.jpg", + "sha256": "82193860efdb446015a3693f4b779d09a7cd170acedec3219b6cdbf8fb356d9f" + }, + { + "kind": "file", + "path": "img_2968.jpg", + "sha256": "8e9de9f12dbd3d8e6372d40503f0cbc4176e2b8d8be87791cc1593c82074469b" + }, + { + "kind": "file", + "path": "img_259.jpg", + "sha256": "bd11f17179b905ca48327a1a509c40065302f58e8350f1ed86c8ac8bff57ca62" + }, + { + "kind": "file", + "path": "img_517.jpg", + "sha256": "eebd72134ffc3c56ba5f294d4c322134f6300d28e481a079f51e135667ec52ad" + }, + { + "kind": "file", + "path": "img_2940.jpg", + "sha256": "c7c962c638587e31e323ca85c53b0f06ccb100d63d550dd0ca3059fb839e9d7d" + }, + { + "kind": "file", + "path": "img_271.jpg", + "sha256": "203e8628e3205494fa217d4aad21069bdf665abc9869a884e04bccfbc2a5ceca" + }, + { + "kind": "file", + "path": "img_3486.jpg", + "sha256": "5c5e1a229c5b00cc5611a2feac2eb96427559e6c07305ab58738d3b203617a6b" + }, + { + "kind": "file", + "path": "img_2798.jpg", + "sha256": "a79fc654e4ed8e3536f40eb5d8b018bb79d2e94e36645669494168b99dc5bd74" + }, + { + "kind": "file", + "path": "img_2954.jpg", + "sha256": "a2563de4ae0e7e2b626e5b9d7b94a4fd9ba67494549a35c7ffddd0a70c353167" + }, + { + "kind": "file", + "path": "img_265.jpg", + "sha256": "42371c50d08bae90d925bbc75e6343262f354965100a96c61f40b3ed6d6b9652" + }, + { + "kind": "file", + "path": "img_3492.jpg", + "sha256": "4b43fe3eb05de2f7f2e248cb02a3ba6087d7b4fa6a7123cb5bb227f96230a9c6" + }, + { + "kind": "file", + "path": "img_5.jpg", + "sha256": "498a3fbbbb56a7f50cb9f1d7be7f485a6a8a3aa003cca74df556ea20ef13cdbc" + }, + { + "kind": "file", + "path": "img_1285.jpg", + "sha256": "c237003475ed3c5c7ba9f85f30a7aaf9009c0204dde3bd7678622cfe00fa2a75" + }, + { + "kind": "file", + "path": "img_4114.jpg", + "sha256": "5239574d27a7d0532aab5bead34419827217b4c3015bd7413f0bbc3539e6dcf6" + }, + { + "kind": "file", + "path": "img_2565.jpg", + "sha256": "b2e6bbc14c03593f13c6c15ad4e68a5c52ecc5e6fa3c865ffe650e159dbe7d03" + }, + { + "kind": "file", + "path": "img_2203.jpg", + "sha256": "e4b2e0063ded5f9fef4b85f857219722ec8a81003066dc8a1ccc28aa74ff9100" + }, + { + "kind": "file", + "path": "img_932.jpg", + "sha256": "e2e49259fb7295470e76374d435437fe7031d78cef224947534ce6a329ada01d" + }, + { + "kind": "file", + "path": "img_4672.jpg", + "sha256": "d2a7b0e34210d54d93215aa885bd38f41c5a7a90470a05ed6985a26cfbe96f65" + }, + { + "kind": "file", + "path": "img_2217.jpg", + "sha256": "67ff8b48b68d454feb9400aabfc0aa78fe8970059cdb900c4e563bfc7de9ea70" + }, + { + "kind": "file", + "path": "img_4666.jpg", + "sha256": "35f94f7aa46e01a543676522697d53decbd0c90308701b6fcb64c58b4ba623b3" + }, + { + "kind": "file", + "path": "img_3109.jpg", + "sha256": "6e23e11e60fb8dcb176548693fec3d7b37c295afffa38d0bb79b3fb3f0541f87" + }, + { + "kind": "file", + "path": "img_1078.jpg", + "sha256": "eba4a056f538f916cc3ca058358a27d68a096838bf7009986e7729132fdae100" + }, + { + "kind": "file", + "path": "img_4100.jpg", + "sha256": "307839c0a6a12e631f0c61c8b054b8d869844017cefb1624591c1e3f3977fc8b" + }, + { + "kind": "file", + "path": "img_2571.jpg", + "sha256": "577b6a3732a7d2fc047a3b435fb7a66b1ce29bbe8e1dfeb7e9fa2691d18b4d34" + }, + { + "kind": "file", + "path": "img_1050.jpg", + "sha256": "43e278daa875633d9c43b1e51971bd4d7d5f4117efee4795cbccce114eff475f" + }, + { + "kind": "file", + "path": "img_3647.jpg", + "sha256": "484bd06e1ccdcd03d2107caed968888a6fb85fda7ecabb517c50d660d075e01e" + }, + { + "kind": "file", + "path": "img_4128.jpg", + "sha256": "3307e2edbfd945eb137eae1f57e7cb8858b6feb425bdc4d3bb2c894bcf033e7c" + }, + { + "kind": "file", + "path": "img_2559.jpg", + "sha256": "922b2ceff13b6a205fc7fab1418af4210acb33152e1d927a92b2c703e410c864" + }, + { + "kind": "file", + "path": "img_4896.jpg", + "sha256": "2bdfe9fc0239ce0bd44811b4bc14a31bde17f003e291d86dd86113939a37218a" + }, + { + "kind": "file", + "path": "img_1736.jpg", + "sha256": "d6ad86678624de7e3970b622ad6e084222e84c1966763118411e8533679269d5" + }, + { + "kind": "file", + "path": "img_1722.jpg", + "sha256": "17b90084aa82e1d61dc66f75848bcf04ebad51ea52bd632d35060a8fbe7c8281" + }, + { + "kind": "file", + "path": "img_4882.jpg", + "sha256": "369ff2b6faf351404d4cb61c0872ec540c460f2de0bccc5593dd6113db7142b4" + }, + { + "kind": "file", + "path": "img_3135.jpg", + "sha256": "923040ce4af219c4b9ca1a08a0837568cbabb153c530e03f36b9c7d269ab3d53" + }, + { + "kind": "file", + "path": "img_3653.jpg", + "sha256": "511c964f2d532795e5e0a01c5dcd7fca789d7379124ca0c2ea95302973f043ea" + }, + { + "kind": "file", + "path": "img_1044.jpg", + "sha256": "4b783117a79e7022a1f0acbc424634502d30b45cd0addd9c4a08519a145202db" + }, + { + "kind": "file", + "path": "img_729.jpg", + "sha256": "9dc633ea7a2d0986b16f1c8faa0873eaed81e942c4fea06f5f0f84730b4c5eae" + }, + { + "kind": "file", + "path": "img_4869.jpg", + "sha256": "c0558ae48a02b81dbe61539b3178a679b2115aff38e054f3a69be402cfaec46e" + }, + { + "kind": "file", + "path": "img_1911.jpg", + "sha256": "7632d2cfbb67256541549f344ba21d3bd6079b277840a3e657f8d88dba569ccc" + }, + { + "kind": "file", + "path": "img_1905.jpg", + "sha256": "5cba17de87bae500dd4f6da6ec5c960fd34fd94fed77853744b25ff68a2a451d" + }, + { + "kind": "file", + "path": "img_1093.jpg", + "sha256": "3b673ead127f054ee57a90d99c97172c2548092c7eafab6c408f004c6438b68f" + }, + { + "kind": "file", + "path": "img_715.jpg", + "sha256": "40fab5a31f91e49c7a38f20d441938a1e5a20b5b6f3de7740e64f2dffc9edc06" + }, + { + "kind": "file", + "path": "img_4855.jpg", + "sha256": "4f95bc9808749da11e63e222acc295d7d6e1b6c79caaeac48ced07df5901697e" + }, + { + "kind": "file", + "path": "img_4699.jpg", + "sha256": "3803da43fcddb0fec55b3915d026e2d672a0a4d867d32deb3481e228bb66711b" + }, + { + "kind": "file", + "path": "img_701.jpg", + "sha256": "4081dafe6efb7bf8028c7702e665466e7b3db7fdc0cc5fcd8c337006152cd8a3" + }, + { + "kind": "file", + "path": "img_4841.jpg", + "sha256": "0df3180c4183fdfb04a53788cb8aa510cf81a42338ea6d3df7d6bd7693ff18cb" + }, + { + "kind": "file", + "path": "img_1939.jpg", + "sha256": "2da9c64887ceec3235b2f764771aff1f66749fa8b93758a1da7668bcca8862f1" + }, + { + "kind": "file", + "path": "img_1087.jpg", + "sha256": "6646e2bd10a9f3ebd3ad72b165e34bcf3a962d19769ad0c0ffb0e8d637843306" + }, + { + "kind": "file", + "path": "img_3848.jpg", + "sha256": "ee1483ed92313006c7e19403a4406b3084ff767bc6a651f62bb9b399b1dcd1ed" + }, + { + "kind": "file", + "path": "img_3690.jpg", + "sha256": "3fb39d5646867633ded7767bf23abdff202533e721d485d27c9da22cac68ac68" + }, + { + "kind": "file", + "path": "img_2411.jpg", + "sha256": "41162ac9d129e6a9ad9efd1e80d429db56f05fa744f75d8b1fa1e3f9ca0884b5" + }, + { + "kind": "file", + "path": "img_4060.jpg", + "sha256": "b033cfc86acc1ef24e8c7fccb3b703f90498436ed6faf914b84db0f6705cb9c5" + }, + { + "kind": "file", + "path": "img_1118.jpg", + "sha256": "ce2f9725aea5e784bb58b263a914188963911af1f0d8fbe24db889279c097dbc" + }, + { + "kind": "file", + "path": "img_3069.jpg", + "sha256": "f4a653207977e3dad71598ab411012c75122299b0bae87c0afe24bdba6c7a96b" + }, + { + "kind": "file", + "path": "img_4706.jpg", + "sha256": "b1e1b254a8cb9e21d86cabf339a1458f1ec7e40e1acc25365dfee94dbd03ad26" + }, + { + "kind": "file", + "path": "img_846.jpg", + "sha256": "fae7ce0c7604432163dbf1f2022993c8991c093c00cd3564cae0e1b5b0165d38" + }, + { + "kind": "file", + "path": "img_2377.jpg", + "sha256": "6cad6cd70cce40bd3b63d4c9b9db70b5fe749d226bd49d17520b12bc63da4467" + }, + { + "kind": "file", + "path": "img_852.jpg", + "sha256": "bf2d845e27e97200d88019f4bd428725ba48a72c92b2637f32df360afc02c0ba" + }, + { + "kind": "file", + "path": "img_2363.jpg", + "sha256": "8300fbcffd54658fb91ef46e49beb7ba1fc0c7bfc345b312d73bee7bbd1b50ba" + }, + { + "kind": "file", + "path": "img_2405.jpg", + "sha256": "c8de890a30023aa2703b56d134d47cc6704dc0666382e17141fb32f138d01c95" + }, + { + "kind": "file", + "path": "img_4074.jpg", + "sha256": "9a8d83f46eb3c9c0d8708c128f130478d25d5264466e2a38e446b2404254f488" + }, + { + "kind": "file", + "path": "img_3055.jpg", + "sha256": "68db2a34cbc8f5dbb645f108aac7462da6b1f90289be3292646d8b20f1ba1a81" + }, + { + "kind": "file", + "path": "img_1656.jpg", + "sha256": "911b2b639c79c40e162560b554f0d250ece53c406a4c3feca0659785d30f0b5c" + }, + { + "kind": "file", + "path": "img_3041.jpg", + "sha256": "f80fd247ae9f36c63f959bb347fd1b03a69fc9032bb47d96ecd1890f52755aef" + }, + { + "kind": "file", + "path": "img_2439.jpg", + "sha256": "99903040134046e350784bd8bb5a7b64de3c2d7bb7bf773355918e6b220cc8cb" + }, + { + "kind": "file", + "path": "img_1130.jpg", + "sha256": "8699a6f4ed8f3e9d1f50dd5b24959b6c249015e8704cdc5f00a8c756b39ec7f2" + }, + { + "kind": "file", + "path": "img_3914.jpg", + "sha256": "f291c0bf1cf5e0bb5a33720add731e2d82c228889ee6ef780e0f22463c477174" + }, + { + "kind": "file", + "path": "img_885.jpg", + "sha256": "8150354de2e968c23cd3709d96f5a9ef8b328ff7d86310098e5e5e3a17876aaa" + }, + { + "kind": "file", + "path": "img_1865.jpg", + "sha256": "9c243de7ade36f96832a66fcc45f5faa098a733bd6cf3cd0d17580c2ae1324fb" + }, + { + "kind": "file", + "path": "img_891.jpg", + "sha256": "8bc1240e37428b439b5e84d5be496ccc4414ef2783d4efb86b6f00681755ab14" + }, + { + "kind": "file", + "path": "img_4909.jpg", + "sha256": "16114f840306876028d3e7cacd3908441715d93f651e42b48ae9e0ae7d978eed" + }, + { + "kind": "file", + "path": "img_649.jpg", + "sha256": "5738c61f5e881668cbf66df64eea2b4a84be61fe414bc45d8de0c9cb00e1eaa1" + }, + { + "kind": "file", + "path": "img_3900.jpg", + "sha256": "c31cad7d2537fefd5c1b3750d08b57ff2304b2e48afcc80fa08340fe8bb909c2" + }, + { + "kind": "file", + "path": "img_107.jpg", + "sha256": "8db49fd9feca27aacafe225277b314c51843da4b8c35ae53e94d8e1023559e17" + }, + { + "kind": "file", + "path": "img_3928.jpg", + "sha256": "2817b8cbfafc963e34debaae603aa92202a0051c0213eb5032d64573caedba15" + }, + { + "kind": "file", + "path": "img_1859.jpg", + "sha256": "ad1e7994d2f53f8caf565461ed6dca6f02e8331e8e0481f6664b7531b682a019" + }, + { + "kind": "file", + "path": "img_1681.jpg", + "sha256": "2c3fc2a5e1c0a7feb909d996bc66292f0f848c2feeff5cc6489eec4970b334ec" + }, + { + "kind": "file", + "path": "img_2388.jpg", + "sha256": "5bca21b5a958438dd857bbbc8bf6e0dafec6be9052c4d3d84e030c874d5b07cd" + }, + { + "kind": "file", + "path": "img_4921.jpg", + "sha256": "a93c1a4e5e0715b8eb8444f1c16696c6cac2f3d3493c8378018acaa2cad339f5" + }, + { + "kind": "file", + "path": "img_3096.jpg", + "sha256": "58ea226321ce279ae6ed749a5e62374641dbef04889e1fbe70b2e466031b8345" + }, + { + "kind": "file", + "path": "img_661.jpg", + "sha256": "386e3a8194523c663fe1f31dfbba5e24db5cd5dea5fd5b411a18d2a4631ac34e" + }, + { + "kind": "file", + "path": "img_4935.jpg", + "sha256": "dd72ce016c85b75867b14e87997ad3243ce3a60383201bbfba6c7ec377d1f25f" + }, + { + "kind": "file", + "path": "img_3082.jpg", + "sha256": "fb3a42cbecc2710a07ec29f924df56af3c9792d17eb06f7ac4c10cf179fb454a" + }, + { + "kind": "file", + "path": "img_675.jpg", + "sha256": "311d078d29c3904d721a0419aa7aa62d9537726c8775337906d6b43c797681ef" + }, + { + "kind": "file", + "path": "img_1695.jpg", + "sha256": "cf508ec560ba23feae61b51048b89e7be1e0bbe10a0c3b78bb8332b637138584" + }, + { + "kind": "file", + "path": "img_113.jpg", + "sha256": "c88b5367573131ba04e255d06a3a2a13ba938e4afdf857a4a506f2db44a8c7da" + }, + { + "kind": "file", + "path": "img_2175.jpg", + "sha256": "4df163345a85516beca7a51c1fc7363a1cee460ec0111219bc1885a6d226ffe6" + }, + { + "kind": "file", + "path": "img_4504.jpg", + "sha256": "bd406383b1bd70620a965f1f8e25331afccd7e845c83c86d8e1752e912e08b3d" + }, + { + "kind": "file", + "path": "img_4262.jpg", + "sha256": "8cec2d8f175858f684783a481d5d329dd3697db6a1d4d116b76594e4ab098116" + }, + { + "kind": "file", + "path": "img_3519.jpg", + "sha256": "8c02c42fc8cd69b4861df045f2d61e71b4f83f3854971922534bac7c5873ab9d" + }, + { + "kind": "file", + "path": "img_4276.jpg", + "sha256": "bfcae89bcc02a01768e486d60a28ccd1d692d370a968f3d879b60274571cc426" + }, + { + "kind": "file", + "path": "img_2607.jpg", + "sha256": "af8e97c0655ed92515ed64b13aa9900e67c0dc2a048d3defe31bfa8ed1fc970a" + }, + { + "kind": "file", + "path": "img_1468.jpg", + "sha256": "ddf6816aec0a9569a4d0ea60f3a0186dd44ce213c7d616da38163ef2e9cc28b5" + }, + { + "kind": "file", + "path": "img_2161.jpg", + "sha256": "3a064d976e4f4bd72d33b61ed4737b2710eced8eb9cc123f5276c67d75cedd7c" + }, + { + "kind": "file", + "path": "img_14.jpg", + "sha256": "b8e53c45ecda2b4c9b80102d00e57acb3f5540bdcf24304232bfef9e72cab135" + }, + { + "kind": "file", + "path": "img_4510.jpg", + "sha256": "dba1ac2be48757923d129c6f53e57b7e779fb8c7b9085a97e747752284d9212b" + }, + { + "kind": "file", + "path": "img_488.jpg", + "sha256": "50fdf1883a26948bb39e7f99fdb47a79b20a7f4e6a9a8036ec38cc6406545981" + }, + { + "kind": "file", + "path": "img_1440.jpg", + "sha256": "88f75256e92487f7b726c8221492a666d16195a2190f21a95f22954f68ac967d" + }, + { + "kind": "file", + "path": "img_2149.jpg", + "sha256": "bd5a16c6c4050c632d646bd1671b88928812f80c699deb3c15fcd127b8bdbabc" + }, + { + "kind": "file", + "path": "img_4538.jpg", + "sha256": "c9f98957674ca208d6e6bb2770ec9efb1f3bed39679bfec53b314f5932f67e71" + }, + { + "kind": "file", + "path": "img_3257.jpg", + "sha256": "226c0f347497b9f1f93dc37530b2ff35c00fddaa5441880b060bf8f620c6a100" + }, + { + "kind": "file", + "path": "img_3531.jpg", + "sha256": "67bf66dbc6aeb768c163a845dfa45917812782aaddd3d830438cbc34fbb27257" + }, + { + "kind": "file", + "path": "img_1332.jpg", + "sha256": "6c33c74d85160da79bf82e3ce25f72e9fd9bf80dbb0857638a4b5caa4b4ca97d" + }, + { + "kind": "file", + "path": "img_3525.jpg", + "sha256": "60aede01a05742a1389be958d1a115f7bb2f27b60ff3c0cff3ed33aefe16ae67" + }, + { + "kind": "file", + "path": "img_28.jpg", + "sha256": "aa00de832ab3c059f8ab0ffc301075aad4959ffad5326d278ad910643bcfa4bb" + }, + { + "kind": "file", + "path": "img_3243.jpg", + "sha256": "e27e9b55a4643c52121f53d673568e9bb0df1c882f3cc0648352b174f5730033" + }, + { + "kind": "file", + "path": "img_1454.jpg", + "sha256": "28caacd5579d9be53f086f954c30a537ac0a2543c10bddfc65830a760e497c88" + }, + { + "kind": "file", + "path": "img_339.jpg", + "sha256": "3125f0d41c608aa50d8f4b17ea51f408b5f003dcfc6a9a183529db3e04df9467" + }, + { + "kind": "file", + "path": "img_2808.jpg", + "sha256": "a6d42b1cc62bb07c7ba62cbb6ca31d579853ceeb8a43c56ed2118f36054e76a6" + }, + { + "kind": "file", + "path": "img_1483.jpg", + "sha256": "ad6d725e45e33bacbd3b429995c262d34cbd0e9e32a6d2d9176e93fbec1c3f7c" + }, + { + "kind": "file", + "path": "img_305.jpg", + "sha256": "bd2b2ab4dda0baac98899e0a31e03f8d1eb488fb5a39c8b067066de4b0ccc955" + }, + { + "kind": "file", + "path": "img_2834.jpg", + "sha256": "ee0f08af8e189ab4641e0c5e3d5c8035802b35323a26e03b15aa7358e7df4db2" + }, + { + "kind": "file", + "path": "img_311.jpg", + "sha256": "33d9cd346bb5f10967e4999a16bb4145cf5afccdb6a30ce70f3526ba7ddc73c6" + }, + { + "kind": "file", + "path": "img_4289.jpg", + "sha256": "62e879ccfe920dc224661011c1b10bfad2220f5b108ac8d4c2dbbdd7fc2a6f96" + }, + { + "kind": "file", + "path": "img_1497.jpg", + "sha256": "c3f1d3fd6d6e214bcf1ee2915412b793f685cd2da9745e24239fa192eaaee886" + }, + { + "kind": "file", + "path": "img_477.jpg", + "sha256": "a750d973f4f948222e26beed1395b28d13ecfe68c36a96e1236bf1047afc67f5" + }, + { + "kind": "file", + "path": "img_3280.jpg", + "sha256": "e9e5a57eb521ff8fab9641564326e84bf0f9d53979cb816a3a035801cce6ac50" + }, + { + "kind": "file", + "path": "img_438.jpg", + "sha256": "aaff7417ad59caab888dfa15deb1be72292b8fcbdfd7040c4b30bad1ac14a1b1" + }, + { + "kind": "file", + "path": "img_376.jpg", + "sha256": "ef2321c91874c24017d6950217ad8d98aae9f63a40f837b3caffc937c6f8d52a" + }, + { + "kind": "file", + "path": "img_3581.jpg", + "sha256": "0e7881d8c36a079bc7b24fe4b7c1251d99d49fe203c3ed18cdd5f333567493a4" + }, + { + "kind": "file", + "path": "img_2847.jpg", + "sha256": "9a8afe0e28b823677e9d839dcb21a5063bb90a06500d806ea974977e7638b366" + }, + { + "kind": "file", + "path": "img_1396.jpg", + "sha256": "f191aadd4c2a9a5b21fde912e5d1e25c5ffc60a4957da67a67ccc471928065f0" + }, + { + "kind": "file", + "path": "img_4588.jpg", + "sha256": "55f159640f79926fa149104ed47cac2768869dd83f8b22bdd2ed0b4678d7b111" + }, + { + "kind": "file", + "path": "img_410.jpg", + "sha256": "ded43298e52ab76e26a2c17b06786d0a072e0009da9feb7fee2fca5b313fe597" + }, + { + "kind": "file", + "path": "img_404.jpg", + "sha256": "b1785409f4aea7cfb41873dbec517e8100a4dfb1de120cf89ba432cf5b236011" + }, + { + "kind": "file", + "path": "img_1382.jpg", + "sha256": "a17aff4f30c5463b92f5236235be67a0a54ff8c13d38da840df8e037c8828269" + }, + { + "kind": "file", + "path": "img_362.jpg", + "sha256": "1cc803668d675113d251028d1cc7ac3428bb177026f9b720a444ecd3d9553174" + }, + { + "kind": "file", + "path": "img_3595.jpg", + "sha256": "5ecc4a3219264cb6d30f4465d2cb9dfc0b52b571c7f259622170cd99b28a8552" + }, + { + "kind": "file", + "path": "img_2660.jpg", + "sha256": "d849b62607dd0cc64023456f8d84deac53009a4fa89f904bb5a649dac385ed1c" + }, + { + "kind": "file", + "path": "img_389.jpg", + "sha256": "1635b6f517faf7a9d2f9a2a473162572027939c92c004ac137b59dc513512242" + }, + { + "kind": "file", + "path": "img_4211.jpg", + "sha256": "e4859b7cad7760c91ac4ae2469f7d375ad47e39326b067ec3c738fe09fec5f85" + }, + { + "kind": "file", + "path": "img_1369.jpg", + "sha256": "78218b5bffcbaedfe76b6fa9cf4629f400e46beca77b0b43a365e5ffd0ac12ee" + }, + { + "kind": "file", + "path": "img_4577.jpg", + "sha256": "d7b8799cbd5068e3ea4798c9f98e1be051cd4f3bdb11288b46651b0fcac70bf6" + }, + { + "kind": "file", + "path": "img_3218.jpg", + "sha256": "ed97642532e5d307ed70a5926fc2ff1b2ee276a730def99c9e95b3c010f4fe82" + }, + { + "kind": "file", + "path": "img_73.jpg", + "sha256": "029628b4dbbd68d798bc5b73b9819b5cc4a0a3fc20c9b736a704b4398e58d784" + }, + { + "kind": "file", + "path": "img_4563.jpg", + "sha256": "9b81d4af13461abb4330aa903d50783b339806f921d3892ad7f0cb0e679a426b" + }, + { + "kind": "file", + "path": "img_67.jpg", + "sha256": "ba9f4e348800084fc6617a2f8b3a438f31605936a019e6acb9ac3d9176a51bd9" + }, + { + "kind": "file", + "path": "img_2674.jpg", + "sha256": "d56190b4fc4b9181d4cf12ec699a10119017108bd35e203574a4f10d0bd2ea55" + }, + { + "kind": "file", + "path": "img_4205.jpg", + "sha256": "745a8f22a871c67fedd6799562a01e70e6e6f5af3a987192fcf79a0ff73337b5" + }, + { + "kind": "file", + "path": "img_1355.jpg", + "sha256": "8f227b34869900cac49bc8d64fa70dfa0d0fc75afd573229cb2abfc655bea1b9" + }, + { + "kind": "file", + "path": "img_3542.jpg", + "sha256": "e9790035d17cf1ed9c21f6b19487ceb97cc86d10bb0fd9a7df9d35af97662218" + }, + { + "kind": "file", + "path": "img_2884.jpg", + "sha256": "39f2911ddc304b13ebe8c6a802dac34622dcc9749a15183e8fdcf4808ee9103b" + }, + { + "kind": "file", + "path": "img_3224.jpg", + "sha256": "81afe069aa5f3ecb309bc824d8912a930341c6e97b5f80edb1335153865aab2b" + }, + { + "kind": "file", + "path": "img_1433.jpg", + "sha256": "166be0a0bbe711c180c6a1482d59184ec52f25af692901c0f9c695a94c39fd36" + }, + { + "kind": "file", + "path": "img_1427.jpg", + "sha256": "f42c3f14a9c488c253515ad65b06325baadacf586c623e43187ce8e742f0f9bd" + }, + { + "kind": "file", + "path": "img_3230.jpg", + "sha256": "5546bbadb5a1620fb52566988e498626310d1f03db7036d31c2cda7478eec135" + }, + { + "kind": "file", + "path": "img_2648.jpg", + "sha256": "31895c52f41b7db1c18e165cf7a5f8e956c30a72d7f31dc78330b0ea94f4ca65" + }, + { + "kind": "file", + "path": "img_3556.jpg", + "sha256": "2291cebd6eac8760a2511fdaf2ddf3ac9482187c6986fd8cadfe07448cb20b70" + }, + { + "kind": "file", + "path": "img_2890.jpg", + "sha256": "4f564a05d185e7ba9cbe774a301fd3af9441e2e3d58a411e1090dbec752338fc" + }, + { + "kind": "file", + "path": "img_1341.jpg", + "sha256": "2949e06c368523a59d9cc773876b7a68d92093541404ff011583d204d735d0b7" + }, + { + "kind": "file", + "path": "img_1816.jpg", + "sha256": "3264a0a180cead9dff684c459675fd45b06ceb392e61dff8e92d88d0fb557379" + }, + { + "kind": "file", + "path": "img_148.jpg", + "sha256": "0e8d66bbd29319fc7248a31a16e0322aaa6f67bf9f66e123dcb012986411dced" + }, + { + "kind": "file", + "path": "img_1802.jpg", + "sha256": "f6fc8201e7e98b675a237f6438e4863b44d4d495a195e091b6e051c645d9a262" + }, + { + "kind": "file", + "path": "img_612.jpg", + "sha256": "1d67c718ac2f9ef2c20325d2efddbcd336e0f8b6cde4b76e77eb40aebad212cb" + }, + { + "kind": "file", + "path": "img_3783.jpg", + "sha256": "f69d8886cde77c8e8a5104e5485cf02bfd56ddaaa0853573c5af42c03aea200c" + }, + { + "kind": "file", + "path": "img_174.jpg", + "sha256": "65b94cf349bfdad010dbecbf482200add86a957b3b60f47f359a2d7ad2558196" + }, + { + "kind": "file", + "path": "img_2489.jpg", + "sha256": "558f895712a9dd44b83b87c8a96dda60a675165fb0702dec08c65ef5496ed786" + }, + { + "kind": "file", + "path": "img_3797.jpg", + "sha256": "af97daea9e180b6e51101a197b6433eea092deae76a1669ad8b949f39689bc63" + }, + { + "kind": "file", + "path": "img_1180.jpg", + "sha256": "94dfc6055dd54f5222ce1037f757e6731bbf7ae4553eca80c843b4abda19ca55" + }, + { + "kind": "file", + "path": "img_606.jpg", + "sha256": "50ab00c1c3faf835b484904bf5f28873264ca604b3ba65e6f56f8442258b9287" + }, + { + "kind": "file", + "path": "img_835.jpg", + "sha256": "6b5c52814063bc10ce64a2eaf2405d5e699670c5d68c02ffeeae35567ab7cb5c" + }, + { + "kind": "file", + "path": "img_2304.jpg", + "sha256": "f4192ca3ca5ae7c0575cfd4b2456235899688abe202dffe30f634da9a4387d1a" + }, + { + "kind": "file", + "path": "img_4775.jpg", + "sha256": "61edefc429666fd9ce107f769302f125ce0302e2bada83e91d6cc8f8ed1037db" + }, + { + "kind": "file", + "path": "img_4013.jpg", + "sha256": "31915b8d91b74e671d75aa25b25884a33897d25dc272cc06f44ae556e71d1de2" + }, + { + "kind": "file", + "path": "img_2462.jpg", + "sha256": "68063deb4783777ea30f0fe0d4e1ff76233c5ee9804cb51fccf6ee56ad37d38a" + }, + { + "kind": "file", + "path": "img_4007.jpg", + "sha256": "b528e1e9bfec26347ef508d3ed2bebdf7fd9de02e4f0011c02c8c9d49e185d1f" + }, + { + "kind": "file", + "path": "img_3768.jpg", + "sha256": "4811739428bfcfa63126d1659067e39a00bd3b33340931a7ff68b538c91aaf50" + }, + { + "kind": "file", + "path": "img_2476.jpg", + "sha256": "1fa1c9990b3bd9d8c785f35895ee3e7aabbf29f5004236ac5e1e78860e748470" + }, + { + "kind": "file", + "path": "img_2310.jpg", + "sha256": "b0137847a0aa586a1f48e511b25718ddc484cff3a1f32f732b6e95394628ce24" + }, + { + "kind": "file", + "path": "img_4761.jpg", + "sha256": "b5b11d71861e3187c80a26f0232492aa533b52ae12badeda66f4a9cbefbef102" + }, + { + "kind": "file", + "path": "img_1631.jpg", + "sha256": "c693ffe7a85df701a60cd6db890ef01de4c6dd6a1f9d52699ea0a63da714dabe" + }, + { + "kind": "file", + "path": "img_2338.jpg", + "sha256": "628b0fa44e57f3cf88d23ebaa9aff4208b7f685fb9c51abf44025bb2ea9c40d1" + }, + { + "kind": "file", + "path": "img_3740.jpg", + "sha256": "b973cba7902ff7a6f8227d200c0419ac5bf7c7bb0d188eadead888a5c350b05d" + }, + { + "kind": "file", + "path": "img_3998.jpg", + "sha256": "4bf1fd3cbd21f4bcb7c56550abb0e2bd7a2b040ab3ef3331e191e968ac61ec6d" + }, + { + "kind": "file", + "path": "img_1157.jpg", + "sha256": "d1ddd983b82d3ad979c5ceba93369bc1039d77ffd076e97d6237db58a8f8a32c" + }, + { + "kind": "file", + "path": "img_1143.jpg", + "sha256": "d13406da9a388c690432bce2da3bb354e033629be488cc8ccc980635432badfe" + }, + { + "kind": "file", + "path": "img_3754.jpg", + "sha256": "882704f9a87e982beabe606e3a827da07eb4c38a8c55cb9dbe6f021a99bdcaa5" + }, + { + "kind": "file", + "path": "img_3032.jpg", + "sha256": "2939214e650213e6ce1a20cb5a65ce506b30da3008cc742548198643dc0665ce" + }, + { + "kind": "file", + "path": "img_1625.jpg", + "sha256": "5fe27da57193fd9fe09d8d7a4061ae69eaf6828d65c94d0da97f853f281c007b" + }, + { + "kind": "file", + "path": "img_1962.jpg", + "sha256": "5e1b6bb1ae853f0dbae31daea91d40e2cfdde4d8910f2f076685dd34d6afe179" + }, + { + "kind": "file", + "path": "img_982.jpg", + "sha256": "2ee8af2f107c1c08bb51b16370223caf3f130e2f4f46c8c87f058c08ab6551e8" + }, + { + "kind": "file", + "path": "img_3813.jpg", + "sha256": "f8ef9fdf393d065e177fae7ba2bba56d77dda1ca21fb9e769262ef0a8ebb611a" + }, + { + "kind": "file", + "path": "img_3807.jpg", + "sha256": "02237879634e869fc6e5b41d3bfe434cd6ccc2bbd1154bfba2fa40dd4c6a1f10" + }, + { + "kind": "file", + "path": "img_996.jpg", + "sha256": "97fa6b76ea6ddafd560908565597a1141bf3140cfe8ab755de703c23d9b0ecff" + }, + { + "kind": "file", + "path": "img_1976.jpg", + "sha256": "5dd8faaf5786221be166249734fe490037c7cd6442d9141ef410dcaa692a75a7" + }, + { + "kind": "file", + "path": "img_3191.jpg", + "sha256": "4f79be2fdcc4fed605779d08394124279ad3743b1c35d0e36c691d5f4f6ee6ec" + }, + { + "kind": "file", + "path": "img_1786.jpg", + "sha256": "372d584356d281605e1ce9a73f58c0e03959b733470c4e5facfb7509159ec545" + }, + { + "kind": "file", + "path": "img_1792.jpg", + "sha256": "02984c6373da7fab2a9ccc14b4c9b5166a00ba54410d57e3c2057a3c84ed09d0" + }, + { + "kind": "file", + "path": "img_4832.jpg", + "sha256": "837563ad51dea33c0b428e5cdda2ede20e2e4f922d3c350d3c9cc9e77ec6cb23" + }, + { + "kind": "file", + "path": "img_3185.jpg", + "sha256": "7a67b4ba7feb2a5a3eddf47719048863451a0ae2f08c87accc808ee77c81c4c9" + }, + { + "kind": "file", + "path": "img_772.jpg", + "sha256": "a2fcedfd17833f1d8635da906e5df0c65438dddd13ab61135811ebcb1a420122" + }, + { + "kind": "file", + "path": "img_4601.jpg", + "sha256": "9b3e384ff801b21b9e65e80ece2ec6f3b5ce447c75748d118bcbd584e41f78de" + }, + { + "kind": "file", + "path": "img_799.jpg", + "sha256": "6720e730aeee67fe13b1a49d4acf83c9b14ce1498c7f1d292124ca931b03bdcd" + }, + { + "kind": "file", + "path": "img_2270.jpg", + "sha256": "a25cb5a7bda1af53778e4f4965917b010088b94b5456f4e531cf506d66078344" + }, + { + "kind": "file", + "path": "img_941.jpg", + "sha256": "a4831585c038debdaef87007c54b5f056e9fdafe23f423535844127c7bcea02c" + }, + { + "kind": "file", + "path": "img_1779.jpg", + "sha256": "d09499a66eb23b6787a50b7ac3cc95df569ba24b96ac51d991263241e0f8a413" + }, + { + "kind": "file", + "path": "img_3608.jpg", + "sha256": "6464fb425d732382b7b7550d226e56b6c1bd42b0d1272d0d91ec7bad0cd0baac" + }, + { + "kind": "file", + "path": "img_2502.jpg", + "sha256": "d98c27db31eff96f23722ddb2247cea9bf1c0ab61f67635c57d28d391a83b240" + }, + { + "kind": "file", + "path": "img_4615.jpg", + "sha256": "b339729ed5b0f99da4da44d036124317623a0b13637cc8d11760599ff1ea7fac" + }, + { + "kind": "file", + "path": "img_2264.jpg", + "sha256": "8ca1af71567ad86ad888b610f20a74e7dbbb58defac3dd44368c33c6e81845dc" + }, + { + "kind": "file", + "path": "img_955.jpg", + "sha256": "6e7342b6d2825074f62809d37901ae03a1e575e79c3ad8b58f4575a8a5362ce2" + }, + { + "kind": "file", + "path": "img_1745.jpg", + "sha256": "6c06b28fe6d5525a716652053902fb25df6dcf2b5f83b0b32e73a4ecba31eb5b" + }, + { + "kind": "file", + "path": "img_3152.jpg", + "sha256": "b48eb68ebec63451e04bcc2c7096898491d4fbf385cd5bcb126d0ccce770f5e0" + }, + { + "kind": "file", + "path": "img_3634.jpg", + "sha256": "52bce1a5d6c2158bf455f930b3d3fc1c066aaeafc346440dd2bb5295852b9d76" + }, + { + "kind": "file", + "path": "img_1037.jpg", + "sha256": "f3cf6c6176baebc94fa484d74699c3ba5916e760bb7b608dbf4fd1a623774556" + }, + { + "kind": "file", + "path": "img_3620.jpg", + "sha256": "4b751e8bbc360fb2aacbc3fd47bee95ff4c64889cbfb3ee7e99cdb639ca64b2a" + }, + { + "kind": "file", + "path": "img_4629.jpg", + "sha256": "f8445fbb176ca040349580f039bc8a0e4a33a5a5aaa605f36bf6f03c24e559b4" + }, + { + "kind": "file", + "path": "img_3146.jpg", + "sha256": "50f3c579fff7b374f56c2eb77f198f8b52549924dc33ddef22573b2d289130ba" + }, + { + "kind": "file", + "path": "img_1751.jpg", + "sha256": "beace40853f4fae4eaa9f0ae9fea55571453eeecfe2fafc7df829777bc2f19e5" + }, + { + "kind": "file", + "path": "img_1989.jpg", + "sha256": "128d64c0dd16b14708a37c394d58e9cb13b421dd33029a2a393c2ee51d441505" + }, + { + "kind": "file", + "path": "img_558.jpg", + "sha256": "1011c2dc88cb044945e06c994408a56a353f71261acd9edc670adee027954d44" + }, + { + "kind": "file", + "path": "img_2933.jpg", + "sha256": "967a1deb9c80e802edf1514f5afc2e26bb2307ebb882a1537514691d752d4f23" + }, + { + "kind": "file", + "path": "img_202.jpg", + "sha256": "fd67047e85c3d962eb423f69aa5846d6e76ee7f7c72d8eac6d2ee37050a9e10c" + }, + { + "kind": "file", + "path": "img_564.jpg", + "sha256": "086cf36386f3b33e1feabed3ac91afd3a89e77d743d05cb0131fa9f1eec6d0fd" + }, + { + "kind": "file", + "path": "img_3393.jpg", + "sha256": "2ceabc2b8a668e12955f73eefa16659ee6e8c5ef6831ed8ad9e8726678ca240b" + }, + { + "kind": "file", + "path": "img_3387.jpg", + "sha256": "28fc500c72fe421b41aec622d6c3acca63d0b4f19bf7839fb2c880f45726529c" + }, + { + "kind": "file", + "path": "img_1590.jpg", + "sha256": "55ca4fb0dca58a927fbfa81b963c0a7c2556608cf37b97b0ae496e4d156c5f4e" + }, + { + "kind": "file", + "path": "img_2927.jpg", + "sha256": "adc4cbe5f676b6dbd4546e92a2989b48b44e552b87ac54cf0fae61b5938aef39" + }, + { + "kind": "file", + "path": "img_216.jpg", + "sha256": "d4b35c2c05e769798ded4b8b79fc63d145347841cd39f5c5052d2f98b8a50d8f" + }, + { + "kind": "file", + "path": "img_4365.jpg", + "sha256": "f94e78873eb2809b13f55021fca991a55643dcff0a6b034df91fbbc25eb5690a" + }, + { + "kind": "file", + "path": "img_2714.jpg", + "sha256": "5362edbf59af71014da83814004773435c1403413c83c48441f457591352156b" + }, + { + "kind": "file", + "path": "img_4403.jpg", + "sha256": "5302f5794e53be89406f48f711ca69e394ff3326664b5a3650eeee6ed79fab08" + }, + { + "kind": "file", + "path": "img_3378.jpg", + "sha256": "99b1388bd73279fb6a944cc6c18c28ab6e30dd99ed16f57132099055a4c99822" + }, + { + "kind": "file", + "path": "img_1209.jpg", + "sha256": "d1e28a0f4ba0d0366347b4bfb5289a854d05f8ff953bba325ee67a0ff0b2faa5" + }, + { + "kind": "file", + "path": "img_4371.jpg", + "sha256": "d87f443c67666f3da31c7409b412482a7c41ff4a89ef2b987a1644a93f41759f" + }, + { + "kind": "file", + "path": "img_2700.jpg", + "sha256": "23ac41958168e459e3082ef6c329c70f3c0156e1b6970cfd045677d8bdbe3b12" + }, + { + "kind": "file", + "path": "img_1221.jpg", + "sha256": "209907224b206777166e498a476b8173a8552d853769c4c9d87da63252dac3f5" + }, + { + "kind": "file", + "path": "img_4359.jpg", + "sha256": "652481739cecdf23f7bf61afb2077a0202ccb966a9d9a963c0ad081214c42810" + }, + { + "kind": "file", + "path": "img_3436.jpg", + "sha256": "48376a7829b39e91b358b7bd6b891d6670e54e1c034521f4e6c5a6dc78f7ee4c" + }, + { + "kind": "file", + "path": "img_2728.jpg", + "sha256": "9b86dda29c93fdbe311fe8a5b509897660f64c56a9828de5e552a663bd237db8" + }, + { + "kind": "file", + "path": "img_3350.jpg", + "sha256": "b04d66bfafad87d19dd2aa90acd57f4668c7f43343bdaa6bf0500727e56f6b00" + }, + { + "kind": "file", + "path": "img_1547.jpg", + "sha256": "15ca0a6d4f63f992fb772687505a45c8e12f6e57926fafd368870b22965a3e53" + }, + { + "kind": "file", + "path": "img_1553.jpg", + "sha256": "e25a360e0809725298f8f0a31a3fa65bf94483cb006cf3a8eef740cd4e34ff91" + }, + { + "kind": "file", + "path": "img_3344.jpg", + "sha256": "a03829290eb8f0bf6bdd6e31cc6397b11537aa2030fedf65e8a8cec973934267" + }, + { + "kind": "file", + "path": "img_3422.jpg", + "sha256": "d250a7432e47ab409d0cdede0504d2d81f67702dee5054293683ddc2e72df748" + }, + { + "kind": "file", + "path": "img_1235.jpg", + "sha256": "cfa7aba8871566a3c74c9a7a8bf67ae81a1507302bf0d9d64bc6d67c9d59468d" + }, + { + "kind": "file", + "path": "img_3345.jpg", + "sha256": "7c711f3724f6c92aab5dede79eba2b32616e1100c75eaacbf192bc9990ea2ede" + }, + { + "kind": "file", + "path": "img_1552.jpg", + "sha256": "8243427406c504025f67926ab580201132f633d7d378ecea31d7a6635144562f" + }, + { + "kind": "file", + "path": "img_2729.jpg", + "sha256": "535f4b7f7ab55a8629bc0c07e4312d5d181e31ec395c55cbc45fdf590d168425" + }, + { + "kind": "file", + "path": "img_3437.jpg", + "sha256": "26b7347d823f60b68721503aef8c73f50a2fb0b85fb4effe37b8205bae23a909" + }, + { + "kind": "file", + "path": "img_4358.jpg", + "sha256": "db2f78889660019571711ae5a4b91b75a9e5712043ceefb47e269de7d3156f95" + }, + { + "kind": "file", + "path": "img_1220.jpg", + "sha256": "33f7d08d91abb9df11e467146f2ad975ab0e77c4f96000a0132da1effe395745" + }, + { + "kind": "file", + "path": "img_1546.jpg", + "sha256": "d4c4d9888ace6adede7163b377ccdc56b278bda0c1fdd6d78d0095ddbf37481f" + }, + { + "kind": "file", + "path": "img_3351.jpg", + "sha256": "0db4d0f97a3bb4b0b6ba5d89b072d6d4c0949962b8253c6665af94d59ad796a1" + }, + { + "kind": "file", + "path": "img_4416.jpg", + "sha256": "0c38ac875f314a895d695aefde05276b4db84d33af78d1cd1615810a22b244c9" + }, + { + "kind": "file", + "path": "img_3379.jpg", + "sha256": "d34cbbac77ff64372589405e150ff6e641a2654baf1f54d5146752ed1715338d" + }, + { + "kind": "file", + "path": "img_2067.jpg", + "sha256": "d31f62fdd6af8561756be2f6358b21e372e23b9866bc92a67927aa73b558c530" + }, + { + "kind": "file", + "path": "img_2701.jpg", + "sha256": "1bf55b7f91b9644895016692d6d181a06b576ed3374b0928fc7e6ee8a7465017" + }, + { + "kind": "file", + "path": "img_1208.jpg", + "sha256": "a1b5faef4716552d9878a31da86c59d323a8053b9a0d489ec2b0642fa9e57e40" + }, + { + "kind": "file", + "path": "img_2715.jpg", + "sha256": "de6a72d8c1e2a39d113c97ba7ffe09de6b8af459e7b7d76378e578f5994b5abb" + }, + { + "kind": "file", + "path": "img_4364.jpg", + "sha256": "56328c182df8fe3df71e976ea7dc66e9fb58b90d1bf89ee80e2975892115632c" + }, + { + "kind": "file", + "path": "img_4402.jpg", + "sha256": "244c94a4732960160048685d0af24227658615361520d3deea80c37fe4fc145b" + }, + { + "kind": "file", + "path": "img_2073.jpg", + "sha256": "729893b2870d6b9f3af07e18bcbb36da4bdd06f1b56b91b0d327137fb7adb5d4" + }, + { + "kind": "file", + "path": "img_3386.jpg", + "sha256": "99e65c239912d8b40730dc662bcee92afb29d9b09b8890eb744513570ca00b59" + }, + { + "kind": "file", + "path": "img_571.jpg", + "sha256": "6f3a652d4e1dbc075557053a068de111a4289f5c3eab764b45ee10e966e8f4b8" + }, + { + "kind": "file", + "path": "img_217.jpg", + "sha256": "dfebcecfaed9bf2721e3dc173332bb71a726b30985df84ec178dc417c7e51801" + }, + { + "kind": "file", + "path": "img_2926.jpg", + "sha256": "15a46fcae677bcc686551c5e1a7ab90198da6164cf092e08dad46fd289bbbfae" + }, + { + "kind": "file", + "path": "img_203.jpg", + "sha256": "9c19f1895cb0b186860016fe2b215cf4ccfb38db1daf0836ca4af7a035ffc235" + }, + { + "kind": "file", + "path": "img_2932.jpg", + "sha256": "ba0ed88429ec31ecc5a6b4910543d2531a783c7d7d3aa68ba904cd206efe3c68" + }, + { + "kind": "file", + "path": "img_3392.jpg", + "sha256": "2bf3f7eecea8b54a66d6c82ac26234bf89b6a408ba25631946d9b5dd5cd3cc57" + }, + { + "kind": "file", + "path": "img_565.jpg", + "sha256": "df6214b01d0342dbbda264333ce4e0579b893d39943adb1f74daec200f2a2216" + }, + { + "kind": "file", + "path": "img_1585.jpg", + "sha256": "5c99acb8d325d225f79781daee2ad20d87ecb590397f2e935cd14725c75d041b" + }, + { + "kind": "file", + "path": "img_559.jpg", + "sha256": "29159aab385f9878ec6635d1b1957c0a8c30791896474752c0a58b91590dc525" + }, + { + "kind": "file", + "path": "img_3621.jpg", + "sha256": "427f198df438fad318fa98805afbb2d42810462f54da78fc0409bd59b6262fc9" + }, + { + "kind": "file", + "path": "img_1036.jpg", + "sha256": "b7cf3d9a56ba259057a3304a659d0e307153bca50689fcd00acc4b87b212693b" + }, + { + "kind": "file", + "path": "img_1750.jpg", + "sha256": "7de6d692bc2a7fb00b6cd751762fb1cd5412e8afa696965f6ed93947c74eca55" + }, + { + "kind": "file", + "path": "img_968.jpg", + "sha256": "c6ab825fcb50b37a341c3881fc6bb142970c6bdafff3ca83741d3499af7e44e9" + }, + { + "kind": "file", + "path": "img_2259.jpg", + "sha256": "2e7ffc1cf7c9171770cbf0d29653b1da39f6e1038a8dddd355b7ac7e3a418478" + }, + { + "kind": "file", + "path": "img_4628.jpg", + "sha256": "7aa0b4c38ea0b96a780e86e473af69f3ef72d6cbe6f01928144cfd52f00704a5" + }, + { + "kind": "file", + "path": "img_3153.jpg", + "sha256": "99517aa15011c2adc4ea5f68cd4095a3e37816e3dfc1b348a858672596e882b9" + }, + { + "kind": "file", + "path": "img_1744.jpg", + "sha256": "01f19abba01de339026f24efe0f2a1ce2556f4c5be5300edf6bb3c1825657b04" + }, + { + "kind": "file", + "path": "img_1022.jpg", + "sha256": "12dcf83e5f6c997c521a0753cf2e89c7ae273d41416e84010f83905434668a24" + }, + { + "kind": "file", + "path": "img_3635.jpg", + "sha256": "dc6adfccdbfab42301c435a6d7ecd41e21fd784bbf7a57172a482a97a466d50a" + }, + { + "kind": "file", + "path": "img_4172.jpg", + "sha256": "d9f8ce210b6e77db8d546bc70fa08ee0f22b3d4392d006d501d773affff5d945" + }, + { + "kind": "file", + "path": "img_2503.jpg", + "sha256": "2f2c5bee3b7238c0bda0f0e1b0eca045cd3d3e18c7ad071d766bc79ac1a879b6" + }, + { + "kind": "file", + "path": "img_2265.jpg", + "sha256": "207e3ff4dbb9c158719157e55acaa3ce9424a17e3116f256a636bca79b7d52d1" + }, + { + "kind": "file", + "path": "img_4614.jpg", + "sha256": "ed776e7d66a84efa3ac38feb95321b6778380b348e465169c8b87c33bffddea8" + }, + { + "kind": "file", + "path": "img_940.jpg", + "sha256": "8ad7a5e9017e0ab1026e7b182ba195d693e182af49d949c58dc3915442aaf5a8" + }, + { + "kind": "file", + "path": "img_2271.jpg", + "sha256": "f38e3052dfd2c384ac65bdfed44f81af5b8e56326c359a9838b548b2b1dfb9dd" + }, + { + "kind": "file", + "path": "img_798.jpg", + "sha256": "60a647aaea2160d10e7326376035cc34a0f1e49635f082fd1af146744cc40fad" + }, + { + "kind": "file", + "path": "img_4600.jpg", + "sha256": "38bd8b94bb277598d94f4af3faa28df7bf9c00f8dba2c0db93efc41b7e077382" + }, + { + "kind": "file", + "path": "img_4166.jpg", + "sha256": "308f7ca78c9b744df590b3ec4bda22590583e29f0760d18189ccb65403ab1fcd" + }, + { + "kind": "file", + "path": "img_3609.jpg", + "sha256": "5ed80bc53f9efeacab76f7295682c8d7840cb2aec9103a428ba14fac9db1100c" + }, + { + "kind": "file", + "path": "img_2517.jpg", + "sha256": "04c79bfcfcd4de24c3575882b2bfc99b1b7ae515a65468e60a123bf0782a7c3b" + }, + { + "kind": "file", + "path": "img_4833.jpg", + "sha256": "4b9d8161cbd1bbb5a0771a38daafe2f4f4175ab17a198a6ca6a9260acbe88057" + }, + { + "kind": "file", + "path": "img_1793.jpg", + "sha256": "b13da581b80ccdfac276e4d04cb26f5a61559a24eea4504a707385017b63835a" + }, + { + "kind": "file", + "path": "img_1787.jpg", + "sha256": "15c08ab55112d6868fd3b6b0cb87eb699a923a41ce622294aa1aa7173dd587ac" + }, + { + "kind": "file", + "path": "img_3190.jpg", + "sha256": "8a340ef2ba4f1ed424f217bd501505b196c7921da4034c1472e81398e495e758" + }, + { + "kind": "file", + "path": "img_4827.jpg", + "sha256": "3c6b4f1342e3a5be5c0a843b773b6abbb14e7f1562e58a37d0ab64797f5ce08b" + }, + { + "kind": "file", + "path": "img_4199.jpg", + "sha256": "2a49cfb1c569f88b72cd7dc76a95b7b7f16dc12e62b53f47302f9d0bf7687db3" + }, + { + "kind": "file", + "path": "img_997.jpg", + "sha256": "233e5221a50ae83d436073d1b672497aaf85c728cb20efaf73098c8676695127" + }, + { + "kind": "file", + "path": "img_983.jpg", + "sha256": "af96bd81ea615c2f58107521b5a53725773a7d56519eb0b7c4e640e35b9593b7" + }, + { + "kind": "file", + "path": "img_1963.jpg", + "sha256": "0d40e21310fd9b4113227e2ee297ef6ec9a877b98ed9c771e50b1533ef484528" + }, + { + "kind": "file", + "path": "img_3812.jpg", + "sha256": "6d208e8578710b3209cb4885d8ce0b8a48823cc189482e61b0ef08ccbf89b594" + }, + { + "kind": "file", + "path": "img_3755.jpg", + "sha256": "9334feb0336352ec7561f52f29791d58807aa13280e87ef9d4e3cacc0f8d6ea0" + }, + { + "kind": "file", + "path": "img_1142.jpg", + "sha256": "13eba7c1dc8793fe4f8cc110614671e8a430dbf89b24e4d80d8c19a316a88dd3" + }, + { + "kind": "file", + "path": "img_1624.jpg", + "sha256": "08371c9fb235913b2845583b04b96ded074d691ffaea8618228a294339aa4c05" + }, + { + "kind": "file", + "path": "img_3033.jpg", + "sha256": "376e9346c4e567f4149bfafd92d3e2b1443a8b2d341d5de35574860cf4bb4211" + }, + { + "kind": "file", + "path": "img_4748.jpg", + "sha256": "cbe80721f37976063024fb2ef70561af5386ab11715bf4ba9ab68d36e121e4ba" + }, + { + "kind": "file", + "path": "img_3027.jpg", + "sha256": "e851cb21b57de0e5191ac4b8f74737894d5ba0f2f690ae164ed83504f0ea7b48" + }, + { + "kind": "file", + "path": "img_808.jpg", + "sha256": "6a72725f628fbf964c034177d77a8a4e06ecf37eda7e6af43d5302e715b5511d" + }, + { + "kind": "file", + "path": "img_1630.jpg", + "sha256": "5d01d028a4d4ac315dba11c3fd6b1a443bf2872b514eaaa795ef16ef95187efb" + }, + { + "kind": "file", + "path": "img_1156.jpg", + "sha256": "10a0300a3abcc19ce9f60a5da19e602333bf052782791b33c8475d106f57efd9" + }, + { + "kind": "file", + "path": "img_3741.jpg", + "sha256": "596f7db9559ee0ba1ed82d19308c7291fa833de0ef10dd0e08d35cd31e839d67" + }, + { + "kind": "file", + "path": "img_2477.jpg", + "sha256": "01894857d8130a3dceba262b016ecd10bae19b39bed7c51023cc29b0b12ad26f" + }, + { + "kind": "file", + "path": "img_3769.jpg", + "sha256": "c0ac2b910b0b819fa00d2453cf2b9269d6ab63f69e9e0b9d40d96c531a2766af" + }, + { + "kind": "file", + "path": "img_4006.jpg", + "sha256": "c71e1921c0b8c1691ed9bef95db3ed03a8a0ed4ddb824c5f222c8258bde8884b" + }, + { + "kind": "file", + "path": "img_820.jpg", + "sha256": "996dc1df972a68e3eb1ab9dc2cb387c165ff700f635ddb97a8ae1b5324ef093f" + }, + { + "kind": "file", + "path": "img_2305.jpg", + "sha256": "773c003625b8dcec50a932cca702d4a301a3062718dc4ecec81c8d750c550599" + }, + { + "kind": "file", + "path": "img_2463.jpg", + "sha256": "79e248700f275445ae7470caa8d2664faa728e04842a72b77d293c7160654813" + }, + { + "kind": "file", + "path": "img_4012.jpg", + "sha256": "b72ed8ee4a5541b73ca13043d5a91068b7e427127f8f3d33efad10af564feae0" + }, + { + "kind": "file", + "path": "img_161.jpg", + "sha256": "525d93071b0e9df0b9622b54ab76ef8b5d5f1caf5a8780894fe4722e0a33aefa" + }, + { + "kind": "file", + "path": "img_3796.jpg", + "sha256": "ed5e8f565017af90ab8394083caef4515db1ef2a1487e37bbd4f361f315a3f7f" + }, + { + "kind": "file", + "path": "img_2488.jpg", + "sha256": "fe64587ea133d27bd329db93f74a68a3c7372999f16466b599000ad7b578292c" + }, + { + "kind": "file", + "path": "img_607.jpg", + "sha256": "33d90cbbb78edb82e69f6ef64346c8462fb4062b18094359f66f4eb4fed24cad" + }, + { + "kind": "file", + "path": "img_175.jpg", + "sha256": "0242120b6dbf311d51853ca5a3b2e1cc86d25dc87d1ac95fbd8fdc567e8514dc" + }, + { + "kind": "file", + "path": "img_3782.jpg", + "sha256": "2229107123ed4c534cb8cf445d98e30b048a87e9a7ee6d792778fa1059e07d23" + }, + { + "kind": "file", + "path": "img_1195.jpg", + "sha256": "9bd71de3f871be69e4b73b4199f636bfe70f198ad8703d7506f108b831a8a5a8" + }, + { + "kind": "file", + "path": "img_3972.jpg", + "sha256": "7b6f911f46cb81f88fa7b60bcd0877588cce5536c016eb04e4a2b89dfcc81a05" + }, + { + "kind": "file", + "path": "img_1803.jpg", + "sha256": "5145338c3d1145b91ff27ccf8a3bfe955798c7d90fa93575f6af8ca550750caf" + }, + { + "kind": "file", + "path": "img_1817.jpg", + "sha256": "9ae7fea0453c219b584eee9a189d6523254c134b7ccf561de28e5ccbeb4b7dae" + }, + { + "kind": "file", + "path": "img_3966.jpg", + "sha256": "e8b47cdfa23126defa1c865dacd05830f45ef49b3f89c2e43e0ca380549b9eb6" + }, + { + "kind": "file", + "path": "img_3231.jpg", + "sha256": "d7cbbbf5705aad5618d63dcd63a788188a3bc5a680ea09ea7b6518560d30b01b" + }, + { + "kind": "file", + "path": "img_1426.jpg", + "sha256": "9e1764677796aabbdd2b9435d66faf64343da327ec21574b8bdcb90e2348ba8c" + }, + { + "kind": "file", + "path": "img_1340.jpg", + "sha256": "7784286cdf0bfaba887aceaa549a2122dab69e5d9636238c6be80baa4760d54a" + }, + { + "kind": "file", + "path": "img_2891.jpg", + "sha256": "8c4c3b8ae78628bd60fe02681984ae64c7dd1e36a359d2a01b63013c661163dc" + }, + { + "kind": "file", + "path": "img_4238.jpg", + "sha256": "6af4ad3ccfc573bb940e53f8b9b14df70da2a62cd53edbb03868e6dde0d24994" + }, + { + "kind": "file", + "path": "img_3557.jpg", + "sha256": "852dfb669fd21b4a68c789199288f9bffae0e726ee6497ddbec31ae9ba8ef26b" + }, + { + "kind": "file", + "path": "img_2649.jpg", + "sha256": "5d7e1b6e3ac9ad5f7f530abca64c2a913aff47aefd487e733ec00031936e9f8b" + }, + { + "kind": "file", + "path": "img_2885.jpg", + "sha256": "6324d798687d9d160418e0458e25b31b28594b36163aa20eceec1bbfe53be4bb" + }, + { + "kind": "file", + "path": "img_3543.jpg", + "sha256": "e6a6748bb0b22e81d9fdcada3dfae6827f2fb0467ba1b030eba847951f4c7687" + }, + { + "kind": "file", + "path": "img_1354.jpg", + "sha256": "af87beae7d852de4880fc710ae5a36d0b47c58f2b73715f7db0fad281b82f084" + }, + { + "kind": "file", + "path": "img_1432.jpg", + "sha256": "a9d2e499b74b0ac48dadaee5c3969407fc001d4d3d03aff8482b4c2c030cc491" + }, + { + "kind": "file", + "path": "img_3225.jpg", + "sha256": "2a4e70e2fa0b284ecf8bc9b3e9814e4dc24e6674476eaa820460345cd2f7de6b" + }, + { + "kind": "file", + "path": "img_66.jpg", + "sha256": "bbb7a5edec555883ff2ef86656e8f1260fea2f3d5a1afd9add5a11ea83f1ca29" + }, + { + "kind": "file", + "path": "img_2113.jpg", + "sha256": "6e198c1bf0d98753b101672e3e867e9a1effc15c9fc8ab9c5a0cb66ba068b4f8" + }, + { + "kind": "file", + "path": "img_4562.jpg", + "sha256": "ac18ebb942562cd1b28636c9f7e5a2f5b97909558a9aa3ea8d2e5724a8d0ed43" + }, + { + "kind": "file", + "path": "img_4204.jpg", + "sha256": "6d49d10d193ff19b9cca1fad51bd7076c0d56d7b3407b8da74a3aacf9fbf8a58" + }, + { + "kind": "file", + "path": "img_2675.jpg", + "sha256": "63b867a1efa37876416bfa892c670af99b937ea2e8f3bab1150c97f460c4c607" + }, + { + "kind": "file", + "path": "img_4210.jpg", + "sha256": "2715521ebee5e5af6eebe8aa6a7029615842a27dfdc3a09066f70ce3eccb003d" + }, + { + "kind": "file", + "path": "img_388.jpg", + "sha256": "6ee489951fe60494696b81577d74ebb3510b2992d17ac44bd3384760f2c3c239" + }, + { + "kind": "file", + "path": "img_2661.jpg", + "sha256": "c761afd81013057e6f2239c3d06c1569e54407bb8c962fb46e64fc4b406b359a" + }, + { + "kind": "file", + "path": "img_72.jpg", + "sha256": "3dd9b7fd9b33cad787becfbdb0bd0ba38d8b66eb9786aa3ca48bcd131ed409f4" + }, + { + "kind": "file", + "path": "img_2107.jpg", + "sha256": "32be20efae3df56cef39ce0d9f7c03cb8a093f6e249ed93d0d80ed4b3077b6b4" + }, + { + "kind": "file", + "path": "img_3219.jpg", + "sha256": "b3f7adff5866d51c286f7363cc951b4c9a5fe7a072610f9d1b966b9fd54d7c90" + }, + { + "kind": "file", + "path": "img_4576.jpg", + "sha256": "5cc8ca49a8b564e0bc7c0ddc589c738135603cb4a6b0468d91a3594120b15410" + }, + { + "kind": "file", + "path": "img_405.jpg", + "sha256": "61565b3b1e77c40c3bd6466d7344999720ca9d4c6c60a92498e8697ed02405c7" + }, + { + "kind": "file", + "path": "img_99.jpg", + "sha256": "0f52425ddb0fa2f08762eddfce8670595fc02d3d012c5169373dc86981358cd4" + }, + { + "kind": "file", + "path": "img_2852.jpg", + "sha256": "71750b5ecf7b75575169ded58a45b595f5f8c5582ec1d22e6207e86cd473ea07" + }, + { + "kind": "file", + "path": "img_3594.jpg", + "sha256": "ed15a988703ecb2d2f03d5f7b835c882ca3fa5b2e4ccafbfba43e5384bcac45a" + }, + { + "kind": "file", + "path": "img_1383.jpg", + "sha256": "087d03e18fa7eef53f2d7b4b64c0bf1f7cbf7b48ab249c251b227dd523a88cd9" + }, + { + "kind": "file", + "path": "img_2846.jpg", + "sha256": "28c1eabcb2f9de0b2ae039b8ee824456bd656ff50de1557854f825e95f04412d" + }, + { + "kind": "file", + "path": "img_3580.jpg", + "sha256": "e19d4831569e11ac2dfe0e16e03869a3368924f48164d1532d549e021ed046b8" + }, + { + "kind": "file", + "path": "img_377.jpg", + "sha256": "51bf2a68298632f701ec8c75906a8743670000aebd49e0a5be6cfd2cccb1740f" + }, + { + "kind": "file", + "path": "img_439.jpg", + "sha256": "9c26b6919bcb2ebd599456132e4421aa9ffaabf28409a1d4ece6cfa5168d9e31" + }, + { + "kind": "file", + "path": "img_1381.jpg", + "sha256": "768fac316ec6acf8686f2e037da7a1fe2af9114be2b93ef924a20dc7ac2ef25e" + }, + { + "kind": "file", + "path": "img_3596.jpg", + "sha256": "0f56e3ca948ca0ce23851d678c21064f11d57f460647a4bb3cd48cc16e24ba22" + }, + { + "kind": "file", + "path": "img_2850.jpg", + "sha256": "e15a6db899a3955a8b69b42b014274e8ca5636bc1e1e1a265299982e13b40af8" + }, + { + "kind": "file", + "path": "img_2688.jpg", + "sha256": "76ce6f3f9657e7e4da2c59a55ede736fffda24c6dcff4daa8dcba00cc89084ac" + }, + { + "kind": "file", + "path": "img_407.jpg", + "sha256": "69edb2cd98bc81c6cb5d733ad1a6bde627da7cc944957c5b9994b03625950f70" + }, + { + "kind": "file", + "path": "img_413.jpg", + "sha256": "d9823c392a84d1171b061ace21a97fa9853cf8be7b30b31894e4738569903492" + }, + { + "kind": "file", + "path": "img_3582.jpg", + "sha256": "64e7bf366f4ad9737fd9647c2a7e97e5e2e92e9f788b07f144fcaac6dc874a61" + }, + { + "kind": "file", + "path": "img_375.jpg", + "sha256": "b158ba96b8fa1bb934277c85a2ebef830c587d0bd3601a83b51ea53a26ff6139" + }, + { + "kind": "file", + "path": "img_2844.jpg", + "sha256": "131005192022c499d3ed68bf9e73950a9bf9d397a42f435c43e4f1d40daca270" + }, + { + "kind": "file", + "path": "img_1395.jpg", + "sha256": "3439e6daee6d46b8002f9670594b22557754a3803d6b3a2eed4a71011f7fc485" + }, + { + "kind": "file", + "path": "img_3569.jpg", + "sha256": "55f8cd3bad0ebb33dfd65cbca9e4b0a79162f0503ebf851cdeb40feef2cf772a" + }, + { + "kind": "file", + "path": "img_4206.jpg", + "sha256": "9339acef612c019069157565fc9891c5b67e402a39aec15dcdfaab46e4d22068" + }, + { + "kind": "file", + "path": "img_4560.jpg", + "sha256": "43a43d81157b3b1a3015386edde6afa3e1085132a623c2dec4fb703e1855a441" + }, + { + "kind": "file", + "path": "img_2111.jpg", + "sha256": "60208c869289f51df99369e75b36ae6f280125630b7e51cd1f65f1a1cc64f50e" + }, + { + "kind": "file", + "path": "img_64.jpg", + "sha256": "2feb4deac7e69ffc8ad19a1b3de9b778e4f58a81518e5bcfdb1a3af07ae1ea16" + }, + { + "kind": "file", + "path": "img_4574.jpg", + "sha256": "b00354c1fc0e1609fdf222be8e6f26b0cf34fc71b55782a55e6f64e288a2871f" + }, + { + "kind": "file", + "path": "img_2105.jpg", + "sha256": "51d7c9ab38380656ff8ef553ae418c875794f3201d17696abfc1b7a9d84eceb8" + }, + { + "kind": "file", + "path": "img_70.jpg", + "sha256": "7411d754e62d2e49f3adebf1fb8fdd1a0c89cb925c88a021e4694951167aae88" + }, + { + "kind": "file", + "path": "img_2663.jpg", + "sha256": "92188a575f432027a776e701abd0f4c48f9a84d0493d733e09c97078979fd5ac" + }, + { + "kind": "file", + "path": "img_4212.jpg", + "sha256": "79dd080aebbcc03fe6f7eb5b87836367e9b271aa98aa51bda443ada32f2f0f85" + }, + { + "kind": "file", + "path": "img_3555.jpg", + "sha256": "294f9a1f188a4f4df9c97999a7a0a21d0a7679b49ee535cb5e709468a552d59d" + }, + { + "kind": "file", + "path": "img_2893.jpg", + "sha256": "75278d1fb186c775f41fcdcb9aa321e6851c30179a2203e7037cc36de2b67c32" + }, + { + "kind": "file", + "path": "img_1342.jpg", + "sha256": "894850dac66e6365f0863e7b11d774bed0a98c320148a2b92ab811da7947cd0c" + }, + { + "kind": "file", + "path": "img_1424.jpg", + "sha256": "2147c4bf3acd2013f4b6d8a6146951b73dc04f1c779375682108021a320fac2e" + }, + { + "kind": "file", + "path": "img_3233.jpg", + "sha256": "367d3b2a4af0cdf9b7839a143ed76f7cdc82b0595a25da4291d368a6c90e966f" + }, + { + "kind": "file", + "path": "img_58.jpg", + "sha256": "849d7c06e990211c9d3f6175773ad9cac153a8f9fdcaf7f1724c66f2f48307d1" + }, + { + "kind": "file", + "path": "img_4548.jpg", + "sha256": "9ccb4c31d5242f924c70ede09c2c6ed1059201d1b5af85ff33a81bef057d5738" + }, + { + "kind": "file", + "path": "img_2139.jpg", + "sha256": "5d54497a965d6be52b5592d3011dd2348bb682a0394cb04e9d8d5d1526d1af1b" + }, + { + "kind": "file", + "path": "img_1430.jpg", + "sha256": "5286799a0fb412416c964b80f4105f25cb7866f6678d9e0b8f4da29c71540464" + }, + { + "kind": "file", + "path": "img_1356.jpg", + "sha256": "377e95237066753c48441f2fbd97ea44085ecef600b41690173465254ffe3077" + }, + { + "kind": "file", + "path": "img_3541.jpg", + "sha256": "d746df6114d97f11600a07d44ba4f46eba076a44348d7e50da819efb5e8e9368" + }, + { + "kind": "file", + "path": "img_2887.jpg", + "sha256": "bddaa7c93113bb1ec31fbf681316ffc7c2d9eae01eb5937ea541a8c577556301" + }, + { + "kind": "file", + "path": "img_639.jpg", + "sha256": "11afd2bbd7bd0b8efc5748e47a4851c2b00c49526d761da93f73150bcecec194" + }, + { + "kind": "file", + "path": "img_1801.jpg", + "sha256": "889609886ce5a8e1d7b57c075ce79d367a0df5bfb37501bc7d5bbf1f6d115255" + }, + { + "kind": "file", + "path": "img_3970.jpg", + "sha256": "ddbd3ee6c35e36331e5a9826a08761ea4456efbfa08fc1780e95e7c7b266095c" + }, + { + "kind": "file", + "path": "img_3964.jpg", + "sha256": "6ed56e40f7f744616b1b170469bd998eeab44079cf6c04769d2da4a521b6f4a7" + }, + { + "kind": "file", + "path": "img_605.jpg", + "sha256": "ce0010c107b267677081e8426e3a048e584e192070902f95f1e51462eda6818a" + }, + { + "kind": "file", + "path": "img_163.jpg", + "sha256": "1a1332808b0b58fe61d8953c383b6b9883e4c4959e522adbb0e33181aee871d1" + }, + { + "kind": "file", + "path": "img_3794.jpg", + "sha256": "94cf06f49160f715b29bda50bb137e2b4c72a2b1b061b905831123287ccf7e30" + }, + { + "kind": "file", + "path": "img_1183.jpg", + "sha256": "6491bd75f5de19b8eed2141bf695a0fc267910a76b5c3f480adf2a296a7831e6" + }, + { + "kind": "file", + "path": "img_1197.jpg", + "sha256": "d7e6d002925117389f1a37219fae7cd8a15ac4a76ce6ace023027376eef64945" + }, + { + "kind": "file", + "path": "img_3958.jpg", + "sha256": "c5ec955e32bbd7ce15b94dedba2b948d103c75cf3d87eff3f7edf13dc121a256" + }, + { + "kind": "file", + "path": "img_177.jpg", + "sha256": "fab67a58e781cbe2124742c87d91845e0f496728f3edee9e5f6c94203dd53325" + }, + { + "kind": "file", + "path": "img_4789.jpg", + "sha256": "ebacf310ec3ee16e51623588a5b784e31f802769bd14eb0f6876e242842134fe" + }, + { + "kind": "file", + "path": "img_1829.jpg", + "sha256": "52daeb09d15a7c482bf2d8ded13ed77264c841966c4f7fff158cceea8dfcfc1c" + }, + { + "kind": "file", + "path": "img_822.jpg", + "sha256": "93e4b01dab1db80b1f302a5370e0c36ee5d8f6ab55a4df420620be8db73735c8" + }, + { + "kind": "file", + "path": "img_2313.jpg", + "sha256": "ca47795e160fcbebb1eb3c20954c67a7544c90f7d0e147dbd34cab157694ffdf" + }, + { + "kind": "file", + "path": "img_4762.jpg", + "sha256": "ba53e22c60292d314135c89c31d78502cab682be0c0f3083a461fa8848920463" + }, + { + "kind": "file", + "path": "img_4010.jpg", + "sha256": "2e224c3123d3355e3f9ec7f8ec1f8992043d31a8d60c2c697e21a079a0f365f7" + }, + { + "kind": "file", + "path": "img_188.jpg", + "sha256": "e29b101578ec30f6b49366b748ca313aa952afcbefb2510a011aba16f8bff304" + }, + { + "kind": "file", + "path": "img_836.jpg", + "sha256": "ae8b8495167658098085e679b56fa057082d2c86a4dadb212657beb536ff6804" + }, + { + "kind": "file", + "path": "img_2307.jpg", + "sha256": "0c4f7d953ef86775e3fdfd3cd06d2382d872506ef9f65f5bd734ec88a5789373" + }, + { + "kind": "file", + "path": "img_4776.jpg", + "sha256": "2a24efd9ff2b22ac71bef918f95fd3eb86eca908e8ebfaa8e87187ef2bb7699e" + }, + { + "kind": "file", + "path": "img_3031.jpg", + "sha256": "8c336786aaa2a45278a03e26993f519fce06542d0d17a9ec94a57ec7b6845ffc" + }, + { + "kind": "file", + "path": "img_1140.jpg", + "sha256": "5cf2fd396e72c81b2a3dcf4a1be93804906665f6a0cecd8b44588561e46239c1" + }, + { + "kind": "file", + "path": "img_4038.jpg", + "sha256": "36da967d9879602869e53c1b23eb9482545b5517b4aebf68db795621b8cab20f" + }, + { + "kind": "file", + "path": "img_3757.jpg", + "sha256": "9c5d4e80951ee86e044fbe210b3f071aa548d7d708f9be48d5530c3698a13099" + }, + { + "kind": "file", + "path": "img_2449.jpg", + "sha256": "e30bc994c4d9696cbfacfc8bec54a8116b9c4309a5454a848dbeb279562bc944" + }, + { + "kind": "file", + "path": "img_3743.jpg", + "sha256": "d9fa65a242e58defe28d6d1624a16cf00a3dad152a72a4d5df03ce4b3b152cae" + }, + { + "kind": "file", + "path": "img_1154.jpg", + "sha256": "5b0ade4d80dec124770bdb374f2f93587cbced7b86f766ab97e321403377b4f4" + }, + { + "kind": "file", + "path": "img_1632.jpg", + "sha256": "f44c391c53bd6fd6763258f392af24a2ea57c0c72002265a984bb4787529ac2b" + }, + { + "kind": "file", + "path": "img_3025.jpg", + "sha256": "113905631f35510b40ed154b8baa4f7bdf4f5168b2e3db9089fe22531cab4a7d" + }, + { + "kind": "file", + "path": "img_995.jpg", + "sha256": "6e6c4cf2bf051d1e1e7988a413a54213c68781d20a9633a60d3bfbb8ea2eaa5c" + }, + { + "kind": "file", + "path": "img_3804.jpg", + "sha256": "c390d45ab7b26173ef4250fc2039cbbbb40340f1becb52e2ba92ffe3b3073a42" + }, + { + "kind": "file", + "path": "img_1961.jpg", + "sha256": "c48271ff33ecfafc28cc0062250ba3c364c3e6fdf7554cecf8072b34b11b20ef" + }, + { + "kind": "file", + "path": "img_4819.jpg", + "sha256": "5dadb83d8ccc9cbd5ccdbb7d4de91d0e9a2c74b2f83e430a016b6b66f2557eed" + }, + { + "kind": "file", + "path": "img_981.jpg", + "sha256": "23e6d4437375383c15718ac0627954422f98c5c92276d3c631b09a28d57444f9" + }, + { + "kind": "file", + "path": "img_759.jpg", + "sha256": "52e550135a6bf3e930e63f7a1d5fffe8e975ed589d2219e9e3a8f600608a3642" + }, + { + "kind": "file", + "path": "img_1791.jpg", + "sha256": "0b939526dfa152505c63fcd1d35bd069ccdb643c1317b8a85c279823bc7dc269" + }, + { + "kind": "file", + "path": "img_2298.jpg", + "sha256": "7a7cf7701fa2c7ed93fc18ac10c27a0852af4ee953f7a5031055e26c6b89ef72" + }, + { + "kind": "file", + "path": "img_771.jpg", + "sha256": "4f95cae0e2af0bf6eb645afc79d1eb52e8d5b12f8c9e1ff08d2348a9afa86a5a" + }, + { + "kind": "file", + "path": "img_3186.jpg", + "sha256": "d1f11d0d77179ed87b049a9505f5fadf59afb2732e5a3375374613dda16e23f8" + }, + { + "kind": "file", + "path": "img_4825.jpg", + "sha256": "41d91b78c839c7e880067f3f79885295fc104b941037641cd883b5578094f1a6" + }, + { + "kind": "file", + "path": "img_765.jpg", + "sha256": "6399bee9db09d789cfd33b8e6b0caac6daca4ef063bfc18636eb1231ce6c2ca3" + }, + { + "kind": "file", + "path": "img_3192.jpg", + "sha256": "43c728cb86622c96ebc00fe3d6e83b3dab340232fb9eb9ad0fb6d04140bdce40" + }, + { + "kind": "file", + "path": "img_1785.jpg", + "sha256": "efb0c052342f9fd5f134e12c3103f69ea20cd5da4431451934836a0a2899540b" + }, + { + "kind": "file", + "path": "img_4616.jpg", + "sha256": "57fb69f4f03869058171a67402a9ed963e994a83efb9339408389a1760cd879e" + }, + { + "kind": "file", + "path": "img_3179.jpg", + "sha256": "03a26f19a50d78580b3e5f35f6003943b8938c50f097c0cf6a2c9b3dd4c8a790" + }, + { + "kind": "file", + "path": "img_2267.jpg", + "sha256": "7fe60a43aefcf42aedeed04055d4efc6f66602152be43b6709ac8253ce2ca8c8" + }, + { + "kind": "file", + "path": "img_956.jpg", + "sha256": "f3adc9090e3995a47cf2b0410cf6f66c100a614159ddb13320321a4fea8d20cc" + }, + { + "kind": "file", + "path": "img_2501.jpg", + "sha256": "2cfccac9e334eb79cc642bf6d6a46ba35ca4ac780df369bc644ec4fea12d8d57" + }, + { + "kind": "file", + "path": "img_4170.jpg", + "sha256": "fec9854fe7ea45a1358a94e2d18f800de26a25703376828219b8f86d98e31633" + }, + { + "kind": "file", + "path": "img_1008.jpg", + "sha256": "e9da496c2eb45c34506b134e8deaadaae7e3fe3864b86a0d014bdcb40a2a1449" + }, + { + "kind": "file", + "path": "img_2515.jpg", + "sha256": "1929b5d68dc9f230df550d1305faaf985c55f9db9fc0f998d3695d1934f91b52" + }, + { + "kind": "file", + "path": "img_4164.jpg", + "sha256": "e07240ecf5f14d6346d0842734691c1718dc61746283c9b8925445ed62bcf4c2" + }, + { + "kind": "file", + "path": "img_4602.jpg", + "sha256": "bbb7d32f7e374d08504db36f9b2569f0822e159b6d5dc258720ef5e8b7dd9bd0" + }, + { + "kind": "file", + "path": "img_1752.jpg", + "sha256": "011cf0dce97ecc1d418d17ea300ad53ddbfda30d0296e954668ff7e4a8293ef8" + }, + { + "kind": "file", + "path": "img_3623.jpg", + "sha256": "0a1554164c4ac73a05a9035e94aceb17441ee8b056daf3daca81baeb80cdbcda" + }, + { + "kind": "file", + "path": "img_3637.jpg", + "sha256": "8be55234e48947a131e84c570884f384fc2f9c9ca6e8cfb52bb0e62c0b01825e" + }, + { + "kind": "file", + "path": "img_4158.jpg", + "sha256": "de74622993f072b1748e50fdedf7a96c720198fbaf84711fda3fc7c5b192351a" + }, + { + "kind": "file", + "path": "img_1020.jpg", + "sha256": "a65a7a1b026d34b8b10ffc94ce7742d035567e5bc3475c698a95599158c81b8a" + }, + { + "kind": "file", + "path": "img_1746.jpg", + "sha256": "667947b2b10a85fb96ccad68f35d812edf3f1b839696909b81167ea19ba400d5" + }, + { + "kind": "file", + "path": "img_3151.jpg", + "sha256": "d2330fd570926d8d798290640c4458a0281ad184080dd7965abae4051d3a79e8" + }, + { + "kind": "file", + "path": "img_2918.jpg", + "sha256": "65d66ce0fefe2a3844c12854a420b0f246952bb47a16b7d5d8d7ce29c8e81770" + }, + { + "kind": "file", + "path": "img_229.jpg", + "sha256": "bb0af6027ed9d7568549cd8e95b9ecb3eed1964a98da8b77c4809a894eb85da1" + }, + { + "kind": "file", + "path": "img_215.jpg", + "sha256": "791714b984f3388d7a880c3642fa7db2eaed7ea016c55a8ad9f986c7dde19da7" + }, + { + "kind": "file", + "path": "img_3384.jpg", + "sha256": "c2a80c4a061e24d8087dbbf5bf1c5fadcb8ae5f52efccee09b39590ba129df7e" + }, + { + "kind": "file", + "path": "img_573.jpg", + "sha256": "2b2cc9a277c300b60cee68042d06f23d893580b48fb6dae9aa4eb756b6f7e56d" + }, + { + "kind": "file", + "path": "img_1593.jpg", + "sha256": "7cbfa717e29923e3551b4805fbfaa6f4b2c266cb7d5b1f7a931f886417549807" + }, + { + "kind": "file", + "path": "img_1587.jpg", + "sha256": "14bf40e07e0a6603e4351173c533329777d4eb832a3a0c835d930a233390784f" + }, + { + "kind": "file", + "path": "img_3390.jpg", + "sha256": "31caa8f776d5076e0ad37c7032f7d676c736347f688ad65c95a1b591aacfc035" + }, + { + "kind": "file", + "path": "img_567.jpg", + "sha256": "e5a91af48c598f6e7d3588c3e8711341627b1f4d7e7ae939baf054b87c2dc209" + }, + { + "kind": "file", + "path": "img_2930.jpg", + "sha256": "f2b2f72d8be16229e7521f2e0875c09fa92082a86b448bf95f22165563255fb9" + }, + { + "kind": "file", + "path": "img_4399.jpg", + "sha256": "43454ed25e0ee198af2f0e76e117bb74ea3619d196fde37288c177fddae69e02" + }, + { + "kind": "file", + "path": "img_201.jpg", + "sha256": "a58a0345e2c84419bcc758fadec2e075845f9d08ada1fc37ff9bf3e69ecbc654" + }, + { + "kind": "file", + "path": "img_4372.jpg", + "sha256": "4f88d74428d914466820411238e961f91f0705c51ee7bbdd0f8f40e0610eef59" + }, + { + "kind": "file", + "path": "img_2703.jpg", + "sha256": "455cf27e622c35cc2eeb79aaff767ce156b19e98e91aeb4fd7f3f02a405a711a" + }, + { + "kind": "file", + "path": "img_2065.jpg", + "sha256": "91011c1b268a21dad177f3751d7b1db345d4d282c7c455e5cf7c757112c6efbb" + }, + { + "kind": "file", + "path": "img_1578.jpg", + "sha256": "c6f8da5de86cf66dff1289b66ac86b14ee4a6fa26b243c1306a5d686345e0ce9" + }, + { + "kind": "file", + "path": "img_2071.jpg", + "sha256": "b564360a95a69b2e5e0742fe290dd582176b016e50e2efa2284c1f0cf6be9390" + }, + { + "kind": "file", + "path": "img_598.jpg", + "sha256": "c96f33cd3c96bff2c53b5f56102fce4ed8626f0c700e6d2d522ad3eeade2ac00" + }, + { + "kind": "file", + "path": "img_4400.jpg", + "sha256": "d69cc25eca85a14c262ad757f75fe62dbe3096c0d4e269a4e0153a48201aaf7d" + }, + { + "kind": "file", + "path": "img_4366.jpg", + "sha256": "481c95d4cc75a13d8920e8d58a2b2bd70ac1215ead6893ce8fcae78eb1ddf6a1" + }, + { + "kind": "file", + "path": "img_3409.jpg", + "sha256": "2a18dd92649ee4aec3eb77855b13ec400a7665b6ef72ab53a6a5bec605abfa3c" + }, + { + "kind": "file", + "path": "img_2717.jpg", + "sha256": "86cc2f12a224ff7bacfb50502bf78286fb544689170cca7489f32f25ab8758fb" + }, + { + "kind": "file", + "path": "img_3421.jpg", + "sha256": "be0a3176444a328792de921a0ffe43957cbba7ab9f68e7f7f5ab75bb9d79760e" + }, + { + "kind": "file", + "path": "img_1236.jpg", + "sha256": "0e26ccfad6077671064c70390df3486f151164ca79c56810c54a59b487fbf7fb" + }, + { + "kind": "file", + "path": "img_1550.jpg", + "sha256": "b9969192bfe17030edb6eb0c3cfe77432b154aa7f830cc2a563c7502861722d1" + }, + { + "kind": "file", + "path": "img_4428.jpg", + "sha256": "8780c7bb99e7b078c0f45d574cac1de53d9ea61ec5fab9c5d543c6b7d328f4c7" + }, + { + "kind": "file", + "path": "img_1222.jpg", + "sha256": "54c07fb991ba0391eea68ab8fdbb0f2c861882c3c2f8f13c7d4e04836ce840ab" + }, + { + "kind": "file", + "path": "img_3435.jpg", + "sha256": "f2ceb4283c4a5dacfcad8e592c44aabcf59b45e2ce8e851da7d53cb2e7fd6ea8" + }, + { + "kind": "file", + "path": "img_1545.jpg", + "sha256": "74525b4e2ef109c1931d923652bafb1802e968dc17aaaac9880d0fbcd0c57535" + }, + { + "kind": "file", + "path": "img_3352.jpg", + "sha256": "b03e50a9e8531d277df4aee7b13fca21aa40ebc205794e5fc555964df30366e0" + }, + { + "kind": "file", + "path": "img_3434.jpg", + "sha256": "9050bc20695181cbb8e1eadf5dafd0385ad52b16506f64f0559eb1b047428f5f" + }, + { + "kind": "file", + "path": "img_1223.jpg", + "sha256": "fcb63e15b71385ec8166b140bca826e53aae34550b1e1e14a90486561885d974" + }, + { + "kind": "file", + "path": "img_1237.jpg", + "sha256": "bdd053d37d1afb4fbeb1f41a376819af6e434dda9db7e82e40cfb94635abf5af" + }, + { + "kind": "file", + "path": "img_3420.jpg", + "sha256": "b7997a8b34c5ae7629d37c2ea0804c2bb330aed7634fade0ca8b09b2fc23474c" + }, + { + "kind": "file", + "path": "img_4429.jpg", + "sha256": "99a6e519354971f302167e599c333ee7408b4ed936cf2d509225f940bf6fda67" + }, + { + "kind": "file", + "path": "img_3346.jpg", + "sha256": "44e008c5b59dc2fd1fab80bad0f78dc0acce0034a7a95ba20152cfc07da76dff" + }, + { + "kind": "file", + "path": "img_2058.jpg", + "sha256": "e4870e8c965a7a772065e9f83054cb60e5a0b72f14317318fed6abc2dd7db26e" + }, + { + "kind": "file", + "path": "img_1551.jpg", + "sha256": "771f3e5004c93d2cedb56b1ab4197b9dce3e45b3925159869868151cd7c7235c" + }, + { + "kind": "file", + "path": "img_4401.jpg", + "sha256": "1042bf7c39b3ebd2d11306358e1ec9ec977992e774e42c5bbf8f5dfb55b715cb" + }, + { + "kind": "file", + "path": "img_2070.jpg", + "sha256": "e6287ac0a55e64a4c152b6efc6917cdb90b03c86842eefbecee77407ab859110" + }, + { + "kind": "file", + "path": "img_1579.jpg", + "sha256": "853c5ee69bcd51f17aaceef9d520758405543c5cd30eeac9ba4afe8657932b37" + }, + { + "kind": "file", + "path": "img_2716.jpg", + "sha256": "1a15b3c7d5e2f8f13abec2ca114b463ff895a6141d8c3c4d16f11e6f24493187" + }, + { + "kind": "file", + "path": "img_3408.jpg", + "sha256": "2dd4462176ca69a1d21ff999e650b38256ddd22e2a0b6da8cf2315db26ca8585" + }, + { + "kind": "file", + "path": "img_4367.jpg", + "sha256": "9c4bc54c7ec8d9ab6039f0189312875f0a20b2d571bf2fb3aec91a514bb66dfc" + }, + { + "kind": "file", + "path": "img_2702.jpg", + "sha256": "75b1b7c322c8e813afb30eb23c9e0d2d3ae9b8b4869700ed830d5778c31c875c" + }, + { + "kind": "file", + "path": "img_4373.jpg", + "sha256": "1ae503b846a01b02db111fb441f5dc7f6a2997f93d61df13b555f719d775c60c" + }, + { + "kind": "file", + "path": "img_566.jpg", + "sha256": "63d345e6d61d7d10b87588e52a1c94a43f8f9b4f520fecf79e4fbc2e2a73d949" + }, + { + "kind": "file", + "path": "img_3391.jpg", + "sha256": "ff1d9f31e72307ee93672bd43792fd7da8f335c5ee43b99a4b6805dcc4c0363d" + }, + { + "kind": "file", + "path": "img_1586.jpg", + "sha256": "74cd3284f1f03910b83ba15cc281001dc3194559081db8f08f72f885db04a560" + }, + { + "kind": "file", + "path": "img_200.jpg", + "sha256": "9b7a99cf356f3684b5d2a37a3ce142545d9d0baa2da0d78e2c332d62f29a67a7" + }, + { + "kind": "file", + "path": "img_4398.jpg", + "sha256": "2b08d78e09c0514e19ae1edc6cb4409c684b56258bf71d53da2f2988d1905485" + }, + { + "kind": "file", + "path": "img_2931.jpg", + "sha256": "c2ba2f7c8bdd0c79612335cc1b0f25e95c5cdcde91809fb84add777372e1f382" + }, + { + "kind": "file", + "path": "img_2925.jpg", + "sha256": "da1b20ed6e2ea1b01d33a588865dabdb717f61fcbd1276bed8045dda97547b30" + }, + { + "kind": "file", + "path": "img_1592.jpg", + "sha256": "9247181d2a67ab6172d85f7bb4b302f0d8e948116e20989312ca5391e9e16a58" + }, + { + "kind": "file", + "path": "img_572.jpg", + "sha256": "620b565cdef416ee65f0159f9bf6f21176155fb9d88713f0e3963ed2b1d2d538" + }, + { + "kind": "file", + "path": "img_228.jpg", + "sha256": "cff6ca7d70bd5bb95a2d7e149a0db23fd83d841e6ce4ce4ed44dc980edf7d2c9" + }, + { + "kind": "file", + "path": "img_2919.jpg", + "sha256": "78746d003fdde53f464528da99e798086bd44af6bd6d98bf56e205057d53fd05" + }, + { + "kind": "file", + "path": "img_4159.jpg", + "sha256": "e40d193794fc8bb0d3aab633ad7f68f7570dee21d78756ef23f4dc24a11d3ff8" + }, + { + "kind": "file", + "path": "img_3636.jpg", + "sha256": "f806067f95c9b204e420bf0e3077b936f9242df2bd834a1f5f2f673db9540887" + }, + { + "kind": "file", + "path": "img_3150.jpg", + "sha256": "e347d067b9930dbf0167e5d30b075235566f1c0fa8e4f5dee910640ab0dad777" + }, + { + "kind": "file", + "path": "img_1747.jpg", + "sha256": "74c209fc401c10f3c01aa4f1a0e35940cb1282fa3681877ca12e829471aa9408" + }, + { + "kind": "file", + "path": "img_1753.jpg", + "sha256": "1dace5f8307875f689588c7738afd5b6c634ecc4fe9d0c578e9ab76c65811cee" + }, + { + "kind": "file", + "path": "img_4165.jpg", + "sha256": "020329dffe015316298c517851e1ed3dcdb807b27a6949c3dd159c5144750cfc" + }, + { + "kind": "file", + "path": "img_943.jpg", + "sha256": "3420dcab84bd76b6665019f07fcf72fab3e8059beceb00f229c28ab13578a35a" + }, + { + "kind": "file", + "path": "img_2272.jpg", + "sha256": "88405bf712c7a4046c5a8c97b3741c4340386ba498d7c5231b9f791ed4694f5f" + }, + { + "kind": "file", + "path": "img_4603.jpg", + "sha256": "c8ac3a012dbe3473b5ecc40cdce283dd0fdbe2248dd6f0d6b89c6500ae3a3992" + }, + { + "kind": "file", + "path": "img_957.jpg", + "sha256": "943e2c2c2567c8ac6b05bad1232a2a4e6ebe6b9f02d6675e6c0929ba8dd8c8c3" + }, + { + "kind": "file", + "path": "img_2266.jpg", + "sha256": "d7cdf6e4a9bb7058707e090d704b3cf9234779a1130468c944f608154c771127" + }, + { + "kind": "file", + "path": "img_1009.jpg", + "sha256": "8edbe1fe5127924a6971c4523a6e5bfb610fac5003ae7d1f922c0a4e2b38fcef" + }, + { + "kind": "file", + "path": "img_1784.jpg", + "sha256": "2af6f48fa9ea6a244f0ca194ccc51e5050d4726619d6687b6dc696e45760ea75" + }, + { + "kind": "file", + "path": "img_3193.jpg", + "sha256": "8b815d88a148a64a6b2418e9f25a0f39dda26faf70b3db7dfe4eca981db22e76" + }, + { + "kind": "file", + "path": "img_764.jpg", + "sha256": "f44640834c0d40fc0c832506a001dcbcbba237e935c9c2c80428bcb31f1dfc95" + }, + { + "kind": "file", + "path": "img_3187.jpg", + "sha256": "945622e5b763371079d0200fde1d0d220d48638b846aca4e7dec7a2bf981f910" + }, + { + "kind": "file", + "path": "img_770.jpg", + "sha256": "1c997d977166168529c3e59d148e5f2d8c853642f57fec2a69a30a3560536041" + }, + { + "kind": "file", + "path": "img_2299.jpg", + "sha256": "8da3b90c75f520b7dc2f1599884a6b98b89d42ebda728e1919f256ff49bf3f17" + }, + { + "kind": "file", + "path": "img_4830.jpg", + "sha256": "b9fce998cc0f1bf73d70e0574cf319565f443826d93cd9d060cfaf4d7eb8be4e" + }, + { + "kind": "file", + "path": "img_1790.jpg", + "sha256": "360d27406435321f3b191d858e492d479340fe0d090fb39b911cfbe79f087187" + }, + { + "kind": "file", + "path": "img_1948.jpg", + "sha256": "f8b1ab119eafb280742963f2215e52ba2a54040b34e2c7fd3232c160c9d77b6b" + }, + { + "kind": "file", + "path": "img_3839.jpg", + "sha256": "654ac1eb650cd2ed1fc5da617a7269d3df67dc7e60efc5e1c653e45bc04d261d" + }, + { + "kind": "file", + "path": "img_3811.jpg", + "sha256": "60fb50e98a5ff07a521b9cefd8766b1bcef4a91878c8e417b4f7c5c80be6cd28" + }, + { + "kind": "file", + "path": "img_980.jpg", + "sha256": "b184b77fe997329a7288e443eda5d8e7c2974fa104a076d80a1b813c5718a80c" + }, + { + "kind": "file", + "path": "img_1960.jpg", + "sha256": "622b2ab73a43f9b240ef6bbe7d0ef738acf5aa58b68648ffcd43cd3969e42049" + }, + { + "kind": "file", + "path": "img_1974.jpg", + "sha256": "72486294601db985a7819f7ce261084308535b6de773a2502071049f6cef79c4" + }, + { + "kind": "file", + "path": "img_994.jpg", + "sha256": "86b1413e2225a7346433058016933981a1d579dcf483f63271163e5a39a12786" + }, + { + "kind": "file", + "path": "img_3805.jpg", + "sha256": "9c8609939058636724b581fa46a80a47feddd53d9512138a5919449ddc7d60b9" + }, + { + "kind": "file", + "path": "img_1155.jpg", + "sha256": "3651fbb4206b10274daf02c7cd4eda00a852da7aac5acc183ce96087b6c8cd22" + }, + { + "kind": "file", + "path": "img_3742.jpg", + "sha256": "64a8546f545293d1b331cb303c710b77265a94f985c66569600d25a30c48e67c" + }, + { + "kind": "file", + "path": "img_3024.jpg", + "sha256": "fc634d05366ae3f0d6e6173b9ec079953bcf54489e2e51cd0d2d4077f3c29d52" + }, + { + "kind": "file", + "path": "img_1633.jpg", + "sha256": "f5a97a08f68070e91a61fede4e62d400349680a8ea0131e1dc8fb958526a4264" + }, + { + "kind": "file", + "path": "img_1627.jpg", + "sha256": "658153e50d90a657d9878c922c47c53cd7b93366e318dd08f712a670434faa0a" + }, + { + "kind": "file", + "path": "img_3030.jpg", + "sha256": "0d9bed7eb1c36ccaf0075f50cf21288e18386542ac44b500dd0094490184a71f" + }, + { + "kind": "file", + "path": "img_2448.jpg", + "sha256": "dd09b52dccb423f5d88d2954220851f39a6516eb8e0e3aeb67a8b53d4ca8c734" + }, + { + "kind": "file", + "path": "img_4039.jpg", + "sha256": "03dc13b9047dae4eccdc75409b88288a2567f9088f8115f705f4577c17a53831" + }, + { + "kind": "file", + "path": "img_1141.jpg", + "sha256": "ddcf3b283a3cd55f8de472cf37595eab82b696b71781844aa3254bcf3d88edce" + }, + { + "kind": "file", + "path": "img_2460.jpg", + "sha256": "764716d7d03a613b5f2467220ee96b3f849a944cc14c510c51c0de19fdf54cbc" + }, + { + "kind": "file", + "path": "img_189.jpg", + "sha256": "5f828ed65dee1ec3bd6d8a7163beaaa5d5ce2391fddb06044ffcbd4acde41151" + }, + { + "kind": "file", + "path": "img_4011.jpg", + "sha256": "0be804515691612e99eaf759aac06b871796570f9a237388bb05a120a07441ce" + }, + { + "kind": "file", + "path": "img_4777.jpg", + "sha256": "2171be784d493f0ae1ef1a4f9641027abad0b67a86465053b8f336ea6b8c2bc6" + }, + { + "kind": "file", + "path": "img_3018.jpg", + "sha256": "1375771a3c533781fbbe2b6d79cc91daa0c33a7ec794a2da32052f85356cb1e0" + }, + { + "kind": "file", + "path": "img_2306.jpg", + "sha256": "bd713a51992acf94a9c4f88c4c6fe371ef091f6fd07fa00786dff74a9af85883" + }, + { + "kind": "file", + "path": "img_4763.jpg", + "sha256": "7910ec17674cb711097118129a50dadbea53061cc0c99f4562c1729c6eff7fbc" + }, + { + "kind": "file", + "path": "img_2312.jpg", + "sha256": "db9a1e844132613dc143133fd0d6cdf5e940ad5f6fb5627d08c578cbf672b3f9" + }, + { + "kind": "file", + "path": "img_823.jpg", + "sha256": "2f8b1e39d8a0bfe37924c2d8133969430e2b335a9c735433f005aa420801175a" + }, + { + "kind": "file", + "path": "img_2474.jpg", + "sha256": "80252351a2ab7ae2f3ce428f0dcae2cbdc11642e2638821262ac10dd1c14b3d6" + }, + { + "kind": "file", + "path": "img_4005.jpg", + "sha256": "599091042a7c0dc9474df310fb1bbd371427ac3d679aec3db353083dc6bbe152" + }, + { + "kind": "file", + "path": "img_3781.jpg", + "sha256": "3653ee6f42d26dcd300e59f35f4f5e2e97d88bfd0470ee7843953b46260f762f" + }, + { + "kind": "file", + "path": "img_176.jpg", + "sha256": "29c8241a1c55485ee2f044551dbf49ea376f1958f640344ff4c267e4d73db544" + }, + { + "kind": "file", + "path": "img_3959.jpg", + "sha256": "60711320cfe9a910f6c2ceaa8496699bc850c5c4e116a729bd123ade0502ae14" + }, + { + "kind": "file", + "path": "img_1196.jpg", + "sha256": "933f97eb717f171d278c44995733c8f804d0364c2ad83bb432d8d7890df0b767" + }, + { + "kind": "file", + "path": "img_4788.jpg", + "sha256": "92e5a3b7c30faa76679a63e593c0959b8054cec279739784f7ffa4efbc923a46" + }, + { + "kind": "file", + "path": "img_610.jpg", + "sha256": "13b643bd0123343154e05eaac1f3a9265a83a5a75b9b70c044598aa1b2564af0" + }, + { + "kind": "file", + "path": "img_162.jpg", + "sha256": "45bdfa2fea56d46a45d81276e1cc5ef8c92fb4d2ceb28f53d1356dd92e68ada2" + }, + { + "kind": "file", + "path": "img_3965.jpg", + "sha256": "d47cc4118c9df446201e605e868615fcde2f9fa5213ae6b0dac361eafa7ddef4" + }, + { + "kind": "file", + "path": "img_1814.jpg", + "sha256": "f2c81cedf967665dd897ca18f285f9d8b68cb74adae3e30fbad3a686624c9c70" + }, + { + "kind": "file", + "path": "img_1800.jpg", + "sha256": "f006610bcb86181bd657de228732fa1e85e7d2001267713f4ee1bdd1f9aca813" + }, + { + "kind": "file", + "path": "img_638.jpg", + "sha256": "eaaa8c861c73e99786a8b05aad3ab003c84a8c0dd4739652264579157161d74d" + }, + { + "kind": "file", + "path": "img_3971.jpg", + "sha256": "6b20c9fa5e2775638e4a2538ecf7fb659b36db54b761a71e7851e3c80c058bb9" + }, + { + "kind": "file", + "path": "img_1431.jpg", + "sha256": "21867c0178a29fd429d57dba68a1180728493a734c462f8eddc9fd871751b0e0" + }, + { + "kind": "file", + "path": "img_3226.jpg", + "sha256": "11af347e078498e358f8f48758edb3e4a22abe0787fdc20d656a8760fa0ea1bb" + }, + { + "kind": "file", + "path": "img_4549.jpg", + "sha256": "84ba3e494a0bd41cf3e0fcc5394da80b4f5576588d50cf763be2a401b2a7794c" + }, + { + "kind": "file", + "path": "img_3540.jpg", + "sha256": "31e3337d2ac511538e4af9275b4e2d3c464b8025f847cea7383c8b6dc4202612" + }, + { + "kind": "file", + "path": "img_1357.jpg", + "sha256": "4129624da9a3002c30827b65f2b9fcd1724fab259a90047b0324e4f7a8978456" + }, + { + "kind": "file", + "path": "img_2892.jpg", + "sha256": "3d703f32089588041333167c72a78f641c01086d3be67f2c50bc3724c37f62d4" + }, + { + "kind": "file", + "path": "img_3232.jpg", + "sha256": "648386cf1afeb2b3db2d72ceb9d9cceb2b5ea915d189771634def2c848f71654" + }, + { + "kind": "file", + "path": "img_1425.jpg", + "sha256": "eac3cd941b33545e11ed5b50b73d0da064777ad7ec30054b7fa022855fa680d3" + }, + { + "kind": "file", + "path": "img_71.jpg", + "sha256": "a0ab0a870e236c3de9a2e5e900885ff835c2faf9c63b35686cd6fa0b0a4426b0" + }, + { + "kind": "file", + "path": "img_4575.jpg", + "sha256": "151e30a48c874455386ce75e2376c5b16279b2cd637218d069900a008ae86e23" + }, + { + "kind": "file", + "path": "img_4213.jpg", + "sha256": "6ecad3159b96048be21e5053b57d233de2df04adf10c9671e12418b61189f03e" + }, + { + "kind": "file", + "path": "img_4207.jpg", + "sha256": "61cdecc30364713b7d34271fbc43b5504efa384d5610b8637a5491131ece4a77" + }, + { + "kind": "file", + "path": "img_2676.jpg", + "sha256": "0939ef59fe45d475b27f53174637f1217a37c18015c42a9056a39d8d0de43172" + }, + { + "kind": "file", + "path": "img_65.jpg", + "sha256": "705e5e9c29da0fe5121aa63e9ee79b53003b5dd4e7e9e1855eddd43f2f3c9a40" + }, + { + "kind": "file", + "path": "img_2110.jpg", + "sha256": "87b6a8d8b26bf791a5746e8fd433add799113d71f14b438818c216e967909566" + }, + { + "kind": "file", + "path": "img_4561.jpg", + "sha256": "04f5a20bbcc6abb0b2abd60936d002514ab6d4025c1354b57b06de59c83f034f" + }, + { + "kind": "file", + "path": "img_1394.jpg", + "sha256": "3b9e8621d50b22cd095085605feb9b78bee567df9145f73747a381de376d0a4e" + }, + { + "kind": "file", + "path": "img_2845.jpg", + "sha256": "3b7496c4d74861870a8faea21b113aedd26e49bfc8fbbcc5e3bbf2d61afc7a85" + }, + { + "kind": "file", + "path": "img_374.jpg", + "sha256": "78e07669ee30815162ba5c6a4a952cf178d655895c8a00a97f38ed6ddf3591d9" + }, + { + "kind": "file", + "path": "img_3583.jpg", + "sha256": "f690bd8d67c7890ae02eb057326c6a1ad900b5bad6c854e6e6303d85f1ff0625" + }, + { + "kind": "file", + "path": "img_2689.jpg", + "sha256": "aa5771d39298b9d1255abc0849d34ee1d0883fd7bffa916f095d1e97ee8f38f1" + }, + { + "kind": "file", + "path": "img_2851.jpg", + "sha256": "4c5fd4c8be8c3ab1bae2bd3a13e572f1b3bf823b97af380c3e11732528c0eb42" + }, + { + "kind": "file", + "path": "img_360.jpg", + "sha256": "8c7a4305352baa536a42edd0c3c14ee0cbf49dd3fd8ceb5a35bb14a37e713d21" + }, + { + "kind": "file", + "path": "img_3597.jpg", + "sha256": "5862266c273474c788d994164de60e117fc78a78693f47d0eb0dd035c431da01" + }, + { + "kind": "file", + "path": "img_1380.jpg", + "sha256": "f0fc036bfbc16cede40105c3b6b92645e736057df164eedfd6fe5b993eda6bea" + }, + { + "kind": "file", + "path": "img_406.jpg", + "sha256": "4be4fb1cd17de3e3652b694f869f20250c0dcf40d1287cdef207a95358f6615e" + }, + { + "kind": "file", + "path": "img_2879.jpg", + "sha256": "4a0c44e298bc1fae4482dbcbb4a8e5dbddab8dbb4bb4836684e66f198755c57b" + }, + { + "kind": "file", + "path": "img_402.jpg", + "sha256": "429327b7eeb8105540aef222a9996b8f2b83e089c349e449ad0befa21c55e8f8" + }, + { + "kind": "file", + "path": "img_1384.jpg", + "sha256": "edf75808e92ec9c57fb997d16b5c9ec54b5bec323f97b769571973121c4f1f9a" + }, + { + "kind": "file", + "path": "img_2855.jpg", + "sha256": "ce7069493f7e8f9ed136b680a6dd65b35e0953a525ed803526027e1c908bf14d" + }, + { + "kind": "file", + "path": "img_3593.jpg", + "sha256": "6f28d8f6e4c40d812833e5b9fd0e7685fcdb1a8a82c5e9815201838150358f48" + }, + { + "kind": "file", + "path": "img_3587.jpg", + "sha256": "72bc470679cf12101dbfa606c242aa3ffc109e8674489b346204a074a0b09eed" + }, + { + "kind": "file", + "path": "img_370.jpg", + "sha256": "bf665f8b85d7407f668858fc96ecd91c47db6f71d096a026ef69d343e5485f8a" + }, + { + "kind": "file", + "path": "img_2699.jpg", + "sha256": "17603bb6ed50cf6fa6cb33ba87b28594c1fa8dd37237bd43883a207024a70098" + }, + { + "kind": "file", + "path": "img_1390.jpg", + "sha256": "2f0eb4dd6a30af6a2cf37d10fa05a6fd59ae1525287145b17ff90080cc4e9eb4" + }, + { + "kind": "file", + "path": "img_416.jpg", + "sha256": "9e0beb53b3d4fe6c39184c8dcc2f880cea31eeb999362fa335a5440316d0f0ab" + }, + { + "kind": "file", + "path": "img_2869.jpg", + "sha256": "6a91e331dd9881bce8dbe8b7e358fdd3e0e8e8731f2851a81c9f3aeff29bc850" + }, + { + "kind": "file", + "path": "img_358.jpg", + "sha256": "698a55d2de434c7d4803fd4716cfe57ddce545f7aaab4b4898c7a3287b44f684" + }, + { + "kind": "file", + "path": "img_3236.jpg", + "sha256": "24a6f21eb386f08e7f596242d12568459c9289fa9e992a49ecce23779a051f2b" + }, + { + "kind": "file", + "path": "img_4559.jpg", + "sha256": "52478e9e7d22ec14be7dccdd8f181f0d07cdc43abc5109c695db1433b1f70309" + }, + { + "kind": "file", + "path": "img_2128.jpg", + "sha256": "6cc795b20b87e51d1ca4b2d0ced5f21038c3c977ab48310724f9b5bbd22b271f" + }, + { + "kind": "file", + "path": "img_2896.jpg", + "sha256": "d8926188a3fc225f18c0bcb891b5bb5d8c7cc0044e1445fad50f80f66b3d5285" + }, + { + "kind": "file", + "path": "img_3550.jpg", + "sha256": "fbd851b06d9dbd326485a400d2533a11bd9c8d4af742cecaf3db01e92a8262b8" + }, + { + "kind": "file", + "path": "img_1347.jpg", + "sha256": "3beebd18c91789f8ea464ee84cb59a81064cb3e3aa101db0c2f08b956d2f93f3" + }, + { + "kind": "file", + "path": "img_1353.jpg", + "sha256": "362004f11ddd196fee0496c000d705307798cc9608836992c23c52442aeb2fb5" + }, + { + "kind": "file", + "path": "img_2882.jpg", + "sha256": "fed5398773d076c21f1f42a5355ca0cecb5202af6147d327792618430109715d" + }, + { + "kind": "file", + "path": "img_3222.jpg", + "sha256": "4311de230c6e87fc446e965a44e8348e23379ff379540f9576e83cb1a90d98cd" + }, + { + "kind": "file", + "path": "img_49.jpg", + "sha256": "e194b1f9cc17f7b03a7900c506270f687df48ab18fd763874ccc417cb66053d6" + }, + { + "kind": "file", + "path": "img_1435.jpg", + "sha256": "8002ccecbecb6b7a5788e941cb77054628f399041e00445b00bd499bf0183507" + }, + { + "kind": "file", + "path": "img_4565.jpg", + "sha256": "6ba2265b322c315061320d210e51cfb8f223208dec092a2af1358c214c4dd902" + }, + { + "kind": "file", + "path": "img_61.jpg", + "sha256": "5828e6f292875831912672ebaa8305664b9dfd510e436b21d62a5de716ccc518" + }, + { + "kind": "file", + "path": "img_2114.jpg", + "sha256": "a24291d1a06275cd285d9adf892cfe69c862aa91d64d6a98ddbbd1bf10e9f49d" + }, + { + "kind": "file", + "path": "img_4203.jpg", + "sha256": "72dd086297a501e34b4cacd80f6b502bfd81a0bafcb7b720bb95704e8da42e50" + }, + { + "kind": "file", + "path": "img_2666.jpg", + "sha256": "f1a76a77a8d53a2cae19bbc15621e55e682eab8e18cc9b6d42d2c32d6eeca999" + }, + { + "kind": "file", + "path": "img_4217.jpg", + "sha256": "f0e6cb76e67d7157b6baf09f934b19564106bd433b54752564cca6c911bc4a14" + }, + { + "kind": "file", + "path": "img_3578.jpg", + "sha256": "41987bf3d5daea8b65236165214fd67a18169379c20a3064d47d9e32ab317f86" + }, + { + "kind": "file", + "path": "img_1409.jpg", + "sha256": "e96b20cae87f63af1b1ddb0109037a82dff9c0d340eae44002505c2faf50f38c" + }, + { + "kind": "file", + "path": "img_4571.jpg", + "sha256": "37a5fcb41caa220ce4ec143023f4fc8f2e8c0510adc9c739e498ff93d98e9296" + }, + { + "kind": "file", + "path": "img_75.jpg", + "sha256": "d641b136f92c74eec8651bb7e1a2820ee4d8e55297477243ab5edc90f964ec00" + }, + { + "kind": "file", + "path": "img_2100.jpg", + "sha256": "bb6b345374a57e917488c0cac096c8ae1a0f32eda6503b22d7a5fab74d11b8ca" + }, + { + "kind": "file", + "path": "img_3949.jpg", + "sha256": "47fe7eac88f3cb22ebb6bc9f3ad54bdcdba6c7c441127878fe660d9aa8f14a44" + }, + { + "kind": "file", + "path": "img_166.jpg", + "sha256": "d941d8c107c0ce7b5ca224b82a2eef63b3774d2c75298bc56ca8790f73f8982b" + }, + { + "kind": "file", + "path": "img_3791.jpg", + "sha256": "fb6780d953e7db733e2b279d18441d8d19e5982c6bae587affa6f07b1e8da50a" + }, + { + "kind": "file", + "path": "img_1186.jpg", + "sha256": "e55a1eb8a9e071c8b258a54affaf66efc104bb4efe5fa9edfa23ea7f399d1737" + }, + { + "kind": "file", + "path": "img_4798.jpg", + "sha256": "18ce82faec6b7c91c5e74f473a994a582f5428300c5db569a7d4081341a0246c" + }, + { + "kind": "file", + "path": "img_600.jpg", + "sha256": "5034eb2ff2b2e1510b5c72a4f9e627d57703a4a5ea7c0c08d75ae2e653efec2a" + }, + { + "kind": "file", + "path": "img_614.jpg", + "sha256": "a6ce0139cce59085229c3ca01584f8935154b25bfeb4549323e982fe7a4d00e6" + }, + { + "kind": "file", + "path": "img_1192.jpg", + "sha256": "51412e95d0488981c973cfb471b030819125b46b49f84192082836e4d1af5dda" + }, + { + "kind": "file", + "path": "img_172.jpg", + "sha256": "f35e7acd1f4922999411048a177a620548f1f162150b094dfa5f823b38994d02" + }, + { + "kind": "file", + "path": "img_3785.jpg", + "sha256": "3dd02dcda9782d83136026ce9634a907a00bab767be3b856f848d162a6bee08e" + }, + { + "kind": "file", + "path": "img_3975.jpg", + "sha256": "791b3fc05b739e3e1d962e528bf1f070f6fb719c4c78dc04481b923fa4bd1127" + }, + { + "kind": "file", + "path": "img_1804.jpg", + "sha256": "33e7efbd8edaf6696093ddf71356aecb831b382c49eeade0c5fce5121294570f" + }, + { + "kind": "file", + "path": "img_1810.jpg", + "sha256": "351cace63e648c93e5406deebee230f75ae5a97cb2659cb420849604681131fe" + }, + { + "kind": "file", + "path": "img_628.jpg", + "sha256": "36e76adfc09a3672f0bd2bd4010de96ec1fc3b9d9eaa92ae41bb939eacde0e78" + }, + { + "kind": "file", + "path": "img_3961.jpg", + "sha256": "92d9f02943c985ae7bedfa1112f1530d73f8d34b4faf6b58c2773981019d7c9c" + }, + { + "kind": "file", + "path": "img_1145.jpg", + "sha256": "797e17e5ffb7963e950a2507750f54198aca055a5ca949ede3f5f421bba856b4" + }, + { + "kind": "file", + "path": "img_3752.jpg", + "sha256": "d16f928a16d49cf797ce19fd6c72d204bad6ffd56c0fd229b6c229f55d5905ad" + }, + { + "kind": "file", + "path": "img_3034.jpg", + "sha256": "89df02b1292cf68c9d3e3af63508710d01dadae605f001829af3af49a4049a24" + }, + { + "kind": "file", + "path": "img_1623.jpg", + "sha256": "b57ef01e78719871335712993ac55731878a2391f88205717219d395ddc86f58" + }, + { + "kind": "file", + "path": "img_1637.jpg", + "sha256": "de6404068bcd48a5833ce374ebd5ef46f65197a7d7b4cd2b8ea8ed70ba08b9d3" + }, + { + "kind": "file", + "path": "img_3020.jpg", + "sha256": "f8f324306a6f60abdc2cf1fab74b82328596215dc5a712ffed31fa8608b865ec" + }, + { + "kind": "file", + "path": "img_4029.jpg", + "sha256": "2376d8556a7df40262444ebdd1a3d41329d72c8efe1cde8a6a647513e1c93865" + }, + { + "kind": "file", + "path": "img_2458.jpg", + "sha256": "58dbb81a7f3ade15e5bec3873b314c71b3a389df935f562e520307410ad10477" + }, + { + "kind": "file", + "path": "img_199.jpg", + "sha256": "33b85f83a5537f7cd730e59c6e10b6b57b19b6a306fc1e1a7405903877b2a7b6" + }, + { + "kind": "file", + "path": "img_4001.jpg", + "sha256": "e3e92eab3b71026f8bf6778dcdbbcace332b8bf51c1d6d29490022e924a188ae" + }, + { + "kind": "file", + "path": "img_1179.jpg", + "sha256": "85573a003fe6eb1c1aa3e66d18b5e30e7cd8eb21bd372eb079f605e658e49368" + }, + { + "kind": "file", + "path": "img_827.jpg", + "sha256": "88daba0599e4d5b7de854abb5aa69acf2030796796f417c8a19bde25890e6f9e" + }, + { + "kind": "file", + "path": "img_4767.jpg", + "sha256": "8afa0493bc383f0072ca3521172405b68105070f73e0cb211af8928c4b96dc1d" + }, + { + "kind": "file", + "path": "img_3008.jpg", + "sha256": "3df7dd5df4a050eae73c92765adf0e0e24bc3a940ba8ddc5c3c76da92baaa8c5" + }, + { + "kind": "file", + "path": "img_2302.jpg", + "sha256": "1cc854c4d7602ee0af5464745158bcafee3add4b35136983415dcd0a81dbd404" + }, + { + "kind": "file", + "path": "img_833.jpg", + "sha256": "40572be4bb612ccf78da360c347d3f0b37b409e2f32dd0214459bb2a72db4a1e" + }, + { + "kind": "file", + "path": "img_4773.jpg", + "sha256": "4fe19f49e21a309e7487c6115d84fb8d7dd208f3303888c7fdeefdf7d1bade59" + }, + { + "kind": "file", + "path": "img_4015.jpg", + "sha256": "583c51b580f132afbb9ff1e16901b5aa02866bd038b20758f4c22e7defa106ee" + }, + { + "kind": "file", + "path": "img_1794.jpg", + "sha256": "d6b1a547495d6e08e8dfbdf84dda565c004aafd2b519a8a3697d590f93efc907" + }, + { + "kind": "file", + "path": "img_4834.jpg", + "sha256": "cc23fe8ac6dd97822982ddcde173e0fc809e56a571815be6351d13a7c27815dd" + }, + { + "kind": "file", + "path": "img_3183.jpg", + "sha256": "f5a6c3d49b0c74e340d254ea5be785e547978e07e708a8aabfeeaaa93792a4b4" + }, + { + "kind": "file", + "path": "img_4820.jpg", + "sha256": "a5dfd7f2478de2e610f7f69305c4aabe2ce96a7680d4cef905a4ea23535f3e24" + }, + { + "kind": "file", + "path": "img_2289.jpg", + "sha256": "4563b6a2fd4d2433e7173adf99e3b434921726da2f312581fd29a5f74d4a2998" + }, + { + "kind": "file", + "path": "img_760.jpg", + "sha256": "daa09a8a2f3cdf3f2e15f111c1cdd39881bc5104334dcdc9f75ddc39ba355a0e" + }, + { + "kind": "file", + "path": "img_3197.jpg", + "sha256": "7d56e83bbb5df9470ecc1f1637ef2a8fa7ec2484fb93cde08dcb181bb78f499c" + }, + { + "kind": "file", + "path": "img_1780.jpg", + "sha256": "cae6334e90e06a2569af3d5a2f00316cac73a1ec188438681b2209181a6413d3" + }, + { + "kind": "file", + "path": "img_3829.jpg", + "sha256": "1ccf15ec2737c85403ab60c35a280754d2d1696069d276abdbc28c28987ccb3b" + }, + { + "kind": "file", + "path": "img_3801.jpg", + "sha256": "2a28cf671fe4eba62069796f96612d17ea25648d7d9abe54f359bc20d6e6833d" + }, + { + "kind": "file", + "path": "img_4808.jpg", + "sha256": "c0b228a38804a85ba5a80e9d036f39842987149e9577e8391aa60d547463e609" + }, + { + "kind": "file", + "path": "img_1970.jpg", + "sha256": "e2fea4ab503c37fc2bfe85bbff72c726c3be3ba14427b4ef4b84577c6be16a83" + }, + { + "kind": "file", + "path": "img_1964.jpg", + "sha256": "9c33f53df4039721e44cace1c2982f15d510967b1d4735f020dc0917c6a17005" + }, + { + "kind": "file", + "path": "img_984.jpg", + "sha256": "943f7d6b2e1b53c1480da12f8fe242e3b355dd2b8bed99532bf6252fb316d919" + }, + { + "kind": "file", + "path": "img_3815.jpg", + "sha256": "20ca7ba5e66e23f4473c5d54b0e7a1a7bdf74c2ce0ec44634ac9f9f412bfb62b" + }, + { + "kind": "file", + "path": "img_2538.jpg", + "sha256": "33aaa75215c961cde40b6694c63870c6e7c5f3a0db822c471cf9a0da8c220443" + }, + { + "kind": "file", + "path": "img_4149.jpg", + "sha256": "dee7e14fc7a97d7c5abc498ab448725a7423f59508b71c7ef08a8c0948e056e1" + }, + { + "kind": "file", + "path": "img_3626.jpg", + "sha256": "5005b94052ff27bc413d4845ecb653a782bd5b53a0357a9d4a73fc274fbe0952" + }, + { + "kind": "file", + "path": "img_1757.jpg", + "sha256": "36335fd0f4b353c16bca61727c88fc7faa41b7fb8c1430851e6343038756c598" + }, + { + "kind": "file", + "path": "img_3154.jpg", + "sha256": "fa5a2f05598f1dc2903e5d4791c7a3741896d6cc7c73578f6013997872bcb402" + }, + { + "kind": "file", + "path": "img_3632.jpg", + "sha256": "a1840542bbeb4e49b027fa57b881220a32c66a651a17e0d9acb55c69b8895b5b" + }, + { + "kind": "file", + "path": "img_1025.jpg", + "sha256": "e97f18969aa6de78525a522c277527f2cf1de861c5cb13186d973e921833649d" + }, + { + "kind": "file", + "path": "img_2504.jpg", + "sha256": "b244d9208b6aee1e714d40e8b246b49ee202b3ade9908468b97372750b181c32" + }, + { + "kind": "file", + "path": "img_4175.jpg", + "sha256": "1aeb2147760fe9af782cb508e5fb239410fcbc25fb8c70224feb36d64c48c4b6" + }, + { + "kind": "file", + "path": "img_4613.jpg", + "sha256": "e525e0b9b9d33f6e0b88579d6927330baedfe8c011c5e87040765a4e06ca81a2" + }, + { + "kind": "file", + "path": "img_953.jpg", + "sha256": "cb6cb967c0163bb735a038aa6b453abfcba8861c548cff6e0f99cd4b262b5e2e" + }, + { + "kind": "file", + "path": "img_3168.jpg", + "sha256": "45bf1a67cbef3e2456b2021fe86fed5e3980ed6123f897cb1f09fe87561786f1" + }, + { + "kind": "file", + "path": "img_4607.jpg", + "sha256": "70cb87bff240e44ec75fbb16c8c1e4838890b70a856012b0a4381e272a008606" + }, + { + "kind": "file", + "path": "img_2276.jpg", + "sha256": "9427d277f61006bcabd21673e07d26cfe22ba4ca1f46ff2e8281a5791ca02845" + }, + { + "kind": "file", + "path": "img_1019.jpg", + "sha256": "1ce44c31ea192bf388680ce215e022fe0d3dcff8a8c10f79bbc61034f779059a" + }, + { + "kind": "file", + "path": "img_2510.jpg", + "sha256": "4c2304296c5b701811d41ebb2a770f817f54c2cae29b50d59b89faeaec049fcc" + }, + { + "kind": "file", + "path": "img_4161.jpg", + "sha256": "1263bd259331093e117e21efd7fe416d5bb9167275185c795e6c7dd1e2ec956a" + }, + { + "kind": "file", + "path": "img_1596.jpg", + "sha256": "da47f628495a360e394e7cb203fef9106847877239c9f2a454210888a6b24de4" + }, + { + "kind": "file", + "path": "img_2921.jpg", + "sha256": "c14f70e998e15e0aab6cc5472e6684a395b1e86ebf553ceec10f0af638ff5106" + }, + { + "kind": "file", + "path": "img_204.jpg", + "sha256": "3ef6abb3d33ca56030adb361f8c62114d78a7f27345686cb0a4a227615c9a281" + }, + { + "kind": "file", + "path": "img_562.jpg", + "sha256": "c707163d9abe193b9ab68225228b25743429676d333674d806a254164ef84e5f" + }, + { + "kind": "file", + "path": "img_238.jpg", + "sha256": "7f5e8c2fff92cc75a7cad8c263195afed5c3bdfe31ab4d1a1ef89c971fd16f63" + }, + { + "kind": "file", + "path": "img_2909.jpg", + "sha256": "853911293fbcdd7c19c39ca829e66b00f41c8c4f350d9360ef7f7e5dd6e53f92" + }, + { + "kind": "file", + "path": "img_1555.jpg", + "sha256": "18a82756a790a273dbb714a7b77ed1a1a025cdcefbefcb526b4ba9eeb9a0e5e5" + }, + { + "kind": "file", + "path": "img_3342.jpg", + "sha256": "f3763510a427637f50a0be9193a0aa641bc9fd4882196a87f9e6c1e3b6580d58" + }, + { + "kind": "file", + "path": "img_3424.jpg", + "sha256": "697773debe822e198f6cd3053fd9c856f198172d5db4fed788ae2d5dd76ee212" + }, + { + "kind": "file", + "path": "img_1227.jpg", + "sha256": "34ab79dffde2c9c34fc102b05114546cf1b9cab2046d44fef1546d09551223ba" + }, + { + "kind": "file", + "path": "img_3430.jpg", + "sha256": "0a201fbce265696280c936bad1d9e99e7d906720e1887cdd1af5170588760910" + }, + { + "kind": "file", + "path": "img_2048.jpg", + "sha256": "b2e75bbc2866224ab8f540bec5ad96f7911f792cf91637f0fdff767fd1a091d2" + }, + { + "kind": "file", + "path": "img_4439.jpg", + "sha256": "ef3d99234f1c9bab8f19ddea5ce1ce5d90444c706f3f1e3b8621622421abf942" + }, + { + "kind": "file", + "path": "img_3356.jpg", + "sha256": "5117ee3cf0f095f60e40802c4ac95b2e4be9809c7a086878b997684d9581c850" + }, + { + "kind": "file", + "path": "img_1541.jpg", + "sha256": "805a84a4468a67e997e48f6f877081f99a305bcb68a918c64123700048f5b666" + }, + { + "kind": "file", + "path": "img_2060.jpg", + "sha256": "ca2f1d9bcd703f04e3297da09d7e318b55afa63123782e396ab5d9952bc8e2eb" + }, + { + "kind": "file", + "path": "img_4411.jpg", + "sha256": "9cca0fd7853ee9700704792cc7ac72f74198863e7820ec4c3d7ca8f87d4ffbaa" + }, + { + "kind": "file", + "path": "img_1569.jpg", + "sha256": "0c3912ed84cee81483f85f78cca43cb58f771438706fbfec3d3935767e286d40" + }, + { + "kind": "file", + "path": "img_3418.jpg", + "sha256": "c1bef94e607ad607fc5d1bd86c4611f35282020d74b78c40179602cf41bede1f" + }, + { + "kind": "file", + "path": "img_4377.jpg", + "sha256": "9ecdc7d080bee75d59fa4cbd6643187782aa80e570c29155e95e86186724cdbf" + }, + { + "kind": "file", + "path": "img_2706.jpg", + "sha256": "6a368132381e7361de89f5e505ba24722af35749d2afb5aaeb23370f7fb36ce0" + }, + { + "kind": "file", + "path": "img_4363.jpg", + "sha256": "76072d03c8933493830ce271579b6fcc815f47d23468979ccfd74de2a46121e3" + }, + { + "kind": "file", + "path": "img_2712.jpg", + "sha256": "5b330caae8123b1f6034ce46e4c4f74b8740583563ed14cc2ac38e0846803819" + }, + { + "kind": "file", + "path": "img_2074.jpg", + "sha256": "51e5130467d4eca634c29b43b8e33d982aeb7d6b0b56692ef346a34c7bffe22e" + }, + { + "kind": "file", + "path": "img_4405.jpg", + "sha256": "e0e8afe3c183085ac945516630bfa8acfc7854d08b28cae15c5cb74a6e62ba8e" + }, + { + "kind": "file", + "path": "img_2713.jpg", + "sha256": "67ee386c7bb2dc62d2303c8100f5b9d559f66f2d626a86fee6507a41130215af" + }, + { + "kind": "file", + "path": "img_4404.jpg", + "sha256": "e2ca3a68e85bbce6acf04c953b09aca3cd3b09d34b8b7e67bf3fc2b559ff8269" + }, + { + "kind": "file", + "path": "img_2075.jpg", + "sha256": "b12ab81a4ef17cb012e9de168857af1244c376f21864e91d4300e85f25041c16" + }, + { + "kind": "file", + "path": "img_1568.jpg", + "sha256": "ae0f5ee40ffe872f2e99779d6dda0b914b8cf3523cc8faab66000620dcaf9b07" + }, + { + "kind": "file", + "path": "img_588.jpg", + "sha256": "24ac0122c66a0f5e4c0a11033b3c0381f24725d733d77f661b8cbeb7f80170a2" + }, + { + "kind": "file", + "path": "img_2707.jpg", + "sha256": "22264f260290149c647c6adda668b54d251c03f2c23ad90ee9cda62edc8382d0" + }, + { + "kind": "file", + "path": "img_4376.jpg", + "sha256": "676f18762297e585bf8e298617fd761aebd22eeb53c5c912c05d223efaeefd89" + }, + { + "kind": "file", + "path": "img_3431.jpg", + "sha256": "44535301892d9d7e15b3665121e68b66f91a3ad6aa5567078246224ae358ab49" + }, + { + "kind": "file", + "path": "img_1540.jpg", + "sha256": "3861242aaa477e8d8a9b81ce2383e4e4b6330d6af41db24441cfbfab763b2b3b" + }, + { + "kind": "file", + "path": "img_3357.jpg", + "sha256": "cb9ed35b6b3a8351c3c7c93a6b6f3ab65e56af9af1259e010119d51a4418f304" + }, + { + "kind": "file", + "path": "img_4438.jpg", + "sha256": "0a66f5a7a8c14c94cb941fecc26a2bd0ff9f49bd634632195466982a4e4f86f2" + }, + { + "kind": "file", + "path": "img_2049.jpg", + "sha256": "ebbe5d40dfcb91ca43d9a5ab518192c89104e1ba7b6ce95ccd8d342fb434aece" + }, + { + "kind": "file", + "path": "img_3343.jpg", + "sha256": "003ff1b93cbac535b229bccf7a27517b7b802b6b276e65683abe7b1bcb513777" + }, + { + "kind": "file", + "path": "img_1554.jpg", + "sha256": "425bf4ce688f92d619c4800e65c4042ade364f0983ac90cf2c01446058fa8c3c" + }, + { + "kind": "file", + "path": "img_1232.jpg", + "sha256": "0eef2cca20b23c87e2e0a25564223ccca8646c29e49c64f6daa0567d4215d60c" + }, + { + "kind": "file", + "path": "img_3425.jpg", + "sha256": "465ef0a22574e40abd08f1f79854d9b192e3b1a94cdbf2454266344864395f28" + }, + { + "kind": "file", + "path": "img_2908.jpg", + "sha256": "a3ca7d7baa0486b2295157874df9f37210adb4237c5592aa351fd0b50ca692ff" + }, + { + "kind": "file", + "path": "img_2934.jpg", + "sha256": "c0f1e97becb25a75747c293c152d569b8608713135cead5a6d47352fb8dd40cc" + }, + { + "kind": "file", + "path": "img_205.jpg", + "sha256": "b8e8bd1b09ad60fd275bfe4d9088c63a9685bc30cd912987188ebd9f2cc2e51b" + }, + { + "kind": "file", + "path": "img_563.jpg", + "sha256": "8bd9c0c3b12d5f6709567f1b5ae665b126868ea1caf4deb982bffdf7bcbe1b02" + }, + { + "kind": "file", + "path": "img_3394.jpg", + "sha256": "866e76d57ddf36d3206ecc5e22c99c44e1d1bb573f3a7f4b0c18deb40cd46327" + }, + { + "kind": "file", + "path": "img_1583.jpg", + "sha256": "28314f6b538cb2cf00fb50a13d1ce9f75710cb76bf20e1200c2b898f22285ef0" + }, + { + "kind": "file", + "path": "img_577.jpg", + "sha256": "322179106d9d5103114084d4cf6c6d7b892aea1fa07abcb4e2bbddedc5ba9490" + }, + { + "kind": "file", + "path": "img_3380.jpg", + "sha256": "3cb20e867d746d9fea3e5f60686ccaf0c1c55a390b556bff057251bac2de0cea" + }, + { + "kind": "file", + "path": "img_4389.jpg", + "sha256": "cd79842a383601e00a80f6b383dd9a4e91632b183ff26bf638e99dc675fe3ca8" + }, + { + "kind": "file", + "path": "img_211.jpg", + "sha256": "e0382879e65a0b4459774d82b23c9818282eab09f8b198c6e2098cea2cb8b6cc" + }, + { + "kind": "file", + "path": "img_946.jpg", + "sha256": "6cd7cd2b399c8f049eb308ab88377e7100696aab12fdca10c9a8234816cde143" + }, + { + "kind": "file", + "path": "img_4606.jpg", + "sha256": "eed5bdae284de21b7f2ca81ab2e0ba8e5f673c200dd9275776e56a5fed464023" + }, + { + "kind": "file", + "path": "img_1018.jpg", + "sha256": "77310a717cbfe29c0166fcac2b1b34cebb6c41e282fa75bf0a10502fcadf3aba" + }, + { + "kind": "file", + "path": "img_4174.jpg", + "sha256": "b90c506b124dfaae5a4814a160d8bde885fb5c069e50bc9ac229ec266fec8274" + }, + { + "kind": "file", + "path": "img_2505.jpg", + "sha256": "7fb2c6e12386962cf424208385e8e40b292fcc375fe8da3649c471373610769b" + }, + { + "kind": "file", + "path": "img_2263.jpg", + "sha256": "69ad36fcc5356ed11dedfbb17f34b3fde562b8479d8eed77cf17ca9961cd9aa8" + }, + { + "kind": "file", + "path": "img_4612.jpg", + "sha256": "c92f439205cf2780a5530b8763b302b4515dd448d54981d54ca2d2fbf0fc8ce1" + }, + { + "kind": "file", + "path": "img_3155.jpg", + "sha256": "e1dd259fa09088cc3f2a76f212c86ab4b458122f348ab5f5fe91792232d4c41d" + }, + { + "kind": "file", + "path": "img_1742.jpg", + "sha256": "3f9a58bc814b2ddd8db53a845e70108009c0a904752ae226af30d92cd82bfd08" + }, + { + "kind": "file", + "path": "img_1024.jpg", + "sha256": "1df358a76cf774bb688e3d36fc13950eb23a975269113f34f7466e80b77eaa36" + }, + { + "kind": "file", + "path": "img_3633.jpg", + "sha256": "f2507c178f1dd9dd46a95929c6fb1a3c6d67fc6bc290d1b1eec51b96972d51bf" + }, + { + "kind": "file", + "path": "img_3627.jpg", + "sha256": "db52cb1ad827f32c8a12e3738aae642d66d19413709647569fcd5e5c1f8edfd0" + }, + { + "kind": "file", + "path": "img_2539.jpg", + "sha256": "4f147becd82769ab9178eab1f23c8b098a66524829ecf15a0d8215350c942593" + }, + { + "kind": "file", + "path": "img_1030.jpg", + "sha256": "7af2e35b46464400b6860b6f5e49c5dc1c8bcdcfadc855c5dcc6a21ab1969721" + }, + { + "kind": "file", + "path": "img_3141.jpg", + "sha256": "eb7d2bb9e003ed63532988f21e3a590d7be38d8488cc57e39c9df8a5c36824f9" + }, + { + "kind": "file", + "path": "img_985.jpg", + "sha256": "ea19321698e714b838e07680ebe72efb4cf698922f0e571c079878267c639314" + }, + { + "kind": "file", + "path": "img_1965.jpg", + "sha256": "92f5c6c73538ba8072ae93445ebf0690b0acdfa635469872b1a021eb9d772f30" + }, + { + "kind": "file", + "path": "img_3814.jpg", + "sha256": "b83a209c09c74aa8edbece584f8a0e272da5b2f8597d0714014524414adf2b39" + }, + { + "kind": "file", + "path": "img_3800.jpg", + "sha256": "90791d25167239a9adba4ce7d4ae868610aa89c219639b97ad6490d434cfdfd0" + }, + { + "kind": "file", + "path": "img_1971.jpg", + "sha256": "b15719d9591ee098580269c866e858b0f3a2720e879c8474a22f0f9d495885a0" + }, + { + "kind": "file", + "path": "img_749.jpg", + "sha256": "48a983271756e98b162a97824521c7811c5c88a94e6d4c838010d8b2556e5258" + }, + { + "kind": "file", + "path": "img_4809.jpg", + "sha256": "383b0814751b899c5bc0740556d8a5303f71e96ed2a1fbe762a0de9c24392933" + }, + { + "kind": "file", + "path": "img_991.jpg", + "sha256": "190a9c37bf7020dfae16e519daea75c8c1902d713f11580d48b74be6dbcc3bd1" + }, + { + "kind": "file", + "path": "img_1781.jpg", + "sha256": "94eff7241634bd617c579c6fe4d095c327daf37ac8a576a6e47b6a2f85cb9e72" + }, + { + "kind": "file", + "path": "img_3196.jpg", + "sha256": "964c778e492869f80d4ba69b9a0d7eb3d33c5614bb41afaec8f1f7f9baba804c" + }, + { + "kind": "file", + "path": "img_761.jpg", + "sha256": "28ed20de83aec51c6a2f7df8793ddf6cb00e45d589250e07c32ef6b7ab7c7ff5" + }, + { + "kind": "file", + "path": "img_2288.jpg", + "sha256": "63d8fdb533ee18a9b5bf5b6d52abe64b72a1ad5239512204b9b1c49d1e71e6fa" + }, + { + "kind": "file", + "path": "img_775.jpg", + "sha256": "e29e06e66e3a8088ae1aba557679368cdf63c18c5ea57e72777d0ae308e48ff2" + }, + { + "kind": "file", + "path": "img_4835.jpg", + "sha256": "a0c39865d7079216bb939ce92d533336e123ae4fe2ac3de7896b1d53efc421b8" + }, + { + "kind": "file", + "path": "img_1795.jpg", + "sha256": "ae0fade2e8f51492568654a14919915becc3a7b301b94540816510544bfbb0c1" + }, + { + "kind": "file", + "path": "img_4772.jpg", + "sha256": "6fa88f7701b7be0959bb7cdb8714f3e0710c85264d6d4805dfdb24d13661bd18" + }, + { + "kind": "file", + "path": "img_832.jpg", + "sha256": "b3ddbf0d87cabf65757c7e9e46eb7db1e17fb92d358b9f55fa2738150b5368bd" + }, + { + "kind": "file", + "path": "img_2303.jpg", + "sha256": "3616de416ba06dff709638fb99941d21864267ad44967cbe007673dca0e01751" + }, + { + "kind": "file", + "path": "img_4014.jpg", + "sha256": "4cd331cacd13c52146c3f4455fba33d98ab896977de7451a99fa201dfc985e7d" + }, + { + "kind": "file", + "path": "img_1178.jpg", + "sha256": "6d29427f7643f5bc7f70131d05d8e8cdb9634db1de4237577963c742acf7b540" + }, + { + "kind": "file", + "path": "img_2471.jpg", + "sha256": "2887ce68d373d8e51b01b80de431636ec8024f34892b9a4fe179f256809df59b" + }, + { + "kind": "file", + "path": "img_3009.jpg", + "sha256": "8335f5286d694521b2c3447f953ddae945f836357df368c58c358834c878738b" + }, + { + "kind": "file", + "path": "img_4766.jpg", + "sha256": "6978ebb4b71657f64c92c2318c7cc5366048b6bd2b0d5a9a6164fa3982d279cd" + }, + { + "kind": "file", + "path": "img_826.jpg", + "sha256": "a98c31125829efef4ce8fd8a0f5a8c6faa6ecf5b312ee204acf3927ce7bd4273" + }, + { + "kind": "file", + "path": "img_2317.jpg", + "sha256": "108a30bb55bbf0b138662df81a0bf1daca7ca6c140015732ed3635e11687907b" + }, + { + "kind": "file", + "path": "img_3021.jpg", + "sha256": "832e0406d50238261a3390af255436870600cf7984b2889f783ca25fb357f968" + }, + { + "kind": "file", + "path": "img_1636.jpg", + "sha256": "5a2d6a813065a98550c9169ffdfa4be173fef7fcf4180a9def7cffff19cb5db9" + }, + { + "kind": "file", + "path": "img_2459.jpg", + "sha256": "77253ebefadaf0908fe26528ef3367b14659312ba8f26b294aab9a93a62a00c5" + }, + { + "kind": "file", + "path": "img_3747.jpg", + "sha256": "fbfff060127169ebc2b09ecb7300f1be3027eaaa2996b6427fcad479d20e2731" + }, + { + "kind": "file", + "path": "img_3753.jpg", + "sha256": "4cef238873872bf40a4c1b5b3df7408a72445a2fd352b33841d8aeed96ac0d39" + }, + { + "kind": "file", + "path": "img_1144.jpg", + "sha256": "8cef72f65e75a72ebf30fb5811d50d6b91dc8c4751d749b2364c5839e632d02e" + }, + { + "kind": "file", + "path": "img_1622.jpg", + "sha256": "5db65bc41377591e76492f6889d54f570055fba935d11a2c998d2d89add38883" + }, + { + "kind": "file", + "path": "img_3035.jpg", + "sha256": "462c9026ce5e54c9a0a5d2a8a6f859a8ed2470b189eb5e819bfd35b911ff7cce" + }, + { + "kind": "file", + "path": "img_629.jpg", + "sha256": "c4a5d91fc94a12f272560ca9327125f4e269196254aa0f1946e34b051832d269" + }, + { + "kind": "file", + "path": "img_1811.jpg", + "sha256": "5b5abd9cab7164ae5fe0f4c2025ff4f5743aab82f17301adb39a2774df45fbce" + }, + { + "kind": "file", + "path": "img_3960.jpg", + "sha256": "8f57a1890eebde864ca860c1c72e5f4d303aed281e8816878ac994a1b924b054" + }, + { + "kind": "file", + "path": "img_3974.jpg", + "sha256": "2a6263ca00f460063d3682240e76df2696804371eca3b78ba19f65c2c79359f1" + }, + { + "kind": "file", + "path": "img_1805.jpg", + "sha256": "9fa1178875475093367954c9d37b3bf834478fe78b0adf083fd789524f2c790d" + }, + { + "kind": "file", + "path": "img_615.jpg", + "sha256": "4e5fc1a45ba8a7a64993ad1fc3a97602458296da4f3a499bb041990f98315d31" + }, + { + "kind": "file", + "path": "img_3784.jpg", + "sha256": "8566cd91dceb62f4570d2342ffaf19672303a640e003670ec1ee3ec20a49cfac" + }, + { + "kind": "file", + "path": "img_173.jpg", + "sha256": "1f02e922ed6d42e5b5a5c32fe52f80d3e01f2dc2c8aa8895a83e9316f6bf9b65" + }, + { + "kind": "file", + "path": "img_1193.jpg", + "sha256": "e09ba2e55555db78dc31eb0449f53f215c2866a51ee628a74fcc475fe6707d4f" + }, + { + "kind": "file", + "path": "img_1187.jpg", + "sha256": "28a2c82486cd20fa628e716880fe01f4889078394fcedf6f028da07afc6c7b70" + }, + { + "kind": "file", + "path": "img_3790.jpg", + "sha256": "8556283bed83014dc167fc4e1a8dbfd3add136c0afa45e7dc4c141c0dfc07216" + }, + { + "kind": "file", + "path": "img_3948.jpg", + "sha256": "47498fcb5c1b7ec27bf7c767c4e4ae26c16525d871cc5e90bf5d17fb9000a808" + }, + { + "kind": "file", + "path": "img_601.jpg", + "sha256": "8416fbe1de9f7ec27b5ba6a3f466a5d2d75e4a4027b236b335a9f7c3b0ca4b6b" + }, + { + "kind": "file", + "path": "img_4799.jpg", + "sha256": "92d5c86a869c54aadb2a29f037ad8c2f58fbbff8d39e12a3aaf7896bc2328b88" + }, + { + "kind": "file", + "path": "img_4216.jpg", + "sha256": "c7d0c09450ea1587bff4b801716401d0cf88382e3b318d161c23b2591a40c3f1" + }, + { + "kind": "file", + "path": "img_2667.jpg", + "sha256": "f3643bc6b12661c042a30a79204f598fef91643e814b885a7a92c9ba7a51a226" + }, + { + "kind": "file", + "path": "img_2101.jpg", + "sha256": "5ff77046886d403be0f5eefd5d90fd60c0f85a74fac453a3e115c25a235d2d3e" + }, + { + "kind": "file", + "path": "img_4570.jpg", + "sha256": "34eabcbe71627a3e07a5c6df58f5e9e63bbec3cb81c683580a1031cf970a428d" + }, + { + "kind": "file", + "path": "img_1408.jpg", + "sha256": "587fe9fe4aebb402ec7956086f0623ee1353aad03589f53f2549d26bc8b95ee6" + }, + { + "kind": "file", + "path": "img_60.jpg", + "sha256": "1843530ef384a1d62bc94748ff4a3843cbef567fe95e6865f042222f37b33bfe" + }, + { + "kind": "file", + "path": "img_4564.jpg", + "sha256": "607f270b6013c926f27ed1a40792a118e35770850065fc73f6184e448a41a6b0" + }, + { + "kind": "file", + "path": "img_4202.jpg", + "sha256": "6a56b8af20fd1d856e867711f47a9b379db7c163a4746cae4ec7449fdb251174" + }, + { + "kind": "file", + "path": "img_2673.jpg", + "sha256": "c89a35fea108b5064b0a35a81500cb93cc92d22800da9632d7f3bfd98a3f905b" + }, + { + "kind": "file", + "path": "img_2883.jpg", + "sha256": "cc9227fbb29d2ebb018609b2e5d2837bbcd9a3046a5f5c16ca85c3c885869938" + }, + { + "kind": "file", + "path": "img_48.jpg", + "sha256": "73d1315a3d6edf6c719179c64ef2a45577f7774f09d580a11f6f87120ed78de9" + }, + { + "kind": "file", + "path": "img_2129.jpg", + "sha256": "b37cb09a5b1c09ea2cc0325750909f1cf90e64fa360388ec33c0b9b63e31ac8c" + }, + { + "kind": "file", + "path": "img_4558.jpg", + "sha256": "a35672acfffe7074883e0600b85abb3e306e8e3c8684286746ab95e346743748" + }, + { + "kind": "file", + "path": "img_3237.jpg", + "sha256": "3624e6f66df862e4b2d96bcd7139ecde3f1ceca129b6b172dddaf46c2cae2a40" + }, + { + "kind": "file", + "path": "img_1420.jpg", + "sha256": "b175aef0c6312fd6d6a8e85dd453dc2c7b5f249b36b12b1ceb7f2e9f46db4dfc" + }, + { + "kind": "file", + "path": "img_1346.jpg", + "sha256": "48ee2fdce7cdd822d11ffcfacc1d9c575090af22a4325fc2ec32d8f2a534e9d7" + }, + { + "kind": "file", + "path": "img_3551.jpg", + "sha256": "1483f557f48a362f170805e68ff992af47eaa3647da44b9750ef2ddf9ef740ee" + }, + { + "kind": "file", + "path": "img_2897.jpg", + "sha256": "490c86c30d82cc56f3dc280f8706a2bba30a0bbc09c09bc222c8c6e9ea9ebaa2" + }, + { + "kind": "file", + "path": "img_359.jpg", + "sha256": "eca5f398ee6e474d0ae31087ede9d2655c5855b42adf2672757f9408ffc064cc" + }, + { + "kind": "file", + "path": "img_2868.jpg", + "sha256": "f65999338f10e408a4bebf81d6da42d6aa1b76c806a81cd270109f59c9fb42e8" + }, + { + "kind": "file", + "path": "img_1391.jpg", + "sha256": "a60b05122d37cee789542f7b9389f29b5b405eaea17e19ce5b074add15d7ff40" + }, + { + "kind": "file", + "path": "img_2698.jpg", + "sha256": "ec63c8f40a7dae4157495f9dc3ed5d330f000b3ed816867dcb58150b2375b346" + }, + { + "kind": "file", + "path": "img_371.jpg", + "sha256": "043d3642b928d7719c1d9894b3891d9f6d243b289c3e0db7e2f3ce6e07dce3ad" + }, + { + "kind": "file", + "path": "img_3586.jpg", + "sha256": "a6ef563ce609a83ecda502d324b4a3a84c5658ee4c854c510269ae0b182bb8d6" + }, + { + "kind": "file", + "path": "img_2840.jpg", + "sha256": "2bb6170d624dcff2cf8b0b896cf7e95ff2947233267ecb257519f40864fb5b60" + }, + { + "kind": "file", + "path": "img_417.jpg", + "sha256": "f850448256197092cb5c996370b2e0ed09506d075669250abeab6367edc50491" + }, + { + "kind": "file", + "path": "img_403.jpg", + "sha256": "9b62424274d46c932fedd21939659e18fa83005a986498098a48ff6f128f00af" + }, + { + "kind": "file", + "path": "img_365.jpg", + "sha256": "c085bb29ee497504fb7f633957a05623a5c010d4a88fb80ff600f9d5effaf8be" + }, + { + "kind": "file", + "path": "img_3592.jpg", + "sha256": "e2109b249098244e83e357df3996cb1e08d9d9cfe2d9aa9cdabdc01cb6762137" + }, + { + "kind": "file", + "path": "img_2854.jpg", + "sha256": "ac49753a1a06cbdf31dd33de51a7f38a859e73f499c02c1f022a51d011926183" + }, + { + "kind": "file", + "path": "img_1385.jpg", + "sha256": "d5f05672e5cdd20d98ca276c5cf352324fd07c80e6dcf397154f4b7dad8a5808" + }, + { + "kind": "file", + "path": "img_89.jpg", + "sha256": "aa0590a02a65f1979fbd78d606c13fc55bfc74453344575f85799a11ae930ec2" + }, + { + "kind": "file", + "path": "img_373.jpg", + "sha256": "56f3fda57ede0feedf9243638db5f1fe4e6e8b07abad6cb501d54c4bdad1c4e3" + }, + { + "kind": "file", + "path": "img_3584.jpg", + "sha256": "4eb781b67e4eae20155f29072bfcebd68572855f7676f76bed94271966ebc5f2" + }, + { + "kind": "file", + "path": "img_1393.jpg", + "sha256": "daa9f67e8ac9b840d584668f1df3d82683e7c385542ec99d24b17b3291e34a80" + }, + { + "kind": "file", + "path": "img_2856.jpg", + "sha256": "23d731c653e56a2c0160c9982ee2db186ec8e300c9e838b7f24de527fc8c0c35" + }, + { + "kind": "file", + "path": "img_367.jpg", + "sha256": "3fb4d76d559315d35906fb9303dd23631ae860523f0e67aa0d424920ee1c5ad8" + }, + { + "kind": "file", + "path": "img_3590.jpg", + "sha256": "e565f153c27e8d684a74a4ca717abd0775fdcd24594a6e38453f98c5cea39e0e" + }, + { + "kind": "file", + "path": "img_401.jpg", + "sha256": "064480dbf2d5af130fcf7464913d8708ea998b162d1c4b806432289480fb9e95" + }, + { + "kind": "file", + "path": "img_4599.jpg", + "sha256": "72659d43e69823ef55b499687e35bb5c1766d475fe3c4c87dcf1a4ca84469bb9" + }, + { + "kind": "file", + "path": "img_429.jpg", + "sha256": "dc80c8aaa69a632f2acd8aa6a329a369dd1ae109f5a1050425b9e0cb2ef5eea7" + }, + { + "kind": "file", + "path": "img_3221.jpg", + "sha256": "11d530eeff0677ea34e0983aa2fa79eaf6181b85d624c6ff0b06d5e27194362c" + }, + { + "kind": "file", + "path": "img_1436.jpg", + "sha256": "3d18292b2f743803873ea28643f0e7c9e3bf9f71a2caa73bd82303b13994b918" + }, + { + "kind": "file", + "path": "img_1350.jpg", + "sha256": "6121972f631343702532d77372e1b58679ed687da4dd05288a8313662f66c188" + }, + { + "kind": "file", + "path": "img_2659.jpg", + "sha256": "4fe1614d588857c3c73f66b74e3d62daa2dc9fd5247a1a9146a438edac0ecc04" + }, + { + "kind": "file", + "path": "img_4228.jpg", + "sha256": "d2ed0ea6f1c24a0ca8bcc2a311762c8f7e973b0038f5c41b43f0d9303c56c029" + }, + { + "kind": "file", + "path": "img_2881.jpg", + "sha256": "ecf7dd6108dc7382aff79256d7634ae5976ddc17be3df7403e71f9ef96681ec3" + }, + { + "kind": "file", + "path": "img_3547.jpg", + "sha256": "89eb9c7c37545b6d0f0071da7acc37e896900e342a9e51bb12213c8098c3f3fc" + }, + { + "kind": "file", + "path": "img_1422.jpg", + "sha256": "bbc8262d0a2f15a3f78e30d0ec666656a6edfcd0b43cab1017a53352312b97ff" + }, + { + "kind": "file", + "path": "img_3235.jpg", + "sha256": "7719998f0bc452d2fc4d9e293597cd202658a1c3a93dc8a47d5a46837873457d" + }, + { + "kind": "file", + "path": "img_4572.jpg", + "sha256": "fce9f4cac66985273472cc9b84655d8a5019a5403390a9af3ee0903b2c44a0e6" + }, + { + "kind": "file", + "path": "img_76.jpg", + "sha256": "3c0557650e82e4172849291aef27cd6a271454874a9ddbeed5c0666c42df1d05" + }, + { + "kind": "file", + "path": "img_2103.jpg", + "sha256": "624980b55fa0b46364eac9bf0fb1e800d7510c1cb87f4766dac4440707addaf4" + }, + { + "kind": "file", + "path": "img_2665.jpg", + "sha256": "51b8d2892aa6487257c1066ce52ce1a588b14c456fbf93fadf50060465efb704" + }, + { + "kind": "file", + "path": "img_4214.jpg", + "sha256": "88a6252eb2f09882744b32f4114682c714f9d1aaf403b351544506270643b0b6" + }, + { + "kind": "file", + "path": "img_2671.jpg", + "sha256": "e0593186bd383c7fb731dbdbff7984dc7cb64cf826ef833cda30c85bf97a2439" + }, + { + "kind": "file", + "path": "img_4200.jpg", + "sha256": "a2efa57def70435a256779914217ed10eec59042962a5935ea87c069b7cfd792" + }, + { + "kind": "file", + "path": "img_398.jpg", + "sha256": "9c3242285b16f33539a9e9f534f2e3b0bdd492ff14a9565c18ea9b7df3f0a99e" + }, + { + "kind": "file", + "path": "img_3209.jpg", + "sha256": "70453befb84b0e2eba8a828b7507da20231a0fdccbf343de726f6eed4047ee9e" + }, + { + "kind": "file", + "path": "img_2117.jpg", + "sha256": "dcff68bf70bb7e39bef72586a148f8949abf52c1f235cd238ebfe2af6087e674" + }, + { + "kind": "file", + "path": "img_1191.jpg", + "sha256": "f21d2b3c551c5c325276bb23033f28e15ac61b2a95fcf0317b1e19f818434e9f" + }, + { + "kind": "file", + "path": "img_2498.jpg", + "sha256": "3d18a53ffac698a67d236cf166ca2ee46c5de84cbe5f29d614206bc46f638988" + }, + { + "kind": "file", + "path": "img_3786.jpg", + "sha256": "2cb1dc0d977df800c474acfc54c1d396c30c61bb10e7395d45b07069ea22826b" + }, + { + "kind": "file", + "path": "img_617.jpg", + "sha256": "bf731384ba7b6ce646161e328fb490b365b6713c94ede37e77f10f7ecdca0ffd" + }, + { + "kind": "file", + "path": "img_3792.jpg", + "sha256": "c6bace0828629b96d5200217a7c56b1434095302e5971f9b25c174f6c8598aa0" + }, + { + "kind": "file", + "path": "img_165.jpg", + "sha256": "2f852c95d351daa73064ed40900ab2c64a24bc86062252ffec8d909347dc4ff5" + }, + { + "kind": "file", + "path": "img_1185.jpg", + "sha256": "e45e097a6fc68c23fc48333b5a2af74cca2f8c03f6221344ca2790ff356713d7" + }, + { + "kind": "file", + "path": "img_3962.jpg", + "sha256": "095e08b1da2ec307791dac0c039c331ad84226b1948de16f622b1ec7afd08bf0" + }, + { + "kind": "file", + "path": "img_1813.jpg", + "sha256": "ae55daa7724599bc10324ca370487bf6ec1ef95024423fc75f6891ffdeb972ee" + }, + { + "kind": "file", + "path": "img_1807.jpg", + "sha256": "056d0c0a2f0e795e74624cbeecf25b8cc172cb324ac629fd682150c32350474d" + }, + { + "kind": "file", + "path": "img_3976.jpg", + "sha256": "af19eec1b0786c9168679087187f6426876e623018a7d29c83b42acd3ffc7f69" + }, + { + "kind": "file", + "path": "img_159.jpg", + "sha256": "444ce76aa4a854218c9a880f348a3de01717fe2cbbbdf71e2aa0de47d9355bee" + }, + { + "kind": "file", + "path": "img_3745.jpg", + "sha256": "fc57b8e1a3b3d83f7fd4f98ee8f49f1b565e87b59d81a996d847a332a58da9e9" + }, + { + "kind": "file", + "path": "img_1152.jpg", + "sha256": "ead67cac2d2ed9f7dd6e27544901010199166f75e93e0fec954dd434975fa9d9" + }, + { + "kind": "file", + "path": "img_1634.jpg", + "sha256": "5d97d3e10aca5c2fdbe8657feb24a0eb8aa841d6a44edd020e63de3cd435e58e" + }, + { + "kind": "file", + "path": "img_3023.jpg", + "sha256": "b001acec0f7168d29766e3cd09519f23969c443ffcf451c50f539680383b6ea5" + }, + { + "kind": "file", + "path": "img_2329.jpg", + "sha256": "b7f7fef2ca0c220a32a27ad795361c9962adb92fd33ebcb0fdc983b5a2f6e401" + }, + { + "kind": "file", + "path": "img_818.jpg", + "sha256": "c8cf549ea166e0ee0b25be47f80297e21a557f675f63c0ea9f2134f93665b2f4" + }, + { + "kind": "file", + "path": "img_4758.jpg", + "sha256": "ae94f5dff9b7921d5f936fb8886eafa03716b4971965a8f854be564f0c42dc4d" + }, + { + "kind": "file", + "path": "img_3037.jpg", + "sha256": "cd52ce23a2484901e451e370f1849d8e55feda52e4e3ced9b19b365d42a6fc07" + }, + { + "kind": "file", + "path": "img_1146.jpg", + "sha256": "05fa3c6dea4d5e119d89a00e38ca811380f0c61512efa603595170f0e892e422" + }, + { + "kind": "file", + "path": "img_3751.jpg", + "sha256": "27af84fb15064a4f002bc13a1c091ccf3200ce7f08e6f8ef964a185558bd9516" + }, + { + "kind": "file", + "path": "img_3989.jpg", + "sha256": "df37c4bfc21380c0457ecf31cbee2cb929b5bc749c7168e200bd390f089af9fd" + }, + { + "kind": "file", + "path": "img_3779.jpg", + "sha256": "b6ed23c741925254eaba08528410f6a0763120528418ac62355c73edf8928c42" + }, + { + "kind": "file", + "path": "img_2467.jpg", + "sha256": "d3859c62e397ea984e70cd9397524c36e5c67cb1952b8d1b98f2b3fb9f177108" + }, + { + "kind": "file", + "path": "img_2301.jpg", + "sha256": "a728efd0559db0ada562018f092a338948b65f4bf9a32f24d35e58ed0e30a2e3" + }, + { + "kind": "file", + "path": "img_830.jpg", + "sha256": "97d5b8389830add1250bd2c5fc237ee6d165dcbe5fa16d6f4ad55b83516604b1" + }, + { + "kind": "file", + "path": "img_4770.jpg", + "sha256": "2c8102f26e316b61bf7137a9541cd930414f3f76d376bcd78e59ce16a8048ca7" + }, + { + "kind": "file", + "path": "img_1608.jpg", + "sha256": "b103162e9c5cb3563c6fbb941a06f5053f3fcf6f821b9a129dd3b290f27a614b" + }, + { + "kind": "file", + "path": "img_2315.jpg", + "sha256": "b7e175b3b5cc9bdae2405c20c4ad0bbfb683db61dd13fccf3dd2921366d7ab10" + }, + { + "kind": "file", + "path": "img_824.jpg", + "sha256": "99e92a8be8b3c28a85992bc9b891126e4bd9e5e9783c8a0cc1442619cec55425" + }, + { + "kind": "file", + "path": "img_4764.jpg", + "sha256": "f3140702d6f8519e3f48b145f6370c360cc3a49e405f09f700a5dc3524c7144f" + }, + { + "kind": "file", + "path": "img_4002.jpg", + "sha256": "679d6cfff976abf29f12e82674a2ebb3396a4f61b129bb53295fcac8dcce11b5" + }, + { + "kind": "file", + "path": "img_2473.jpg", + "sha256": "c7595ebf0254b223451e1605616d2c4d5320faff73a28bdc7b54b25faea83e32" + }, + { + "kind": "file", + "path": "img_4823.jpg", + "sha256": "d5f03d90816418a4fdf682546517b95e6286961c77df38c71a93232315cfd5e0" + }, + { + "kind": "file", + "path": "img_3194.jpg", + "sha256": "813850aa8734324ad765e0f049aca449018828b2c4f2ee991daca5b750131c1d" + }, + { + "kind": "file", + "path": "img_763.jpg", + "sha256": "a9f550bed02d72e3aaeb50df7ee320e607e7c45d99926bbbcf51e9f2d1c3a693" + }, + { + "kind": "file", + "path": "img_1783.jpg", + "sha256": "16118b1bb8ad48397ec5c2cd457a896e42bdcba2c9b8c550001c9badfa8a648c" + }, + { + "kind": "file", + "path": "img_1797.jpg", + "sha256": "b5e2d6a2af6bd06f436a10a7298776be18f6e6120a8da430ba61a95711cd2ffd" + }, + { + "kind": "file", + "path": "img_4837.jpg", + "sha256": "39c70406253cc88033690ba0c9e5f70727604857346abc12c567144030972070" + }, + { + "kind": "file", + "path": "img_3180.jpg", + "sha256": "c478e1b5c6e0aa11d83b263b94603b4abe2f5be51cd8252c561de598d0c9e3f7" + }, + { + "kind": "file", + "path": "img_777.jpg", + "sha256": "91b3e5751a1a953031a2910f16b5c177fc323a4dc5a8a5a2a8b54d9bd2b852c7" + }, + { + "kind": "file", + "path": "img_4189.jpg", + "sha256": "cea3f782b74b76c10c8d339a192c7717be770fe761adc194d06e83efd9c4180d" + }, + { + "kind": "file", + "path": "img_3816.jpg", + "sha256": "cc96d3afba9a45fea9c38e1f61ab6e87863ccdee1b2a1657302072ae143ba1df" + }, + { + "kind": "file", + "path": "img_1967.jpg", + "sha256": "1967f7a60dd8d6f3dda94b02fa96a05790fe9aa3f30b32893856ab6c9eb22b00" + }, + { + "kind": "file", + "path": "img_987.jpg", + "sha256": "597d61625a3560a14009636a7a26748c21ed21e772e005cbeec6215c6a4c122e" + }, + { + "kind": "file", + "path": "img_993.jpg", + "sha256": "c7b80e84d8549681698d910763564585b61546169c205621911079685b9fdb4b" + }, + { + "kind": "file", + "path": "img_1973.jpg", + "sha256": "86d144236b4491504d6a1c89b03bb088bb3971115c52f5fddc987a937419fd4c" + }, + { + "kind": "file", + "path": "img_3802.jpg", + "sha256": "a9fd5c937caabd7fca9df5c3230ec8f69e4cbca0b413d60b260baa5658bc3e57" + }, + { + "kind": "file", + "path": "img_3631.jpg", + "sha256": "8e8436c4552c2155de5373a5645ffac029696ca85f4616e60ca0eec59c4f090f" + }, + { + "kind": "file", + "path": "img_1740.jpg", + "sha256": "e2ac2790ac4ae755031ab602a2d6631238b84e73c93e6464f7f31a80534dc662" + }, + { + "kind": "file", + "path": "img_3157.jpg", + "sha256": "fb46fcf7a66f48530668de39a0ed6931ef85990fea3aa0d42a49fe8769d222c2" + }, + { + "kind": "file", + "path": "img_4638.jpg", + "sha256": "e6d29f0cd6eb7205a259e73890efe201758e1da7badf16c85b1817d744bbb4a0" + }, + { + "kind": "file", + "path": "img_978.jpg", + "sha256": "fe882a959cb1480722fb894f63c69f7951d46dcd46b1a760f88a98b4577ded91" + }, + { + "kind": "file", + "path": "img_2249.jpg", + "sha256": "119a95a07091ad533d2f1048eb56a25c2a3124c16381360fbd140f5c57eeeaee" + }, + { + "kind": "file", + "path": "img_3143.jpg", + "sha256": "25f8a036293acfaa57071b73d07d174fe9a71612184a2e44b07936050436b10d" + }, + { + "kind": "file", + "path": "img_1754.jpg", + "sha256": "1c3bbe4ac0911f2831f325fa8267ae473a36f01ab7f71fd9f2f0c651cc2bcd96" + }, + { + "kind": "file", + "path": "img_1032.jpg", + "sha256": "4870667d0a29ffa347ada0667c85338c05fd9ea2e5ab7894a0baeba34b4114ca" + }, + { + "kind": "file", + "path": "img_3625.jpg", + "sha256": "432a397aa3b974f579bfb108ae5c241a3dc825c16985480f048ac6b23a01ca11" + }, + { + "kind": "file", + "path": "img_2513.jpg", + "sha256": "ceeb8db6b5d74e2249b959a518a0f3f615462d113f953eb41986a58228b6eba5" + }, + { + "kind": "file", + "path": "img_4604.jpg", + "sha256": "87a36d3022a3652f9798c122eb78fc42c9405fcb5a3e4ceff51f25648be8a293" + }, + { + "kind": "file", + "path": "img_944.jpg", + "sha256": "79b6708d4b4034fda861adc716fc8b6fdfa75971cba7ca44bc0903350e7d80cf" + }, + { + "kind": "file", + "path": "img_2275.jpg", + "sha256": "1d0b6360203b0fef32426b5bfbedd456ef893b9f3816e861ce5437d33185c184" + }, + { + "kind": "file", + "path": "img_1768.jpg", + "sha256": "10b4f37238ed191c2e06e45d355d951b7a6092a631260ceba473171f2c4d8b17" + }, + { + "kind": "file", + "path": "img_788.jpg", + "sha256": "2031b09a2be835a9deca778bbab6e3c45d9eb23b810b08d579899d2d55271338" + }, + { + "kind": "file", + "path": "img_4610.jpg", + "sha256": "e0ef5de170cbb825bcc4dee8da33ebd277873b108edfa194803499bcbaca4ca6" + }, + { + "kind": "file", + "path": "img_950.jpg", + "sha256": "593a122c1904bebeb3f656a5140c4a231b392ce7621176f018eb24a40a320810" + }, + { + "kind": "file", + "path": "img_2507.jpg", + "sha256": "b828094ac5617a189d04ff24ca6df1864234086ad5549d8130dd3bcb5e79311c" + }, + { + "kind": "file", + "path": "img_3619.jpg", + "sha256": "83b8d2f6bab7bc0a7e7e32d1df96d95317ba92b46c9e52602c338b64ca532149" + }, + { + "kind": "file", + "path": "img_1581.jpg", + "sha256": "c1b7099e0c0c486735e34292bc4240d07463331e8072f21bff86a26c3023afba" + }, + { + "kind": "file", + "path": "img_561.jpg", + "sha256": "d56a2c916cb2e91f067909f3e8bb5870b5047fc9a98d4324802649f2b2ab5072" + }, + { + "kind": "file", + "path": "img_3396.jpg", + "sha256": "7d8993ea7d00b54ff37b0dd991fd555085a9cf8dc1ebb959a1c87a991c91be46" + }, + { + "kind": "file", + "path": "img_207.jpg", + "sha256": "1ea7b5b61e1d307b85975a883b9503cf3ea925faa69de3734723c948a66e303b" + }, + { + "kind": "file", + "path": "img_2936.jpg", + "sha256": "342d0be7da25aba8c4eee7618138026f10e3e8c5ab366051980467ba554d8ea2" + }, + { + "kind": "file", + "path": "img_213.jpg", + "sha256": "7f87eee57465637dc65101cce8865ba8348062b395d1ebea5a1debd02bb1c831" + }, + { + "kind": "file", + "path": "img_2922.jpg", + "sha256": "85e333fd6c0d4ae6a90c15b8b1cb1667b4e921cf0b0b1e97a19a5df6219bcf0f" + }, + { + "kind": "file", + "path": "img_575.jpg", + "sha256": "9fc05d0ed99f4fd9802d32a5f7e862fa426e50aabe0f535e0a8162c49fd00e90" + }, + { + "kind": "file", + "path": "img_3382.jpg", + "sha256": "bc3b55fb198fad860316c0a843817da0aca779d82d25284f8fd9eceb64f8546a" + }, + { + "kind": "file", + "path": "img_1595.jpg", + "sha256": "0ed5e0dced2a2a5ae8c0bdbfaa4acd70a670dad25a6932509d5dc7d4d24331b4" + }, + { + "kind": "file", + "path": "img_549.jpg", + "sha256": "ee72d2af6fb310441eb87130f9bae6cbc97f806dede09df124f6b9b6c67e6311" + }, + { + "kind": "file", + "path": "img_3355.jpg", + "sha256": "a58af20d517aef15a63d2b4155b2854904c31fdbd85bf04e8039f93f36994f27" + }, + { + "kind": "file", + "path": "img_1542.jpg", + "sha256": "4dfec7c5055f694395f2daa5ec179601974faa1e5b995e21eae2143a27b86249" + }, + { + "kind": "file", + "path": "img_1224.jpg", + "sha256": "82157333a56b71f56a7633f5d1ecb288083075674af39ddf30395c91ebf9a589" + }, + { + "kind": "file", + "path": "img_3433.jpg", + "sha256": "817ba02daec73e92892b643d41d470e777a9d82133581d597595aeca2be31756" + }, + { + "kind": "file", + "path": "img_3427.jpg", + "sha256": "0f2d661068b3a96c6d10196586f573f87c8912aa14bebffff2c9208e5055821c" + }, + { + "kind": "file", + "path": "img_4348.jpg", + "sha256": "79250703042daa832f68ea85ac5057a81c0241929fa80be1ed4cfa2d1d0d6235" + }, + { + "kind": "file", + "path": "img_2739.jpg", + "sha256": "d9ddd8da5cf25f0fa1fef8ff4dbccdf3b8cf32e5e4d9d7f92932ac94e8af4849" + }, + { + "kind": "file", + "path": "img_1556.jpg", + "sha256": "8b8570174c9d11653e394154a181e36c533195886ec8b14d4ff2cad5411dae66" + }, + { + "kind": "file", + "path": "img_3341.jpg", + "sha256": "5c82a70a12276578ec4b47c0c30e986f6b6cb95c9bc973961b25dc10094bb2a6" + }, + { + "kind": "file", + "path": "img_2077.jpg", + "sha256": "5172fa9a7fe9cb47356de2bb8e89ab4d781bfb014ee06f0160e3f8689d21b06f" + }, + { + "kind": "file", + "path": "img_4406.jpg", + "sha256": "ca016d8a2547882c2034bb593d86625d2ee9497797ae60a9b60ae84c466bd9ee" + }, + { + "kind": "file", + "path": "img_3369.jpg", + "sha256": "c9d968926718f321d3096e862eb09a2e88a8a4c80c5b2a9564e13201609e6ece" + }, + { + "kind": "file", + "path": "img_4360.jpg", + "sha256": "c013720ba63f9af89fabe8a7aff23967ba53d6249d3a0cd7e46c7ce036e4af8e" + }, + { + "kind": "file", + "path": "img_2711.jpg", + "sha256": "29366fb1479bf29cc2780fee3a1c1e1077cf6cef8d35d9ec8105fea66e26971f" + }, + { + "kind": "file", + "path": "img_2063.jpg", + "sha256": "4cd93f339c1e3e8e8c3af32ee7e2677bac8867c5d5d73de648749b5679401709" + }, + { + "kind": "file", + "path": "img_4412.jpg", + "sha256": "7ef1b9e1c61847e2fe43656347951319b04308a3cefe0f23d89912b6861549f2" + }, + { + "kind": "file", + "path": "img_2704.jpg", + "sha256": "5b5e6cf5e81e99ed8754f6f802eeba133eeb0f4f637943a2c235ee41e2f93283" + }, + { + "kind": "file", + "path": "img_4375.jpg", + "sha256": "2f9e45772fefa76fe6610ea5f5c47f0713f1cd1a1f74ca68d8e585c6da32149a" + }, + { + "kind": "file", + "path": "img_4413.jpg", + "sha256": "f44361b188a6d9e481c06f2b2c50dd45a5d419d49ed5dd7ba966e347845d39d8" + }, + { + "kind": "file", + "path": "img_2062.jpg", + "sha256": "cb1a2a11accfd3dfdd23677aa582ea3ee3382b0c56cae5dc43c883b59f3cba4b" + }, + { + "kind": "file", + "path": "img_3368.jpg", + "sha256": "3ff0568ed85beaebdf2b2b342674cc40bfda2017f59766d74b7bca0718724bb9" + }, + { + "kind": "file", + "path": "img_4407.jpg", + "sha256": "5ffe1300253b395f3f5d90814ad486af75b3404992194f98712bd50e5ee56364" + }, + { + "kind": "file", + "path": "img_2710.jpg", + "sha256": "152c636074a80c7b9674e5dc098e3928a81cacce84016bf111a2366bb29fc3df" + }, + { + "kind": "file", + "path": "img_4361.jpg", + "sha256": "566b0b805b27da2e4d110a844016c1c995579f4cd13608c913779c0b6da1b36c" + }, + { + "kind": "file", + "path": "img_1231.jpg", + "sha256": "22b338c13a08d168d63fe31f9e23e0561e5e7eb8f382759e7319ab5d72e1d2bd" + }, + { + "kind": "file", + "path": "img_2738.jpg", + "sha256": "6ad1299bb7ad4cad52fd17495c14610419cb875880e3121ed44bbea15974cef0" + }, + { + "kind": "file", + "path": "img_4349.jpg", + "sha256": "d111bde311b1caf502aa2be1e0e0e71ce7929ccd425186ae7b78ee8233e98814" + }, + { + "kind": "file", + "path": "img_3426.jpg", + "sha256": "5306a2fac90c68f966bee34d6c926fae71705465d2191f946870bb51a001a6dd" + }, + { + "kind": "file", + "path": "img_3340.jpg", + "sha256": "492e2b2ff5aa9f0318374f4a8ce55b1deb3733e13eddb9702d1a0b2479bf86fc" + }, + { + "kind": "file", + "path": "img_3354.jpg", + "sha256": "416f88c13cd98fb67a273702b87d793fa04502ee22af4b57b13cfe1921c15de2" + }, + { + "kind": "file", + "path": "img_3432.jpg", + "sha256": "999606b3e414c09eae7b52b68f9ef3cb55aab638307bc887f4b8670a43b3c2d8" + }, + { + "kind": "file", + "path": "img_1225.jpg", + "sha256": "bb1e41ce17dde416d02d67ee29382d2f3104aeda11123e615af4a8865122f841" + }, + { + "kind": "file", + "path": "img_548.jpg", + "sha256": "27ca052c011a574965c21190ac7c248aeeb6b419f40afadb35b829b7deb7e67f" + }, + { + "kind": "file", + "path": "img_2923.jpg", + "sha256": "f187ffa643fbe2d75b2166dad313534aac14480ad8caac250832e86e42b460f2" + }, + { + "kind": "file", + "path": "img_1594.jpg", + "sha256": "a83224a5baf26beacbde19e2c80a9f76e9a9b71c9838db5645cd7aac75ab3886" + }, + { + "kind": "file", + "path": "img_3383.jpg", + "sha256": "fa063f023f98ed267a7371d0bc5e762073c99029ee55fc4b1bc508140f95b302" + }, + { + "kind": "file", + "path": "img_574.jpg", + "sha256": "777d1bfed59bef4c779ff323cd6e9e717e4c2ae3f37be11601c0359d1bfe34f0" + }, + { + "kind": "file", + "path": "img_2089.jpg", + "sha256": "77e4c875cebcc1670bb127bbd2ae13edbd851dca09c0acbc6404286fb42f9b60" + }, + { + "kind": "file", + "path": "img_3397.jpg", + "sha256": "73757d5d0d6ec55c74afa7c14713c421f98cce042eeee5a142216439df16ff35" + }, + { + "kind": "file", + "path": "img_560.jpg", + "sha256": "fcc2175a7a90c161b9bfb99437dbd6baeb39b8e31cd04b44d43acf7af168c0af" + }, + { + "kind": "file", + "path": "img_206.jpg", + "sha256": "900d4b3cb5312b1b4cfcf69d6349cc2c4b0d51a9c8d055492e367758a4af2fdc" + }, + { + "kind": "file", + "path": "img_2260.jpg", + "sha256": "e854ba1c0d5d0c8e0a57a54eb2b7f17d4bce51733318fc4f82999cfa965ac4fb" + }, + { + "kind": "file", + "path": "img_951.jpg", + "sha256": "db7bbeee84962ceb473f74586e453d40eac7b7332f490f79e1628de453a476be" + }, + { + "kind": "file", + "path": "img_789.jpg", + "sha256": "5c27008ba158f87de53fcde43deb730324182aa6642ac04ac28efec32dd40f16" + }, + { + "kind": "file", + "path": "img_1769.jpg", + "sha256": "32f7e14517e2f68e61bebeb3afbf619963f2e2c8c95c8a43a55ab297830e15ae" + }, + { + "kind": "file", + "path": "img_2512.jpg", + "sha256": "114b92e5d1f94486c37daf1bfff691b9828661cf01af3fa335c0fdf97cb58284" + }, + { + "kind": "file", + "path": "img_2274.jpg", + "sha256": "7681d0eef35a5cd9ba48dff3a30dbedb816fa9fd303c46035ce0bcfaeaf548fd" + }, + { + "kind": "file", + "path": "img_945.jpg", + "sha256": "26d60b125658e5d0625b83cff47e9b89a44a77a9806f5c947a26ca1ac37afd7d" + }, + { + "kind": "file", + "path": "img_3142.jpg", + "sha256": "5aaf7da5cc4a242ac0e3d10ed4848871a18316c299b0753dfd9cdd66084a546a" + }, + { + "kind": "file", + "path": "img_3624.jpg", + "sha256": "5b374a27eec05e42285257783b04ca0a644f673af31b04e23cae6fe1ee820e9f" + }, + { + "kind": "file", + "path": "img_1027.jpg", + "sha256": "7c4a750a71b626c7b4166dfd5c82970e44dec84f184f1accb31096ecc0b1d1aa" + }, + { + "kind": "file", + "path": "img_3630.jpg", + "sha256": "639ef7f02366f2c1a86c9df5024f886936bbeaad4691d7938a8ed1af0c5f8ca0" + }, + { + "kind": "file", + "path": "img_2248.jpg", + "sha256": "1ff0298c2d927c78c0340b5da042afd540b8711afd6ee0a4934271eac444dbcc" + }, + { + "kind": "file", + "path": "img_4639.jpg", + "sha256": "90e9d2315bfeca8f6344f40a49baff3501c569e074fa7a8a2e445d2610a9c75e" + }, + { + "kind": "file", + "path": "img_3156.jpg", + "sha256": "4e073620ae4cd415aceeba605a484a7798c9efd21a20a84e83f9d331036d987e" + }, + { + "kind": "file", + "path": "img_1972.jpg", + "sha256": "7f2d8533b5fee320d2dd53926f726573656992b30c0737ce29c760dcfc40de16" + }, + { + "kind": "file", + "path": "img_992.jpg", + "sha256": "8cfc4628a68577280ffef1bdba2cf3fb68f19adce35d680a652659d44dbadc55" + }, + { + "kind": "file", + "path": "img_3803.jpg", + "sha256": "562e0d78236c86dc22d8885af159cd81905d7894b3b7bf9a15c0634a068c1922" + }, + { + "kind": "file", + "path": "img_986.jpg", + "sha256": "a1519e36453f16cd2685b1c9cdb9aef45985fdf3d54d2a70f7dc424b44ddd960" + }, + { + "kind": "file", + "path": "img_1966.jpg", + "sha256": "2c20012ebcc7851c9e90fe7c34e07cdd6cd1aacc9bda135597adbc43a3bbdd48" + }, + { + "kind": "file", + "path": "img_4836.jpg", + "sha256": "b848bb3515fb4c31912f93e83d5f4e94d143b3c464f2a21de1668faf4b1b5962" + }, + { + "kind": "file", + "path": "img_4188.jpg", + "sha256": "9d8bb4caa1ed4e324ff8b6418c2899ca68145f370ac5915c9d00e64b2a8a834b" + }, + { + "kind": "file", + "path": "img_762.jpg", + "sha256": "a5ed94efc07ceb63d5e13a1cc2ebe2933678123af328649f3e77dec2bd7b3925" + }, + { + "kind": "file", + "path": "img_3195.jpg", + "sha256": "d65b4b30faf5f12cff448791d305b79b9608cb9c08f5ced2ca99570445ac0148" + }, + { + "kind": "file", + "path": "img_4822.jpg", + "sha256": "e703945610f5ec69c10dda523f20cedc78bb6967782b174bd6b0acd66e8410d7" + }, + { + "kind": "file", + "path": "img_4765.jpg", + "sha256": "7794c1b3d7b2b866a5b12d42fca30848f2a38b926c1171a77787014a4c04051e" + }, + { + "kind": "file", + "path": "img_825.jpg", + "sha256": "5cf8e9793eec52468cbeab9610041eac17d86b73d999f23910d824f08804b07e" + }, + { + "kind": "file", + "path": "img_2314.jpg", + "sha256": "a1539ecd637009f6c40d8d8fe045478ad4a49171cac929dac0f9578d5e65456b" + }, + { + "kind": "file", + "path": "img_2472.jpg", + "sha256": "e8a3c65d3534326459a00b92cf900403a813b7ec915858ec5061b4348a4a9de4" + }, + { + "kind": "file", + "path": "img_2466.jpg", + "sha256": "aeb6707caa327c2e2664fcda56fdbdbf4212e051736437a2d84fe6fc58782b66" + }, + { + "kind": "file", + "path": "img_4017.jpg", + "sha256": "e25fa9f9444e7990759845a759508c6f3440528c9ae6ee8f1858cb8050e31613" + }, + { + "kind": "file", + "path": "img_3778.jpg", + "sha256": "49af43e767ecc037f51e572121dcb4800898c1e1e17c5264278b7473e90a62f3" + }, + { + "kind": "file", + "path": "img_1609.jpg", + "sha256": "6682c753f4da9957eec97ff8224a2c705cc3820b6e831b8774ee3a4b34397830" + }, + { + "kind": "file", + "path": "img_2300.jpg", + "sha256": "d78caba296f6a2f5c0051037bcb43e7baf6df1eca086d685ca1fae87b6290254" + }, + { + "kind": "file", + "path": "img_3036.jpg", + "sha256": "1df60972200db519d84456814d94e2ffb2aa1d6dce0dd10ecfb8f5010b609806" + }, + { + "kind": "file", + "path": "img_4759.jpg", + "sha256": "9f7d79b35e22bed081df4830e35c2681e2768dd8f15d03af7d0230dc2d0a90b9" + }, + { + "kind": "file", + "path": "img_819.jpg", + "sha256": "37b0c01521c1fb20b0fdaa5700239ebb1547fa76326caa2843fe9768a76f9ac7" + }, + { + "kind": "file", + "path": "img_2328.jpg", + "sha256": "ae3f3c1367de83e9ac1d2cdfefa7756e5c587789a671e8f0ead9d91a1692e60d" + }, + { + "kind": "file", + "path": "img_3988.jpg", + "sha256": "05f0ed261de5803ced7c1cb2a9cc21d72a8e988ea899f8ee592d6f5c165bfdfd" + }, + { + "kind": "file", + "path": "img_3750.jpg", + "sha256": "589399a3d22341479a97ee844a471015d018499ecbff65c1fe2675c4be21c636" + }, + { + "kind": "file", + "path": "img_1147.jpg", + "sha256": "cb67ebb1bbb3c1b54cc9eecde3fded7f937c38c22549cc78b17b5bd34b27680d" + }, + { + "kind": "file", + "path": "img_1153.jpg", + "sha256": "0f3a39fd79998b8d197c492a18044b38d8c710c47af8b1aa5a23efb966718ed7" + }, + { + "kind": "file", + "path": "img_3744.jpg", + "sha256": "ad29e0574e41315d2950871995d183f85639c8efdea0f9f6a9610a0e1aa4d986" + }, + { + "kind": "file", + "path": "img_1635.jpg", + "sha256": "be96c2b553cb1bfa53668a77bdbe0a801ce4a91753cd1811129c9aa93898a13e" + }, + { + "kind": "file", + "path": "img_1806.jpg", + "sha256": "e5465ca2c30fedf3b266092044d61ca10ac8b7698cfd0d5059eb2fb45779c68f" + }, + { + "kind": "file", + "path": "img_158.jpg", + "sha256": "55753954f7b8b5b860889a28353f4e25f6497ae15975430bcbe36c76148ac732" + }, + { + "kind": "file", + "path": "img_3963.jpg", + "sha256": "47e45a7e42c501b0187f7e01669bd55e898389f22e994807ae466ff5d33308e7" + }, + { + "kind": "file", + "path": "img_1812.jpg", + "sha256": "017f8186b0b9832f6e677ad838473cd23a4e5f0c7f621a4488e457e23cbe1dc0" + }, + { + "kind": "file", + "path": "img_602.jpg", + "sha256": "0f93f80eea75dec670a8b01f1729536ded8347b091c47d3b3d55b240c6e3129b" + }, + { + "kind": "file", + "path": "img_1184.jpg", + "sha256": "05982648ba769bc13bd0ea82332721a6b82574ce349f0b9623240cd74704d7e3" + }, + { + "kind": "file", + "path": "img_164.jpg", + "sha256": "bbd1c3ce8fb05026db736a64a94deef769c81459c69d4f96c83c5da1b35e995f" + }, + { + "kind": "file", + "path": "img_3793.jpg", + "sha256": "8789cf531f50d9c1fa4c6d0a5729de96e90e12d7524dc8fbd6645e45aa247213" + }, + { + "kind": "file", + "path": "img_170.jpg", + "sha256": "53294166d91a1bfd6883a5598387c2ca739577e02012e36d0b8c874a5f053379" + }, + { + "kind": "file", + "path": "img_3787.jpg", + "sha256": "28405e271d8af29c2cfc2e982731c37a639ab84da4a990257e830e2d81845770" + }, + { + "kind": "file", + "path": "img_2499.jpg", + "sha256": "4e0f786e86cb5d1ea1e13d4f9b2a63117ebd2305d226dd9134645cb992ee9f28" + }, + { + "kind": "file", + "path": "img_1190.jpg", + "sha256": "37b04c439824e9504706ae83a7fb2355220a3392709c3013e3ac31bade4bbaff" + }, + { + "kind": "file", + "path": "img_616.jpg", + "sha256": "39481fe85b354b0fc92f38f32d149965d456f3b8a66ae586cdccbbaaab379927" + }, + { + "kind": "file", + "path": "img_4201.jpg", + "sha256": "f66f82311d17918ef7f46a9a8e027e75c1d4f82c2339bcb81ccff56f564b3c06" + }, + { + "kind": "file", + "path": "img_2670.jpg", + "sha256": "98241af5b23784640789949014ea0aede85eba9f91809102e6db0cc411cf04fd" + }, + { + "kind": "file", + "path": "img_1379.jpg", + "sha256": "ad94f738958d16ab18f609eba36bee0c4526ef4dceb98136ad007f72263d9664" + }, + { + "kind": "file", + "path": "img_2116.jpg", + "sha256": "e6e1480ec6c9bd2df04934fcafb8361fca60c3accea21298945e57941abd66eb" + }, + { + "kind": "file", + "path": "img_4567.jpg", + "sha256": "9dccd44bd2d07cb42a70f46b3089ed660e58ab252958f159c9449ee260ddf1d6" + }, + { + "kind": "file", + "path": "img_3208.jpg", + "sha256": "f71ac38ce2033eb8f823ec916f0816f87c4e302187d57408f6abc852a8d21538" + }, + { + "kind": "file", + "path": "img_2102.jpg", + "sha256": "b45676681adcd5f5aea1261c95e634c403b7fdd1657e21553a49dd4c1dd1b90c" + }, + { + "kind": "file", + "path": "img_4573.jpg", + "sha256": "1063c8357a9759f4954964eec5111f4be9bbc8d0d3c4f850bfd6d232bdcfdee0" + }, + { + "kind": "file", + "path": "img_4215.jpg", + "sha256": "3481ae987f059052b5c7646ac362c2250745583bca788dc5bd82dd4a4365ca1c" + }, + { + "kind": "file", + "path": "img_2664.jpg", + "sha256": "f4ad66ff23d17893bf76ba3e3989340bbfe5f421560dd1346f843cd293e11a51" + }, + { + "kind": "file", + "path": "img_1345.jpg", + "sha256": "dba2db0064d9cc6395973459bd60344f212373c3fdabe6c1053269f4b9a7a540" + }, + { + "kind": "file", + "path": "img_3552.jpg", + "sha256": "54d88ef2772133d2516c3ca3a4d80897533d0c36c8ed1781e44db1c8ed7a787d" + }, + { + "kind": "file", + "path": "img_2894.jpg", + "sha256": "67ddae9c375b24aa6f4a77fb7f92cdf574e70adb7f128eb6af7d098d2682256c" + }, + { + "kind": "file", + "path": "img_3234.jpg", + "sha256": "3400299437c4e26d22eeb7ba49ad61977383e4675e19e34e6ba9198d2844bccc" + }, + { + "kind": "file", + "path": "img_1423.jpg", + "sha256": "9956f0506685fec5fe86a0bc087d8471c8941b323e5bcfc43d04b3830de2df98" + }, + { + "kind": "file", + "path": "img_1437.jpg", + "sha256": "ec3274f8be1bdef77e86b7467810d758443fab920a52eddc8e7e70adeafe4253" + }, + { + "kind": "file", + "path": "img_3220.jpg", + "sha256": "d8443d69c919f9fdd6d64d5f359f4b65c96d3767af970439157c9bba6eb10a4d" + }, + { + "kind": "file", + "path": "img_3546.jpg", + "sha256": "f1e2e3666f835697e7db564390509b0cd81998c8da4c781477eb26cb5c088738" + }, + { + "kind": "file", + "path": "img_2880.jpg", + "sha256": "3f6c575b5580990e5ef95588a2909499c7411be3ded13331ec07008acf7e759a" + }, + { + "kind": "file", + "path": "img_4229.jpg", + "sha256": "7e6fcba35170aa52e9165cb53f32e09af98f19207298f9414c01504e13cc77bf" + }, + { + "kind": "file", + "path": "img_2658.jpg", + "sha256": "5abd8ce6c19cbf6883ba55918a441ddb32ae49a9e121ba1fbd74171bc61e6d60" + }, + { + "kind": "file", + "path": "img_1351.jpg", + "sha256": "02697355c19d72304b71e98c9f445b3435262a8e3183897c09a253a52754d21d" + }, + { + "kind": "file", + "path": "img_428.jpg", + "sha256": "98dcda813b1aab4a8d4c35da7d679ddbc840e4a88a45837cf0f9605c777ac6cd" + }, + { + "kind": "file", + "path": "img_3591.jpg", + "sha256": "3e56e8b461322c430a50949a008210547a7783a0f153e7ffc28d61eada817c1c" + }, + { + "kind": "file", + "path": "img_366.jpg", + "sha256": "8397f167621a2e9680aeab8f5c4b5cf3b04e439a30c29d1a1bed86c3e29d7af8" + }, + { + "kind": "file", + "path": "img_1386.jpg", + "sha256": "d24e9f31d9fd6626e59b9963a6cb4982ad2584b2d7cdd59abedb47372e1a1196" + }, + { + "kind": "file", + "path": "img_4598.jpg", + "sha256": "755d455a550e5b1ed8c622474b69109a827754a79aa30d4ded894f3f7c262c7e" + }, + { + "kind": "file", + "path": "img_400.jpg", + "sha256": "21835780a42e152cfacc5985c554a6f086136ee1d297160492b2066ac281f050" + }, + { + "kind": "file", + "path": "img_414.jpg", + "sha256": "ec0f625c54d2c9070c4864d9be9c0aa864fc5ca420e3738cdca50dfd2443f1bf" + }, + { + "kind": "file", + "path": "img_88.jpg", + "sha256": "e979b543cd6c7a3167ae08c01842b0ddd265de17b9929a7d90303dae88bfbce9" + }, + { + "kind": "file", + "path": "img_1392.jpg", + "sha256": "086dc8362997e4b7d1b39d43a6aa0f5e5a89d19893fe0d70d48fb626562c404f" + }, + { + "kind": "file", + "path": "img_3585.jpg", + "sha256": "2a9ac895269087560d67a20fa3142a5905865777c6bc786d299ea84a11883cd8" + }, + { + "kind": "file", + "path": "img_372.jpg", + "sha256": "bd03e5cd23a97549f7af937703b9ced7e79e246d2cfbfd352732a1abca0c36ee" + }, + { + "kind": "file", + "path": "img_2843.jpg", + "sha256": "10cc93b774a838e8210156ad508bc6c05b13b18c0eb1757a55aafd8c5eaa525c" + }, + { + "kind": "file", + "path": "img_2682.jpg", + "sha256": "13401802643a17aca9d9dde72220ff0f54c7d53c8d1fcf2271b5765b9a183489" + }, + { + "kind": "file", + "path": "img_91.jpg", + "sha256": "38937a20f3203695bb4a6996907b6376df5aa2d0c8b659b5a0b6221ae38fbdd0" + }, + { + "kind": "file", + "path": "img_85.jpg", + "sha256": "dc4b87ce52c1856e639feee36b23e7433edc18de4aafa95d4744aa49c18118dd" + }, + { + "kind": "file", + "path": "img_4581.jpg", + "sha256": "057a049cd97724028b95cda5b8152151545a79cf23484bff925e1d96a2372a57" + }, + { + "kind": "file", + "path": "img_419.jpg", + "sha256": "469f9a479392eca3ca1b8dfd75244c7b19a041a983b59e7c3563842399afac8d" + }, + { + "kind": "file", + "path": "img_3588.jpg", + "sha256": "afc7ee0c512d0e594c0f2c16b44fbc955441ebad4f6391a4703f44b113823de0" + }, + { + "kind": "file", + "path": "img_425.jpg", + "sha256": "56662e79cf14493cc94cbdec45d983f7f45f065285d9fc4007a438bb7e8d4e8f" + }, + { + "kind": "file", + "path": "img_343.jpg", + "sha256": "a5d8c64ab53abff604be5b417e76048bb1aa47c7b039371775552d58d2270b7c" + }, + { + "kind": "file", + "path": "img_1348.jpg", + "sha256": "48ea8cd5daa05ce234b459c29e0198f6547790efb09eadec709d530d40613459" + }, + { + "kind": "file", + "path": "img_2641.jpg", + "sha256": "09ecd7966b43425c9b47ff8b4135f50c3edf20116e17c2b20bb040df900e7a08" + }, + { + "kind": "file", + "path": "img_2899.jpg", + "sha256": "efe900862d072d9009d530857c37b8d895db13bd9271b9530b1caba92e775906" + }, + { + "kind": "file", + "path": "img_4556.jpg", + "sha256": "b1522aaef35b6da8c638bba3a5b209fa30f02e2c8a030e79e6448e470c42f477" + }, + { + "kind": "file", + "path": "img_2127.jpg", + "sha256": "bc2a33b246ebc340baf6ae5583b812a73577fa1a567f15364ad7292cb4429519" + }, + { + "kind": "file", + "path": "img_4542.jpg", + "sha256": "415510816bf52fbdfd4888d09fd246f2d040240a8ab1106e3c41068551b7737b" + }, + { + "kind": "file", + "path": "img_46.jpg", + "sha256": "8f6f44cdc53f36a7a3ee9ffb3cf0bbc9434acd56e58fc3edaf8859280207e048" + }, + { + "kind": "file", + "path": "img_2655.jpg", + "sha256": "461e9d3230f23a1d72738a492e6f270ea9603e6a430eefc80b3443ce05d72949" + }, + { + "kind": "file", + "path": "img_4224.jpg", + "sha256": "84bba293d4855dabc8ab5365184c708172f8a41dec34789da007161f961177b1" + }, + { + "kind": "file", + "path": "img_394.jpg", + "sha256": "26c75d933243d443a38d7086bf2f53bc2be45d3e9c8d1d833291e6525c467de2" + }, + { + "kind": "file", + "path": "img_3563.jpg", + "sha256": "9ab48bd3b20c5630f22c201299ac3c36f3b22be32134547fd21347c1b4480a6d" + }, + { + "kind": "file", + "path": "img_1374.jpg", + "sha256": "6c7d55237e0dedaa988307298e4934db3a2590548e348c82352515445a9379e0" + }, + { + "kind": "file", + "path": "img_3205.jpg", + "sha256": "0fae50553a09c2fd9d6cc7e1ae460add7ed899fc85542fe0142d05cb66772252" + }, + { + "kind": "file", + "path": "img_3211.jpg", + "sha256": "3efe1397319f068e9b4e4f5e1d66d791c24b5a176d6dc29141cf045294abfc39" + }, + { + "kind": "file", + "path": "img_1406.jpg", + "sha256": "619a54d7586569f3a42fd2ad0c1bf4651144af6740f4438d8a2a985cd3264aef" + }, + { + "kind": "file", + "path": "img_1360.jpg", + "sha256": "248321dd0339ed3b1601172182b9e5ca0ccebb3f0b76d4ff97d04da79b73011d" + }, + { + "kind": "file", + "path": "img_2669.jpg", + "sha256": "50e60e60ede5165adaf9a497ba2f734a45f9f1dcfa639652294124ecf396ce28" + }, + { + "kind": "file", + "path": "img_380.jpg", + "sha256": "4b167311b466385b01d3a44d82168fc0c8501105d158fde124cee5f79f078f57" + }, + { + "kind": "file", + "path": "img_3577.jpg", + "sha256": "d2f9c42a17a0b74700c09fe8b1b1331820614765f181ee3922702fdcdf531373" + }, + { + "kind": "file", + "path": "img_4218.jpg", + "sha256": "089c6d88f344292810fb60df11d4326613ae7eb8d43d79d0d88e9da639fa988c" + }, + { + "kind": "file", + "path": "img_1837.jpg", + "sha256": "ee3c79d4b978b15b9aee874b75967a8cc34c9a21fa2a8e38304d85de2e68b031" + }, + { + "kind": "file", + "path": "img_2480.jpg", + "sha256": "93d4853e7b7004b657a99f79df9fea1ce612a6d65f177fe0fdc7fff2677e00d6" + }, + { + "kind": "file", + "path": "img_3946.jpg", + "sha256": "064b55c6a369f6a85879a4b20ebcca003e44d5fe37bffd19917223bf2ad50896" + }, + { + "kind": "file", + "path": "img_169.jpg", + "sha256": "2c8f8efbf1cab5ddfeafecb13fa8ecadfc65d88d29fb86d511ae2ab28c775671" + }, + { + "kind": "file", + "path": "img_2494.jpg", + "sha256": "fb3ccf0c90ef6e137f722c5751a29936b47b37570d690994f9ced6667aeceb1f" + }, + { + "kind": "file", + "path": "img_3952.jpg", + "sha256": "bbe0f13a97c93e4840beb44647168d41935547296be374f34b5351c37de33cb0" + }, + { + "kind": "file", + "path": "img_4783.jpg", + "sha256": "1e91a0b68bf30c8de54fd633a53f99b3c8795d8c9716e6127744dcf1bc0ee640" + }, + { + "kind": "file", + "path": "img_633.jpg", + "sha256": "0320a9f7060d2091ac01bc69b32061a3d91e62825b119d7d5729d3541c64449f" + }, + { + "kind": "file", + "path": "img_155.jpg", + "sha256": "f09df33ff4c60f06dfcf43b789b8c27bca2e93a2abe65183f9ceca5e895f4328" + }, + { + "kind": "file", + "path": "img_141.jpg", + "sha256": "829cc81f624c5fa6b2b2923bda102ad5b87b1daa84c821b5af9f149e2e03722c" + }, + { + "kind": "file", + "path": "img_814.jpg", + "sha256": "4e179768abaa1f252772f9a882b18a6de7322f26d9a02ae03bb3c9c91be9584a" + }, + { + "kind": "file", + "path": "img_2443.jpg", + "sha256": "d5b28052eadd206e49947602f611737df59a095388ea7ee909bbe0cd07d44149" + }, + { + "kind": "file", + "path": "img_3985.jpg", + "sha256": "fb4a1aa5cd2c74602ad2b7320f3c532f8c3274070f408039f3808a20e7b3f808" + }, + { + "kind": "file", + "path": "img_4026.jpg", + "sha256": "6392c5856abaefc45c08ec9dfab073d843fee2d5e89561adf381ffc432dadf87" + }, + { + "kind": "file", + "path": "img_3749.jpg", + "sha256": "7d0655f75a6251dc22c0c3e3b67e4ac2f3c29035770c88d854cbc8014286b61b" + }, + { + "kind": "file", + "path": "img_2457.jpg", + "sha256": "ea0333cc2e053f3ee1dd52c3e8bfcf6b40c5ccf3a27ec1fcb4c0f3530d963751" + }, + { + "kind": "file", + "path": "img_800.jpg", + "sha256": "e5fd72c32e073a69b58a44e3c5092a951a408e73ef105b8ef3cb385a298d5479" + }, + { + "kind": "file", + "path": "img_2331.jpg", + "sha256": "990ebcf9247ac8a615bce37491270dbc29f20163a2f1cf23263d133c1f191820" + }, + { + "kind": "file", + "path": "img_4740.jpg", + "sha256": "bf664907478b4551cafe21d08524a08e1c7fbbe88b98bdb810cc9ee5fad36ff1" + }, + { + "kind": "file", + "path": "img_1638.jpg", + "sha256": "e3a8e7c5671acd261df81cd73e0006b3b7e8ba3d97ffd17da68761e0009cd57d" + }, + { + "kind": "file", + "path": "img_828.jpg", + "sha256": "eed6700b8a05151e6b88552fe07711855ac65da3dee20c66bcb1fd0d16ca217c" + }, + { + "kind": "file", + "path": "img_2319.jpg", + "sha256": "d5cecc80e8129b1f99ed9531eba782b6d0fc6c481a56d9ba9e290e4a25c8df1a" + }, + { + "kind": "file", + "path": "img_3007.jpg", + "sha256": "f9f61eaba865f6120f10a55ba4f9fda43b7f334bd945cd9e7efeb62d8b9f5bd7" + }, + { + "kind": "file", + "path": "img_1610.jpg", + "sha256": "861c1fab3e069a54536afafde065f6a4d03b23e9cfaf63ecbf9cfdb4aceffc76" + }, + { + "kind": "file", + "path": "img_3761.jpg", + "sha256": "68c937a3a86169aa77b9e87921cbadd226fe499f4ae9f7fc8f797d994aea8bc1" + }, + { + "kind": "file", + "path": "img_3775.jpg", + "sha256": "1c16fcd1b72ce29d1856249b19230f89802c64cec58027b7eb7d4a8f26fe6252" + }, + { + "kind": "file", + "path": "img_182.jpg", + "sha256": "783b42f89dcb493f8deed103590c0191c213b34d659fcf93155eb3de7e9c3087" + }, + { + "kind": "file", + "path": "img_1162.jpg", + "sha256": "2f3105304c78830ce8c5acde63ea729cdefb809d06ee73c98832908e4d80321c" + }, + { + "kind": "file", + "path": "img_2292.jpg", + "sha256": "58dcdde23505f0ad0dcb9f00ea82a55cca62406e19e698990f2fdb361c0cd186" + }, + { + "kind": "file", + "path": "img_4185.jpg", + "sha256": "8e5fb2663501470db51a513c1dfd418e22008327a68ba684a9465b442c5296b5" + }, + { + "kind": "file", + "path": "img_3832.jpg", + "sha256": "8496eed67d8a669d29a99aad1eec196ee32823822fcedac825920419201fa9b4" + }, + { + "kind": "file", + "path": "img_3826.jpg", + "sha256": "a7ee5514ecd57222cae43d49dd6dfb46add51ba1b24dac6e886e875cd6234547" + }, + { + "kind": "file", + "path": "img_1957.jpg", + "sha256": "6523c22b99f66ef2ebcd87d06748c9b995824aa75e9cc0299e56d24bb28e468f" + }, + { + "kind": "file", + "path": "img_2286.jpg", + "sha256": "445246486a5151059abe032d54c112dcc4a22f6b6462bad6c6237031be156523" + }, + { + "kind": "file", + "path": "img_3198.jpg", + "sha256": "60db2085bb46bfd92053de468bbcd85527de7bf174f73993646497054bf39bd0" + }, + { + "kind": "file", + "path": "img_4807.jpg", + "sha256": "f60f9c5629fc253b0eaf41d415555ad4c786c66192c0c4666aeb91ad4c978765" + }, + { + "kind": "file", + "path": "img_747.jpg", + "sha256": "6f2bd950f44c49bbbabc687b8c0094e0238f887fb440b4e5ade9b263acd334d8" + }, + { + "kind": "file", + "path": "img_4813.jpg", + "sha256": "f7be492c3e0603674d115e52a0e99379a8a71d0247f19b7448699273a28b1991" + }, + { + "kind": "file", + "path": "img_753.jpg", + "sha256": "babcfab769258be6189a4de83161be4bb2ef2e6d888ec647c41265100da192a7" + }, + { + "kind": "file", + "path": "img_1758.jpg", + "sha256": "cb2104713dd48eb751364b6b490ee96886a561d4a73ce573d1825dffc1e6441b" + }, + { + "kind": "file", + "path": "img_1980.jpg", + "sha256": "665ff81a58d4a9da093a5c44cf345e43dce715d37fe3c1a29bd9661f4037d54f" + }, + { + "kind": "file", + "path": "img_4620.jpg", + "sha256": "af3a6c884a15a7e2d6f8a3fe6e18e9963b8611417e0f1a12ab6610877ad94d37" + }, + { + "kind": "file", + "path": "img_960.jpg", + "sha256": "8759b73755d574a15441a7e805d6f5942af9a89f02e56c719b56e1bac22de3c7" + }, + { + "kind": "file", + "path": "img_2537.jpg", + "sha256": "ee2e77edf135563792488370ab465cc2f59b31bd145003ab2a1faf4139ebaea9" + }, + { + "kind": "file", + "path": "img_3629.jpg", + "sha256": "ad08a0f6747707a90589a07a9280e0ebee2fe9d6c32cf28902d47a3f0ea79d8b" + }, + { + "kind": "file", + "path": "img_4146.jpg", + "sha256": "c9beb93a1f854d4270bd70a710de45c0172bfe3119aa9835822940d6d3321860" + }, + { + "kind": "file", + "path": "img_974.jpg", + "sha256": "73bd1702227a0f519fbef7cd7fb74ddf920c15d6d05d21dd7f912f8f42bb685b" + }, + { + "kind": "file", + "path": "img_3173.jpg", + "sha256": "728bf8010add7b40d781e5d67fc823134a5561a55ba9c2ad916bd75a7d9e42e6" + }, + { + "kind": "file", + "path": "img_784.jpg", + "sha256": "f111d03a58b619a56cefe95143a7823fada15c40efaa5fe7c93edf834de082db" + }, + { + "kind": "file", + "path": "img_1764.jpg", + "sha256": "ccb553a416976bb4d00ee715e7e92d441d3e8daa3b0324073c4c25685f343fbe" + }, + { + "kind": "file", + "path": "img_1002.jpg", + "sha256": "33017bd0ea88077b1241c4f293a1563597dfe91ab5355bde94c2050a3dcc4569" + }, + { + "kind": "file", + "path": "img_3601.jpg", + "sha256": "2d4c369a44bd11ffdc5538b7ea5eee778cb390f24374d23d70c07448eea05e18" + }, + { + "kind": "file", + "path": "img_1016.jpg", + "sha256": "7d44334712c38faec731688888443846b6a845604533901fb70ad2bbb5097f6c" + }, + { + "kind": "file", + "path": "img_1770.jpg", + "sha256": "364d43ed1411093f3074ed5884aa75f36b027dad5a83ac87f73b28997e76f1df" + }, + { + "kind": "file", + "path": "img_4608.jpg", + "sha256": "5f2ce36a4e1977920c4f1dc2bc28ad76be3e3bb8f96c540267a8f307b2189f79" + }, + { + "kind": "file", + "path": "img_3167.jpg", + "sha256": "eee3901c9cd73c5830c0b9ffc2858419c993fb70e4eed274ae337b08a5b5f2df" + }, + { + "kind": "file", + "path": "img_790.jpg", + "sha256": "88a15cfa7a1971c8e25701f1c1f2fed15baa11eb1852e471fd554b9d2bd9c988" + }, + { + "kind": "file", + "path": "img_2279.jpg", + "sha256": "6cc5682af6fb7e3191ac1dafaf5ca5745032265877770e2e4a80161e34d3a50e" + }, + { + "kind": "file", + "path": "img_948.jpg", + "sha256": "ac6446f05b05ecee46a6b01a8730de4202162d71c53b1ddd68e27f99c7293ee6" + }, + { + "kind": "file", + "path": "img_4387.jpg", + "sha256": "9cbc20b7667a4dc1d35ff56473b56b0ffaa8b270ce9ecf32367808e7a3fa10f1" + }, + { + "kind": "file", + "path": "img_1599.jpg", + "sha256": "fcf4038050592e85fa409151a3f95132a95850505e4856bcd5a2ee51f4238ec5" + }, + { + "kind": "file", + "path": "img_579.jpg", + "sha256": "88a1859b0a400cb3559fe72a978733e97b0cfc8d5a77d49070aabbc82921acbe" + }, + { + "kind": "file", + "path": "img_2090.jpg", + "sha256": "66bffce09903fca4e45a892ea881245540a78a739eec3b96494b46a313202e22" + }, + { + "kind": "file", + "path": "img_2084.jpg", + "sha256": "0ac86a072acf9205b35bd3a6c538de94fb587b6ef42ab3417671fb547d2f76a0" + }, + { + "kind": "file", + "path": "img_2912.jpg", + "sha256": "9cd38b4f95d6ed1d211bf8ea900a3cc2a68c46ace6078f6f14d9c0bf991b8057" + }, + { + "kind": "file", + "path": "img_223.jpg", + "sha256": "c2bf1a60ffffc5ff1e8528e5c918d5d351b4e6328cb63b34d21d0f2afcd55de7" + }, + { + "kind": "file", + "path": "img_545.jpg", + "sha256": "379e378cd56e9e11a5854bda3dd9c01c11d846e1467febc7d8f7ea7929f5e6cb" + }, + { + "kind": "file", + "path": "img_551.jpg", + "sha256": "bb9d7e10dced76d19ca398edc682697ff500efababf63759fb2eb8717bdfcd52" + }, + { + "kind": "file", + "path": "img_2906.jpg", + "sha256": "706cd5bcddd5d7b37ed6988632dbb5a4a05e835f8d776683c4c07fa1ab42afe2" + }, + { + "kind": "file", + "path": "img_237.jpg", + "sha256": "6b9a2537796aa2c1d42b2bdda3c654a938715f24a7dcb5219917177800bff98f" + }, + { + "kind": "file", + "path": "img_4344.jpg", + "sha256": "cc4643c70c185b0dae644d1454b41677052200f77930ca73031d3956a0f15197" + }, + { + "kind": "file", + "path": "img_2053.jpg", + "sha256": "f463f56abe746f5d11579cb1451bb9e4260e040df6c359a986fbabf81e94980f" + }, + { + "kind": "file", + "path": "img_4422.jpg", + "sha256": "7592bb14b2bec925764585f09444e1db336e9a73953c605f19b65a5a933e6728" + }, + { + "kind": "file", + "path": "img_2047.jpg", + "sha256": "5640363aeb336b42541b1472a073ad006fd2600dec514e02b9a557fd6f3765db" + }, + { + "kind": "file", + "path": "img_4350.jpg", + "sha256": "880d0e4ad3ecccd7bbd4517f706c61c060ce88e6205c484cbfffcf38487cceb8" + }, + { + "kind": "file", + "path": "img_2721.jpg", + "sha256": "f84424f23d13373ec2b492d078d0a407987e7715ecee3630fa94fd88e0e45f05" + }, + { + "kind": "file", + "path": "img_1228.jpg", + "sha256": "01a1194a7c5d55faba8867f92ac908c7c70d3c1e6e0581f4794f9034d2ab467d" + }, + { + "kind": "file", + "path": "img_3417.jpg", + "sha256": "cb9bae25e29d21257572e4c32a2c86195345b2c2899341a99f11af87e504d32d" + }, + { + "kind": "file", + "path": "img_2709.jpg", + "sha256": "e361b5b324fd07249faa8cd9516208adba79167df4a8b3224263f366eee2e80d" + }, + { + "kind": "file", + "path": "img_1566.jpg", + "sha256": "06e87d40aa61dec20137230db27dc67cc2420a3fee20879cbf4a68fa00546f94" + }, + { + "kind": "file", + "path": "img_3371.jpg", + "sha256": "58ee27f7ea1368c2f0b47c0265b7f0cda46fcc09127b34785942683bc332495f" + }, + { + "kind": "file", + "path": "img_3365.jpg", + "sha256": "0a96cfcf715d683af83478b30e16a09c9d0be7121e1ffe6217a2492cda6bafc0" + }, + { + "kind": "file", + "path": "img_1572.jpg", + "sha256": "6e515993adb337f20da4668fd706d64a5aa1fc2631ca3ea8e3a3c1d1752893b0" + }, + { + "kind": "file", + "path": "img_1214.jpg", + "sha256": "0503bc4d49fc420f71e726c6ff7fe1c9d341b14e596d0e175e1875c3bd7a032e" + }, + { + "kind": "file", + "path": "img_3403.jpg", + "sha256": "e6b306d35f7fe1fa7c031f03072c3fc395e842e0bcd44e008ca732c28e95e992" + }, + { + "kind": "file", + "path": "img_1573.jpg", + "sha256": "06de090c5245ee88ed9ee015608080db2fde78395105ee9d23c8b731a2c56bd9" + }, + { + "kind": "file", + "path": "img_593.jpg", + "sha256": "852a21e9dee514ac03dc021cfc79744efc26b601960601818a7c4378985fd2c4" + }, + { + "kind": "file", + "path": "img_3402.jpg", + "sha256": "6cfecaeae7910a6bd9b298f22e024b21ec7cc1bbe0753fe6c531eb910ef90b69" + }, + { + "kind": "file", + "path": "img_1215.jpg", + "sha256": "b7fecaf929d106813381df873284747f322f2c59b009ce505d3e20f3ba1068ad" + }, + { + "kind": "file", + "path": "img_2708.jpg", + "sha256": "beef1993558adee3ccb8a54d3aad686f4c74db8ad37c622f4fb9c1a929ced171" + }, + { + "kind": "file", + "path": "img_3416.jpg", + "sha256": "4af38c0c9ee7849bab7fa69145d4f34f3e7d2da0686dc7856fefa71e7c79745b" + }, + { + "kind": "file", + "path": "img_4379.jpg", + "sha256": "58b935fe8fa608ae15b31453c09a31e4edb90972ddde39ff79b54a231ee97ff0" + }, + { + "kind": "file", + "path": "img_3370.jpg", + "sha256": "42a2bc8e1af924a22271d57f699a0b4b69fbf14b9f30447526561c8546b1f635" + }, + { + "kind": "file", + "path": "img_587.jpg", + "sha256": "eafbd6b7f71b93fd5150c4e6f4e26c2b94f3e7f03ea8b5105272e7b4aeacab8b" + }, + { + "kind": "file", + "path": "img_1567.jpg", + "sha256": "e5b32023928b00e60faad7806b4901e2223e5a623bef3fdfe1b073b490dac93a" + }, + { + "kind": "file", + "path": "img_3358.jpg", + "sha256": "44bbb164c8ee0840563b5e5637f07ccf3475ac946dbe5e65101b531365b9d3fa" + }, + { + "kind": "file", + "path": "img_1229.jpg", + "sha256": "2a5928afb47a3801a0a623f2b091d182539b6212bb9f7555e808bfd996507bf2" + }, + { + "kind": "file", + "path": "img_2720.jpg", + "sha256": "bee7a3033c65041a3c1ab755c8af66be0b9e35589d48a4e7be48bc5a6fe6c581" + }, + { + "kind": "file", + "path": "img_4351.jpg", + "sha256": "ae98ecfe52eb8c84ae6708dd8b9c9b11f73b87c28cfdac65915edd9ebc9a4e0d" + }, + { + "kind": "file", + "path": "img_2734.jpg", + "sha256": "e8f91093eb6970594b093c814aa4bc9a5626a0f3d6784bb9d7d7251fde2b5afa" + }, + { + "kind": "file", + "path": "img_4345.jpg", + "sha256": "a3ecf3a4ff4dc92abe7500e89cacb07b6a3dbd494e91f7ad6e16edabe0ae0f90" + }, + { + "kind": "file", + "path": "img_4423.jpg", + "sha256": "d35544d2ccfbef0a584e20fd08377ebacdb496edd60898a09bc02a3802bc0b13" + }, + { + "kind": "file", + "path": "img_2052.jpg", + "sha256": "b4fb0edbfdb1805cd5b54ea8c7dbffce75a7f19bf2b50f8431054191cdc715a4" + }, + { + "kind": "file", + "path": "img_236.jpg", + "sha256": "80042c44fe53848c39f62c260d4b343a2b65a2b5596cb492ecb6232147bd8bd6" + }, + { + "kind": "file", + "path": "img_2907.jpg", + "sha256": "ca076b65c64cec939a36c2fa5ed6de27d25d8961e6db4642d688fa5a340e6d67" + }, + { + "kind": "file", + "path": "img_222.jpg", + "sha256": "169428b1a7782d99b398ce20506c664ddaaaaa677c1966a0cfb0adcccc5f3b83" + }, + { + "kind": "file", + "path": "img_2913.jpg", + "sha256": "24465a56d06b27a6f5e1a23b35a37248fe4c53aec3275e746228755be76c6cb8" + }, + { + "kind": "file", + "path": "img_544.jpg", + "sha256": "501061b70b8747f8b29cc2a64a8d8d06f191c2d8221cb276215f759aa7e66f82" + }, + { + "kind": "file", + "path": "img_2085.jpg", + "sha256": "364d5ffa2e5bcec5fe42af45959177665817676e567a1d521f8d4577079f899a" + }, + { + "kind": "file", + "path": "img_2091.jpg", + "sha256": "61a37438373aae0ebb1ed0a68b5a33e02ff155d278a5af35c346cc4b0df402a8" + }, + { + "kind": "file", + "path": "img_578.jpg", + "sha256": "71aa125681b99e12900c563817c0c79569798c6adc120f5415c01ae65c158bfb" + }, + { + "kind": "file", + "path": "img_1598.jpg", + "sha256": "e22cd47b0fddd4f0752e5a8e372b569390480b79ef82cfa095bedde35341b4e2" + }, + { + "kind": "file", + "path": "img_1017.jpg", + "sha256": "b1ae4e3288315568905fbc2fbf769a3e13fc73ac125c04b0f979560b0e4c5a2e" + }, + { + "kind": "file", + "path": "img_3600.jpg", + "sha256": "225bcf620f5c4b1a167ae6f031b6dedef5bc9084284d2479a9a4bab8627c53d1" + }, + { + "kind": "file", + "path": "img_949.jpg", + "sha256": "1ad82b90b267d7c3f5a9b1cc957d7f29591c89f4b8d6249b9ea2a82d70105613" + }, + { + "kind": "file", + "path": "img_2278.jpg", + "sha256": "762c5826d89ceebe479120d3810dbedc77f9ea7bcb5817390be1c549ec5ac5b1" + }, + { + "kind": "file", + "path": "img_791.jpg", + "sha256": "bd31e39ed6cd4d770e02766eb3ba908c74606a5d4f1df3d87da72d13f0d78e16" + }, + { + "kind": "file", + "path": "img_3166.jpg", + "sha256": "3eaf73475cec828f11ad33d2c5401e822b0d55fb1984bf3f6696b54cbd9105cb" + }, + { + "kind": "file", + "path": "img_1765.jpg", + "sha256": "3aa329116b0a725a1da32aa1e515caf843ef3b7e0c7955afe0686b491e3ea734" + }, + { + "kind": "file", + "path": "img_785.jpg", + "sha256": "ac56b912c9b6b65b6429d28d5d18876a0d2e08a6fdf8cd7a0753c54a3091372b" + }, + { + "kind": "file", + "path": "img_3172.jpg", + "sha256": "11a642c62792e1f1ac30702b2b05746559e555135d2c0d6fdfed2fd3dc978528" + }, + { + "kind": "file", + "path": "img_3614.jpg", + "sha256": "2a50763e701e9a7393a4c5b0ab6cc4cdf01f1b767fe52bad981823955625511c" + }, + { + "kind": "file", + "path": "img_1003.jpg", + "sha256": "84ff2cfd7eb5a40d6ef408e6a0cf95bc96fbc16f722e938678b33283215988fd" + }, + { + "kind": "file", + "path": "img_2522.jpg", + "sha256": "aaa874ad135ed50d95b6dd6a1c0522b428778c90350523bb21b8a0dfbc665c54" + }, + { + "kind": "file", + "path": "img_1995.jpg", + "sha256": "5358f9a6bfe275305f492cebaf674a1db8978eb8fcc44c98b23e00b80e1c69c3" + }, + { + "kind": "file", + "path": "img_975.jpg", + "sha256": "fef94d952390f8b3b26e64f3627a7c79fbf52a719ae35272feb7b3113a46122b" + }, + { + "kind": "file", + "path": "img_2244.jpg", + "sha256": "533983ec54a88b4596704d8e7012c41d6350f28ec8e44e849327d4a83c12c8ac" + }, + { + "kind": "file", + "path": "img_4635.jpg", + "sha256": "deb33781bebde032318579caf13a9779992c3ed86f950cdf3fabf986d7c22e80" + }, + { + "kind": "file", + "path": "img_961.jpg", + "sha256": "2f709be4c947b5af065f1fdc51c2d649d71b38d58e07b07e7f01a82649ba957d" + }, + { + "kind": "file", + "path": "img_2250.jpg", + "sha256": "d3eb00bd75345f8fe6703462d47e333ad5c4ae27e5feb5094c1502123489daa8" + }, + { + "kind": "file", + "path": "img_4621.jpg", + "sha256": "95d0ebe633415d83c87871854b3f0887cd7a0783f3b2d5864f3b8001cae51299" + }, + { + "kind": "file", + "path": "img_1981.jpg", + "sha256": "d3625dd45dbc1617de80765c8986066cb7defdf3bc6228ab21df76fdc63b21c6" + }, + { + "kind": "file", + "path": "img_1759.jpg", + "sha256": "7e89f9253a0f26f7363382d0adf862a211da203632674413838335bccad4a420" + }, + { + "kind": "file", + "path": "img_4147.jpg", + "sha256": "268b19dcdd4c54edbc0d1043d67aad060ae344ca037d16b1a1811104e5b8d4a5" + }, + { + "kind": "file", + "path": "img_3628.jpg", + "sha256": "4cc89711288fe149a09a780edea25e4efbe6fd1366195948453e452b2b01540d" + }, + { + "kind": "file", + "path": "img_2536.jpg", + "sha256": "f585b8c9e431ca42a8bcda62658fdb7f44a41eb272c1505771a6305a6af723df" + }, + { + "kind": "file", + "path": "img_4812.jpg", + "sha256": "0ea99a537c557aade0d3ab5d26c687d7ebfcbd0c5522f07b018addae9315dc21" + }, + { + "kind": "file", + "path": "img_746.jpg", + "sha256": "6ed0d0ed5623ef7d5514ee9b505a2ed2424182a9077c7f3f3c9794409e3fbd33" + }, + { + "kind": "file", + "path": "img_4806.jpg", + "sha256": "9b1889d6d47c28520160e924a01503f7aeda9fc1369e4cb0428055212abc5a16" + }, + { + "kind": "file", + "path": "img_3827.jpg", + "sha256": "857e541e4fd7ea45049e30948f4e7d921946538c843707169998d597bf46dace" + }, + { + "kind": "file", + "path": "img_4190.jpg", + "sha256": "4f07b60addf3643d01a2397cc24b8cb97cb3a84e672c469726110ff58f48f535" + }, + { + "kind": "file", + "path": "img_3199.jpg", + "sha256": "9d8d7ca731fe7b05f5b277c742a718eecae70e0cbb6083877aa9ce6ad0f17912" + }, + { + "kind": "file", + "path": "img_2287.jpg", + "sha256": "07434a85853bfadd7fd2be9cca1507e9a16591c61b2580b21cbea07302252409" + }, + { + "kind": "file", + "path": "img_1956.jpg", + "sha256": "c16ed3a213abb11c37825f0703c63c40b9631ec0bed1ab18bf0437d769ea1864" + }, + { + "kind": "file", + "path": "img_1942.jpg", + "sha256": "2c47f28b8011d5064af9b9e46398378e9c490276195f2ace959459fe7756f528" + }, + { + "kind": "file", + "path": "img_2293.jpg", + "sha256": "78ff509ff8feb9a8ca6e7f57afef8c55b8e65dfb9ea56c659763b6c01e0486d9" + }, + { + "kind": "file", + "path": "img_3833.jpg", + "sha256": "4cb0f238267956048a244a18c2b56493b0d7c46b2a4da6651da0e15d13a5f28d" + }, + { + "kind": "file", + "path": "img_4184.jpg", + "sha256": "a2990004ff3d26088cf7298a9665289b0e274f3db3513714d1146379f7dfaf46" + }, + { + "kind": "file", + "path": "img_1163.jpg", + "sha256": "9bb0036d27f9a91a9e3eb02bd3f3a397a24262212792c613f4773eef1651943a" + }, + { + "kind": "file", + "path": "img_183.jpg", + "sha256": "7d06a4a1e1c21236674888f55b00bc4ccfcc97f2adbb34ffa72da10e8aa97fa4" + }, + { + "kind": "file", + "path": "img_3774.jpg", + "sha256": "1832d283f9811432f0803872fe16b290ee3de2f718e1d2b26e9d52166eaa4539" + }, + { + "kind": "file", + "path": "img_1605.jpg", + "sha256": "3d19244403f842e798f59f827e66c0fe744a92a2385c10b29454f76505a0472f" + }, + { + "kind": "file", + "path": "img_4769.jpg", + "sha256": "3aa0c47a6dbb9c0373c71f7c7492d15231d9975bd2b85d8b766362f11ecc12d3" + }, + { + "kind": "file", + "path": "img_3006.jpg", + "sha256": "b0023220aaa055e1bd1dfdeb4debd2175c27477907811e7d2337a9af1a262875" + }, + { + "kind": "file", + "path": "img_2318.jpg", + "sha256": "6967875fe623966ac9d210793c6d68c6bf297241fb247e4a3fa708719325bc66" + }, + { + "kind": "file", + "path": "img_829.jpg", + "sha256": "e1a89c4ba0bab522128f8da3fcc937b49250dc17839beef1bf0dc40832703c58" + }, + { + "kind": "file", + "path": "img_3760.jpg", + "sha256": "94fe50aad476b3f647b37263a1941e18ecb126d13c5f9e37910f9a0abd17ae62" + }, + { + "kind": "file", + "path": "img_3990.jpg", + "sha256": "bca6cf9cf79d5f44d53c3e3c0ae91fab9c640fc6ea62d0df38f19ed9633f04a5" + }, + { + "kind": "file", + "path": "img_2456.jpg", + "sha256": "f1bf97c1ba7b66b15b91d9a8725cf484e6410f51b64a3e17750b387ea8ebd55f" + }, + { + "kind": "file", + "path": "img_3748.jpg", + "sha256": "5f00c4c42f83a4f6eed1e6f193b532625e71dbb9690ed869f1c36168c6a93ccb" + }, + { + "kind": "file", + "path": "img_4027.jpg", + "sha256": "43c214e4c2f3b9f4caec7a93de3913c3c6f5b0ffccf089c9e2fe5c6b935f61ba" + }, + { + "kind": "file", + "path": "img_4741.jpg", + "sha256": "59c72078956dae8d69fa0628aa494b749e4389ae26ce98fa44b8f0c630e80520" + }, + { + "kind": "file", + "path": "img_2330.jpg", + "sha256": "aea27e2a7523629e0fec2fc6be8509e2477bf86093e0944f08954bd5916f9c78" + }, + { + "kind": "file", + "path": "img_2324.jpg", + "sha256": "beddbfd328f746932e56cd31959681c5bee789d49735106b969fe29223b6a820" + }, + { + "kind": "file", + "path": "img_3984.jpg", + "sha256": "3212026d88e3fe8c7a44244459065243ce52d8faacd23f69662ebce2dba255c1" + }, + { + "kind": "file", + "path": "img_2442.jpg", + "sha256": "5b825c7f1d9eb2e489712fdd43800bb0cf8f140618917b1965dabe0aed17713c" + }, + { + "kind": "file", + "path": "img_4033.jpg", + "sha256": "9f62bb68f3d718c1db4658d836b15876dbc9313ec995b2364567f7db16142d42" + }, + { + "kind": "file", + "path": "img_632.jpg", + "sha256": "d4af176fc21a5629bb50bc2aab30575ba33cc5a9bd6e4fea41d3ba4b97815355" + }, + { + "kind": "file", + "path": "img_154.jpg", + "sha256": "6951af6641e22f6919c9066dcc08e6add36759bfdeeac8df9ee4c5a5eccdb2c2" + }, + { + "kind": "file", + "path": "img_3953.jpg", + "sha256": "cf162002529f3ff77b187eb418e07987aacf8c6d0e0dde91243b5075c6a62000" + }, + { + "kind": "file", + "path": "img_2495.jpg", + "sha256": "17a4866b3d0a1a0b5f6a3ba98c2bd29d5f82e43129b36bcfc54642854cf6ba36" + }, + { + "kind": "file", + "path": "img_4782.jpg", + "sha256": "d714b1e1a8c82dbecac5638974cccd45456cbd71970847c59a768697c4cb4274" + }, + { + "kind": "file", + "path": "img_1822.jpg", + "sha256": "cacd0fe788dccbe6d2597035f0ed4930c6ccc8a0e603c4b2e42d24bf8a6bd673" + }, + { + "kind": "file", + "path": "img_4796.jpg", + "sha256": "d3161bc7047dcad4d4b778942c84c3f6c9725ba28eea938f54e52614684f2052" + }, + { + "kind": "file", + "path": "img_168.jpg", + "sha256": "6b4f6ffb8aa074a81e927de0613281bb1716153775692e303f7cdbe15e03704f" + }, + { + "kind": "file", + "path": "img_2481.jpg", + "sha256": "16ea0007c03173ab893c1d65d370d5f4d0fec575b3b5e5b5885efb369b62c4ad" + }, + { + "kind": "file", + "path": "img_1188.jpg", + "sha256": "65b0301381512030046e313cb620986388f639e560eea9fc3ceb7a1da9adee99" + }, + { + "kind": "file", + "path": "img_3210.jpg", + "sha256": "23c9f5410bd6e0f1fb52d455aed5e2dcfbc2eb9edc777e87f0dc846a455f2713" + }, + { + "kind": "file", + "path": "img_4219.jpg", + "sha256": "139cd5bcb25ea6d91478e8d980bc9230db72be64d4a12b07cbd2be49d37e4808" + }, + { + "kind": "file", + "path": "img_381.jpg", + "sha256": "4dc158a732567e9feea2fddc33abbcbf6af8f8582c6528326bee037a60198fe6" + }, + { + "kind": "file", + "path": "img_2668.jpg", + "sha256": "492d7e9fc77b99255b3175605a27d9f847017a796e334bd8b737c5f522508ef4" + }, + { + "kind": "file", + "path": "img_1361.jpg", + "sha256": "0c3588991de22ab269767bcd39b2bbd988be6b27dbfec8664ee148845c8ce2b2" + }, + { + "kind": "file", + "path": "img_395.jpg", + "sha256": "b377fb36e1fa9b145697c0e0444bcf6edd6bd474204026900344a8d9e07f227d" + }, + { + "kind": "file", + "path": "img_3204.jpg", + "sha256": "34548b9c5f2555dfc0fca8ab19d380d05a508e2b34a8c6f0fc884f250c297325" + }, + { + "kind": "file", + "path": "img_1413.jpg", + "sha256": "2ba6955b9628d164101ca60d5f08f5a79ba9b9aa88fbc9388056740791ac42b9" + }, + { + "kind": "file", + "path": "img_47.jpg", + "sha256": "34c2e7389e6a5323c441ca93562a42f7c8f1a6a31e10b9a6ad8eb9359b9064be" + }, + { + "kind": "file", + "path": "img_2132.jpg", + "sha256": "d8adf0646b9aecdeef4a34d465dda6d35b23219dce3e047593bd4ad495bf4e24" + }, + { + "kind": "file", + "path": "img_4543.jpg", + "sha256": "e9f9a74205d97d4ceb05bbf2241c9de899f596b98ea438e36d7289b627b7b8cb" + }, + { + "kind": "file", + "path": "img_4225.jpg", + "sha256": "010f4635b26a2eb1ea1d6fff8037313000941dae3f0eaa7eb74974b664942183" + }, + { + "kind": "file", + "path": "img_2654.jpg", + "sha256": "63bc616e06b390f36412556214fa0cb045dd042e485e35917bfae32519a0e167" + }, + { + "kind": "file", + "path": "img_4231.jpg", + "sha256": "bf1c2528fb85f525d20584e982825921ab5b4c274aa8fd92980fccf3a757c36e" + }, + { + "kind": "file", + "path": "img_2898.jpg", + "sha256": "36b9c5ed662c6ad7a86d3ace048687b436330ccb19778bdcfcd1c7180a966e81" + }, + { + "kind": "file", + "path": "img_53.jpg", + "sha256": "197bad9465c18c13ed194c60d011cb83de1e661d958c8afee47fb538da3fb481" + }, + { + "kind": "file", + "path": "img_3238.jpg", + "sha256": "4690e3935a2d6a65c8d06cf716a05386adade6fc9fdb7d6a1408628c5401ede2" + }, + { + "kind": "file", + "path": "img_4557.jpg", + "sha256": "f66cb86ffb3c146a044040caa70e1870330c00ec83b8adbbbafacb99fdab50a4" + }, + { + "kind": "file", + "path": "img_342.jpg", + "sha256": "148f16506a3e5e93e7b74bf3bc4e5bb29b5833bc40a5e2748a085b35b8c1f476" + }, + { + "kind": "file", + "path": "img_2867.jpg", + "sha256": "54a648bffc93d49984d60f4cbafe21b50a9c2113562dc5835e88f434cf478991" + }, + { + "kind": "file", + "path": "img_356.jpg", + "sha256": "4dd8abefecc7c660c529ba666b81d5cc8fbc855e8b599f49c8903cfc79d2e484" + }, + { + "kind": "file", + "path": "img_430.jpg", + "sha256": "0aeda30f0eccf4caa78885719c3bfb8d9fdaa2c37053f5b56e367609c13475b2" + }, + { + "kind": "file", + "path": "img_418.jpg", + "sha256": "2bbe6baaccfe383e0b52947e8232104eb9071fc48acfeacfe04b93df04c33b74" + }, + { + "kind": "file", + "path": "img_84.jpg", + "sha256": "1977540c6f5a2b0769c51a374955013649c58843c9db64b095b8846708535a25" + }, + { + "kind": "file", + "path": "img_2697.jpg", + "sha256": "9fb0217c628b11678b5f7f1ce32f568c939b763727c545b93d5028fa8fbb3bb9" + }, + { + "kind": "file", + "path": "img_3589.jpg", + "sha256": "60fe779ea71ee3a1337e2a011a726fc474c02a5d6c5e2e9503c01432dcffbaab" + }, + { + "kind": "file", + "path": "img_2683.jpg", + "sha256": "2385db8f63b55b0a119f27eb5307aa9357174eb52c31b512b4505941eeca33c1" + }, + { + "kind": "file", + "path": "img_90.jpg", + "sha256": "211b077c0a8813ae70bf11bf267d409b7c869fd329ed87c885e671c902de1a81" + }, + { + "kind": "file", + "path": "img_2695.jpg", + "sha256": "fa39eca7778dc99de6f71e0d45d7825d748338e0aa1d1389b087cd96c5c6c5a6" + }, + { + "kind": "file", + "path": "img_86.jpg", + "sha256": "eb052750244ee1d1d8479e5b3fb7095ed113e828689081b753347459c68ea39d" + }, + { + "kind": "file", + "path": "img_4582.jpg", + "sha256": "13ec84f5aaf8c03386c888c369975dd23e1b1e06f1b69d706664239f207ff179" + }, + { + "kind": "file", + "path": "img_92.jpg", + "sha256": "d4224cfdaa644797f0b9fb6fb70a3344fee95fe60aaa261e99aeeaac6c636e15" + }, + { + "kind": "file", + "path": "img_4596.jpg", + "sha256": "86b55c3fa3403c7d4b8b3d034ded91a6d0f12e0a07d273214532f66b33b871ba" + }, + { + "kind": "file", + "path": "img_368.jpg", + "sha256": "fa5c61ad5d705079c9735b509befc633354d1659da51b5dee224b919cc965708" + }, + { + "kind": "file", + "path": "img_2859.jpg", + "sha256": "82be39bb380081e38b6ecfa4aa313f805e9987990f5a1310bd0c0b6d5bd32d9d" + }, + { + "kind": "file", + "path": "img_2681.jpg", + "sha256": "1cdf35be59efd1a2e1108ff37711bb5ba02950d7dc4692b531bca62284e53ff2" + }, + { + "kind": "file", + "path": "img_1388.jpg", + "sha256": "c51634a235867697fc716a91a363bfd29f7d1016f7f8611f1ee55f04baa98b5b" + }, + { + "kind": "file", + "path": "img_340.jpg", + "sha256": "d59f0eb90886896a27f2f0444365720b41aeae0930c63245093251ef0b4fadb3" + }, + { + "kind": "file", + "path": "img_2871.jpg", + "sha256": "2b78bececa29ef769f991a357627c3d853dce9e842fcb539b7035df222b39dde" + }, + { + "kind": "file", + "path": "img_426.jpg", + "sha256": "17376735c0ed3c308548078a6fef07cb868b42299001d858c460625cbcf4e825" + }, + { + "kind": "file", + "path": "img_432.jpg", + "sha256": "260299524ac468eed71b4f79652a0ba80aeb847440552674bf90619c391919b6" + }, + { + "kind": "file", + "path": "img_3548.jpg", + "sha256": "7701bfef73392778c7dc880f413cde900d34d0aa7ddafbd7b8453a38c02dfcac" + }, + { + "kind": "file", + "path": "img_4227.jpg", + "sha256": "53240871cc94bef9bec163147a8421b6093da847d393fb3cce4248a742528598" + }, + { + "kind": "file", + "path": "img_4541.jpg", + "sha256": "2c885d6387474f32f139f121059012b24f8f4a4acdda558ea98fde0442a19355" + }, + { + "kind": "file", + "path": "img_2124.jpg", + "sha256": "44cea54ff497ee1cbb5d9b35d82f12c1b94f3ff55b84d4c5e48cedd829df7bf7" + }, + { + "kind": "file", + "path": "img_51.jpg", + "sha256": "60d3521ee7cd75b40f499b5e0302e6843639edebf26810e2326c25cbfe958241" + }, + { + "kind": "file", + "path": "img_2642.jpg", + "sha256": "a201a39c220bae95014fe3877e60fa47afbec5c18a9bc46a51e940daafe7c6bb" + }, + { + "kind": "file", + "path": "img_4233.jpg", + "sha256": "6f17654c5ece6062bdda17207e6adc7580f3ab550f362b3073045c06d925cae5" + }, + { + "kind": "file", + "path": "img_1363.jpg", + "sha256": "37a04ec3b641f971ac657ef7158bf6bbf5de6a0b9e364a41602fff24c28da5ea" + }, + { + "kind": "file", + "path": "img_3574.jpg", + "sha256": "5922eabc4e8b9da1ccb30a48c8914292083ca4bc117ac7af3776985fe40a0731" + }, + { + "kind": "file", + "path": "img_383.jpg", + "sha256": "1496e91c2776b938f2ab5a537e26ed610eb534012dae4bf429fe486979947c86" + }, + { + "kind": "file", + "path": "img_3212.jpg", + "sha256": "f0e42754e69f1afc979a2e7be441336150571cc1c6e9626b0fb33a608fbd370e" + }, + { + "kind": "file", + "path": "img_79.jpg", + "sha256": "4d7a7b0f9d2b0f3e8cf33d81a8370eebdd245351349b7086ebd9049963692b40" + }, + { + "kind": "file", + "path": "img_1405.jpg", + "sha256": "a3bb6d48e4a26594569661d4c1c9ff4a3df83cde3703d723cab665ab19058db5" + }, + { + "kind": "file", + "path": "img_1411.jpg", + "sha256": "9ad0f6850e63efae76eb9da626b696512f2ba489339c1832a97c98de65ca99d6" + }, + { + "kind": "file", + "path": "img_4569.jpg", + "sha256": "f00ad3d01fe8f841e5a3728ed747e4aa7cad8a76fb876f541fb5121042d6d4b0" + }, + { + "kind": "file", + "path": "img_3206.jpg", + "sha256": "d90f60258bade282a05fdbbce2088db57ca817a9222a1a747d3d21c0dbf6646c" + }, + { + "kind": "file", + "path": "img_2118.jpg", + "sha256": "7a5b26f6023f36967c4aea6b79766305d7b2557183a74d3a714e4d8e0c692a2c" + }, + { + "kind": "file", + "path": "img_3560.jpg", + "sha256": "6e7112acc499246272764eaa116d82c8f2e2d2cb5d4397a143234defc86f90ab" + }, + { + "kind": "file", + "path": "img_1377.jpg", + "sha256": "c555424ee1ffbd8d305e643853d51aeceb3f22eb635fc08f2b83323d044b09ff" + }, + { + "kind": "file", + "path": "img_1820.jpg", + "sha256": "5e21edad16a2ac651c32aa43f1e9d769e3c718912ffede4b98396a766387ea43" + }, + { + "kind": "file", + "path": "img_618.jpg", + "sha256": "57b59d3655982474b761821062343223dbc69bb2606fb698e1caa7e00fbf3649" + }, + { + "kind": "file", + "path": "img_4780.jpg", + "sha256": "98110aebb82edbc6ac13ca65036bdc71c3e56e99ee4a6005d577ae8a36966786" + }, + { + "kind": "file", + "path": "img_2497.jpg", + "sha256": "fa14d7325277802f1f98e3c7807a8e7665553407b115930e726ef1ab77fa4bed" + }, + { + "kind": "file", + "path": "img_3951.jpg", + "sha256": "8cbbe4db4250adcf5212e5df2148bfe588b4e0782be83365f839f2950d9ae77e" + }, + { + "kind": "file", + "path": "img_3789.jpg", + "sha256": "7c2ccd6f09a8b01bfa930f473bb0231918f3a505f27dec4b811d36047c6cdf5d" + }, + { + "kind": "file", + "path": "img_3945.jpg", + "sha256": "07101946c958139efd0847673164f8fe937e92fb2826e80d39e97c1534146984" + }, + { + "kind": "file", + "path": "img_4794.jpg", + "sha256": "a3a257b3e28f9cf12951f9d0aa64a216d565b88fb4ba97ff3fb10cd7e2f60512" + }, + { + "kind": "file", + "path": "img_1834.jpg", + "sha256": "691e39c11acde49411e7c7a255692269b1e8bf5e8ec1ffbab23c8568c3c6a65b" + }, + { + "kind": "file", + "path": "img_624.jpg", + "sha256": "6ece4f85e9496ef54970adb2d6020d2e5b6a629ba839c446dfa916e43d98a66e" + }, + { + "kind": "file", + "path": "img_142.jpg", + "sha256": "ad1cec5f990e5d99f51146d40ec5aa0ee6528977981735e4756c45786ef73a43" + }, + { + "kind": "file", + "path": "img_3979.jpg", + "sha256": "8c3073cac3b132596f48a726c02049f15fcdb11e29a1370f42761a7dfb079355" + }, + { + "kind": "file", + "path": "img_1808.jpg", + "sha256": "e604b6473b625291c4ae99c0c009b7a87af580302fed3fa3e7b2e9e76fb2a367" + }, + { + "kind": "file", + "path": "img_630.jpg", + "sha256": "9a459a9ecc028acedc7a394d76b51c85c1caef8494b28a1bfc38b0d7ac39d505" + }, + { + "kind": "file", + "path": "img_803.jpg", + "sha256": "c62d9d206d5e0d885baaf7fa7b36aab6f0c626706dbdfef7a77cba6174f25865" + }, + { + "kind": "file", + "path": "img_2332.jpg", + "sha256": "dadf894bb8acc0b749020e76eb3298834709ed4c73fb49995772d7d840f7a90a" + }, + { + "kind": "file", + "path": "img_4025.jpg", + "sha256": "678ce760c9901cea3a5ec1b045773b1d7e8e8ef1248edbb8ecabfd3103300fbf" + }, + { + "kind": "file", + "path": "img_2454.jpg", + "sha256": "40b2e4f77ec9c0f46200c86f084c7ebecd7deec99cbfc6824cea22a0639ffae8" + }, + { + "kind": "file", + "path": "img_3992.jpg", + "sha256": "254a6c2c90299c7af1896fa2ff5f0b5144ab369dd42f3511d2999574bad971fd" + }, + { + "kind": "file", + "path": "img_4031.jpg", + "sha256": "dcb0cfb1cd72aa50e417ccbf6c003b2e77764dc36350ada9edfc3e32b9bafecb" + }, + { + "kind": "file", + "path": "img_2440.jpg", + "sha256": "884e3a2da2d94d92ac4261b1e1c1e36b75c9d203dd13a37f7f88c81845aeeef6" + }, + { + "kind": "file", + "path": "img_3986.jpg", + "sha256": "b7a889dfdc6ca8e95feb23b3fe1cf200feab4b950efb19e33aef1d38fe976c0e" + }, + { + "kind": "file", + "path": "img_1149.jpg", + "sha256": "7b8ea93368be410fab8f05afb04db2f5783cf42a14f3c82df18a397d34f1c0dd" + }, + { + "kind": "file", + "path": "img_817.jpg", + "sha256": "4b738b20a7a1235d510b2f6b35d06bd90cf41977e8e41382430ae40e7c5719e5" + }, + { + "kind": "file", + "path": "img_3038.jpg", + "sha256": "c49bab3db578532a2d8bfbe1c2e055fd7b3f40b83b3fb991c4360bff726f69cf" + }, + { + "kind": "file", + "path": "img_4757.jpg", + "sha256": "dcf75d87e712eebe815b580d14c2d361bbb24aa528cd03ac0e15281d9710b8f8" + }, + { + "kind": "file", + "path": "img_1607.jpg", + "sha256": "d7d5f82d0d931b13c28e1c498fcba392b6196ffee093184c25923f0d82f20440" + }, + { + "kind": "file", + "path": "img_3010.jpg", + "sha256": "d030c30e638153cd6710d33b003f980871e0ab088273e4cb70d5b422aa9f8d6f" + }, + { + "kind": "file", + "path": "img_4019.jpg", + "sha256": "16632d6c1d56106af5b6232ef3cd3bdc31aca4b34a686036e7dae4250eaa48e9" + }, + { + "kind": "file", + "path": "img_181.jpg", + "sha256": "c2f7d12cb4185e762f28dfdeab276a52ecbf13f3198032a6d373495e1b5fb188" + }, + { + "kind": "file", + "path": "img_3776.jpg", + "sha256": "135c9e47e856e93ef8b6d854a63d1121309cf3394d00a3980b7606c364d06ede" + }, + { + "kind": "file", + "path": "img_1161.jpg", + "sha256": "2a9469a10580d35117ea38bfc740cc4ad52e5a509ee4f9d8c5de694fc2b0d1ee" + }, + { + "kind": "file", + "path": "img_1175.jpg", + "sha256": "f14600a5b0a951d001b88a76b451c67ebfa8f66c0cbfceb7c361ffa6d6f22ffa" + }, + { + "kind": "file", + "path": "img_195.jpg", + "sha256": "8aea520a0b83812dc524ccd8281ba617dd0a4deac41fb1cf72f4f4b200410756" + }, + { + "kind": "file", + "path": "img_3762.jpg", + "sha256": "e1a6dc2a1ce83f666ddeedf87d57f93b514ca9db1b8ea674f1b4ea803ddfe8f2" + }, + { + "kind": "file", + "path": "img_3004.jpg", + "sha256": "56269018815c4724491bf8ab34d5bce3d7f0e5d4828c7cf176f8c16e920763b7" + }, + { + "kind": "file", + "path": "img_1613.jpg", + "sha256": "ddca625f22374b0f980805c2c6e48c60bde36047c0f6973c4bd24d4c926f1ff3" + }, + { + "kind": "file", + "path": "img_1954.jpg", + "sha256": "4e857c824e0459048a9dff3c009072785caf79a97e1cafef445512e2c86f5cd3" + }, + { + "kind": "file", + "path": "img_2285.jpg", + "sha256": "0c14bc5f9ddaf0b0f58ca88808b2ce749065aa9d7c7e2ce002c113d6ed90cf9c" + }, + { + "kind": "file", + "path": "img_4192.jpg", + "sha256": "44f2c456e4d9e68660eed59f7cdd6237e4bb59cd644ec295bd504a9399571983" + }, + { + "kind": "file", + "path": "img_4186.jpg", + "sha256": "ae0a82311f16b2a9b53e8879df183ee836f5617e85ec28bad59fff76d7ba39d7" + }, + { + "kind": "file", + "path": "img_3831.jpg", + "sha256": "324cfda1f83883b8cc8608f6536a2a3eeab465d684d311a617c0f8883826c0af" + }, + { + "kind": "file", + "path": "img_4838.jpg", + "sha256": "9c1fbf192177c878c1b2195d5126530daf815dbd8391754b8faac360ed50f9ac" + }, + { + "kind": "file", + "path": "img_778.jpg", + "sha256": "e1c98462ebf92fb1f9a78ad3baf63f804c77107bcfd0422f1e7d6b721bb54d9e" + }, + { + "kind": "file", + "path": "img_1798.jpg", + "sha256": "9f2a8ccc27766c72e691d77baf3bb8e72a7523e0710da0bde9d498b826874f13" + }, + { + "kind": "file", + "path": "img_4810.jpg", + "sha256": "5dd059913b4a13c0921deb4a4de57a2ab19d0574d79490bb91dcc43f018661e9" + }, + { + "kind": "file", + "path": "img_988.jpg", + "sha256": "a7f94f9451133a1b62542b93e3eb88aa9a3458a472b0ad1fc73c31d71d08e892" + }, + { + "kind": "file", + "path": "img_750.jpg", + "sha256": "13479b899780d5a45ac5fc78171f466f6a94533a3da6c416d03d592c8025eba5" + }, + { + "kind": "file", + "path": "img_1968.jpg", + "sha256": "f3ff7a50a8caa5c184df651b27f10ca1e52ddf48c4318b98bd90adf1aac17bec" + }, + { + "kind": "file", + "path": "img_3819.jpg", + "sha256": "7978efe46d84be7458d93745e547b80a10e900082af5f22a5fb5ff4bb9362937" + }, + { + "kind": "file", + "path": "img_4804.jpg", + "sha256": "7f75800bf5fbe89c91bbdddb6da2b06bf4e12e9eb18e4c8357da2c3ce39a00c4" + }, + { + "kind": "file", + "path": "img_744.jpg", + "sha256": "23c7d69d909ce3883b5e47d5cddfc6859baeb8356047f26a7d6a2ecf3a63c2d1" + }, + { + "kind": "file", + "path": "img_4637.jpg", + "sha256": "e1a624022f76b36db13b012dc8735b34fd6611353458fa16a881e4efebeeaead" + }, + { + "kind": "file", + "path": "img_3158.jpg", + "sha256": "65fa615ba738fef74563e2822545ee2e4d9ee8b0e52284fdb4c76dc1363484b6" + }, + { + "kind": "file", + "path": "img_1997.jpg", + "sha256": "9a66f9424bca29f4fa7387debb236da2824010ef52b0a44a04ed2f1622f1f1af" + }, + { + "kind": "file", + "path": "img_2520.jpg", + "sha256": "ed4e1100cedab3db68fe6c6c41cdea029e5fc6554028f7298d9e88cc53424289" + }, + { + "kind": "file", + "path": "img_4145.jpg", + "sha256": "5b9677d6c359f2b876437ac9e8752e27d0dfc4acdae3eb7a8c754871e906e88d" + }, + { + "kind": "file", + "path": "img_1983.jpg", + "sha256": "d6f2521a7fa25ccaa3f919ed0c8a9e0714cabc92bda234cfa2965cab97a16195" + }, + { + "kind": "file", + "path": "img_2252.jpg", + "sha256": "9cc475ab7cfcfedf4e4a51ac210469f1a99d44a3a2a9dfe949eeab9196cc16ea" + }, + { + "kind": "file", + "path": "img_963.jpg", + "sha256": "8f0a5c45cc829e8481126163fcab046035393db60392a6b69d7c3078b23b3789" + }, + { + "kind": "file", + "path": "img_1773.jpg", + "sha256": "5928168f8eafb1626cdd6734fdd3dbc3ff1d6987a24bc22a681f58b55c9e8613" + }, + { + "kind": "file", + "path": "img_793.jpg", + "sha256": "916a417e6b379aaf63117cca8bfac0ff0eb14641d4b8e6b3bfca4055832b4b00" + }, + { + "kind": "file", + "path": "img_3164.jpg", + "sha256": "8eb68c5a49c174d112ab8159cd7d733352800fcc5bd98fcb754a458738ed66c5" + }, + { + "kind": "file", + "path": "img_3602.jpg", + "sha256": "18040ea2d379670fe05f155bc087184d073b988b9b5e86659ae394dcd227dc68" + }, + { + "kind": "file", + "path": "img_1001.jpg", + "sha256": "8e85704ddfb107d21463a3030aef7b510705aad1ea4db895c9e5c7b1aa474c9c" + }, + { + "kind": "file", + "path": "img_2508.jpg", + "sha256": "26620f1aa2fb84b40b8cf18f8cf0a0d2e5d7c7130615fac358a70d71e6a5d779" + }, + { + "kind": "file", + "path": "img_3616.jpg", + "sha256": "e5cc846043cce0af0d84d2f0b4562fb8d6aa699adc3d050769c33e4f68b9e9cf" + }, + { + "kind": "file", + "path": "img_4179.jpg", + "sha256": "db9031f9e5f0c8469b94546bb42f2b8b340fa553c11dc9375e01a478d57f8c5a" + }, + { + "kind": "file", + "path": "img_787.jpg", + "sha256": "239d2975c3077191cc178ca4348f68cca07b1593091d31ecbe541ac4cacb753c" + }, + { + "kind": "file", + "path": "img_3170.jpg", + "sha256": "8ea4e01592ffa47a7f5b51af5c65ec70a409abe30d72f350b41419e8f10085a3" + }, + { + "kind": "file", + "path": "img_2939.jpg", + "sha256": "434fe292440b782f7cd2460aa8eb63ca24a29c581bb1b6e07f638a813f4e06b6" + }, + { + "kind": "file", + "path": "img_208.jpg", + "sha256": "325bea523dcbc204d20c57c07e99c79c7bdc5d5c3a7baeca8e9943d6192bdbac" + }, + { + "kind": "file", + "path": "img_3399.jpg", + "sha256": "f98bea9ef189a6583fdda678f7aae7edfe1f205c2be83b1d10750f5bf911fb2d" + }, + { + "kind": "file", + "path": "img_2087.jpg", + "sha256": "7c1aca6cfdea4d2cd33b8f7ea689561ddf5d1870c9962f392af89b5a84542ced" + }, + { + "kind": "file", + "path": "img_4384.jpg", + "sha256": "09c2cf49a2e39e7124ec13b25931dfaa25f0eb4eb15cfa552dddff78bef5d6a4" + }, + { + "kind": "file", + "path": "img_234.jpg", + "sha256": "e16a087656e77d00ee6ecf268deb53c24746716fbf7c12f3453de869e1f839f0" + }, + { + "kind": "file", + "path": "img_552.jpg", + "sha256": "d55a9a12bbb75721e9786e14d67c13230c8617f6f0f551326345c6a4e0c85aa9" + }, + { + "kind": "file", + "path": "img_546.jpg", + "sha256": "70efaa3662c638e608a08f1a469eefa6f66fb0fecb4281beda19b939931f563c" + }, + { + "kind": "file", + "path": "img_2911.jpg", + "sha256": "49702103a1dadf3eb3b42c7ed75b411e26cb856ad520d06dd7c3768e5c92ea55" + }, + { + "kind": "file", + "path": "img_2722.jpg", + "sha256": "6bd70205df0fbbef4469eade2bbc843dd373f7c03a2ddeab29fbf49fa929fa6c" + }, + { + "kind": "file", + "path": "img_2044.jpg", + "sha256": "8efc354d5d8e19873572aa7344e861a8702efe2ee48a4c9cff0c146cb6590ffc" + }, + { + "kind": "file", + "path": "img_4435.jpg", + "sha256": "9165fe36ee902f5d409f8712985ffbbac5de12e664e73a2c43c8a3205f93ac9d" + }, + { + "kind": "file", + "path": "img_2050.jpg", + "sha256": "889d89c1b67ad770025ccc43dbf55df356bedc92cf3cff827c8bc04924c3dd54" + }, + { + "kind": "file", + "path": "img_1559.jpg", + "sha256": "210d5d60df4ad42925d81c650dc2ca265c646efb77e5cdebd96caff3293ba2b3" + }, + { + "kind": "file", + "path": "img_4347.jpg", + "sha256": "ed1c2e7cba1297f9be1583885aeb9ba1940ac51562af7a87ab8f03bdce0a0d2b" + }, + { + "kind": "file", + "path": "img_3428.jpg", + "sha256": "b5ca315369ca775ab3332ed886658991fbaaec8ac8720ec3534f1c1f265d9b91" + }, + { + "kind": "file", + "path": "img_1217.jpg", + "sha256": "8b945132ddd560070abc328c2a034dd234f854af5227cec8a305bbe3ac8b9ba7" + }, + { + "kind": "file", + "path": "img_3400.jpg", + "sha256": "6a6b1db471b5e366fd4461134b0b79f93107edbbfba9d423351c9bdb48be2540" + }, + { + "kind": "file", + "path": "img_2078.jpg", + "sha256": "87f1f756b2593e84c57b23dd27a2e0771259f2866c30de9a956fbf1246de7f1d" + }, + { + "kind": "file", + "path": "img_3366.jpg", + "sha256": "69e76a787ed79d2873f97fb9e1fa5d9fac2fb9f4a4b2b4e9c3089b9fc43814c0" + }, + { + "kind": "file", + "path": "img_591.jpg", + "sha256": "14776fe725c29d78a73f47323c9c686b3b4a9bb0c982d80d21039792679cbd3b" + }, + { + "kind": "file", + "path": "img_4409.jpg", + "sha256": "61614b524cb71cbd1065e12753173e5c54b44dcdcb72bed940065f0c5972192c" + }, + { + "kind": "file", + "path": "img_1571.jpg", + "sha256": "2a5dfeeba148a8fd3a092d8bd62260ebc2b022b4379a6f1b33db2e4bc9e66747" + }, + { + "kind": "file", + "path": "img_1565.jpg", + "sha256": "7da6abc416bc0dce295f0636ca2539b24bbfcd5ab13abd14f133b6c62f5b9ba4" + }, + { + "kind": "file", + "path": "img_3372.jpg", + "sha256": "a213a552b249fc868937bd658f7796d63264441bcdc5ce9fc89f06df361c2b3d" + }, + { + "kind": "file", + "path": "img_585.jpg", + "sha256": "fafe5a8dd234d2a94ec488fdbd3d89f74d3e4f53142eccacf6556f5b11778ec7" + }, + { + "kind": "file", + "path": "img_3414.jpg", + "sha256": "5222b26914d8a937f8499debf86fa5e4f4cbbc637d1d982e2a776439e0d3cb53" + }, + { + "kind": "file", + "path": "img_1203.jpg", + "sha256": "3bfb613d48036c25424660f0576b4f0bf7a07c45bb93334e3ed7c2a5bdb5f8df" + }, + { + "kind": "file", + "path": "img_584.jpg", + "sha256": "8126b7a9c26e2bb3c133e26a6a3420826c33210aeb71c7012c23ca2f5b378afe" + }, + { + "kind": "file", + "path": "img_3373.jpg", + "sha256": "128fb00caea8f5eaea975d6266ba6b3deef8a2e2be7ad06cc30b0c374274766c" + }, + { + "kind": "file", + "path": "img_3415.jpg", + "sha256": "19d64f7bedc2574af2624713e516d71937611ee06e3afda01e293cbbf03f644a" + }, + { + "kind": "file", + "path": "img_3401.jpg", + "sha256": "8f757de57627506f8949b664242f69fdfe1e3ffed6f7e222970a6a44a434fc64" + }, + { + "kind": "file", + "path": "img_1216.jpg", + "sha256": "9f8236bab7c9afceaa198cbc7b4bb5aa4422e0aa71c4d4d04c967caf24113b28" + }, + { + "kind": "file", + "path": "img_1570.jpg", + "sha256": "37b5ca2f9d138278c293bffeda3e07327bd81b50fb49170bb5aac199321d309c" + }, + { + "kind": "file", + "path": "img_4408.jpg", + "sha256": "5743bcf5bf1cba9b6416a7b9bc8505f03761bf0cc5f0629f5fc4daf9251c8091" + }, + { + "kind": "file", + "path": "img_590.jpg", + "sha256": "d85ec8cb8f4202763578c2709d6a7fb6c101ea9ba61883744e53b9d5c33a559c" + }, + { + "kind": "file", + "path": "img_3367.jpg", + "sha256": "b86d7fb29bffc66db4bc2d5dc900a97107b85ca5772a996e202cc3d36d0e685a" + }, + { + "kind": "file", + "path": "img_2079.jpg", + "sha256": "eb35859653fd348359bea05b4049271af4b83505b59f7b7ad1ae7535899d11d5" + }, + { + "kind": "file", + "path": "img_1558.jpg", + "sha256": "631d9130cafcad2babc58b669851178f2fe183795290b151101bd20d3ff9f5cb" + }, + { + "kind": "file", + "path": "img_4420.jpg", + "sha256": "3c01c083d2e31a0d34aa97daa0154a3c4110d040dfb99fc109096a9cee97f068" + }, + { + "kind": "file", + "path": "img_2051.jpg", + "sha256": "f21d9c13f9fa659b6758fd000023cac13fc405c6e0163cf3642239cf39a4a61c" + }, + { + "kind": "file", + "path": "img_3429.jpg", + "sha256": "f68e8ff08334af4cfd440f5f2055832864787626543364df1d5cb6ef891fa039" + }, + { + "kind": "file", + "path": "img_2723.jpg", + "sha256": "f236d16fd54bfb1c27a0ff1704c57d62d729eafc231c979d890cd10a27781abc" + }, + { + "kind": "file", + "path": "img_4352.jpg", + "sha256": "6d83f133171303cda7188d2b0c548250ad07f68f24bb35d18fe0eae8da89c1f1" + }, + { + "kind": "file", + "path": "img_4434.jpg", + "sha256": "90f2210b73557d8515af99081879e9a3b2a911ee987ac12322e6ddb9a5d1e804" + }, + { + "kind": "file", + "path": "img_2045.jpg", + "sha256": "6b843e38ab36099a1c3e9ab76b4c6dc88903a008c2dd60024b3730973db59f57" + }, + { + "kind": "file", + "path": "img_221.jpg", + "sha256": "27a584cd5784cba2a8c6a0835128d1106a744a18d04d2acfe121173dfc067cf4" + }, + { + "kind": "file", + "path": "img_235.jpg", + "sha256": "137f048c2e22c16677bc9f5202fe7c1d6ec17826f6aef41998603a529ca2fbfc" + }, + { + "kind": "file", + "path": "img_2904.jpg", + "sha256": "e837eb0d76d77d2d545122b4d7676e054a2524aaca46cc3799559cf78a36dd50" + }, + { + "kind": "file", + "path": "img_553.jpg", + "sha256": "604ee2dff72ada606a68065d9cfa5f03c8c8cad1a0c58fe794dbfc446216030e" + }, + { + "kind": "file", + "path": "img_2092.jpg", + "sha256": "1186ac9937fcf702e482324651ca133412a7e0afc05610e4b79e8f24e04c3c9e" + }, + { + "kind": "file", + "path": "img_209.jpg", + "sha256": "19b6b4bdff2845ed79ea7e062c8791c1c89bfa377ef43fc350858b72873d5c2f" + }, + { + "kind": "file", + "path": "img_2938.jpg", + "sha256": "dc40a7f3381e8391c9f62e2fdcc6e3dbd43cc63747551c2fd84bcfa1505e8f7d" + }, + { + "kind": "file", + "path": "img_2086.jpg", + "sha256": "6c1c35dd29a7c4ee45f3c95682084f282d708a662017b385a4d4ad6d2764edfb" + }, + { + "kind": "file", + "path": "img_3398.jpg", + "sha256": "078616394dba2aece5ad0f84fc75d84a318b152358d21ade88bd2daf13cfa8a2" + }, + { + "kind": "file", + "path": "img_4178.jpg", + "sha256": "4782175cc4993501d1e533ea86c6a81da3f1da2bf25a474508c2cb75a5a5f426" + }, + { + "kind": "file", + "path": "img_1766.jpg", + "sha256": "27e8ddec3bdb38a71b2d6af917e63897c1a3fbe231b1a0219c005f4b4ed4f262" + }, + { + "kind": "file", + "path": "img_3171.jpg", + "sha256": "f4da3eb6d3886327a98720d500b068bfbcd8598e4ea6c83e2b9b02c8ca330708" + }, + { + "kind": "file", + "path": "img_786.jpg", + "sha256": "7ffa102ab58491de6cd5bcdb8a3f96f6786daab7b6519facaa133bb435049225" + }, + { + "kind": "file", + "path": "img_3165.jpg", + "sha256": "ed155beeb63e6253270bcdc57e5f2fbf4f005bb96fe14567e164309484f7514a" + }, + { + "kind": "file", + "path": "img_1772.jpg", + "sha256": "79cd9ef1a1c80347ae7b331c757780c51dcdb579ac208fae9f0e1e2f4ea276b5" + }, + { + "kind": "file", + "path": "img_1014.jpg", + "sha256": "c863056b2eccc44d335a4f74ec4e54317c1103a7e05405ba6b52669415a1837c" + }, + { + "kind": "file", + "path": "img_3603.jpg", + "sha256": "f90fd5f600c80c322d6bc96055876212fd7711da23de1cde0ba78a7d2ecb9231" + }, + { + "kind": "file", + "path": "img_4144.jpg", + "sha256": "83bce8515cc2727128707ec399c6666fadfb32b6c1df3fda1b9e38cce1ae501a" + }, + { + "kind": "file", + "path": "img_2535.jpg", + "sha256": "8d67285c33150af6edb6d6207432746199d5c0050c5b2863d62ac612f7512f76" + }, + { + "kind": "file", + "path": "img_962.jpg", + "sha256": "7614e63d2fde87e2364341fac493dde1c6c8b808f875a0d464ff8ec2083e98f4" + }, + { + "kind": "file", + "path": "img_2253.jpg", + "sha256": "57d6076d462c4d8158d3bf2205a4dc061978cef62c6656bb3bb6d571da35215b" + }, + { + "kind": "file", + "path": "img_4622.jpg", + "sha256": "9673e7af41d5990b382427f0fbea1d6f617048088fd8a4efc0125fc4af3f84dc" + }, + { + "kind": "file", + "path": "img_1982.jpg", + "sha256": "df06d25c3ce5b03d971953a70afce101869c84c2bb69e7e9f227e24a5e042dde" + }, + { + "kind": "file", + "path": "img_1996.jpg", + "sha256": "7baf6c94e8a57c3c69cdfda313c1b9432a3cbdeba5aeda46ef90b1933936b3af" + }, + { + "kind": "file", + "path": "img_976.jpg", + "sha256": "31585bcb639cd83876f6676658027641749ddb56cd33e025b682cf700eccd5a2" + }, + { + "kind": "file", + "path": "img_2247.jpg", + "sha256": "209aedff189121f9de2ed5e7433405d22e882c1531a4c02a3f8a3eab13bb8ade" + }, + { + "kind": "file", + "path": "img_3159.jpg", + "sha256": "e63d1d7e4710736b952b7f0b023a8968cbbc8dede4f36608abc0600d675ef809" + }, + { + "kind": "file", + "path": "img_4636.jpg", + "sha256": "ca164492296025526c4e63f2c6f3ecb4dda07b4a3560f9955660ac44327f08cd" + }, + { + "kind": "file", + "path": "img_4150.jpg", + "sha256": "a8b711ff5787fd2055719dfe750944b87493c36af70a8cbf6c69b1ab82dd3d14" + }, + { + "kind": "file", + "path": "img_2521.jpg", + "sha256": "440bd3351173165f61d566a2c8013dd737a41e77c0cc4a1974f113f63a68440f" + }, + { + "kind": "file", + "path": "img_745.jpg", + "sha256": "67483305510143d2e5ce045d722916ec4d5be533daf94451db1f3c521a2dd917" + }, + { + "kind": "file", + "path": "img_4805.jpg", + "sha256": "25f39a57c8f070540c9d33d3d2d3b3e96597509642e5c0fd8fef97394c7f9d48" + }, + { + "kind": "file", + "path": "img_1969.jpg", + "sha256": "f205cfabd9b1fef185c6569032b7c873c74b1bac8021452ce116e9427ddcf35f" + }, + { + "kind": "file", + "path": "img_751.jpg", + "sha256": "3f3d51fb694b4161563a4a43d2bc9f3798a1b10e58066ba7c2bc0ca54b76a580" + }, + { + "kind": "file", + "path": "img_989.jpg", + "sha256": "12469c17e1ddd345c957ac7a811ae8384ec9ea33e0a13a257f73308faee9f171" + }, + { + "kind": "file", + "path": "img_4811.jpg", + "sha256": "789393c5fb94a3c97e138712f31b2728c5bf399268fd37e0b292b37bf3a88e9a" + }, + { + "kind": "file", + "path": "img_3818.jpg", + "sha256": "e244abf3a705fe735c70b67669bc803a56953e808419a2cb810c5ae83e089e3d" + }, + { + "kind": "file", + "path": "img_3830.jpg", + "sha256": "eda7e2b4d3d859635d571a06d9123237b6bdd0427a9640719e111bcd468e0875" + }, + { + "kind": "file", + "path": "img_4187.jpg", + "sha256": "ab39892cf1d5d8887fdbed75504999dde6f5df1b8956519c01c9cdc2b662ee84" + }, + { + "kind": "file", + "path": "img_1799.jpg", + "sha256": "09401bdee1d17cec4f1d1dca2299c358359c6d3a3fb0807c5b1995fc09645918" + }, + { + "kind": "file", + "path": "img_1941.jpg", + "sha256": "f964c3211bcae45863602ef0488459c460e2fad419eecc240dbdd8cac4d6a574" + }, + { + "kind": "file", + "path": "img_779.jpg", + "sha256": "6a4ff1082cbc764c3d8abb17375772511c24b09a19ae950864ad6fca902d6c54" + }, + { + "kind": "file", + "path": "img_4839.jpg", + "sha256": "2d14a35ac137a2bd24ac285b8212b5f722c97a11f082d085f51457e4d8e24e87" + }, + { + "kind": "file", + "path": "img_2290.jpg", + "sha256": "7f70c79d12acf3ce4d3b2e4445ff6a4d52a14227b091b4a3433412c9491c2847" + }, + { + "kind": "file", + "path": "img_1955.jpg", + "sha256": "d2376fdb245e607110998f1edce6b68265a22fbdf8a8a22084a0d2543f08bfb6" + }, + { + "kind": "file", + "path": "img_3824.jpg", + "sha256": "67183b49982bc1b237b7c024b81a643274afa58c7b1c204163f915086db63a93" + }, + { + "kind": "file", + "path": "img_4193.jpg", + "sha256": "434a3ead294e72b017e4475fa605c7342451f1ff77ceb49fb8dafb55d0ba5e84" + }, + { + "kind": "file", + "path": "img_3763.jpg", + "sha256": "e817ab022fd081c7ed9e73dafde6f4b123294f390d14f0f2fdf7e61279e61a6a" + }, + { + "kind": "file", + "path": "img_3005.jpg", + "sha256": "77209057419ec8dfe3f165ecd8f9c75eb321a01fbd58db0ec66757d24048fcba" + }, + { + "kind": "file", + "path": "img_1160.jpg", + "sha256": "a1e91ebba062d7dce922b89407949ff34927a011c5633672c6a68eb0abf73888" + }, + { + "kind": "file", + "path": "img_2469.jpg", + "sha256": "9c0faaed755ad4a677adb1fcf95c27210b9b026edcff576bd42bde7bed85f2f0" + }, + { + "kind": "file", + "path": "img_3777.jpg", + "sha256": "f68968ed6380376b1221c934c367af4904b9507023e8b2f254c99f391a8bac87" + }, + { + "kind": "file", + "path": "img_180.jpg", + "sha256": "1b73ac6eee85ac5dccd95bad6a77e7563fbabbcb9b2dc6bf8c8f9eed64549558" + }, + { + "kind": "file", + "path": "img_4018.jpg", + "sha256": "91a0363999d95b0d20bebe2e757e492514058b5aa59a39d24f48b7a8574c0cba" + }, + { + "kind": "file", + "path": "img_1148.jpg", + "sha256": "423e246148029e01d4699f440e0818e4bdf1c6572e48b5a2bc20e3b6809d78f9" + }, + { + "kind": "file", + "path": "img_4756.jpg", + "sha256": "c22b084cdfd87e3761de4ebf32a9b694f2778b19e8e11712a8551737eb68b2b6" + }, + { + "kind": "file", + "path": "img_3039.jpg", + "sha256": "b9289ea7ca74b93f62c25db7fd91966e8e057d0dd0e1fd7ab5a5f2b1edec616b" + }, + { + "kind": "file", + "path": "img_816.jpg", + "sha256": "598fa2bf484c3ffb04d20dee3fddb64be9d29538a4291f46def0c32de4e1f920" + }, + { + "kind": "file", + "path": "img_4742.jpg", + "sha256": "5a04ab22a70fbea524ba83d1be7382af850becc8bdaca59ac1e02930f38974fd" + }, + { + "kind": "file", + "path": "img_2333.jpg", + "sha256": "af4c58c6e8a4df1086829689daa6b9396cc863868476c69c6f62503216e27892" + }, + { + "kind": "file", + "path": "img_3993.jpg", + "sha256": "fe42f1cb0e6ee67d38b2c0bf34d6836333bce6992979654c1ac88a905019de4c" + }, + { + "kind": "file", + "path": "img_2455.jpg", + "sha256": "d949a8998cb88504bb648cdf198e4e51a16c07cfe1d8f3fea3e283c0f599ab53" + }, + { + "kind": "file", + "path": "img_4024.jpg", + "sha256": "447d95f32a50d1f7e7fc00af80e48de88b535cc9c28684d3298ad4a81efbe457" + }, + { + "kind": "file", + "path": "img_157.jpg", + "sha256": "fb0511c019377d1b5f7a5e2f43453503d6ea872624bd4d622a8083628db4bcff" + }, + { + "kind": "file", + "path": "img_631.jpg", + "sha256": "4b4a80ddf1805b9bf8b1ea24407dff2c74fb9b439cd3779dd6a606647f183722" + }, + { + "kind": "file", + "path": "img_1809.jpg", + "sha256": "a61217fd7d2a2249eb98c349231382c80c31f61fc4a799f4ee7efb0ad3e411d2" + }, + { + "kind": "file", + "path": "img_625.jpg", + "sha256": "30bb22cd0fa914025f082a02ee76d05cc277b8e93a2eafbfa1ef1ad28306b191" + }, + { + "kind": "file", + "path": "img_143.jpg", + "sha256": "a53b67ee2b302dbd9c6b38543a40edcc141d5eac9f7f4e0cae0beede780b3e30" + }, + { + "kind": "file", + "path": "img_3944.jpg", + "sha256": "1a2b0e2cffbdbefd8f78ea75884349edbdcbaeba23e8d47d2c9459600452592e" + }, + { + "kind": "file", + "path": "img_2482.jpg", + "sha256": "4226dba7a4fc3c04662269ee16d7708ce9a7b7d07f18edb6c9b3dde47f93a171" + }, + { + "kind": "file", + "path": "img_1835.jpg", + "sha256": "ffac9ef24662d991713cd6121c7fef95c9d43cc40dd3481b0f1f2560abc67391" + }, + { + "kind": "file", + "path": "img_4795.jpg", + "sha256": "45ad460ba8654479fb64ab9869110350d68430068362b3d69a63dacf0255148b" + }, + { + "kind": "file", + "path": "img_4781.jpg", + "sha256": "2efe9e2b27b1228365c1076b66c53ae4238582a2dac3292736015f42896441c1" + }, + { + "kind": "file", + "path": "img_619.jpg", + "sha256": "1a43e7103b7385f653ce6910030ca60d32020b30be82dc228556467a2f03c2ae" + }, + { + "kind": "file", + "path": "img_1821.jpg", + "sha256": "6936dbd8936a75e5826499587d519e8b30dc1e8aae158de7f24ebd34584daa1d" + }, + { + "kind": "file", + "path": "img_3788.jpg", + "sha256": "17e0a8a5f3ecdaecbb2e1d52137a7b448fae0a0a6688a3b33fc9c80c9eebd340" + }, + { + "kind": "file", + "path": "img_3950.jpg", + "sha256": "ab43f24af775c7f073e9f00fe2a1f6409f2684f4cef76a78fa41f4fd8be93233" + }, + { + "kind": "file", + "path": "img_2496.jpg", + "sha256": "54817ba3505533d44ba77c8908339ad92e61364d6f3cfd18f0130f2e0030f1fe" + }, + { + "kind": "file", + "path": "img_2119.jpg", + "sha256": "0cfd5ebc4c9e31e9c43334155c698e88dde843969ca92af7c1804bf5e4d361fb" + }, + { + "kind": "file", + "path": "img_3207.jpg", + "sha256": "9608e0b3ac4aad3989b6e26fa554e37e93c7a19c6f28f360ccf25645524f5fb4" + }, + { + "kind": "file", + "path": "img_4568.jpg", + "sha256": "0d03e93b4b145602461075ea83bb398716d8dd03dff0836748380298e0de34a9" + }, + { + "kind": "file", + "path": "img_1410.jpg", + "sha256": "2a23b2eaf68d86d6026999b0d809bfc75fbaf93a064863114da3083050305336" + }, + { + "kind": "file", + "path": "img_1376.jpg", + "sha256": "81bcbc4cb5b86badd4e9a76a622fbda7d3522d8125fae2f94da99f5a044a2fd1" + }, + { + "kind": "file", + "path": "img_3561.jpg", + "sha256": "c14f93e7a1f36f789649164551bf571effb4e6ab152b46cb06d7df386fe37ca8" + }, + { + "kind": "file", + "path": "img_382.jpg", + "sha256": "1a23c7bc432f4677f02ec3887f5b7f3f5ce0c011cb4ed5338ca80c36642213c9" + }, + { + "kind": "file", + "path": "img_3575.jpg", + "sha256": "15414e7836f24707fc052824ed665fc2e09f0814a979c5540f624c2b389b0d41" + }, + { + "kind": "file", + "path": "img_1362.jpg", + "sha256": "b3b1320f7b46e23b5f3b4b82b793c85426c8f6132a822d07a67ef8f57136b15b" + }, + { + "kind": "file", + "path": "img_1404.jpg", + "sha256": "45be66fadaa75aba99c38a9ec11236f7f8cbc91508532cf8d5875a2939b18697" + }, + { + "kind": "file", + "path": "img_78.jpg", + "sha256": "47e0ef6a6219ac919615b1d1f22156657cd7494e322a38a1dc4d18abeae584d3" + }, + { + "kind": "file", + "path": "img_3213.jpg", + "sha256": "374a40f93806ebc986b79ccb26f7041c04cddd9fddf94500efc0b79d1098fbad" + }, + { + "kind": "file", + "path": "img_50.jpg", + "sha256": "aea246a2a22ad5f480b9db1ef1fad7457287a32e214147123591e943cd13e15c" + }, + { + "kind": "file", + "path": "img_4554.jpg", + "sha256": "4bf8e9407ce2a68029e88660308f08ccb57a0a1254afb2a4fd293a2a9ac84e8b" + }, + { + "kind": "file", + "path": "img_4232.jpg", + "sha256": "3f3cfe26f459652bf80da7bd14a33987995690d6786289b505744fec8b6dc3e9" + }, + { + "kind": "file", + "path": "img_4226.jpg", + "sha256": "2f46c28c5b918dcf1eadab362fa4999cb0bda5e1197b44a1bdb68269bd429886" + }, + { + "kind": "file", + "path": "img_3549.jpg", + "sha256": "77d8029f9d951e8cb56aa882c5317c75d36b371aa19513bc03809bd60059b078" + }, + { + "kind": "file", + "path": "img_2657.jpg", + "sha256": "d5d482d41ae777a2526c673d0f31e83aa24f42aae1058f0a6f247330f0f8a684" + }, + { + "kind": "file", + "path": "img_44.jpg", + "sha256": "cdb58aacbda68e2b1c69e89dd1cfb746512058bd032dabceb10154cca094b642" + }, + { + "kind": "file", + "path": "img_2131.jpg", + "sha256": "9cb8d3605de222a56ac8ec6aee889694028726f21f6ab5275179c51e357037f6" + }, + { + "kind": "file", + "path": "img_4540.jpg", + "sha256": "4a0ec943844dd726eccb91bcd4a6d03f69a729558ace97d8083c9d68b5ec3e3f" + }, + { + "kind": "file", + "path": "img_1438.jpg", + "sha256": "3611d719a521bd4a08fa48bedeebf9f1b659ae36ebe294bc023af2af48536eda" + }, + { + "kind": "file", + "path": "img_433.jpg", + "sha256": "3aa7edddb852bb71ff6bbcd4f4fc0848e3dd9be4ac4b264754ac35b68800230a" + }, + { + "kind": "file", + "path": "img_2864.jpg", + "sha256": "c2e777c049c389b5ee5e54ffa3af32681d99807ced225e71a1b56552e335402c" + }, + { + "kind": "file", + "path": "img_355.jpg", + "sha256": "bd401aaf9271b0ccead2ece1f5ea91c99074a631e29bbed30e27e65d91b45c3c" + }, + { + "kind": "file", + "path": "img_2870.jpg", + "sha256": "db20c2a30616f1ea2941a846cb24488ac603a7082568352010a108af21e4bf11" + }, + { + "kind": "file", + "path": "img_341.jpg", + "sha256": "f71674b000e59e668bc90a148427dfd35591e07d0f20e6c20f33686661397137" + }, + { + "kind": "file", + "path": "img_427.jpg", + "sha256": "9004ff03178ba822deeb82ed84e67304a2f8dfe6041e5bdebae747c88ce8c0cc" + }, + { + "kind": "file", + "path": "img_4597.jpg", + "sha256": "9df89bd972c0e8495ec3657d5e379c564c2f9fad4439891322bc85552f44d27d" + }, + { + "kind": "file", + "path": "img_93.jpg", + "sha256": "dd1ee752a28373977a5133224c982b5864979169e63ae0fe66d7c4bc4f55fa28" + }, + { + "kind": "file", + "path": "img_2680.jpg", + "sha256": "ccd43570107c4b86dcade3b053f63de4267054379f3fa7a38676ebaa86cbee3e" + }, + { + "kind": "file", + "path": "img_2858.jpg", + "sha256": "15031c75f0a04aff78be2937ec0a491ec77dec3a653a574c93098d8aadb356b2" + }, + { + "kind": "file", + "path": "img_369.jpg", + "sha256": "72b7766a4ce80459d8b2637e59a5302edfc1e625c616543fa2527633a42c0340" + }, + { + "kind": "file", + "path": "img_2694.jpg", + "sha256": "41891ec70f8efff28cd0623742f85bb0365824095a06f79aa80df997ca962953" + }, + { + "kind": "file", + "path": "img_4583.jpg", + "sha256": "2943dbf05cbb1e0be485671cb98192c9701787f5e01c28d33a7134ace1fb4065" + }, + { + "kind": "file", + "path": "img_2874.jpg", + "sha256": "5b31aaaab72976a931f368907fa8d7dac0c6b494054eb27846008d42a7db7c55" + }, + { + "kind": "file", + "path": "img_345.jpg", + "sha256": "9662ee992966e78159db1d36e2b94113e80d202ed6d4827bc27370f7f2afd80f" + }, + { + "kind": "file", + "path": "img_2860.jpg", + "sha256": "6f875d81dd441d9273cb5e7af1a90738b3dba6d41fe13e7b5a436b7e5ab0e9a2" + }, + { + "kind": "file", + "path": "img_437.jpg", + "sha256": "22484488ed361d0b188979e6e0b0edf25a6208a6ed32c6e1c6d1ccf6a9ce5e73" + }, + { + "kind": "file", + "path": "img_83.jpg", + "sha256": "fa57fd3126e92711108937783002af7b3e1f185576b6cae1c62a1363b46115f6" + }, + { + "kind": "file", + "path": "img_4587.jpg", + "sha256": "cba4b6adf72e0a33b2c5366de6fe5f239647c8d3bbb7f6ab3c390a90ec3dd3a5" + }, + { + "kind": "file", + "path": "img_2848.jpg", + "sha256": "dada0160fd22e972cb462b032d81fe349d9ad6bf9be4afe7f2e36c41145ec695" + }, + { + "kind": "file", + "path": "img_379.jpg", + "sha256": "15281d8770e5a78116b8f50ccff8477f9a190075bc39c2b9da29116fca998267" + }, + { + "kind": "file", + "path": "img_97.jpg", + "sha256": "d38d4624431f713ed2baa59c3d6c1ed235db5621434dba63622653a69efd85a3" + }, + { + "kind": "file", + "path": "img_4593.jpg", + "sha256": "44061449fe6aadd820784c7833adc5f886791dba3e1049edce201d3313e0bb03" + }, + { + "kind": "file", + "path": "img_3217.jpg", + "sha256": "c6b4ddeb95dd3db0eba7d6b5f9f4863d8a6b61e15a351cb3166877611945dd0e" + }, + { + "kind": "file", + "path": "img_1400.jpg", + "sha256": "a3ee00d1a7e85d88f414bb88c485abc0bd65c2df84d8621ff74bc051d0410458" + }, + { + "kind": "file", + "path": "img_3571.jpg", + "sha256": "7d89d4253541169d8bcca618af233cf59368680ee94d40ce97ee491ca434679a" + }, + { + "kind": "file", + "path": "img_386.jpg", + "sha256": "8b33425bac4cfb776b9a46c07403cdfaa0681614c9d42ae33369dbd9ddb505a1" + }, + { + "kind": "file", + "path": "img_3565.jpg", + "sha256": "1bd0febdc7d0eef39fba6057866cf78d8ce4a26c382c10f42a585ea67a871990" + }, + { + "kind": "file", + "path": "img_392.jpg", + "sha256": "db9c599b5ae8f9a368ec5dbb761b01db9b05af09e137eef80ae3201667e66186" + }, + { + "kind": "file", + "path": "img_1372.jpg", + "sha256": "0b0231ab62d084bc24899ec1551fe6a76b2cac30d6e8d3579f2ea7634902a4ef" + }, + { + "kind": "file", + "path": "img_1414.jpg", + "sha256": "6d1749d53d3c6898fd2e11e17816c7b56d34119da0eaa2c5618ae434943c3914" + }, + { + "kind": "file", + "path": "img_3203.jpg", + "sha256": "70fcb6448cb0b062d7b61d2af5dd1cde1efafa7a18d670e895b4da0eecc51695" + }, + { + "kind": "file", + "path": "img_68.jpg", + "sha256": "6e68fe8880eed3e39d8891a438b87f09b3cd0a6060d16709712ae7cdcffc516e" + }, + { + "kind": "file", + "path": "img_4544.jpg", + "sha256": "df95219d8c1201bbfc771489d7414c0c2690e6eddf7f59b24a182c2d014ba716" + }, + { + "kind": "file", + "path": "img_40.jpg", + "sha256": "f6ae73fd729e7b2df66245d5512db64dc604a7cccf5b498a8bc734bf27465886" + }, + { + "kind": "file", + "path": "img_2135.jpg", + "sha256": "8c3af8c07c055aeefae0471a220b5e9c215651d3149f043096eadd08504feefc" + }, + { + "kind": "file", + "path": "img_2653.jpg", + "sha256": "bc6315f00d9c391ab04529c57d5432d60d9bd0ae1c12cd6596b2937646440b1d" + }, + { + "kind": "file", + "path": "img_4222.jpg", + "sha256": "eb860afe1899537330ca011646aa496eb9ca882c83c2cd68581089028ebacd2c" + }, + { + "kind": "file", + "path": "img_2647.jpg", + "sha256": "3b163b21e2d875556db514ca41e46bf6d2aa5ebc375c475e9ecc6b0a2dafb39e" + }, + { + "kind": "file", + "path": "img_4236.jpg", + "sha256": "971a5407496c608298b007369a7c071976e1c01f1ce3444a851cd0917a035c19" + }, + { + "kind": "file", + "path": "img_3559.jpg", + "sha256": "9df526f8f8a37ca710060e34fa09444265d4a2c116caebac541127129345898d" + }, + { + "kind": "file", + "path": "img_4550.jpg", + "sha256": "d6a32ec195992add697d517d191cec9634938c075874c31e09ddf9a97bfee685" + }, + { + "kind": "file", + "path": "img_54.jpg", + "sha256": "12660860e0de9d9e26c41e24d7b35c7016bd1f68be46b000776dc309e0fdb303" + }, + { + "kind": "file", + "path": "img_2121.jpg", + "sha256": "d707c73b0a7727299cbb729cc47dcfff3b4038741f57a627ab96e7e94e019dbb" + }, + { + "kind": "file", + "path": "img_1428.jpg", + "sha256": "ba604920f6a64c440513342a58e3367840928a08486b88f3516c66488be3f7dd" + }, + { + "kind": "file", + "path": "img_3968.jpg", + "sha256": "98f5ae28c0bbbfa4d78c213271e52a632531fb2dee651097c467df33f819fc26" + }, + { + "kind": "file", + "path": "img_147.jpg", + "sha256": "b9cd6c9306fb9a2080dd818e98db22df07a0dac8989c9ea101ed69ca8563f0ba" + }, + { + "kind": "file", + "path": "img_621.jpg", + "sha256": "e9d2bd85e20a1637f552f1e9f66dc44f077e19e4efbad4f4fcb279cda695e433" + }, + { + "kind": "file", + "path": "img_1819.jpg", + "sha256": "cdc58430ac0ac5e5b4202dc6308bf33bef9e6d31431755066ffba91118dd2613" + }, + { + "kind": "file", + "path": "img_635.jpg", + "sha256": "4c8c7ce5f7519baa377b981883a7f8dfab0a2ec32e367d22798349736fe1a291" + }, + { + "kind": "file", + "path": "img_153.jpg", + "sha256": "0ce73b7b2fa951a0ed3c348d507cd19bfacc30446dc29f34ca35684a50007bc1" + }, + { + "kind": "file", + "path": "img_3954.jpg", + "sha256": "804ff253deb3671c74eb6f378c8f9a7f6407ee1ae74aa86b5f52b5c8f6353599" + }, + { + "kind": "file", + "path": "img_2492.jpg", + "sha256": "5fb7d8f907a691b6c186a6c660ffdc09c36dccf51320bab391c67a8338add6d8" + }, + { + "kind": "file", + "path": "img_1825.jpg", + "sha256": "41722255beff2e053ec41fedbb1915d4d28d3492268632aee8742dc22e42a055" + }, + { + "kind": "file", + "path": "img_4791.jpg", + "sha256": "dc1099a8796d5e83bce074fc45ebaa93930a6b2d29414fd3b51c9f486d2cd546" + }, + { + "kind": "file", + "path": "img_609.jpg", + "sha256": "471eed1d444ddef3a3c6864388685b09ada031d4f613ad1231e85a7cc897f04e" + }, + { + "kind": "file", + "path": "img_1831.jpg", + "sha256": "8c82b03aefb5e361403bb5a060d0b529dff2fc408f3698d234fb169939305168" + }, + { + "kind": "file", + "path": "img_3940.jpg", + "sha256": "4a6772a3fb138fc95652926ee44ceccf5a85ca375f02cef28a142a5a8376ccad" + }, + { + "kind": "file", + "path": "img_2486.jpg", + "sha256": "b8f7f0ad08a1692458c5db6241b17c5e4847910924cd0a9bd3c5c79c2368e700" + }, + { + "kind": "file", + "path": "img_3798.jpg", + "sha256": "659600f1588bd0711e7c3444515a84feadbaa298b707cf456713dca9c851d491" + }, + { + "kind": "file", + "path": "img_184.jpg", + "sha256": "d19aae06a4eea05d9183f7e8b4da722492206aa71628df4d332803d5d0c7567b" + }, + { + "kind": "file", + "path": "img_1164.jpg", + "sha256": "7c97ca6660f6254b95e08240aa83da0cf82b07faebda63642045f80a1a657d94" + }, + { + "kind": "file", + "path": "img_1602.jpg", + "sha256": "6fbf86244ead4b2ee799d092b77c950442201634fae6583535cfbb0f6078534f" + }, + { + "kind": "file", + "path": "img_3015.jpg", + "sha256": "f0a8bd4cba3913187fef104cfe0564ac49fa4f560dd895d78055d9182c30c1e8" + }, + { + "kind": "file", + "path": "img_1616.jpg", + "sha256": "165c4488fea6880ecc79ab7f7ec557849359be4d8f1295d976df0daa3fc376ea" + }, + { + "kind": "file", + "path": "img_1170.jpg", + "sha256": "ccbf62822021a1701d76117780d2aaeffca98464f173409ac9a487c5b207c7ec" + }, + { + "kind": "file", + "path": "img_190.jpg", + "sha256": "f5f4fec7ac75a20d27d606c684164f0fc6be7db1d9f8de0c4f8448b597837a52" + }, + { + "kind": "file", + "path": "img_3767.jpg", + "sha256": "88c3fc32e485915ef327dbae5f9d8b4d9eff3ccfe34c90b35dc9f0eab58a3141" + }, + { + "kind": "file", + "path": "img_4008.jpg", + "sha256": "79dd9b4d383dc0c903e6a646322dcc773f8ab0cf44dff0209d984d015d3bf439" + }, + { + "kind": "file", + "path": "img_1158.jpg", + "sha256": "960984c7d6b6c4aff6cd31145c7df17058511539b654b024fff49c867b103b78" + }, + { + "kind": "file", + "path": "img_3997.jpg", + "sha256": "49f02bbc16e443ebac08576e3b7d2cd8e86bd8e8912128c5808cdd9e643ea38f" + }, + { + "kind": "file", + "path": "img_2451.jpg", + "sha256": "4672c612fc942a70139ebf80e66add9fa2d72fe63a23e8dc783250c00335b7ba" + }, + { + "kind": "file", + "path": "img_2337.jpg", + "sha256": "5d19d35c750aa17732e6735827452d603d43b16c039b5267eee5dd8a387c1309" + }, + { + "kind": "file", + "path": "img_3029.jpg", + "sha256": "007278e7aa497fa6a70038f3b52e0c279880548d16dbe1d121841cf4ab101cec" + }, + { + "kind": "file", + "path": "img_812.jpg", + "sha256": "d8379f9832eea865f927978982a9c113c135859d5cf7586854671839f71cb487" + }, + { + "kind": "file", + "path": "img_4752.jpg", + "sha256": "a5fb456ceade679305394b219452c220b5707247e787572cdda330fc17a28ae9" + }, + { + "kind": "file", + "path": "img_4034.jpg", + "sha256": "b004ba0ed5fdef8fd5b1803a282015e4c01bafff43b166719945665b4be094b2" + }, + { + "kind": "file", + "path": "img_2445.jpg", + "sha256": "27fb32342c036328c5c84ebf91242714e13074a191fcc942ea976934279d6fa2" + }, + { + "kind": "file", + "path": "img_755.jpg", + "sha256": "6447d834d88d264261f409ce9a0dd0bd3f89f9528b4f08cc5e703a9fee800537" + }, + { + "kind": "file", + "path": "img_1979.jpg", + "sha256": "95d61860a12362aac961dd24926a057e55f8ba75071462328758448db66684ff" + }, + { + "kind": "file", + "path": "img_4801.jpg", + "sha256": "5ab97e8fdffb024338c766b026cd024f914a4da7722abc661bbf20e6c6b7ca5f" + }, + { + "kind": "file", + "path": "img_741.jpg", + "sha256": "2806f47087c4ed97cb311d6d70d0dbfdf0bee41c35cab8f98910ce72cb03c766" + }, + { + "kind": "file", + "path": "img_3808.jpg", + "sha256": "6d80e2eff4349e429722a0d9ba05d47929cb2c99897923202b35f2de0a5f1fef" + }, + { + "kind": "file", + "path": "img_4197.jpg", + "sha256": "e04cfbc6b7d200f5ed63f7778019dc2f16911ab90f23ed5fd1b833bf4fb03d83" + }, + { + "kind": "file", + "path": "img_1951.jpg", + "sha256": "3c32b956b63b10503e9d614dd4fa51574657aaff13d03278703b7593b0ad3857" + }, + { + "kind": "file", + "path": "img_1789.jpg", + "sha256": "03a9f99915114bcd5066f6fe023c63d2c7853b27b541c98a02867ee20e607fb2" + }, + { + "kind": "file", + "path": "img_769.jpg", + "sha256": "e51b8000da442876bceb2db1bd7eaf0d0286459f9cb8d3a4bc63cd23d6189f62" + }, + { + "kind": "file", + "path": "img_2294.jpg", + "sha256": "ed0564950a915ecbc9b0e36e634879ab2293beddae3b7f1943e8cdbda5a66767" + }, + { + "kind": "file", + "path": "img_1945.jpg", + "sha256": "757686e92981af52b192d3d7523eb1269b89c7fa3998eba379f6c177df62a57d" + }, + { + "kind": "file", + "path": "img_3834.jpg", + "sha256": "2bdc54bbcf640a913d02e2f05b031125a1cbf94d44cc11ca4ddd782fe4041c52" + }, + { + "kind": "file", + "path": "img_2519.jpg", + "sha256": "c79ecf207078fb41cc9502186c65184bcd807057faa05daab87105d3f6bb819c" + }, + { + "kind": "file", + "path": "img_4168.jpg", + "sha256": "f818c7fae87d7557748ab4ec9ec4e4d63198bef0f0e2179bb5651de451704024" + }, + { + "kind": "file", + "path": "img_3607.jpg", + "sha256": "8ddbdbff8f3fa96e8b0e3fd693c5433506f95a8f485d79bcfc9a1b207b9b2c15" + }, + { + "kind": "file", + "path": "img_1010.jpg", + "sha256": "8bcb2519398920bd6da904603b5fb8319cd3217301c0df20c34de1ac8996684b" + }, + { + "kind": "file", + "path": "img_1776.jpg", + "sha256": "b3d80ad13f1432e0930c24fcc9fee7d4bb4d6eeeb4adfd6f2a29adedf0b41116" + }, + { + "kind": "file", + "path": "img_3161.jpg", + "sha256": "32df03d38580970486bb80d13a499ed13642ca1f50f769b7f1a2254bbb4c4813" + }, + { + "kind": "file", + "path": "img_782.jpg", + "sha256": "b07db9980f22ec47892519bc6b8f151d3be4bdc01216672510190955005febef" + }, + { + "kind": "file", + "path": "img_3175.jpg", + "sha256": "c206ecbcf009f8f26f11714b86d8a1e1afdb82477831a06407c89c9e59fc4c26" + }, + { + "kind": "file", + "path": "img_1004.jpg", + "sha256": "aecfce33328884cac0b8aad287241dd61c1e8640aa2d8c09a3405eecb5063958" + }, + { + "kind": "file", + "path": "img_3613.jpg", + "sha256": "75a8f2642d5f1c6de22f981f528a254699c00036f529956019c4d9b8b8de27ea" + }, + { + "kind": "file", + "path": "img_4154.jpg", + "sha256": "e2bf26d964c98103a8de7e321401f30dbd78f5faaeefeb7a323c056fc8800b68" + }, + { + "kind": "file", + "path": "img_4632.jpg", + "sha256": "4adfa90e351aa840dd5a20e0ab3364ee088d0d7546ae2210bcee1a29df0e418b" + }, + { + "kind": "file", + "path": "img_972.jpg", + "sha256": "60c06bb94fff573ce392566d1161342b4cc36fca5920f799dd23b14363e58ba6" + }, + { + "kind": "file", + "path": "img_2243.jpg", + "sha256": "74f9debcf8868f3ea0f03c7e66715f5c89f00bf3dcfb1ba8c39042d6d42d53d6" + }, + { + "kind": "file", + "path": "img_1992.jpg", + "sha256": "600b0d563a6319f817afcc6f446f93d938c3df9652aaeeffb0d258e0c92c5058" + }, + { + "kind": "file", + "path": "img_1986.jpg", + "sha256": "c631e73e3869bc411b6223d95ac345f6e78250a62d9c97d49b77c2ebfd80532b" + }, + { + "kind": "file", + "path": "img_3149.jpg", + "sha256": "8a2ea1c00b91a96452d5da5debba382bd33868e35525cfc23ee3dfd7ab441c4e" + }, + { + "kind": "file", + "path": "img_4626.jpg", + "sha256": "a8d7e3fa8443871c8537f1e341b842d0f63430748c43b0baf33f86accaebed50" + }, + { + "kind": "file", + "path": "img_966.jpg", + "sha256": "adf572eb7eac2afcf871e51e0e4613097077853cfefe6f1b8be10e8d557f8de8" + }, + { + "kind": "file", + "path": "img_2257.jpg", + "sha256": "13bc1e07fdd17a566a19c5e383bf25bcb3066a00dc5dae7f56857ba9f846b68d" + }, + { + "kind": "file", + "path": "img_2531.jpg", + "sha256": "faeb46ed9bf159a6a240fb7a78af374ac28828ced7c72d9837a9f39ccb919e74" + }, + { + "kind": "file", + "path": "img_4140.jpg", + "sha256": "a2d3431b208fce8dcc01197c42ae493972e3143d4a4185531921e2178bbe9fcf" + }, + { + "kind": "file", + "path": "img_557.jpg", + "sha256": "5c97e7b352ed6ffd9644de7be1127aefaa1e6272debff4560d1c3e8977d38293" + }, + { + "kind": "file", + "path": "img_231.jpg", + "sha256": "4dd5b16eafb6c516a5aa99e13926ee0d39125dbe128b840ccecbb387f0f95e1a" + }, + { + "kind": "file", + "path": "img_2900.jpg", + "sha256": "eba5873106d9087d93927e7a161e25d0244390e84ac6bae50e6e6e832a91b4ca" + }, + { + "kind": "file", + "path": "img_225.jpg", + "sha256": "cab5159ba55344d6b1b12c5ffc73d154263ab4974e47f3aefbf303b2476f587c" + }, + { + "kind": "file", + "path": "img_2914.jpg", + "sha256": "3d1368acb447b5c5f247df88422e4263d04fc208c02edd236ca8ba69ba3949c3" + }, + { + "kind": "file", + "path": "img_543.jpg", + "sha256": "f97785458cf233c710ef75ae1bbdf223da14d8cae38ff0f3b19050df4f0b5820" + }, + { + "kind": "file", + "path": "img_2082.jpg", + "sha256": "e90ad66d2008d91ac1864c7a6b20229690fd852c7070753fb9e5514aaa4866e0" + }, + { + "kind": "file", + "path": "img_4395.jpg", + "sha256": "67f2a7ee005ad02dc6d2283d174381ad9202920430340a1a5f659a969d25a5dd" + }, + { + "kind": "file", + "path": "img_219.jpg", + "sha256": "9d8d37f13f03fec1b66274a39c4f690c18f8b6026bc31e91685f83789dc99da6" + }, + { + "kind": "file", + "path": "img_3388.jpg", + "sha256": "24146507daa1f6871216b11b3afde434e76c0f164b07c5fdc9ebcf041d83c033" + }, + { + "kind": "file", + "path": "img_2096.jpg", + "sha256": "380f683390d6ab6a4a9e42ef5d063efd045a2d0bde91822b398949295bdab555" + }, + { + "kind": "file", + "path": "img_3363.jpg", + "sha256": "240b4cb6f79c22d67fffdb1372c1beee7ef29b9d091202f0b92d121e2a03bb45" + }, + { + "kind": "file", + "path": "img_594.jpg", + "sha256": "e95c6d9c630be8c3e3e7375edd38a939fc869ffaa4e2aee7bcb9ac682c2b8799" + }, + { + "kind": "file", + "path": "img_1574.jpg", + "sha256": "a87d859762dbb5b7db6304eef8220d61c8ec534234c0453c5fc22481f5355cbd" + }, + { + "kind": "file", + "path": "img_1212.jpg", + "sha256": "4ad168147964e37009136d0d99b8e84bade90d0c553e2a94014a3edacd50292f" + }, + { + "kind": "file", + "path": "img_3411.jpg", + "sha256": "b120edbf0f3a4547612387e00e84c885e9e60034eda97b66caf1310ae29fdeb2" + }, + { + "kind": "file", + "path": "img_1206.jpg", + "sha256": "ca511bcf747a6e504ef73b5d602c4fabc23aa02796fbfb576d79d3ba98502f2f" + }, + { + "kind": "file", + "path": "img_1560.jpg", + "sha256": "c2d22a7dc082aa7c4c3b1fc1432ed73a95e7d61ca66e36dc2150caebfbc97cda" + }, + { + "kind": "file", + "path": "img_2069.jpg", + "sha256": "547a32e1a482b58907c2a81111b10205f26f3cb18c22313512781fd26faee6da" + }, + { + "kind": "file", + "path": "img_4418.jpg", + "sha256": "71d28b72709d88790fa629699855468ea00e201919dd8b67fa0bd665bcf774b4" + }, + { + "kind": "file", + "path": "img_3377.jpg", + "sha256": "11e75188e59cffff246dd6d3734ae4c9fa9793aaf706b624f56990a304fe8a6f" + }, + { + "kind": "file", + "path": "img_580.jpg", + "sha256": "cecabfff26ffb09419a25d223da09036f976ca52572a8f8b2bf971395aef2a47" + }, + { + "kind": "file", + "path": "img_1548.jpg", + "sha256": "8704b44470de885852ecc89d148386e7a3bbbb40c194239ee442e2993f8aa51d" + }, + { + "kind": "file", + "path": "img_4430.jpg", + "sha256": "cdd789bd62d9a94378a947ec815eb638d1399966e7c880482fdc04204dd5914a" + }, + { + "kind": "file", + "path": "img_3439.jpg", + "sha256": "72ce0fa722bb0db267427a8922433471abe7742c92e6956a3ace73bbcf68afc1" + }, + { + "kind": "file", + "path": "img_4356.jpg", + "sha256": "dc625a8f226de569e8a7e360e6289dd1b4035ae925ddb567721f44d9db87d716" + }, + { + "kind": "file", + "path": "img_2727.jpg", + "sha256": "2f3a56045b50d01dd9cfe3c18abfc4bba12adff03d9867aa314ade2c4f9b45af" + }, + { + "kind": "file", + "path": "img_4342.jpg", + "sha256": "c71862c10a7d47ffddad734b4d6ca529b385f6e942fc3db4fdfbb687dc84baa7" + }, + { + "kind": "file", + "path": "img_2733.jpg", + "sha256": "2f338420e260e55d5df1ceb7c4491bc7fff5a031c55a0aed7652ded7d9c4adf1" + }, + { + "kind": "file", + "path": "img_2055.jpg", + "sha256": "2e268492c7d1150914fdd7766cf8808d63f455c1ce11e206dc67e6a3df4f2e17" + }, + { + "kind": "file", + "path": "img_4424.jpg", + "sha256": "23e1291f0bcb1e2da9db0b1a77e508eb766aa10344e16385d481857084ca6158" + }, + { + "kind": "file", + "path": "img_2732.jpg", + "sha256": "9ba32858a812c4f3dc8975cd7ca7c53ead27a408b159832c2e5eff24f6bbeee2" + }, + { + "kind": "file", + "path": "img_4343.jpg", + "sha256": "1018b66c826f21ee19e3edce9291951ef0b6d878b7069e630878ac98ca8f476f" + }, + { + "kind": "file", + "path": "img_2054.jpg", + "sha256": "c1f019735fac73dd69635f6a8fdc4c0456d7cbdeb8f00cbeaf6166a8eb9c8135" + }, + { + "kind": "file", + "path": "img_4431.jpg", + "sha256": "6b64c9ada25238426c180388f6a7889e7dca068d59c8819acc61474d593b1c36" + }, + { + "kind": "file", + "path": "img_2040.jpg", + "sha256": "152caf94852d4db40f6c15b2d58a2ad635718e8bf563f981fe3e1c488d05f865" + }, + { + "kind": "file", + "path": "img_2726.jpg", + "sha256": "97f430c418500c265b4985fc9b7be9b111d9bf4fa4735c9f448c7408485c8629" + }, + { + "kind": "file", + "path": "img_4357.jpg", + "sha256": "27b82dce086244193da1b03e3c5698d5ef0e5367d9b26074b9c38ffa78edad4d" + }, + { + "kind": "file", + "path": "img_3438.jpg", + "sha256": "4e583cf0279295c56f82340651b7f950a1545c36f2a227f6cd16b2468d290d17" + }, + { + "kind": "file", + "path": "img_1207.jpg", + "sha256": "03128fe91dcd294fdfbae61caa43b3180a5c2213897b4c6f6f43c5cb0f0cda31" + }, + { + "kind": "file", + "path": "img_3410.jpg", + "sha256": "812130dda3baddff1b0d32ca9731c0142fd02eeec23eef2cb40903bfba9a7e2d" + }, + { + "kind": "file", + "path": "img_581.jpg", + "sha256": "8615d45b8c13f4d04f885bc7c5ef4273e501353537b12fb5ad84694af308c971" + }, + { + "kind": "file", + "path": "img_3376.jpg", + "sha256": "6190b406892bbcea73b27b93a441d82c5b83209651467810aabe97c657cb2529" + }, + { + "kind": "file", + "path": "img_4419.jpg", + "sha256": "8a9f2d366979f681ac080b3767527682e8e643625852f64a595eb0e100a0591a" + }, + { + "kind": "file", + "path": "img_2068.jpg", + "sha256": "55b606fc87199db9e3b49b851a77627d16cc2f9d23dea71d47f518af4c60e19a" + }, + { + "kind": "file", + "path": "img_1561.jpg", + "sha256": "aff80c8df107f54b063a0f513e050e25dcdb5638aad07d5cf0c45211fd5cc166" + }, + { + "kind": "file", + "path": "img_1575.jpg", + "sha256": "9883588bf414003f58506e50f5f72fe852b7ec3c65a4d169639c4a9a1622c3d8" + }, + { + "kind": "file", + "path": "img_595.jpg", + "sha256": "26943c8aa8854cc64c3a4397657a7f76ec3a95b2fc891d108a6f832d62f00107" + }, + { + "kind": "file", + "path": "img_3404.jpg", + "sha256": "047440d513252ac71ebe11951c25ef4a06a74af495bbbe7104beab0d62b468c1" + }, + { + "kind": "file", + "path": "img_1213.jpg", + "sha256": "086ec35210526db6c43bc9a6443a7db8438fff6a47b488c1d386ad63908d57ba" + }, + { + "kind": "file", + "path": "img_2929.jpg", + "sha256": "9f62ecfba92629efed7b4ec745d2972339082f5889624cf53a716934e9235ab4" + }, + { + "kind": "file", + "path": "img_218.jpg", + "sha256": "c58fa51ca13fcade7678cde54428a6c7ede556f7e1c8ac780f02fc06fb93e7aa" + }, + { + "kind": "file", + "path": "img_2097.jpg", + "sha256": "45c1d1b29d62e66f1d6e3239f84cb63ec29a0c484ff0e1c80830806d21e5a31b" + }, + { + "kind": "file", + "path": "img_3389.jpg", + "sha256": "c218f95b09d16ad0008b4f7eb16a19e7f32d5b1d11bbcb1dac89a2453dc4fa06" + }, + { + "kind": "file", + "path": "img_2083.jpg", + "sha256": "5c0dfb5a41e6f5c5bd11e840d5bd277b65c179a3ccf123e5f3a2d1275e2c81d9" + }, + { + "kind": "file", + "path": "img_4394.jpg", + "sha256": "99b2b70464c0ba613e90f2a74b8346f4971bea9b776e8cc56a05a6d37e2cffbb" + }, + { + "kind": "file", + "path": "img_2915.jpg", + "sha256": "f9f1788d0f1959787ee93b5aec5efc77a104683b17c0710b765b0e1713c52423" + }, + { + "kind": "file", + "path": "img_224.jpg", + "sha256": "c68a7bcf50c0f8c0c1b72b6aeb236faf77d55fc5a51ff5cce5c538b7cf416a9f" + }, + { + "kind": "file", + "path": "img_542.jpg", + "sha256": "af1d0310293e1f08c18815dc0688d3cdb401636c92a31796066a8cbb998951fb" + }, + { + "kind": "file", + "path": "img_556.jpg", + "sha256": "917659118c5281bb8a5494bcecbcda857b55a5fbf4751f51d6f9e17524017fef" + }, + { + "kind": "file", + "path": "img_230.jpg", + "sha256": "1926e86d7ad4d83575d1b08236ee9018b93b60277218d8c9cd5f732c193e5a5b" + }, + { + "kind": "file", + "path": "img_2256.jpg", + "sha256": "6832737571871dcfcf22502055afd645764460a9639b95b8585e68319c9fe8e8" + }, + { + "kind": "file", + "path": "img_4627.jpg", + "sha256": "ed1d12e9922a238304ada2051e309fa9ffbed18f5988ee7ce67f7d5b72469881" + }, + { + "kind": "file", + "path": "img_3148.jpg", + "sha256": "ea805516688c05e919c3838eab3bc8f05d8b99313fc892378851f5bf2ae5f7eb" + }, + { + "kind": "file", + "path": "img_1039.jpg", + "sha256": "be493a4290dade668d0241302aaffb23d00477f3f61c806546d4bf01004b5edc" + }, + { + "kind": "file", + "path": "img_4141.jpg", + "sha256": "b848970ce94da8d7fe3582c2739d21530b76ec236fb03f1decf18afdbf2fe297" + }, + { + "kind": "file", + "path": "img_2530.jpg", + "sha256": "b0378df56c78b59563304990cd4cc5ef3666c461ac6c25ae356ffad64dd0e8b0" + }, + { + "kind": "file", + "path": "img_4155.jpg", + "sha256": "8c7457ed39a741f322121ff5e388fb908fd806fdeacdf0edb5d0cfa9da2876b1" + }, + { + "kind": "file", + "path": "img_2242.jpg", + "sha256": "3d42941b5fca724e1ed6629fad8459786ee0f193a15b6e4765124d6c7c8cad6f" + }, + { + "kind": "file", + "path": "img_973.jpg", + "sha256": "c26962a61057430b99a878ef85bc15808dafe03c8d2eee362fade2fcb8239674" + }, + { + "kind": "file", + "path": "img_4633.jpg", + "sha256": "537e40878c503021bfe473d3a54413bdcb4005d528a8a07b65c764f132951925" + }, + { + "kind": "file", + "path": "img_1763.jpg", + "sha256": "7a6bb105a4e132299bae41f9332cf7192c7e7e9d1857cc6d4aae0238ab473dd7" + }, + { + "kind": "file", + "path": "img_3174.jpg", + "sha256": "5da1ba83cc6525ea2aa50387f921124546416e5f39770246547a30cc70f9218e" + }, + { + "kind": "file", + "path": "img_783.jpg", + "sha256": "c8ef564c787047be67c2834a8c724dad238781e9fb3df30912227a8bea5fb45c" + }, + { + "kind": "file", + "path": "img_3612.jpg", + "sha256": "8644d7a26d467abf853b51e0ca71f5e29218effbc4c1d87bd4d5eda2372cb7ae" + }, + { + "kind": "file", + "path": "img_1005.jpg", + "sha256": "98eadb1b6bb0b175afee651f3609fd19ca6c19d516c19b7d053719cc69f63036" + }, + { + "kind": "file", + "path": "img_1011.jpg", + "sha256": "cde50e402e7beabfa84134d96f90664a479fdc61813720daf9391ad13b00f8cc" + }, + { + "kind": "file", + "path": "img_3606.jpg", + "sha256": "4f6701c0963b60ac0a8bd9a620ac6739c7a1d51f0b650e5edf74e00b139d26f2" + }, + { + "kind": "file", + "path": "img_4169.jpg", + "sha256": "7caccebf5f53a9f0a7da90e053559fe94164fe2ee15396538f6f7d082eab58a6" + }, + { + "kind": "file", + "path": "img_3160.jpg", + "sha256": "806b02a973160eb9f27cfec845f51b1beac377776b9c2ab20fc763c113b41bb0" + }, + { + "kind": "file", + "path": "img_797.jpg", + "sha256": "188bc1052669743d484ad2b39c31416cf68ff4e5d52c8c7c44d63c4f9741f5c3" + }, + { + "kind": "file", + "path": "img_1777.jpg", + "sha256": "82881517fcc2a8f4a2b54148b51ef4fe02a93ae4adae7704d4d5a7dc46f01e07" + }, + { + "kind": "file", + "path": "img_1944.jpg", + "sha256": "552230f7901ded16d53a7baa404c2c36a48be7a8c9011d26d418676986a90882" + }, + { + "kind": "file", + "path": "img_2295.jpg", + "sha256": "791510a18e216a8fcbbe535b2849c9c9bfeb5ab49fee19bf22227d9730599501" + }, + { + "kind": "file", + "path": "img_4182.jpg", + "sha256": "25a13f32722844dad6a3c8693526faa47eb7a3a3da05d5e587dd3d226921f021" + }, + { + "kind": "file", + "path": "img_3821.jpg", + "sha256": "6f4816c36d6c52a52752c6b1d870a5a12759efae7d311ede0f552010be0db86e" + }, + { + "kind": "file", + "path": "img_4196.jpg", + "sha256": "5f74099df5d6daf44ae127d5345734e4c53757be25436a9b64e6af1d9e68ab3d" + }, + { + "kind": "file", + "path": "img_768.jpg", + "sha256": "9729f0db0a32eb5ed5902fbcaa357eb170946f16c9613043623f29d025584315" + }, + { + "kind": "file", + "path": "img_4828.jpg", + "sha256": "c36a25337cf70dbd5b6d9a6f939f033e882ba5cca78618a593cee821750bb55b" + }, + { + "kind": "file", + "path": "img_1788.jpg", + "sha256": "2b83bdae778ac68e902086f8e1f83d9940b9031eff3aad2f4e5dc02dc9d1a8ca" + }, + { + "kind": "file", + "path": "img_1950.jpg", + "sha256": "4ac7987dd96a21a7f34b21544ba1794857ca1feb2ed7608e78f8811e675332c3" + }, + { + "kind": "file", + "path": "img_998.jpg", + "sha256": "7db41f1fe363eb42286ad07a19eb676f5c449629db60ec906b4b18b83aed4e89" + }, + { + "kind": "file", + "path": "img_1978.jpg", + "sha256": "7a9f83cb9439469e29b55424ec961ee88fa0e34f5d1d649fbcf66b8b646201eb" + }, + { + "kind": "file", + "path": "img_3809.jpg", + "sha256": "03f39da1f0e466cbeacbf5fa27f6e53ee33f0edb37ff9c98797a3ae7bed6b2e0" + }, + { + "kind": "file", + "path": "img_754.jpg", + "sha256": "8549224c6c968f6fba643bd64f39b8aad4a2998beae6759a937bb98476df0d84" + }, + { + "kind": "file", + "path": "img_4814.jpg", + "sha256": "c358bb1f20c4027305227937ad39e2067fc89c1055fd363a4c0daec0a249e7bc" + }, + { + "kind": "file", + "path": "img_813.jpg", + "sha256": "69549d1fa5f0fecb079f116eba21f244455c54f9cbcd56af95a7fd621ddd99e0" + }, + { + "kind": "file", + "path": "img_2444.jpg", + "sha256": "824d53ec858d5f0e1b6697b751bb58da8d8eb93d529fa89d3e509fe1e2cd1b84" + }, + { + "kind": "file", + "path": "img_3982.jpg", + "sha256": "aaf8e70abfcd09a3431c99f928656de46ceb130990776395dcfeec24535de4ea" + }, + { + "kind": "file", + "path": "img_2450.jpg", + "sha256": "9e91795076bdc159d894974b8f1a36cf0c644e0623f1ae2d98b4741806aeb9e1" + }, + { + "kind": "file", + "path": "img_3996.jpg", + "sha256": "b0e7d24848687b6baabd8acef5185c0f2f8de3adee46b7789d5ed05700b0d4fa" + }, + { + "kind": "file", + "path": "img_4021.jpg", + "sha256": "e6cb4b72fb0d537c109c0c610f9ae1d6c9e7eeaaad53dec6093840550f700e06" + }, + { + "kind": "file", + "path": "img_1159.jpg", + "sha256": "85f0965fb34152d0d43245ece364f859dfd1f5818a8d50d2b240bfe6cbdb5924" + }, + { + "kind": "file", + "path": "img_3028.jpg", + "sha256": "f31dd615e011ededba6ffe4ff7ecd29e18af375167caebfb0307755c20e9389e" + }, + { + "kind": "file", + "path": "img_4747.jpg", + "sha256": "3fde61cba9fdaf534bcec35855d59d241b726a46c8611e343feafcd0fcc57b4e" + }, + { + "kind": "file", + "path": "img_807.jpg", + "sha256": "fe4acd26846e216d3d51e0f04d32eb0bc93002d265e811f6f954ee81acdea181" + }, + { + "kind": "file", + "path": "img_3000.jpg", + "sha256": "1f728c8e44e9a9135565a0ba055d66065c36f1e5de4c664b1e4333e5398a55b4" + }, + { + "kind": "file", + "path": "img_2478.jpg", + "sha256": "f321556757353882e71aa59b312ca4a6717c56bc6bc51b2c5197e20f222116d7" + }, + { + "kind": "file", + "path": "img_4009.jpg", + "sha256": "9b8c54e1b9ee9eabc24233d799bf181f1067135b517c07f5c7d9329185df8da6" + }, + { + "kind": "file", + "path": "img_3766.jpg", + "sha256": "be26c65f88b3a6afeff148746dc565c7a3e7eed3476fb236d96beff384075cf9" + }, + { + "kind": "file", + "path": "img_191.jpg", + "sha256": "5fc2c65166a42fcfb6c194d05c63117e0a09e131ea660f1ed04681d5dd07d57a" + }, + { + "kind": "file", + "path": "img_1171.jpg", + "sha256": "15262f32781a0c2b7004db1c83da1694fe2315b68996f6c09fbad19faae9c1c7" + }, + { + "kind": "file", + "path": "img_1165.jpg", + "sha256": "21812a7411fc1b92b03d933b2a3a5127d3eb53864c004356922e96d4f5737228" + }, + { + "kind": "file", + "path": "img_3772.jpg", + "sha256": "8c8b05ef4e3962f3c1399eec588624b84440d6f43ef5760c4ef2280e8c343d27" + }, + { + "kind": "file", + "path": "img_185.jpg", + "sha256": "bc0cf974abe673f379b67dd40875120ba24d91141a60539a149e9aec982e9ca6" + }, + { + "kind": "file", + "path": "img_3014.jpg", + "sha256": "ba2445d0863f4a6f5254f8b7627f43049a2e88f63975858d94320754f4888fd5" + }, + { + "kind": "file", + "path": "img_1603.jpg", + "sha256": "02ed4f550d4901e1b07b4545a0b46808adc17fa8f92165b91a65334e685fa402" + }, + { + "kind": "file", + "path": "img_1830.jpg", + "sha256": "1a2f421d52775be937badc29709557cffe46ab26fcf0863faa5ce424b927a8d5" + }, + { + "kind": "file", + "path": "img_608.jpg", + "sha256": "c57d9485105b35155ca5aeb26370ef40689f54d8c3e7074da72e5a29eb5bc2f2" + }, + { + "kind": "file", + "path": "img_4790.jpg", + "sha256": "64ded4d7b06353c681d8ce5a216dfcf8852a6156e8f2f0776fafd6702af44013" + }, + { + "kind": "file", + "path": "img_3799.jpg", + "sha256": "9b5dae0347d2176d4571c2e30989b534ada948c96111cd31bbf22adf6b1c71c5" + }, + { + "kind": "file", + "path": "img_2487.jpg", + "sha256": "b39e89cac92decd2d32fdf7260e482c19f2602f3e3aa0d87cd5aba8f117c245b" + }, + { + "kind": "file", + "path": "img_3941.jpg", + "sha256": "f63c8ac55339967f83e58481800b3f578cde671a16bbab17cd6deae9f07df9c0" + }, + { + "kind": "file", + "path": "img_2493.jpg", + "sha256": "2fd1eb40989403c6c31f19558539a3ee3a2e7d2aa119a83e746f1d745a93d9ea" + }, + { + "kind": "file", + "path": "img_3955.jpg", + "sha256": "7df4a8e489cdac69e1ffecc92a9ce204dc4232fe0dddb8492380f3b53cec902f" + }, + { + "kind": "file", + "path": "img_634.jpg", + "sha256": "50e7dc387bd9be4b0cdf2c29acd3bd15addbdbe5368c3a9bf3e350954915208e" + }, + { + "kind": "file", + "path": "img_152.jpg", + "sha256": "89da80c703f9bdcec3e9d5238ae2f365efc1d6bf95f512aaa2227cca9abc8dfd" + }, + { + "kind": "file", + "path": "img_146.jpg", + "sha256": "3a84f7c980220ab17ff402bd8fbec027fbc5ef5338f9863f0f1a145f697fc6dc" + }, + { + "kind": "file", + "path": "img_3969.jpg", + "sha256": "3e7fe3879fe599c480c9b77e7823bcc049f43d2694ffce3e0e1bd88da8cdcecd" + }, + { + "kind": "file", + "path": "img_620.jpg", + "sha256": "055f01f8793bf6be55cd5f55feba317ebd39d5347a19aacf8eb8770c7aac0546" + }, + { + "kind": "file", + "path": "img_2646.jpg", + "sha256": "1ff051d806ce73faa640500a80fdf48c9fbae07bd0f181dde717893aa19bb979" + }, + { + "kind": "file", + "path": "img_55.jpg", + "sha256": "3ffba0ececa0e0383543325a2144f5cefa4e914abd258be0dfd4ca34fdd0dc2e" + }, + { + "kind": "file", + "path": "img_4551.jpg", + "sha256": "6ee2b41f7dad5596f7df9fb9b82116c6c73cfbcc6853bcbca4154511e1682e8d" + }, + { + "kind": "file", + "path": "img_2134.jpg", + "sha256": "aa31ae0bfa43d601b3773c65650d024eb985101606918e037efe2bcf04a47787" + }, + { + "kind": "file", + "path": "img_4545.jpg", + "sha256": "67b099fa79fabab14c0f2c255093fc7a2cb0d4eece5f81371e7b6fbd093443da" + }, + { + "kind": "file", + "path": "img_4223.jpg", + "sha256": "b6d877f02b7ec0eb88612c522f86a28941ce9b738bdd6669f7326fc4b7ef502b" + }, + { + "kind": "file", + "path": "img_2652.jpg", + "sha256": "11cdb7487074a3ee7251d3059f6ba79f9060f99ec5ac5fe0d74b7f7b4a567064" + }, + { + "kind": "file", + "path": "img_1373.jpg", + "sha256": "fc9ee06ecfa2c111fe8c89141a1115a46477ba67daca41f555e39b47b625d3d9" + }, + { + "kind": "file", + "path": "img_393.jpg", + "sha256": "efaec241f75467b539e4ca1b3a93643a038d0331ca9989d0a6f2e0b72f76899a" + }, + { + "kind": "file", + "path": "img_3564.jpg", + "sha256": "e278d60afe0f4d1dda85a0f868970deb6b5535fa451f9b0929952013f9f4df39" + }, + { + "kind": "file", + "path": "img_69.jpg", + "sha256": "a27f584fbed724c98333c4f2e62d988d832d78f3a0b8fec06d38408d7f9769b1" + }, + { + "kind": "file", + "path": "img_3202.jpg", + "sha256": "610f793041268f3d44733ff3bd4bea6554779103189f1794a7c9a9405b8f6eca" + }, + { + "kind": "file", + "path": "img_1415.jpg", + "sha256": "0c05ddbb1c1040c675be7387185d3ea2f7caf0bd43559241d9afd46dd8582d6b" + }, + { + "kind": "file", + "path": "img_2108.jpg", + "sha256": "70f0b74f9e3638c2a5a38f847423e14611f25f123807dea4d268e516dc2fee45" + }, + { + "kind": "file", + "path": "img_4579.jpg", + "sha256": "92b9242a41782422df1e5694e0750da38f149a56e550fa9674f2db62ae70b457" + }, + { + "kind": "file", + "path": "img_3216.jpg", + "sha256": "28d2f02ab623d46a06c334aff44c826bece305bdd0d69e4b00ab6d00d302c722" + }, + { + "kind": "file", + "path": "img_387.jpg", + "sha256": "a1699d4f1c6df0172ec31b0f4163f9a04f71736b1f04f5fb4d55dffa8f05b5ba" + }, + { + "kind": "file", + "path": "img_3570.jpg", + "sha256": "498542f350c7e28f640518958b709eec82fd2704024588020d7deaf54c88881e" + }, + { + "kind": "file", + "path": "img_1367.jpg", + "sha256": "b762fe335cdb2ed0c28f75f184935311006081fc2995526da2d06ab404e82f36" + }, + { + "kind": "file", + "path": "img_4592.jpg", + "sha256": "6520a6e40a3d022f5b59d721996c36a55686ef495d18289a763318d006674a41" + }, + { + "kind": "file", + "path": "img_96.jpg", + "sha256": "89c40fc28d5af42f65b04c49b157094115a121c329f878914f27546fb9f8928f" + }, + { + "kind": "file", + "path": "img_4586.jpg", + "sha256": "9ea3d5c761e848cd3ea008cc08993610d901372d7bbb828b79767ca8c303ea22" + }, + { + "kind": "file", + "path": "img_82.jpg", + "sha256": "a13aeb1fbff46dc2b7e7f37861f92b0131ea0c407f71997eda71abc9f33de3dd" + }, + { + "kind": "file", + "path": "img_2691.jpg", + "sha256": "a7b211bef2c800c18fd0005425524258a15294ae1713b4ec597e186d368abba5" + }, + { + "kind": "file", + "path": "img_378.jpg", + "sha256": "28b761a1193d9846d1d4aa8008cb77472c5d5a96bb3fd34de240c4a7f8580fb7" + }, + { + "kind": "file", + "path": "img_2849.jpg", + "sha256": "3053a8852007910961b6413b322a54cf4492de131c0326e7feb969f6594acf08" + }, + { + "kind": "file", + "path": "img_1398.jpg", + "sha256": "a88bf5a11b27ef2204322a16504a7c3b10751f5f0567dc1efc607d7971eb1724" + }, + { + "kind": "file", + "path": "img_350.jpg", + "sha256": "b72b322d007445f5837037feae2e069636b376cc0603efc7ebf8810607c896d0" + }, + { + "kind": "file", + "path": "img_422.jpg", + "sha256": "1875e70b1e8159084cc8f3102914d2ef9ae29730a7983d352b3f2507f7ad6dba" + }, + { + "kind": "file", + "path": "img_344.jpg", + "sha256": "bc6c4686aa92214126b6c0f60f47e0b02c746540f82dfb8515bcd7af33de1b5e" + }, + { + "kind": "file", + "path": "img_2875.jpg", + "sha256": "eaee426b27b52b7f28f77077ce5b07ed8371d42a4294fd98de399405fe41e480" + }, + { + "kind": "file", + "path": "img_434.jpg", + "sha256": "ea48418d049d7699853c3ae07b9e89e9f3ffb2befa1cad6c9b5390cbfd7dd8f3" + }, + { + "kind": "file", + "path": "img_2863.jpg", + "sha256": "07f0fbe0b55d6ef09f3008f875bc0baa7757adbbba503b51f0534965bc703265" + }, + { + "kind": "file", + "path": "img_352.jpg", + "sha256": "8fedc64c6957963d73ce9f2d22e7b4df1cc87ff3cd88c8cee91b11154307de54" + }, + { + "kind": "file", + "path": "img_2877.jpg", + "sha256": "1a1ee454adde87cf07aee2b707822967ebf05a1be92ca08c6d6cf2ae00b53e80" + }, + { + "kind": "file", + "path": "img_346.jpg", + "sha256": "68eb1fc25b928bf530b73cefaf8be2d2b5d363e7d873a2121cdb5937e8912dd5" + }, + { + "kind": "file", + "path": "img_420.jpg", + "sha256": "5e1c93930afd64da33b815623c2f172d8f66b8d81f40c7384b9deec5930fd39b" + }, + { + "kind": "file", + "path": "img_94.jpg", + "sha256": "425732a53ff11d320e8ab1f5572ef9b48fc60befc55b65f03fbbd4f21bf84be7" + }, + { + "kind": "file", + "path": "img_408.jpg", + "sha256": "cbe897f7aeaf2a5c8469537753d346876ae253ac3c480b03f4a344cfd07384b5" + }, + { + "kind": "file", + "path": "img_4590.jpg", + "sha256": "17821c3a1a2fbc0e979f8ab301352a9ea49ca533041cc159be61e0cb040c3bb5" + }, + { + "kind": "file", + "path": "img_2687.jpg", + "sha256": "29cc5229e89aa2228dc6dbc62ec9421573e2938756150431d480caca973ae20d" + }, + { + "kind": "file", + "path": "img_80.jpg", + "sha256": "ec2ee5fbd289643d97c81e10f315904741173ba88970ea4482c911512811b646" + }, + { + "kind": "file", + "path": "img_4584.jpg", + "sha256": "36bc5ba3410e0311da1195b7718cc4b4b0813c60fd861c8ba624f0b7a44c3d58" + }, + { + "kind": "file", + "path": "img_1417.jpg", + "sha256": "62dd3d7395358eaffcebee9ee71e7a4fb8311a5498a5f69c90b3039d1ef6ebcc" + }, + { + "kind": "file", + "path": "img_3200.jpg", + "sha256": "d69ac84a4c43b38f5ab912e6cbb395663ae21e2852afba1eee12b63545d96d30" + }, + { + "kind": "file", + "path": "img_2678.jpg", + "sha256": "f5777c7c7abf67353503e4460b33298c3f8feb8c72a8e53ac3f1697acecb958d" + }, + { + "kind": "file", + "path": "img_391.jpg", + "sha256": "3d03b4d283c15b40a4daacd6628674ffa42130ec906381e37b4528b20697533e" + }, + { + "kind": "file", + "path": "img_3566.jpg", + "sha256": "e3fdd2cc8cd6b017533dffe08bdf3ce2fdb4b669ec5be7537bfcea4320578b1e" + }, + { + "kind": "file", + "path": "img_1371.jpg", + "sha256": "414631f335ebc91c5811f65e3ea6ca4b099fea5d68e7140585dea4f897ce1237" + }, + { + "kind": "file", + "path": "img_1365.jpg", + "sha256": "50493608f21b8b8dc2cdf349a921c13db01db55b9dfadf8d57aa568f034ef06b" + }, + { + "kind": "file", + "path": "img_385.jpg", + "sha256": "2dc125e6246d8d89bddb560d509d48615e071397c281b05c4f2bfabaada24cdf" + }, + { + "kind": "file", + "path": "img_3214.jpg", + "sha256": "0773631f90bd41d020b588ee622f27327c39e676a99334b03aa2685d36339292" + }, + { + "kind": "file", + "path": "img_1403.jpg", + "sha256": "1aeefa37c26d60345984d33755e27c163c69b7db0886ae13e2875bd6cd9c4f69" + }, + { + "kind": "file", + "path": "img_4553.jpg", + "sha256": "7086568452216fcc7cfe78c29d75357af3516abd737ac24f7e663ab89e63cc79" + }, + { + "kind": "file", + "path": "img_57.jpg", + "sha256": "50e5a96e9da367fad278181079a2ed4860cdd7ea466893b893d9faa06faaa627" + }, + { + "kind": "file", + "path": "img_2122.jpg", + "sha256": "9aa8acf7d1471c5846ffddac41da83a7d5bf2a95d22591787430b4689a7ce464" + }, + { + "kind": "file", + "path": "img_4235.jpg", + "sha256": "e9f34722f6d9ff13efde8df79399ae18f1def3f02fe677ea1ca7b932c5315422" + }, + { + "kind": "file", + "path": "img_2888.jpg", + "sha256": "db58282b99c394dd9f3e8bc4e989016b1302905711b8808740aa6d3e9ba9a3a8" + }, + { + "kind": "file", + "path": "img_1359.jpg", + "sha256": "596ea356e7c75c5b6f18e113772897608a0d350c0fe2a147d88584b10931d119" + }, + { + "kind": "file", + "path": "img_3228.jpg", + "sha256": "c839c752966336225b8527b649671dd78e99879197d97f41dbbb6334acb771da" + }, + { + "kind": "file", + "path": "img_4547.jpg", + "sha256": "7383415f601c36a0cb636254c0ce1e864bbbebbcb7adf790663feda271991d3a" + }, + { + "kind": "file", + "path": "img_43.jpg", + "sha256": "d0bf24a8cd189a3b5625418777cd13f01af0e56319697018c9fce0b6913ef793" + }, + { + "kind": "file", + "path": "img_2136.jpg", + "sha256": "74cbb85c48df2363d88cc3180fce2d51932ac0e6f8d22525c059f71f370f8144" + }, + { + "kind": "file", + "path": "img_150.jpg", + "sha256": "9e238dd0c7427a6be5184f0180690bb612a8b50d9f1f8a6d8e37f46c835db112" + }, + { + "kind": "file", + "path": "img_636.jpg", + "sha256": "694c82c1f60c39837ed5eafe2e199ce8010ecc2a77e23135b0ae6b6b3bcb2e35" + }, + { + "kind": "file", + "path": "img_622.jpg", + "sha256": "57fe697117e69765bf7435b14940c144e9bc4e8fa2d361e4c1bfd87f25fc39fd" + }, + { + "kind": "file", + "path": "img_144.jpg", + "sha256": "45933aaf9710b3ea1fed28c3079f258586890e4a010bcecd20f9824b56bec6d7" + }, + { + "kind": "file", + "path": "img_2485.jpg", + "sha256": "d35f3d6187fe13e29be2d58f0c1054fdd1b7d4a48acdafdec945169c0e6396f4" + }, + { + "kind": "file", + "path": "img_4792.jpg", + "sha256": "a4f466f13255dbe40fe87de1733909f9738524144c1ca65bc7a4343ebb537e2d" + }, + { + "kind": "file", + "path": "img_1832.jpg", + "sha256": "3496d3d1e1bbfb55fc2758a6ae86075a111e1f7bb757b7e4d2260c0eaa926b0b" + }, + { + "kind": "file", + "path": "img_1826.jpg", + "sha256": "fef30a8f22440dff927837c7203223d0caadfa1307cc201f3092fcd3863376f3" + }, + { + "kind": "file", + "path": "img_4786.jpg", + "sha256": "f1719c36a69664456549fc63b3757dc8b66acb004e02ac2414280827d28a0e87" + }, + { + "kind": "file", + "path": "img_3957.jpg", + "sha256": "ef12e550eba53436604f908d304e493754f0259fd9036a22d4cc17fa764d7e13" + }, + { + "kind": "file", + "path": "img_2491.jpg", + "sha256": "3aa87e9da9d3275c10a6d5829b8394332d0c0e147b6844779d2b60a988d44483" + }, + { + "kind": "file", + "path": "img_178.jpg", + "sha256": "d95c0a052a954df71fa2f0a126246c7a526192a6c3c91d6b4dede1c46c4d1beb" + }, + { + "kind": "file", + "path": "img_1198.jpg", + "sha256": "6a101f40ec59d2316190d7a998c1a684ffb3007cf4a9d0dcd49c9778f880b123" + }, + { + "kind": "file", + "path": "img_1173.jpg", + "sha256": "a44b29bc3ac0f282c28ba690c6ed8c80e82ccf3b7a8172580e55c184d68363fe" + }, + { + "kind": "file", + "path": "img_3764.jpg", + "sha256": "1d3b90bea97fbcbc61adc47f7ae98f9e962832e182dfbe23f8b00d4f55a27df1" + }, + { + "kind": "file", + "path": "img_193.jpg", + "sha256": "5c3ce7176c438dd507d119ef80943f78eff3c59ef404291bfdbf4e15ceff74e2" + }, + { + "kind": "file", + "path": "img_3002.jpg", + "sha256": "654682325ea456a6181b9621f8b18208df93bead8c7f74427c13b333fd32d125" + }, + { + "kind": "file", + "path": "img_1615.jpg", + "sha256": "ac262fa6fe366c3fed9577562bbe1377ed35f56668f5938fa6b5adf6c67a7a39" + }, + { + "kind": "file", + "path": "img_1601.jpg", + "sha256": "eb9ce32b1caddbf5f8c71580586f2a7befae23ceee5fd30f8785968bc217cc96" + }, + { + "kind": "file", + "path": "img_839.jpg", + "sha256": "4334e8e5284f512a9b678f9e6ea00f7535c9a3e8124023ff5a68612d2ffafdc4" + }, + { + "kind": "file", + "path": "img_4779.jpg", + "sha256": "d875407fead94038bff0598affb5795ece009ae7a3827f81a2e9a966f6763882" + }, + { + "kind": "file", + "path": "img_3770.jpg", + "sha256": "566305ef97ac3bc902893c997d9d33a86ae1028a6afe174f6b9858e9d0641fe3" + }, + { + "kind": "file", + "path": "img_187.jpg", + "sha256": "e3439c0bcfb182b4fcf92c1f5ebc8aaca6ae7ae1ede0ef21de7fcc4429f0a59f" + }, + { + "kind": "file", + "path": "img_1167.jpg", + "sha256": "f027ef6f57628c7419f8ba9d458aa47b534e9774a0de87e6a87f62f0920867dc" + }, + { + "kind": "file", + "path": "img_3758.jpg", + "sha256": "2fb594a2ef7f344b54182732444c17deee7126c8e25cb9b2b482e677c1df66ac" + }, + { + "kind": "file", + "path": "img_4037.jpg", + "sha256": "2185c49d3b93c26b86eba4d74c4f6bfe56a7f0ec6f20da8aa6134faa53f9ea02" + }, + { + "kind": "file", + "path": "img_3980.jpg", + "sha256": "64355b503c5fa33e1ea9288304d06cdaf804614fdad789659f585eaf4507635e" + }, + { + "kind": "file", + "path": "img_2446.jpg", + "sha256": "7cc50302c25df9b62e09188a933eefa7e1d2b301de6bac4e521e0e5f3bba086e" + }, + { + "kind": "file", + "path": "img_2320.jpg", + "sha256": "09184d5d5effc689b08188fd93c841f3fb0d0aee69976d6be41d0d6dc1e62658" + }, + { + "kind": "file", + "path": "img_811.jpg", + "sha256": "caae35dd67bb7bb9a07a83124154b2f52798f061abb56285d078f9584c8bd13f" + }, + { + "kind": "file", + "path": "img_4751.jpg", + "sha256": "c5613bd0d43187967ceea60f0cce7e0f2df86167ddd4e605853503580f15b70b" + }, + { + "kind": "file", + "path": "img_2334.jpg", + "sha256": "e3a39d61412a529a01a69f1b3e5816b526fe288aac5a9178580b7c3e481704b0" + }, + { + "kind": "file", + "path": "img_805.jpg", + "sha256": "78148ce84bec847279ee32bf24a75474aee68a0d4f2369fc9527d5b904663890" + }, + { + "kind": "file", + "path": "img_4745.jpg", + "sha256": "3259d92afdb9b736ce0d9b17406e7fec149b8237abbbcfb19642879514949cef" + }, + { + "kind": "file", + "path": "img_4023.jpg", + "sha256": "dc2a8eccda6fef0d556faa6e8d70c07b88c0cc5f57047b1f3510833235bd94d0" + }, + { + "kind": "file", + "path": "img_3994.jpg", + "sha256": "913f152a8a37b6a7f7aa0559216f312ded9a27edd4fcff5fe91a8ab91f8560f3" + }, + { + "kind": "file", + "path": "img_2452.jpg", + "sha256": "3120350adf552ba670d3b8ff196208bcc2b41aff0893e2905910d22a0bf4d437" + }, + { + "kind": "file", + "path": "img_4802.jpg", + "sha256": "a53ad51eeb7b2bd1455e356532dad5bfce2f36e6cac7afdd0e3aed3a712e8022" + }, + { + "kind": "file", + "path": "img_742.jpg", + "sha256": "2f267ea82b0593b8627bd745a743a56d5972966394dd36d551d4bb819e33cb34" + }, + { + "kind": "file", + "path": "img_756.jpg", + "sha256": "886700d1335e65e12941f78b646d03b5d0e534b1a91c02cfb52fac499537e2f8" + }, + { + "kind": "file", + "path": "img_4180.jpg", + "sha256": "8f668662478e63cf63705a44d4a0688abf9c490f5f89e713c5ee9f6723830694" + }, + { + "kind": "file", + "path": "img_3837.jpg", + "sha256": "9ed670bde06da40b69207c49d2fa5026a079558e713bfcc731ff852ee36ee0a1" + }, + { + "kind": "file", + "path": "img_2297.jpg", + "sha256": "cd0fc203fbd0855afcff91eeb31ff7c5e4e78ded0952cb4210a0efc241b54b16" + }, + { + "kind": "file", + "path": "img_1946.jpg", + "sha256": "90c317303d763bcc3fa49212d5cfa95cb55dbe1ad064cb0d98e7594b8b5d9a0a" + }, + { + "kind": "file", + "path": "img_1952.jpg", + "sha256": "6298a33d1774aa66581812d82243b526a77f7eee90499402f55fbd7f782c84b4" + }, + { + "kind": "file", + "path": "img_2283.jpg", + "sha256": "dcf1bd3ce4bc8f46c3a215337c79da3c28899efd26c1c48f8cadde9f30098a99" + }, + { + "kind": "file", + "path": "img_3823.jpg", + "sha256": "8f34b69670fc5dfb1ba6700e75652a6249b1745f225b18fe7f8e65eb7b5f8596" + }, + { + "kind": "file", + "path": "img_3610.jpg", + "sha256": "caa3d7080cae8f06ef2bf94d171698a87ad7bbbc7bc413c432fe95627856a8c0" + }, + { + "kind": "file", + "path": "img_3176.jpg", + "sha256": "830f3d031dc6255aa629268330ab786059f8f8e7140b808cc16a69ba6812d21d" + }, + { + "kind": "file", + "path": "img_781.jpg", + "sha256": "00367a71fc3f6543f2281049880e2f3f72078d50cd21e25e54767d6a35376a11" + }, + { + "kind": "file", + "path": "img_959.jpg", + "sha256": "034c89bbe61468a0d32d36197feb7c6e3bc3092775afa2308da1c8f2d6a81522" + }, + { + "kind": "file", + "path": "img_2268.jpg", + "sha256": "50dc097cc13194376b424260bddfd28862439fafd78323c90298fb92f22ef5c2" + }, + { + "kind": "file", + "path": "img_1775.jpg", + "sha256": "6817b46900d40218e3571486841a46fcdaa1be826bdfe7a9b18d7c06ba6dc2df" + }, + { + "kind": "file", + "path": "img_3162.jpg", + "sha256": "5cfe19e0d7ce2287dae58d8fa2f0efec07fe36a1477744be87938ac8d8e89e9a" + }, + { + "kind": "file", + "path": "img_795.jpg", + "sha256": "d3770942ff07bb1d6fe8008791ec49ac2ab47a9ca7e84134750314d73da3d979" + }, + { + "kind": "file", + "path": "img_3604.jpg", + "sha256": "cff47ef1d8b32776a44768a76cc57145a39c0b09b314060515ac95bf4804fd6c" + }, + { + "kind": "file", + "path": "img_2532.jpg", + "sha256": "d9069b20b4ef7e7f867fda90b932898abbafc581240ad489fee08acc3c113726" + }, + { + "kind": "file", + "path": "img_4143.jpg", + "sha256": "23ac8cc844cbb51d71b0b7602765a878c5344931eefdb52a704ec06acb9ab130" + }, + { + "kind": "file", + "path": "img_1985.jpg", + "sha256": "463f1128d6a4a3f16401acb2f841db1315df4ecfc0f062052a0452e2cada2d1e" + }, + { + "kind": "file", + "path": "img_4625.jpg", + "sha256": "f71e8d27cef735bf745fc57343fa1b4898730f6a7c18f40dd7de1d5f7e7af28f" + }, + { + "kind": "file", + "path": "img_965.jpg", + "sha256": "356ea180f5a3ed2e0d236ac9b76130f186ab972b1b3eb583e4305b3875010327" + }, + { + "kind": "file", + "path": "img_2254.jpg", + "sha256": "fadee563ac51472d21ac64c1edf3ecbea772afc11f38d01aa58e204f359fa3bd" + }, + { + "kind": "file", + "path": "img_4631.jpg", + "sha256": "c6ef2b9c7cb2f85ea5600ad3e378514bb7225b8013b8b508665597e01d993235" + }, + { + "kind": "file", + "path": "img_971.jpg", + "sha256": "b70a01c07627384374f94943a92cf5a37425309ee0c8e434edca039dbaee0c39" + }, + { + "kind": "file", + "path": "img_2240.jpg", + "sha256": "4f29551b7da09600537801b3a414dfe6f2af9025c4e8e2818bd9357201a7c3e4" + }, + { + "kind": "file", + "path": "img_1749.jpg", + "sha256": "c2f664c601b2e3126cc73034b1041c5fe2f48813185481941c20e4cb152c0c1f" + }, + { + "kind": "file", + "path": "img_1991.jpg", + "sha256": "df75f251c9039dd3c5402f9465ab900ace5afc6ecf2cc50d66707c8fe5607e42" + }, + { + "kind": "file", + "path": "img_2526.jpg", + "sha256": "f20bb17fe857bc6fdce7d1a70ea5aaee015c77bfe4f960e59582be64b3d0bb4f" + }, + { + "kind": "file", + "path": "img_3638.jpg", + "sha256": "924d78960c56f0e544ecbd727cdfcbbbfa9b344f5b21e2f487feec90f45250d9" + }, + { + "kind": "file", + "path": "img_540.jpg", + "sha256": "eefcc5868eca41f716b60412f9e06f39838fa94d83e0b21fed0d44458c6b2230" + }, + { + "kind": "file", + "path": "img_226.jpg", + "sha256": "8084e96bd9fc9f328133380d2d24c5e88263d30ca37237d4ed46e8afd915df2b" + }, + { + "kind": "file", + "path": "img_232.jpg", + "sha256": "4797f692184d592426d966701c09df8e987e98832594b7b8f59c12ce385b2172" + }, + { + "kind": "file", + "path": "img_554.jpg", + "sha256": "ea2db77418a2d7d31d340aa3f403716942eebbf8ff79c5ab2b0f89afc4a9486b" + }, + { + "kind": "file", + "path": "img_2095.jpg", + "sha256": "fa80c1479b4aeb532f4d18ce952b883501f637191cd6ff64458c8d32e0593d3a" + }, + { + "kind": "file", + "path": "img_4382.jpg", + "sha256": "c1e0f7936d061630783eb30ce4e165e6f9373518e5c106b0121cac4dfdcbdd1e" + }, + { + "kind": "file", + "path": "img_4396.jpg", + "sha256": "5b87dac18a829f905791b7519d45e6960173a6e6dc3ed8cbf6d137d44cbc8b5e" + }, + { + "kind": "file", + "path": "img_568.jpg", + "sha256": "b44b987735dc92aab6cc8f8683a738b0ce625d598f20aa6b92c89a0c69ef5e78" + }, + { + "kind": "file", + "path": "img_2081.jpg", + "sha256": "57143e1e19968b9a3299257b3dbf6111ac8dd7fd2da16bb8c3b3e88caa1d0dd2" + }, + { + "kind": "file", + "path": "img_1588.jpg", + "sha256": "70b3d9b3670dc1a1f2d6fcbad26c3fca94300afd40a4750ffe7c94b787ea77f0" + }, + { + "kind": "file", + "path": "img_1563.jpg", + "sha256": "ea8dd0dc98cea073bb06a51eee902354693a2c05d3d24be32173d15eebd9fb90" + }, + { + "kind": "file", + "path": "img_583.jpg", + "sha256": "0ebbc71034708e5d5569642330d1e1b71679aeb5c7d42c444296bc125d93b821" + }, + { + "kind": "file", + "path": "img_3374.jpg", + "sha256": "2c68208f6d8b927db6b71da61bfd64386f3ea58f99aa217717f78c7ec0461aef" + }, + { + "kind": "file", + "path": "img_3412.jpg", + "sha256": "bd2b7b88519f19368b73caaff3f05e7be30bf3ffc437278921b3b8cf2d55b553" + }, + { + "kind": "file", + "path": "img_1205.jpg", + "sha256": "aadefad354d48b5ac5fa3cf62212dfc51034416cae037c949eb12e2732ccbc41" + }, + { + "kind": "file", + "path": "img_3406.jpg", + "sha256": "24f9572efa5e12da0073c011aac153586b869e69ce8b51d8094575597a2d98b3" + }, + { + "kind": "file", + "path": "img_597.jpg", + "sha256": "8c2637ddce881c152074ed3a2e3277dd44a8361238ec878f73883dcca6cdeaf4" + }, + { + "kind": "file", + "path": "img_3360.jpg", + "sha256": "8127f700d1d7fbe95b19e9e3df24a5e796ca69ff92b5cb33e63b3a652d013265" + }, + { + "kind": "file", + "path": "img_2056.jpg", + "sha256": "da7a0508699ca3881b43d9e64299ae0c234e6d8859a662c299cd80b8185b652b" + }, + { + "kind": "file", + "path": "img_4427.jpg", + "sha256": "45af00d376c32cf277c402578975decd76dbd78431d83f487dcab8bb42f680a2" + }, + { + "kind": "file", + "path": "img_3348.jpg", + "sha256": "507aaf40b96d3e5bf9a9d7a36fccbda70d7f77e695d02153bde5990f49b375d7" + }, + { + "kind": "file", + "path": "img_1239.jpg", + "sha256": "da11008e4340c91468616326ceff92cc3a1dddf67c5704f878032ea8ee2c2601" + }, + { + "kind": "file", + "path": "img_4341.jpg", + "sha256": "93cc52a4d8032def54a53e97d702e77efaf03ebd361535d98d4c04018a22ea17" + }, + { + "kind": "file", + "path": "img_2730.jpg", + "sha256": "2845e035025f998c07ebe692e300bf06d4e75047fa065074e8fb1bcb3c563af8" + }, + { + "kind": "file", + "path": "img_4433.jpg", + "sha256": "b8417e68bc50d6558115bbc29767f83d9ef356d6296b3ad1c485587ec2f24b8e" + }, + { + "kind": "file", + "path": "img_2725.jpg", + "sha256": "20f1338ace5e65329bf72d9723aca4ddefa479f5ffccbd6d86071b2a323e4fec" + }, + { + "kind": "file", + "path": "img_4354.jpg", + "sha256": "cc76e8295ed2830283f26bfb816d1ee7822bff915a1479b600147c3b8403438b" + }, + { + "kind": "file", + "path": "img_4432.jpg", + "sha256": "e330913a19678878e40050c04d6c309205506bc9175b69145d1ae1f7ac6eaa28" + }, + { + "kind": "file", + "path": "img_2043.jpg", + "sha256": "d5e72852ab9e93a836bda8e4c2bb74f612a0eb349d6abfdf08fb81f90c6d6c59" + }, + { + "kind": "file", + "path": "img_3349.jpg", + "sha256": "4784efe6a2a9369361e066e1b986c32b76d298fa3fe68e7c87ca600f67ef0c54" + }, + { + "kind": "file", + "path": "img_4426.jpg", + "sha256": "d4d9695c6c42150263a6e8563f22347b0cacd3598a1ba8d358813369ae2f48bb" + }, + { + "kind": "file", + "path": "img_2057.jpg", + "sha256": "0f62c8dc5245c9f894fda3a922d5e3498a5bca3fb478a5ef7027c3856445177c" + }, + { + "kind": "file", + "path": "img_2731.jpg", + "sha256": "7713066b579774b092e1ea04c7253f8e480d15b1da717bfd565338606a56caee" + }, + { + "kind": "file", + "path": "img_4340.jpg", + "sha256": "7db6aabc10a8a55bd3ec54fb8a77dcbd43f67e880368a8546a812b6b10b12489" + }, + { + "kind": "file", + "path": "img_1238.jpg", + "sha256": "a01e83cf8edd528fb5c41c4281acbc8a68631c36fdd46825501974f32743ee7b" + }, + { + "kind": "file", + "path": "img_2719.jpg", + "sha256": "09338cdf197b3d32b686ba388140bbebcf71571a38c21bbd3641dc9e5422e1ca" + }, + { + "kind": "file", + "path": "img_4368.jpg", + "sha256": "e5d42b6939464cdb2fb285a1b1760da29aab0a765abc6505a4a9dc70b19f30e8" + }, + { + "kind": "file", + "path": "img_1576.jpg", + "sha256": "0fc745b0a3bd4ad52f2057e9fc643586e3d8d3af07da2cccef9d546da059b484" + }, + { + "kind": "file", + "path": "img_3361.jpg", + "sha256": "cef733743f89197b2d981432118984b5c5f52dda30739e19371a7201b4d90ea4" + }, + { + "kind": "file", + "path": "img_596.jpg", + "sha256": "06bee582c9daa20758efea7a22e4444a470346df45831db80343205488a905c4" + }, + { + "kind": "file", + "path": "img_3375.jpg", + "sha256": "e48d75c4cb0811dc8967254923f82a70faa90fe86f840465a5598f6d041b647c" + }, + { + "kind": "file", + "path": "img_582.jpg", + "sha256": "0c9a594ca0da7231fedcfad6f49c985797920f765e36c322380ea4873dd29afe" + }, + { + "kind": "file", + "path": "img_1562.jpg", + "sha256": "4376aea8ed8fb9d580fd3c4d2305840aa9cde6da80c8c6bfd7b786ffccf069df" + }, + { + "kind": "file", + "path": "img_1204.jpg", + "sha256": "26d76b390d0667db994404f030d03c22aed779da4e3844415d172b32b469a32e" + }, + { + "kind": "file", + "path": "img_3413.jpg", + "sha256": "266f3c061a8acae93c023707bee62e57d651bdcdffb9a2fda6982fd8016fe177" + }, + { + "kind": "file", + "path": "img_4397.jpg", + "sha256": "00c8d697fdb2ee230f675286c9b59f4f42921bc7118b2e2a057c0b58b40400cc" + }, + { + "kind": "file", + "path": "img_1589.jpg", + "sha256": "0615413dfbb34a919aea40401c74c599db967d5ee825e6929f59719ce80006e2" + }, + { + "kind": "file", + "path": "img_2080.jpg", + "sha256": "9c19bcfc38b0a5af9445e20c4fe6eea79d3aac2798749c682c780fb72a0f2d9d" + }, + { + "kind": "file", + "path": "img_569.jpg", + "sha256": "eaafa2583aedb9d0aec256c5fff52444759ffd25fef1bdd6743e7c1e4bd3474f" + }, + { + "kind": "file", + "path": "img_2902.jpg", + "sha256": "8a0639d0455575d38c5f83355c6a559d6befb36c33aacf58e3b3bc93ade68400" + }, + { + "kind": "file", + "path": "img_541.jpg", + "sha256": "15658296f5d0fae2c30a7b9096d4bef077eaec0e39f28a817577496e53ced170" + }, + { + "kind": "file", + "path": "img_2916.jpg", + "sha256": "1cc2f5168cb89cccaa3f5c7f4c46b4a87eccabaa6a14392dbf6028c96476a623" + }, + { + "kind": "file", + "path": "img_227.jpg", + "sha256": "c8f5f7599e7038ba498788c9b431b55bd07f2ebe1f147e9e5088e21b9342713e" + }, + { + "kind": "file", + "path": "img_1990.jpg", + "sha256": "905eb0ae1f7002f6cf6f77b3777bd2c7b4caaabc56e1ef76ebae5d5a443bf8e4" + }, + { + "kind": "file", + "path": "img_970.jpg", + "sha256": "9dc2d3b62fb0ae361ad8e9e7bebf63d77b1770cfd144bc452362278f2ab4e0a9" + }, + { + "kind": "file", + "path": "img_4630.jpg", + "sha256": "5d66ac955c8bb14976f4204cef749a8c32146559fc9f83b4363dd36082b52688" + }, + { + "kind": "file", + "path": "img_3639.jpg", + "sha256": "e66593456f79aff3c1908ba77babed101139b8c0b0f821332ed1f44d8d94e554" + }, + { + "kind": "file", + "path": "img_4156.jpg", + "sha256": "fd83f3e237f03e2c2c73186a63afbd1caba8686bbc21998452437326831e8daf" + }, + { + "kind": "file", + "path": "img_2527.jpg", + "sha256": "eebf1c462619fdeb9cbdb1677566b51492638ae9ec1896c84a672217e217d834" + }, + { + "kind": "file", + "path": "img_4142.jpg", + "sha256": "e3c5c348105dbd50bd198594f1c800009c8e9b095aba3327acbe20d270d2f46d" + }, + { + "kind": "file", + "path": "img_2533.jpg", + "sha256": "9fbe50de2ad803fe07b892d72b919aaf47a77f07ff8df6be158940104ff1bec4" + }, + { + "kind": "file", + "path": "img_2255.jpg", + "sha256": "4e6b80c16ad762207ede88f85e079255ca2f4e539a726dd7de0966eae7670a6a" + }, + { + "kind": "file", + "path": "img_4624.jpg", + "sha256": "ba077c8cd8bf1dd58612363f12c5bbf7c2c76bae507bf01dcda9b933a758ca49" + }, + { + "kind": "file", + "path": "img_1984.jpg", + "sha256": "2d13b7dcf5791432f904b9bbcec055b714350056863cf69e3ef2c09275212202" + }, + { + "kind": "file", + "path": "img_794.jpg", + "sha256": "3f4890b965aee3e331728fb2acc6b0c948814e875d96054f1027673ed627ac38" + }, + { + "kind": "file", + "path": "img_3163.jpg", + "sha256": "e1fa4396b437ff669513e7d6253a649380980ca1f3b06100adc306f979043e01" + }, + { + "kind": "file", + "path": "img_1774.jpg", + "sha256": "0ad14b4de5dc34363e004ff2a7d92dc272726b45d8e56104d477da1246109eeb" + }, + { + "kind": "file", + "path": "img_1012.jpg", + "sha256": "9432fbf58ae9176707bfe39d308a61de4cad09a62b0542e748905005632b83c4" + }, + { + "kind": "file", + "path": "img_3605.jpg", + "sha256": "5804de890f95a4b9e799dbba6f28c48ffe1ac2c5134b78751b81986aa11fd119" + }, + { + "kind": "file", + "path": "img_3611.jpg", + "sha256": "ca5b65ed9d9b00060e8418317693de9a8ad02e4396b71f011ae28a935420183e" + }, + { + "kind": "file", + "path": "img_1006.jpg", + "sha256": "ae69f7459ce4519462e6a864e4002cc8bce9215bbfdd341fdd42462b19edd279" + }, + { + "kind": "file", + "path": "img_2269.jpg", + "sha256": "d7af39e0ce815358f8b89d81136f7adbdd70378f5cfae3780ea776547741fc8e" + }, + { + "kind": "file", + "path": "img_958.jpg", + "sha256": "92ab94820508f4b6c8ca464c18db9c9df1af9b5df695a547e9ac37f33bb612ad" + }, + { + "kind": "file", + "path": "img_4618.jpg", + "sha256": "c04be3f695e8a25d47e2ec227f669226e871153e8ad1d3d16fbe3fcb73f5b006" + }, + { + "kind": "file", + "path": "img_780.jpg", + "sha256": "536665cad8d0cec39daa820595087ca8a1dc5fefc8478b1b2aacc99068b42429" + }, + { + "kind": "file", + "path": "img_3177.jpg", + "sha256": "b6be9124b6767696a813f2de99955063dc946c03ecb05636b5f92996eefde32a" + }, + { + "kind": "file", + "path": "img_2282.jpg", + "sha256": "5f029b35c9a56ecfb007a5188bf17c8d58fd11606974e57815cab38e21af7362" + }, + { + "kind": "file", + "path": "img_1953.jpg", + "sha256": "d88113f6e65e69f968505298c47a215ec6c4566754f8b800f9552478155eb4a1" + }, + { + "kind": "file", + "path": "img_3822.jpg", + "sha256": "498b9459c9e90ed83f1c31477ef12a0c34e245ec382f360bb956f28f373222f0" + }, + { + "kind": "file", + "path": "img_4195.jpg", + "sha256": "c5f65e78d6ce6d836f40a7f1206caafc7b67f491d13c1cc94015c6392a5f7eeb" + }, + { + "kind": "file", + "path": "img_3836.jpg", + "sha256": "a7c27e7a5f2c0772a1991946bc254843d09c331c85fafbc5c4f1e6b58228a307" + }, + { + "kind": "file", + "path": "img_4181.jpg", + "sha256": "0cebbdac4dbbf785d691b8fefd4b59eb75bef4c2bda37aa7e35232ee7e888ed8" + }, + { + "kind": "file", + "path": "img_2296.jpg", + "sha256": "600c4a917e0fac4ff0c4750fddb4b97ce18f17d84bbfa23b2ef1adfb05d5d7d7" + }, + { + "kind": "file", + "path": "img_757.jpg", + "sha256": "70652da4a19584a263e550a9d8d3273f50b8788904aa0cfa9f59d12dc5048c54" + }, + { + "kind": "file", + "path": "img_4817.jpg", + "sha256": "1faf15c8ba264131bb4146a20f9b57d0021fea028d29274f72cadcc2aae204e1" + }, + { + "kind": "file", + "path": "img_743.jpg", + "sha256": "b834676f1895010a0deefee636ba94f1142acdd6aed65511ee4d1393a6897fb2" + }, + { + "kind": "file", + "path": "img_4803.jpg", + "sha256": "9c37d8f614f41c11944bbace81d9c86c99cd590486d64489fb541c59a612a71b" + }, + { + "kind": "file", + "path": "img_4744.jpg", + "sha256": "4d5293510993802df403486fff5d3e2588b8e468e592b84935c55c5cdee1301c" + }, + { + "kind": "file", + "path": "img_804.jpg", + "sha256": "57d48e49d65aa9dc9ec49f37cdb0e7c15e1d920f94cf99823c2e9029aa61d418" + }, + { + "kind": "file", + "path": "img_2335.jpg", + "sha256": "92c17496721dc1520ab6ce1c06e768e08ff4e3b0d6e94cbfd842063ab7b2f386" + }, + { + "kind": "file", + "path": "img_2453.jpg", + "sha256": "676ee072da912ceee4360fb93e0a28a5318c33c4f8ff4cb4f7a5679281dc05c8" + }, + { + "kind": "file", + "path": "img_3995.jpg", + "sha256": "e43e7fa759baeffb5f2eae07ac113f8a24888d289ab4d91e1f6a28b276bddd62" + }, + { + "kind": "file", + "path": "img_4022.jpg", + "sha256": "b56f7ba9eb432183149c4c92f4e0b7cf42a2a79dda49b441388546820d2c4b8d" + }, + { + "kind": "file", + "path": "img_2447.jpg", + "sha256": "abb83def8f5955625960b05c290e3dfe4a7b3fa4544d44b61d599c0cd48b77d0" + }, + { + "kind": "file", + "path": "img_3981.jpg", + "sha256": "2aefdbae3ae84d7496aa494e02d443f7d0b0257084aaaa486833738335959640" + }, + { + "kind": "file", + "path": "img_3759.jpg", + "sha256": "7d871a2b777b7fea7a2c4b95ecfd4da5aa8ac1b2a4eea25e4c597999cf67ea0b" + }, + { + "kind": "file", + "path": "img_4750.jpg", + "sha256": "89a4fdb39553dbc2660fb394a577e4be674e153f562753445a388f508f4c6b6a" + }, + { + "kind": "file", + "path": "img_810.jpg", + "sha256": "ea90f11fb831bdc8d132fff40052260f06e68771cc147cac4caf5ad3aca9892b" + }, + { + "kind": "file", + "path": "img_2321.jpg", + "sha256": "4f27315235acd48719abde2c6c75b4d6e2afed3e363d065e39344b8cf878caeb" + }, + { + "kind": "file", + "path": "img_1628.jpg", + "sha256": "d2abd5ee7dcfba3fcd33cfa35565319228a23b04fb0f3b2e4e1dbb9600844927" + }, + { + "kind": "file", + "path": "img_3017.jpg", + "sha256": "6feb535d393ca82ab808b01f17cca9d5054650205e60b11f37cf860521f515dc" + }, + { + "kind": "file", + "path": "img_4778.jpg", + "sha256": "8503b804e2f14e3190cdb0a0afff5e92f285d599d659fb4825c465bdae8b530d" + }, + { + "kind": "file", + "path": "img_838.jpg", + "sha256": "28db5ad8ae35ec15bd5d0cf171096854e33d533bfd4c926577d977be1474a1ea" + }, + { + "kind": "file", + "path": "img_2309.jpg", + "sha256": "9f35f3fcd55bfcbdbd46ba70ffc1d11e495a0755f9ed49f7417ada10e8a5610f" + }, + { + "kind": "file", + "path": "img_1600.jpg", + "sha256": "f1cdad2e329c09097ddfba7fcdabcdfaaacb67d34ac4ae766fdb347dc72a0289" + }, + { + "kind": "file", + "path": "img_1166.jpg", + "sha256": "f9864b0ed0cb808fbfa86b005fbf6771ccc8466feff9df50242f40f950834900" + }, + { + "kind": "file", + "path": "img_186.jpg", + "sha256": "0542dec689fe6997781d0a9686e6325410435056af93ca1d8274cefe1a9218e4" + }, + { + "kind": "file", + "path": "img_3771.jpg", + "sha256": "cf3d8d5b38cc6ff1124d021b4dec240cef0ef180cec3cb35187e4b80d827f78f" + }, + { + "kind": "file", + "path": "img_192.jpg", + "sha256": "45498c1001f8d351f266627e01ff6987c58142c1bf4cea738c9577220f8c97ab" + }, + { + "kind": "file", + "path": "img_3765.jpg", + "sha256": "01303450d733f58d591de159905032436deb7181c7189431e2510c74ef6c37ca" + }, + { + "kind": "file", + "path": "img_1172.jpg", + "sha256": "69d95c947f12db5f200fe45a8ac54ccc69f3be49bad78c9cc5c9176948333aaa" + }, + { + "kind": "file", + "path": "img_3003.jpg", + "sha256": "086f69c320f17e846a10826a208995af69e49c0d38b5771cc60783419627e0c7" + }, + { + "kind": "file", + "path": "img_4787.jpg", + "sha256": "1adc39204bdaa21752c49331d411b588d62aae6b5e5d7457f115372cbabd8df4" + }, + { + "kind": "file", + "path": "img_1827.jpg", + "sha256": "7948ce44a61cf6d82bbef18236ab675f11fe7514872e094eedd6539533858b3c" + }, + { + "kind": "file", + "path": "img_1199.jpg", + "sha256": "d86df72c1cff36315f27622b8c8dfe216c8b5ef4b68892d097bd39c2a1926ca4" + }, + { + "kind": "file", + "path": "img_2484.jpg", + "sha256": "f9546a7de164b43a9aada9c621c12a1a7e16e183605cebf2b093ceb4c9855af4" + }, + { + "kind": "file", + "path": "img_3942.jpg", + "sha256": "ea1a304a60f5be45028aab47781398d073d7184e2aed42c0ea6a2ae97b7b4dfb" + }, + { + "kind": "file", + "path": "img_1833.jpg", + "sha256": "f97d0210d1bfc865cff328ae8ddab2ee31cd1d60546bac1f5566e47260912451" + }, + { + "kind": "file", + "path": "img_4793.jpg", + "sha256": "7861bcbdf9669c70a1acf381d942b82fbf2628180802aa92a5125f7c393d64ed" + }, + { + "kind": "file", + "path": "img_623.jpg", + "sha256": "99d1f3cfcd9cfc8f43e086271576fdb308201ff32a917389bcf953bf1ed23378" + }, + { + "kind": "file", + "path": "img_145.jpg", + "sha256": "46830d49e11e91781490ffdc35318519ad21df7e6140283edbfadfb9567a5689" + }, + { + "kind": "file", + "path": "img_151.jpg", + "sha256": "46cd8176f6d5b402099ba82a67a56279c0077e6457f3748b279a73c248102596" + }, + { + "kind": "file", + "path": "img_637.jpg", + "sha256": "b999f84a3f18f241b2a780137301e32c3c34088f56866079c56ee0be0186c528" + }, + { + "kind": "file", + "path": "img_1358.jpg", + "sha256": "be50a32041fe4dd2e876e00455916c7ef7a7e08d0061ba3fb11645f76e36874e" + }, + { + "kind": "file", + "path": "img_4220.jpg", + "sha256": "6e05d64101ff2b3ac5b6994ecca2608309de4e1ad935113f32f2764901977e0f" + }, + { + "kind": "file", + "path": "img_2889.jpg", + "sha256": "3836de063992051bdb227603a7d06d348860722a7d3cd3af3205a0290bac9a92" + }, + { + "kind": "file", + "path": "img_2651.jpg", + "sha256": "79fe0b4a0db07bc7f21fa8c643e15c9af6c716c09636ab892d2ae88de6ae4306" + }, + { + "kind": "file", + "path": "img_2137.jpg", + "sha256": "a21bb30660c5aeb759888f85516ab764830c73dc9709eec78a8eda88f8019f34" + }, + { + "kind": "file", + "path": "img_42.jpg", + "sha256": "ae4fde31e0f630072b4ccfb79761677f5a62ffe2cfa172df0175242dd373947e" + }, + { + "kind": "file", + "path": "img_4546.jpg", + "sha256": "c3498f5138d0bcf752f752550db37ce90c1074c33d990d24314a662effeeb9e1" + }, + { + "kind": "file", + "path": "img_3229.jpg", + "sha256": "4701c28fec61023c13254ea5eee373b7149dfefd246fa9158feb6877317c47df" + }, + { + "kind": "file", + "path": "img_2123.jpg", + "sha256": "c080c5218a7f38713af80dfb3647e40baaa0e51f34ac02a523a55cee5b0ad940" + }, + { + "kind": "file", + "path": "img_4552.jpg", + "sha256": "5d572f4d441fc8b7b7f141f0caf30883a30bb2f3ad37a3580b0489e83003106d" + }, + { + "kind": "file", + "path": "img_4234.jpg", + "sha256": "3248f3dba981ea24b5ea4c5852915c8a44003c27f27e49beed03a6009ddbefc0" + }, + { + "kind": "file", + "path": "img_2645.jpg", + "sha256": "3a53f18f68f8aabfb46d5122a57bc39a760676ba5e51705d0d7f3f7bd2ab555a" + }, + { + "kind": "file", + "path": "img_3573.jpg", + "sha256": "55334b48e010339f22fcf50c4ea6e997bc196de2a5c61e99f2fa21168e01311a" + }, + { + "kind": "file", + "path": "img_1364.jpg", + "sha256": "7fcf6ed4f50ffdf234369ce3f4468abf562c091c29ea1c7db023cb33605d2fe2" + }, + { + "kind": "file", + "path": "img_1402.jpg", + "sha256": "1e8168307c130f942ee5ea091e57506cf99bbea4a94436352dd31296dd18be20" + }, + { + "kind": "file", + "path": "img_3215.jpg", + "sha256": "226c3c1d30d7cdfc320a589e13c9d7b14a0ad79fa5155f5e424e41200f4afea6" + }, + { + "kind": "file", + "path": "img_3201.jpg", + "sha256": "29a93e67c0efa0568c1a063e06965092634ac1eb0ff5c6380894f704ea207287" + }, + { + "kind": "file", + "path": "img_1416.jpg", + "sha256": "aae0912677a11ff3be182914a2ae116475b39a35fc600e76ef8ec02af6bd4de8" + }, + { + "kind": "file", + "path": "img_3567.jpg", + "sha256": "c6e108be0cf7fef22397b11f296a8d5cef0b8a674f09fd58246d2d0229a4390f" + }, + { + "kind": "file", + "path": "img_390.jpg", + "sha256": "b10fbc62a35236b7c1a04c0ba9e85c69676e0a0ffef9f7ad5870f6ef3273f1eb" + }, + { + "kind": "file", + "path": "img_4208.jpg", + "sha256": "ce385223d41d533e9fe889dde44ec94bccf43f052f5d47f7aed5e4bd5844f48d" + }, + { + "kind": "file", + "path": "img_2679.jpg", + "sha256": "e6b7f17e3a9c888c36f2cb275336e8dc4c0dbdab9a3d92dfe752674ce46ac188" + }, + { + "kind": "file", + "path": "img_4585.jpg", + "sha256": "e0f328a1ef53a57982bd193040d2e39199e3f65b0ad8e98d61dc41de54cf6608" + }, + { + "kind": "file", + "path": "img_81.jpg", + "sha256": "d8710aa50e0564403d6d145f9e9257fcf69601fa887cd6debb587ced7a13644e" + }, + { + "kind": "file", + "path": "img_4591.jpg", + "sha256": "b8b6b30437e27e9314a4a0741195010093d73ceb691f0e4c456b0cfc2f1fa488" + }, + { + "kind": "file", + "path": "img_409.jpg", + "sha256": "e3bcca833ac7575c5f94e0afbb7065ed7b08a1431c23dc4b7b464fb7556af7b8" + }, + { + "kind": "file", + "path": "img_95.jpg", + "sha256": "2c000a8963e1e5c72962d1f0b98a62c395f0c8fd2fc4398b2df451a259580ec2" + }, + { + "kind": "file", + "path": "img_2686.jpg", + "sha256": "cc59b275e843ff23ee09635a05ff01c51db711c814fde3700dd15e092370ee19" + }, + { + "kind": "file", + "path": "img_3598.jpg", + "sha256": "e8a9e751d5be52e723b4943e22ea74870e5abe7ff39e1c8cb394007ce0c699d3" + }, + { + "kind": "file", + "path": "img_2876.jpg", + "sha256": "de6e001cd57f90eb2ffb310615cd2ed6e78f595c520260cd93be5ceaf074867a" + }, + { + "kind": "file", + "path": "img_421.jpg", + "sha256": "a26a8babc99f22cce9a7a560f06dd3627f05d52b98f7dbfada0b058e2d8d2f4e" + }, + { + "kind": "file", + "path": "img_435.jpg", + "sha256": "bc1d76bedd966d391fec7ca077e7057784f94735dd8059528f7e836f5fb72828" + }, + { + "kind": "file", + "path": "img_2862.jpg", + "sha256": "46b78b80f5a4630ce0818af5feb9f7b041ba70b5b2ab9a0b7ef4cc1b35eaa742" + }, + { + "kind": "file", + "path": "img_3299.jpg", + "sha256": "a37b1f7391dabc291c2d76685997d64a4e859d2382b254a11d87eb482cf70fc4" + }, + { + "kind": "file", + "path": "img_308.jpg", + "sha256": "974e11b8edfbcfe28dc6f2b13f28705fa6216bae2faf31c902eaa729ec3380be" + }, + { + "kind": "file", + "path": "img_4290.jpg", + "sha256": "8857721b7586c8202b59f06228013bc1c37004e3dcd34cabf74aeda6d4cd8903" + }, + { + "kind": "file", + "path": "img_2839.jpg", + "sha256": "ee083d8f4d704471a3c1f428fd9c1e3f46c20671ae97e9c63b05f67ba6fa5721" + }, + { + "kind": "file", + "path": "img_4284.jpg", + "sha256": "4ce3c54a9a2bcc9eb2eb637ddcbfc64a82f569e8c2dcc8d37284eee2a5ca0b11" + }, + { + "kind": "file", + "path": "img_2193.jpg", + "sha256": "ce72cac6a1fdb68d3419e18f66f8e0c95c473a50d107711a30e220d972ae1dfb" + }, + { + "kind": "file", + "path": "img_334.jpg", + "sha256": "947bc6765b7d209a7b5bbbd5470b3f6ee2008b73b13335e8dcddf852093a6dde" + }, + { + "kind": "file", + "path": "img_2805.jpg", + "sha256": "002be275548e1d6019ad993a41bdffa2af1ef20d84547e80f5328a118a349013" + }, + { + "kind": "file", + "path": "img_320.jpg", + "sha256": "6c8aad8f9e9d6aeb73e2ac2f892f9ebe1d06df390cb5a6a5a48ba15306819d2b" + }, + { + "kind": "file", + "path": "img_2811.jpg", + "sha256": "de72df51b45706f54477adbbfbc022b9ed6ccfc2b3386c893ec4b8ee741e142a" + }, + { + "kind": "file", + "path": "img_446.jpg", + "sha256": "511c5ad823160eb37990609d746aa98263c8bee160ca7cbeff90fdc60ff46f47" + }, + { + "kind": "file", + "path": "img_2144.jpg", + "sha256": "93a8857bd73e391c82967d7ab0e6739be506ee244598f9277c3118aba3a9e43d" + }, + { + "kind": "file", + "path": "img_2622.jpg", + "sha256": "94e93a5834373830b4fa578f9cf6e3244ad99fe972835e3edc9ae7edc54f22da" + }, + { + "kind": "file", + "path": "img_2636.jpg", + "sha256": "637a5abdbe4840734e5e6bec6d90cccb8ab4c65cea488f21d8f7c7bd5d1cb2e5" + }, + { + "kind": "file", + "path": "img_3528.jpg", + "sha256": "58899dd6e990eb5dd3ed0dae5f9aa372df4c810ed2bca03fa5dc939ba8864ff1" + }, + { + "kind": "file", + "path": "img_4521.jpg", + "sha256": "21d0f2aa62b7123957f66ac482b5ca0aeb60e73ca8e5fb0f8c80be485da30a0a" + }, + { + "kind": "file", + "path": "img_2150.jpg", + "sha256": "490604777a8fb99b514a645620ecd2622abf5f1314e20c1f1aa93971aa4c2269" + }, + { + "kind": "file", + "path": "img_25.jpg", + "sha256": "d230430171314b4ef6f008aea571928f2dd601513a9b8afafce96d977b89f55a" + }, + { + "kind": "file", + "path": "img_1459.jpg", + "sha256": "e35b62c2fd8fffdb2ef87838f3ce11353fac3b5915d866c83537dc725f8209f9" + }, + { + "kind": "file", + "path": "img_4509.jpg", + "sha256": "ba8a7e926bdf0e5fa574a47ad2b0b4bdfa32c5a35c757329f90443f2261a7450" + }, + { + "kind": "file", + "path": "img_3266.jpg", + "sha256": "a60a816f1cba7b6bf221a5c2789c8f51f4a748a13d9106d228520226c81e7c77" + }, + { + "kind": "file", + "path": "img_491.jpg", + "sha256": "823a32972338cd845c7298de2ab8ff97ad3c9a2bd82593c7d91b0bf3affd093b" + }, + { + "kind": "file", + "path": "img_2178.jpg", + "sha256": "ce372d9ce196794eeae987f3d941ce716c6140c5e7898466f8d1452285c033e0" + }, + { + "kind": "file", + "path": "img_1317.jpg", + "sha256": "39e074dbf5ca063376ffe7a36e8d67589f423033753b7549445cbde77c2788e2" + }, + { + "kind": "file", + "path": "img_3500.jpg", + "sha256": "9e39c2d058ad300cb4d4c3ea0eefb7f54b72df034d072162f91a8d62e0daf727" + }, + { + "kind": "file", + "path": "img_3514.jpg", + "sha256": "b14f980d2654b65115f52a9bf9883c508c155be0428991cd2a1b52de0841ce11" + }, + { + "kind": "file", + "path": "img_1303.jpg", + "sha256": "1f7078a6e37a1772e35c76ac977588259d668e995227c351c910c5b3716c483b" + }, + { + "kind": "file", + "path": "img_3272.jpg", + "sha256": "0ebd391fb4501a3b4c1686f103bd2f20a44d92f6faba3200c139ad72d16844a9" + }, + { + "kind": "file", + "path": "img_485.jpg", + "sha256": "2cd8f23597a9facaf4c36bfec52655df37653ed1a01fc923817c78246f0f4397" + }, + { + "kind": "file", + "path": "img_19.jpg", + "sha256": "86f2e56cd749778fca29421d58619d93fab249eaca355d85e9b21ca9d2dc00a0" + }, + { + "kind": "file", + "path": "img_3925.jpg", + "sha256": "339222ec69f032caf87a8300e2dfd22114dde1e722864187ac36b5573047a2e9" + }, + { + "kind": "file", + "path": "img_4092.jpg", + "sha256": "6ee514ac57ce90a2c6cbfb125fe2411a4de0da445d40829dd2dfaa2db70ddf22" + }, + { + "kind": "file", + "path": "img_1854.jpg", + "sha256": "86f36acad87ae7377e269af79e3bf0a67d2079f4d292f1aceb58089d80a822ff" + }, + { + "kind": "file", + "path": "img_2391.jpg", + "sha256": "9cf9a5a46174b7627b3505fb8e3ebfb77e4f05313d7aceee361b623bb233238c" + }, + { + "kind": "file", + "path": "img_4938.jpg", + "sha256": "8b8c865501b3cb385b1bed5f6b68215e422b83f13a621bd9917452ebb10476f3" + }, + { + "kind": "file", + "path": "img_1698.jpg", + "sha256": "2125d2028cf7bdafb25bd96ff7bd76223c4f08645a55e1a00dcd3d771fe38660" + }, + { + "kind": "file", + "path": "img_1840.jpg", + "sha256": "d4845aa6e23e879bf6868cb0669f89a74fdbc23d957411ce00b403021da89bb9" + }, + { + "kind": "file", + "path": "img_3931.jpg", + "sha256": "d9343bb35e40245821799efa4a20b2d4b77f6fe15ed44081593fd5596aa7c61f" + }, + { + "kind": "file", + "path": "img_3919.jpg", + "sha256": "8701b47e198e71732c942d89bb43001c8735bfbeb26931e45b2c58aeb72c5427" + }, + { + "kind": "file", + "path": "img_136.jpg", + "sha256": "a6141113f160463ac0dfe553934b8ecafeddef96615cae19efcbfdf7b7cf5c6a" + }, + { + "kind": "file", + "path": "img_650.jpg", + "sha256": "7d57515f6afeea57d5592adf1d26805894246bd5830312037c78fbb138bf6f0e" + }, + { + "kind": "file", + "path": "img_4910.jpg", + "sha256": "9e8e7bd88a388210183dfad5f0a906d72bd58312dcd95a1a97ca40dfaac627b1" + }, + { + "kind": "file", + "path": "img_1868.jpg", + "sha256": "704bcf3c0ce99cdf506d72e2293576d26dcee5037af135f21199b785b3c89186" + }, + { + "kind": "file", + "path": "img_4904.jpg", + "sha256": "d4758a09f6eae42e67f67268cb93a1aff9017f80c510f2a33a3a656ce226b44a" + }, + { + "kind": "file", + "path": "img_122.jpg", + "sha256": "6708cf8ba5357e1b4d93a4438e7d3b875543452d107edf5d88dbb69a9c5ba166" + }, + { + "kind": "file", + "path": "img_1129.jpg", + "sha256": "908a7ffc8bc57eb149d8e6f6109b7942cf5deaf9c60c91546bc6d0626398fd72" + }, + { + "kind": "file", + "path": "img_4051.jpg", + "sha256": "9768d1b14ada811edb878a465512a4c4fee7cc88db7491f02f1001448eaa571b" + }, + { + "kind": "file", + "path": "img_877.jpg", + "sha256": "d0cdfbbe1c97a5d4e2b6af4cd8ed4fc2d7198150e18ad592f3a04c264f0cf6a0" + }, + { + "kind": "file", + "path": "img_2346.jpg", + "sha256": "f6db3f250baeeadf1bb8b6aa82cd7e2533f87f9aa613ec6ccf0c68506f09a01f" + }, + { + "kind": "file", + "path": "img_3058.jpg", + "sha256": "d77095fd6b29f23aaec831557de4865819c3d12b685fba503865f0909f3ec846" + }, + { + "kind": "file", + "path": "img_4737.jpg", + "sha256": "9963400ab4a86e4c3d4a7c0bbf4f84b85f07d3d71ff847a2a8a3e23e842000c8" + }, + { + "kind": "file", + "path": "img_1897.jpg", + "sha256": "36b52864ad49e9dd565c7ac04201c374789a6678b67696fb2a44578f7866ff70" + }, + { + "kind": "file", + "path": "img_1883.jpg", + "sha256": "3fcb213387b02d192a97176f538e4cfa8f8ab48c6360f46957c49c61e5222178" + }, + { + "kind": "file", + "path": "img_2352.jpg", + "sha256": "6e1e05f3f038ea8ffa80868cbb2aa46d2e5e16b7c3657b745a4e03ca3e319c31" + }, + { + "kind": "file", + "path": "img_4723.jpg", + "sha256": "1f42afaa2b80a473c4fc7d9810e081b4e358b58819d9730bd56ea26fb597653e" + }, + { + "kind": "file", + "path": "img_4045.jpg", + "sha256": "6cdf7decad3512a7eca12e43657d2a25d64822a59a65089e23fcf429669bdcf9" + }, + { + "kind": "file", + "path": "img_2434.jpg", + "sha256": "212e6a12ea4e3493bbfa34cbb6ed2ce75ecb8f9912b6b0f3e6f3d6f90b2f6aae" + }, + { + "kind": "file", + "path": "img_1673.jpg", + "sha256": "3fdc946e8f7208c4299d9d8c8cb2ef6f6b5188c3a0addb1f97321b8dc86361d8" + }, + { + "kind": "file", + "path": "img_693.jpg", + "sha256": "7b3143a7694705abc91693783ec53f804178ebb651df4da471bb133576c19784" + }, + { + "kind": "file", + "path": "img_3064.jpg", + "sha256": "0eef9586ad470c60b57217dc43968ab3f8b3d772fb6ae2f29ae520c2180ecb21" + }, + { + "kind": "file", + "path": "img_3070.jpg", + "sha256": "d2ee2484de8eb31818f7580e9b30286866ba693364c848c48594dc4d8b135581" + }, + { + "kind": "file", + "path": "img_1667.jpg", + "sha256": "c03511a37e8992bef940f02ae5a44ccfd72c2e03423060405199171b0be870b6" + }, + { + "kind": "file", + "path": "img_4079.jpg", + "sha256": "e2a0b2266af4cd278d17892fe30a583ad19740303b20fd6c98fdd343adbbe692" + }, + { + "kind": "file", + "path": "img_3716.jpg", + "sha256": "3073a68513f4a6025114f4f27c0720aad8df50fae62be2ae6ccac0c4bd683c0d" + }, + { + "kind": "file", + "path": "img_2408.jpg", + "sha256": "649606368f499c564c87fcd65c8b3cf9f980100adeda4df11c8e96c4c397a9e3" + }, + { + "kind": "file", + "path": "img_3689.jpg", + "sha256": "dbdf6e3b2225518f5e30157ec08355e1b8df390725ee7f3e81d4baaed6362d4c" + }, + { + "kind": "file", + "path": "img_3851.jpg", + "sha256": "7f0f4fedb2cff2b03e18eddf74d0e36e05a477a5cce4c391c2cb704d96720eda" + }, + { + "kind": "file", + "path": "img_2597.jpg", + "sha256": "4c81c6ef96557b4d1eb958b9680fc4b623e05aa9f203d7e6062f60c55b0b690a" + }, + { + "kind": "file", + "path": "img_4858.jpg", + "sha256": "3c3de76a081785a6811c360959f90ad850e5d741624261b5215a342fd8ce5e21" + }, + { + "kind": "file", + "path": "img_4680.jpg", + "sha256": "9cb3276dadbf4d7ca7ff9b7fcb3a4cf5d80d7345e20f2ffad73d8167d248de22" + }, + { + "kind": "file", + "path": "img_718.jpg", + "sha256": "f967d746b777a4a5b1cfa760db453d82f754f2554b11111e806ad28f57749c46" + }, + { + "kind": "file", + "path": "img_4694.jpg", + "sha256": "45a117f8653d2417e5c955cbb421220cdebf9ecad4a65f8f82612bb15580313f" + }, + { + "kind": "file", + "path": "img_1934.jpg", + "sha256": "bce1b698dfa9448c88bec4e8a90da5394c63098ab0d819ae37d13f1ae7ef8f73" + }, + { + "kind": "file", + "path": "img_3845.jpg", + "sha256": "1ca8c1d5a6821600284f652cc34c62bf4e484b3d2c675ac8cd157727c51c6748" + }, + { + "kind": "file", + "path": "img_724.jpg", + "sha256": "48138e5994917703d6b80f0b22d35a1164b5bfef58e423ba42c70ff692f68327" + }, + { + "kind": "file", + "path": "img_1908.jpg", + "sha256": "c407f62fea6e7fee50c4f82f38c0ed3f0393d6a2b5dcc82a0eea0341b7844cb4" + }, + { + "kind": "file", + "path": "img_4870.jpg", + "sha256": "b427a2b4e458f32b62d6b02d93e4d9ea79b1a9854f1ff68eb6ffbeadf2c00af8" + }, + { + "kind": "file", + "path": "img_730.jpg", + "sha256": "b93f6bef516e5d21b93a5b823808b01c6b628232400080e953a6763c2c095eb3" + }, + { + "kind": "file", + "path": "img_3879.jpg", + "sha256": "b299b3f5e0ea581f1d72da577f03bd83bbc5fb925c8bbefa0a4235d23e615695" + }, + { + "kind": "file", + "path": "img_3892.jpg", + "sha256": "1b158db0e8f2cf1e5b994e1d2e713f61d4f8645f57099f4513c8dc69a6233d10" + }, + { + "kind": "file", + "path": "img_2554.jpg", + "sha256": "c0eaa19de032cbd6101a52afac73f6b1a4379c1a1aabfdb0c63996e9a93fd5ef" + }, + { + "kind": "file", + "path": "img_4125.jpg", + "sha256": "e9be3194a7fe8f5f337cb0dd9530d78ff234ad3bcc1b3f1d0f295f2b0db70dd7" + }, + { + "kind": "file", + "path": "img_4643.jpg", + "sha256": "a86507d8176c2b82892d6a1d2b80786229231874fe47d3a2d716c3a376160e3c" + }, + { + "kind": "file", + "path": "img_903.jpg", + "sha256": "da3ed70d34474b1e56cfaf22d2de772b5fca1cf7a0c8cb043ccca6e0c85002c2" + }, + { + "kind": "file", + "path": "img_4657.jpg", + "sha256": "743f8ff3736c14ca622d9f446bc8076139d7db6c18b559f0d7aae4e6e5a61d63" + }, + { + "kind": "file", + "path": "img_2226.jpg", + "sha256": "be94a13febb895ecd159607204aa3c8e36acb90f4d648caab03ff172209ad88a" + }, + { + "kind": "file", + "path": "img_917.jpg", + "sha256": "6cdbd3806a8f71926ab286b22de6fa31409481470d5f1d830158f33aa8fd9421" + }, + { + "kind": "file", + "path": "img_3886.jpg", + "sha256": "2ad788e2ad8929fd8bbab60370957b7f07ce1ef64ef039fe2601c93ae2aed3f3" + }, + { + "kind": "file", + "path": "img_4131.jpg", + "sha256": "a4f53fb6a1c251882736cf461babb2823ce3c9eff2655431baf1e7d829274036" + }, + { + "kind": "file", + "path": "img_1049.jpg", + "sha256": "3e92b990fb96debeece81ee31a92fe581473f972837037f3c2d17835dd834715" + }, + { + "kind": "file", + "path": "img_2568.jpg", + "sha256": "96015d1ef530e664cf0d5c3f443dc4675cb5ec1b37d8b7421d26a5ba83e18176" + }, + { + "kind": "file", + "path": "img_3676.jpg", + "sha256": "f7cc77c62381e48f405a0e589ac7fa357cc98c89e96d79952e5f22a2e1de2296" + }, + { + "kind": "file", + "path": "img_4119.jpg", + "sha256": "e64d3ed62fa281092bf20e538fb7122694da672c86d889bd94f47d46e9262e7d" + }, + { + "kind": "file", + "path": "img_1061.jpg", + "sha256": "f79648273fbcf35cf91130e8e9aa068b9392e3f06ccf4034371f0f610fa8697e" + }, + { + "kind": "file", + "path": "img_1713.jpg", + "sha256": "fe5f203ce8d4d4a96ce2f6ed8c3025da79ce9fc9aad1cf7b2387eea2b4794d23" + }, + { + "kind": "file", + "path": "img_1075.jpg", + "sha256": "f5bc749d1d6d08a78248b5ba18737b237d32f06283b04ccc1b4a42192709ef40" + }, + { + "kind": "file", + "path": "img_3662.jpg", + "sha256": "29ec3dc441a7de21dfae11f73e5f73e95acd5e9b12d0f20d012f1e527a6bd58d" + }, + { + "kind": "file", + "path": "img_2795.jpg", + "sha256": "a133b3398d6e1fb66984f880308a87923405b5c70c2da615b509a7f145de0d80" + }, + { + "kind": "file", + "path": "img_2781.jpg", + "sha256": "cf0c79acaeaccbd75a098d39fd08263146159d29cb94dd43a92f728a88a3d75b" + }, + { + "kind": "file", + "path": "img_8.jpg", + "sha256": "3006363dceeb260b93f5293d71b54a3f394cb9f61c2dac11a77a2750c6fbe984" + }, + { + "kind": "file", + "path": "img_2959.jpg", + "sha256": "288c58e379354b0b5266aa52e83d87b72006a87c1a10852b2456dac55d777ae4" + }, + { + "kind": "file", + "path": "img_268.jpg", + "sha256": "93ffe2e4df70f23b93772737fe8d2a9d4998d21080c62aa05aecebb3fb1afabb" + }, + { + "kind": "file", + "path": "img_1288.jpg", + "sha256": "07bc67e80a68894ff96259883cce8853af699f8ebe0cd996f439b467c9085c42" + }, + { + "kind": "file", + "path": "img_2971.jpg", + "sha256": "ec354002892e915e8a9cd824f8b5b0df655673ec4def1be975f836be42fde398" + }, + { + "kind": "file", + "path": "img_240.jpg", + "sha256": "be2d2bae7346f7243f9a59d81f7f539eaeba64f2dc192c03d6afe37ba9b4825d" + }, + { + "kind": "file", + "path": "img_254.jpg", + "sha256": "4f80c26da02b44fe567138d82367e34e734d091b5eaf261dc5d14da7c3b04564" + }, + { + "kind": "file", + "path": "img_532.jpg", + "sha256": "f991c8ee6c4b354367c351c8388e208e2e896a17eca2686ef6ee23f823186332" + }, + { + "kind": "file", + "path": "img_1539.jpg", + "sha256": "ff50dcb09539d9b5cafe9669f8dc14d54ba5c567633039e5cc1e186f057e3867" + }, + { + "kind": "file", + "path": "img_4441.jpg", + "sha256": "7882b83f353c8fa8dc0479fb89a2f342d29d1a999c2ab1a3c9e71990b757ae92" + }, + { + "kind": "file", + "path": "img_3448.jpg", + "sha256": "b79a14a1d6c75790eea513f7059a63b9c0a2b7a4efc256fac59cf2158747fc99" + }, + { + "kind": "file", + "path": "img_2756.jpg", + "sha256": "152b8a9796906e733b1a9cdaaa0ab82fe6c0ce2f7350042de2a716bea9b2a188" + }, + { + "kind": "file", + "path": "img_4333.jpg", + "sha256": "84ac958b726cab6dcb21456b6d632985a9dc61c53986da128376072188625048" + }, + { + "kind": "file", + "path": "img_2742.jpg", + "sha256": "4dcc470c5c370e6c2c1eb1c3b6aadc5edddd15e45a18516da422b937da0d48a6" + }, + { + "kind": "file", + "path": "img_2024.jpg", + "sha256": "655457e8c808b34fa626c57358aa6e2d183257ea6b09ee0c9fa381a60cb0e60b" + }, + { + "kind": "file", + "path": "img_3312.jpg", + "sha256": "72f882babefb343fc91b14b93b1ad3fdfe71d26be6070cd6b7d0219723e3858b" + }, + { + "kind": "file", + "path": "img_1263.jpg", + "sha256": "7941ae8fbe1eeebb39477208d46fc4ffdeb189aa09291a749382f6aa5d6093be" + }, + { + "kind": "file", + "path": "img_3474.jpg", + "sha256": "9fda893aeccf00fad8c3596cdc4fde4975b9f0f8f5249be9314b90c3265bce26" + }, + { + "kind": "file", + "path": "img_283.jpg", + "sha256": "8a7b07cdfabb45e3ed99396c289110ce569ea527d1e907467b3de5eaa98715b7" + }, + { + "kind": "file", + "path": "img_297.jpg", + "sha256": "a45e02c81c8324f945916cb086f13973337ebe429933fa4ecd0361d2fedd870a" + }, + { + "kind": "file", + "path": "img_1277.jpg", + "sha256": "1e7849c8414e9ebe1e7f3febbfd93d90ebe205aba80531f2a66806f79f9c563c" + }, + { + "kind": "file", + "path": "img_1511.jpg", + "sha256": "c907d5030e4f8906acf1707916652fd34084fe2200ed7ee594187bfd804ffced" + }, + { + "kind": "file", + "path": "img_2018.jpg", + "sha256": "bb2af70e17c2898628f72941a5714190246bf5ad7276fd28f401fd9d8f3d9b0b" + }, + { + "kind": "file", + "path": "img_3306.jpg", + "sha256": "2bc09d98b15521aa12e4d18f468c213fcb576dc2939da0722fa62371c1d93f1c" + }, + { + "kind": "file", + "path": "img_4469.jpg", + "sha256": "a1313b94af322d2bb04ef9359c75d1bac5ca863aa5d0aee4e3dd5c081a83fc6d" + }, + { + "kind": "file", + "path": "img_1276.jpg", + "sha256": "f22b1444fa74e070f7d3f46bcf31f5419b31e7b7f24a645abcdf311e94050d02" + }, + { + "kind": "file", + "path": "img_296.jpg", + "sha256": "f971a33e977f9b21b7c540249e347c597f66fc349b14b61ce918e741501e7b1e" + }, + { + "kind": "file", + "path": "img_3461.jpg", + "sha256": "fe8cf23c8b31034a7a12e1e113d5e0ae6c03f8bd989af665c808d9ced3f750cf" + }, + { + "kind": "file", + "path": "img_4468.jpg", + "sha256": "4e2a528c60d46062510f6c4561eace209b86a69d5ea889244f9117bc75dbb98f" + }, + { + "kind": "file", + "path": "img_3307.jpg", + "sha256": "60d703a1001320130596f4a86be6fc786c66cb8a72d81b2d17b1cbda215c8e5e" + }, + { + "kind": "file", + "path": "img_2019.jpg", + "sha256": "f0a96a1b62456f29ca3e85aa4d034d9d58aad28513a8d678a3f74037dcf75866" + }, + { + "kind": "file", + "path": "img_1510.jpg", + "sha256": "fde7d887d86c77881620ac391fa80d13ef813281024fe455d40079426515627d" + }, + { + "kind": "file", + "path": "img_1504.jpg", + "sha256": "5f4d4370fd7b3ba008a56bee4b08867a6b381227c3e11106f96019ed882db6be" + }, + { + "kind": "file", + "path": "img_3313.jpg", + "sha256": "8e7e1d77763412433810b5cef99e10800472d37314d0fc3e27b809546986c06e" + }, + { + "kind": "file", + "path": "img_282.jpg", + "sha256": "6d1e3f9cfab15a835c9bd5a1480db862e938f0cb89cf2bbb102ec87e0b1e1c59" + }, + { + "kind": "file", + "path": "img_3475.jpg", + "sha256": "3f705e6642f905642f6ac56325cc6a5713187bea9fc16eb5af638216f350aa51" + }, + { + "kind": "file", + "path": "img_1262.jpg", + "sha256": "6a5ed82c19cda825e4eb519564e9f8956f754c48852210c609673d047843d24f" + }, + { + "kind": "file", + "path": "img_4454.jpg", + "sha256": "4b0345bf7cca9647268ba4e76d9f3e28dc3a4358d3ab960e0336bf7cf85c38ba" + }, + { + "kind": "file", + "path": "img_2025.jpg", + "sha256": "43285b9a45d9712bc2ed8ded8ef3d5c6f24658f117e86d73c13bdd723f1219c7" + }, + { + "kind": "file", + "path": "img_4440.jpg", + "sha256": "f99c43497c019f3da92d27b93bbdb2ace792c3ced1d713040112d45df948ef22" + }, + { + "kind": "file", + "path": "img_2031.jpg", + "sha256": "315e1da2cb1fceb8b83452d9b8db4cc17af54ba5fc907e80e6ed5f3a84843068" + }, + { + "kind": "file", + "path": "img_1538.jpg", + "sha256": "3e8aaf7324f1b9cc4ecbe2df0a152222e8030ed5b9624d414d56485175715643" + }, + { + "kind": "file", + "path": "img_2757.jpg", + "sha256": "1364f460119c9a4e2b39c2da156bd73372dea688477a9df32cc0c9fa568c6d35" + }, + { + "kind": "file", + "path": "img_3449.jpg", + "sha256": "e466d4cfa2c4ca78c8dad0b2f20de41f25dc454b0704fcf2ddf6c9cbe1a27d3f" + }, + { + "kind": "file", + "path": "img_4326.jpg", + "sha256": "51e6a8aca8a4b956fe8a1e723cc4170614a69338c2d1cb2a6ec8fd04504df5a6" + }, + { + "kind": "file", + "path": "img_533.jpg", + "sha256": "0c0fe5961fbcd6460e7427185c6ae6a04319e3ab4e482e5e05e8753ab41d71d3" + }, + { + "kind": "file", + "path": "img_527.jpg", + "sha256": "55f051b39e79ba4849827105c67c1e41f9c1a24030f732fde817b48c7fd13915" + }, + { + "kind": "file", + "path": "img_241.jpg", + "sha256": "9fa57a4cc189100f671a404e88bfb2b9d71d7ab8cb00daa4d6570faedbe178e6" + }, + { + "kind": "file", + "path": "img_2970.jpg", + "sha256": "a165dbef8282703f7a8f4d1a2bd5cdd1fda99d56e2985f34ab3bf87bb673a31e" + }, + { + "kind": "file", + "path": "img_1289.jpg", + "sha256": "e658029a979b7e8ca259468f7e7d9a92e0111b18d21884909363417efae53790" + }, + { + "kind": "file", + "path": "img_269.jpg", + "sha256": "aecffd68e65306686d0810dbf68b850ea8f02266a917b989216983ab0d0b130e" + }, + { + "kind": "file", + "path": "img_2780.jpg", + "sha256": "deaed82b7312f872db85635308723d0453f87083c3a2f8b19bc43253f6e21ee1" + }, + { + "kind": "file", + "path": "img_4497.jpg", + "sha256": "dfd69ed4fab7babf6e2b1163bd18e7b41c143c0b0c701912e7a715f468d48db1" + }, + { + "kind": "file", + "path": "img_4483.jpg", + "sha256": "44fc48d723b2007c0220daea0b8c79ed6df5e6b57378bfc3d184222a7d9e89cd" + }, + { + "kind": "file", + "path": "img_2794.jpg", + "sha256": "706026d0b53a75c215e99f0ec03e36f54855ea8baaa8bdb95ee40aaf1f01b072" + }, + { + "kind": "file", + "path": "img_3105.jpg", + "sha256": "e8bc440310eab556be4a5101e79d9f8bd268a81702719c261f2f1c02198b2acd" + }, + { + "kind": "file", + "path": "img_3663.jpg", + "sha256": "442a91324749f95f0e10932954cc07f839f5926213dc4a49fb39334b76f09645" + }, + { + "kind": "file", + "path": "img_1074.jpg", + "sha256": "cbb51f5a54b5bc1cf3eddcb1ed14294b3ad6ce5b4006f03822f7b20d089f3259" + }, + { + "kind": "file", + "path": "img_1060.jpg", + "sha256": "9bd3dfe39eb1b57acff9f52d5a973b5740e40007bdc208a2e03d6d44fee26b27" + }, + { + "kind": "file", + "path": "img_4118.jpg", + "sha256": "1a166467b8eeadb77a103904f036c161cf8ece0de71ea74e14024c9435c7edcd" + }, + { + "kind": "file", + "path": "img_2569.jpg", + "sha256": "ccb1d4941d292734a6146682d22554d49dc0e1575565aeba11151f9b553dd520" + }, + { + "kind": "file", + "path": "img_3111.jpg", + "sha256": "e7809b84a9e9e941acf35de5c8ace1a5f3db59ac9eb478467380e5fec1a02ddf" + }, + { + "kind": "file", + "path": "img_1706.jpg", + "sha256": "b932ecbf30bf5ceaba11c15ba7af0e99e0a8465d9f0e3d39d3c22d52987ea917" + }, + { + "kind": "file", + "path": "img_2227.jpg", + "sha256": "826360a128975005c1f1b4f94ce5218b9a1419ba989b567e0083462069be8236" + }, + { + "kind": "file", + "path": "img_3139.jpg", + "sha256": "591a765f919d36e98564a89e10361d3f7155c94a5109a1a207115ee84c05d300" + }, + { + "kind": "file", + "path": "img_4656.jpg", + "sha256": "e2b3fe0f6ffe8df32c119173f6d349f0599a34e22ec787058f6f7d2e20dc04a9" + }, + { + "kind": "file", + "path": "img_1048.jpg", + "sha256": "003866a3b694fe12548b4d3ce193d2a2063826b868b484224ab0d0a367e1a1eb" + }, + { + "kind": "file", + "path": "img_2541.jpg", + "sha256": "c29d5efe3e37cdae4d75a400e8e50f0548dabeedf09cc2f89d3a9402ec154e55" + }, + { + "kind": "file", + "path": "img_3887.jpg", + "sha256": "c96e5737395830c9612614d07c28857fad4a0f48f4da5e855bef9975870e5d73" + }, + { + "kind": "file", + "path": "img_4124.jpg", + "sha256": "3c24d3b88cea363865c20612591ab1e20ffe8323052435f83fbb6eb4495517bf" + }, + { + "kind": "file", + "path": "img_2555.jpg", + "sha256": "045ed2a896e1deb7d7e03ec0d9235942330809797cb69683c8b4a943da66b0be" + }, + { + "kind": "file", + "path": "img_3893.jpg", + "sha256": "dcdfc081b17299e9de056dae51d0bb94fd52536b8b02df9ef72162d1d9951fd6" + }, + { + "kind": "file", + "path": "img_902.jpg", + "sha256": "85987952e5eb975a8d51a946d44311f6491635e9f1f620e1d47caba679e8ce87" + }, + { + "kind": "file", + "path": "img_2233.jpg", + "sha256": "fb64315825803bbf77f447d829694fb9578b29733596bf5c8a04bc83c54d1756" + }, + { + "kind": "file", + "path": "img_4642.jpg", + "sha256": "38321e0d46c15cd257e4453a827ab36cfc02858840fa3566f6a6c3c77e78d588" + }, + { + "kind": "file", + "path": "img_1909.jpg", + "sha256": "b6f0027261b9b35d838334aa37ea1fbc103430dfd6a1ef8b94ae6b2c411a73ac" + }, + { + "kind": "file", + "path": "img_3878.jpg", + "sha256": "e4a25ed1bd2ddf35aadc6a43a44169a3262896a067fb820b34f6c1997fd6c896" + }, + { + "kind": "file", + "path": "img_4865.jpg", + "sha256": "91fc70ef1d404a163ef3741197aa3dcac2bb975380abd3fe8ab9f6f6106f149b" + }, + { + "kind": "file", + "path": "img_1935.jpg", + "sha256": "a7264c5ca6ecb75a002d36aa1030943e96d4761670ded4bdec546baad14a9c14" + }, + { + "kind": "file", + "path": "img_2596.jpg", + "sha256": "a7f921c880b7db64df7ee061bb7cc3de008c90adc1b4dc8e8370cf715b462710" + }, + { + "kind": "file", + "path": "img_3850.jpg", + "sha256": "5561f154a4fec823846979685585379fdadf5b15424f2ecee63c6ff95c354b1e" + }, + { + "kind": "file", + "path": "img_3688.jpg", + "sha256": "06241d298f695fe7626da6ad1dbdd4f9e8b5d6ee3acb27d9890a1bea096aa6a8" + }, + { + "kind": "file", + "path": "img_719.jpg", + "sha256": "7133de8f6eebce33802d03dd2e133faadf59ae925e1fd864c68c0e07ea77bbec" + }, + { + "kind": "file", + "path": "img_4681.jpg", + "sha256": "77b1b1df842ecd03fadc9843586259389b9f824a009499bbb0f74b518d6ba4e0" + }, + { + "kind": "file", + "path": "img_4859.jpg", + "sha256": "87effc92a441e921876985a1be1bcb9820616952b117d662402adb1b2a8dee4e" + }, + { + "kind": "file", + "path": "img_1921.jpg", + "sha256": "99472debbb5d01c4af317f39c30dd5a7a43bb4e8c586addd5dfb84848a84f927" + }, + { + "kind": "file", + "path": "img_1666.jpg", + "sha256": "85183c1247ce9f95e4278e8b0f6f2effe60557e792d1cccab6c5aaf88b844261" + }, + { + "kind": "file", + "path": "img_3071.jpg", + "sha256": "1b5eaac7a3904df479b2a566f7923843d5159ada56737c436836d3d2c8393435" + }, + { + "kind": "file", + "path": "img_2409.jpg", + "sha256": "6aa864023a29b606c2a2aa0253ef2f2adff0ec81a3a9edb2a91d1f7077d83b56" + }, + { + "kind": "file", + "path": "img_3717.jpg", + "sha256": "dbb6b467dc88881b804e793b23b17ee10b186c6d270b28bb124d61de3ee8f69c" + }, + { + "kind": "file", + "path": "img_1100.jpg", + "sha256": "f8504589a62234cf2fbb76d6ec9bae3987c52f0db73cbc0a05016a92b0ef446e" + }, + { + "kind": "file", + "path": "img_1114.jpg", + "sha256": "c6a6bf0b286022583ce6cdc7c8aa7cac6dcb25d441ebe9f1f75bf1ce46297903" + }, + { + "kind": "file", + "path": "img_3703.jpg", + "sha256": "1fb3539525e9f96f8ba350333f450dad9da4ed76e28eba297a00a70eb807eacf" + }, + { + "kind": "file", + "path": "img_3065.jpg", + "sha256": "4e1fbda0ddee7321013aded36c83d139edf6d2b50aff2ba005434bcca95bcefd" + }, + { + "kind": "file", + "path": "img_692.jpg", + "sha256": "96e9bfca8db016823c57e838fda09214b79b818edddc8cdefa465cfc677f2087" + }, + { + "kind": "file", + "path": "img_1672.jpg", + "sha256": "1bc00f8453c6550e1a55743279359d69d7feea250ff768c921182764f583e08e" + }, + { + "kind": "file", + "path": "img_4722.jpg", + "sha256": "5a117023e0460ebce8ca7c8a97d2d4dd1883073f683772c1837e58d1ae225eed" + }, + { + "kind": "file", + "path": "img_2353.jpg", + "sha256": "18478e5a8c2095d919739129e73c16ac32f4b75bb14ab05c85ecb7eed12f3747" + }, + { + "kind": "file", + "path": "img_862.jpg", + "sha256": "241b4a788e2b8cfd99d8a0da43ef1dabfdabb44d13be8803f9215fb648b33f29" + }, + { + "kind": "file", + "path": "img_1882.jpg", + "sha256": "de316fff6228c7a103fe5d17bb43a50d37bf65153b83326cfc92e7671c61d935" + }, + { + "kind": "file", + "path": "img_2435.jpg", + "sha256": "f202fd8d0e1215c642f9cdddedd6a9b99eed31f9ef5c7900ffdcfdcabd6f447e" + }, + { + "kind": "file", + "path": "img_4044.jpg", + "sha256": "f4cde9a2e58f3f3c2c007b5d81059cfede3fd5f8e7367f935a04510eb8b1b70d" + }, + { + "kind": "file", + "path": "img_4050.jpg", + "sha256": "922115f51a3c09febf853fd5e3dfffbe3f9f4620262c2028e092f6883fa893f5" + }, + { + "kind": "file", + "path": "img_1128.jpg", + "sha256": "f714fc2aae28ff0ae602bcffe849f26e4118793146b07ce97736f7181628beaa" + }, + { + "kind": "file", + "path": "img_4736.jpg", + "sha256": "eef670d1c98f8585a90669bf32a345f138401aa5f0b631ec1d935a5c5d793d3c" + }, + { + "kind": "file", + "path": "img_3059.jpg", + "sha256": "95458ba1d02aa3b3f41fdcf6775a2c09333ad8652d9e98bad0250a72ef996da6" + }, + { + "kind": "file", + "path": "img_876.jpg", + "sha256": "592f1077f1a16d1e3d88ffa7ffe793bc0d6bcbc0d1eb0a378832a08987b5a6cc" + }, + { + "kind": "file", + "path": "img_645.jpg", + "sha256": "00e37fce24af17224e803608d2985f14956612dd0f176578fffc9f7e7c463528" + }, + { + "kind": "file", + "path": "img_137.jpg", + "sha256": "e433b27ac33524448ae4138173c5be7a442f964f0dc70a2293a118a529f89809" + }, + { + "kind": "file", + "path": "img_4911.jpg", + "sha256": "1a61a407c79070eebeab0093651660668cfde1c535b6528301341111b042c0bf" + }, + { + "kind": "file", + "path": "img_889.jpg", + "sha256": "292e744602df5e20b50f653538141d9ebe27c5f404e58ee1bddcc62b258f376e" + }, + { + "kind": "file", + "path": "img_651.jpg", + "sha256": "fcc5d1d146c195ccacab8203f8ac7a61d7c29c559813652e4f09ec157662100f" + }, + { + "kind": "file", + "path": "img_1841.jpg", + "sha256": "84e448ade4a3b4380d09543311a44f1a25bf18b51165b93693ada93bfcce524b" + }, + { + "kind": "file", + "path": "img_1699.jpg", + "sha256": "21142f581995d71c0f5e1184348e56969f9c80b3d3872e1a958ae480c0913e16" + }, + { + "kind": "file", + "path": "img_4939.jpg", + "sha256": "cc4d2ce1128308e1afe3fd4fbb6dcbf0b99ff4f9d8a394ceadf38ce798c2a0f6" + }, + { + "kind": "file", + "path": "img_2390.jpg", + "sha256": "924d2a77f2cf4b0d08a2d53439fa8d682ea3217542f40b43eed3d212673445d9" + }, + { + "kind": "file", + "path": "img_679.jpg", + "sha256": "3a2e766016c0a692bbe00dcfb68d6830a726cd06cbbce3963914a3c4d6b0f8cd" + }, + { + "kind": "file", + "path": "img_4087.jpg", + "sha256": "d849b9e6b21070cfb615c83302b7d5216e40233ad0ba03ca8d6d22ccfa1bbf4b" + }, + { + "kind": "file", + "path": "img_3930.jpg", + "sha256": "6ef983415904c76a20b7cac6600a01ce238be5bedaa02d50c8628a233b53ac01" + }, + { + "kind": "file", + "path": "img_4093.jpg", + "sha256": "6dbf5e279645850bcca6766b4517d260b94d99a411d254029a2dd9b4bb8574cb" + }, + { + "kind": "file", + "path": "img_3924.jpg", + "sha256": "420c272d912b5501a1243981197c0f850b3746b2a197aceb70c45dfbe026e321" + }, + { + "kind": "file", + "path": "img_2384.jpg", + "sha256": "040e3ae0e14f633cd882cf7dfff2ade2c6c5902293da01216d6674ac69285a69" + }, + { + "kind": "file", + "path": "img_1855.jpg", + "sha256": "f1d9c328c2033b3529990686df5764a63c484b80d10e968881f6bde201ec68bd" + }, + { + "kind": "file", + "path": "img_1302.jpg", + "sha256": "82f79df66584eba3b65af6be0285227f15e9f6b63b2d82822f8d4ce375d471ca" + }, + { + "kind": "file", + "path": "img_18.jpg", + "sha256": "3d7487608135adf1b676b84ed48dba5ead66699cb929041a4f643ffa14c3dde3" + }, + { + "kind": "file", + "path": "img_484.jpg", + "sha256": "9d565115bf062ee508b1de94ee68dc5c8925ae56c23612031edabc50e757ae14" + }, + { + "kind": "file", + "path": "img_3273.jpg", + "sha256": "c404e572997b23abdfcfabf20167674d224a0e106200c002c48a6bacb370befd" + }, + { + "kind": "file", + "path": "img_1464.jpg", + "sha256": "b2533f263b522a4e5e9c2237fa0ab053f20a5fed1617435fe8fcc08c0c7231f5" + }, + { + "kind": "file", + "path": "img_1470.jpg", + "sha256": "6b1c678f182f91470ee73944d2d075d6359c6327ef0dfba7e1a37ad129518819" + }, + { + "kind": "file", + "path": "img_490.jpg", + "sha256": "82aa6a789de4365185872d1e1f46fee0fc8ed900227fa2ab29bc0b32c9fadcca" + }, + { + "kind": "file", + "path": "img_3267.jpg", + "sha256": "f4a21de09100ce518260cfe778fcd08f004c6fb2e8e4acaf739b79b92a76ccdc" + }, + { + "kind": "file", + "path": "img_4508.jpg", + "sha256": "236775ce6fda87f2688ece7674bcd49af433ac52c3132459ec7a0977727e325c" + }, + { + "kind": "file", + "path": "img_3501.jpg", + "sha256": "fc5a70431e269e34f1f5ae46c57d0f169ac597e40b07ad6a4727b9a0f51d2d70" + }, + { + "kind": "file", + "path": "img_4246.jpg", + "sha256": "bda4279654e50ac8cf75d4db3242c97fc0f976c83fefb626086053a1d078f463" + }, + { + "kind": "file", + "path": "img_3529.jpg", + "sha256": "9bad7006b40eca287ccbf71813bb9bab9e5dfc457cd042cf8796a20d2b7c6ce9" + }, + { + "kind": "file", + "path": "img_2637.jpg", + "sha256": "657f261c07c32a2608357823c9898cf7c8ce65eb1a5504c921f2a4998f737480" + }, + { + "kind": "file", + "path": "img_1458.jpg", + "sha256": "843c01049efe28fc0026a6327e3a26f80a286f2ad128c283af938ab2ba314914" + }, + { + "kind": "file", + "path": "img_24.jpg", + "sha256": "38b71b8899c0fa8171cd48e91941510ee43679bd47742ca581bae707b53c1f0e" + }, + { + "kind": "file", + "path": "img_2151.jpg", + "sha256": "9632b4641282d7cfcd5200e49d2a24f0d5c212d4d9062f0226d304e4028bd9e3" + }, + { + "kind": "file", + "path": "img_30.jpg", + "sha256": "62cb6006101f9e9da55d108af85503a5f43f7b5c42906f44c0331ac9d527891a" + }, + { + "kind": "file", + "path": "img_4534.jpg", + "sha256": "3b6fb1d76e7b3fe9e9a4876f107717d52d9558507439354a9a7323ef84930ae9" + }, + { + "kind": "file", + "path": "img_4252.jpg", + "sha256": "a59897eeef962a2e04ee430510788b32b9014a129bc152ae51b1a3e933fd6144" + }, + { + "kind": "file", + "path": "img_2623.jpg", + "sha256": "ad57afd45dada3c0db8273e03e3e2fe9dad2abc5d9b681b408373cae6a0aaf54" + }, + { + "kind": "file", + "path": "img_2810.jpg", + "sha256": "3efdf3e86689d877db274d64d5fb83ff1c92d7ff6538626c663d7d74d7dd3cf6" + }, + { + "kind": "file", + "path": "img_447.jpg", + "sha256": "12f5c24d61f47407b80938a32077a384c78514162f6c0249090a6a89638ab83c" + }, + { + "kind": "file", + "path": "img_453.jpg", + "sha256": "ff3eda1faed011241ecf65bb17c3d46a4ada60efacc353a5d7033244a4678ada" + }, + { + "kind": "file", + "path": "img_335.jpg", + "sha256": "9c57d0c11bb65b7aeffb0c419d09b9109ddded761b70bacac9a8a825cbcdba7d" + }, + { + "kind": "file", + "path": "img_4285.jpg", + "sha256": "5db30863c250d6bcdee849400b894916399dbe3c1a02fd04acd8577ddb82e6c8" + }, + { + "kind": "file", + "path": "img_3298.jpg", + "sha256": "3e92fbd06ca2c63b7408f4d5ea6a9317dd7b7910da71e01c4a31df35dc51b393" + }, + { + "kind": "file", + "path": "img_2186.jpg", + "sha256": "c4172cd0f9cd1a3a94a53d20172b9d8f0cc4d24d5ac3816443f923c149dc04ba" + }, + { + "kind": "file", + "path": "img_2838.jpg", + "sha256": "d37231c54821c8987bd84a45429277a25e06316b774d40e44049e954866079dd" + }, + { + "kind": "file", + "path": "img_4291.jpg", + "sha256": "98d6e0249a3f52ae709cdcbd74aa1ea24611b180f609a373eb5a87cec75b6283" + }, + { + "kind": "file", + "path": "img_309.jpg", + "sha256": "329cc77a567f6eae8cd8cc27a4dc1a45c1f8e27a15cce0ce25410bae2abbff83" + }, + { + "kind": "file", + "path": "img_1499.jpg", + "sha256": "fbc1dfd6249ab5380ff656cf8e84ff609673bef97f4f4cc7d39c727b6f642968" + }, + { + "kind": "file", + "path": "img_2190.jpg", + "sha256": "33e78c7589add651784c7abffde540678d6b640443917aa3a012836d5b7dc7d6" + }, + { + "kind": "file", + "path": "img_479.jpg", + "sha256": "9dd8c9dd9eb8e461da0346313cf042618575702167c330fed39a7d13debb4676" + }, + { + "kind": "file", + "path": "img_4287.jpg", + "sha256": "188256898cc1f1849905b0b2a76b670e1af902c7ab0c443e781833e963d70b94" + }, + { + "kind": "file", + "path": "img_445.jpg", + "sha256": "10c65a847e94144a80043068695e66f1e6236c01c12e7092605006c49544c7d0" + }, + { + "kind": "file", + "path": "img_2812.jpg", + "sha256": "4478b1fe45363bfe138c268725fec9f1e1b25666b8042a0d572df3d59e2e2316" + }, + { + "kind": "file", + "path": "img_337.jpg", + "sha256": "b54976c1981a4cd5822d6aa586eece1f060814c44aa8d00525b32c86b965e226" + }, + { + "kind": "file", + "path": "img_2806.jpg", + "sha256": "6f94d3a68578785203b13f4e20fd3daee871075defb20b2bdfc69fd10595f750" + }, + { + "kind": "file", + "path": "img_451.jpg", + "sha256": "dcd7cb1dc76e4ac161143ec1c41c042053ad5a1a263217683ba17a97ebf0377d" + }, + { + "kind": "file", + "path": "img_4522.jpg", + "sha256": "cab9c50090cf6a94d006a111c6e4bf3580e1dfd7d21185be2b9bb68c4d314473" + }, + { + "kind": "file", + "path": "img_2153.jpg", + "sha256": "7060ce99f30b0bb145a0338277c7729b66f85e268e0572fdb0b5a3ac4163daa3" + }, + { + "kind": "file", + "path": "img_26.jpg", + "sha256": "97b714d2857b52f34016d389272b8b0085fd58bb4536a2a973fa193f0d49c20d" + }, + { + "kind": "file", + "path": "img_2635.jpg", + "sha256": "04000e95e4ccc7d2864f97c95d163a529e9f536937e24cdbf1860c01e2381a00" + }, + { + "kind": "file", + "path": "img_4244.jpg", + "sha256": "0c0c49e39dd0551603a6302fb9ce011ab2181485b8caa4f52cfed15296565607" + }, + { + "kind": "file", + "path": "img_2621.jpg", + "sha256": "2fe78896f6ad374519fd68ec67e9921f551d441fb40a6a698cf6b0af85b6efda" + }, + { + "kind": "file", + "path": "img_4250.jpg", + "sha256": "3988b353908c607aaf2ebe41e212a69c2fef7a29cb62ab85b1749a76bba7eb65" + }, + { + "kind": "file", + "path": "img_1328.jpg", + "sha256": "94affa2d3fc0f1d79199d34d1a8af366ba2cd1ced5f7f29df2fd36ddd69d5627" + }, + { + "kind": "file", + "path": "img_4536.jpg", + "sha256": "052a9962b1d8b3fc2a9b4de13f59fc5663af24c4837664c73e59e248b65b735b" + }, + { + "kind": "file", + "path": "img_3259.jpg", + "sha256": "ab74ed7cb9ab0003f4738160cfba56b4063a0e1abd32afcc4380d71f04871efd" + }, + { + "kind": "file", + "path": "img_2147.jpg", + "sha256": "4e046593050d5e97775cee94b539dae0556cf1c5317b5bc5e93dcecca43acaaf" + }, + { + "kind": "file", + "path": "img_32.jpg", + "sha256": "655fbe6951060c831807a2b6081c7402445ca74bb8f5a40f7f15c63429ca6764" + }, + { + "kind": "file", + "path": "img_1466.jpg", + "sha256": "3b5611786f89b8e93353d88b92d309ac5339adac27c475f2377e4a35640e1990" + }, + { + "kind": "file", + "path": "img_486.jpg", + "sha256": "e17e908e35d2c3e352595e113bb687b4e72be0448fce6c53665053b7f2af9805" + }, + { + "kind": "file", + "path": "img_3271.jpg", + "sha256": "9b6222991b0b8d2a36d66c18ed5d837660349f3a202496806654ae4d6206490a" + }, + { + "kind": "file", + "path": "img_2609.jpg", + "sha256": "44de4362f2612b0ea736a57de983add0dde21cbad1e1a3f10b767ae47fa5ae10" + }, + { + "kind": "file", + "path": "img_4278.jpg", + "sha256": "99dcce16e76c212105ffe2a998c34439a91690f13e8eac9a41243a456e89c023" + }, + { + "kind": "file", + "path": "img_1300.jpg", + "sha256": "174ffa5a3e10e993204a74aca3001114d5229e3194fe692444acfa5552f0d8b4" + }, + { + "kind": "file", + "path": "img_1314.jpg", + "sha256": "079bf74352fe3c2a901b22ddf802df8c34d588350bd0519f804f51fcf59fa574" + }, + { + "kind": "file", + "path": "img_3503.jpg", + "sha256": "c1136b90265d18dabf05a3a2175c9791a26b491490a99c8e7d1fcf1630730d1d" + }, + { + "kind": "file", + "path": "img_492.jpg", + "sha256": "0b32ecb3586bdb4788f0561d6567880d695c5d604e4d4438038771e33f2d0c74" + }, + { + "kind": "file", + "path": "img_1472.jpg", + "sha256": "53bebb9903a97762837fdda7934af2f839f1de2c2d19a3696831380129b62ff2" + }, + { + "kind": "file", + "path": "img_4085.jpg", + "sha256": "b4487ae743a6d3144da39838270a4fce76c0e60cebf7969f6c001227af37e6cf" + }, + { + "kind": "file", + "path": "img_2392.jpg", + "sha256": "940a9d872faa1d650ebf9fc8a0f2f608eb4bb342dc0824b7c59873200197afff" + }, + { + "kind": "file", + "path": "img_1843.jpg", + "sha256": "ccba1d018ad378e6521b227b760337fc8f1c9715692b871ef228d6da185d27c8" + }, + { + "kind": "file", + "path": "img_1857.jpg", + "sha256": "c10834a67014d48775aa7aa515e435e39168a01689c1f64d48339df9e5d720a8" + }, + { + "kind": "file", + "path": "img_3098.jpg", + "sha256": "c1d1f3b592cbf93b64e758241991e462727227f57408313b5ebdfa907235a61c" + }, + { + "kind": "file", + "path": "img_2386.jpg", + "sha256": "e6c4c60e1017ca0f6f24bdcc886395eb2b1eeb39dff0afa45fc9987d32c59e2c" + }, + { + "kind": "file", + "path": "img_3926.jpg", + "sha256": "c60812d55badb598dcb6e1572d6f62ae2d2e53b3e2b0f86175d6772672250eac" + }, + { + "kind": "file", + "path": "img_109.jpg", + "sha256": "3449cf9332f46508ec0ac61f2d9a56f8514c2aa9471e7a6513f825935f7aaed4" + }, + { + "kind": "file", + "path": "img_647.jpg", + "sha256": "e775d738c661a4797532052a62e7317ff323a67734b3cef1b93324bf1da7aca7" + }, + { + "kind": "file", + "path": "img_4907.jpg", + "sha256": "ee0d4615e63ca58fd2093367a27265aa5ea83d5b6f6412b36047442f2ee27d78" + }, + { + "kind": "file", + "path": "img_653.jpg", + "sha256": "7afb4e76d74d2bfdd9bc907e7cf7ad8341745836316da0607e30a131e70c977f" + }, + { + "kind": "file", + "path": "img_135.jpg", + "sha256": "82d149bc31ebfe85047e8c3095b9a2b8494a8783070ffa0be695d9afb648075e" + }, + { + "kind": "file", + "path": "img_4046.jpg", + "sha256": "fa2fb7921a29b792f3fa7141b689ae804e5a92bfa2099b4762afe44142c545b9" + }, + { + "kind": "file", + "path": "img_1880.jpg", + "sha256": "10e2174ba027bd11d02905fbf407dcd23b0af4aa2bf694fbd69901ad831583d2" + }, + { + "kind": "file", + "path": "img_1658.jpg", + "sha256": "8e9d0b857986e6dfd51d98343d94ad4f70b8c5aeee113bbf32d26cbf211af540" + }, + { + "kind": "file", + "path": "img_2351.jpg", + "sha256": "85dde3a64011aede43b8bee4b0fb8865efe119d3126c17136fc3e6f051822257" + }, + { + "kind": "file", + "path": "img_874.jpg", + "sha256": "4e0ec83f4ae463fafeb3d4128a4ea4281d36dcfa4b18aff52a5b0030e7780478" + }, + { + "kind": "file", + "path": "img_2345.jpg", + "sha256": "6dd98ad2520b15c15a9e3386319f7928e87da088c389dd66cf97e04681ccc652" + }, + { + "kind": "file", + "path": "img_4734.jpg", + "sha256": "ee415371edc22c6cd63f133057953fcd2b04e7978d01bd021cb4da4df8747ec5" + }, + { + "kind": "file", + "path": "img_1894.jpg", + "sha256": "d952f63675485a4115324f63377137485bd42c83ce4a59cf1d97c4d53b1bb327" + }, + { + "kind": "file", + "path": "img_2423.jpg", + "sha256": "57b2b0f0c6927a6e38e3a82b7434919d7c59c4dec6103383855d78e47c9d391a" + }, + { + "kind": "file", + "path": "img_1102.jpg", + "sha256": "683824c454591f6add1fef8880d671bad4a52328de9da40ba500d4c43baaaa21" + }, + { + "kind": "file", + "path": "img_3073.jpg", + "sha256": "3c8aaa1a2176b3bef93ce5538b027152b230cada8996f7f61b20eff19baae443" + }, + { + "kind": "file", + "path": "img_1664.jpg", + "sha256": "02129c1269cabb6de55b5474833b1d276be78f39c91268ca6097ce21dd0765dc" + }, + { + "kind": "file", + "path": "img_848.jpg", + "sha256": "1a31e8e1b02a396aae834986fdbc48b1e3c6df861244774cc73e97444a14b4c9" + }, + { + "kind": "file", + "path": "img_2379.jpg", + "sha256": "5ecadddb5992d6c426cd9958d724f97edf12bd2ba3ab3bd39b73ed8caab0bc5f" + }, + { + "kind": "file", + "path": "img_3067.jpg", + "sha256": "b29a550112c0e0b90c6afeb61024a50c5f4e2245e71837b80a15ecc33a9bb8d6" + }, + { + "kind": "file", + "path": "img_690.jpg", + "sha256": "aa82233b6f552d5996de02a25ed425eac84b7000214ac1ecec8ad90ffafc4cd6" + }, + { + "kind": "file", + "path": "img_3701.jpg", + "sha256": "ff26d83f11ec7c74511bf9ecb1d775ac7c791109f10121a11644292f356da6f4" + }, + { + "kind": "file", + "path": "img_1089.jpg", + "sha256": "c43e0820b702c6dcfa9918cbf768f9f3d1ca12ea7f03fc8fa816022caf32169a" + }, + { + "kind": "file", + "path": "img_3846.jpg", + "sha256": "a91bd5bb0d3a2fbce471b76fb8ebd366a01ebf3ab79d9bc38f40a958b685645b" + }, + { + "kind": "file", + "path": "img_2580.jpg", + "sha256": "8870c068086107433b9ec2b9c9339517db29e694d1012a5d74874708114852bb" + }, + { + "kind": "file", + "path": "img_1937.jpg", + "sha256": "36ac438a469800f3a9687beca460199dd651a15387c63848a228efa2598a5045" + }, + { + "kind": "file", + "path": "img_4683.jpg", + "sha256": "dff7cf69e301b4d4b411580de93566fb48a34f2cb5932e04b14970ea90501ef1" + }, + { + "kind": "file", + "path": "img_2594.jpg", + "sha256": "61f607eadb72137bd453aef346f36bd5a76a79a14c7afe8df796708e2fafd631" + }, + { + "kind": "file", + "path": "img_4873.jpg", + "sha256": "14ddbb64288c25fcabd6a636c5319272e8cbe332cedd46aad54f44465364f4f0" + }, + { + "kind": "file", + "path": "img_733.jpg", + "sha256": "a0365583af313d4ee52f2f9260a2e4211ddd8251ecb0066f062d9ef811b4b0fe" + }, + { + "kind": "file", + "path": "img_727.jpg", + "sha256": "b39e4246ee8da071b85bc53f53f624c9cd40e5dd5cdc1135072113f6996f4608" + }, + { + "kind": "file", + "path": "img_3885.jpg", + "sha256": "a423afce1afd51f1949002228db2e0d509be7a86fa9de0f7fef5319515de1d1a" + }, + { + "kind": "file", + "path": "img_2543.jpg", + "sha256": "2b28aa294861a3f362366e2cd26022e0e03fbb48912b866a32fc0c888b635d73" + }, + { + "kind": "file", + "path": "img_4132.jpg", + "sha256": "76b717519a466b6cfcd6c0897b52bc432c22bdeb673fe080f586ed08742e9b95" + }, + { + "kind": "file", + "path": "img_4654.jpg", + "sha256": "5ec710c0716f02f279462a41733f7da9d204bfae06c0bef45de63a5505fea965" + }, + { + "kind": "file", + "path": "img_2225.jpg", + "sha256": "280904e2ccbd7d77fac76e483193496980b885670f56531c0922827f66b9a458" + }, + { + "kind": "file", + "path": "img_4640.jpg", + "sha256": "62813ddbb57f117567c1a61424ac4d6537f8368ebb20f9d09966c5bc48f4feeb" + }, + { + "kind": "file", + "path": "img_4898.jpg", + "sha256": "21bdbe6dec0753f442581f6e67030f5f5eaabbf1b4dd705723e4dc5126e65603" + }, + { + "kind": "file", + "path": "img_900.jpg", + "sha256": "fa7315b16dc4d78b88a52e30c0177528434035dc0c7d158a20cc2a6191aff3be" + }, + { + "kind": "file", + "path": "img_1738.jpg", + "sha256": "edebfd5c4657300da06fff7d4e591ded5c935b6cd1fd017143acb357b3d7d731" + }, + { + "kind": "file", + "path": "img_3891.jpg", + "sha256": "0472d40d4f8feaaeb764185de78f908a71f3bf29c61f3f23a3196503bd64b5c9" + }, + { + "kind": "file", + "path": "img_2557.jpg", + "sha256": "8cee91ae0cf90e5f77f86dc9db5b942e085b827964195cb5f3791cbe09b2fdc5" + }, + { + "kind": "file", + "path": "img_3649.jpg", + "sha256": "4efbd459d1eed4d83b19dfd164b1bfba2a31ff50bbc9853e80a401099a3b1362" + }, + { + "kind": "file", + "path": "img_4126.jpg", + "sha256": "784140b62e25f963c1d3a2f7fdaa0b08b8923fe68ed73ed8996706979036c791" + }, + { + "kind": "file", + "path": "img_1076.jpg", + "sha256": "603ee195b9434141f7667e6680c3df4f31f7796a419064a7b5c281f20e937422" + }, + { + "kind": "file", + "path": "img_3661.jpg", + "sha256": "2e106f23cc8d093a6e157d990ba6caccfddde93dadaae3d894d0db7a6372dfac" + }, + { + "kind": "file", + "path": "img_4668.jpg", + "sha256": "5ec54228e4246896b15db5b6b95dbf4c07100973b8881d6b6a50d16d419face5" + }, + { + "kind": "file", + "path": "img_3107.jpg", + "sha256": "a79bb26631a2edc0be345942d17cef5d2318c39f499bd1b718dfbd1e6711ac27" + }, + { + "kind": "file", + "path": "img_2219.jpg", + "sha256": "63c4926e8afe0f3954d9f163a52998d089ee87cc704570fa17ac3348767742d0" + }, + { + "kind": "file", + "path": "img_928.jpg", + "sha256": "b94832c1b1d297c843f0b4d209d3c58451746244941804fdc8a39637323b425d" + }, + { + "kind": "file", + "path": "img_1710.jpg", + "sha256": "298f6ed7a92c4747411c867e290d03c721ed14ee05c074e67ec4a567e54bbbb5" + }, + { + "kind": "file", + "path": "img_1704.jpg", + "sha256": "392a1a39deea56cfc00c6e9649f4e886d0d43c230e590178287d0d7c82b7be6b" + }, + { + "kind": "file", + "path": "img_4495.jpg", + "sha256": "b02901bc26660651afc15ebbcfda997fe097a7cb48d2deb450d6d88ca2f13074" + }, + { + "kind": "file", + "path": "img_2796.jpg", + "sha256": "9a7fd8bd5a8d468d2a31d67c6f691e69a6a042194311733a59268c517bc7feb2" + }, + { + "kind": "file", + "path": "img_3488.jpg", + "sha256": "43f2769e083795867f1297242d82a9c058d69a752b93894eb9b4c25f728a3b30" + }, + { + "kind": "file", + "path": "img_519.jpg", + "sha256": "248cec0d4cfcf7fe199c0b489e0e83293ed2f0d09dc59fbe67bb8bbd8ce753e0" + }, + { + "kind": "file", + "path": "img_4481.jpg", + "sha256": "00a8c5dd3a208ef8c114cdf09b09c51c8e0c1ce33b7fbda0c0fe539ea917ad12" + }, + { + "kind": "file", + "path": "img_531.jpg", + "sha256": "82eacf9da132c19f02522e6205febaf69d1e518e2e541a2f23fb6a7e405aa48f" + }, + { + "kind": "file", + "path": "img_2966.jpg", + "sha256": "b7d8db4137246d216716dc8658ccb5d7dadc992ce657e2b75bc305d49dd1c72b" + }, + { + "kind": "file", + "path": "img_257.jpg", + "sha256": "41d6b628629dd0df15c4d475cf51675b9fb26b830125b359044061c1b5bfa460" + }, + { + "kind": "file", + "path": "img_243.jpg", + "sha256": "05e1e0e3ff3bd784339d472e5d423123a26f4e412ed1c55fa4bb473022168a18" + }, + { + "kind": "file", + "path": "img_525.jpg", + "sha256": "d5292415755f4801ae674b68cf6ce7afca94fe556c27b3758cfb4ae603e75ad7" + }, + { + "kind": "file", + "path": "img_2027.jpg", + "sha256": "e2dbafd1d02a373c225884e14775ddd1b841cd12c48eb0e66add3038611ad094" + }, + { + "kind": "file", + "path": "img_3339.jpg", + "sha256": "ab6ffe82557220656777004f4e145e78639c6cde6c27e2820194ecdb1aebb0a4" + }, + { + "kind": "file", + "path": "img_4456.jpg", + "sha256": "62c60d6160b6f7d189fa34a4abe5a633c3402f037a14377c005e972e7e3763f0" + }, + { + "kind": "file", + "path": "img_1248.jpg", + "sha256": "d8680809dff676a2eaf6c3a63765ffe07b52eff41e3efa9435c14b12a078f0f9" + }, + { + "kind": "file", + "path": "img_2999.jpg", + "sha256": "9ed2bb7de6f6da12f9b5888554ecc5028d9dfca447f752befee4cff82bce8bce" + }, + { + "kind": "file", + "path": "img_2741.jpg", + "sha256": "4fa9d68ad65066900c632ce9a9264572079ac0d5d26a7e726a91c3456cdca0ae" + }, + { + "kind": "file", + "path": "img_4324.jpg", + "sha256": "97ecd39908c4832c025212090fc3fb200d41c5d85ffc3fdeb9f28d7f6532f469" + }, + { + "kind": "file", + "path": "img_2755.jpg", + "sha256": "593328228ce46704c390a5d08a11ebb991d7b41fe81c009f87217cbdc47f48e6" + }, + { + "kind": "file", + "path": "img_2033.jpg", + "sha256": "e7cea536e2bccec6c742eaf61a3e771e922935cef20077cdffc6010b71b0d5c1" + }, + { + "kind": "file", + "path": "img_4442.jpg", + "sha256": "1d7044fef68aac3e85adabb5a15af7defa1cc7c3b7b5ed5e0df311865e6ceecb" + }, + { + "kind": "file", + "path": "img_1512.jpg", + "sha256": "e9ee850b9f9a31d96908ee82da3cd74622a2cbd35d62d20c153b9fea42780c73" + }, + { + "kind": "file", + "path": "img_294.jpg", + "sha256": "930c3bafe999affe7966e33c05a8e21624597e889049ada15aebbf21d3800726" + }, + { + "kind": "file", + "path": "img_3463.jpg", + "sha256": "183c3ba4bfcc18b02171901d1cbb486299f0d8c33764f6ce35e413d43aabd492" + }, + { + "kind": "file", + "path": "img_1274.jpg", + "sha256": "88acf8baedc2f98354c953f625993aa1b60ea752d027d5dd961d67a02efaefc7" + }, + { + "kind": "file", + "path": "img_1260.jpg", + "sha256": "a2ac505e91714a655fead677ded65d120b723b0b2433939708f1445ff70c6376" + }, + { + "kind": "file", + "path": "img_4318.jpg", + "sha256": "bb9d0fc7e49bef548e5d84c930adb3192c4f735f9a51605157e6c1230160fa6a" + }, + { + "kind": "file", + "path": "img_280.jpg", + "sha256": "e963cb93cc613aa4061c4ae1a3f7bac60b26a833129e0002cef8b348ebab379c" + }, + { + "kind": "file", + "path": "img_3477.jpg", + "sha256": "5889b3c1c093119c90c700ccb52470b70abeb1a0e3980d899496b28ebb4e4e5b" + }, + { + "kind": "file", + "path": "img_2769.jpg", + "sha256": "6377e79342c51883a99eafd63ea344ed3fd29e5f4bbd9bae6acf3cf2bbbac11e" + }, + { + "kind": "file", + "path": "img_3311.jpg", + "sha256": "6a5cd75bd4dee4b14d45ea328adf911ec6d77075b9b9aae97eb0574408d55c62" + }, + { + "kind": "file", + "path": "img_1506.jpg", + "sha256": "791f2defe337d1947778d0f0e12765e9732e40eda50fab86f7e71ecedf631383" + }, + { + "kind": "file", + "path": "img_2768.jpg", + "sha256": "89088d86e3df63bd5bc8a59057c079767baa83d084f204be99e1b7ed3d6e1689" + }, + { + "kind": "file", + "path": "img_3476.jpg", + "sha256": "b9858b6381fc0f453d8acd3ef43a61c93064d687305d9c029e6385e3174584fb" + }, + { + "kind": "file", + "path": "img_4319.jpg", + "sha256": "ceb329babc619a140d83a0a724e4e0681b150a0f82453d34206e2fc09159d7b2" + }, + { + "kind": "file", + "path": "img_1507.jpg", + "sha256": "d00798edcd8a042951c971e2f24cbfceacf79868b2cdeeb019f5b9c11af55113" + }, + { + "kind": "file", + "path": "img_3310.jpg", + "sha256": "e4adfa4468493d143c710882287044ac2611bf8c5bdf9e90830c54a7e24d5a4a" + }, + { + "kind": "file", + "path": "img_3304.jpg", + "sha256": "cb888f23894db58492ed7c72a7d941d6a244e00aea1e6852a79a493f44c479a5" + }, + { + "kind": "file", + "path": "img_1513.jpg", + "sha256": "0a313d28c7a2efde42af5e015a2f38f0198256554376776cb3ed7b7fd43e9b57" + }, + { + "kind": "file", + "path": "img_1275.jpg", + "sha256": "a6c53929f99eecd2d70b5813ede254771f6b3a8e8c6e28093ac027f58be46a52" + }, + { + "kind": "file", + "path": "img_3462.jpg", + "sha256": "9b0b3543c3aa10de9ad0b185fec4e67b30b70c8a0ef35a72cd5094f59d18bf36" + }, + { + "kind": "file", + "path": "img_295.jpg", + "sha256": "d2170217907fed4d197f584e9e11650681722a644a97e73517238124b592c259" + }, + { + "kind": "file", + "path": "img_2754.jpg", + "sha256": "e1e7140be3fcac206bb6b3370b954e4606e23a69902ec7113a5223b8b0246517" + }, + { + "kind": "file", + "path": "img_4325.jpg", + "sha256": "0532b7786c4f3a95aeba4af89c4ae8addafac34cb8d556b7321a80720374a570" + }, + { + "kind": "file", + "path": "img_4443.jpg", + "sha256": "78a42dfb1f0ba51c088ba390de4dc956bab2c6d08fb685d06fcc954b3369df15" + }, + { + "kind": "file", + "path": "img_2032.jpg", + "sha256": "a24168eb796e41f51133b64eb91e49ee5bc9777504c2054b884f98bd97bd2fa9" + }, + { + "kind": "file", + "path": "img_4457.jpg", + "sha256": "f2e523ce177b7e9ce12e41b4613111cf014813d9501903016419867bc84ecf26" + }, + { + "kind": "file", + "path": "img_3338.jpg", + "sha256": "3404612aaf032e7db1f8107dba32156e3871aea1c88ee1c10f8f78e22ec8d895" + }, + { + "kind": "file", + "path": "img_2026.jpg", + "sha256": "117df9ebe6805f66644a3bcf26bd0388de791abf5f7dfb634c92a53a4628e454" + }, + { + "kind": "file", + "path": "img_2740.jpg", + "sha256": "c271d7835974acc160ffb876446b76affb5787b850486ae0fda86c7b5d101964" + }, + { + "kind": "file", + "path": "img_4331.jpg", + "sha256": "ed19b02dd74a5603b62e507f4d480f85e8c8f677edf6df30c841b5c280ee9387" + }, + { + "kind": "file", + "path": "img_2998.jpg", + "sha256": "716a73a12eb2afdb26cb84f1d9bc5ad4012a083af41e9a3ca6a345f20bfa7fac" + }, + { + "kind": "file", + "path": "img_1249.jpg", + "sha256": "17ccbaa57b974c7e07c95c1208f5f1da0ddace5ce47c90d911068faef23e431e" + }, + { + "kind": "file", + "path": "img_2973.jpg", + "sha256": "9e4df909300c2a41e51bfd7fd62e9fa41fb73918e8ca4170a6e1af7ca114102a" + }, + { + "kind": "file", + "path": "img_256.jpg", + "sha256": "61cce5ea583303272725a378f0c8131ba78569384981cedc5e0b6e0e68bab6a9" + }, + { + "kind": "file", + "path": "img_2967.jpg", + "sha256": "c78467e84ff236cba069ec84f7bf305ebf4740db962af16bfc2abe198d7818f9" + }, + { + "kind": "file", + "path": "img_3489.jpg", + "sha256": "c52f6bed925e56cef9c3563c026540e4fdb98dd8f141231ff2480dfd1ba54617" + }, + { + "kind": "file", + "path": "img_2797.jpg", + "sha256": "2f71189e20fd3556ab8167f7a564cc98e8ca99161363dc72a95a58b9b1e82e5c" + }, + { + "kind": "file", + "path": "img_518.jpg", + "sha256": "bb82f52af526822ca98a83fe054664f968365f30f6497ceff13d5421260ee118" + }, + { + "kind": "file", + "path": "img_4494.jpg", + "sha256": "ab11fe118e0f491aca7f2b3e7a74d3621a8b590e473bcc8b3593af4a26c051d9" + }, + { + "kind": "file", + "path": "img_2783.jpg", + "sha256": "03eda02944b097027567314c4a7b73803948a4ab36c3408755f6422e0e77f2dc" + }, + { + "kind": "file", + "path": "img_1705.jpg", + "sha256": "a721b76944b71802eaa171355fe2751b66bcea101513899848c987dc0ef26817" + }, + { + "kind": "file", + "path": "img_1063.jpg", + "sha256": "51ec48a513ddd9b2640924aba6f4c1fb8856f655f2c1f8bf09a70bc6f3e6ce7c" + }, + { + "kind": "file", + "path": "img_3674.jpg", + "sha256": "05359904a64cb9b32d963497316156da8d791f7a440a7153a5adcfa07d9113c0" + }, + { + "kind": "file", + "path": "img_3660.jpg", + "sha256": "ed1aadfd7b2463e3b6fc9e11dd50eaef2c054a998d05e366bed2f9db80f91bd3" + }, + { + "kind": "file", + "path": "img_1077.jpg", + "sha256": "f4e90f03b8c32da30f8ca244cdd2636f1d2092fe51e58082e2990d2fad4b9970" + }, + { + "kind": "file", + "path": "img_1711.jpg", + "sha256": "aa1c3b3eebab3e0bfa1736d668299391d7eac44449331fbb047a46d19888d10a" + }, + { + "kind": "file", + "path": "img_929.jpg", + "sha256": "35f7ba693f1fde29bae9826427402c368b174ba2248e930c1cf24f6ff55648a3" + }, + { + "kind": "file", + "path": "img_2218.jpg", + "sha256": "ed1b5a364caf0e0190eb017b8f7ebcfab4aedb674fc0e9a43ef35fa307221930" + }, + { + "kind": "file", + "path": "img_3106.jpg", + "sha256": "dd7574fca93819455110985a30afd04491f197719a111129b4271611d2708d69" + }, + { + "kind": "file", + "path": "img_4669.jpg", + "sha256": "e83cbfd879f0bbb8c98ad24fee205d0d45062c752d78ba5a5d2d83100055eab0" + }, + { + "kind": "file", + "path": "img_1739.jpg", + "sha256": "bfa8c67e8d9df49eb4b4cf89ec599922d90ea13113e96edd73b5afbaa580e9b2" + }, + { + "kind": "file", + "path": "img_901.jpg", + "sha256": "754eaff399949a3d7c5a270f677fd4746eb03ed905cfa5e77df44703061d21dd" + }, + { + "kind": "file", + "path": "img_2230.jpg", + "sha256": "6bf33b5d24b9951b42d6c22e1346548e34c1064985765b1f93640dd64fa25053" + }, + { + "kind": "file", + "path": "img_4641.jpg", + "sha256": "a9d556c905a83e57a5fe74ee33e45c829ed79ea10b6791145e7258a319bf1900" + }, + { + "kind": "file", + "path": "img_4127.jpg", + "sha256": "b444687fe7327d991658bf4eb10ffb031aa0871da693dbbab7aa17a0bd8e89f9" + }, + { + "kind": "file", + "path": "img_3648.jpg", + "sha256": "1eda9cd25715b96b3662854507c6974c92ad49ffd591f3cdde38c84f725d5770" + }, + { + "kind": "file", + "path": "img_2556.jpg", + "sha256": "8e202e5331c8268235539ab9cc655321f2c2507277a886816b0571bf79f572ef" + }, + { + "kind": "file", + "path": "img_3890.jpg", + "sha256": "f884955b7256c1224bcabc6e62b390767119c39d292da98ec0111bf0e81159ec" + }, + { + "kind": "file", + "path": "img_2542.jpg", + "sha256": "64fb328627217167cb55c336dc5df4ffff5c67bb8f4eb8315c0847113261a31b" + }, + { + "kind": "file", + "path": "img_3884.jpg", + "sha256": "c063689786f787e0f0fd275dff8ace03a20e498528f8888d01832a4096802db6" + }, + { + "kind": "file", + "path": "img_915.jpg", + "sha256": "e43e52f5de67b2d44b266e429a0a4876170f5192bcc9a82c47e42dc70472c8d2" + }, + { + "kind": "file", + "path": "img_2224.jpg", + "sha256": "781ec8bd712ea7623aac63751665af9037b2d89fb5b9bd0e3dc32d6e47c0db32" + }, + { + "kind": "file", + "path": "img_726.jpg", + "sha256": "6fa2091d19ebad324c58fa6bd1864083c5afb6661b9b018ea151b335827e3366" + }, + { + "kind": "file", + "path": "img_4866.jpg", + "sha256": "68fab42db6dfee7a8a7a57ae7d73e2c63a65c9ad50082f766e3d04ba9b69e599" + }, + { + "kind": "file", + "path": "img_732.jpg", + "sha256": "e45bc44ac21b6c0504d75b2aa08684b7e0d4e53bd590f92d27d228c650a51563" + }, + { + "kind": "file", + "path": "img_4682.jpg", + "sha256": "fd311f6609ec17f7cc187700f48b15dbb473c55042343e524ca4ccd57b326d09" + }, + { + "kind": "file", + "path": "img_1922.jpg", + "sha256": "1a05aa241051ac42e9426570eb8245b82ca5d15798ec1cbe8d1477e46bdb8a7b" + }, + { + "kind": "file", + "path": "img_2595.jpg", + "sha256": "55ce2ffe54471d5c7dba5adb42aac43ffbdc4a45dacb207e14dd11492f2f82a4" + }, + { + "kind": "file", + "path": "img_3853.jpg", + "sha256": "606d2601573650827fc2bf4de393ab40f8b281c05c045813122cdfc831071b4b" + }, + { + "kind": "file", + "path": "img_2581.jpg", + "sha256": "1fc075a0cca123cce40d49651e2538446e204ff4e36b72131aab5bc757b12844" + }, + { + "kind": "file", + "path": "img_3847.jpg", + "sha256": "a03a1763e18b144e2c690467fb287af1083d34dd738a5cb548eb2e2c9a2125c8" + }, + { + "kind": "file", + "path": "img_1088.jpg", + "sha256": "a4a9d2447c7c8020d4218960db2bdf30ecc6ab0d56acafc861e6da9543412d6f" + }, + { + "kind": "file", + "path": "img_1936.jpg", + "sha256": "a672c5985bf54e27536f40d3cd1461330462afd6a135b0ea48f7d180c88baf25" + }, + { + "kind": "file", + "path": "img_4696.jpg", + "sha256": "0a0fa8c06f135fe73c39917a67cdc4940d3dcc8922d2f7d007a529eb1a24d652" + }, + { + "kind": "file", + "path": "img_4709.jpg", + "sha256": "df1603ea53f777559ff8190cf4b582a7a647628b0c2be8a6d48133b308118c9f" + }, + { + "kind": "file", + "path": "img_691.jpg", + "sha256": "ab43196394cc90119952356d663e4e02a6cd1de7ca5208bc00465f29049a45bb" + }, + { + "kind": "file", + "path": "img_3066.jpg", + "sha256": "3ee975c477b83a7cd1df71a67ea8104fef8acea187b71aabe33f309de602f1e9" + }, + { + "kind": "file", + "path": "img_2378.jpg", + "sha256": "db9a24059a966ec1d4b5412cf1414e72090e69b53097a9c0ee8af8ef28ba99f1" + }, + { + "kind": "file", + "path": "img_849.jpg", + "sha256": "c5aa574c35add6875ae8100cd335465dbc91f333e7c91a6ba8d2c953c53e9029" + }, + { + "kind": "file", + "path": "img_1671.jpg", + "sha256": "63d1353e0666cae9b8c3085078da12923dbd5349dac7e19f9a2faa44a5bbcf50" + }, + { + "kind": "file", + "path": "img_3700.jpg", + "sha256": "d1eb11bd21b248be414a0d5ca25d0505dd3a7f37562be43ae5cf54c4652bba73" + }, + { + "kind": "file", + "path": "img_3714.jpg", + "sha256": "ef03b7b6648dec11fa5488844b5cfea9b940a420e0e55678340fe7908cce17e5" + }, + { + "kind": "file", + "path": "img_1103.jpg", + "sha256": "50407899dee6210d82c7e54bd20afc84f45384b8b13547185af433598d1bbb26" + }, + { + "kind": "file", + "path": "img_1665.jpg", + "sha256": "f7097782451df66e5eeb50c7c8a338345e8642489c0935d28245f77be95dcba9" + }, + { + "kind": "file", + "path": "img_685.jpg", + "sha256": "b7c75ad4e718a539d3a882cf3f270876f32974199ed5bc54ff4fc0f3e18366ff" + }, + { + "kind": "file", + "path": "img_3072.jpg", + "sha256": "c503277b99dd1fc79fba8749b3c47673e06c1579f2ebbc461b04429afc7c10aa" + }, + { + "kind": "file", + "path": "img_1895.jpg", + "sha256": "50089c241c1792a00ad753d6f00402ef981f526436b657195075129958e933c0" + }, + { + "kind": "file", + "path": "img_4735.jpg", + "sha256": "22afc3d028d5c90fe42110718c0299d8a668604a46d3b9398e63880f26c99534" + }, + { + "kind": "file", + "path": "img_2344.jpg", + "sha256": "09d18bffcfb19f86a5b35b799cbc53a1221e551a7b1dc4a406c74fda108974ad" + }, + { + "kind": "file", + "path": "img_2422.jpg", + "sha256": "6457ae417e466cc394c8291e0914c7d117861f38e440acaf7c9246f5ea41e642" + }, + { + "kind": "file", + "path": "img_4053.jpg", + "sha256": "d9e42af7628f51cbc510311ce602a4a32ba8334e0b8edf6c97e9342015487455" + }, + { + "kind": "file", + "path": "img_2436.jpg", + "sha256": "ec641a4e492f4730edda624a4fd0e499684954631dc24360cf7faa416dd35aae" + }, + { + "kind": "file", + "path": "img_3728.jpg", + "sha256": "0696910d4b6cf43e7551906b0e08e85dc94016c92048a0e0944a3694125ae5d2" + }, + { + "kind": "file", + "path": "img_4047.jpg", + "sha256": "0e8d49903de76cae9d0b51aa490cef59b6f3fe3aa670ffeae8283b9e29c58254" + }, + { + "kind": "file", + "path": "img_4721.jpg", + "sha256": "39e522c0cd07f5d25f7ca228edc91fae2b908c8ade113588363cb4f508e1809b" + }, + { + "kind": "file", + "path": "img_2350.jpg", + "sha256": "5887305b1b5605c11cb78e56dbfa90f8d364ef04d13f4e6145da50eee795144a" + }, + { + "kind": "file", + "path": "img_861.jpg", + "sha256": "8758a24dc30de393f43b2efe033eefa5172afe8484bb17f8a2a217cbb30da356" + }, + { + "kind": "file", + "path": "img_1659.jpg", + "sha256": "fbcf2e7b298598bdfd31edf6883e10645a85416340a18437da38f58549491ae5" + }, + { + "kind": "file", + "path": "img_1881.jpg", + "sha256": "78670f91d1a38ec99102bf4d7cfc71021a7c2b05d17073d0553d1c3cfc3ee0f8" + }, + { + "kind": "file", + "path": "img_4912.jpg", + "sha256": "a5013065b8d010516219b2e2dd2e8cee73a689b45ef076e121f0e286aa7c6ce2" + }, + { + "kind": "file", + "path": "img_652.jpg", + "sha256": "e748ecbb36dc365bc1978bf8753011bca28583ee01530796445cf32fdd8772d2" + }, + { + "kind": "file", + "path": "img_134.jpg", + "sha256": "33b87dcf1c961ad79267097ff2689c0c9a1ad38bee8a3190bfc9611ce9e173cf" + }, + { + "kind": "file", + "path": "img_120.jpg", + "sha256": "6172f68a566333af941161d857579da9565a23d945c989a484607f04e60f2368" + }, + { + "kind": "file", + "path": "img_4906.jpg", + "sha256": "dd99051200cf796e0d4500a2943d73dbb1bfcc6adb0e6f48e78b9695969ff2df" + }, + { + "kind": "file", + "path": "img_646.jpg", + "sha256": "11f0a5cb1950bfe14379d2ebd11bc6074ae59dcc672bcea05f56f2e220b2fc11" + }, + { + "kind": "file", + "path": "img_2387.jpg", + "sha256": "9b8325230156fa287ed31feb227eacdc251ab321118c45225b81ef9c5a4b11c3" + }, + { + "kind": "file", + "path": "img_1856.jpg", + "sha256": "888c29059ccd8086bfe570f66908f6feb7379c803c4029c55f4efb355fa0d282" + }, + { + "kind": "file", + "path": "img_108.jpg", + "sha256": "8f767b4de9f6986d5904e5d141e84ecc93357041fe0c1e5eeacc0c4ce518531e" + }, + { + "kind": "file", + "path": "img_4090.jpg", + "sha256": "56c843aa28951126da37512ea49790df6ed1260cc81b74ddc525b3894d09983e" + }, + { + "kind": "file", + "path": "img_3927.jpg", + "sha256": "2ab32fc278d34349cfe37356b896d25a1263b59b015624ed45cde78be68767b9" + }, + { + "kind": "file", + "path": "img_3933.jpg", + "sha256": "f5279bfae94b05f5b6074a5143e256ef438d140bfe0e37288e0af964798fd2cb" + }, + { + "kind": "file", + "path": "img_1842.jpg", + "sha256": "7e0681f54e846a82472dfad5dfcb9da0621837a2001ebc5c3ca3ea01e27df6ad" + }, + { + "kind": "file", + "path": "img_2393.jpg", + "sha256": "09433d7c41b4ceefb87d827efe20b27a5e7bcb87398ded1c36f384ddefb6cd00" + }, + { + "kind": "file", + "path": "img_3502.jpg", + "sha256": "60f0c52db98fcf164de5b9061b35961ac64c95842c3e6a7717d422228573b7e5" + }, + { + "kind": "file", + "path": "img_1315.jpg", + "sha256": "4178fda4ee3c5becc4452a19eb2f7028816685d4b3509950390f7e7c279a2407" + }, + { + "kind": "file", + "path": "img_1473.jpg", + "sha256": "3f902777698bad5c60197c84026468b266dee2846b97311d40fa795825f656f8" + }, + { + "kind": "file", + "path": "img_3264.jpg", + "sha256": "51fb84dd2c670d0fbdea1ffcc18ffe82735428c9027192886204ec73b018a9ac" + }, + { + "kind": "file", + "path": "img_493.jpg", + "sha256": "61a3a7c2f57dceb9fcfb80d6cbf54b6bc5290a3d81d7511a52ae2889f5750de9" + }, + { + "kind": "file", + "path": "img_3270.jpg", + "sha256": "5e692b9bd3119b4191046ef429be8fc3d37bf3c1b57e31fe9e6285276e8844ab" + }, + { + "kind": "file", + "path": "img_1467.jpg", + "sha256": "f95301575dea44b5176c9bd1331ebe30470d21bceafc8de7c4592387cec118d6" + }, + { + "kind": "file", + "path": "img_4279.jpg", + "sha256": "4b661a2ac9cf9b63cef56f39d5aa5ddc2ed7aa1a69c6edf9a53fc9da3e1d1592" + }, + { + "kind": "file", + "path": "img_3516.jpg", + "sha256": "22a522988488d9c82b35576b35879fa9ad1f028ac7b6c18ddc31edcdd2b7e76a" + }, + { + "kind": "file", + "path": "img_2608.jpg", + "sha256": "805acab428249aeee36c2afc36be38de40986e6e95a33125fb41c42b615ce027" + }, + { + "kind": "file", + "path": "img_1329.jpg", + "sha256": "f479cea99dbe2998b7979e650d74e45a2c45188654e7fffe2b55d0166ee7c184" + }, + { + "kind": "file", + "path": "img_4251.jpg", + "sha256": "b467f6865a7d53db6f8a65b6121eeaceda60ba5cc5d591e8823778d9d10cca8d" + }, + { + "kind": "file", + "path": "img_2620.jpg", + "sha256": "58c99c7f65ba4f1e939c1ce908f869e9457d78dc18500ef4788e77744898bcce" + }, + { + "kind": "file", + "path": "img_33.jpg", + "sha256": "9a3f57a3f67c559396be8035f6ecfb393ebc7285ecb468657d6847bb36396bd5" + }, + { + "kind": "file", + "path": "img_2146.jpg", + "sha256": "0f0747fa48b27c31978103ac707ff787211a4ff58b46f6cec492e173e30ffc4c" + }, + { + "kind": "file", + "path": "img_3258.jpg", + "sha256": "559aafd922efb0409d489aef65b9f1ebb51267f9b03216a09cd1398a3ac152f3" + }, + { + "kind": "file", + "path": "img_4537.jpg", + "sha256": "13a336715a17eb0092e19b5fc4faaa9d99fdd7edc6f3a3b25521d42a9244651a" + }, + { + "kind": "file", + "path": "img_27.jpg", + "sha256": "ade47b89afa104a8bc3ac5caa34d0ad3f6bf77182fbf4f2b71c7f5c06e2f6dce" + }, + { + "kind": "file", + "path": "img_2152.jpg", + "sha256": "5609185687f89180631b66b05b7b83d444b6c94f613bda37b0413ed822df1674" + }, + { + "kind": "file", + "path": "img_4245.jpg", + "sha256": "3df6438c0a9b640e71dcaf9a3521d9956689f878ed12534ee6678f80c170d4a9" + }, + { + "kind": "file", + "path": "img_2634.jpg", + "sha256": "4cc15b8fd244623313754145fc6c990d3b5eefcf8bdc56d9c186410d0cd2ad48" + }, + { + "kind": "file", + "path": "img_2807.jpg", + "sha256": "44f48815ffedf353532d8164262b216fe4c96bb506c956bc0d88d986d9f7384a" + }, + { + "kind": "file", + "path": "img_450.jpg", + "sha256": "a672bdb866233ad75b07f16e7317bb0eb9501692f2e748e781c0e4c0e86589cc" + }, + { + "kind": "file", + "path": "img_444.jpg", + "sha256": "fdebacd6335430ff8ade2addbb3f8cf33de6b7e3701f8a772711a6124401c76e" + }, + { + "kind": "file", + "path": "img_2813.jpg", + "sha256": "aa6c67a63d38dd57b8d4d888d6ec7f0eb21133eb426712b6ce015539ccb13b69" + }, + { + "kind": "file", + "path": "img_322.jpg", + "sha256": "a077b6e6abf3a2fd128f7a9ea19a67622bb4466009360ca1ca9388879ffa4361" + }, + { + "kind": "file", + "path": "img_4292.jpg", + "sha256": "289a533acf0a7b401397e7cdfd76a3143a22ad2a1be3c1c7733ed7dfa5d7fb6b" + }, + { + "kind": "file", + "path": "img_2185.jpg", + "sha256": "743fbd632c2a5e0d31947913b22b7e634254a194c0b3a22ddec840a550eaa6ea" + }, + { + "kind": "file", + "path": "img_478.jpg", + "sha256": "bb4a74600e248ec4a4556dda3f760b55d520d6cbeb4465d1eec6579189eeacf5" + }, + { + "kind": "file", + "path": "img_2191.jpg", + "sha256": "4ccaf7b498b862dcd41bc98847ed6254c7333d4a37fb9efe5ee7cde4bbc69b4d" + }, + { + "kind": "file", + "path": "img_2817.jpg", + "sha256": "8585cf22404f4ccfc52c0bfae9df5fee052f39be0f5df54e4b33ae70233db7c1" + }, + { + "kind": "file", + "path": "img_326.jpg", + "sha256": "11ae083d14075d8cb1a74d1984e358aaba58946a4ba6db2048e913f08e3e6884" + }, + { + "kind": "file", + "path": "img_454.jpg", + "sha256": "ff4c11639f31603e33fb2937402bd582a5468739b4ff6e920199d0ee752b94e3" + }, + { + "kind": "file", + "path": "img_332.jpg", + "sha256": "ec82d65a99bd00536af84050b65a3f4b93065da5fe15721a369493f6ec4798c6" + }, + { + "kind": "file", + "path": "img_4282.jpg", + "sha256": "68ea021de79cc4dc51ea964266a15da2b6010e966f513c9bd1dadd1bd71290b8" + }, + { + "kind": "file", + "path": "img_2181.jpg", + "sha256": "b5fb5484214efb187d175fbd036ddcb3ceef8534ff83e10c258f8e20317698d6" + }, + { + "kind": "file", + "path": "img_1488.jpg", + "sha256": "11521323143694afacd0b5a07969fab061628a885773048b27a984038a97c53c" + }, + { + "kind": "file", + "path": "img_4296.jpg", + "sha256": "1de1a805578ecdad394175400ac59a36dbb284aafb7df9efdcb50cf7bab41c03" + }, + { + "kind": "file", + "path": "img_3512.jpg", + "sha256": "d243fdb03df4801fed4bfc454a13920d24fe098be8da7c188e159f81e5f86da4" + }, + { + "kind": "file", + "path": "img_1305.jpg", + "sha256": "c07203ad4482c72c2c808f07c78c5e7d745284f353f8301af5fa7a108d3c9427" + }, + { + "kind": "file", + "path": "img_1463.jpg", + "sha256": "47d100b7e19ef5cadf9980a4886a9bfb3dee5b48ef2631f2cacd1b96218282d9" + }, + { + "kind": "file", + "path": "img_483.jpg", + "sha256": "1bdc3ae542613e94abf5ae13b5a0357b27c75dfb3afcf417ffdcb19a004ab54d" + }, + { + "kind": "file", + "path": "img_3274.jpg", + "sha256": "e12922568424b2baa779b77753b24cf0222482d5f15e68e4d79071e2b3e995af" + }, + { + "kind": "file", + "path": "img_497.jpg", + "sha256": "ae5ba4a6723e208b1fe1667b8edd44bc906eaff86bc0b5965cb3b772ba45e94d" + }, + { + "kind": "file", + "path": "img_3260.jpg", + "sha256": "5877ae6d2f3c3e75e8e66de09b84caa613631001d9e39718ab9dcc1ec6bd3e11" + }, + { + "kind": "file", + "path": "img_1477.jpg", + "sha256": "dcbbc5eccc9c0de544f5274a932317332fa110e56434a7295fc43e47052d60dd" + }, + { + "kind": "file", + "path": "img_2618.jpg", + "sha256": "72cf6206542ce29362d4a9992084490fec852b22b476ab423ae8912bc168da41" + }, + { + "kind": "file", + "path": "img_4269.jpg", + "sha256": "47a1c2aabbb2efdd01cef99ed3c2b890ca6a30e89a66efdc7fb1e8a2c8e17799" + }, + { + "kind": "file", + "path": "img_3506.jpg", + "sha256": "4f4f41430b2f2494f43fd356761edc0c31c93cfd688b98a43f284def1b1381de" + }, + { + "kind": "file", + "path": "img_1339.jpg", + "sha256": "9d4695dbb0508534c12879dc5b94c6750189c32fdb22c72b8e8ed26be9af2941" + }, + { + "kind": "file", + "path": "img_2630.jpg", + "sha256": "d23228b17f4bcf049aec9e9f93f7c3ed4235d3bfe578ac4cb8526a1d5ae284ce" + }, + { + "kind": "file", + "path": "img_4241.jpg", + "sha256": "65aead0b30df3d39805763da3f6373c59101b0dd22d9ba56b950f5d946e967b2" + }, + { + "kind": "file", + "path": "img_3248.jpg", + "sha256": "b189e418e8c197cc3fb9c6ddb6c6c7df85f8ad08496ba4bce93d037cd389709e" + }, + { + "kind": "file", + "path": "img_4527.jpg", + "sha256": "8e8813f84d6bd038589e06dd31da5c6427ade02254f7047cf0f2044f05dfb352" + }, + { + "kind": "file", + "path": "img_2156.jpg", + "sha256": "cec9d9faf37a1f98daab65c0d6c99b3f0e573de8e16403710dc3ef970ed354cb" + }, + { + "kind": "file", + "path": "img_37.jpg", + "sha256": "145adaa968ec97b94ff3fc0adcb6ed361227a26ee4cd217a423983b143737f7e" + }, + { + "kind": "file", + "path": "img_2142.jpg", + "sha256": "4af9df169636d30144c89afffcba03901655e3c55ae372a89886c319860c7ebd" + }, + { + "kind": "file", + "path": "img_2624.jpg", + "sha256": "37d9dbeab6978e658d520424b19376a4a3803a2b51ec9bdd93afc833d645a4e8" + }, + { + "kind": "file", + "path": "img_4255.jpg", + "sha256": "51391bed6041dfe691145db11f5a6c0261d52cc1835f46743841cc56c350955b" + }, + { + "kind": "file", + "path": "img_642.jpg", + "sha256": "035240f5640f968f953db2f5c381097852df0f80538da9932461a218e811b187" + }, + { + "kind": "file", + "path": "img_4902.jpg", + "sha256": "91b2ea3f86596dedcef69917a325fc96d70238702cd0aa5fbc82c1c9fd374062" + }, + { + "kind": "file", + "path": "img_124.jpg", + "sha256": "43420d942ee77973d7f311c9d740b0f128f720ebf9e83878490e5a9b8c9d30bf" + }, + { + "kind": "file", + "path": "img_130.jpg", + "sha256": "2e4faef234f3f9729979be89a53f82024b3e9f660a2960c179164e96860c3a9f" + }, + { + "kind": "file", + "path": "img_656.jpg", + "sha256": "b267ea950fc52edaa912f199327ee3c76638d68c393bdc1a376967740b32c74e" + }, + { + "kind": "file", + "path": "img_4916.jpg", + "sha256": "d70d36e9211a108b83873e10fcfb029654936ee9b5c9d1368c5a1d0ba8175fb9" + }, + { + "kind": "file", + "path": "img_3089.jpg", + "sha256": "e2778b261f6df164b38dabf7fb198d281e2cf4d768b5c8959126b007e4cae749" + }, + { + "kind": "file", + "path": "img_2397.jpg", + "sha256": "eadcfa7346db4b52b23b2078434d0d151eb49ca5720b601992a1be99373ce400" + }, + { + "kind": "file", + "path": "img_1846.jpg", + "sha256": "aeb7ef384bb6a90f872e79b9904efa6fe92c9a0d9cde2ddb1510f7cd5b3480df" + }, + { + "kind": "file", + "path": "img_118.jpg", + "sha256": "cfb9e799b007db8ff0c7a3950a5e2ef0f473297ff583f011294b030c66e80536" + }, + { + "kind": "file", + "path": "img_4080.jpg", + "sha256": "3444d5844dac40aa82470021e8ff28fda3ab3d3ec1ede40e4d9fb972a6b6587e" + }, + { + "kind": "file", + "path": "img_3923.jpg", + "sha256": "81d7766de0d1717af8bc2e1b3b0448ef1b4b8ebbbfe03f8b458e1ab33abdbfd3" + }, + { + "kind": "file", + "path": "img_4094.jpg", + "sha256": "0bace469431bcae73ce2c8e4a92d8ed572dfeddc9e0fec129598ccb23eada22f" + }, + { + "kind": "file", + "path": "img_1852.jpg", + "sha256": "fc02de2ad2f6769b9612e0c8c82c3896614367a0db1926178ad0b95f46deaf84" + }, + { + "kind": "file", + "path": "img_2383.jpg", + "sha256": "b7de9831822192b6adc4a3000170ee7548b3d7fb18b414d55127975211792fa8" + }, + { + "kind": "file", + "path": "img_2368.jpg", + "sha256": "cfcb044fb8c3af24e57822b0c329a42c400f1e52bc9ad346c785912d8de162da" + }, + { + "kind": "file", + "path": "img_859.jpg", + "sha256": "a395a84d2992c8cacddff95cad18ac080d834c6c8c94233b5c2b61b69661fe0e" + }, + { + "kind": "file", + "path": "img_4719.jpg", + "sha256": "2b5e71939251c95b886467bebcb9c15dad7f5a25d6785795a2f74a6fcc96825e" + }, + { + "kind": "file", + "path": "img_3076.jpg", + "sha256": "a57cda61d2788af836021733a0adbac9c8242f60b7152c8de0f989854fb7ec7f" + }, + { + "kind": "file", + "path": "img_681.jpg", + "sha256": "de21d2443025390a0979604a460311163bc07e38e18c0812aec882195221d382" + }, + { + "kind": "file", + "path": "img_1107.jpg", + "sha256": "d79d486066614d359301c66a5eda330757092e532558e97c9437767a254ee18e" + }, + { + "kind": "file", + "path": "img_3710.jpg", + "sha256": "1eb699ef5135f0aae4d9eef2d57df863561994b0732d3f2954b78562056d7737" + }, + { + "kind": "file", + "path": "img_3704.jpg", + "sha256": "1d5d79288b805685c6db3eb9a11b390b30dd97ca343ae0128fb139021c44d1fa" + }, + { + "kind": "file", + "path": "img_1113.jpg", + "sha256": "3db67d425f2a0619c22cc3cb72d9210e6cb9ee80bca790c0060f4122a144cfcc" + }, + { + "kind": "file", + "path": "img_1675.jpg", + "sha256": "6988e2352faf55362218b755ce98dfcb703a425a71b9397e28968b711a3e4b83" + }, + { + "kind": "file", + "path": "img_695.jpg", + "sha256": "78c650bfff18c7addfb03f19b70bf3a742820a470f7cb9abe27d89747a2d73ad" + }, + { + "kind": "file", + "path": "img_2354.jpg", + "sha256": "4b66ce98a7c68f4b2ce729a10ddd9d306f232fd9f13ea987025c36c6468bc13c" + }, + { + "kind": "file", + "path": "img_865.jpg", + "sha256": "ce0a0151ee7455939d9d5ea4c92613db25b5cf420d73326a2b9c8c6bfa9b56d2" + }, + { + "kind": "file", + "path": "img_4043.jpg", + "sha256": "98e89624e4b1fa81a1749d35e323dcf3162f35c48532d623a8f105d73dd1f666" + }, + { + "kind": "file", + "path": "img_2432.jpg", + "sha256": "7269e7213ad7423a08400f985cf85e9d0b9acc3408359f356534aa8c5bb608bd" + }, + { + "kind": "file", + "path": "img_3738.jpg", + "sha256": "c4a7556d3369c75d8cb7e128300aed8597f254871a13fee7b609c4b9f60b0ce0" + }, + { + "kind": "file", + "path": "img_4057.jpg", + "sha256": "c32cb1181229a590729710c49ce87b975ced859ab95d8e56abdf8e3a2f99a898" + }, + { + "kind": "file", + "path": "img_2426.jpg", + "sha256": "e5236937affc1c5273abaca396127e8ae3f7c1e6d8d1b2a7410ccea74030c65c" + }, + { + "kind": "file", + "path": "img_871.jpg", + "sha256": "b033592415b585bedfed91bdbdc6e2b5cec2bff03416b49fbe2092064e84891a" + }, + { + "kind": "file", + "path": "img_4731.jpg", + "sha256": "56ff293edf8eec33274dbd02b52c86135f0abe01635a5092269ca34c81f27fce" + }, + { + "kind": "file", + "path": "img_736.jpg", + "sha256": "eb0b430e7edbc88fd87063f19150c765a61a7dde9777f04e6bec75a401b0fd0a" + }, + { + "kind": "file", + "path": "img_4862.jpg", + "sha256": "1157db1ebe9f66cc50bdb46036a528c861f7f56725188f82db7c1b48c2158b47" + }, + { + "kind": "file", + "path": "img_722.jpg", + "sha256": "726aead35aec51058184d67f51b56c8dbd29166e272243472d49fa49ac717d12" + }, + { + "kind": "file", + "path": "img_1932.jpg", + "sha256": "bd35f48f6a10d37adf9b0849820da73bfc977ad448a907a8d61ede2f00852796" + }, + { + "kind": "file", + "path": "img_2585.jpg", + "sha256": "03a1249219a8d94a20bbd145e1289972408d94a334526ec7cd9d58a7610c30cb" + }, + { + "kind": "file", + "path": "img_3843.jpg", + "sha256": "11ab4bb74a9998d54ed53b8639bae1b306ad6e239c64c06612ce09266dadd036" + }, + { + "kind": "file", + "path": "img_3857.jpg", + "sha256": "63bfe0b9afbc0efdb966cb77b88c4e55c7a864a198f90ab6784bf9ce3da4d8b7" + }, + { + "kind": "file", + "path": "img_1098.jpg", + "sha256": "c485eb3137853d731d57fa56ecf146ae57c708f74507a42051906e1474687e7d" + }, + { + "kind": "file", + "path": "img_4686.jpg", + "sha256": "d49f7d17ee7e98cfdde76a8db38174fedf50caed07f9156bb0195958bfbcac14" + }, + { + "kind": "file", + "path": "img_3102.jpg", + "sha256": "4b83703a2017bd973484ee52625da1ce6b30ace7f1a596b718746645ae24557e" + }, + { + "kind": "file", + "path": "img_1715.jpg", + "sha256": "a909f2a912bd7e42badbb662f584e3eb91af8acd93311f820be2abcee4d32113" + }, + { + "kind": "file", + "path": "img_3664.jpg", + "sha256": "6b042a38ffc65420d39f30662ad56920faaf0f19569d249413bbe74734b312b9" + }, + { + "kind": "file", + "path": "img_1701.jpg", + "sha256": "0ed2544f4af452dbdae74730be516031e29476a149eb437683f46573f85f504e" + }, + { + "kind": "file", + "path": "img_3116.jpg", + "sha256": "a091d203338f71e260ee87fd7fc67a55dee0e950a9e52fe846e07e953a749753" + }, + { + "kind": "file", + "path": "img_4679.jpg", + "sha256": "5ccfd15696d0fc67dc5b8ea66690c6773b5bc779cb864b058706631cf9e72949" + }, + { + "kind": "file", + "path": "img_939.jpg", + "sha256": "df881b9baad06b92f8c82b6f4494da979574e8b6b3abfc4dbb5ae1c6d3b7d548" + }, + { + "kind": "file", + "path": "img_1729.jpg", + "sha256": "62f1073e21f296e95e7b46f3223684d72ae391f1c0be8678c76415073f5971d9" + }, + { + "kind": "file", + "path": "img_4651.jpg", + "sha256": "95128b404892e9324e89044e26e7f2d81d31ee068129b865d9186517ce9ae38e" + }, + { + "kind": "file", + "path": "img_4889.jpg", + "sha256": "89cd66bbc6ca7f07f0688df0d7b77f5fd2758c27fd01c560f3988a267eda0ad0" + }, + { + "kind": "file", + "path": "img_2220.jpg", + "sha256": "0ae3307692f753e303e6b11a24eb8057374c71a0102ef667e010d1416190e4b9" + }, + { + "kind": "file", + "path": "img_3880.jpg", + "sha256": "5065430968fcb5501b782ac245aadc6122b9b025163cf3ec22444f11f9fa17f6" + }, + { + "kind": "file", + "path": "img_4137.jpg", + "sha256": "2219b1fa0c4bef4c267a66a8f7c483888e3a75c5517b6d5750e8d056699d6780" + }, + { + "kind": "file", + "path": "img_3658.jpg", + "sha256": "a449175af547b58ac92bfde2e03672d9ffd4a26e5fe108a93f676c83e1ddfd16" + }, + { + "kind": "file", + "path": "img_2552.jpg", + "sha256": "17b76f2a37ef649732fc4f0bf26f31690be0975d00af77e047845507ed2b179b" + }, + { + "kind": "file", + "path": "img_3894.jpg", + "sha256": "acadba2194be7dea63e6c7785f4fa066609dca935f6e6c76f2ffa0b77e67318c" + }, + { + "kind": "file", + "path": "img_4123.jpg", + "sha256": "144556e6f89c0b9d891446b91a2d3a20084777982665a5dd4517f549cd29c822" + }, + { + "kind": "file", + "path": "img_4645.jpg", + "sha256": "d3f621a7a0375a5c977951a2466642668ed820a438237031ca775d206d5f06c7" + }, + { + "kind": "file", + "path": "img_905.jpg", + "sha256": "d630a76ba3024cdcd4d31995c5f6fadbd94e04439cf052f496caefd1153d760d" + }, + { + "kind": "file", + "path": "img_2234.jpg", + "sha256": "2f053add4e0efc4c29bc76d8192bce370b713b97db0e4f476c40562792b6a562" + }, + { + "kind": "file", + "path": "img_252.jpg", + "sha256": "872d51ddf654a6a374b705aa5a5bf763c2499f1e9daf0f9177b189843047f6e1" + }, + { + "kind": "file", + "path": "img_2963.jpg", + "sha256": "5204fa27ecf16e0ccb99fdddbb59c2a212b8668d993974da7d1acdb280e8c955" + }, + { + "kind": "file", + "path": "img_520.jpg", + "sha256": "ff3d8bff457c525585a4ad74856df5ceb125e3ce20c85b2762b7e6fd3beaec0e" + }, + { + "kind": "file", + "path": "img_2977.jpg", + "sha256": "716f8a05eae1a5496a22153622d9727784d74c60c26f8f29727b031a61cd132e" + }, + { + "kind": "file", + "path": "img_4490.jpg", + "sha256": "0c021d0e93022408882ead83132147e26c52a8ba80d93f071094354d65a529c7" + }, + { + "kind": "file", + "path": "img_508.jpg", + "sha256": "9ef2ee3893065cc5e980989fb80f9c66b830c6a9deb594babc93aa204d43c4cc" + }, + { + "kind": "file", + "path": "img_4484.jpg", + "sha256": "7258e188d71fdfdd0b4b7d95f1ae312923e4fedea7f9978fe79cdd4226418b65" + }, + { + "kind": "file", + "path": "img_2793.jpg", + "sha256": "932df027ee2581feee33c5812b507340a257e3e4478d24f64a25e703be56226a" + }, + { + "kind": "file", + "path": "img_291.jpg", + "sha256": "d7c50b750376e7959c90f0e270bea3a594cffe3d6f2a232fe5afe045eae92706" + }, + { + "kind": "file", + "path": "img_3466.jpg", + "sha256": "12150eb5fc604e1c5bdb2405d4a403cbd921ea129a8ee31d16709ea8a9835f55" + }, + { + "kind": "file", + "path": "img_4309.jpg", + "sha256": "45f70f5f192ef2734c6ea6ce18ca83486abee20fefc80997e2ce68425505e398" + }, + { + "kind": "file", + "path": "img_2778.jpg", + "sha256": "32619ec02b3ec611397c08e35aedbf8f6d60a47aaf8ae5b8a8c546384433a1d6" + }, + { + "kind": "file", + "path": "img_1271.jpg", + "sha256": "2e9a7546b708b28cb486ee2924a9fa640acdd50c31d1bbc7a455085386d547c8" + }, + { + "kind": "file", + "path": "img_1517.jpg", + "sha256": "6f49f12cf25fd784a91de6a23a0a49387d5d69ff3371c285b5ec52682fe59842" + }, + { + "kind": "file", + "path": "img_3314.jpg", + "sha256": "84af1520bb7860b1e39b9c13192d9c74473fc7a50719e498a3dfcfbcfa41d44e" + }, + { + "kind": "file", + "path": "img_1503.jpg", + "sha256": "178d77b073b8ec3d95c8c5216f135d53b419fd30d76d117e8e9db2084f33f4b2" + }, + { + "kind": "file", + "path": "img_1265.jpg", + "sha256": "bae69aa870514222d97ae5df252954692a080f15f2c2b2456e676f1a8c2b9c45" + }, + { + "kind": "file", + "path": "img_285.jpg", + "sha256": "04160d9a0afc931f1e8e6ed5105244a7c5b16065c54cb91971b57cf834aa436c" + }, + { + "kind": "file", + "path": "img_3472.jpg", + "sha256": "663668f4ef18d021daab09a66656e52ac6d3822518ab66978b29243031fe6662" + }, + { + "kind": "file", + "path": "img_4335.jpg", + "sha256": "bb3d01cbaf181e1e7cb0d22fe3d8d3c40451604a465ea31d11fe3ec81df1d6cc" + }, + { + "kind": "file", + "path": "img_2744.jpg", + "sha256": "27e7af74a9798a2c2ea721e84fc0a272e8a5ccc5e27774eae0e527fc2cc4cc4f" + }, + { + "kind": "file", + "path": "img_2022.jpg", + "sha256": "b9bf7f51b7ca20cf36c973f8f7d25754ed1936db35a296926084e85b85b8de82" + }, + { + "kind": "file", + "path": "img_4453.jpg", + "sha256": "373ff982d1d102f3037ba37c4def1a89ed68d3f6fb83d3cc7179671bf0ec1750" + }, + { + "kind": "file", + "path": "img_2036.jpg", + "sha256": "3cf9f44b5b6c7d767dde8fd8f658028580fe6280343248c36375c3a8eb95965d" + }, + { + "kind": "file", + "path": "img_4447.jpg", + "sha256": "3e26c9fc75ce8376be2b27501fd83383da14e227e376184e501c67dec9cb62c1" + }, + { + "kind": "file", + "path": "img_3328.jpg", + "sha256": "a117741e89fb87d249ce6e6ecaffb8d835f310ac45d54d3f6d4f25138dac4539" + }, + { + "kind": "file", + "path": "img_2988.jpg", + "sha256": "2fd5c218f647fef20ddd29f58e0ed884edcdf81cb1870019628af1bf11106a3b" + }, + { + "kind": "file", + "path": "img_4321.jpg", + "sha256": "ffd2fa79714b1349e0d6cfaa27c6c97c22e45e030468a47d67c082a9aa87b9ec" + }, + { + "kind": "file", + "path": "img_2750.jpg", + "sha256": "a47abea7ae166349fa23befa51491dc9a3c3687a2f2c49bf2ec21ef4608ba3ce" + }, + { + "kind": "file", + "path": "img_1259.jpg", + "sha256": "bfe05dcdb2d4f5545c093ee39ba38de4696d255158a876b51de8075d8b1bd91d" + }, + { + "kind": "file", + "path": "img_3329.jpg", + "sha256": "1faf9e23a8ce6bf6f9f78e268e949f8f6c8f88f329c82321b04efd4a60e990b7" + }, + { + "kind": "file", + "path": "img_4446.jpg", + "sha256": "ac2dbdc16b78e8e8f5597260b3247e5268ccae99dfcda9cde911ac63bb44a8ae" + }, + { + "kind": "file", + "path": "img_1258.jpg", + "sha256": "6d4e96306b47c5a180a439c957b2598997ea28e910c86c8e7257c9439a62eeee" + }, + { + "kind": "file", + "path": "img_2751.jpg", + "sha256": "79a8b576372f9e745dfb8ce2b864e4da53b5932498a61a36fdb6bfb53c3b1ee1" + }, + { + "kind": "file", + "path": "img_4320.jpg", + "sha256": "9c9cb62352155759f283f3f668567171d404d70dcab4ece365315c3f071c92b9" + }, + { + "kind": "file", + "path": "img_2989.jpg", + "sha256": "8eaac26086a316750442c63b8d649f0e9cbcef389df22c515fba07003d11b72d" + }, + { + "kind": "file", + "path": "img_2745.jpg", + "sha256": "d851fe2d3340afd8cb50559135ed3970469f4a86cfe2044a88fd9dc443486e5b" + }, + { + "kind": "file", + "path": "img_4334.jpg", + "sha256": "0b79ee2ed251453d0fd2829b233258fa8318db92d662263d1a6e4f4f326e0ae8" + }, + { + "kind": "file", + "path": "img_4452.jpg", + "sha256": "fb9847723e97f27de6afb3de8ba9ed088fdffeeddb61f46ebdc023b6990a08e7" + }, + { + "kind": "file", + "path": "img_2023.jpg", + "sha256": "088e7866bc3d53b89b315fd7a14549fb2bde86366bb5bbe089d3ffc5da96c662" + }, + { + "kind": "file", + "path": "img_1502.jpg", + "sha256": "5b7b39db9e1594c5a83a08051b423e68799f7351085298d5224fd5b4f119da0f" + }, + { + "kind": "file", + "path": "img_3315.jpg", + "sha256": "27f1435e2f9a13cebf68bcd015f5b2f52cfe24751ed4df0d262f36644421bdfa" + }, + { + "kind": "file", + "path": "img_284.jpg", + "sha256": "04ec30a4d73fed142e90686a18e1b948d5044fa0461813d1574fbffed5c3554d" + }, + { + "kind": "file", + "path": "img_1264.jpg", + "sha256": "7c5458b2b3c0c98520370f28ee1d44d6e0e706f170de60423fcbb6bf7167ca69" + }, + { + "kind": "file", + "path": "img_1270.jpg", + "sha256": "7bbd72982f3a68d69efba427ece046dc2db6d06c7516b8657d23a110f36c1e06" + }, + { + "kind": "file", + "path": "img_2779.jpg", + "sha256": "ee7f3e376c072211d328f4b81ff947551f1018e2d12bffe15c98297e87d254d9" + }, + { + "kind": "file", + "path": "img_4308.jpg", + "sha256": "1f83f3f29a57b76fadd817c4e97f85f8f23a4882f6b42db3e74f48097c295978" + }, + { + "kind": "file", + "path": "img_3467.jpg", + "sha256": "f3a78e2cc9367b0a007d18a07ee6f7ca4a6f93a98028c2b564a557ff53f7321c" + }, + { + "kind": "file", + "path": "img_290.jpg", + "sha256": "40764f5ba368c82964ae31e25c53f0647f316c7b7b05ca4b525228e9ddcd394e" + }, + { + "kind": "file", + "path": "img_3301.jpg", + "sha256": "a026b5ca9080a7f1f82725d1279bd7799f1347fffba8a6684f16e18919430d65" + }, + { + "kind": "file", + "path": "img_4485.jpg", + "sha256": "5a98e441962281fe0512a87e47f4e07522ca7e71b2afc4c06f536831cceb9909" + }, + { + "kind": "file", + "path": "img_2792.jpg", + "sha256": "07a99ab53899664f68171c6e9dca72b54b9b25eca4b7572a903dd55bac2328cd" + }, + { + "kind": "file", + "path": "img_2786.jpg", + "sha256": "f9fc8ac5110f02f74ac30b1f708f26786a80083c1e2a2376537f0efe6204f955" + }, + { + "kind": "file", + "path": "img_509.jpg", + "sha256": "c1f34571f4270ebf815fafff1033cb0ef6e0813d2fd8faf7d12c02584158bb51" + }, + { + "kind": "file", + "path": "img_253.jpg", + "sha256": "476235d0799f33248dffc8dffed02590b4964a21ee6889e741bbd70b7ac24ba9" + }, + { + "kind": "file", + "path": "img_535.jpg", + "sha256": "f31eaece8869dfa279f689683a7f8aae881a24dbd7eade6fef0467266038b2d7" + }, + { + "kind": "file", + "path": "img_4122.jpg", + "sha256": "ae1bcdb03418ad48066ccd0812289c9524cc87a3d3027bc3ae2ad6740aca6e39" + }, + { + "kind": "file", + "path": "img_3895.jpg", + "sha256": "549ecb0d1d4c99698c3c82403fed9df0dbe15d6d6149e8d17132bbad76ba09f5" + }, + { + "kind": "file", + "path": "img_2553.jpg", + "sha256": "7e8338fed367916a353b4655fd8e65adff89a233d48af3023e82327653ff27a5" + }, + { + "kind": "file", + "path": "img_2235.jpg", + "sha256": "c30cdaaec4304c08a1ff723beaf618e90079f1fb73f70ec2b906c17387e0b90c" + }, + { + "kind": "file", + "path": "img_4644.jpg", + "sha256": "e95e34df4bb90c7c0bee7739be8cde2fa72027476b6795c92576a3402fca1be9" + }, + { + "kind": "file", + "path": "img_2221.jpg", + "sha256": "d4da9e244539fc10b0d7ce44d4d6e765d5bcb60d1bd7efaf6b59307e232d2c2a" + }, + { + "kind": "file", + "path": "img_4888.jpg", + "sha256": "72e1a1c01f995d38df7083f1684ffb12950b2de2b68866828ecf082d79a88642" + }, + { + "kind": "file", + "path": "img_910.jpg", + "sha256": "9034962bc7407179fa54b48eafa97ddf6dc3fb4b021187eda1e4e8bb66c4065f" + }, + { + "kind": "file", + "path": "img_4650.jpg", + "sha256": "16f9169a656b5182bd1c2c801487a0fe76fe523b0c1066205c1a8dc1369df14e" + }, + { + "kind": "file", + "path": "img_1728.jpg", + "sha256": "631c9ab380455ec400779a2a04946b09a56c8503802582e24345727ff55675c4" + }, + { + "kind": "file", + "path": "img_3659.jpg", + "sha256": "fef7112ec27955e067a61e48817c917342563e577ab04667699e2ddad6189399" + }, + { + "kind": "file", + "path": "img_4136.jpg", + "sha256": "a34d50abf2ac1fd228b3e3f44a7765e91b3a4d05362ecf6f6b395fb6628a8b4f" + }, + { + "kind": "file", + "path": "img_2547.jpg", + "sha256": "c55c4aec827604a04a945dee1db791d6beacace42236e9d438408f2d12249334" + }, + { + "kind": "file", + "path": "img_1066.jpg", + "sha256": "b7c7dbc7c0d37efe53720a8677814362fc9bab2bc2b6c6599936a0fb8de5b3ff" + }, + { + "kind": "file", + "path": "img_3671.jpg", + "sha256": "ba3eaf6e8d7155577b14288bb6724891fd0ed12baeb0ef72eadf941efea6a46b" + }, + { + "kind": "file", + "path": "img_2209.jpg", + "sha256": "0cf8e8a083c2d4eef43dcc65a0a8e45d3e4fcbb2899d946268fc38b1076a3722" + }, + { + "kind": "file", + "path": "img_938.jpg", + "sha256": "0e073ec127cde6f7a8291f74a2f0efe5c75624369183da488ede3d1039064bfd" + }, + { + "kind": "file", + "path": "img_3117.jpg", + "sha256": "aa61fdbd28505557aa3f148a19457689cb450ea654c46346598e9c9dcf472589" + }, + { + "kind": "file", + "path": "img_1714.jpg", + "sha256": "5b7b161448a6e276ef361013920270b705fc78c2ce6ee7e1e8907daf27f84998" + }, + { + "kind": "file", + "path": "img_1072.jpg", + "sha256": "671442ac19e7065a5817bb35efd4f41b2bb97e0c8f9810d56810aeb4d7791e0a" + }, + { + "kind": "file", + "path": "img_1099.jpg", + "sha256": "6410417c881c2912e2ce9fd74e6a2fb35582685258ba98a76bdd4de2620bf9c5" + }, + { + "kind": "file", + "path": "img_3856.jpg", + "sha256": "7a49bf52bee54f9bcfc1a31c4f89ab8b8a5ee68a7eed7d83d78df3a37ad1a660" + }, + { + "kind": "file", + "path": "img_4687.jpg", + "sha256": "c157db599901b221c20b0b886fc683c6fe427c37e766c0f9ed0d8197b11149f7" + }, + { + "kind": "file", + "path": "img_1927.jpg", + "sha256": "5689cd3f576cf728b1b421484b253c538e334bce64785f62d925b9fb3916bc1c" + }, + { + "kind": "file", + "path": "img_1933.jpg", + "sha256": "ef1939a15b47e0e2360f1ca8bd173f785cf7af7a802e70ed19d54a2920b5b754" + }, + { + "kind": "file", + "path": "img_4693.jpg", + "sha256": "17ec884a37328cc19984d5b9d8c8abb30f2c2e3c56c7ad5d7e96bd9c9a5bd8d8" + }, + { + "kind": "file", + "path": "img_3842.jpg", + "sha256": "52e357ac891354bf8c78596288251678d0b6a333bff7c5c5c433ee43c96ea2dc" + }, + { + "kind": "file", + "path": "img_2584.jpg", + "sha256": "70eca374b69bc8cda3264169b561a0b4386f557e708714f580b4870aee65f35d" + }, + { + "kind": "file", + "path": "img_723.jpg", + "sha256": "189cebd4cf44337711a60136f3d81c8485fa6c7ba3281d2e1326b72dcd64fae2" + }, + { + "kind": "file", + "path": "img_4863.jpg", + "sha256": "6bd220fb99acadf118953cea08e2668c236df92694e88cd614442fece079a4f8" + }, + { + "kind": "file", + "path": "img_737.jpg", + "sha256": "083b5af5ba4b15608fbc966de66672e4b9aeead71ae1630918559d7d3a322e2d" + }, + { + "kind": "file", + "path": "img_4877.jpg", + "sha256": "d33045ff0f6d103ed2b82c9635bb0548f3b5d3e8d16b4aafca80efb5765e161e" + }, + { + "kind": "file", + "path": "img_2427.jpg", + "sha256": "3f7b2f17870c198ee9b74c8beb8034bf718e73157bfaf94b6d304c6332d74c67" + }, + { + "kind": "file", + "path": "img_1890.jpg", + "sha256": "a4d0578b71af4f70f67d36c40941cc3caaa6db7b2abdcd129b7db39a546f2cf5" + }, + { + "kind": "file", + "path": "img_4730.jpg", + "sha256": "3960d1f20026b9df64950f504a4bdbbe339d6febb30e5cbd9ab9bc03576dbde2" + }, + { + "kind": "file", + "path": "img_870.jpg", + "sha256": "e63ff93e44400af04b8a49ddbab88e7030156cf278e5c40dd0a586b2663912a4" + }, + { + "kind": "file", + "path": "img_2341.jpg", + "sha256": "4aae870ff01005d39fbc82d108b76e05714401bed365f1b542a70ee65afd77c5" + }, + { + "kind": "file", + "path": "img_4724.jpg", + "sha256": "c90624ee360f96995083e56453953e69e6d9625da5575a9800a120d3d5b05c0f" + }, + { + "kind": "file", + "path": "img_864.jpg", + "sha256": "88661f9b5c59879ef2e188694341cfa16d4a131fb7f3178cf4be29fcee93c8e4" + }, + { + "kind": "file", + "path": "img_2355.jpg", + "sha256": "42a515bc143f8bb7d17723b09a338d86f1d1ffc32bc582c6800d14969e7c9403" + }, + { + "kind": "file", + "path": "img_1884.jpg", + "sha256": "eeccad053d918a9aec6c8d237685f47b30cea151f2094538493b7891ff9b3e10" + }, + { + "kind": "file", + "path": "img_2433.jpg", + "sha256": "f21d2c0e626c5a390391f4c1d06e14b6c542c3b6fdd4f23f1ae535552358a2bd" + }, + { + "kind": "file", + "path": "img_4042.jpg", + "sha256": "2e903985f244e2964b35991429be0fb7d711ebdc3102343e1ae9294e3767daa4" + }, + { + "kind": "file", + "path": "img_1112.jpg", + "sha256": "ed5fee83f70c9cfade370cd29727b60c5d6994b308a12c2e8736e9deebcfae13" + }, + { + "kind": "file", + "path": "img_3705.jpg", + "sha256": "f88b6177daf186fc59cd0b046e145397671d9f6227e7c4635f0e173fea8bed5b" + }, + { + "kind": "file", + "path": "img_1674.jpg", + "sha256": "c7966bee007c8dff49cc9842059932084abb1f640c0cf421b6e11c599cfea24c" + }, + { + "kind": "file", + "path": "img_1660.jpg", + "sha256": "9d5601e706a8681c69b8f6b6453773fb13fad6d28f3099aa5bbb915782d2d46f" + }, + { + "kind": "file", + "path": "img_680.jpg", + "sha256": "19587243041f3b035ba76ea79a75219f004c7e7652b56dac72e8f3f0a1551476" + }, + { + "kind": "file", + "path": "img_3077.jpg", + "sha256": "b8389cafbfa7923d15da8402a51f1897e4a4327a7c3552c16aff3c68ff9da917" + }, + { + "kind": "file", + "path": "img_4718.jpg", + "sha256": "b84e2f6492f139cfa327618c4bdb2098642acb938c4d6f5dcbc9cbc93a8b2372" + }, + { + "kind": "file", + "path": "img_858.jpg", + "sha256": "5478d99b7de384cc42299d00a9384dacc13bc196e49fe6bcde10d178630a880d" + }, + { + "kind": "file", + "path": "img_3711.jpg", + "sha256": "75fd7424c635be7269c724523644c04ead3b6351f107450e5653e6eaad607fef" + }, + { + "kind": "file", + "path": "img_4095.jpg", + "sha256": "c256282eedfb4a49a24e1c0bdd60b03237fadbf6d49c670c3a05817f32f230a1" + }, + { + "kind": "file", + "path": "img_3922.jpg", + "sha256": "3e4a0d7832a1268da4b3403af4735aa19e57d3f9ee0865d05993051f1afee896" + }, + { + "kind": "file", + "path": "img_2382.jpg", + "sha256": "ea3be14a333b99bb440c7d76a8f9e6e1af2895989fed8e43ba4e84f1236dafda" + }, + { + "kind": "file", + "path": "img_1847.jpg", + "sha256": "dd1bc56b45112ce7d50f62dc756f2ed67b0b1c08aa0238462bebe9a5859fc7f1" + }, + { + "kind": "file", + "path": "img_3088.jpg", + "sha256": "558ff21e8adb1103bcf70c510255f935cac80a00599787f064a4180049125dd0" + }, + { + "kind": "file", + "path": "img_119.jpg", + "sha256": "7f809ec987497ca0886353e4565aa6cb0f8e9f6ba314304685e740ab038acea6" + }, + { + "kind": "file", + "path": "img_3936.jpg", + "sha256": "799eb648122ca08b9ecdafe3a474300991f2895ddafa3933d19d57236cdd59dc" + }, + { + "kind": "file", + "path": "img_131.jpg", + "sha256": "918fe8be31841616650660ce76e520c9f32d5d030f09cc504a8c18ae25e0ce5f" + }, + { + "kind": "file", + "path": "img_657.jpg", + "sha256": "85dedda0c500ba1e65bdfd9984c9c010e8ee6b679f2c9c1a1775fabd0ac373bc" + }, + { + "kind": "file", + "path": "img_643.jpg", + "sha256": "923a8b08494f72d126728e5e67d51a0a32412b431a2dbd4b9f6b3b7174bed576" + }, + { + "kind": "file", + "path": "img_125.jpg", + "sha256": "53c23bae764172ec0803d3fcf7f612178807607101bd393d6b9faeb629441ca0" + }, + { + "kind": "file", + "path": "img_2143.jpg", + "sha256": "7c42b98bca547ac58a5277cecb32c71c7168e2f73e575c804358995a0bbb718f" + }, + { + "kind": "file", + "path": "img_36.jpg", + "sha256": "a1b1430c4b0311612d2745db440e09f53321e8b05eae9985ef76bb1c4a199ac8" + }, + { + "kind": "file", + "path": "img_4532.jpg", + "sha256": "9f29591dd7d5c4463958a22dbc4c41f5f5a322c89ab480374503fabf71dce57b" + }, + { + "kind": "file", + "path": "img_4254.jpg", + "sha256": "694d0b8f42bf5d624ec9337cb272351d8310b05b326f6d90ccc73e2169b7e361" + }, + { + "kind": "file", + "path": "img_2625.jpg", + "sha256": "cc3f0a841252d14523bf1be096ba5753336b531f4f05f3d79f1d4809121285de" + }, + { + "kind": "file", + "path": "img_4240.jpg", + "sha256": "81b6a51b8399c78f08b46646742b554552a03f2e9a9d7814c46d14ca8a21cbd9" + }, + { + "kind": "file", + "path": "img_2631.jpg", + "sha256": "f6eb0da9ab94733aa69054f284b2405d18c97a0cfef2e6f9d1011760f1e16ec7" + }, + { + "kind": "file", + "path": "img_1338.jpg", + "sha256": "6c4f020d16e17dada25ff54000206e85da8948b4a1b821090ec5fbac27d7583b" + }, + { + "kind": "file", + "path": "img_2157.jpg", + "sha256": "9dff8088615894463b81d2451e66de1aa68790af45ce18f2fdc6e7b5cfb57262" + }, + { + "kind": "file", + "path": "img_22.jpg", + "sha256": "e1d56957816b64379769dc200b8aa74374c5f6353e5ea4669ce3410f837c407d" + }, + { + "kind": "file", + "path": "img_4526.jpg", + "sha256": "4669d5f5e4d5809bd95f217e84d2e9cb8fca4cc4047ca3646a6d51115ea5c0e9" + }, + { + "kind": "file", + "path": "img_3249.jpg", + "sha256": "d94c8e3dd846cc10d66fb8564dd7ba7092e3384d68ed0c358818340315203777" + }, + { + "kind": "file", + "path": "img_1476.jpg", + "sha256": "693eacfe3d3f4b74db3034669c02cf3a1d6edbcaa3b123ff0549d4537c8ce81c" + }, + { + "kind": "file", + "path": "img_3261.jpg", + "sha256": "33328e03ed83a2684893981662f1652b7958b2c7b49f839e65dadd2f8bd00dd6" + }, + { + "kind": "file", + "path": "img_496.jpg", + "sha256": "83309e61c4bbdb760095c36d44f36e07d605c91e06029503cd5745b519a1815e" + }, + { + "kind": "file", + "path": "img_4268.jpg", + "sha256": "3cae0cbae9757f9bff567cc09de1ddaf18e6db11a0a92fe97728cbd45c76c107" + }, + { + "kind": "file", + "path": "img_2619.jpg", + "sha256": "75752857d8e549480e0722eb5f6c9dc170e65e7449ebe97d3ec5f91c4b2be6f5" + }, + { + "kind": "file", + "path": "img_1310.jpg", + "sha256": "f84b9bfed52f379c1bdcf588c8fa8161ef435266864922d4fc57859af3aafbd6" + }, + { + "kind": "file", + "path": "img_3513.jpg", + "sha256": "b0c363297d3fbf58801904a5773b6a8c48e12c1a26ee7069dfc3436334e558bc" + }, + { + "kind": "file", + "path": "img_3275.jpg", + "sha256": "64341f337ea101516700622b84e830b28cdc510407eb0605ebf7d2c9f9ebc2c2" + }, + { + "kind": "file", + "path": "img_482.jpg", + "sha256": "1a025f51c2b32439b9c2b3051d3f0641b4effe9a9e93bb264a9e82eb924cc998" + }, + { + "kind": "file", + "path": "img_1462.jpg", + "sha256": "789da244ea6567f10244d5b7ad91e473158d06fd25b6c1f8e7b1998ee828700b" + }, + { + "kind": "file", + "path": "img_1489.jpg", + "sha256": "9418163bf6aa850528df399afccb40e9125d2cebd7761ed225d44ed09c324c2d" + }, + { + "kind": "file", + "path": "img_4297.jpg", + "sha256": "6a1de166f538492f9379f761eda8be4a21901c1b76f62653687afe92f584e30e" + }, + { + "kind": "file", + "path": "img_455.jpg", + "sha256": "ce2b9ad39d9776d30076c95106b013fe36edd5d68723f5ac453dd0dec365c598" + }, + { + "kind": "file", + "path": "img_333.jpg", + "sha256": "a0226e40ca055f56134ece1d92e0cca4e972618327ed03dfbb2f50e5597b7bc3" + }, + { + "kind": "file", + "path": "img_2802.jpg", + "sha256": "cb4eb568d22f47b213f92e62335830b85d1dd8ff4d9e9d69ee28c314083d6790" + }, + { + "kind": "file", + "path": "img_327.jpg", + "sha256": "3dd8cd5c8046c20450865b95dbbe2fc0d782548103cef54e8d174d2c78343a96" + }, + { + "kind": "file", + "path": "img_2816.jpg", + "sha256": "60d0de0173dc40f95f4655abf4d93701d143b3ccfedc36215d9597f38bdff062" + }, + { + "kind": "file", + "path": "img_441.jpg", + "sha256": "46499a93f1c1c39c2936166934acad0b66682cd012f44712c16d127340b369cb" + }, + { + "kind": "file", + "path": "img_2800.jpg", + "sha256": "d5f0ef7e6b0f7486f2241a6ece64b0d3b0b239f864bba3cc5413a57a7b341290" + }, + { + "kind": "file", + "path": "img_331.jpg", + "sha256": "c9b54d7165d8ed7fdf1867a262b7ad6523697fe227c696f1615670c84183c38f" + }, + { + "kind": "file", + "path": "img_457.jpg", + "sha256": "d3aa2db2aafd451b43914ca64cfa04f527ee6a4ce3fe9877a8b541bc33cb7e56" + }, + { + "kind": "file", + "path": "img_2814.jpg", + "sha256": "00e180ba856e9ba2a8e24da6343fe772a5804f8af916528f397e77928a3097a0" + }, + { + "kind": "file", + "path": "img_4295.jpg", + "sha256": "4fa6cb355e53dce65b72cf8bbc140142d8b8dacb83fe0670c649deb5324a013e" + }, + { + "kind": "file", + "path": "img_2182.jpg", + "sha256": "be28e9015d92433c82bf9e3d141faf29ded303d74d89bded235f2eb9ffff2ba7" + }, + { + "kind": "file", + "path": "img_3288.jpg", + "sha256": "88681db65075d7001e877fcc609c0d0e22108d6b4f4fbb9356caf3a1ff6ef159" + }, + { + "kind": "file", + "path": "img_2828.jpg", + "sha256": "a56be21946afb709f31c870ce82358325bc53590f1fc0609eaf15610222ef5d0" + }, + { + "kind": "file", + "path": "img_319.jpg", + "sha256": "9dba0aef14e1c4c147a5d6be4835a6b8a45648d585eacb86aabbaaa7390bc2e2" + }, + { + "kind": "file", + "path": "img_1312.jpg", + "sha256": "052d11797c73abea471fceb00d860822d73ccb326d28f700c62a1af649890f59" + }, + { + "kind": "file", + "path": "img_3505.jpg", + "sha256": "030f3af1275e42e9150c6990884fd3924418127641cbecee5b62ba2404c2ed5d" + }, + { + "kind": "file", + "path": "img_3263.jpg", + "sha256": "13f792207783b21fa4dafae5887cf206e2e4c442252a50c93af960ea8dc85ff0" + }, + { + "kind": "file", + "path": "img_494.jpg", + "sha256": "d043ec04b5796723e4a60142c7cf04cec8534ecbd27ab65cc16e15b6d49de00a" + }, + { + "kind": "file", + "path": "img_1474.jpg", + "sha256": "2f500d78a170d31184ff1fc3e9273b90079e249d2da3b796568b5f07526df573" + }, + { + "kind": "file", + "path": "img_1460.jpg", + "sha256": "99e83e1f90ec9c4a4f9ecb5080c5683e779840c76fda5cd98c3d44428320009a" + }, + { + "kind": "file", + "path": "img_3277.jpg", + "sha256": "764519490ff624de133cc3b8238ea71b05c2a38c9312e902f9d6bf411d40b635" + }, + { + "kind": "file", + "path": "img_4518.jpg", + "sha256": "9e0d9b7244f7b496c0d415a1938b44b00ca00ab14e0b725bf101277c5cf59ed6" + }, + { + "kind": "file", + "path": "img_2169.jpg", + "sha256": "e1cd9d8e7dd5a1a9d2554b8d2ec87182abbf23f172ddf40776e385efb5281c88" + }, + { + "kind": "file", + "path": "img_3511.jpg", + "sha256": "05d7f2bd429ad4d860544609659960304a51396fbee96563dc85249028b941e4" + }, + { + "kind": "file", + "path": "img_1306.jpg", + "sha256": "d91a48377b7728fb1b6b643058c0c435c5a4ea65e4216cc5d65d08cffb404fcf" + }, + { + "kind": "file", + "path": "img_2627.jpg", + "sha256": "dd44b4b082ebc2da7fd28556a75c4274f7eddebf6372140b8c12bcd903f0c4ac" + }, + { + "kind": "file", + "path": "img_4256.jpg", + "sha256": "cba865793aeff81c3f45df8f9397dcdb2e7bcf60ed99471b0ceeda24e8f85551" + }, + { + "kind": "file", + "path": "img_3539.jpg", + "sha256": "ab206f1dc485d42e9ee175c888abaaf40ce159a67e7c3eefe384474038ca0c58" + }, + { + "kind": "file", + "path": "img_1448.jpg", + "sha256": "3b30c90912488e0cbef8e1feb6fb0f8cdd8de7b298ab907e093ea7c23cb920ce" + }, + { + "kind": "file", + "path": "img_4530.jpg", + "sha256": "156ce8143e3b4ece1eb598f7eb10ab000ce8149a83e73df5c1bf56249e19f08a" + }, + { + "kind": "file", + "path": "img_34.jpg", + "sha256": "4705ba7756065139b73d7243e8e411c1e0bee309c82baea5888385f89c7f1bfe" + }, + { + "kind": "file", + "path": "img_2141.jpg", + "sha256": "935fd4ac0f65883798f9854047b3c0b6c352ef71d4bb837050e674e612e2be8e" + }, + { + "kind": "file", + "path": "img_4524.jpg", + "sha256": "42f5204ed47bcc05fdabd2a5afcab0df752e5679a64abe0ad99e0158cd12b35c" + }, + { + "kind": "file", + "path": "img_2155.jpg", + "sha256": "b8e1df538bb1ac1d509f22f72bef7186fc28e2c42c76ecffc05a62699af155ba" + }, + { + "kind": "file", + "path": "img_2633.jpg", + "sha256": "3493777aeb0cc1df0e3bc0447ee3063ac774a19ed21f28d54a063606c73d03f4" + }, + { + "kind": "file", + "path": "img_4242.jpg", + "sha256": "9bb499ec16f98b9ffdcf36bed851dbdb28ab80014e116b81cd342152879173dc" + }, + { + "kind": "file", + "path": "img_655.jpg", + "sha256": "e5c4eb496bcd54344d22b62c7b2d8eeb419518031cf66ca8cf381d9e5b381325" + }, + { + "kind": "file", + "path": "img_4915.jpg", + "sha256": "f9fe304647f66793225637a52d8af961bacf7722965506672b1a14ef4db1afb2" + }, + { + "kind": "file", + "path": "img_133.jpg", + "sha256": "808ba5eb8e20c0c4080fc56f8ccb5066aebcd51ff7e97a118f9b1511fbb96365" + }, + { + "kind": "file", + "path": "img_3908.jpg", + "sha256": "e126e8a31a1552a0e00618d3190868f937fe87e701ad771c359d481150d45085" + }, + { + "kind": "file", + "path": "img_127.jpg", + "sha256": "7e8383a4909739d48326285e13636eff9991858dd3ccedacc809f9215e3a697b" + }, + { + "kind": "file", + "path": "img_1879.jpg", + "sha256": "152b36a859d67b6568ed8827aa0f121532be5b6052c63183896b10bdacd6f05b" + }, + { + "kind": "file", + "path": "img_641.jpg", + "sha256": "80f3bed55318fd76298d25cf9a16508f04eab335f97b073ec6a643fbd70a5597" + }, + { + "kind": "file", + "path": "img_4901.jpg", + "sha256": "4861a160b1f43fb50e5c9111a74ded780762d83c6ef1ff10d1c996fccdaca1f4" + }, + { + "kind": "file", + "path": "img_1689.jpg", + "sha256": "ab3326d405f4561964417fcaa65a3495957fb55b903b602760d869bcf2a1f2be" + }, + { + "kind": "file", + "path": "img_669.jpg", + "sha256": "8c18e3b5060c3d08a03824d2fb425ea6c2426bf759cb27b7a306621597b29b4e" + }, + { + "kind": "file", + "path": "img_2380.jpg", + "sha256": "260cc04c62a9c3b227651d0b71479ad2706c6223bab3616fe3dc031dc7b4c04a" + }, + { + "kind": "file", + "path": "img_4929.jpg", + "sha256": "a55bcbe7a195fde26cf7fc57707566313d1032a225eb2302710dc76424b315e6" + }, + { + "kind": "file", + "path": "img_3920.jpg", + "sha256": "468efe72351ad36284b5ddc1c5d3de390de04a11197b0f75275f18372e8ae5f7" + }, + { + "kind": "file", + "path": "img_4097.jpg", + "sha256": "4a5d2dad14467c5d161b4e886fe71418afc4ff70e242c8125dffaa21c97403f0" + }, + { + "kind": "file", + "path": "img_4083.jpg", + "sha256": "8af0e4660e57987e4741ee6b2e93810bfa06cdaa7f13ee55f5f223f4fc33de68" + }, + { + "kind": "file", + "path": "img_2394.jpg", + "sha256": "3d02b5c05dfcf5b83b83c539204d510919c0c44a465ad7482d4f0fb8a0f6a74b" + }, + { + "kind": "file", + "path": "img_1676.jpg", + "sha256": "1459bfa28725fb4a1eaab4fd175a4d3f360e70ece6f6eb7360393c39e59e77bb" + }, + { + "kind": "file", + "path": "img_696.jpg", + "sha256": "dedcf83cda38ebdbd6177c6ca8bbf9601e8a05fa78a058ae9e19703f320dcb07" + }, + { + "kind": "file", + "path": "img_3061.jpg", + "sha256": "0d68d3b949e291e550c18bbc422f29fb5edc83111fa953994a04055ccaa34543" + }, + { + "kind": "file", + "path": "img_3707.jpg", + "sha256": "9c64da05cbec8437c9d1abe663222e06e849cf33325d00b18273a180370d1ce4" + }, + { + "kind": "file", + "path": "img_4068.jpg", + "sha256": "9d8c7c3f4b11d09f3a988edf3a4673afe08817cab6c6203963c1a9af32b3b594" + }, + { + "kind": "file", + "path": "img_2419.jpg", + "sha256": "aa65418b002b3755038ed1a31b8129db154f4d5181a15215d76a2295f3cabfcf" + }, + { + "kind": "file", + "path": "img_1110.jpg", + "sha256": "243889af7021a0e3e35a16eda2e931b491976f8e32589e7d380dc680579548d6" + }, + { + "kind": "file", + "path": "img_1104.jpg", + "sha256": "61f8290566bee4c6002086a15e46154d6418e66eff7782fa44acf0b41ffb7055" + }, + { + "kind": "file", + "path": "img_3713.jpg", + "sha256": "f86e4646d25e055e62992689976c2eeef3d8b585c4fca39cacabdab1ddcd12c8" + }, + { + "kind": "file", + "path": "img_682.jpg", + "sha256": "8193f4b7f4b2a76bfd0eaf711544ceb8e933f4534ea24277bdf011e8b3f7b362" + }, + { + "kind": "file", + "path": "img_3075.jpg", + "sha256": "88224137b4def4784618c0677eea1e4f21f0c8c8d9c24c3ef36c9f0b6200c4e2" + }, + { + "kind": "file", + "path": "img_1662.jpg", + "sha256": "7d02d0fb97599b6d7578b551b02eda42867f71a969573e419874b539a611581f" + }, + { + "kind": "file", + "path": "img_2343.jpg", + "sha256": "049e409a917dc21a4a367bdcb345ddfd3b93f4b9c43e0af8436b6b8119604874" + }, + { + "kind": "file", + "path": "img_872.jpg", + "sha256": "68adf37c22674264cfb9b74a82d5ac9ceca7d34ffd38360ea0da1bb49e940a8f" + }, + { + "kind": "file", + "path": "img_4732.jpg", + "sha256": "6f611d2464f2cfb58cf58bcc291434a38c2fe09f24376d64bb66cd170c97f563" + }, + { + "kind": "file", + "path": "img_1892.jpg", + "sha256": "069a41a42a8e600a16534327d4035569e829d7001b124fa63a4ea2b938073d1a" + }, + { + "kind": "file", + "path": "img_4054.jpg", + "sha256": "358636194b24871c4e7f2534ff73b8f89f30603cad99e6554a4115ac40ab584b" + }, + { + "kind": "file", + "path": "img_4040.jpg", + "sha256": "29d00350ceb2f33222a492616dd63b8b761588185c560cc1f6e8fd791ac6d2ec" + }, + { + "kind": "file", + "path": "img_2431.jpg", + "sha256": "d145066c89a9635ed8fc7a039f40d00c10f275c26039dd9174f4110f1446af61" + }, + { + "kind": "file", + "path": "img_1138.jpg", + "sha256": "28fa5e7a5df9ab058b2a6e51b416040f5c66a83ba29ba4d1eb4e5f86e2e79ad6" + }, + { + "kind": "file", + "path": "img_1886.jpg", + "sha256": "2ab5d6e93ad72aac7f0dc0a84c5fd0e593c92423f22d4c14a1afc443f88ba521" + }, + { + "kind": "file", + "path": "img_2357.jpg", + "sha256": "fc621ea87575d999c18eb3a6497e536d9812df0bba4be0949f663078267f6ce5" + }, + { + "kind": "file", + "path": "img_4726.jpg", + "sha256": "60722a66a1ca64a407f0b0e73f720ea2c48bb00c871db299cc5922ff9a18f012" + }, + { + "kind": "file", + "path": "img_3049.jpg", + "sha256": "5be34b6ea74fed0dbc5fdf333bb2d9b53843a081c15f85805c7c4dede98dcda7" + }, + { + "kind": "file", + "path": "img_721.jpg", + "sha256": "5f2f349d9236354f576f68bac71a3d2c9cd22dd6c019402a445d1d70f03198f6" + }, + { + "kind": "file", + "path": "img_1919.jpg", + "sha256": "cdf2c9ff2bea5b0af584fe344d4df61a8fe2346e646a3385d01de1651ecc89c3" + }, + { + "kind": "file", + "path": "img_4875.jpg", + "sha256": "6557fa0151da8346ccfa61ff877bf4fa5f590f6db39977e0ff234671f0a351d6" + }, + { + "kind": "file", + "path": "img_735.jpg", + "sha256": "a4cd33d8e3df886e646cd25ff3863f7955226edd84dc7ea410372bb39feeaa82" + }, + { + "kind": "file", + "path": "img_4685.jpg", + "sha256": "5af3d276d1d8c2f4e8ba063c41619df8ec478e1d9dc547ebc58683480194841d" + }, + { + "kind": "file", + "path": "img_2592.jpg", + "sha256": "989a74c7cb79ab973d97367d21408e4a137d524448d29da3dd6de55052a47f2d" + }, + { + "kind": "file", + "path": "img_3698.jpg", + "sha256": "a45db532c887f026f673e97bce695570af2e36019dfa87de7489aac1b18b3e11" + }, + { + "kind": "file", + "path": "img_2586.jpg", + "sha256": "d2937d14fd17702ca7d56466364a7bb4a909f08c0c011f555d3313f84d61e8d1" + }, + { + "kind": "file", + "path": "img_3840.jpg", + "sha256": "c652fbae9ad19614a24f4536a64e12f44c72b72e6715cde611f9d0aec287e961" + }, + { + "kind": "file", + "path": "img_4849.jpg", + "sha256": "226ad8eec60e5b326c3492bb36b06881bc223a5b9fabf4ec35eec950a3de8d22" + }, + { + "kind": "file", + "path": "img_709.jpg", + "sha256": "80235ef5dd7195c0bcb7d52572aef571602ed7103adafd24989d92e6b4c9c6e8" + }, + { + "kind": "file", + "path": "img_1931.jpg", + "sha256": "432341674478f0988c85b776686846280142e709922c625145b6154462feb0b8" + }, + { + "kind": "file", + "path": "img_3115.jpg", + "sha256": "2b6a6b9535ba55532079ed333f8eca1ddceadde739d698ae72f9432035d170d8" + }, + { + "kind": "file", + "path": "img_1070.jpg", + "sha256": "99a92a510d0d0479ad323acf2f067cc2f7caa67c8df8a4cefecdf13fe878de8a" + }, + { + "kind": "file", + "path": "img_2579.jpg", + "sha256": "ba36ed41c7530d27820df54bff1760b28e7e84e4a94d6159bc016cd26a23a086" + }, + { + "kind": "file", + "path": "img_4108.jpg", + "sha256": "237ae65bb12c41ede9148c908d081dfc996e2b3f6a51e1d7f777cf2b47646bb3" + }, + { + "kind": "file", + "path": "img_1716.jpg", + "sha256": "a143c1f51d37ec5d37c73ceabcbdd20d6272951033e2a76c53640dd58ee8b62b" + }, + { + "kind": "file", + "path": "img_3129.jpg", + "sha256": "07a3777a8c280000be10124da562e5847dc5b19bfac98f9b549f0def3b7977db" + }, + { + "kind": "file", + "path": "img_906.jpg", + "sha256": "d140e5b3919fcba1f52005c10f27effb8b7fe8b47af20adb004a86c13efdcd38" + }, + { + "kind": "file", + "path": "img_2237.jpg", + "sha256": "5fb994e2d14b4b61e2f00cf87a33f28fbafc15ca3b03fb22b6e6cc7d79437545" + }, + { + "kind": "file", + "path": "img_1058.jpg", + "sha256": "27ad8242c8c25fc9dab76f731ed39e6dac7867a020c1e468873b2a4076a3939c" + }, + { + "kind": "file", + "path": "img_3897.jpg", + "sha256": "c5872d4857e43518f00d0ffda54a58eb71197a9f144930e66a45d9ee9d3e9416" + }, + { + "kind": "file", + "path": "img_4120.jpg", + "sha256": "6d542f09316bc8bfcbd2576c2f5a53c3dc5e1452e1ff5bc2f42f0d4135f41a2c" + }, + { + "kind": "file", + "path": "img_2545.jpg", + "sha256": "f84295f3ea03aa459d911bb9b54fd63f107820a5e14f76b23f67c27c76e1d47e" + }, + { + "kind": "file", + "path": "img_4134.jpg", + "sha256": "8b604fb3794a7750dd5e5d2c2e82f28a55dcfa6f29e8f687a432b5f617c55ed7" + }, + { + "kind": "file", + "path": "img_4652.jpg", + "sha256": "a80484126086094b0a3fd646a2133bfc555aa793c2b02a6d16d6419ffbc48ca7" + }, + { + "kind": "file", + "path": "img_912.jpg", + "sha256": "f20c41f0c30528cf9769932e6ddcdbe66667cb4c312a2118d2a387153bfdb4d8" + }, + { + "kind": "file", + "path": "img_2223.jpg", + "sha256": "ab5d1d40f7920304f34af8be83c3b6cac3f51cd7db8c19e847a996fe1d0fe189" + }, + { + "kind": "file", + "path": "img_245.jpg", + "sha256": "44a935e417ac075fe7c37dce8c5bf89740df206baacb2e4620d3b4c96290ea45" + }, + { + "kind": "file", + "path": "img_2974.jpg", + "sha256": "659ee922e5f57b52100e7e28221af51f07064ee36baaf5461a37bebbf8a1ea4a" + }, + { + "kind": "file", + "path": "img_523.jpg", + "sha256": "563852f5b5030dac5b06a55519b113d48f72b168db08e2b178458e6b5b93c0a3" + }, + { + "kind": "file", + "path": "img_537.jpg", + "sha256": "49dd43f3ca83e6ad6233e3eb95b50a5723a360afbc3184ad1924a7faebd93041" + }, + { + "kind": "file", + "path": "img_251.jpg", + "sha256": "4d97a839733229a78cca6bbd70be0a0f7f1eca191831376da2efe45d8cbe6c35" + }, + { + "kind": "file", + "path": "img_2960.jpg", + "sha256": "3d89d5f1aec91caf414349322874630234076120f0ccd7d7bccd832423102433" + }, + { + "kind": "file", + "path": "img_1299.jpg", + "sha256": "d4cd5c95e4c42002b39770eef6c816dce687535cc3654b52a78fb8fc5f727941" + }, + { + "kind": "file", + "path": "img_2790.jpg", + "sha256": "c12a80e350fddb512b59b8772fdff009db6ab1ac41aee743875250957767ea79" + }, + { + "kind": "file", + "path": "img_279.jpg", + "sha256": "4c8b02dc1a16a814b6eb76020a9f650e8fc196c3dff578092662d97b89622f23" + }, + { + "kind": "file", + "path": "img_2948.jpg", + "sha256": "e6fde7c57ffe1da0a403463b51d1433e30ac33106bdd41f923c14ad197b7a6b6" + }, + { + "kind": "file", + "path": "img_4493.jpg", + "sha256": "7207d937198cf8942140af568f1d35bb096a1c6f95e95a728a71515763781c1a" + }, + { + "kind": "file", + "path": "img_2784.jpg", + "sha256": "9677ec08d6fde7ba78d0a4ae6eb0056862e41360ff93253b5a97f2e1734758c9" + }, + { + "kind": "file", + "path": "img_1266.jpg", + "sha256": "3240f6a8c003e1b030f1b75991d1ad04b4ec61003fd5ed1d0085e4698e89bf39" + }, + { + "kind": "file", + "path": "img_3471.jpg", + "sha256": "d1e734cece3be001b24855fc22e81af6121033b6bda35eacae8e394a63005090" + }, + { + "kind": "file", + "path": "img_286.jpg", + "sha256": "104963834b4646bc058b30948b9a3ef787f945e1a2927a62772920f4113d684e" + }, + { + "kind": "file", + "path": "img_2009.jpg", + "sha256": "cccdf945bd31a9d1b8984874b7e659154c480d8a5ac7f5b3f49916ce29c7a3cc" + }, + { + "kind": "file", + "path": "img_4478.jpg", + "sha256": "2f65163b6595748d33c1ce5462e2bc53f71e20136ebc371037b1546b50267ba8" + }, + { + "kind": "file", + "path": "img_3317.jpg", + "sha256": "2415d52fb67141aa2f2b072563fb65627440232f10b20e3cb202188379be1dc5" + }, + { + "kind": "file", + "path": "img_1514.jpg", + "sha256": "f3f83b6ea84aba1f03724588471eb64db14d6f23b75609c1767e8df741323b5e" + }, + { + "kind": "file", + "path": "img_3303.jpg", + "sha256": "fc660a236551b4dc507942a0d59fc4f84809cf3bd1a75ed5d33341da450ca823" + }, + { + "kind": "file", + "path": "img_3465.jpg", + "sha256": "58576fe46140325895c28df126ff66f10b7fef390c9b378853acf74fb55023c1" + }, + { + "kind": "file", + "path": "img_292.jpg", + "sha256": "199db7dd367e78fa17b0d8240ea029778cd5784e48cb8c727c84c97bb6d2eae6" + }, + { + "kind": "file", + "path": "img_2753.jpg", + "sha256": "60d9255823fd9bf5c9e734550be6bdf83fc0813e505770837cb7eed34b79edae" + }, + { + "kind": "file", + "path": "img_2035.jpg", + "sha256": "47a733941ba837cc768db2e2552789d13e5e464dbfc0a189190af92ad73fba07" + }, + { + "kind": "file", + "path": "img_4444.jpg", + "sha256": "2eb15aefa29b180b86a514235335a0589efc152badab9b5cfff03f7f0956028a" + }, + { + "kind": "file", + "path": "img_2021.jpg", + "sha256": "98ffa178b180f61a02a74e30f8510b9045a6bb835f348e5ea96b413b52059ff7" + }, + { + "kind": "file", + "path": "img_4450.jpg", + "sha256": "7d65437ff376b90069a4c19a653dcfc729278cfd20d42e5ff00eae4c8ab62310" + }, + { + "kind": "file", + "path": "img_1528.jpg", + "sha256": "1edd7d24f1625ffdfbeac4ed2fe611ffa3c54a015dca0731516edd8e250f0c2b" + }, + { + "kind": "file", + "path": "img_3459.jpg", + "sha256": "923e28874d843d695c580fef23d034be5f5c0c70f9378454e621e571b320f4f8" + }, + { + "kind": "file", + "path": "img_4336.jpg", + "sha256": "4a709e6a21264f7369517de06939a01168db4aa538658041e83a67335861fcaa" + }, + { + "kind": "file", + "path": "img_2747.jpg", + "sha256": "82d9bac0527a4d6f0549817977f87b79a8577a97319185a17a177dfe4825a019" + }, + { + "kind": "file", + "path": "img_4451.jpg", + "sha256": "a6e825f1c64468b599e182716334dd72e40ebcc10265c165e972ff8cdb4bf017" + }, + { + "kind": "file", + "path": "img_2746.jpg", + "sha256": "90e9e81bef1d710084116ab545e816e8ef32635fff8dad1b9b064ad344a6f872" + }, + { + "kind": "file", + "path": "img_3458.jpg", + "sha256": "2cae8e23fa437e40802b5e64967c4e363db39973aa8e37b6cc9a9dab044aa4e2" + }, + { + "kind": "file", + "path": "img_2752.jpg", + "sha256": "64769e91d74c091ba1ad7803dd82045101c067b885295cb7fc98c6c84d4f5da6" + }, + { + "kind": "file", + "path": "img_4323.jpg", + "sha256": "5da0ae224a5ab5d6c18ab59ab50a02748bd205b165568fc0af9eefbb6a2a5621" + }, + { + "kind": "file", + "path": "img_4445.jpg", + "sha256": "ad743075dc9395ca4aefefd259ab42e26f68b3fa25bca3df284847de18f13fa4" + }, + { + "kind": "file", + "path": "img_2034.jpg", + "sha256": "b14d1b793b771bbbee70d4af90b666ea2b7af91c18042a66ded5a43ff6a313c4" + }, + { + "kind": "file", + "path": "img_3302.jpg", + "sha256": "1da23c242b22a0b3c9825271c15b9ed6346e511622f610541d1a296db80bbfa3" + }, + { + "kind": "file", + "path": "img_1515.jpg", + "sha256": "b5df6c6859a89b2deb53b28de7cf20147e1cb3e2f28550e376e75517d84db059" + }, + { + "kind": "file", + "path": "img_1273.jpg", + "sha256": "d8ea791cabf9e2bf399aa864a465c86d380c9b78754116d9c78b74a2f72c3c38" + }, + { + "kind": "file", + "path": "img_293.jpg", + "sha256": "4769b316f5cd15bcb6dee0396eba9a9a740b089e53bf5279bdf0d46de38041f0" + }, + { + "kind": "file", + "path": "img_3464.jpg", + "sha256": "a340c3feed8698fbbc844210fc26faa8e476fe5c8baa95c96c3e293f4208b975" + }, + { + "kind": "file", + "path": "img_287.jpg", + "sha256": "1e8501ab38236bcbfb008a309efce80afdeb5953afbc5e18a3848193d8e1a7af" + }, + { + "kind": "file", + "path": "img_3470.jpg", + "sha256": "06e78ba7a38bec9ea3fdbab997980bc2d681fbcd53c61daeeed9a9e416f03c41" + }, + { + "kind": "file", + "path": "img_1267.jpg", + "sha256": "505bcdef41442b8d9aca918d98c1c1f7843df9eb3b5a16145718fd2ad533ac4c" + }, + { + "kind": "file", + "path": "img_1501.jpg", + "sha256": "113248f3d7302d3e0bd5d1d87ec1c4c44373913ad34a8f169d5a7c3f71c5628b" + }, + { + "kind": "file", + "path": "img_3316.jpg", + "sha256": "af9fa48b7a9c7a545ddef04410e4a74a24399b0711aa576090fef227bb0b75d3" + }, + { + "kind": "file", + "path": "img_4479.jpg", + "sha256": "5fd5332745188915e5b0218648d42bfa034d4f0a8483ff9daa32412b5e7d2199" + }, + { + "kind": "file", + "path": "img_4492.jpg", + "sha256": "13df0453a74562a014f09a0f7af1d8b99fdd667b39c1a307ad75eaa0c39b920b" + }, + { + "kind": "file", + "path": "img_2785.jpg", + "sha256": "ba713afad4a6fb1d182ff75707ec815505805aaa8eb9c8963c805c1811ec8ce1" + }, + { + "kind": "file", + "path": "img_2949.jpg", + "sha256": "f32652abd2411477aaddb70e7fa0297418875d5fedb4418db3642a6ff077c8bb" + }, + { + "kind": "file", + "path": "img_278.jpg", + "sha256": "5808bee419aaf03ba1d13bc579c9adb3fe70e4f92a75038460fe1bd760195ff7" + }, + { + "kind": "file", + "path": "img_2791.jpg", + "sha256": "3fcf84aaddd2aa6a0192f48b1eed7bfbf1060bb59ac922e8bba121640a384dbf" + }, + { + "kind": "file", + "path": "img_1298.jpg", + "sha256": "4ff9263ca143178bddced8db92adb7e6e69177085320b9d360606d27fd3b82ad" + }, + { + "kind": "file", + "path": "img_4486.jpg", + "sha256": "767e70cfc4980f0173279b29eb33c3394fe0907092b97baad178363a68083943" + }, + { + "kind": "file", + "path": "img_536.jpg", + "sha256": "1f09c757f02b40fec2e687b93c3b126b12f4ad6d0f89323e04636e739fdf40b3" + }, + { + "kind": "file", + "path": "img_2961.jpg", + "sha256": "739bb2c9daa5efdafcdf401134ead793a2a4e9d47203d5aa0356c31bed835739" + }, + { + "kind": "file", + "path": "img_2975.jpg", + "sha256": "bf3d59f56bef50c9c6ba344d19cc841a4a8ad3074496efdae457d2ab52b7c556" + }, + { + "kind": "file", + "path": "img_3882.jpg", + "sha256": "8fd7119de5eb4d0a11a6cd250d77e7ba40fb30f935166998f0ada7d105e1ea13" + }, + { + "kind": "file", + "path": "img_2544.jpg", + "sha256": "91e7c0bb538c8b685c694c6719d6469e7477c4a01f85b09aabafd5e7516e5123" + }, + { + "kind": "file", + "path": "img_2222.jpg", + "sha256": "7905f053be8807eca21732d908a36bfb2e3b21bcb89fd1d3b7ab022f4f181c56" + }, + { + "kind": "file", + "path": "img_2236.jpg", + "sha256": "74cf8f2a167eae5d0bf2765543cdd2e5152c22214bcf4f40d4058d5e82a23d05" + }, + { + "kind": "file", + "path": "img_4647.jpg", + "sha256": "16a97ba7ea7d89a11ac900d64ee7d89ec1eadfd28eb111e601512922d71fd3e5" + }, + { + "kind": "file", + "path": "img_3128.jpg", + "sha256": "25c564b312da7cd51f7369893ece1bb586ef1389b5e2dba588e4b17ed7603051" + }, + { + "kind": "file", + "path": "img_4121.jpg", + "sha256": "2391cedde8e390776364211a9b4ae60880747a77f9286fbb3ac7aa09bbc40015" + }, + { + "kind": "file", + "path": "img_3896.jpg", + "sha256": "c2a96476616decdbbb74d419b089d699747c73a12aeb4c6277b7d12ffdf1e9a3" + }, + { + "kind": "file", + "path": "img_2550.jpg", + "sha256": "fcbbe1cda9107f2ea12040816612dc95a267a3a16010f26d0b748808afa68cf9" + }, + { + "kind": "file", + "path": "img_1059.jpg", + "sha256": "5ebdf3318aa839c02df1526ed43d9f51ce7cd35d2fa22ce9e5090cdfd1ab16eb" + }, + { + "kind": "file", + "path": "img_3666.jpg", + "sha256": "c9cc59561bc9852874e9846e9265e7d50661aabdf81d30f551d039b1e195b602" + }, + { + "kind": "file", + "path": "img_4109.jpg", + "sha256": "5ce083cf49b5d56686e52246120a01db06618238c6dc6c5df49c877701b0680c" + }, + { + "kind": "file", + "path": "img_2578.jpg", + "sha256": "27bc9b345a442f4fa1efd13b22ad30efbb28e33c74c0a6e31880bade2290a8bb" + }, + { + "kind": "file", + "path": "img_1071.jpg", + "sha256": "a80c1df42727b2c5f0a77ba75d1eb807bf833e2318e5f14a75c3f221fea4f524" + }, + { + "kind": "file", + "path": "img_1717.jpg", + "sha256": "9ab76f5a6a70e60be39b35865d89382e8a54fbf107517d4de88a1f1b4997d149" + }, + { + "kind": "file", + "path": "img_3114.jpg", + "sha256": "e5c0a18b3fd2107c7612bd073a80c7fbf5b600b761743c6af0d8aa6cd241be94" + }, + { + "kind": "file", + "path": "img_1703.jpg", + "sha256": "444f5f1a3806fcf0cc5e80765fb92b63bb1f0d07d44251f7033cafddfad9d92a" + }, + { + "kind": "file", + "path": "img_1065.jpg", + "sha256": "06b48e037df48f10974d9a176826e412947c63eed82235b5339a08bf06f9b0e2" + }, + { + "kind": "file", + "path": "img_3672.jpg", + "sha256": "64e9747f5b53b28d73fa81602d6ae1d0787c1ba298a9b760fd31c0c8a6566638" + }, + { + "kind": "file", + "path": "img_3841.jpg", + "sha256": "a9272fccae53ef73c5bc0372f1a6266aeb0faca32840e206375505ea38b253be" + }, + { + "kind": "file", + "path": "img_2587.jpg", + "sha256": "335428bf7760cfb077e3c37414e5f0124ab8577fbd8b948e7c5c01e3503312fb" + }, + { + "kind": "file", + "path": "img_3699.jpg", + "sha256": "45aa23452039107e3af5b7f539b0fffedea2fe9dba7d8e46a5e8b868ee511af5" + }, + { + "kind": "file", + "path": "img_1930.jpg", + "sha256": "d2ffabe516ecf339498dcdca55914a085fafe1f0e2d0be0e744c27e8597cef8f" + }, + { + "kind": "file", + "path": "img_4690.jpg", + "sha256": "5eadaf8dbd68e79c5fb69eb3714ed568451a6d5f6b460c7b0f9c934d8c3a54f3" + }, + { + "kind": "file", + "path": "img_708.jpg", + "sha256": "69cb79879ae6024d9a4f8e13bb272bbd25bba59b400e9427457f2b5b4f00ca1e" + }, + { + "kind": "file", + "path": "img_4848.jpg", + "sha256": "5e849f9dbae91c1328d1e5e4c4320c6b073f8de231a998367c38b4954edbea6a" + }, + { + "kind": "file", + "path": "img_4684.jpg", + "sha256": "08d48f9e507e5a430cce3f793782137ae58e1b4a87c35bf6e35f0e0e1c318462" + }, + { + "kind": "file", + "path": "img_1924.jpg", + "sha256": "edaa83671636b7769ee8a398c204c862d9009999c1a1453aa056bb41227329fc" + }, + { + "kind": "file", + "path": "img_3855.jpg", + "sha256": "91a4649c6e8ba78086fe34cc63e6826aae4782b69804df3b12da658f61b9eafb" + }, + { + "kind": "file", + "path": "img_2593.jpg", + "sha256": "fcfcc745708243def319f83cdfbf1697e267de2c688f874561c901eaeb2870dc" + }, + { + "kind": "file", + "path": "img_734.jpg", + "sha256": "d680fa531843eed9bbb370b70f5c3e3b33da8b285305cc3d68c0173463c1ec4a" + }, + { + "kind": "file", + "path": "img_1918.jpg", + "sha256": "9af0c44aeeb6a72392c3742504a580fdeabb6d2514db666933c7c70c29b3f959" + }, + { + "kind": "file", + "path": "img_720.jpg", + "sha256": "9e1a67fab95feacd882c940bbc3220bc178dff10c4a4f91e15b4d951290cc316" + }, + { + "kind": "file", + "path": "img_4860.jpg", + "sha256": "0074864ce97f28603a9d77c0ac324fcfe7ccc736776ae3ea5beddfcfb775203a" + }, + { + "kind": "file", + "path": "img_3869.jpg", + "sha256": "06715daaa6c5f4fa8acbfbed6de89ecade96747fffa3da2edda1b054dce591fe" + }, + { + "kind": "file", + "path": "img_1139.jpg", + "sha256": "a55c3128c0e6cb5657dea0e72c17e32815f7e8fc76c460b6134bf27774907ba5" + }, + { + "kind": "file", + "path": "img_2430.jpg", + "sha256": "c0af5692629e347efec590774812799aad419e29d5d8b60a039fabe6e0745ac2" + }, + { + "kind": "file", + "path": "img_4041.jpg", + "sha256": "32a5563507dba4eaf4cdf943c83dbe1fb311e29054ef622bf5163b610b43d49f" + }, + { + "kind": "file", + "path": "img_3048.jpg", + "sha256": "c287fb308ccd852372f2bd20e10680794adc6fa6aab8e693b1446f703e14b723" + }, + { + "kind": "file", + "path": "img_4727.jpg", + "sha256": "81be35b6ec174736cd54f33ccfb3bbd3bdf8ee7a67062e53a9f838c8e3440372" + }, + { + "kind": "file", + "path": "img_867.jpg", + "sha256": "19972c9878b5f8b490e97b8fc80e3d2446c8aad99b2ffa07727c27825f6704bd" + }, + { + "kind": "file", + "path": "img_2356.jpg", + "sha256": "c5f6752d88a68b56b2e64a595b134c66f28ed2844323671a51a7b89df3be5acb" + }, + { + "kind": "file", + "path": "img_1887.jpg", + "sha256": "6eac3925447a63fb2f3f0bc8dbab49e13a53e2b89ad37019ae1921ced1b1203c" + }, + { + "kind": "file", + "path": "img_1893.jpg", + "sha256": "b0261e9b41428517471e356340774535ad2afc99b6242b48b1ae717599a2a6a4" + }, + { + "kind": "file", + "path": "img_873.jpg", + "sha256": "1609685401bb1465e5f20e03286e98cfec7ecca5f28806e7dd630398c1f4d9a7" + }, + { + "kind": "file", + "path": "img_2424.jpg", + "sha256": "1d93b8b3fc8c102d76859fe157a6177ff1f8c1f77b6bbde1a30308331a78fea8" + }, + { + "kind": "file", + "path": "img_3712.jpg", + "sha256": "785f4a8a2fb6399162bafe8d32c4c376c2baf5fbfce171118c34fe1efe80abfc" + }, + { + "kind": "file", + "path": "img_1105.jpg", + "sha256": "0d8db60c2dbed5fe850270e6a724df25bb4f397bf68982b35ecc34955f756bf8" + }, + { + "kind": "file", + "path": "img_683.jpg", + "sha256": "6545d10bde26795fcf2e0f2348c5359799450aff5a510a2a351316c7b5ce0e66" + }, + { + "kind": "file", + "path": "img_3060.jpg", + "sha256": "496575aa09925c564e84923ea7d6770e21e060ae21f044fc6798244eeaf0be06" + }, + { + "kind": "file", + "path": "img_697.jpg", + "sha256": "08d34ffa5d559d9f4fdc4517becb93f81ebbaac315cadb876ab211651cb1330b" + }, + { + "kind": "file", + "path": "img_1677.jpg", + "sha256": "cd244475df16e826a1eb717cae59d47ee4f364875b0403e247c01ec70f6d8f6a" + }, + { + "kind": "file", + "path": "img_1111.jpg", + "sha256": "bad7d3dc0f8ae915c5c17302f41193b20905086db046f7c1af3286c54b2f08c6" + }, + { + "kind": "file", + "path": "img_2418.jpg", + "sha256": "a0e3a0527af6a75f696df967b849885b1045625e0b4ade9a887a8fc4b6f96519" + }, + { + "kind": "file", + "path": "img_4069.jpg", + "sha256": "27decea51216f6398c133bace6ad2294999bbf74237ef82bc988b8d4bc921ba7" + }, + { + "kind": "file", + "path": "img_4082.jpg", + "sha256": "5264fa99fb61159f691dc01d0ee39d9079838243d071c5941315f2f181377b0c" + }, + { + "kind": "file", + "path": "img_1844.jpg", + "sha256": "b88c71aad7a1f117c5afe2447efee29b54ba2fe7b890a9946a42fb87f39e60a8" + }, + { + "kind": "file", + "path": "img_4928.jpg", + "sha256": "554a06917cfc5bf7dabc505208d372019ab0d1fb325f7df4129a03eef6c3b2f2" + }, + { + "kind": "file", + "path": "img_2381.jpg", + "sha256": "906f5b1ba408e6d1c7245a744d2dd031263bab6b4380916ed0174ca63e139f2f" + }, + { + "kind": "file", + "path": "img_668.jpg", + "sha256": "3c9978a948565ee6d4a7bed3d3ef583d78aa8fcfd732ca36fb64b5691414031d" + }, + { + "kind": "file", + "path": "img_1850.jpg", + "sha256": "df1e2fea22c08c0bdb45fb20f97b035b5dffa2fefe49f121a102ab2427f8cb9d" + }, + { + "kind": "file", + "path": "img_1688.jpg", + "sha256": "7845666cde6c54e65df18dfec6e3407c155cd778795d917d1079170929a5691e" + }, + { + "kind": "file", + "path": "img_4096.jpg", + "sha256": "906b851fc527e3983d48a4114fa3a0d694b184c629bf71a772439f58b927c453" + }, + { + "kind": "file", + "path": "img_3921.jpg", + "sha256": "e6a550eb5dddf212b7a4e98788d41991158d5f9f793d0fc9c7d1b0427a2de6d6" + }, + { + "kind": "file", + "path": "img_126.jpg", + "sha256": "0a6eaddb5e51d7308d9ebab95da8b24d4e69179dbc9c5336eabbe1141e4070c5" + }, + { + "kind": "file", + "path": "img_4900.jpg", + "sha256": "37c9f80a7141332e67025d9433e3039a767b91a1db82b46f692c1d595366c5fb" + }, + { + "kind": "file", + "path": "img_640.jpg", + "sha256": "e3e46e4c893bbe8440934284476b5d84e143b771555cf2632e2f73d55ca6157e" + }, + { + "kind": "file", + "path": "img_1878.jpg", + "sha256": "f90fa75471cb1412caa619b9ca93951bc419f80cb1dad2589e72db9a45beabff" + }, + { + "kind": "file", + "path": "img_4914.jpg", + "sha256": "1dc062e93c5f1bf5f81f29ac66ff7b085f7867691655f32d8a5d3cdb967e347d" + }, + { + "kind": "file", + "path": "img_654.jpg", + "sha256": "50c012661e803b55381aae766a1dcccadfae21dea541f2a0d89c18b66b3f8836" + }, + { + "kind": "file", + "path": "img_132.jpg", + "sha256": "6f632155e8a346b1faf46aa1628a8c0c3739907addae46c6e34f130ec20cfa7f" + }, + { + "kind": "file", + "path": "img_2154.jpg", + "sha256": "c6b4061126d8ce8b77d2c86d2a8a9aa1f71ab486bc6fad1e91434a0b85b54760" + }, + { + "kind": "file", + "path": "img_21.jpg", + "sha256": "98b61f371e01cfea15a71c6c1e2be828d8e6bb24c5925cc8306d84de96bd397e" + }, + { + "kind": "file", + "path": "img_4525.jpg", + "sha256": "35eb86e9f136bf18414ca0347c5b1e5e46f3fc6a6228653e5df2b85334623c38" + }, + { + "kind": "file", + "path": "img_4243.jpg", + "sha256": "6aabc882b3d9c20000a0a6e5d641284ef58b78acbbeb247f4ea0e1cc36887db3" + }, + { + "kind": "file", + "path": "img_3538.jpg", + "sha256": "88ed31bfd184d598d084dba8913cf991502abd0c66194cbbcc14cb7203b6c232" + }, + { + "kind": "file", + "path": "img_4257.jpg", + "sha256": "3e2174d7ea50f5b7472c76aaf3704cc8663e340a1814d62285620be85f800b7c" + }, + { + "kind": "file", + "path": "img_2140.jpg", + "sha256": "2f261e2f2e6b8a0d89ec6f946b7214e8d9d17d905ed1af79e27be69037277d64" + }, + { + "kind": "file", + "path": "img_35.jpg", + "sha256": "e889000b72bfdb97ded39c61e395fd82d07f5942ef2c387ed6b35afd75553a44" + }, + { + "kind": "file", + "path": "img_4531.jpg", + "sha256": "3b97b5070428cf3ef4d94e77a605d501512505daf28ce8d8008bac62984026cc" + }, + { + "kind": "file", + "path": "img_2168.jpg", + "sha256": "d1ce0914a5f5d2f5f47c0e8a9ad72a93cb9d6149bf3a91e076cca65eb677a586" + }, + { + "kind": "file", + "path": "img_481.jpg", + "sha256": "1fc46ca4c4b81eeab81a1ddef95a7b1bf7d198e1cd20c05c751ae1665c810a76" + }, + { + "kind": "file", + "path": "img_3276.jpg", + "sha256": "30b0c7533e4b63e7c5ade9c2b9d22deac6e739b1ff2c08843bb728cbab226a4e" + }, + { + "kind": "file", + "path": "img_1461.jpg", + "sha256": "40d430de981bd9a15044932175e07ab55b2ce5bef8db754f8e2ffb063609d3de" + }, + { + "kind": "file", + "path": "img_1307.jpg", + "sha256": "b37bdad42b92bcd89131a571a9d2abfe7ea49aad2da6476f97944b0484141ccb" + }, + { + "kind": "file", + "path": "img_3510.jpg", + "sha256": "03afff52da05fee2034b7e6b4e61b88506061a93df644db1e1ec0bc783bbf62f" + }, + { + "kind": "file", + "path": "img_3504.jpg", + "sha256": "0e4b842a83660747df5ac65bc677461b6729eac988e957839253b35f7be56577" + }, + { + "kind": "file", + "path": "img_1313.jpg", + "sha256": "74ede34ff6b0b977ef2408f2e5ccba447dd2fa137c404ff4958040e2d3718a89" + }, + { + "kind": "file", + "path": "img_1475.jpg", + "sha256": "59a7e6880f42b04d90f140e0900d902001875ceead7ee7abd11e61479aca2476" + }, + { + "kind": "file", + "path": "img_495.jpg", + "sha256": "b40f74fe2513d4b5aba441a948a4e7ef8cf1bae8884fc55ea42958c0277d23ce" + }, + { + "kind": "file", + "path": "img_3262.jpg", + "sha256": "fc5a377827de0304258d609d5c48307d2b27348b9a56114e56a65052c260d9d2" + }, + { + "kind": "file", + "path": "img_3289.jpg", + "sha256": "f410038ee8a1aab642cbaed2a091ef5ec33df7a9237b83c6c1c9f92d3b713a0e" + }, + { + "kind": "file", + "path": "img_2197.jpg", + "sha256": "46831cc855700aa95b12b713ebeac7e5b0d078724c5158aaacefeb1beb253a54" + }, + { + "kind": "file", + "path": "img_318.jpg", + "sha256": "ee6a141b7ce4c42f3bcf9b48ba6c03f802e78005676b3965abad085bd0baf72a" + }, + { + "kind": "file", + "path": "img_2829.jpg", + "sha256": "ac01aa7236202e1244bfffbba29c8d554896412e9dba8837c316ed351b98f12e" + }, + { + "kind": "file", + "path": "img_4280.jpg", + "sha256": "3062c00a43aba8a91068af0a2c64fd95098280a4e954b9625a58c3e0955c698e" + }, + { + "kind": "file", + "path": "img_4294.jpg", + "sha256": "195cd7a00e2a41c770b74effd15b386c29b6b230661879bf78038a6b1bb278ff" + }, + { + "kind": "file", + "path": "img_2183.jpg", + "sha256": "4c5b4d44f07a579e6e3463b11f68ac068eb71b263b3f942e76d7c166164098da" + }, + { + "kind": "file", + "path": "img_442.jpg", + "sha256": "77401162fcbce83c30ecbff81298dfe99f344013f51b698d61aa979291174f2b" + }, + { + "kind": "file", + "path": "img_324.jpg", + "sha256": "1c14faf81857fed028816609e7e685e02a2e64a8d00e301e5681ab4c7960546e" + }, + { + "kind": "file", + "path": "img_2815.jpg", + "sha256": "6fc63424540685fbb78fecfaa66e114c3009d9fd234261a28309c5ab92d0405f" + }, + { + "kind": "file", + "path": "img_330.jpg", + "sha256": "5535ca55c39d16fc072fdd10760bcc1271e7d067da735df6a559d2656ad28433" + }, + { + "kind": "file", + "path": "img_2801.jpg", + "sha256": "6c98d573768c3208671fde04a0687b4a321c4602d98395ed669f32eefb46016b" + } + ] + } + ] +} \ No newline at end of file diff --git a/tests/data/resources/pu-user1/apps/app2/datasetcmp/samokat/v1/metadata.json b/tests/data/resources/pu-user1/apps/app2/datasetcmp/samokat/v1/metadata.json new file mode 100644 index 0000000..4c40495 --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app2/datasetcmp/samokat/v1/metadata.json @@ -0,0 +1,31 @@ +{ + "@context": "https://schema.org/", + "@type": "Dataset", + "name": "HSE-Scooter Dataset", + "description": "Датасет содержит изображения с комплексов видеонаблюдения на проезжих частях и дорогах общего пользования, включая зоны пешеходных переходов.", + "creator": { + "@type": "Organization", + "address": { + "@type": "PostalAddress", + "addressLocality": "Moscow, Russia", + "postalCode": "101000", + "streetAddress": "20 Myasnitskaya Ulitsa" + }, + "name": "HSE University" + }, + "contentRating": "General", + "dateCreated": "26-08-2024", + "keywords": "images,scooter,roads", + "maintainer": { + "@type": "Organization", + "address": { + "@type": "PostalAddress", + "addressLocality": "Moscow, Russia", + "postalCode": "101000", + "streetAddress": "20 Myasnitskaya Ulitsa" + }, + "name": "HSE University" + }, + "size": "2.25GB", + "version": "26-08-2024" +} \ No newline at end of file diff --git a/tests/data/resources/pu-user1/apps/app2/exp-pipeline10.yaml b/tests/data/resources/pu-user1/apps/app2/exp-pipeline10.yaml new file mode 100644 index 0000000..7ed0479 --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app2/exp-pipeline10.yaml @@ -0,0 +1,62 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: ExperimentPipeline +metadata: + name: test-ep10 + namespace: pu-user1-pa-app2 +spec: + vars: + - name: input1 + path: /data/i1 + mountFrom: + box: + name: user_data + - name: input2 + path: /data/i2 + mountFrom: + box: + name: user_data + - name: input3 + path: /data/i3 + mountFrom: + box: + name: user_data + - name: input4 + path: /use + mountFrom: + box: + name: user_data + boxPath: models + - name: output1 + path: /data/o1 + mountFrom: + box: + name: user_data + stages: + - name: stage1 + image: + existingImageName: platform-reg.stratpro.hse.ru/pu-user1/test-model1:1.0.0-c25bfce + inputs: + - name: input1 + - name: input2 + - name: input3 + - name: input4 + outputs: + - name: output1 + entryPoint: + cmd: + - bash + - -c + - echo "test" + connectedBoxes: + - name: user_data + path: /data + default: true + mountS3Box: + s3BoxName: test-app2-user-data + diff --git a/tests/data/resources/pu-user1/apps/app2/exp-pipeline101.yaml b/tests/data/resources/pu-user1/apps/app2/exp-pipeline101.yaml new file mode 100644 index 0000000..b9a80ba --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app2/exp-pipeline101.yaml @@ -0,0 +1,65 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: ExperimentPipeline +metadata: + name: test-ep101 + namespace: pu-user1-pa-app2 +spec: + vars: + - name: input1 + mountFrom: + box: + name: user_data + - name: input2 + mountFrom: + dataset: + name: dataset_storage + - name: input3 + mountFrom: + dataset: + name: dataset_storage_ref + - name: input4 + path: /use + mountFrom: + box: + name: user_data + boxPath: models + - name: output1 + path: /data/o1 + mountFrom: + box: + name: user_data + stages: + - name: stage1 + image: + existingImageName: platform-reg.stratpro.hse.ru/pu-user1/test-model1:1.0.0-c25bfce + inputs: + - name: input1 + - name: input2 + - name: input3 + - name: input4 + outputs: + - name: output1 + entryPoint: + cmd: + - bash + - -c + - echo "test" + connectedBoxes: + - name: user_data + path: /data + default: true + mountS3Box: + s3BoxName: test-app2-user-data + - name: dataset1 + path: /data + mountDataset: + # опция, если используется ящик вида dataset + datasetName: dataset_box_or_ref + + diff --git a/tests/data/resources/pu-user1/apps/app2/exp-pipeline11.yaml b/tests/data/resources/pu-user1/apps/app2/exp-pipeline11.yaml new file mode 100644 index 0000000..5448780 --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app2/exp-pipeline11.yaml @@ -0,0 +1,103 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: ExperimentPipeline +metadata: + name: test-ep11 + namespace: pu-user1-pa-app2 +spec: + vars: + - name: input1 + - name: input2 + - name: input3 + - name: internal1 + - name: output1 + - name: output2 + mountFrom: + box: + name: pipeline_data + stages: + - name: stage1 + image: + existingImageName: platform-reg.stratpro.hse.ru/pu-user1/test-model1:1.0.0-c25bfce + inputs: + - name: input1 + path: /input1 + - name: input2 + path: /input2 + outputs: + - name: output1 + path: /output1 + - name: internal1 + path: /internal1 + entryPoint: + cmd: + - bash + - -c + - >- + echo "VAR input1 $UNIP_PIPELINE_INPUT1" + && echo "CMD ls -al input1" + && ls -al "$UNIP_PIPELINE_INPUT1" + && echo "VAR input2 $UNIP_PIPELINE_INPUT2" + && echo "CMD cat input2" + && cat "$UNIP_PIPELINE_INPUT2" + && echo "" + && echo "CMD ls -al input1 > output1/out.txt" + && ls -al "$UNIP_PIPELINE_INPUT1" > "$UNIP_PIPELINE_OUTPUT1/out.txt" + && echo "CMD echo test > internal1/data.txt" + && echo "test\n" > "$UNIP_PIPELINE_INTERNAL1/data.txt" + && echo "CMD cat input2 >> internal1/data.txt" + && cat "$UNIP_PIPELINE_INPUT2" >> "$UNIP_PIPELINE_INTERNAL1/data.txt" + && echo "VAR output1 $UNIP_PIPELINE_OUTPUT1" + && echo "CMD cat output1/out.txt" + && cat "$UNIP_PIPELINE_OUTPUT1/out.txt" + && echo "VAR internal1 $UNIP_PIPELINE_INTERNAL1" + && echo "CMD cat internal1/data.txt" + && cat "$UNIP_PIPELINE_INTERNAL1/data.txt" + && echo "" + - name: stage2 + image: + existingImageName: platform-reg.stratpro.hse.ru/pu-user1/test-model1:1.0.0-c25bfce + inputs: + - name: input3 + # "обычный" вход + path: /data1 + - name: internal1 + path: /use + outputs: + - name: output2 + path: /data2 + entryPoint: + cmd: + - bash + - -c + - >- + echo "VAR internal1 $UNIP_PIPELINE_INTERNAL1" + && echo "CMD cat internal1/data.txt" + && cat "$UNIP_PIPELINE_INTERNAL1/data.txt" + && echo "" + && echo "CMD cat internal1/data.txt > output2/result.txt" + && cat "$UNIP_PIPELINE_INTERNAL1/data.txt" > "$UNIP_PIPELINE_OUTPUT2/result.txt" + && echo "CMD cat input3" + && cat "$UNIP_PIPELINE_INPUT3" + && echo "" + && echo "CMD cat input3 >> output2/result.txt" + && cat "$UNIP_PIPELINE_INPUT3" >> "$UNIP_PIPELINE_OUTPUT2/result.txt" + && echo "CMD cat output2/result.txt" + && cat "$UNIP_PIPELINE_OUTPUT2/result.txt" + && echo "" + connectedBoxes: + - name: user_data + path: /data + default: true + mountS3Box: + s3BoxName: test-app2-user-data + - name: pipeline_data + path: /data + default: false + mountS3Box: + s3BoxName: sized-s3-box diff --git a/tests/data/resources/pu-user1/apps/app2/exp-pipeline12.yaml b/tests/data/resources/pu-user1/apps/app2/exp-pipeline12.yaml new file mode 100644 index 0000000..0d5c78a --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app2/exp-pipeline12.yaml @@ -0,0 +1,41 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: ExperimentPipeline +metadata: + name: test-ep12 + namespace: pu-user1-pa-app2 +spec: + vars: + - name: input1 + - name: input2 + - name: output1 + - name: output2 + stages: + - name: stage1 + image: + existingImageName: platform-reg.stratpro.hse.ru/pu-user1/test-model1:1.0.0-c25bfce + inputs: + - name: input1 + outputs: + - name: output1 + entryPoint: + cmd: + - bash + - -c + - echo "test" + resourceLimits: + cpu: 125m + memory: 128M + gpu: "1" + connectedBoxes: + - name: user_data + path: /data + default: true + mountS3Box: + s3BoxName: test-app2-user-data + diff --git a/tests/data/resources/pu-user1/apps/app2/exp-pipeline6.yaml b/tests/data/resources/pu-user1/apps/app2/exp-pipeline6.yaml new file mode 100644 index 0000000..70d08cb --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app2/exp-pipeline6.yaml @@ -0,0 +1,89 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: ExperimentPipeline +metadata: + name: test-ep6 + namespace: pu-user1-pa-app2 +spec: + vars: + - name: input1 + path: /data/i1 + mountFrom: + box: + name: user_data + - name: input2 + mountFrom: + box: + name: user_data + - name: input3 + path: /use + mountFrom: + box: + name: user_data + boxPath: models + - name: output1 + path: /data/o1 + mountFrom: + box: + name: user_data + - name: output2 + path: /data/o2 + mountFrom: + box: + name: user_data + stages: + - name: stage1 + image: + existingImageName: platform-reg.stratpro.hse.ru/pu-user1/test-model1:1.0.0-c25bfce + inputs: + - name: input1 + - name: input2 + path: /data/i2 + - name: input3 + outputs: + - name: output1 + - name: output2 + entryPoint: + cmd: + - bash + - -c + - >- + echo "VAR input1 $UNIP_PIPELINE_INPUT1" + && echo "CMD ls -al input1" + && ls -al "$UNIP_PIPELINE_INPUT1" + && echo "VAR input2 $UNIP_PIPELINE_INPUT2" + && echo "CMD cat input2" + && cat "$UNIP_PIPELINE_INPUT2" + && echo "VAR input3 $UNIP_PIPELINE_INPUT3" + && echo "CMD ls -al input3" + && ls -al "$UNIP_PIPELINE_INPUT3" + && echo "CMD ls -al input1 > output1/out.txt" + && ls -al "$UNIP_PIPELINE_INPUT1" > "$UNIP_PIPELINE_OUTPUT1/out.txt" + && echo "CMD echo test> output2/data.txt" + && echo "test\n" > "$UNIP_PIPELINE_OUTPUT2/data.txt" + && echo "CMD cat input2 >> output2/data.txt" + && cat "$UNIP_PIPELINE_INPUT2" >> "$UNIP_PIPELINE_OUTPUT2/data.txt" + && echo "VAR output1 $UNIP_PIPELINE_OUTPUT1" + && echo "CMD cat output1/out.txt" + && cat "$UNIP_PIPELINE_OUTPUT1/out.txt" + && echo "VAR output2 $UNIP_PIPELINE_OUTPUT2" + && echo "CMD cat output2/data.txt" + && cat "$UNIP_PIPELINE_OUTPUT2/data.txt" + resourceLimits: + cpu: 500m + memory: 128M + env: + - name: VAR1 + value: "100" + connectedBoxes: + - name: user_data + path: /data + default: true + mountS3Box: + s3BoxName: sized-default-s3-box + diff --git a/tests/data/resources/pu-user1/apps/app2/exp-pipeline61.yaml b/tests/data/resources/pu-user1/apps/app2/exp-pipeline61.yaml new file mode 100644 index 0000000..a92b816 --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app2/exp-pipeline61.yaml @@ -0,0 +1,114 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +# Отличается от exp-pipeline6.yaml наличием секций envFrom, configFrom +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: ExperimentPipeline +metadata: + name: test-ep61 + namespace: pu-user1-pa-app2 +spec: + vars: + - name: input1 + path: /data/i1 + mountFrom: + box: + name: user_data + - name: input2 + mountFrom: + box: + name: user_data + - name: input3 + path: /use + mountFrom: + box: + name: user_data + boxPath: models + - name: output1 + path: /data/o1 + mountFrom: + box: + name: user_data + - name: output2 + path: /data/o2 + mountFrom: + box: + name: user_data + stages: + - name: stage1 + image: + existingImageName: platform-reg.stratpro.hse.ru/pu-user1/test-model1:1.0.0-c25bfce + inputs: + - name: input1 + - name: input2 + path: /data/i2 + - name: input3 + outputs: + - name: output1 + - name: output2 + entryPoint: + cmd: + - bash + - -c + - >- + echo "VAR input1 $UNIP_PIPELINE_INPUT1" + && echo "CMD ls -al input1" + && ls -al "$UNIP_PIPELINE_INPUT1" + && echo "VAR input2 $UNIP_PIPELINE_INPUT2" + && echo "CMD cat input2" + && cat "$UNIP_PIPELINE_INPUT2" + && echo "VAR input3 $UNIP_PIPELINE_INPUT3" + && echo "CMD ls -al input3" + && ls -al "$UNIP_PIPELINE_INPUT3" + && echo "CMD ls -al input1 > output1/out.txt" + && ls -al "$UNIP_PIPELINE_INPUT1" > "$UNIP_PIPELINE_OUTPUT1/out.txt" + && echo "CMD echo test> output2/data.txt" + && echo "test\n" > "$UNIP_PIPELINE_OUTPUT2/data.txt" + && echo "CMD cat input2 >> output2/data.txt" + && cat "$UNIP_PIPELINE_INPUT2" >> "$UNIP_PIPELINE_OUTPUT2/data.txt" + && echo "VAR output1 $UNIP_PIPELINE_OUTPUT1" + && echo "CMD cat output1/out.txt" + && cat "$UNIP_PIPELINE_OUTPUT1/out.txt" + && echo "VAR output2 $UNIP_PIPELINE_OUTPUT2" + && echo "CMD cat output2/data.txt" + && cat "$UNIP_PIPELINE_OUTPUT2/data.txt" + resourceLimits: + cpu: 500m + memory: 128M + env: + - name: VAR1 + value: "100" + envFrom: + - secretRef: + name: test-secret1 + - configMapRef: + name: test-cm1 + configFrom: + - configMap: + name: test-cm1 + path: /cms + - configMap: + name: test-cm1 + items: + - key: key1 + path: cm1/items/key1 + path: /cms-items + - secret: + name: test-secret1 + path: /secrets + - secret: + name: test-secret1 + items: + - key: secretKey1 + path: secret1/items/key1 + path: /secrets-items + connectedBoxes: + - name: user_data + path: /data + default: true + mountS3Box: + s3BoxName: test-app2-user-data + diff --git a/tests/data/resources/pu-user1/apps/app2/exp-pipeline7.yaml b/tests/data/resources/pu-user1/apps/app2/exp-pipeline7.yaml new file mode 100644 index 0000000..3ef4040 --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app2/exp-pipeline7.yaml @@ -0,0 +1,73 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: ExperimentPipeline +metadata: + name: test-ep7 + namespace: pu-user1-pa-app2 +spec: + vars: + - name: input1 + - name: input2 + - name: input3 + path: /use + mountFrom: + box: + name: user_data + boxPath: models + - name: output1 + - name: output2 + stages: + - name: stage1 + image: + existingImageName: platform-reg.stratpro.hse.ru/pu-user1/test-model1:1.0.0-c25bfce + inputs: + - name: input1 + - name: input2 + - name: input3 + outputs: + - name: output1 + - name: output2 + entryPoint: + cmd: + - bash + - -c + - >- + echo "input1 $UNIP_PIPELINE_INPUT1" + && echo "ls -al input1" + && ls -al "$UNIP_PIPELINE_INPUT1" + && echo "input2 $UNIP_PIPELINE_INPUT2" + && echo "cat input2" + && cat "$UNIP_PIPELINE_INPUT2" + && echo "input3 $UNIP_PIPELINE_INPUT3" + && echo "ls -al input3" + && ls -al "$UNIP_PIPELINE_INPUT3" + && echo "ls -al input1 > output1/out.txt" + && ls -al "$UNIP_PIPELINE_INPUT1" > "$UNIP_PIPELINE_OUTPUT1/out.txt" + && echo "echo test> output2/data.txt" + && echo "test\n" > "$UNIP_PIPELINE_OUTPUT2/data.txt" + && echo "cat input2 >> output2/data.txt" + && cat "$UNIP_PIPELINE_INPUT2" >> "$UNIP_PIPELINE_OUTPUT2/data.txt" + && echo "output1 $UNIP_PIPELINE_OUTPUT1" + && echo "cat output1/out.txt" + && cat "$UNIP_PIPELINE_OUTPUT1/out.txt" + && echo "output2 $UNIP_PIPELINE_OUTPUT2" + && echo "cat output2/data.txt" + && cat "$UNIP_PIPELINE_OUTPUT2/data.txt" + resourceLimits: + cpu: 500m + memory: 128M + env: + - name: VAR1 + value: "100" + connectedBoxes: + - name: user_data + path: /data + default: true + mountS3Box: + s3BoxName: sized-default-s3-box + diff --git a/tests/data/resources/pu-user1/apps/app2/exp-pipeline8.yaml b/tests/data/resources/pu-user1/apps/app2/exp-pipeline8.yaml new file mode 100644 index 0000000..fe9cbeb --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app2/exp-pipeline8.yaml @@ -0,0 +1,53 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: ExperimentPipeline +metadata: + name: test-ep8 + namespace: pu-user1-pa-app2 +spec: + vars: + - name: input1 + - name: output1 + stages: + - name: stage1 + image: + existingImageName: platform-reg.stratpro.hse.ru/pu-user1/test-model1:1.0.0-c25bfce + inputs: + - name: input1 + outputs: + - name: output1 + entryPoint: + cmd: + - bash + - -c + - >- + echo "input1 $UNIP_PIPELINE_INPUT1" + && echo "ls -al input1" + && ls -al "$UNIP_PIPELINE_INPUT1" + && echo "echo test> output1/data.txt" + && echo "test" > "$UNIP_PIPELINE_OUTPUT1/data.txt" + && echo "cat input1 >> output1/data.txt" + && cat "$UNIP_PIPELINE_INPUT1" >> "$UNIP_PIPELINE_OUTPUT1/data.txt" + && echo "output1 $UNIP_PIPELINE_OUTPUT1" + && echo "cat output1/data.txt" + && cat "$UNIP_PIPELINE_OUTPUT1/data.txt" + resourceLimits: + cpu: 500m + memory: 128M + env: + - name: VAR1 + value: "100" + connectedBoxes: + - name: user_data + path: /data + default: true + mountS3Box: + s3BoxName: test-app2-user-data + continueWith: + name: test-ep9 + diff --git a/tests/data/resources/pu-user1/apps/app2/exp-pipeline9.yaml b/tests/data/resources/pu-user1/apps/app2/exp-pipeline9.yaml new file mode 100644 index 0000000..6a683d1 --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app2/exp-pipeline9.yaml @@ -0,0 +1,51 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: ExperimentPipeline +metadata: + name: test-ep9 + namespace: pu-user1-pa-app2 +spec: + vars: + - name: input2 + - name: output2 + stages: + - name: stage1 + image: + existingImageName: platform-reg.stratpro.hse.ru/pu-user1/test-model1:1.0.0-c25bfce + inputs: + - name: input2 + outputs: + - name: output2 + entryPoint: + cmd: + - bash + - -c + - >- + echo "VAR input2 $UNIP_PIPELINE_INPUT2" + && echo "CMD ls -al input2" + && ls -al "$UNIP_PIPELINE_INPUT2" + && echo "CMD echo test> output2/data.txt" + && echo "test" > "$UNIP_PIPELINE_OUTPUT2/data.txt" + && echo "CMD cat input2 >> output2/data.txt" + && cat "$UNIP_PIPELINE_INPUT2" >> "$UNIP_PIPELINE_OUTPUT2/data.txt" + && echo "VAR output2 $UNIP_PIPELINE_OUTPUT2" + && echo "CMD cat output2/data.txt" + && cat "$UNIP_PIPELINE_OUTPUT2/data.txt" + resourceLimits: + cpu: 500m + memory: 128M + env: + - name: VAR1 + value: "100" + connectedBoxes: + - name: user_data + path: /data + default: true + mountS3Box: + s3BoxName: test-app2-user-data + diff --git a/tests/data/resources/pu-user1/apps/app2/sized-default-s3-box.yaml b/tests/data/resources/pu-user1/apps/app2/sized-default-s3-box.yaml new file mode 100755 index 0000000..3bab0d5 --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app2/sized-default-s3-box.yaml @@ -0,0 +1,14 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: DataBox +metadata: + name: sized-default-s3-box + namespace: pu-user1-pa-app2 +spec: + s3DefaultStorage: + capacity: 50G \ No newline at end of file diff --git a/tests/data/resources/pu-user1/apps/app2/sized-s3-box.yaml b/tests/data/resources/pu-user1/apps/app2/sized-s3-box.yaml new file mode 100755 index 0000000..6dd0506 --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app2/sized-s3-box.yaml @@ -0,0 +1,18 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: DataBox +metadata: + name: sized-s3-box + namespace: pu-user1-pa-app2 +spec: + s3Storage: + host: storage.yandexcloud.net + bucket: + name: test-app2-test + capacity: 5G + awsVarsS3Credentials: app2-all-s3-boxes-cred \ No newline at end of file diff --git a/tests/data/resources/pu-user1/apps/app2/test-cm1.yaml b/tests/data/resources/pu-user1/apps/app2/test-cm1.yaml new file mode 100644 index 0000000..13e7a56 --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app2/test-cm1.yaml @@ -0,0 +1,13 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: pu-user1-pa-app2 + name: test-cm1 +data: + key1: "value1" diff --git a/tests/data/resources/pu-user1/apps/app2/test-secret1.yaml b/tests/data/resources/pu-user1/apps/app2/test-secret1.yaml new file mode 100644 index 0000000..b3c36e5 --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app2/test-secret1.yaml @@ -0,0 +1,13 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: v1 +kind: Secret +metadata: + namespace: pu-user1-pa-app2 + name: test-secret1 +stringData: + secretKey1: "secretValue1" diff --git a/tests/data/resources/pu-user1/apps/app2/unsized-s3-box.yaml b/tests/data/resources/pu-user1/apps/app2/unsized-s3-box.yaml new file mode 100755 index 0000000..3e656bf --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app2/unsized-s3-box.yaml @@ -0,0 +1,18 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: DataBox +metadata: + name: unsized-s3-box + namespace: pu-user1-pa-app2 +spec: + s3Storage: + host: storage.yandexcloud.net + bucket: + name: test-app2-test + #capacity: 5G + awsVarsS3Credentials: app2-all-s3-boxes-cred \ No newline at end of file diff --git a/tests/data/resources/pu-user1/apps/app2/user-data-s3-box.yaml b/tests/data/resources/pu-user1/apps/app2/user-data-s3-box.yaml new file mode 100755 index 0000000..02fa9f8 --- /dev/null +++ b/tests/data/resources/pu-user1/apps/app2/user-data-s3-box.yaml @@ -0,0 +1,18 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: DataBox +metadata: + name: test-app2-user-data + namespace: pu-user1-pa-app2 +spec: + s3Storage: + host: storage.yandexcloud.net + bucket: + name: test-app2-user-data + #subPath: test + awsVarsS3Credentials: app2-all-s3-boxes-cred \ No newline at end of file diff --git a/tests/data/resources/pu-user1/user/apis/README.md b/tests/data/resources/pu-user1/user/apis/README.md new file mode 100644 index 0000000..399ad3e --- /dev/null +++ b/tests/data/resources/pu-user1/user/apis/README.md @@ -0,0 +1,6 @@ +Basic auth secret + +htpasswd -c auth user +htpasswd auth developer + +kubectl create secret generic basic-auth-credentials -n pu-user1 --from-file=auth \ No newline at end of file diff --git a/tests/data/resources/pu-user1/user/apps/app1.yaml b/tests/data/resources/pu-user1/user/apps/app1.yaml new file mode 100644 index 0000000..1fd2064 --- /dev/null +++ b/tests/data/resources/pu-user1/user/apps/app1.yaml @@ -0,0 +1,45 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: PlatformApp +metadata: + name: pu-user1-pa-app1 + namespace: pu-user1 +spec: + appSourceCode: + sourceRepositoryRef: + name: test-git-source-repository + sourceRepositoryKind: git + credentialsKind: HTTPBasedURLCredentials + repositoryPath: app + revision: main + repositories: + - name: app1-docker-image-registry + imageRegistryRef: + name: test-docker-image-registry + imageKind: docker + credentialsKind: DockerConfigJsonCredentials + - name: app1-python-package-registry + packageRegistryRef: + name: test-python-package-registry + packageKind: python + credentialsKind: HTTPBasedURLCredentials + - name: app1-git-source-repository + sourceRepositoryRef: + name: test-git-source-repository + sourceRepositoryKind: git + credentialsKind: HTTPBasedURLCredentials + boxesCredentials: + - name: app1-all-s3-boxes + secretRef: + name: aws-vars-s3-credentials + apisCredentials: + - name: app1-apis + secretRef: + name: basic-auth-credentials + + diff --git a/tests/data/resources/pu-user1/user/apps/app2.yaml b/tests/data/resources/pu-user1/user/apps/app2.yaml new file mode 100644 index 0000000..f9a2332 --- /dev/null +++ b/tests/data/resources/pu-user1/user/apps/app2.yaml @@ -0,0 +1,45 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: PlatformApp +metadata: + name: pu-user1-pa-app2 + namespace: pu-user1 +spec: + appSourceCode: + sourceRepositoryRef: + name: test-git-source-repository + sourceRepositoryKind: git + credentialsKind: HTTPBasedURLCredentials + repositoryPath: app + revision: main + repositories: + - name: app2-docker-image-registry + imageRegistryRef: + name: test-docker-image-registry + imageKind: docker + credentialsKind: DockerConfigJsonCredentials + - name: app2-python-package-registry + packageRegistryRef: + name: test-python-package-registry + packageKind: python + credentialsKind: HTTPBasedURLCredentials + - name: app2-git-source-repository + sourceRepositoryRef: + name: test-git-source-repository + sourceRepositoryKind: git + credentialsKind: HTTPBasedURLCredentials + boxesCredentials: + - name: app2-all-s3-boxes + secretRef: + name: aws-vars-s3-credentials + apisCredentials: + - name: app2-apis-ba + secretRef: + name: basic-auth-credentials + + diff --git a/tests/data/resources/pu-user1/user/git_repository/git-http-based-url-credentials-secret.yaml.sample b/tests/data/resources/pu-user1/user/git_repository/git-http-based-url-credentials-secret.yaml.sample new file mode 100755 index 0000000..7821f65 --- /dev/null +++ b/tests/data/resources/pu-user1/user/git_repository/git-http-based-url-credentials-secret.yaml.sample @@ -0,0 +1,13 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: v1 +kind: Secret +metadata: + namespace: pu-user1 + name: git-http-based-url-credentials +data: + credentials: sample \ No newline at end of file diff --git a/tests/data/resources/pu-user1/user/git_repository/git-source-repository.yaml b/tests/data/resources/pu-user1/user/git_repository/git-source-repository.yaml new file mode 100755 index 0000000..97a8c53 --- /dev/null +++ b/tests/data/resources/pu-user1/user/git_repository/git-source-repository.yaml @@ -0,0 +1,15 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: Repository +metadata: + name: test-git-source-repository + namespace: pu-user1 +spec: + sourceRepository: + host: forgejo.platform-test.stratpro.hse.ru + gitHTTPBasedURLCredentials: git-http-based-url-credentials \ No newline at end of file diff --git a/tests/data/resources/pu-user1/user/image_registry/docker-config-json-credentials-secret.yaml.sample b/tests/data/resources/pu-user1/user/image_registry/docker-config-json-credentials-secret.yaml.sample new file mode 100755 index 0000000..dae6059 --- /dev/null +++ b/tests/data/resources/pu-user1/user/image_registry/docker-config-json-credentials-secret.yaml.sample @@ -0,0 +1,14 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: v1 +kind: Secret +metadata: + name: docker-config-json-credentials + namespace: pu-user1 +type: kubernetes.io/dockerconfigjson +data: + .dockerconfigjson: sample \ No newline at end of file diff --git a/tests/data/resources/pu-user1/user/image_registry/docker-image-registry.yaml b/tests/data/resources/pu-user1/user/image_registry/docker-image-registry.yaml new file mode 100755 index 0000000..63fd5cf --- /dev/null +++ b/tests/data/resources/pu-user1/user/image_registry/docker-image-registry.yaml @@ -0,0 +1,15 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: Repository +metadata: + name: test-docker-image-registry + namespace: pu-user1 +spec: + imageRegistry: + host: platform-reg.stratpro.hse.ru + dockerDockerConfigJsonCredentials: docker-config-json-credentials \ No newline at end of file diff --git a/tests/data/resources/pu-user1/user/links/ba-link1.yaml b/tests/data/resources/pu-user1/user/links/ba-link1.yaml new file mode 100644 index 0000000..7ba410c --- /dev/null +++ b/tests/data/resources/pu-user1/user/links/ba-link1.yaml @@ -0,0 +1,19 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2025 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: ComponentLink +metadata: + name: ba-link1 + namespace: pu-user1 +spec: + platformAppName: pu-user1-pa-app2 + targets: + - name: test-api7 + platformAppName: pu-user1-pa-app2 + basicAuth: {} + secretRef: + name: ba-secret1 diff --git a/tests/data/resources/pu-user1/user/links/ba-link2.yaml b/tests/data/resources/pu-user1/user/links/ba-link2.yaml new file mode 100644 index 0000000..44a53a3 --- /dev/null +++ b/tests/data/resources/pu-user1/user/links/ba-link2.yaml @@ -0,0 +1,19 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2025 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: ComponentLink +metadata: + name: ba-link2 + namespace: pu-user1 +spec: + platformAppName: pu-user1-pa-app2 + targets: + - name: test-api7 + platformAppName: pu-user1-pa-app2 + basicAuth: {} + secretRef: + name: ba-secret2 \ No newline at end of file diff --git a/tests/data/resources/pu-user1/user/links/ba-link3-dataset.yaml b/tests/data/resources/pu-user1/user/links/ba-link3-dataset.yaml new file mode 100644 index 0000000..03382af --- /dev/null +++ b/tests/data/resources/pu-user1/user/links/ba-link3-dataset.yaml @@ -0,0 +1,20 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2025 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: ComponentLink +metadata: + name: ba-link3 + namespace: pu-user1 +spec: + platformAppName: pu-user1-pa-app2 + targets: + - name: dataset1 + platformAppName: pu-user1-pa-app2 + kind: DatasetComponent + basicAuth: {} + secretRef: + name: ba-secret2 \ No newline at end of file diff --git a/tests/data/resources/pu-user1/user/links/config-link-robot-tokens.yaml b/tests/data/resources/pu-user1/user/links/config-link-robot-tokens.yaml new file mode 100644 index 0000000..7b529f5 --- /dev/null +++ b/tests/data/resources/pu-user1/user/links/config-link-robot-tokens.yaml @@ -0,0 +1,17 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: ComponentLink +metadata: + name: config-link-robot-tokens + namespace: pu-user1 +spec: + platformAppName: pu-user1-pa-app2 + config: {} + secretRef: + name: robot-keycloak-user-registry-robot1-cred + diff --git a/tests/data/resources/pu-user1/user/links/config-link1.yaml b/tests/data/resources/pu-user1/user/links/config-link1.yaml new file mode 100644 index 0000000..3b66805 --- /dev/null +++ b/tests/data/resources/pu-user1/user/links/config-link1.yaml @@ -0,0 +1,17 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: ComponentLink +metadata: + name: config-link1 + namespace: pu-user1 +spec: + platformAppName: pu-user1-pa-app2 + config: {} + secretRef: + name: config-secret1 + diff --git a/tests/data/resources/pu-user1/user/links/config-link2.yaml b/tests/data/resources/pu-user1/user/links/config-link2.yaml new file mode 100644 index 0000000..d921d8b --- /dev/null +++ b/tests/data/resources/pu-user1/user/links/config-link2.yaml @@ -0,0 +1,17 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: ComponentLink +metadata: + name: config-link2 + namespace: pu-user1 +spec: + platformAppName: pu-user1-pa-app2 + config: {} + secretRef: + name: config-secret1 + diff --git a/tests/data/resources/pu-user1/user/links/init-pass-secret-pod-test.yaml b/tests/data/resources/pu-user1/user/links/init-pass-secret-pod-test.yaml new file mode 100644 index 0000000..7b067f4 --- /dev/null +++ b/tests/data/resources/pu-user1/user/links/init-pass-secret-pod-test.yaml @@ -0,0 +1,32 @@ +apiVersion: v1 +kind: Pod +metadata: + name: init-pass-secret-pod + namespace: pu-user1-pa-app2 +spec: + initContainers: + - name: init + image: busybox:1.37.0 + volumeMounts: + - name: var-secret-volume + mountPath: /unip/var-secret + readOnly: true + - name: prepared-env-var-volume + mountPath: /unip/prepared-env-var + command: ['sh', '-c', 'echo -n "var=" > /unip/prepared-env-var/env-var && cat /unip/var-secret/var | paste -sd "," - >> /unip/prepared-env-var/env-var'] + containers: + - name: busybox + image: busybox:1.37.0 + command: ['sh', '-c', 'source <(grep "=" /unip/prepared-env-var/env-var) && /bin/sh -c "echo $var"'] + volumeMounts: + - name: prepared-env-var-volume + mountPath: /unip/prepared-env-var + restartPolicy: Never + volumes: + - name: var-secret-volume + secret: + secretName: var-secret + - name: prepared-env-var-volume + emptyDir: + sizeLimit: 10Mi + diff --git a/tests/data/resources/pu-user1/user/links/init-secret-test.yaml b/tests/data/resources/pu-user1/user/links/init-secret-test.yaml new file mode 100644 index 0000000..d881221 --- /dev/null +++ b/tests/data/resources/pu-user1/user/links/init-secret-test.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: Secret +metadata: + name: var-secret + namespace: pu-user1-pa-app2 +stringData: + var: |- + val1 + val2 diff --git a/tests/data/resources/pu-user1/user/links/kg-link1.yaml b/tests/data/resources/pu-user1/user/links/kg-link1.yaml new file mode 100644 index 0000000..131fe20 --- /dev/null +++ b/tests/data/resources/pu-user1/user/links/kg-link1.yaml @@ -0,0 +1,21 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2025 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: ComponentLink +metadata: + name: kg-link1 + namespace: pu-user1 +spec: + platformAppName: pu-user1-pa-app2 + targets: + - name: test-api7 + platformAppName: pu-user1-pa-app2 + keycloakGroup: + userRegistryRef: + name: test-keycloak-user-registry + secretRef: + name: kg-secret2 diff --git a/tests/data/resources/pu-user1/user/links/kg-link2-dataset.yaml b/tests/data/resources/pu-user1/user/links/kg-link2-dataset.yaml new file mode 100644 index 0000000..3baa281 --- /dev/null +++ b/tests/data/resources/pu-user1/user/links/kg-link2-dataset.yaml @@ -0,0 +1,22 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2025 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: ComponentLink +metadata: + name: kg-link2 + namespace: pu-user1 +spec: + platformAppName: pu-user1-pa-app2 + targets: + - name: dataset1 + platformAppName: pu-user1-pa-app2 + kind: DatasetComponent + keycloakGroup: + userRegistryRef: + name: test-keycloak-user-registry + secretRef: + name: kg-secret1 \ No newline at end of file diff --git a/tests/data/resources/pu-user1/user/links/kg-secret1.yaml b/tests/data/resources/pu-user1/user/links/kg-secret1.yaml new file mode 100644 index 0000000..061e9cb --- /dev/null +++ b/tests/data/resources/pu-user1/user/links/kg-secret1.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Secret +metadata: + namespace: pu-user1 + name: kg-secret1 +stringData: + # end-user1@platform-test.stratpro.hse.ru + emails: |- + emaildoesntexist + end-user1@platform-test.stratpro.hse.ru + usernames: |- + usernamedoesntexist + end-user2 + end-user + test-user + robots: |- + robot1 + robotdoesntexist diff --git a/tests/data/resources/pu-user1/user/links/kg-secret2.yaml b/tests/data/resources/pu-user1/user/links/kg-secret2.yaml new file mode 100644 index 0000000..6949b49 --- /dev/null +++ b/tests/data/resources/pu-user1/user/links/kg-secret2.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Secret +metadata: + namespace: pu-user1 + name: kg-secret2 +stringData: + # end-user2@platform-test.stratpro.hse.ru + emails: |- + end-user1@platform-test.stratpro.hse.ru + emaildoesntexist + # end-user2 + usernames: |- + end-user + usernamedoesntexist + robots: |- + robot1 + robotdoesntexist + robot2 \ No newline at end of file diff --git a/tests/data/resources/pu-user1/user/links/test-deployment.yaml b/tests/data/resources/pu-user1/user/links/test-deployment.yaml new file mode 100644 index 0000000..961fd7b --- /dev/null +++ b/tests/data/resources/pu-user1/user/links/test-deployment.yaml @@ -0,0 +1,28 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: test-deployment + namespace: pu-user1-pa-app2 + labels: + app: test +spec: + replicas: 1 + selector: + matchLabels: + app: test-nginx + template: + metadata: + labels: + app: test-nginx + spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 \ No newline at end of file diff --git a/tests/data/resources/pu-user1/user/links/test-ingress.yaml b/tests/data/resources/pu-user1/user/links/test-ingress.yaml new file mode 100644 index 0000000..9bfd8b9 --- /dev/null +++ b/tests/data/resources/pu-user1/user/links/test-ingress.yaml @@ -0,0 +1,39 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: test-ingress + namespace: pu-user1-pa-app2 + annotations: + nginx.ingress.kubernetes.io/auth-type: basic + #nginx.ingress.kubernetes.io/auth-secret: api-cmp1-joint-cred + nginx.ingress.kubernetes.io/auth-secret: app1-apis-cred + nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required - pu-user1-pa-app1-user' + nginx.ingress.kubernetes.io/rewrite-target: / + nginx.ingress.kubernetes.io/configuration-snippet: | + proxy_set_header X-User-Id $http_authorization; + proxy_pass_header X-User-Id; + proxy_set_header Authorization $http_authorization; + proxy_pass_header Authorization; + proxy_pass_header Content-Type; +spec: + ingressClassName: nginx + tls: + - hosts: + - platform-dev-cs-hse.objectoriented.ru + rules: + - host: platform-dev-cs-hse.objectoriented.ru + http: + paths: + - path: /pu-user1-pa-app1/test + pathType: ImplementationSpecific + backend: + service: + name: test-svc + port: + number: 80 diff --git a/tests/data/resources/pu-user1/user/links/test-svc.yaml b/tests/data/resources/pu-user1/user/links/test-svc.yaml new file mode 100644 index 0000000..4f09863 --- /dev/null +++ b/tests/data/resources/pu-user1/user/links/test-svc.yaml @@ -0,0 +1,19 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: v1 +kind: Service +metadata: + name: test-svc + namespace: pu-user1-pa-app2 +spec: + type: ClusterIP + selector: + app: test-nginx + ports: + - protocol: TCP + port: 80 + targetPort: 80 \ No newline at end of file diff --git a/tests/data/resources/pu-user1/user/pu-user1.yaml b/tests/data/resources/pu-user1/user/pu-user1.yaml new file mode 100644 index 0000000..43f3d7c --- /dev/null +++ b/tests/data/resources/pu-user1/user/pu-user1.yaml @@ -0,0 +1,11 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: PlatformUser +metadata: + name: pu-user1 + namespace: unip-app-platform-users \ No newline at end of file diff --git a/tests/data/resources/pu-user1/user/python_registry/python-http-based-url-credentials-secret.yaml.sample b/tests/data/resources/pu-user1/user/python_registry/python-http-based-url-credentials-secret.yaml.sample new file mode 100755 index 0000000..2821889 --- /dev/null +++ b/tests/data/resources/pu-user1/user/python_registry/python-http-based-url-credentials-secret.yaml.sample @@ -0,0 +1,13 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: v1 +kind: Secret +metadata: + namespace: pu-user1 + name: python-http-based-url-credentials +data: + credentials: sample \ No newline at end of file diff --git a/tests/data/resources/pu-user1/user/python_registry/python-package-registry.yaml b/tests/data/resources/pu-user1/user/python_registry/python-package-registry.yaml new file mode 100755 index 0000000..b63eddb --- /dev/null +++ b/tests/data/resources/pu-user1/user/python_registry/python-package-registry.yaml @@ -0,0 +1,15 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: Repository +metadata: + name: test-python-package-registry + namespace: pu-user1 +spec: + packageRegistry: + host: forgejo.platform-test.stratpro.hse.ru + pythonHTTPBasedURLCredentials: python-http-based-url-credentials \ No newline at end of file diff --git a/tests/data/resources/pu-user1/user/s3_storage/aws-vars-s3-credentials-secret.yaml.sample b/tests/data/resources/pu-user1/user/s3_storage/aws-vars-s3-credentials-secret.yaml.sample new file mode 100755 index 0000000..250af65 --- /dev/null +++ b/tests/data/resources/pu-user1/user/s3_storage/aws-vars-s3-credentials-secret.yaml.sample @@ -0,0 +1,15 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: v1 +kind: Secret +metadata: + name: aws-vars-s3-credentials + namespace: pu-user1 +type: Opaque +stringData: + AWS_ACCESS_KEY_ID: sample + AWS_SECRET_ACCESS_KEY: sample \ No newline at end of file diff --git a/tests/data/resources/pu-user1/user/s3_storage/csi-s3-secret.yaml.sample b/tests/data/resources/pu-user1/user/s3_storage/csi-s3-secret.yaml.sample new file mode 100644 index 0000000..70401cf --- /dev/null +++ b/tests/data/resources/pu-user1/user/s3_storage/csi-s3-secret.yaml.sample @@ -0,0 +1,18 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +apiVersion: v1 +kind: Secret +metadata: + namespace: pu-user1 + name: csi-s3-secret +stringData: + accessKeyID: sample + secretAccessKey: sample + # For AWS set it to "https://s3..amazonaws.com", for example https://s3.eu-central-1.amazonaws.com + endpoint: https://storage.yandexcloud.net + # For AWS set it to AWS region + # region: "" diff --git a/tests/data/resources/pu-user1/user/s3_storage/sc.yaml b/tests/data/resources/pu-user1/user/s3_storage/sc.yaml new file mode 100644 index 0000000..7d10ed3 --- /dev/null +++ b/tests/data/resources/pu-user1/user/s3_storage/sc.yaml @@ -0,0 +1,25 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2024 г. +# ============================================================ +kind: StorageClass +apiVersion: storage.k8s.io/v1 +metadata: + name: pu-user1-csi-s3-sc +provisioner: ru.yandex.s3.csi +parameters: + mounter: geesefs + # you can set mount options here, for example limit memory cache size (recommended) + # options: "--memory-limit 1000 --dir-mode 0777 --file-mode 0666" + # to use an existing bucket, specify it here: + # bucket: cloud-platform-dev-gc6d85hf + csi.storage.k8s.io/provisioner-secret-name: csi-s3-secret + csi.storage.k8s.io/provisioner-secret-namespace: pu-user1 + csi.storage.k8s.io/controller-publish-secret-name: csi-s3-secret + csi.storage.k8s.io/controller-publish-secret-namespace: pu-user1 + csi.storage.k8s.io/node-stage-secret-name: csi-s3-secret + csi.storage.k8s.io/node-stage-secret-namespace: pu-user1 + csi.storage.k8s.io/node-publish-secret-name: csi-s3-secret + csi.storage.k8s.io/node-publish-secret-namespace: pu-user1 \ No newline at end of file diff --git a/tests/data/resources/pu-user1/user/user_registry/keycloak-user-registry.yaml b/tests/data/resources/pu-user1/user/user_registry/keycloak-user-registry.yaml new file mode 100755 index 0000000..e0ef20e --- /dev/null +++ b/tests/data/resources/pu-user1/user/user_registry/keycloak-user-registry.yaml @@ -0,0 +1,18 @@ +# ============================================================ +# Система: Единая библиотека, Центр ИИ НИУ ВШЭ +# Модуль: Тесты +# Авторы: Полежаев В.А., Хританков А.С. +# Дата создания: 2025 г. +# ============================================================ +apiVersion: "unified-platform.cs.hse.ru/v1" +kind: Repository +metadata: + name: test-keycloak-user-registry + namespace: pu-user1 +spec: + userRegistry: + host: sso.platform-test.stratpro.hse.ru + keycloak: + robots: + secretRef: + name: reg-secret1 diff --git a/tests/data/resources/pu-user1/user/user_registry/reg-secret1.yaml b/tests/data/resources/pu-user1/user/user_registry/reg-secret1.yaml new file mode 100644 index 0000000..83011fe --- /dev/null +++ b/tests/data/resources/pu-user1/user/user_registry/reg-secret1.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: Secret +metadata: + namespace: pu-user1 + name: reg-secret1 +stringData: + robots: |- + robot1 + robot2 diff --git a/tests/integration/openapi/gen_spec.md b/tests/integration/openapi/gen_spec.md new file mode 100644 index 0000000..8828dd1 --- /dev/null +++ b/tests/integration/openapi/gen_spec.md @@ -0,0 +1,5 @@ +workdir: . + +```shell +python -m ./controller/src/exp_pipeline/openapi.py ./tests/data/resources/pu-user1/apps/app2/exp-pipeline10.yaml ./dev/openapi.json +``` \ No newline at end of file diff --git a/tests/integration/requests/app1/files_complete_tests.md b/tests/integration/requests/app1/files_complete_tests.md new file mode 100644 index 0000000..6d72f39 --- /dev/null +++ b/tests/integration/requests/app1/files_complete_tests.md @@ -0,0 +1,111 @@ +--- +**Система**: Единая библиотека, Центр ИИ НИУ ВШЭ + +**Модуль**: Тесты + +**Авторы**: Полежаев В.А., Хританков А.С. + +**Дата создания**: 2024 г. + +--- + +# POST + +### Пустая локация (/) + +curl -X POST https:///pu-user1-pa-app1/files/test-app1-user-data/ -u "1-2-3:**" + +Создаст пустой файл со сгенерированным именем в файловой группе со сгенерированным именем. + +### Простая локация, на конце '/' ('/test-group3/') + +curl -X POST https:///pu-user1-pa-app1/files/test-app1-user-data/test-group3/ -u "1-2-3:**" + +Создаст пустой файл со сгенерированным именем, даже если файловые группы по пути отсутствуют. + +### Сложная локация, на конце '/' ('/test-group3/inner-group/') + +curl -X POST https:///pu-user1-pa-app1/files/test-app1-user-data/test-group3/inner-group/ -u "1-2-3:**" + +Создаст пустой файл со сгенерированным именем, даже если файловые группы по пути отсутствуют. + +### Простая локация, без '/' на конце ('/test-group3') + +curl -X POST https:///pu-user1-pa-app1/files/test-app1-user-data/test-group3 -u "1-2-3:**" + +Считает, что /test-group3 это то же, что /test-group3/. + +### Сложная локация, без '/' на конце ('/test-group3/inner') + +curl -X POST https:///pu-user1-pa-app1/files/test-app1-user-data/test-group3/inner -u "1-2-3:**" + +Ошибка неподдерживаемый формат локации. + +# GET + +### Пустая локация (/) + +curl -X GET https:///pu-user1-pa-app1/files/test-app1-user-data/ -u "1-2-3:**" + +Ошибка локация не указана + +### Простая локация, на конце '/' ('/test-group3/') + +curl -X GET https:///pu-user1-pa-app1/files/test-app1-user-data/test-group3/ -u "1-2-3:**" + +Возвращает содержимое fg - только файлы в этой папке, без вложенности. +И игнорируя вложенные объекты-папки, пустые или с содержимым. + +Если пустая папка - возвращается пустой список файлов. + +Если локации нет - возвращается 404. + +### Простая локация, без '/' на конце ('/test-group3') + +curl -X GET https:///pu-user1-pa-app1/files/test-app1-user-data/test-group3 -u "1-2-3:**" + +Считает, что /test-group3 это то же, что /test-group3/. + +Возвращает содержимое fg - только файлы в этой папке, аналогично выше. + +### Сложная локация, без '/' на конце ('/test-group3/test-file1') + +curl -X GET https:///pu-user1-pa-app1/files/test-app1-user-data/test-group3/test-file2 -u "1-2-3:**" + +Возвращает файл test-file1, если он есть. Иначе 404. + +# PUT + +### Пустая локация (/) + +curl -X PUT https:///pu-user1-pa-app1/files/test-app1-user-data/ -u "1-2-3:**" + +Ошибка локация не указана + +### Простая локация, на конце '/' ('/test-group3/') + +curl -X PUT https:///pu-user1-pa-app1/files/test-app1-user-data/test-group3/ -u "1-2-3:**" + +Если отсутвует fg, создает новую пустую fg. Иначе ничего не делает. + +Возвращает fg с содержимым (пустой список файлов для новой fg), аналогично GET. + +### Сложная локация, на конце '/' ('/test-group3/test-inner1/') + +curl -X PUT https:///pu-user1-pa-app1/files/test-app1-user-data/test-group3/test-inner1/ -u "1-2-3:**" + +Аналогично. + +### Простая локация, без '/' на конце ('/test-group3') + +curl -X PUT https:///pu-user1-pa-app1/files/test-app1-user-data/test-group5 -u "1-2-3:**" + +Считает, что /test-group5 это то же, что /test-group5/. + +Аналогично выше. + +### Сложная локация, без '/' на конце ('/test-group3/not-created') + +curl -X PUT https:///pu-user1-pa-app1/files/test-app1-user-data/test-group3/not-created -u "1-2-3:**" + +Считает файлом, но не создает пустой файл, а только формирует pre-signed url. \ No newline at end of file diff --git a/tests/integration/requests/app2/data/data-typed-bad.json b/tests/integration/requests/app2/data/data-typed-bad.json new file mode 100644 index 0000000..aba8539 --- /dev/null +++ b/tests/integration/requests/app2/data/data-typed-bad.json @@ -0,0 +1,34 @@ +{ + "inputs": [ + { + "name": "input1", + "data": [11, 21, 31, 41, 51, 61, 71, 81], + "datatype": "FP32", + "shape": [2, 4] + }, + { + "name": "input2", + "data": "test-group21", + "datatype": "FILE", + "shape": 123, + "content_type": "BED" + }, + { + "name": "input3", + "data": "test-group23", + "datatype": "FILE", + "shape": 123, + "content_type": "CustomType" + } + ], + "output_vars": [ + { + "name": "output1", + "data": "test-group1", + "content_type": "PDB" + }, + { + "name": "wrong_output" + } + ] +} \ No newline at end of file diff --git a/tests/integration/requests/app2/data/data-typed-bad2.json b/tests/integration/requests/app2/data/data-typed-bad2.json new file mode 100644 index 0000000..df995d0 --- /dev/null +++ b/tests/integration/requests/app2/data/data-typed-bad2.json @@ -0,0 +1,31 @@ +{ + "inputs": [ + { + "name": "input1", + "data": [11, 21, 31, 41, 51, 61, 71, 81], + "datatype": "FP32", + "shape": [2, 4] + }, + { + "name": "input2", + "data": "test-group21", + "datatype": "FILE", + "shape": 123, + "content_type": "WrongType" + }, + { + "name": "input3", + "data": "test-group23", + "datatype": "FILE", + "shape": 123, + "content_type": "CustomType" + } + ], + "output_vars": [ + { + "name": "output1", + "data": "test-group1", + "content_type": "PDB" + } + ] +} \ No newline at end of file diff --git a/tests/integration/requests/app2/data/data-typed-bad3.json b/tests/integration/requests/app2/data/data-typed-bad3.json new file mode 100644 index 0000000..56db975 --- /dev/null +++ b/tests/integration/requests/app2/data/data-typed-bad3.json @@ -0,0 +1,30 @@ +{ + "inputs": [ + { + "name": "input1", + "data": "website", + "datatype": "WEBSITE", + "shape": 123 + }, + { + "name": "input2", + "data": "test-group21", + "datatype": "WEBSITE", + "shape": 123, + "content_type": "BED" + }, + { + "name": "input3", + "data": "test-group23", + "datatype": "WEBSITE", + "shape": 123 + } + ], + "output_vars": [ + { + "name": "output1", + "data": "test-group1", + "datatype": "WEBSITE" + } + ] +} \ No newline at end of file diff --git a/tests/integration/requests/app2/data/data-typed.json b/tests/integration/requests/app2/data/data-typed.json new file mode 100644 index 0000000..ee91d07 --- /dev/null +++ b/tests/integration/requests/app2/data/data-typed.json @@ -0,0 +1,31 @@ +{ + "inputs": [ + { + "name": "input1", + "data": [11, 21, 31, 41, 51, 61, 71, 81], + "datatype": "FP32", + "shape": [2, 4] + }, + { + "name": "input2", + "data": "test-group21", + "datatype": "FILE", + "shape": 123, + "content_type": "BED" + }, + { + "name": "input3", + "data": "test-group23", + "datatype": "FILE", + "shape": 123, + "content_type": "CustomType" + } + ], + "output_vars": [ + { + "name": "output1", + "data": "test-group1", + "content_type": "PDB" + } + ] +} \ No newline at end of file diff --git a/tests/integration/requests/app2/data/data.json b/tests/integration/requests/app2/data/data.json new file mode 100644 index 0000000..91bb653 --- /dev/null +++ b/tests/integration/requests/app2/data/data.json @@ -0,0 +1,27 @@ +{ + "inputs": [ + { + "name": "input1", + "data": "test-group21", + "datatype": "FILE", + "shape": 49, + "content_type": "text/csv" + }, + { + "name": "input2", + "data": "test-group21/file22", + "datatype": "FILE", + "shape": 49, + "content_type": "text/csv" + } + ], + "output_vars": [ + { + "name": "output1", + "data": "test-group1" + }, + { + "name": "output2" + } + ] +} \ No newline at end of file diff --git a/tests/integration/requests/app2/data/data1.json b/tests/integration/requests/app2/data/data1.json new file mode 100644 index 0000000..27c2d92 --- /dev/null +++ b/tests/integration/requests/app2/data/data1.json @@ -0,0 +1,26 @@ +{ + "inputs": [ + { + "name": "input1", + "data": "test-group21", + "datatype": "FILE", + "shape": 49, + "content_type": "text/csv" + }, + { + "name": "input2", + "data": [1, 2, 3, 4, 5, 6, 7, 8], + "datatype": "FP32", + "shape": [2, 4] + } + ], + "output_vars": [ + { + "name": "output1", + "data": "test-group1" + }, + { + "name": "output2" + } + ] +} \ No newline at end of file diff --git a/tests/integration/requests/app2/data/data11.json b/tests/integration/requests/app2/data/data11.json new file mode 100644 index 0000000..ac4bb45 --- /dev/null +++ b/tests/integration/requests/app2/data/data11.json @@ -0,0 +1,34 @@ +{ + "inputs": [ + { + "name": "input1", + "data": "test-group21", + "datatype": "FILE", + "shape": 49, + "content_type": "text/csv" + }, + { + "name": "input2", + "data": "test-group21/file22", + "datatype": "FILE", + "shape": 49, + "content_type": "text/csv" + }, + { + "name": "input3", + "data": "test-group21/file22", + "datatype": "FILE", + "shape": 49, + "content_type": "text/csv" + } + ], + "output_vars": [ + { + "name": "output1", + "data": "test-group1" + }, + { + "name": "output2" + } + ] +} \ No newline at end of file diff --git a/tests/integration/requests/app2/data/data112.json b/tests/integration/requests/app2/data/data112.json new file mode 100644 index 0000000..3a24436 --- /dev/null +++ b/tests/integration/requests/app2/data/data112.json @@ -0,0 +1,31 @@ +{ + "inputs": [ + { + "name": "input1", + "data": [11, 21, 31, 41, 51, 61, 71, 81], + "datatype": "FP32", + "shape": [2, 4] + }, + { + "name": "input2", + "data": [1, 2, 3, 4, 5, 6, 7, 8], + "datatype": "FP32", + "shape": [2, 4] + }, + { + "name": "input3", + "data": [31, 32, 33, 34, 35, 36, 37, 38], + "datatype": "FP32", + "shape": [2, 4] + } + ], + "output_vars": [ + { + "name": "output1", + "data": "test-group1" + }, + { + "name": "output2" + } + ] +} \ No newline at end of file diff --git a/tests/integration/requests/app2/data/data2.json b/tests/integration/requests/app2/data/data2.json new file mode 100644 index 0000000..7b8bf2e --- /dev/null +++ b/tests/integration/requests/app2/data/data2.json @@ -0,0 +1,25 @@ +{ + "inputs": [ + { + "name": "input1", + "data": [11, 21, 31, 41, 51, 61, 71, 81], + "datatype": "FP32", + "shape": [2, 4] + }, + { + "name": "input2", + "data": [1, 2, 3, 4, 5, 6, 7, 8], + "datatype": "FP32", + "shape": [2, 4] + } + ], + "output_vars": [ + { + "name": "output1", + "data": "test-group1" + }, + { + "name": "output2" + } + ] +} \ No newline at end of file diff --git a/tests/integration/requests/app2/data/some_data.csv b/tests/integration/requests/app2/data/some_data.csv new file mode 100644 index 0000000..ccdaa62 --- /dev/null +++ b/tests/integration/requests/app2/data/some_data.csv @@ -0,0 +1,5 @@ +x,y,z +5.0,2.0,3.0 +5.0,2.0,3.0 +5.0,2.0,3.0 +5.0,2.0,3.0 \ No newline at end of file diff --git a/tests/integration/requests/app2/data/status-condition.json b/tests/integration/requests/app2/data/status-condition.json new file mode 100644 index 0000000..78bde7a --- /dev/null +++ b/tests/integration/requests/app2/data/status-condition.json @@ -0,0 +1,7 @@ +{ + "type": "SomeStatus", + "message": "msg", + "reason": "rsn", + "transition_time": "2024-11-06T16:48:30.814147+0300", + "stage": "Stage" +} \ No newline at end of file diff --git a/tests/integration/requests/app2/readme.md b/tests/integration/requests/app2/readme.md new file mode 100644 index 0000000..023d610 --- /dev/null +++ b/tests/integration/requests/app2/readme.md @@ -0,0 +1,163 @@ +--- +**Система**: Единая библиотека, Центр ИИ НИУ ВШЭ + +**Модуль**: Тесты + +**Авторы**: Полежаев В.А., Хританков А.С. + +**Дата создания**: 2024 г. + +--- + + +# Ручное тестирование пайплайнов + +## Используемые данные + +Ресурсы тестового приложения находятся в папке `tests/data/resources/pu-user1/apps/app2`. + +Используется тестовый пользователь `pu-user1` +(ресурсы пользователя см. в папке `tests/data/resources/pu-user1`). + +Запросы и данные запросов находятся в папке `tests/integration/requests/test_app2`. + +1. Приложение pu-user1-pa-app2 пользователя pu-user1 c размещенным APIComponent для Pipelines API, Files API. + См. api-pipelines.yaml, api-files.yaml. + +2. Пайплайны. См. exp-pipeline6.yaml и остальные ресурсы пайплайнов в файлах с маской exp-pipeline*.yaml. + +## Пайплайны + +### test-ep6 (exp-pipeline6.yaml) + +Базовый тестовый пайплайн с одним этапом. + +Для этого пайплайна есть два манифеста интерфесов APIComponent с OIDC аутентификацией: +- api-cmp6-oidc.yaml (OIDC) +- api-cmp6-oidc-ba.yaml (OIDC, Basic) + +### test-ep7 (exp-pipeline7.yaml) + +Особенности: +- Повторяет логику test-ep6, но для переменных пути и ящики используются по умолчанию; + +### test-ep8, test-ep9 (exp-pipeline8.yaml, exp-pipeline9.yaml) + +Особенности: +- Пайплайны связаны в цепочку, test-ep8 вызывает test-ep9. + +### test-ep10 (exp-pipeline10.yaml) + +Особенности: +- Включает спецификацию типов входных и выходных переменных; + +## Данные запросов + +### data.json, data1.json, data2.json + +Отражают все основные виды входов: +- только файловый вход (data.json) +- файловый и объектный вход (data1.json) +- только объектный вход (data2.json) + +Виды выходов: +- заданная файловая группа (все файлы) +- файловая группа не задана, будет создана временная файловая группа (все файлы) + +Для использования data.json необходимо предварительно загрузить содержимое файла +test-group21/file22. + +Данные data.json, data1.json, data2.json применимы для тестирования пайплайнов: +- test-ep6 +- test-ep7 +- test-ep12 + +Данные data2.json применимы для тестирования пайплайнов: +- test-ep8 и test-ep9 + +### data-typed.json, data-typed-bad.json, data-typed-bad2.json + +Включают корректные и некорректные относительно спецификации типов входов и выходов +типы данных и типы содержимого. + +Данные применимы для тестирования пайплайнов: +- test-ep10 + +### data11.json, data112.json + +Аналогичны data.json и data2.json соответственно. + +Данные применимы для тестирования пайплайнов: +- test-ep11 + +### Тестовые данные + +Файл some_data.csv можно использовать в качестве тестового файлового входа +(файл может быть загружен через Files API). + +## Запросы + +### Старт триала + +curl -X POST https:///pu-user1-pa-app2/pipelines/test-ep6/trials \ +-d @./data/data.json -H "Content-Type: application/json" -u "developer:" + +### Добавить условие статуса + +curl -X POST https:///pu-user1-pa--app2/pipelines/test-ep6/trials//status/conditions \ +-d @./data/status-condition.json -H "Content-Type: application/json" -u "developer:" + +### Получить триалы + +Один: + +url -X GET https:///pu-user1-pa-app2/trials/6bc5dfee-aeae-4269-8982-abf0fcfa3c65 \ +-u "developer:" + +Все триалы пайплайна: + +curl -X GET https:///pu-user1-pa-app2/pipelines/test-ep6/trials \ +-u "developer:" + +Все триалы пользователя: + +curl -X GET https:///pu-user1-pa-app2/trials \ +-u "developer:" + +### Получить пайплайны + +curl -X GET https:///pu-user1-pa-app2/pipelines/test-ep6 \ +-u "developer:" + +curl -X GET https:///pu-user1-pa-app2/pipelines/test-ep6/version \ +-u "developer:" + +curl -X GET https:///pu-user1-pa-app2/pipelines \ +-u "developer:" + +### Загрузка файла some-data.csv (при необходимости) + +curl -X PUT https:///pu-user1-pa-app2/files/test-app2-user-data/test-group21/file22 \ +-u "developer:" + +curl -X PUT -d @./data/some_data.csv "" + +### OIDC аутентификация + +Получить токен для OIDC аутентификации: + +curl -L -X POST https:///keycloak/realms/master/protocol/openid-connect/token \ +--data-urlencode 'client_id=dev-multi-auth' \ +--data-urlencode 'grant_type=password' \ +--data-urlencode 'username=test-multi-auth' \ +--data-urlencode 'password=' + +dev-multi-auth - имя клиента Keycloak, test-multi-auth - имя пользователя. + +Использовать токен в запросах: + +(например, для получения списка пайплайнов) + +curl -X GET https:///pu-user1-pa-app2/pipelines \ +-L \ +-H "Authorization: Bearer " \ No newline at end of file diff --git a/tests/integration/requests/app2/resources_test.md b/tests/integration/requests/app2/resources_test.md new file mode 100644 index 0000000..30cfb76 --- /dev/null +++ b/tests/integration/requests/app2/resources_test.md @@ -0,0 +1,25 @@ +--- +**Система**: Единая библиотека, Центр ИИ НИУ ВШЭ + +**Модуль**: Тесты + +**Авторы**: Полежаев В.А., Хританков А.С. + +**Дата создания**: 2024 г. + +--- + +# Подходящие пайплайны + +test-ep12 + +# Добавление лейблов и тейнов к узлам + +kubectl get nodes --show-labels + +kubectl label nodes node.unified-platform.cs.hse.ru/resources.gpu=true +kubectl label nodes node.unified-platform.cs.hse.ru/resources.gpu- + +kubectl taint nodes node.unified-platform.cs.hse.ru/is-gpu-available=true:NoSchedule +kubectl taint nodes node.unified-platform.cs.hse.ru/is-gpu-available=true:NoSchedule- + diff --git a/tests/integration/requests/app2/validate_results.md b/tests/integration/requests/app2/validate_results.md new file mode 100644 index 0000000..7a82081 --- /dev/null +++ b/tests/integration/requests/app2/validate_results.md @@ -0,0 +1,27 @@ +--- +**Система**: Единая библиотека, Центр ИИ НИУ ВШЭ + +**Модуль**: Тесты + +**Авторы**: Полежаев В.А., Хританков А.С. + +**Дата создания**: 2024 г. + +--- + +(только для отладки с локальным сервисом API и UNIP_PIPELINE_RUN_MODE=Debug, +при развернутом сервисе API валидацию результатов осуществляет контейнер Job; +при этом локальные пути будут отличаться от путей внутри контейнера валидации, +поэтому проверка без изменений логики всегда будет завершаться неудачей) + + +```shell +source ./controller/venv/bin/activate + +export PYTHONPATH=$PYTHONPATH:./contoller/src +export UNIP_PIPELINE_API=http://localhost:8001 +export UNIP_TRACKING_ID= + +python3 -m exp_pipeline.results.validate_trial_results +``` +