Showing preview only (2,328K chars total). Download the full file or copy to clipboard to get everything.
Repository: ipsingh06/seedsync
Branch: master
Commit: ff2a1039935b
Files: 337
Total size: 2.1 MB
Directory structure:
gitextract_tfp7f5p4/
├── .github/
│ └── workflows/
│ └── master.yml
├── .gitignore
├── LICENSE.txt
├── Makefile
├── README.md
├── doc/
│ ├── CodingGuidelines.md
│ ├── DeveloperReadme.md
│ └── assets/
│ ├── logo.ai
│ └── logo_with_name.ai
└── src/
├── angular/
│ ├── .angular-cli.json
│ ├── .editorconfig
│ ├── .gitignore
│ ├── e2e/
│ │ ├── app.e2e-spec.ts
│ │ ├── app.po.ts
│ │ └── tsconfig.e2e.json
│ ├── karma.conf.js
│ ├── package.json
│ ├── protractor.conf.js
│ ├── src/
│ │ ├── app/
│ │ │ ├── app.module.ts
│ │ │ ├── common/
│ │ │ │ ├── _common.scss
│ │ │ │ ├── cached-reuse-strategy.ts
│ │ │ │ ├── capitalize.pipe.ts
│ │ │ │ ├── click-stop-propagation.directive.ts
│ │ │ │ ├── eta.pipe.ts
│ │ │ │ ├── file-size.pipe.ts
│ │ │ │ ├── localization.ts
│ │ │ │ └── storage-keys.ts
│ │ │ ├── pages/
│ │ │ │ ├── about/
│ │ │ │ │ ├── about-page.component.html
│ │ │ │ │ ├── about-page.component.scss
│ │ │ │ │ └── about-page.component.ts
│ │ │ │ ├── autoqueue/
│ │ │ │ │ ├── autoqueue-page.component.html
│ │ │ │ │ ├── autoqueue-page.component.scss
│ │ │ │ │ └── autoqueue-page.component.ts
│ │ │ │ ├── files/
│ │ │ │ │ ├── file-list.component.html
│ │ │ │ │ ├── file-list.component.scss
│ │ │ │ │ ├── file-list.component.ts
│ │ │ │ │ ├── file-options.component.html
│ │ │ │ │ ├── file-options.component.scss
│ │ │ │ │ ├── file-options.component.ts
│ │ │ │ │ ├── file.component.html
│ │ │ │ │ ├── file.component.scss
│ │ │ │ │ ├── file.component.ts
│ │ │ │ │ ├── files-page.component.html
│ │ │ │ │ └── files-page.component.ts
│ │ │ │ ├── logs/
│ │ │ │ │ ├── logs-page.component.html
│ │ │ │ │ ├── logs-page.component.scss
│ │ │ │ │ └── logs-page.component.ts
│ │ │ │ ├── main/
│ │ │ │ │ ├── app.component.html
│ │ │ │ │ ├── app.component.scss
│ │ │ │ │ ├── app.component.ts
│ │ │ │ │ ├── header.component.html
│ │ │ │ │ ├── header.component.scss
│ │ │ │ │ ├── header.component.ts
│ │ │ │ │ ├── sidebar.component.html
│ │ │ │ │ ├── sidebar.component.scss
│ │ │ │ │ └── sidebar.component.ts
│ │ │ │ └── settings/
│ │ │ │ ├── option.component.html
│ │ │ │ ├── option.component.scss
│ │ │ │ ├── option.component.ts
│ │ │ │ ├── options-list.ts
│ │ │ │ ├── settings-page.component.html
│ │ │ │ ├── settings-page.component.scss
│ │ │ │ └── settings-page.component.ts
│ │ │ ├── routes.ts
│ │ │ ├── services/
│ │ │ │ ├── autoqueue/
│ │ │ │ │ ├── autoqueue-pattern.ts
│ │ │ │ │ └── autoqueue.service.ts
│ │ │ │ ├── base/
│ │ │ │ │ ├── base-stream.service.ts
│ │ │ │ │ ├── base-web.service.ts
│ │ │ │ │ └── stream-service.registry.ts
│ │ │ │ ├── files/
│ │ │ │ │ ├── mock-model-files.ts
│ │ │ │ │ ├── model-file.service.ts
│ │ │ │ │ ├── model-file.ts
│ │ │ │ │ ├── screenshot-model-files.ts
│ │ │ │ │ ├── view-file-filter.service.ts
│ │ │ │ │ ├── view-file-options.service.ts
│ │ │ │ │ ├── view-file-options.ts
│ │ │ │ │ ├── view-file-sort.service.ts
│ │ │ │ │ ├── view-file.service.ts
│ │ │ │ │ └── view-file.ts
│ │ │ │ ├── logs/
│ │ │ │ │ ├── log-record.ts
│ │ │ │ │ └── log.service.ts
│ │ │ │ ├── server/
│ │ │ │ │ ├── server-command.service.ts
│ │ │ │ │ ├── server-status.service.ts
│ │ │ │ │ └── server-status.ts
│ │ │ │ ├── settings/
│ │ │ │ │ ├── config.service.ts
│ │ │ │ │ └── config.ts
│ │ │ │ └── utils/
│ │ │ │ ├── connected.service.ts
│ │ │ │ ├── dom.service.ts
│ │ │ │ ├── logger.service.ts
│ │ │ │ ├── notification.service.ts
│ │ │ │ ├── notification.ts
│ │ │ │ ├── rest.service.ts
│ │ │ │ └── version-check.service.ts
│ │ │ └── tests/
│ │ │ ├── mocks/
│ │ │ │ ├── mock-event-source.ts
│ │ │ │ ├── mock-model-file.service.ts
│ │ │ │ ├── mock-rest.service.ts
│ │ │ │ ├── mock-storage.service.ts
│ │ │ │ ├── mock-stream-service.registry.ts
│ │ │ │ ├── mock-view-file-options.service.ts
│ │ │ │ └── mock-view-file.service.ts
│ │ │ └── unittests/
│ │ │ └── services/
│ │ │ ├── autoqueue/
│ │ │ │ └── autoqueue.service.spec.ts
│ │ │ ├── base/
│ │ │ │ ├── base-stream.service.spec.ts
│ │ │ │ ├── base-web.service.spec.ts
│ │ │ │ └── stream-service.registry.spec.ts
│ │ │ ├── files/
│ │ │ │ ├── model-file.service.spec.ts
│ │ │ │ ├── model-file.spec.ts
│ │ │ │ ├── view-file-filter.service.spec.ts
│ │ │ │ ├── view-file-options.service.spec.ts
│ │ │ │ ├── view-file-sort.service.spec.ts
│ │ │ │ └── view-file.service.spec.ts
│ │ │ ├── logs/
│ │ │ │ ├── log-record.spec.ts
│ │ │ │ └── log.service.spec.ts
│ │ │ ├── server/
│ │ │ │ ├── server-command.service.spec.ts
│ │ │ │ ├── server-status.service.spec.ts
│ │ │ │ └── server-status.spec.ts
│ │ │ ├── settings/
│ │ │ │ ├── config.service.spec.ts
│ │ │ │ └── config.spec.ts
│ │ │ └── utils/
│ │ │ ├── connected.service.spec.ts
│ │ │ ├── dom.service.spec.ts
│ │ │ ├── notification.service.spec.ts
│ │ │ ├── rest.service.spec.ts
│ │ │ └── version-check.service.spec.ts
│ │ ├── assets/
│ │ │ └── .gitkeep
│ │ ├── environments/
│ │ │ ├── environment.prod.ts
│ │ │ └── environment.ts
│ │ ├── index.html
│ │ ├── main.ts
│ │ ├── polyfills.ts
│ │ ├── styles.scss
│ │ ├── test.ts
│ │ ├── tsconfig.app.json
│ │ ├── tsconfig.spec.json
│ │ └── typings.d.ts
│ ├── tsconfig.json
│ └── tslint.json
├── debian/
│ ├── changelog
│ ├── compat
│ ├── config
│ ├── control
│ ├── postinst
│ ├── postrm
│ ├── rules
│ ├── seedsync.service
│ ├── source/
│ │ └── format
│ └── templates
├── docker/
│ ├── build/
│ │ ├── deb/
│ │ │ ├── Dockerfile
│ │ │ └── Dockerfile.dockerignore
│ │ └── docker-image/
│ │ ├── Dockerfile
│ │ ├── Dockerfile.dockerignore
│ │ ├── run_as_user
│ │ ├── scp
│ │ ├── setup_default_config.sh
│ │ └── ssh
│ ├── stage/
│ │ ├── deb/
│ │ │ ├── Dockerfile
│ │ │ ├── compose-ubu1604.yml
│ │ │ ├── compose-ubu1804.yml
│ │ │ ├── compose-ubu2004.yml
│ │ │ ├── compose.yml
│ │ │ ├── entrypoint.sh
│ │ │ ├── expect_seedsync.exp
│ │ │ ├── id_rsa
│ │ │ ├── id_rsa.pub
│ │ │ ├── install_seedsync.sh
│ │ │ └── ubuntu-systemd/
│ │ │ ├── ubuntu-16.04-systemd/
│ │ │ │ ├── Dockerfile
│ │ │ │ └── setup
│ │ │ ├── ubuntu-18.04-systemd/
│ │ │ │ ├── Dockerfile
│ │ │ │ └── setup
│ │ │ └── ubuntu-20.04-systemd/
│ │ │ ├── Dockerfile
│ │ │ └── setup
│ │ └── docker-image/
│ │ └── compose.yml
│ ├── test/
│ │ ├── angular/
│ │ │ ├── Dockerfile
│ │ │ └── compose.yml
│ │ ├── e2e/
│ │ │ ├── Dockerfile
│ │ │ ├── chrome/
│ │ │ │ └── Dockerfile
│ │ │ ├── compose-dev.yml
│ │ │ ├── compose.yml
│ │ │ ├── configure/
│ │ │ │ ├── Dockerfile
│ │ │ │ └── setup_seedsync.sh
│ │ │ ├── parse_seedsync_status.py
│ │ │ ├── remote/
│ │ │ │ ├── Dockerfile
│ │ │ │ └── id_rsa.pub
│ │ │ ├── run_tests.sh
│ │ │ └── urls.ts
│ │ └── python/
│ │ ├── Dockerfile
│ │ ├── compose.yml
│ │ └── entrypoint.sh
│ └── wait-for-it.sh
├── e2e/
│ ├── .gitignore
│ ├── README.md
│ ├── conf.ts
│ ├── package.json
│ ├── tests/
│ │ ├── about.page.spec.ts
│ │ ├── about.page.ts
│ │ ├── app.spec.ts
│ │ ├── app.ts
│ │ ├── autoqueue.page.spec.ts
│ │ ├── autoqueue.page.ts
│ │ ├── dashboard.page.spec.ts
│ │ ├── dashboard.page.ts
│ │ ├── settings.page.spec.ts
│ │ └── settings.page.ts
│ ├── tsconfig.json
│ └── urls.ts
├── pyinstaller_hooks/
│ └── hook-patoolib.py
└── python/
├── __init__.py
├── common/
│ ├── __init__.py
│ ├── app_process.py
│ ├── config.py
│ ├── constants.py
│ ├── context.py
│ ├── error.py
│ ├── job.py
│ ├── localization.py
│ ├── multiprocessing_logger.py
│ ├── persist.py
│ ├── status.py
│ └── types.py
├── controller/
│ ├── __init__.py
│ ├── auto_queue.py
│ ├── controller.py
│ ├── controller_job.py
│ ├── controller_persist.py
│ ├── delete/
│ │ ├── __init__.py
│ │ └── delete_process.py
│ ├── extract/
│ │ ├── __init__.py
│ │ ├── dispatch.py
│ │ ├── extract.py
│ │ └── extract_process.py
│ ├── model_builder.py
│ └── scan/
│ ├── __init__.py
│ ├── active_scanner.py
│ ├── local_scanner.py
│ ├── remote_scanner.py
│ └── scanner_process.py
├── docs/
│ ├── faq.md
│ ├── index.md
│ ├── install.md
│ └── usage.md
├── lftp/
│ ├── __init__.py
│ ├── job_status.py
│ ├── job_status_parser.py
│ └── lftp.py
├── mkdocs.yml
├── model/
│ ├── __init__.py
│ ├── diff.py
│ ├── file.py
│ └── model.py
├── pyproject.toml
├── scan_fs.py
├── seedsync.py
├── ssh/
│ ├── __init__.py
│ └── sshcp.py
├── system/
│ ├── __init__.py
│ ├── file.py
│ └── scanner.py
├── tests/
│ ├── __init__.py
│ ├── integration/
│ │ ├── __init__.py
│ │ ├── test_controller/
│ │ │ ├── __init__.py
│ │ │ ├── test_controller.py
│ │ │ └── test_extract/
│ │ │ ├── __init__.py
│ │ │ └── test_extract.py
│ │ ├── test_lftp/
│ │ │ ├── __init__.py
│ │ │ └── test_lftp.py
│ │ └── test_web/
│ │ ├── __init__.py
│ │ ├── test_handler/
│ │ │ ├── __init__.py
│ │ │ ├── test_auto_queue.py
│ │ │ ├── test_config.py
│ │ │ ├── test_controller.py
│ │ │ ├── test_server.py
│ │ │ ├── test_status.py
│ │ │ ├── test_stream_log.py
│ │ │ ├── test_stream_model.py
│ │ │ └── test_stream_status.py
│ │ └── test_web_app.py
│ ├── unittests/
│ │ ├── __init__.py
│ │ ├── test_common/
│ │ │ ├── __init__.py
│ │ │ ├── test_app_process.py
│ │ │ ├── test_config.py
│ │ │ ├── test_job.py
│ │ │ ├── test_multiprocessing_logger.py
│ │ │ ├── test_persist.py
│ │ │ └── test_status.py
│ │ ├── test_controller/
│ │ │ ├── __init__.py
│ │ │ ├── test_auto_queue.py
│ │ │ ├── test_controller_persist.py
│ │ │ ├── test_extract/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_dispatch.py
│ │ │ │ └── test_extract_process.py
│ │ │ ├── test_model_builder.py
│ │ │ └── test_scan/
│ │ │ ├── __init__.py
│ │ │ ├── test_remote_scanner.py
│ │ │ └── test_scanner_process.py
│ │ ├── test_lftp/
│ │ │ ├── __init__.py
│ │ │ ├── test_job_status.py
│ │ │ ├── test_job_status_parser.py
│ │ │ └── test_lftp.py
│ │ ├── test_model/
│ │ │ ├── __init__.py
│ │ │ ├── test_diff.py
│ │ │ ├── test_file.py
│ │ │ └── test_model.py
│ │ ├── test_seedsync.py
│ │ ├── test_ssh/
│ │ │ ├── __init__.py
│ │ │ └── test_sshcp.py
│ │ ├── test_system/
│ │ │ ├── __init__.py
│ │ │ ├── test_file.py
│ │ │ └── test_scanner.py
│ │ └── test_web/
│ │ ├── __init__.py
│ │ ├── test_handler/
│ │ │ └── test_stream_log.py
│ │ └── test_serialize/
│ │ ├── __init__.py
│ │ ├── test_serialize.py
│ │ ├── test_serialize_auto_queue.py
│ │ ├── test_serialize_config.py
│ │ ├── test_serialize_log_record.py
│ │ ├── test_serialize_model.py
│ │ └── test_serialize_status.py
│ └── utils.py
└── web/
├── __init__.py
├── handler/
│ ├── __init__.py
│ ├── auto_queue.py
│ ├── config.py
│ ├── controller.py
│ ├── server.py
│ ├── status.py
│ ├── stream_log.py
│ ├── stream_model.py
│ └── stream_status.py
├── serialize/
│ ├── __init__.py
│ ├── serialize.py
│ ├── serialize_auto_queue.py
│ ├── serialize_config.py
│ ├── serialize_log_record.py
│ ├── serialize_model.py
│ └── serialize_status.py
├── utils.py
├── web_app.py
├── web_app_builder.py
└── web_app_job.py
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/workflows/master.yml
================================================
name: CI
on:
push:
branches: [ master ]
tags:
- v[0-9]+.[0-9]+.[0-9]+
pull_request:
branches: [ master ]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
jobs:
unittests-python:
name: Python unit tests
runs-on: ubuntu-latest
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- name: Checkout
uses: actions/checkout@v2
# Build package
- name: Run Python unit tests
run: make run-tests-python
unittests-angular:
name: Angular unit tests
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
# Build package
- name: Run Angular unit tests
run: make run-tests-angular
build-deb:
name: Build Deb
runs-on: ubuntu-latest
needs: [ unittests-python, unittests-angular ]
steps:
- name: Checkout
uses: actions/checkout@v2
# Sets up build environment
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v1
with:
driver-opts: |
image=moby/buildkit:master
network=host
- name: Show buildx builder instance name
run: echo ${{ steps.buildx.outputs.name }}
- name: Show buildx available platforms
run: echo ${{ steps.buildx.outputs.platforms }}
# Build package
- name: Build deb package
run: make deb
# Upload package
- name: Publish artifact
uses: actions/upload-artifact@v2
with:
path: ${{ github.workspace }}/build/*.deb
name: deb-${{ github.run_number }}
# Post build steps
- name: List built packages
if: ${{ success() }}
run: ls -l $GITHUB_WORKSPACE/build/
build-docker-image:
name: Build Docker Image
runs-on: ubuntu-latest
needs: [ unittests-python, unittests-angular ]
steps:
- name: Checkout
uses: actions/checkout@v2
# Sets up build environment
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v1
with:
driver-opts: |
image=moby/buildkit:master
network=host
- name: Show buildx builder instance name
run: echo ${{ steps.buildx.outputs.name }}
- name: Show buildx available platforms
run: echo ${{ steps.buildx.outputs.platforms }}
# Login using a PAT with write:packages scope
- name: Log into GitHub Container Registry
run: echo "${{ secrets.CR_PAT }}" | docker login https://ghcr.io -u ${{ github.actor }} --password-stdin
# Set staging registry
- name: Set staging registry env variable
run: echo "staging_registry=ghcr.io/${{ github.repository }}" >> $GITHUB_ENV
# Build docker image
- name: Build docker image
run: make docker-image STAGING_REGISTRY=${{ env.staging_registry }} STAGING_VERSION=${{ github.run_number }}
e2etests-deb:
name: End-to-end tests on Deb
runs-on: ubuntu-latest
needs: [ build-deb ]
strategy:
matrix:
oscode: [ ubu1604, ubu1804, ubu2004 ]
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Download deb package artifact
uses: actions/download-artifact@v2
with:
name: deb-${{ github.run_number }}
path: build/
# Run e2e test
- name: Run e2e test
run: make run-tests-e2e SEEDSYNC_DEB=`readlink -f build/*.deb` SEEDSYNC_OS=${{ matrix.oscode }}
e2etests-docker-image:
name: End-to-end tests on Docker Image
runs-on: ubuntu-latest
needs: [ build-docker-image ]
strategy:
matrix:
arch: [ amd64, arm64, arm/v7 ]
steps:
- name: Checkout
uses: actions/checkout@v2
# Sets up build environment
- name: Enable Docker experimental features
run: |
echo $'{\n "experimental": true\n}' | sudo tee /etc/docker/daemon.json
sudo service docker restart
docker version
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v1
with:
driver-opts: |
image=moby/buildkit:master
network=host
- name: Show buildx builder instance name
run: echo ${{ steps.buildx.outputs.name }}
- name: Show buildx available platforms
run: echo ${{ steps.buildx.outputs.platforms }}
# Login using a PAT with write:packages scope
- name: Log into GitHub Container Registry
run: echo "${{ secrets.CR_PAT }}" | docker login https://ghcr.io -u ${{ github.actor }} --password-stdin
# Set staging registry
- name: Set staging registry env variable
run: echo "staging_registry=ghcr.io/${{ github.repository }}" >> $GITHUB_ENV
# Run e2e test
- name: Run e2e test
run: make run-tests-e2e \
STAGING_REGISTRY=${{ env.staging_registry }} \
STAGING_VERSION=${{ github.run_number }} \
SEEDSYNC_ARCH=${{ matrix.arch }}
publish-docker-image:
name: Publish Docker Image
if: startsWith(github.ref, 'refs/tags/v')
runs-on: ubuntu-latest
needs: [ e2etests-deb, e2etests-docker-image ]
steps:
- name: Set release env variable
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_ENV
- name: Checkout
uses: actions/checkout@v2
# Sets up build environment
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v1
with:
driver-opts: |
image=moby/buildkit:master
network=host
- name: Show buildx builder instance name
run: echo ${{ steps.buildx.outputs.name }}
- name: Show buildx available platforms
run: echo ${{ steps.buildx.outputs.platforms }}
# Login to GHCR using a PAT with write:packages scope
- name: Log into GitHub Container Registry
run: echo "${{ secrets.CR_PAT }}" | docker login https://ghcr.io -u ${{ github.actor }} --password-stdin
# Login to Dockerhub
- name: Log into Dockerhub registry
run: echo "${{ secrets.DOCKER_PASSWORD }}" |
docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin
# Set staging registry
- name: Set staging registry env variable
run: echo "staging_registry=ghcr.io/${{ github.repository }}" >> $GITHUB_ENV
# Push image to dockerhub
- name: Push to Dockerhub (tag vX.X.X)
run: make docker-image-release \
STAGING_REGISTRY=${{ env.staging_registry }} \
STAGING_VERSION=${{ github.run_number }} \
RELEASE_REGISTRY=docker.io/ipsingh06 \
RELEASE_VERSION=${{ env.RELEASE_VERSION }}
- name: Push to Dockerhub (tag latest)
run: make docker-image-release \
STAGING_REGISTRY=${{ env.staging_registry }} \
STAGING_VERSION=${{ github.run_number }} \
RELEASE_REGISTRY=docker.io/ipsingh06 \
RELEASE_VERSION=latest
publish-deb:
name: Publish Deb package
if: startsWith(github.ref, 'refs/tags/v')
runs-on: ubuntu-latest
needs: [ e2etests-deb, e2etests-docker-image ]
steps:
- name: Set release env variable
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_ENV
- name: Download deb package artifact
uses: actions/download-artifact@v2
with:
name: deb-${{ github.run_number }}
path: build/
- name: Set deb file path and name env variable
run: |
echo "DEB_PATH=$(readlink -f ./build/*.deb)" >> $GITHUB_ENV
echo "DEB_NAME=$(basename $(readlink -f ./build/*.deb))" >> $GITHUB_ENV
- name: Create Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: Release ${{ github.ref }}
body: ${{ github.event.head_commit.message }}
draft: false
prerelease: false
- name: Upload Release Asset
id: upload-release-asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ${{ env.DEB_PATH }}
asset_name: ${{ env.DEB_NAME }}
asset_content_type: application/x-deb
================================================
FILE: .gitignore
================================================
.idea
*.pyc
/build
.venv
package-lock.json
src/python/build
src/python/site
================================================
FILE: LICENSE.txt
================================================
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 [yyyy] [name of copyright owner]
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.
================================================
FILE: Makefile
================================================
# Copyright 2017, Inderpreet Singh, All rights reserved.
# Catch sigterms
# See: https://stackoverflow.com/a/52159940
export SHELL:=/bin/bash
export SHELLOPTS:=$(if $(SHELLOPTS),$(SHELLOPTS):)pipefail:errexit
.ONESHELL:
# Color outputs
red=`tput setaf 1`
green=`tput setaf 2`
reset=`tput sgr0`
ROOTDIR:=$(shell realpath .)
SOURCEDIR:=$(shell realpath ./src)
BUILDDIR:=$(shell realpath ./build)
DEFAULT_STAGING_REGISTRY:=localhost:5000
#DOCKER_BUILDKIT_FLAGS=BUILDKIT_PROGRESS=plain
DOCKER=${DOCKER_BUILDKIT_FLAGS} DOCKER_BUILDKIT=1 docker
DOCKER_COMPOSE=${DOCKER_BUILDKIT_FLAGS} COMPOSE_DOCKER_CLI_BUILD=1 DOCKER_BUILDKIT=1 docker-compose
.PHONY: builddir deb docker-image clean
all: deb docker-image
builddir:
mkdir -p ${BUILDDIR}
scanfs: builddir
$(DOCKER) build \
-f ${SOURCEDIR}/docker/build/deb/Dockerfile \
--target seedsync_build_scanfs_export \
--output ${BUILDDIR} \
${ROOTDIR}
deb: builddir
$(DOCKER) build \
-f ${SOURCEDIR}/docker/build/deb/Dockerfile \
--target seedsync_build_deb_export \
--output ${BUILDDIR} \
${ROOTDIR}
docker-buildx:
$(DOCKER) run --rm --privileged multiarch/qemu-user-static --reset -p yes
docker-image: docker-buildx
@if [[ -z "${STAGING_REGISTRY}" ]] ; then \
export STAGING_REGISTRY="${DEFAULT_STAGING_REGISTRY}"; \
fi;
echo "${green}STAGING_REGISTRY=$${STAGING_REGISTRY}${reset}";
@if [[ -z "${STAGING_VERSION}" ]] ; then \
export STAGING_VERSION="latest"; \
fi;
echo "${green}STAGING_VERSION=$${STAGING_VERSION}${reset}";
# scanfs image
$(DOCKER) buildx build \
-f ${SOURCEDIR}/docker/build/deb/Dockerfile \
--target seedsync_build_scanfs_export \
--tag $${STAGING_REGISTRY}/seedsync/build/scanfs/export:$${STAGING_VERSION} \
--cache-to=type=registry,ref=$${STAGING_REGISTRY}/seedsync/build/scanfs/export:cache,mode=max \
--cache-from=type=registry,ref=$${STAGING_REGISTRY}/seedsync/build/scanfs/export:cache \
--push \
${ROOTDIR}
# angular html export
$(DOCKER) buildx build \
-f ${SOURCEDIR}/docker/build/deb/Dockerfile \
--target seedsync_build_angular_export \
--tag $${STAGING_REGISTRY}/seedsync/build/angular/export:$${STAGING_VERSION} \
--cache-to=type=registry,ref=$${STAGING_REGISTRY}/seedsync/build/angular/export:cache,mode=max \
--cache-from=type=registry,ref=$${STAGING_REGISTRY}/seedsync/build/angular/export:cache \
--push \
${ROOTDIR}
# final image
$(DOCKER) buildx build \
-f ${SOURCEDIR}/docker/build/docker-image/Dockerfile \
--target seedsync_run \
--build-arg STAGING_VERSION=$${STAGING_VERSION} \
--build-arg STAGING_REGISTRY=$${STAGING_REGISTRY} \
--tag $${STAGING_REGISTRY}/seedsync:$${STAGING_VERSION} \
--cache-to=type=registry,ref=$${STAGING_REGISTRY}/seedsync:cache,mode=max \
--cache-from=type=registry,ref=$${STAGING_REGISTRY}/seedsync:cache \
--platform linux/amd64,linux/arm64,linux/arm/v7 \
--push \
${ROOTDIR}
docker-image-release:
@if [[ -z "${STAGING_REGISTRY}" ]] ; then \
export STAGING_REGISTRY="${DEFAULT_STAGING_REGISTRY}"; \
fi;
echo "${green}STAGING_REGISTRY=$${STAGING_REGISTRY}${reset}";
@if [[ -z "${STAGING_VERSION}" ]] ; then \
export STAGING_VERSION="latest"; \
fi;
echo "${green}STAGING_VERSION=$${STAGING_VERSION}${reset}";
@if [[ -z "${RELEASE_REGISTRY}" ]] ; then \
echo "${red}ERROR: RELEASE_REGISTRY is required${reset}"; exit 1; \
fi
@if [[ -z "${RELEASE_VERSION}" ]] ; then \
echo "${red}ERROR: RELEASE_VERSION is required${reset}"; exit 1; \
fi
echo "${green}RELEASE_REGISTRY=${RELEASE_REGISTRY}${reset}"
echo "${green}RELEASE_VERSION=${RELEASE_VERSION}${reset}"
# final image
$(DOCKER) buildx build \
-f ${SOURCEDIR}/docker/build/docker-image/Dockerfile \
--target seedsync_run \
--build-arg STAGING_VERSION=$${STAGING_VERSION} \
--build-arg STAGING_REGISTRY=$${STAGING_REGISTRY} \
--tag ${RELEASE_REGISTRY}/seedsync:${RELEASE_VERSION} \
--cache-from=type=registry,ref=$${STAGING_REGISTRY}/seedsync:cache \
--platform linux/amd64,linux/arm64,linux/arm/v7 \
--push \
${ROOTDIR}
tests-python:
# python run
$(DOCKER) build \
-f ${SOURCEDIR}/docker/build/docker-image/Dockerfile \
--target seedsync_run_python_devenv \
--tag seedsync/run/python/devenv \
${ROOTDIR}
# python tests
$(DOCKER_COMPOSE) \
-f ${SOURCEDIR}/docker/test/python/compose.yml \
build
run-tests-python: tests-python
$(DOCKER_COMPOSE) \
-f ${SOURCEDIR}/docker/test/python/compose.yml \
up --force-recreate --exit-code-from tests
tests-angular:
# angular build
$(DOCKER) build \
-f ${SOURCEDIR}/docker/build/deb/Dockerfile \
--target seedsync_build_angular_env \
--tag seedsync/build/angular/env \
${ROOTDIR}
# angular tests
$(DOCKER_COMPOSE) \
-f ${SOURCEDIR}/docker/test/angular/compose.yml \
build
run-tests-angular: tests-angular
$(DOCKER_COMPOSE) \
-f ${SOURCEDIR}/docker/test/angular/compose.yml \
up --force-recreate --exit-code-from tests
tests-e2e-deps:
# deb pre-reqs
$(DOCKER) build \
${SOURCEDIR}/docker/stage/deb/ubuntu-systemd/ubuntu-16.04-systemd \
-t ubuntu-systemd:16.04
$(DOCKER) build \
${SOURCEDIR}/docker/stage/deb/ubuntu-systemd/ubuntu-18.04-systemd \
-t ubuntu-systemd:18.04
$(DOCKER) build \
${SOURCEDIR}/docker/stage/deb/ubuntu-systemd/ubuntu-20.04-systemd \
-t ubuntu-systemd:20.04
# Setup docker for the systemd container
# See: https://github.com/solita/docker-systemd
$(DOCKER) run --rm --privileged -v /:/host solita/ubuntu-systemd setup
run-tests-e2e: tests-e2e-deps
# Check our settings
@if [[ -z "${STAGING_VERSION}" ]] && [[ -z "${SEEDSYNC_DEB}" ]]; then \
echo "${red}ERROR: One of STAGING_VERSION or SEEDSYNC_DEB must be set${reset}"; exit 1; \
elif [[ ! -z "${STAGING_VERSION}" ]] && [[ ! -z "${SEEDSYNC_DEB}" ]]; then \
echo "${red}ERROR: Only one of STAGING_VERSION or SEEDSYNC_DEB must be set${reset}"; exit 1; \
fi
# Set up environment for deb
@if [[ ! -z "${SEEDSYNC_DEB}" ]] ; then \
if [[ -z "${SEEDSYNC_OS}" ]] ; then \
echo "${red}ERROR: SEEDSYNC_OS is required for DEB e2e test${reset}"; \
echo "${red}Options include: ubu1604, ubu1804, ubu2004${reset}"; exit 1; \
fi
fi
# Set up environment for image
@if [[ ! -z "${STAGING_VERSION}" ]] ; then \
if [[ -z "${SEEDSYNC_ARCH}" ]] ; then \
echo "${red}ERROR: SEEDSYNC_ARCH is required for docker image e2e test${reset}"; \
echo "${red}Options include: amd64, arm64, arm/v7${reset}"; exit 1; \
fi
if [[ -z "${STAGING_REGISTRY}" ]] ; then \
export STAGING_REGISTRY="${DEFAULT_STAGING_REGISTRY}"; \
fi;
echo "${green}STAGING_REGISTRY=$${STAGING_REGISTRY}${reset}";
# Removing and pulling is the only way to select the arch from a multi-arch image :(
$(DOCKER) rmi -f $${STAGING_REGISTRY}/seedsync:$${STAGING_VERSION}
$(DOCKER) pull $${STAGING_REGISTRY}/seedsync:$${STAGING_VERSION} --platform linux/$${SEEDSYNC_ARCH}
fi
# Set the flags
COMPOSE_FLAGS="-f ${SOURCEDIR}/docker/test/e2e/compose.yml "
COMPOSE_RUN_FLAGS=""
if [[ ! -z "${SEEDSYNC_DEB}" ]] ; then
COMPOSE_FLAGS+="-f ${SOURCEDIR}/docker/stage/deb/compose.yml "
COMPOSE_FLAGS+="-f ${SOURCEDIR}/docker/stage/deb/compose-${SEEDSYNC_OS}.yml "
fi
if [[ ! -z "${STAGING_VERSION}" ]] ; then \
COMPOSE_FLAGS+="-f ${SOURCEDIR}/docker/stage/docker-image/compose.yml "
fi
if [[ "${DEV}" = "1" ]] ; then
COMPOSE_FLAGS+="-f ${SOURCEDIR}/docker/test/e2e/compose-dev.yml "
else \
COMPOSE_RUN_FLAGS+="-d"
fi
echo "${green}COMPOSE_FLAGS=$${COMPOSE_FLAGS}${reset}"
# Set up Ctrl-C handler
function tearDown {
$(DOCKER_COMPOSE) \
$${COMPOSE_FLAGS} \
stop
}
trap tearDown EXIT
# Build the test
echo "${green}Building the tests${reset}"
$(DOCKER_COMPOSE) \
$${COMPOSE_FLAGS} \
build
# This suppresses the docker-compose error that image has changed
$(DOCKER_COMPOSE) \
$${COMPOSE_FLAGS} \
rm -f myapp
# Run the test
echo "${green}Running the tests${reset}"
$(DOCKER_COMPOSE) \
$${COMPOSE_FLAGS} \
up --force-recreate \
$${COMPOSE_RUN_FLAGS}
if [[ "${DEV}" != "1" ]] ; then
$(DOCKER) logs -f seedsync_test_e2e
fi
EXITCODE=`$(DOCKER) inspect seedsync_test_e2e | jq '.[].State.ExitCode'`
if [[ "$${EXITCODE}" != "0" ]] ; then
false
fi
run-remote-server:
$(DOCKER) container rm -f seedsync_test_e2e_remote-dev
$(DOCKER) run \
-it --init \
-p 1234:1234 \
--name seedsync_test_e2e_remote-dev \
seedsync/test/e2e/remote
clean:
rm -rf ${BUILDDIR}
================================================
FILE: README.md
================================================
<p align="center">
<img src="https://user-images.githubusercontent.com/12875506/85908858-c637a100-b7cb-11ea-8ab3-75c0c0ddf756.png" alt="SeedSync" />
</p>
<p align="center">
<!--<a href="https://travis-ci.com/ipsingh06/seedsync">
<img src="https://img.shields.io/travis/com/ipsingh06/seedsync" alt="Build">
</a>-->
<a href="https://github.com/ipsingh06/seedsync">
<img src="https://img.shields.io/github/stars/ipsingh06/seedsync" alt="Stars">
</a>
<a href="https://hub.docker.com/r/ipsingh06/seedsync">
<img src="https://img.shields.io/docker/pulls/ipsingh06/seedsync" alt="Downloads">
</a>
<a href="https://hub.docker.com/r/ipsingh06/seedsync">
<img src="https://img.shields.io/docker/v/ipsingh06/seedsync?color=blue" alt="Version">
</a>
<a href="https://hub.docker.com/r/ipsingh06/seedsync">
<img src="https://img.shields.io/docker/image-size/ipsingh06/seedsync/latest?style=flat" alt="Size">
</a>
<a href="https://github.com/ipsingh06/seedsync/blob/master/LICENSE.txt">
<img src="https://img.shields.io/github/license/ipsingh06/seedsync" alt="License">
</a>
</p>
SeedSync is a tool to sync the files on a remote Linux server (like your seedbox, for example).
It uses LFTP to transfer files fast!
## Features
* Built on top of [LFTP](http://lftp.tech/), the fastest file transfer program ever
* Web UI - track and control your transfers from anywhere
* Automatically extract your files after sync
* Auto-Queue - only sync the files you want based on pattern matching
* Delete local and remote files easily
* Fully open source!
## How it works
Install SeedSync on a local machine.
SeedSync will connect to your remote server and sync files to the local machine as
they become available.
You don't need to install anything on the remote server.
All you need are the SSH credentials for the remote server.
## Supported Platforms
* Linux
* Raspberry Pi (v2, v3 and v4)
* Windows (via Docker)
* MacOS (via Docker)
## Installation and Usage
Please refer to the [documentation](https://ipsingh06.github.io/seedsync/).
## Report an Issue
Please report any issues on the [issues](../../issues) page.
Please post the logs as well. The logs are available at:
* Deb install: `<user home directory>/.seedsync/log/seedsync.log`
* Docker: Run `docker logs <container id>`
## Contribute
Contributions to SeedSync are welcome!
Please take a look at the [Developer Readme](doc/DeveloperReadme.md) for instructions
on environment setup and the build process.
## License
SeedSync is distributed under Apache License Version 2.0.
See [License.txt](https://github.com/ipsingh06/seedsync/blob/master/LICENSE.txt) for more information.

================================================
FILE: doc/CodingGuidelines.md
================================================
# Coding Guidelines
## Python
1. Try not to throw exceptions in constructors.
Delay exceptions until after the web service is up and running.
This allows us to notify the user about the error.
2. Try to keep constructors short and passive.
Try not to start any threads or processes in constructors.
3. Do not rely on timing constraints in tests.
That is, don't use `time.sleep()` to wait for something to happen.
Actually wait for the condition and use a watchdog timer to check for failure.
## Angular
1. Keep constructor of Immutable.Record blank.
Any pre-processing that is needed to convert a JS object to Record should be put in a factory function.
This ensures that the Record object can be easily constructed for tests without having to know the JS object translations.
================================================
FILE: doc/DeveloperReadme.md
================================================
[TOC]
# Environment Setup
## Install dependencies
1. Install [nodejs](https://joshtronic.com/2019/04/29/how-to-install-node-v12-on-debian-and-ubuntu/) (comes with npm)
2. Install [Poetry](https://python-poetry.org/docs/#installation):
3. Install docker and docker-compose:
https://docs.docker.com/engine/installation/linux/docker-ce/ubuntu/#install-docker-ce
https://docs.docker.com/compose/install/
4. Install docker buildx
1. https://github.com/docker/buildx/issues/132#issuecomment-582218096
2. https://github.com/docker/buildx/issues/132#issuecomment-636041307
5. Build dependencies
```bash
sudo apt-get install -y jq
```
6. Install the rest:
```bash
sudo apt-get install -y lftp python3-dev rar
```
## Fetch code
```bash
git clone git@gitlab.com:ipsingh06/seedsync.git
cd seedsync
```
## Setup Poetry project
```bash
cd src/python
poetry install
```
## Setup angular node modules
```bash
cd src/angular
npm install
```
## Setup end-to-end tests node modules
```bash
cd src/e2e
npm install
```
# Build
1. Set up docker buildx for multi-arch builds
```bash
docker buildx create --name mybuilder --driver docker-container --driver-opt image=moby/buildkit:master,network=host
docker buildx use mybuilder
docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
docker buildx inspect --bootstrap
# Make sure the following architectures are listed: linux/amd64, linux/arm64, linux/arm/v7
```
2. Multi-arch docker images can only be stored in a registry.
Create local docker registry to store multi-arch images
```bash
docker run -d -p 5000:5000 --restart=always --name registry registry:2
```
3. Run these commands inside the root directory.
```bash
make clean
make
```
4. The .deb package will be generated inside `build` directory.
The docker image will be pushed to the local registry as `seedsync:latest`. See if using:
```bash
curl -X GET http://localhost:5000/v2/_catalog
```
To inspect the architectures of image:
```bash
docker buildx imagetools inspect localhost:5000/seedsync:latest
```
To use a different registry during the build process, use `STAGING_REGISTRY=`.
For example:
```bash
make STAGING_REGISTRY=another-registry:5000
```
To build a tag other than `latest`, use `STAGING_VERSION=`.
For example:
```bash
make STAGING_VERSION=0.0.1
```
## Python Dev Build and Run
### Build scanfs
```bash
make scanfs
```
### Run python
```bash
cd src/python
mkdir -p build/config
poetry run python seedsync.py -c build/config --html ../angular/dist --scanfs build/scanfs
```
## Angular Dev Build and Run
```bash
cd src/angular
node_modules/@angular/cli/bin/ng build
node_modules/@angular/cli/bin/ng serve
```
Dev build will be served at [http://localhost:4200](http://localhost:4200)
## Documentation
### Preview documentation in browser
```bash
cd src/python
poetry run mkdocs serve
```
Preview will be served at [http://localhost:8000](http://localhost:8000)
### Deploy documentation
```bash
poetry run mkdocs gh-deploy
git push github gh-pages
```
# Setup dev environment
## PyCharm
1. Set project root to top-level `seedsync` directory
2. Switch interpreter to virtualenv
3. Mark src/python as 'Sources Root'
4. Add run configuration
| Config | Value |
| ----------- | ------------------------------------------------------------ |
| Name | seedsync |
| Script path | seedsync.py |
| Parameters | -c ./build/config --html ../angular/dist --scanfs ./build/scanfs |
# Run tests
## Manual
### Python Unit Tests
Create a new user account for python tests, and add the current user to its authorized keys.
Also add the test account to the current user group so it may access any files created by the current user.
Note: the current user must have SSH keys already generated.
```bash
sudo adduser -q --disabled-password --disabled-login --gecos 'seedsynctest' seedsynctest
sudo bash -c "echo seedsynctest:seedsyncpass | chpasswd"
sudo -u seedsynctest mkdir /home/seedsynctest/.ssh
sudo -u seedsynctest chmod 700 /home/seedsynctest/.ssh
cat ~/.ssh/id_rsa.pub | sudo -u seedsynctest tee /home/seedsynctest/.ssh/authorized_keys
sudo -u seedsynctest chmod 664 /home/seedsynctest/.ssh/authorized_keys
sudo usermod -a -G $USER seedsynctest
```
Run from PyCharm
OR
Run from terminal
```bash
cd src/python
poetry run pytest
```
### Angular Unit Tests
```bash
cd src/angular
node_modules/@angular/cli/bin/ng test
```
### E2E Tests
[See here](../src/e2e/README.md)
## Docker-based Test Suite
```bash
# Python tests
make run-tests-python
# Angular tests
make run-tests-angular
# E2E Tests
# Docker image (arch=amd64,arm64,arm/v7)
make run-tests-e2e STAGING_VERSION=latest SEEDSYNC_ARCH=<arch code>
# Debian package (os=ubu1604,ubu1804,ubu2004)
make run-tests-e2e SEEDSYNC_DEB=`readlink -f build/*.deb` SEEDSYNC_OS=<os code>
```
By default images are pulled from `localhost:5000`. To test image from a registry other than the local, use `STAGING_REGISTRY=`.
For example:
```bash
make run-tests-e2e STAGING_VERSION=latest SEEDSYNC_ARCH=arm64 STAGING_REGISTRY=ipsingh06
```
# Release
## Continuous Integration
This method uses Github Action to post releases.
1. Do all of these in one change
1. Version update in `src/angular/package.json`
2. Version update and changelog in `src/debian/changelog`.
Use command `LANG=C date -R` to get the date.
3. Update `src/e2e/tests/about.page.spec.ts`
4. Update Copyright date in `about-page.component.html`
2. Tag the commit as vX.X.X
3. Push tag to Github
## Manual Method
This manual method is deprecated in favour of the Github Actions based CI.
### Checklist
1. Do all of these in one change
1. Version update in `src/angular/package.json`
2. Version update and changelog in `src/debian/changelog`.
Use command `LANG=C date -R` to get the date.
3. Update `src/e2e/tests/about.page.spec.ts`
4. Update Copyright date in `about-page.component.html`
2. Tag the commit as vX.X.X
3. Deploy documentation to github
4. make clean && make
5. Run all tests
6. Upload deb file to github
7. Tag and upload image to Dockerhub (see below)
### Docker image upload to Dockerhub
```bash
make docker-image-release RELEASE_VERSION=<version> RELEASE_REGISTRY=ipsingh06
make docker-image-release RELEASE_VERSION=latest RELEASE_REGISTRY=ipsingh06
```
# Development
## Remote Server
Use the following command to run the docker image for the remote server for development testing.
This is the same image used by the end-to-end tests.
```bash
make run-remote-server
```
The connection parameters for the remote server are:
| Option | Value |
| -------------- | --------------------------------- |
| Remote Address | localhost or host.docker.internal |
| Remote Port | 1234 |
| Username | remoteuser |
| Pass | remotepass |
| Remote Path | /home/remoteuser/files |
## Run Docker Image
Use the following command to run the docker image locally:
```bash
docker run --rm -p 8800:8800 localhost:5000/seedsync:latest
```
================================================
FILE: doc/assets/logo.ai
================================================
%PDF-1.5
%
1 0 obj
<</Metadata 2 0 R/OCProperties<</D<</ON[5 0 R 32 0 R 58 0 R 84 0 R 110 0 R 136 0 R 162 0 R 188 0 R 214 0 R 240 0 R]/Order 241 0 R/RBGroups[]>>/OCGs[5 0 R 32 0 R 58 0 R 84 0 R 110 0 R 136 0 R 162 0 R 188 0 R 214 0 R 240 0 R]>>/Pages 3 0 R/Type/Catalog>>
endobj
2 0 obj
<</Length 53343/Subtype/XML/Type/Metadata>>stream
<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.0-c060 61.134777, 2010/02/12-17:32:00 ">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about=""
xmlns:dc="http://purl.org/dc/elements/1.1/">
<dc:format>application/pdf</dc:format>
<dc:title>
<rdf:Alt>
<rdf:li xml:lang="x-default">Print</rdf:li>
</rdf:Alt>
</dc:title>
</rdf:Description>
<rdf:Description rdf:about=""
xmlns:xmp="http://ns.adobe.com/xap/1.0/"
xmlns:xmpGImg="http://ns.adobe.com/xap/1.0/g/img/">
<xmp:MetadataDate>2017-12-20T16:27:36-08:00</xmp:MetadataDate>
<xmp:ModifyDate>2017-12-20T16:27:36-08:00</xmp:ModifyDate>
<xmp:CreateDate>2017-12-20T15:03:31-08:00</xmp:CreateDate>
<xmp:CreatorTool>Adobe Illustrator CS5</xmp:CreatorTool>
<xmp:Thumbnails>
<rdf:Alt>
<rdf:li rdf:parseType="Resource">
<xmpGImg:width>256</xmpGImg:width>
<xmpGImg:height>240</xmpGImg:height>
<xmpGImg:format>JPEG</xmpGImg:format>
<xmpGImg:image>/9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA
AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK
DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f
Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgA8AEAAwER
AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA
AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB
UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE
1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ
qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy
obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp
0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo
+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq7
FXYq7FXYq7FXYq7FVC9v7GxgNxfXMVrANjNM6xoD/rMQMSUEgc2Faz+eP5a6XyU6qL2ZTT0rNHmr
8pABF/w+RMw4s9fhj/F8t2Gap/zlFo8bMNL0O4uRT4XuZUg3/wBVBP8AryPiOJPtaA+kEsWv/wDn
JvzpLyWz0+wtVPRmWWVx9JdV/wCFwcZcaXa0+gASG7/Pr80bgELqqwKRQiK3tx9xZGYffg4i0y7S
zHrXwSif81fzGnar+Yb0Gtf3cpjH3JxwWWs67Mf4kvn87+c5wBPr+oyhfs87udqV8KvjbV+Yyfzp
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
KuxV2KuxV2KuxV//2Q==</xmpGImg:image>
</rdf:li>
</rdf:Alt>
</xmp:Thumbnails>
</rdf:Description>
<rdf:Description rdf:about=""
xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/"
xmlns:stRef="http://ns.adobe.com/xap/1.0/sType/ResourceRef#"
xmlns:stEvt="http://ns.adobe.com/xap/1.0/sType/ResourceEvent#">
<xmpMM:InstanceID>uuid:92c58e1a-0e41-446e-95bc-d00422909d30</xmpMM:InstanceID>
<xmpMM:DocumentID>xmp.did:57893048C9E5E7118238DD4578CC24E0</xmpMM:DocumentID>
<xmpMM:OriginalDocumentID>uuid:5D20892493BFDB11914A8590D31508C8</xmpMM:OriginalDocumentID>
<xmpMM:RenditionClass>proof:pdf</xmpMM:RenditionClass>
<xmpMM:DerivedFrom rdf:parseType="Resource">
<stRef:instanceID>xmp.iid:56893048C9E5E7118238DD4578CC24E0</stRef:instanceID>
<stRef:documentID>xmp.did:56893048C9E5E7118238DD4578CC24E0</stRef:documentID>
<stRef:originalDocumentID>uuid:5D20892493BFDB11914A8590D31508C8</stRef:originalDocumentID>
<stRef:renditionClass>proof:pdf</stRef:renditionClass>
</xmpMM:DerivedFrom>
<xmpMM:History>
<rdf:Seq>
<rdf:li rdf:parseType="Resource">
<stEvt:action>saved</stEvt:action>
<stEvt:instanceID>xmp.iid:55893048C9E5E7118238DD4578CC24E0</stEvt:instanceID>
<stEvt:when>2017-12-20T13:03:52-08:00</stEvt:when>
<stEvt:softwareAgent>Adobe Illustrator CS5</stEvt:softwareAgent>
<stEvt:changed>/</stEvt:changed>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<stEvt:action>saved</stEvt:action>
<stEvt:instanceID>xmp.iid:56893048C9E5E7118238DD4578CC24E0</stEvt:instanceID>
<stEvt:when>2017-12-20T15:03:24-08:00</stEvt:when>
<stEvt:softwareAgent>Adobe Illustrator CS5</stEvt:softwareAgent>
<stEvt:changed>/</stEvt:changed>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<stEvt:action>saved</stEvt:action>
<stEvt:instanceID>xmp.iid:57893048C9E5E7118238DD4578CC24E0</stEvt:instanceID>
<stEvt:when>2017-12-20T15:03:32-08:00</stEvt:when>
<stEvt:softwareAgent>Adobe Illustrator CS5</stEvt:softwareAgent>
<stEvt:changed>/</stEvt:changed>
</rdf:li>
</rdf:Seq>
</xmpMM:History>
</rdf:Description>
<rdf:Description rdf:about=""
xmlns:illustrator="http://ns.adobe.com/illustrator/1.0/">
<illustrator:Type>Document</illustrator:Type>
<illustrator:StartupProfile>Print</illustrator:StartupProfile>
</rdf:Description>
<rdf:Description rdf:about=""
xmlns:xmpTPg="http://ns.adobe.com/xap/1.0/t/pg/"
xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#"
xmlns:xmpG="http://ns.adobe.com/xap/1.0/g/">
<xmpTPg:HasVisibleOverprint>False</xmpTPg:HasVisibleOverprint>
<xmpTPg:HasVisibleTransparency>False</xmpTPg:HasVisibleTransparency>
<xmpTPg:NPages>1</xmpTPg:NPages>
<xmpTPg:MaxPageSize rdf:parseType="Resource">
<stDim:w>500.000000</stDim:w>
<stDim:h>500.000000</stDim:h>
<stDim:unit>Pixels</stDim:unit>
</xmpTPg:MaxPageSize>
<xmpTPg:PlateNames>
<rdf:Seq>
<rdf:li>Cyan</rdf:li>
<rdf:li>Magenta</rdf:li>
<rdf:li>Yellow</rdf:li>
<rdf:li>Black</rdf:li>
</rdf:Seq>
</xmpTPg:PlateNames>
<xmpTPg:SwatchGroups>
<rdf:Seq>
<rdf:li rdf:parseType="Resource">
<xmpG:groupName>Default Swatch Group</xmpG:groupName>
<xmpG:groupType>0</xmpG:groupType>
<xmpG:Colorants>
<rdf:Seq>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>White</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>0.000000</xmpG:cyan>
<xmpG:magenta>0.000000</xmpG:magenta>
<xmpG:yellow>0.000000</xmpG:yellow>
<xmpG:black>0.000000</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>Black</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>0.000000</xmpG:cyan>
<xmpG:magenta>0.000000</xmpG:magenta>
<xmpG:yellow>0.000000</xmpG:yellow>
<xmpG:black>100.000000</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>CMYK Red</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>0.000000</xmpG:cyan>
<xmpG:magenta>100.000000</xmpG:magenta>
<xmpG:yellow>100.000000</xmpG:yellow>
<xmpG:black>0.000000</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>CMYK Yellow</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>0.000000</xmpG:cyan>
<xmpG:magenta>0.000000</xmpG:magenta>
<xmpG:yellow>100.000000</xmpG:yellow>
<xmpG:black>0.000000</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>CMYK Green</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>100.000000</xmpG:cyan>
<xmpG:magenta>0.000000</xmpG:magenta>
<xmpG:yellow>100.000000</xmpG:yellow>
<xmpG:black>0.000000</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>CMYK Cyan</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>100.000000</xmpG:cyan>
<xmpG:magenta>0.000000</xmpG:magenta>
<xmpG:yellow>0.000000</xmpG:yellow>
<xmpG:black>0.000000</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>CMYK Blue</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>100.000000</xmpG:cyan>
<xmpG:magenta>100.000000</xmpG:magenta>
<xmpG:yellow>0.000000</xmpG:yellow>
<xmpG:black>0.000000</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>CMYK Magenta</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>0.000000</xmpG:cyan>
<xmpG:magenta>100.000000</xmpG:magenta>
<xmpG:yellow>0.000000</xmpG:yellow>
<xmpG:black>0.000000</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=15 M=100 Y=90 K=10</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>14.999998</xmpG:cyan>
<xmpG:magenta>100.000000</xmpG:magenta>
<xmpG:yellow>90.000004</xmpG:yellow>
<xmpG:black>10.000002</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=0 M=90 Y=85 K=0</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>0.000000</xmpG:cyan>
<xmpG:magenta>90.000004</xmpG:magenta>
<xmpG:yellow>84.999996</xmpG:yellow>
<xmpG:black>0.000000</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=0 M=80 Y=95 K=0</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>0.000000</xmpG:cyan>
<xmpG:magenta>80.000001</xmpG:magenta>
<xmpG:yellow>94.999999</xmpG:yellow>
<xmpG:black>0.000000</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=0 M=50 Y=100 K=0</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>0.000000</xmpG:cyan>
<xmpG:magenta>50.000000</xmpG:magenta>
<xmpG:yellow>100.000000</xmpG:yellow>
<xmpG:black>0.000000</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=0 M=35 Y=85 K=0</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>0.000000</xmpG:cyan>
<xmpG:magenta>35.000002</xmpG:magenta>
<xmpG:yellow>84.999996</xmpG:yellow>
<xmpG:black>0.000000</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=5 M=0 Y=90 K=0</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>5.000001</xmpG:cyan>
<xmpG:magenta>0.000000</xmpG:magenta>
<xmpG:yellow>90.000004</xmpG:yellow>
<xmpG:black>0.000000</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=20 M=0 Y=100 K=0</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>19.999999</xmpG:cyan>
<xmpG:magenta>0.000000</xmpG:magenta>
<xmpG:yellow>100.000000</xmpG:yellow>
<xmpG:black>0.000000</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=50 M=0 Y=100 K=0</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>50.000000</xmpG:cyan>
<xmpG:magenta>0.000000</xmpG:magenta>
<xmpG:yellow>100.000000</xmpG:yellow>
<xmpG:black>0.000000</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=75 M=0 Y=100 K=0</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>75.000000</xmpG:cyan>
<xmpG:magenta>0.000000</xmpG:magenta>
<xmpG:yellow>100.000000</xmpG:yellow>
<xmpG:black>0.000000</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=85 M=10 Y=100 K=10</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>84.999996</xmpG:cyan>
<xmpG:magenta>10.000002</xmpG:magenta>
<xmpG:yellow>100.000000</xmpG:yellow>
<xmpG:black>10.000002</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=90 M=30 Y=95 K=30</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>90.000004</xmpG:cyan>
<xmpG:magenta>30.000001</xmpG:magenta>
<xmpG:yellow>94.999999</xmpG:yellow>
<xmpG:black>30.000001</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=75 M=0 Y=75 K=0</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>75.000000</xmpG:cyan>
<xmpG:magenta>0.000000</xmpG:magenta>
<xmpG:yellow>75.000000</xmpG:yellow>
<xmpG:black>0.000000</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=80 M=10 Y=45 K=0</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>80.000001</xmpG:cyan>
<xmpG:magenta>10.000002</xmpG:magenta>
<xmpG:yellow>44.999999</xmpG:yellow>
<xmpG:black>0.000000</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=70 M=15 Y=0 K=0</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>69.999999</xmpG:cyan>
<xmpG:magenta>14.999998</xmpG:magenta>
<xmpG:yellow>0.000000</xmpG:yellow>
<xmpG:black>0.000000</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=85 M=50 Y=0 K=0</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>84.999996</xmpG:cyan>
<xmpG:magenta>50.000000</xmpG:magenta>
<xmpG:yellow>0.000000</xmpG:yellow>
<xmpG:black>0.000000</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=100 M=95 Y=5 K=0</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>100.000000</xmpG:cyan>
<xmpG:magenta>94.999999</xmpG:magenta>
<xmpG:yellow>5.000001</xmpG:yellow>
<xmpG:black>0.000000</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=100 M=100 Y=25 K=25</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>100.000000</xmpG:cyan>
<xmpG:magenta>100.000000</xmpG:magenta>
<xmpG:yellow>25.000000</xmpG:yellow>
<xmpG:black>25.000000</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=75 M=100 Y=0 K=0</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>75.000000</xmpG:cyan>
<xmpG:magenta>100.000000</xmpG:magenta>
<xmpG:yellow>0.000000</xmpG:yellow>
<xmpG:black>0.000000</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=50 M=100 Y=0 K=0</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>50.000000</xmpG:cyan>
<xmpG:magenta>100.000000</xmpG:magenta>
<xmpG:yellow>0.000000</xmpG:yellow>
<xmpG:black>0.000000</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=35 M=100 Y=35 K=10</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>35.000002</xmpG:cyan>
<xmpG:magenta>100.000000</xmpG:magenta>
<xmpG:yellow>35.000002</xmpG:yellow>
<xmpG:black>10.000002</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=10 M=100 Y=50 K=0</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>10.000002</xmpG:cyan>
<xmpG:magenta>100.000000</xmpG:magenta>
<xmpG:yellow>50.000000</xmpG:yellow>
<xmpG:black>0.000000</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=0 M=95 Y=20 K=0</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>0.000000</xmpG:cyan>
<xmpG:magenta>94.999999</xmpG:magenta>
<xmpG:yellow>19.999999</xmpG:yellow>
<xmpG:black>0.000000</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=25 M=25 Y=40 K=0</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>25.000000</xmpG:cyan>
<xmpG:magenta>25.000000</xmpG:magenta>
<xmpG:yellow>39.999998</xmpG:yellow>
<xmpG:black>0.000000</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=40 M=45 Y=50 K=5</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>39.999998</xmpG:cyan>
<xmpG:magenta>44.999999</xmpG:magenta>
<xmpG:yellow>50.000000</xmpG:yellow>
<xmpG:black>5.000001</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=50 M=50 Y=60 K=25</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>50.000000</xmpG:cyan>
<xmpG:magenta>50.000000</xmpG:magenta>
<xmpG:yellow>60.000002</xmpG:yellow>
<xmpG:black>25.000000</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=55 M=60 Y=65 K=40</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>55.000001</xmpG:cyan>
<xmpG:magenta>60.000002</xmpG:magenta>
<xmpG:yellow>64.999998</xmpG:yellow>
<xmpG:black>39.999998</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=25 M=40 Y=65 K=0</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>25.000000</xmpG:cyan>
<xmpG:magenta>39.999998</xmpG:magenta>
<xmpG:yellow>64.999998</xmpG:yellow>
<xmpG:black>0.000000</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=30 M=50 Y=75 K=10</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>30.000001</xmpG:cyan>
<xmpG:magenta>50.000000</xmpG:magenta>
<xmpG:yellow>75.000000</xmpG:yellow>
<xmpG:black>10.000002</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=35 M=60 Y=80 K=25</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>35.000002</xmpG:cyan>
<xmpG:magenta>60.000002</xmpG:magenta>
<xmpG:yellow>80.000001</xmpG:yellow>
<xmpG:black>25.000000</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=40 M=65 Y=90 K=35</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>39.999998</xmpG:cyan>
<xmpG:magenta>64.999998</xmpG:magenta>
<xmpG:yellow>90.000004</xmpG:yellow>
<xmpG:black>35.000002</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=40 M=70 Y=100 K=50</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>39.999998</xmpG:cyan>
<xmpG:magenta>69.999999</xmpG:magenta>
<xmpG:yellow>100.000000</xmpG:yellow>
<xmpG:black>50.000000</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=50 M=70 Y=80 K=70</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>50.000000</xmpG:cyan>
<xmpG:magenta>69.999999</xmpG:magenta>
<xmpG:yellow>80.000001</xmpG:yellow>
<xmpG:black>69.999999</xmpG:black>
</rdf:li>
</rdf:Seq>
</xmpG:Colorants>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:groupName>Grays</xmpG:groupName>
<xmpG:groupType>1</xmpG:groupType>
<xmpG:Colorants>
<rdf:Seq>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=0 M=0 Y=0 K=100</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>0.000000</xmpG:cyan>
<xmpG:magenta>0.000000</xmpG:magenta>
<xmpG:yellow>0.000000</xmpG:yellow>
<xmpG:black>100.000000</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=0 M=0 Y=0 K=90</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>0.000000</xmpG:cyan>
<xmpG:magenta>0.000000</xmpG:magenta>
<xmpG:yellow>0.000000</xmpG:yellow>
<xmpG:black>89.999402</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=0 M=0 Y=0 K=80</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>0.000000</xmpG:cyan>
<xmpG:magenta>0.000000</xmpG:magenta>
<xmpG:yellow>0.000000</xmpG:yellow>
<xmpG:black>79.998797</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=0 M=0 Y=0 K=70</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>0.000000</xmpG:cyan>
<xmpG:magenta>0.000000</xmpG:magenta>
<xmpG:yellow>0.000000</xmpG:yellow>
<xmpG:black>69.999701</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=0 M=0 Y=0 K=60</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>0.000000</xmpG:cyan>
<xmpG:magenta>0.000000</xmpG:magenta>
<xmpG:yellow>0.000000</xmpG:yellow>
<xmpG:black>59.999102</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=0 M=0 Y=0 K=50</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>0.000000</xmpG:cyan>
<xmpG:magenta>0.000000</xmpG:magenta>
<xmpG:yellow>0.000000</xmpG:yellow>
<xmpG:black>50.000000</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=0 M=0 Y=0 K=40</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>0.000000</xmpG:cyan>
<xmpG:magenta>0.000000</xmpG:magenta>
<xmpG:yellow>0.000000</xmpG:yellow>
<xmpG:black>39.999402</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=0 M=0 Y=0 K=30</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>0.000000</xmpG:cyan>
<xmpG:magenta>0.000000</xmpG:magenta>
<xmpG:yellow>0.000000</xmpG:yellow>
<xmpG:black>29.998803</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=0 M=0 Y=0 K=20</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>0.000000</xmpG:cyan>
<xmpG:magenta>0.000000</xmpG:magenta>
<xmpG:yellow>0.000000</xmpG:yellow>
<xmpG:black>19.999701</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=0 M=0 Y=0 K=10</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>0.000000</xmpG:cyan>
<xmpG:magenta>0.000000</xmpG:magenta>
<xmpG:yellow>0.000000</xmpG:yellow>
<xmpG:black>9.999102</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=0 M=0 Y=0 K=5</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>0.000000</xmpG:cyan>
<xmpG:magenta>0.000000</xmpG:magenta>
<xmpG:yellow>0.000000</xmpG:yellow>
<xmpG:black>4.998803</xmpG:black>
</rdf:li>
</rdf:Seq>
</xmpG:Colorants>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:groupName>Brights</xmpG:groupName>
<xmpG:groupType>1</xmpG:groupType>
<xmpG:Colorants>
<rdf:Seq>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=0 M=100 Y=100 K=0</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>0.000000</xmpG:cyan>
<xmpG:magenta>100.000000</xmpG:magenta>
<xmpG:yellow>100.000000</xmpG:yellow>
<xmpG:black>0.000000</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=0 M=75 Y=100 K=0</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>0.000000</xmpG:cyan>
<xmpG:magenta>75.000000</xmpG:magenta>
<xmpG:yellow>100.000000</xmpG:yellow>
<xmpG:black>0.000000</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=0 M=10 Y=95 K=0</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>0.000000</xmpG:cyan>
<xmpG:magenta>10.000002</xmpG:magenta>
<xmpG:yellow>94.999999</xmpG:yellow>
<xmpG:black>0.000000</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=85 M=10 Y=100 K=0</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>84.999996</xmpG:cyan>
<xmpG:magenta>10.000002</xmpG:magenta>
<xmpG:yellow>100.000000</xmpG:yellow>
<xmpG:black>0.000000</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=100 M=90 Y=0 K=0</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>100.000000</xmpG:cyan>
<xmpG:magenta>90.000004</xmpG:magenta>
<xmpG:yellow>0.000000</xmpG:yellow>
<xmpG:black>0.000000</xmpG:black>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<xmpG:swatchName>C=60 M=90 Y=0 K=0</xmpG:swatchName>
<xmpG:mode>CMYK</xmpG:mode>
<xmpG:type>PROCESS</xmpG:type>
<xmpG:cyan>60.000002</xmpG:cyan>
<xmpG:magenta>90.000004</xmpG:magenta>
<xmpG:yellow>0.003099</xmpG:yellow>
<xmpG:black>0.003099</xmpG:black>
</rdf:li>
</rdf:Seq>
</xmpG:Colorants>
</rdf:li>
</rdf:Seq>
</xmpTPg:SwatchGroups>
</rdf:Description>
<rdf:Description rdf:about=""
xmlns:pdf="http://ns.adobe.com/pdf/1.3/">
<pdf:Producer>Adobe PDF library 9.90</pdf:Producer>
</rdf:Description>
</rdf:RDF>
</x:xmpmeta>
<?xpacket end="w"?>
endstream
endobj
3 0 obj
<</Count 1/Kids[7 0 R]/Type/Pages>>
endobj
7 0 obj
<</ArtBox[47.9487 58.0 456.267 438.254]/BleedBox[0.0 0.0 500.0 500.0]/Contents 242 0 R/LastModified(D:20171220162736-07'00')/MediaBox[0.0 0.0 500.0 500.0]/Parent 3 0 R/PieceInfo<</Illustrator 243 0 R>>/Resources<</ColorSpace<</CS0 244 0 R>>/ExtGState<</GS0 245 0 R>>/Properties<</MC0 240 0 R>>>>/Thumb 246 0 R/TrimBox[0.0 0.0 500.0 500.0]/Type/Page>>
endobj
242 0 obj
<</Filter/FlateDecode/Length 608>>stream
HԔnT1y
@\qUAU<"J ޞd3ʒE&|nnBo(=%*~|N{9IW#csz"ݨ
:>pS<f%>&XZ֬)m6.'Ke~il#j<T1r$<r5 Jn|sqz.X}.GaXVv-e~NgWd919]ʵ֕]M=
nHk!
2Ӑ~HqM&+gczYC_SrA&,(
U/r1Vp
T %$,9˴HhpV6_/7W+QA/Ay]P
jD:6h&IS?jG+X!MѣX'Bj(W]H3pHɄNp}!#ŇW)XMUԢ|F*AQ4rPp.G'AЌSjnptzBĕ`qt K 5w-I
endstream
endobj
246 0 obj
<</BitsPerComponent 8/ColorSpace 247 0 R/Filter[/ASCII85Decode/FlateDecode]/Height 62/Length 635/Width 62>>stream
8;Z]!c#!S,%#$4i1_es`;b9^u_fiQW"De/uCI;,_-!Dj87`di>5+_Rq5!S)bNhFCQ
'Ms9mk'OM%n\4]$N3daW@cAfrmA0/lE2T0\5AK]b8^(0XN@_UD]l2GYOe^FKKrXTW
P;kuG\U5,ck4Z_aghB^K`TJIeK_i/=,J2*h(0M#QD2p+lE,26$TVZ;CE5gaUCPN.3
9MBkg(63_2GgZXV+i"8!QfD_^*m]YMDPYuUEQ(WM<CFjRW,(,9VO1S#1G'n-[n)gr
;;[!%c4:LXgp6ni9Qa`H-C;rAGg;+BS#M7-\0j-HNu;re=;`QMHVcM<T+O_Ue<<kE
1[tW2,DP+>[IcD\50$\ESD%gSQc3Ir1OAHTCZorm*c%CqCO:K=M%lNZl8'd\J[)q'
5KR\Z%q80'g\u/Zl^1T`@s\"je^i7/Q'l7>:q$p8bY0NJ+4L&VV#;@AEaQ;fr$f5t
F/A84mL=Ti41.Ks*OjF7[;R!J]@=4+VVf5\RD!c%e1gfLnJUK3G1GF;`TKh\h\pH^
9:o5XFhKegaDXd(f(JIFdb"4cN4EL@gt?/NH?\gRrT^kd(#=;LUTHHiR>8YMgPUIS
3f*GX-6,3`q<W9GYPm"BF<`su5N?[Amf<FZ<:`u~>
endstream
endobj
247 0 obj
[/Indexed/DeviceRGB 255 248 0 R]
endobj
248 0 obj
<</Filter[/ASCII85Decode/FlateDecode]/Length 428>>stream
8;X]O>EqN@%''O_@%e@?J;%+8(9e>X=MR6S?i^YgA3=].HDXF.R$lIL@"pJ+EP(%0
b]6ajmNZn*!='OQZeQ^Y*,=]?C.B+\Ulg9dhD*"iC[;*=3`oP1[!S^)?1)IZ4dup`
E1r!/,*0[*9.aFIR2&b-C#s<Xl5FH@[<=!#6V)uDBXnIr.F>oRZ7Dl%MLY\.?d>Mn
6%Q2oYfNRF$$+ON<+]RUJmC0I<jlL.oXisZ;SYU[/7#<&37rclQKqeJe#,UF7Rgb1
VNWFKf>nDZ4OTs0S!saG>GGKUlQ*Q?45:CI&4J'_2j<etJICj7e7nPMb=O6S7UOH<
PO7r\I.Hu&e0d&E<.')fERr/l+*W,)q^D*ai5<uuLX.7g/>$XKrcYp0n+Xl_nU*O(
l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~>
endstream
endobj
240 0 obj
<</Intent 249 0 R/Name(Layer 1)/Type/OCG/Usage 250 0 R>>
endobj
249 0 obj
[/View/Design]
endobj
250 0 obj
<</CreatorInfo<</Creator(Adobe Illustrator 15.0)/Subtype/Artwork>>>>
endobj
245 0 obj
<</AIS false/BM/Normal/CA 1.0/OP false/OPM 1/SA true/SMask/None/Type/ExtGState/ca 1.0/op false>>
endobj
244 0 obj
[/ICCBased 251 0 R]
endobj
251 0 obj
<</Filter/FlateDecode/Length 389757/N 4>>stream
HuTKtKKJI,t(4K%ҹH4J#Ғ(H
wqyy~3̙g<3 Y9El
@ ]!O-@ \+BVKK
:OX~WCaiHKL 0qY `5 ck
X] x=8 X Ŀ>.f#aPn D^{y8 dpH st:Yc xc
IV?S!:_9[YbQP~+rA
ShHht^
'0߅kYXY9Yqqpl'WzEE$%D>,^|t*K)%/`\ҫ:&D[7dplDa5|mb4,yy{e5
3⚅,t+whlA
mk
xYUH&%Ȥ
qO'Mz3KT@v[NUnn^\o]abTrtlmE]e~U+jאZ:zaqi5};CS[\_ۆwCaQ1;>L$Lz}4:%8M7l̎Χ/}XT^]X>\Ym[n!ycskkƶʷ;v{pIs0Xݯ3s&$WWW*)!$$%!e$cHNOAKIMEqƕ;KLw@YX;ؚ8^+DspfKOTCPpJ%D=++O%$*8IZ\Z^UK_wL"dx]} >9=;s_G8/̹N!Gz[<=2|B}PQzlH0Wc(Een|Pds::5&89yFT"od䳔i/ZK^&gd:fgQl
kJХeJ*+篍kj5U[ZUh0|em6]B@`PpH?QM1Msψ*iϛ.Z[JYZ)X-]RѺپw?@?5 ǖ'vNg
W3gLC#u!MMMEvAms˔FVNA̝GLwA̬,llؿsݛnͽ+!B²"<b4$݇kRғedk*JY*/TS'<SV҈ԌЊЎԉЍЋЏ042?M4I~fs-,"+uMm]}CcSQ\RZsvGiH3GFFaGDƬč&$V''g$FLG˰4͂djikhCf%VNeAqYUڪG^/Ճ[Z{Vڱ:;`=c}nK
Fv(ރ> 'R&k?3?4+:6oT\ұڿ6VʝoF?LT;:>::>:;eqvx^sawݥʕ'_ EFO\DKLtAnFF)F|ԭ6\`@z?m+F;LwiA hy͖)Mgw~_
@ZH_XA,"F)%/*9aZ:Q,\B^_AU2
*'[jo5[uR1uh`fm$1xJgBdrltlyyEe$feg-g#`dGbwj0TOC9; ܨݿxz6zx8IP=A!.aAxۑ ϊ}bG-ޒēx`G/Ԝq_O?0"۬խЮ˯ǰı²µŶȷӹۺ 0@RfzƏǦȾ*GcЀџҿ'LsٛFsM6+1MZ:{ T?~ò~i~L}~cbA~Dad~ty~W~O>~\/~|~`C x}%H}1X}%z}K}
{N}<_~7A~-ψ||Dz|+E|[s|z}^}wO@}-~ċ {Gu{Dz{]Ĭ{f{Zx|[]|ϕM?}R<}Ǝz]YzHħz|z={LNw{\|=>|v|ېI8z/r
z;bz'sMzd6zɬqv{D[{0>|;|yyaIy?yazYvzݮ[{^=c{ФI{R*y߄yfUy`VyyuKzZi{<{z%zȎ~+~ }͇}W0}3}HtЄ}Zk}=~zɇ }!~Єd*s}Y<9wpSwuuVrUW؈|;,뇔{RsѲ;:8q)PCV:4.8Ȅ2?UpVu9ScbփR.ՁNn U388A/ͬδz6߆өn1T\e7݀tXT)$̯̕6;eCʷˆ imw3SƀV7M
\lGNػځNāa5tNzlߴS<H6*<a|kz|CV|Ǎ||Ik|Ru}26'~2F-B*ojQ^@5zI`ٳ $ĝ"cߘ&Uij|PJˇv4vyVG.2{萾hS掼O[3(Jьx&$Ԟs҉h
~2gK>-N}o2ن
N%է >w֣A}⇤\fXMݘ2,KԐ3g°[}
0e6M_1?1ӣǾI^I|B̯dܪwLe1$:rW]
1S{z|diL
g0\U{[G{!{ ޔ`{&yE{xbie{Jr|/c5}~
~:f#MKx+Ca|uI~.yW ώәߎ%¡唘[w!^T`^H*- 5GȨ瘎=Π4rv_ҍRGf,ދ̋|,ƕ{Ҙtٕ^1Fő,;'<!_Yl~JJtS#]'FA4+;ۊLPf&ɔޝըs@夏]0E+:ևSS 𧠨jVPp,<XQ)XVl(Js&J!K{@BE.eWqQ䆓~37FHI^\ӡ+j&YbdML{#)FA;qT0_
^9IݤxֺƢYFh9ՅhX;Jln+jġ(m,ּJ(VaV/aؑ@Q~.8_]7]g|F)-/MH|P8%oFxC<RlA^QlzrJAUUd*N$i
#v
b7F*4ނ
pvix֖IoJ۱#
Whԉl"kxwVjGDz*ߜxW:ƩdP$j4WM[,]ʫ$W$I&N}7¨
s1@9TɎ.EzNDf*uwr *#,h"8=N
%=(pQu9sLӓ(&wھ?ERAHi.R~ Ԅ6:*tД3*۱x#m?r~32+wp6yXaTO#
U¼<_)I(}W2SX Uw
Mf_T)?kYYFK8u;J$þ*1T >,#h%T,Qۥ{[s:9&^!Փa@!"y
.Jl6mHju,bU6+shܸd-ʥ}wi -sun=0Ľi-_*)U_ˈb$na+;ϧT;ppA7C4.*Iߥa8Mm.ACi7\j|fiԫ)]ޭjʄU]3(íwhJch-4x7h*P0H됎L랇ڡuÂ,{Bz}8vggҲd[!XTZZ.vlAg
{;Sm`vؿ`~?ga.
3Ì{L^WYe4]L<pqk!G]l v:DeHXqEK4kHoS|XֽO7o**+ 2h`?k6ݤg,M{ST3`b5XE#*і}z#C//7}V;9T)?ވ2[ُ]n$~fЌ,dp,BAdrH]`uPVkaEVvYNU5/yfD.ݡ\ 1Qa#KE:|N[k=&[],1$ξB0Y(ߊq$]!{Ik5U3j=Or)<V
A8H:YjD!L_|OlxE{EY[9#Evx2Eas=[RQi*i66`ώ,+#,i1A2 @ƪWmHXJNP+)̧+=l$zUkb]i[:<旰Ar)<